mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1496468 - Add a console pause indicator. r=loganfsmyth
Differential Revision: https://phabricator.services.mozilla.com/D7741 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
9f095c8011
commit
46254f84e4
@ -18,6 +18,19 @@ function findMessages(hud, text, selector = ".message") {
|
||||
return elements;
|
||||
}
|
||||
|
||||
function waitForThreadEvents(console, eventName) {
|
||||
info(`Waiting for thread event '${eventName}' to fire.`);
|
||||
const thread = console.threadClient;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
thread.addListener(eventName, function onEvent(eventName, ...args) {
|
||||
info(`Thread event '${eventName}' fired.`);
|
||||
thread.removeListener(eventName, onEvent);
|
||||
resolve.apply(resolve, args);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function openContextMenu(hud, element) {
|
||||
const onConsoleMenuOpened = hud.ui.consoleOutput.once("menu-open");
|
||||
synthesizeContextMenuEvent(element);
|
||||
@ -61,6 +74,10 @@ async function test() {
|
||||
|
||||
await once(Services.ppmm, "TimeWarpFinished");
|
||||
|
||||
await waitForThreadEvents(console, 'paused')
|
||||
messages = findMessages(hud, "", ".paused");
|
||||
ok(messages.length == 1, "Found one paused message");
|
||||
|
||||
let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
|
||||
await client.interrupt();
|
||||
|
||||
|
@ -77,6 +77,7 @@ a {
|
||||
border-inline-start: solid 3px transparent;
|
||||
font-size: var(--console-output-font-size);
|
||||
line-height: var(--console-output-line-height);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -106,6 +107,22 @@ a {
|
||||
background-color: var(--warning-background-color);
|
||||
}
|
||||
|
||||
.message.paused::before {
|
||||
background: #d8461f;
|
||||
opacity: 0.6;
|
||||
width: 100vw;
|
||||
height: 1px;
|
||||
bottom: 0px;
|
||||
left: -3px;
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.message.paused ~ .message {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.message.startGroup,
|
||||
.message.startGroupCollapsed {
|
||||
--console-output-indent-border-color: transparent;
|
||||
@ -190,7 +207,7 @@ a {
|
||||
}
|
||||
|
||||
|
||||
span.icon[title="Jump"] {
|
||||
.message > span.icon[title="Jump"] {
|
||||
background-image:var(--theme-console-jump-image);
|
||||
background-size: 14px 14px;
|
||||
cursor: pointer;
|
||||
|
@ -21,6 +21,7 @@ const {
|
||||
MESSAGE_CLOSE,
|
||||
MESSAGE_TYPE,
|
||||
MESSAGE_TABLE_RECEIVE,
|
||||
PAUSED_EXCECUTION_POINT,
|
||||
PRIVATE_MESSAGES_CLEAR,
|
||||
} = require("../constants");
|
||||
|
||||
@ -57,6 +58,13 @@ function messagesClear() {
|
||||
};
|
||||
}
|
||||
|
||||
function setPauseExecutionPoint(executionPoint) {
|
||||
return {
|
||||
type: PAUSED_EXCECUTION_POINT,
|
||||
executionPoint
|
||||
};
|
||||
}
|
||||
|
||||
function privateMessagesClear() {
|
||||
return {
|
||||
type: PRIVATE_MESSAGES_CLEAR
|
||||
@ -139,4 +147,5 @@ module.exports = {
|
||||
privateMessagesClear,
|
||||
// for test purpose only.
|
||||
messageTableDataReceive,
|
||||
setPauseExecutionPoint,
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ const {
|
||||
getAllMessagesTableDataById,
|
||||
getAllNetworkMessagesUpdateById,
|
||||
getVisibleMessages,
|
||||
getPausedExecutionPoint,
|
||||
getAllRepeatById,
|
||||
} = require("devtools/client/webconsole/selectors/messages");
|
||||
const MessageContainer = createFactory(require("devtools/client/webconsole/components/MessageContainer").MessageContainer);
|
||||
@ -44,6 +45,7 @@ class ConsoleOutput extends Component {
|
||||
visibleMessages: PropTypes.array.isRequired,
|
||||
networkMessageActiveTabId: PropTypes.string.isRequired,
|
||||
onFirstMeaningfulPaint: PropTypes.func.isRequired,
|
||||
pausedExecutionPoint: PropTypes.any
|
||||
};
|
||||
}
|
||||
|
||||
@ -132,6 +134,7 @@ class ConsoleOutput extends Component {
|
||||
serviceContainer,
|
||||
timestampsVisible,
|
||||
initialized,
|
||||
pausedExecutionPoint
|
||||
} = this.props;
|
||||
|
||||
if (!initialized) {
|
||||
@ -153,6 +156,7 @@ class ConsoleOutput extends Component {
|
||||
repeat: messagesRepeat[messageId],
|
||||
networkMessageUpdate: networkMessagesUpdate[messageId],
|
||||
networkMessageActiveTabId,
|
||||
pausedExecutionPoint,
|
||||
getMessage: () => messages.get(messageId)
|
||||
}));
|
||||
|
||||
@ -183,6 +187,7 @@ function isScrolledToBottom(outputNode, scrollNode) {
|
||||
function mapStateToProps(state, props) {
|
||||
return {
|
||||
initialized: state.ui.initialized,
|
||||
pausedExecutionPoint: getPausedExecutionPoint(state),
|
||||
messages: getAllMessagesById(state),
|
||||
visibleMessages: getVisibleMessages(state),
|
||||
messagesUi: getAllMessagesUiById(state),
|
||||
|
@ -63,7 +63,8 @@ class Message extends Component {
|
||||
notes: PropTypes.arrayOf(PropTypes.shape({
|
||||
messageBody: PropTypes.string.isRequired,
|
||||
frame: PropTypes.any,
|
||||
}))
|
||||
})),
|
||||
isPaused: PropTypes.bool
|
||||
};
|
||||
}
|
||||
|
||||
@ -143,6 +144,7 @@ class Message extends Component {
|
||||
collapseTitle,
|
||||
source,
|
||||
type,
|
||||
isPaused,
|
||||
level,
|
||||
indent,
|
||||
topLevelClasses,
|
||||
@ -156,7 +158,7 @@ class Message extends Component {
|
||||
notes
|
||||
} = this.props;
|
||||
|
||||
topLevelClasses.push("message", source, type, level);
|
||||
topLevelClasses.push("message", source, type, level, isPaused ? "paused" : "");
|
||||
if (open) {
|
||||
topLevelClasses.push("open");
|
||||
}
|
||||
|
@ -24,6 +24,13 @@ const componentMap = new Map([
|
||||
["PageError", require("./message-types/PageError")]
|
||||
]);
|
||||
|
||||
function isPaused({ getMessage, pausedExecutionPoint }) {
|
||||
const message = getMessage();
|
||||
return pausedExecutionPoint
|
||||
&& message.executionPoint
|
||||
&& pausedExecutionPoint.checkpoint === message.executionPoint.checkpoint;
|
||||
}
|
||||
|
||||
class MessageContainer extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
@ -52,19 +59,23 @@ class MessageContainer extends Component {
|
||||
this.props.timestampsVisible !== nextProps.timestampsVisible;
|
||||
const networkMessageUpdateChanged =
|
||||
this.props.networkMessageUpdate !== nextProps.networkMessageUpdate;
|
||||
const pausedChanged = isPaused(this.props) !== isPaused(nextProps);
|
||||
|
||||
return repeatChanged
|
||||
|| openChanged
|
||||
|| tableDataChanged
|
||||
|| timestampVisibleChanged
|
||||
|| networkMessageUpdateChanged;
|
||||
|| networkMessageUpdateChanged
|
||||
|| pausedChanged;
|
||||
}
|
||||
|
||||
render() {
|
||||
const message = this.props.getMessage();
|
||||
|
||||
const MessageComponent = getMessageComponent(message);
|
||||
return MessageComponent(Object.assign({message}, this.props));
|
||||
return MessageComponent(Object.assign({message}, this.props, {
|
||||
isPaused: isPaused(this.props)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ function ConsoleApiCall(props) {
|
||||
serviceContainer,
|
||||
timestampsVisible,
|
||||
repeat,
|
||||
isPaused
|
||||
} = props;
|
||||
const {
|
||||
id: messageId,
|
||||
@ -115,6 +116,7 @@ function ConsoleApiCall(props) {
|
||||
return Message({
|
||||
messageId,
|
||||
executionPoint,
|
||||
isPaused,
|
||||
open,
|
||||
collapsible,
|
||||
collapseTitle,
|
||||
|
@ -32,6 +32,7 @@ function PageError(props) {
|
||||
repeat,
|
||||
serviceContainer,
|
||||
timestampsVisible,
|
||||
isPaused
|
||||
} = props;
|
||||
const {
|
||||
id: messageId,
|
||||
@ -57,6 +58,7 @@ function PageError(props) {
|
||||
return Message({
|
||||
dispatch,
|
||||
messageId,
|
||||
isPaused,
|
||||
open,
|
||||
collapsible: Array.isArray(stacktrace),
|
||||
source,
|
||||
|
@ -38,6 +38,7 @@ const actionTypes = {
|
||||
REVERSE_SEARCH_INPUT_CHANGE: "REVERSE_SEARCH_INPUT_CHANGE",
|
||||
REVERSE_SEARCH_NEXT: "REVERSE_SEARCH_NEXT",
|
||||
REVERSE_SEARCH_BACK: "REVERSE_SEARCH_BACK",
|
||||
PAUSED_EXCECUTION_POINT: "PAUSED_EXCECUTION_POINT"
|
||||
};
|
||||
|
||||
const prefs = {
|
||||
|
@ -55,6 +55,7 @@ const MessageState = overrides => Object.freeze(Object.assign({
|
||||
// Map of the form {messageId : networkInformation}
|
||||
// `networkInformation` holds request, response, totalTime, ...
|
||||
networkMessagesUpdateById: {},
|
||||
pausedExecutionPoint: null
|
||||
}, overrides));
|
||||
|
||||
function cloneState(state) {
|
||||
@ -69,6 +70,7 @@ function cloneState(state) {
|
||||
removedActors: [...state.removedActors],
|
||||
repeatById: {...state.repeatById},
|
||||
networkMessagesUpdateById: {...state.networkMessagesUpdateById},
|
||||
pausedExecutionPoint: state.pausedExecutionPoint
|
||||
};
|
||||
}
|
||||
|
||||
@ -159,6 +161,8 @@ function messages(state = MessageState(), action, filtersState, prefsState) {
|
||||
|
||||
let newState;
|
||||
switch (action.type) {
|
||||
case constants.PAUSED_EXCECUTION_POINT:
|
||||
return { ...state, pausedExecutionPoint: action.executionPoint };
|
||||
case constants.MESSAGES_ADD:
|
||||
// Preemptively remove messages that will never be rendered
|
||||
const list = [];
|
||||
|
@ -49,6 +49,10 @@ function getGroupsById(state) {
|
||||
return state.messages.groupsById;
|
||||
}
|
||||
|
||||
function getPausedExecutionPoint(state) {
|
||||
return state.messages.pausedExecutionPoint;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAllGroupsById,
|
||||
getAllMessagesById,
|
||||
@ -61,4 +65,5 @@ module.exports = {
|
||||
getGroupsById,
|
||||
getMessage,
|
||||
getVisibleMessages,
|
||||
getPausedExecutionPoint
|
||||
};
|
||||
|
@ -173,6 +173,9 @@ WebConsoleOutputWrapper.prototype = {
|
||||
};
|
||||
|
||||
if (this.toolbox) {
|
||||
this.toolbox.threadClient.addListener("paused", this.dispatchPaused.bind(this));
|
||||
this.toolbox.threadClient.addListener("resumed", this.dispatchResumed.bind(this));
|
||||
|
||||
Object.assign(serviceContainer, {
|
||||
onViewSourceInDebugger: frame => {
|
||||
this.toolbox.viewSourceInDebugger(frame.url, frame.line).then(() => {
|
||||
@ -355,6 +358,16 @@ WebConsoleOutputWrapper.prototype = {
|
||||
store.dispatch(actions.timestampsToggle(enabled));
|
||||
},
|
||||
|
||||
dispatchPaused: function(_, packet) {
|
||||
if (packet.executionPoint) {
|
||||
store.dispatch(actions.setPauseExecutionPoint(packet.executionPoint));
|
||||
}
|
||||
},
|
||||
|
||||
dispatchResumed: function(_, packet) {
|
||||
store.dispatch(actions.setPauseExecutionPoint(null));
|
||||
},
|
||||
|
||||
dispatchMessageUpdate: function(message, res) {
|
||||
// network-message-updated will emit when all the update message arrives.
|
||||
// Since we can't ensure the order of the network update, we check
|
||||
|
@ -343,7 +343,7 @@ ReplayDebugger.prototype = {
|
||||
() => handler.call(this, this.getNewestFrame()));
|
||||
},
|
||||
|
||||
_getNewConsoleMessage() {
|
||||
getNewConsoleMessage() {
|
||||
const message = this._sendRequest({ type: "getNewConsoleMessage" });
|
||||
return this._convertConsoleMessage(message);
|
||||
},
|
||||
@ -353,7 +353,7 @@ ReplayDebugger.prototype = {
|
||||
},
|
||||
set onConsoleMessage(handler) {
|
||||
this._breakpointKindSetter("ConsoleMessage", handler,
|
||||
() => handler.call(this, this._getNewConsoleMessage()));
|
||||
() => handler.call(this, this.getNewConsoleMessage()));
|
||||
},
|
||||
|
||||
clearAllBreakpoints: NYI,
|
||||
|
@ -1479,6 +1479,13 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
||||
packet.frame = this._createFrameActor(frame).form();
|
||||
}
|
||||
|
||||
if (this.dbg.replaying) {
|
||||
const message = this.dbg.getNewConsoleMessage();
|
||||
if (message) {
|
||||
packet.executionPoint = message.executionPoint;
|
||||
}
|
||||
}
|
||||
|
||||
if (poppedFrames) {
|
||||
packet.poppedFrames = poppedFrames;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user