Bug 1711463 - [devtools] Update EvaluationContextSelector items on DOCUMENT_EVENT resources. r=jdescottes.

This patch adds a `refreshTargets` action that is called from the toolbox when
a dom-interactive DOCUMENT_EVENT is received.
This action will only update a new state property, `lastTargetRefresh`, with the
current timestamp, so the `EvaluationContextSelector` component will re-render;
as the target information are directly retrieved from the target fronts, any
changes in the title/url will be shown in the component.

Differential Revision: https://phabricator.services.mozilla.com/D115205
This commit is contained in:
Nicolas Chevobbe 2021-05-19 16:58:07 +00:00
parent f8b1226395
commit 1f638b9e06
5 changed files with 57 additions and 12 deletions

View File

@ -21,8 +21,13 @@ function selectTarget(targetActorID) {
};
}
function refreshTargets() {
return { type: "REFRESH_TARGETS" };
}
module.exports = {
registerTarget,
unregisterTarget,
selectTarget,
refreshTargets,
};

View File

@ -8,6 +8,10 @@ const initialReducerState = {
targets: [],
// The selected targetFront instance
selected: null,
// timestamp of the last time a target was updated (i.e. url/title was updated).
// This is used by the EvaluationContextSelector component to re-render the list of
// targets when the list itself did not change (no addition/removal)
lastTargetRefresh: Date.now(),
};
exports.reducer = targetsReducer;
@ -40,6 +44,15 @@ function targetsReducer(state = initialReducerState, action) {
};
}
case "REFRESH_TARGETS": {
// The data _in_ targetFront was updated, so we only need to mutate the state,
// while keeping the same values.
return {
...state,
lastTargetRefresh: Date.now(),
};
}
case "UNREGISTER_TARGET": {
const targets = state.targets.filter(
target => target !== action.targetFront
@ -56,12 +69,18 @@ function targetsReducer(state = initialReducerState, action) {
return state;
}
exports.getToolboxTargets = getToolboxTargets;
function getToolboxTargets(state) {
return state.targets.targets;
}
exports.getSelectedTarget = getSelectedTarget;
function getSelectedTarget(state) {
return state.targets.selected;
}
function getLastTargetRefresh(state) {
return state.targets.lastTargetRefresh;
}
exports.getToolboxTargets = getToolboxTargets;
exports.getSelectedTarget = getSelectedTarget;
exports.getLastTargetRefresh = getLastTargetRefresh;

View File

@ -62,8 +62,9 @@ loader.lazyRequireGetter(
loader.lazyRequireGetter(
this,
[
"registerWalkerListeners",
"refreshTargets",
"registerTarget",
"registerWalkerListeners",
"selectTarget",
"unregisterTarget",
],
@ -4319,7 +4320,6 @@ Toolbox.prototype = {
if (
resource.resourceType === this.resourceCommand.TYPES.DOCUMENT_EVENT &&
resource?.targetFront.isTopLevel &&
!resource.isFrameSwitching &&
// `url` is set on the targetFront when we receive dom-loading, and `title` when
// `dom-interactive` is received. Here we're only updating the window title in
@ -4330,9 +4330,14 @@ Toolbox.prototype = {
// the host title a bit in order for the event listener in targetCommand to be
// executed.
setTimeout(() => {
this._refreshHostTitle();
// Update the EvaluationContext selector so url/title of targets can be updated
this.store.dispatch(refreshTargets());
if (resource.targetFront.isTopLevel) {
this._refreshHostTitle();
this._setDebugTargetData();
}
}, 0);
this._setDebugTargetData();
}
}

View File

@ -48,6 +48,7 @@ class EvaluationContextSelector extends Component {
updateInstantEvaluationResultForCurrentExpression:
PropTypes.func.isRequired,
selectedTarget: PropTypes.object,
lastTargetRefresh: PropTypes.number,
targets: PropTypes.array,
webConsoleUI: PropTypes.object.isRequired,
};
@ -57,9 +58,15 @@ class EvaluationContextSelector extends Component {
if (this.props.selectedTarget !== nextProps.selectedTarget) {
return true;
}
if (this.props.lastTargetRefresh !== nextProps.lastTargetRefresh) {
return true;
}
if (this.props.targets.length !== nextProps.targets.length) {
return true;
}
for (let i = 0; i < nextProps.targets.length; i++) {
const target = this.props.targets[i];
const nextTarget = nextProps.targets[i];
@ -206,6 +213,7 @@ const toolboxConnected = connect(
state => ({
targets: targetSelectors.getToolboxTargets(state),
selectedTarget: targetSelectors.getSelectedTarget(state),
lastTargetRefresh: targetSelectors.getLastTargetRefresh(state),
}),
dispatch => ({
selectTarget: actorID => dispatch(frameworkActions.selectTarget(actorID)),

View File

@ -62,12 +62,20 @@ add_task(async function() {
});
// Wait until the new iframe is rendered in the context selector.
await waitFor(() => getContextSelectorItems(hud).length === 4);
await waitFor(() => {
const items = getContextSelectorItems(hud);
return (
items.length === 4 &&
items.some(el =>
el
.querySelector(".label")
?.textContent.includes("iframe-2|test1.example.org")
)
);
});
const expectedSecondIframeItem = {
// The title is set in a script, but we don't update the context selector entry (it
// should be "iframe-2|test1.example.org:80").
label: `http://test1.example.org/${IFRAME_PATH}?id=iframe-2`,
label: `iframe-2|test1.example.org`,
tooltip: `http://test1.example.org/${IFRAME_PATH}?id=iframe-2`,
};
@ -78,11 +86,11 @@ add_task(async function() {
},
expectedSeparatorItem,
{
...expectedSecondIframeItem,
...expectedFirstIframeItem,
checked: false,
},
{
...expectedFirstIframeItem,
...expectedSecondIframeItem,
checked: false,
},
]);