Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

UI for XHR Breakpoints #6934

Merged
merged 17 commits into from
Oct 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ env:
global:
- DISPLAY=':99.0'
- YARN_VERSION='1.9.4'
- MC_COMMIT='f66e525e6978' # https://hg.mozilla.org/mozilla-central/shortlog
- MC_COMMIT='ffb770ed3871' # https://hg.mozilla.org/mozilla-central/shortlog

notifications:
slack:
Expand Down
10 changes: 10 additions & 0 deletions assets/panel/debugger.properties
Original file line number Diff line number Diff line change
Expand Up @@ -506,13 +506,23 @@ original=original
# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression
# input element
expressions.placeholder=Add watch expression

# LOCALIZATION NOTE (expressions.errorMsg): Error text for expression
# input element
expressions.errorMsg=Invalid expression…
expressions.label=Add watch expression
expressions.accesskey=e
expressions.key=CmdOrCtrl+Shift+E

# LOCALIZATION NOTE (xhrBreakpoints.header): The pause on any XHR breakpoints headings
xhrBreakpoints.header=XHR Breakpoints
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a note here.

xhrBreakpoints.placeholder=Break when URL contains
xhrBreakpoints.label=Add XHR breakpoint

# LOCALIZATION NOTE (pauseOnAnyXHR): The pause on any xhr checkbox description
# when the debugger will pause on any xhr requests.
pauseOnAnyXHR=Pause on any URL

# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item
# for closing the selected tab below the mouse.
sourceTabs.closeTab=Close tab
Expand Down
1 change: 1 addition & 0 deletions assets/panel/prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ pref("devtools.debugger.features.async-stepping", true);
pref("devtools.debugger.features.skip-pausing", true);
pref("devtools.debugger.features.autocomplete-expressions", false);
pref("devtools.debugger.features.map-expression-bindings", true);
pref("devtools.debugger.features.xhr-breakpoints", true);
110 changes: 108 additions & 2 deletions src/actions/breakpoints/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import { PROMISE } from "../utils/middleware/promise";
import {
getBreakpoint,
getBreakpoints,
getXHRBreakpoints,
getSelectedSource,
getBreakpointAtLocation,
getBreakpointsAtLine
} from "../../selectors";
import { assertBreakpoint } from "../../utils/breakpoint";
import { assertBreakpoint, createXHRBreakpoint } from "../../utils/breakpoint";
import {
addBreakpoint,
addHiddenBreakpoint,
Expand All @@ -31,7 +32,7 @@ import { isEmptyLineInSource } from "../../reducers/ast";
// this will need to be changed so that addCLientBreakpoint is removed

import type { ThunkArgs, Action } from "../types";
import type { Breakpoint, Location } from "../../types";
import type { Breakpoint, Location, XHRBreakpoint } from "../../types";
import type { BreakpointsMap } from "../../reducers/types";

import { recordEvent } from "../../utils/telemetry";
Expand Down Expand Up @@ -382,4 +383,109 @@ export function toggleDisabledBreakpoint(line: number, column?: number) {
};
}

export function enableXHRBreakpoint(index: number, bp: XHRBreakpoint) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const xhrBreakpoints = getXHRBreakpoints(getState());
const breakpoint = bp || xhrBreakpoints.get(index);
const enabledBreakpoint = {
...breakpoint,
disabled: false
};

return dispatch({
type: "ENABLE_XHR_BREAKPOINT",
breakpoint: enabledBreakpoint,
index,
[PROMISE]: client.setXHRBreakpoint(breakpoint.path, breakpoint.method)
});
};
}

export function disableXHRBreakpoint(index: number, bp: XHRBreakpoint) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const xhrBreakpoints = getXHRBreakpoints(getState());
const breakpoint = bp || xhrBreakpoints.get(index);
const disabledBreakpoint = {
...breakpoint,
disabled: true
};

return dispatch({
type: "DISABLE_XHR_BREAKPOINT",
breakpoint: disabledBreakpoint,
index,
[PROMISE]: client.removeXHRBreakpoint(breakpoint.path, breakpoint.method)
});
};
}

export function updateXHRBreakpoint(
index: number,
path: string,
method: string
) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const xhrBreakpoints = getXHRBreakpoints(getState());
const breakpoint = xhrBreakpoints.get(index);

const updatedBreakpoint = {
...breakpoint,
path,
method,
text: `URL contains "${path}"`
};

return dispatch({
type: "UPDATE_XHR_BREAKPOINT",
breakpoint: updatedBreakpoint,
index,
[PROMISE]: Promise.all([
client.removeXHRBreakpoint(breakpoint.path, breakpoint.method),
client.setXHRBreakpoint(path, method)
])
});
};
}
export function togglePauseOnAny() {
return ({ dispatch, getState }: ThunkArgs) => {
const xhrBreakpoints = getXHRBreakpoints(getState());
const index = xhrBreakpoints.findIndex(({ path }) => path.length === 0);
if (index < 0) {
return dispatch(setXHRBreakpoint("", "ANY"));
}

const bp = xhrBreakpoints.get(index);
if (bp.disabled) {
return dispatch(enableXHRBreakpoint(index, bp));
}

return dispatch(disableXHRBreakpoint(index, bp));
};
}

export function setXHRBreakpoint(path: string, method: string) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoint = createXHRBreakpoint(path, method);

return dispatch({
type: "SET_XHR_BREAKPOINT",
breakpoint,
[PROMISE]: client.setXHRBreakpoint(path, method)
});
};
}

export function removeXHRBreakpoint(index: number) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const xhrBreakpoints = getXHRBreakpoints(getState());
const breakpoint = xhrBreakpoints.get(index);
return dispatch({
type: "REMOVE_XHR_BREAKPOINT",
breakpoint,
index,
[PROMISE]: client.removeXHRBreakpoint(breakpoint.path, breakpoint.method)
});
};
}

export { addBreakpoint, addHiddenBreakpoint, enableBreakpoint, syncBreakpoint };
27 changes: 25 additions & 2 deletions src/actions/types/BreakpointAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// @flow

import type { Breakpoint, Location } from "../../types";
import type { Breakpoint, Location, XHRBreakpoint } from "../../types";

import type { PromiseAction } from "../utils/middleware/promise";

Expand All @@ -27,7 +27,30 @@ export type BreakpointAction =
+breakpoint: Breakpoint,
+disabled: boolean
|}>
// for simulating a successful server request
| PromiseAction<{|
+type: "SET_XHR_BREAKPOINT",
+breakpoint: XHRBreakpoint
|}>
| PromiseAction<{|
+type: "ENABLE_XHR_BREAKPOINT",
+breakpoint: XHRBreakpoint,
+index: number
|}>
| PromiseAction<{|
+type: "UPDATE_XHR_BREAKPOINT",
+breakpoint: XHRBreakpoint,
+index: number
|}>
| PromiseAction<{|
+type: "DISABLE_XHR_BREAKPOINT",
+breakpoint: XHRBreakpoint,
+index: number
|}>
| PromiseAction<{|
+type: "REMOVE_XHR_BREAKPOINT",
+index: number,
+breakpoint: XHRBreakpoint
|}>
| {|
+type: "REMOVE_BREAKPOINT",
+breakpoint: Breakpoint,
Expand Down
10 changes: 10 additions & 0 deletions src/client/firefox/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ function getBreakpointByLocation(location: Location) {
return null;
}

function setXHRBreakpoint(path: string, method: string) {
return threadClient.setXHRBreakpoint(path, method);
}

function removeXHRBreakpoint(path: string, method: string) {
return threadClient.removeXHRBreakpoint(path, method);
}

function setBreakpoint(
location: Location,
condition: boolean,
Expand Down Expand Up @@ -439,6 +447,8 @@ const clientCommands = {
sourceContents,
getBreakpointByLocation,
setBreakpoint,
setXHRBreakpoint,
removeXHRBreakpoint,
removeBreakpoint,
setBreakpointCondition,
evaluate,
Expand Down
2 changes: 2 additions & 0 deletions src/client/firefox/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ export type ThreadClient = {
source: ({ actor: SourceId }) => SourceClient,
pauseGrip: (Grip | Function) => ObjectClient,
pauseOnExceptions: (boolean, boolean) => Promise<*>,
setXHRBreakpoint: (path: string, method: string) => Promise<boolean>,
removeXHRBreakpoint: (path: string, method: string) => Promise<boolean>,
interrupt: () => Promise<*>,
eventListeners: () => Promise<*>,
getFrames: (number, number) => FramesResponse,
Expand Down
19 changes: 17 additions & 2 deletions src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
bootstrapStore,
bootstrapWorkers
} from "../utils/bootstrap";
import { initialBreakpointsState } from "../reducers/breakpoints";

function loadFromPrefs(actions: Object) {
const { pauseOnExceptions, pauseOnCaughtExceptions } = prefs;
Expand All @@ -25,10 +26,24 @@ function loadFromPrefs(actions: Object) {
}
}

function syncXHRBreakpoints() {
asyncStore.xhrBreakpoints.then(bps => {
bps.forEach(({ path, method, disabled }) => {
if (!disabled) {
firefox.clientCommands.setXHRBreakpoint(path, method);
}
});
});
}

async function loadInitialState() {
const pendingBreakpoints = await asyncStore.pendingBreakpoints;
const tabs = await asyncStore.tabs;
return { pendingBreakpoints, tabs };
const xhrBreakpoints = await asyncStore.xhrBreakpoints;

const breakpoints = initialBreakpointsState(xhrBreakpoints);

return { pendingBreakpoints, tabs, breakpoints };
}

export async function onConnect(
Expand All @@ -54,7 +69,7 @@ export async function onConnect(
const workers = bootstrapWorkers();
await firefox.onConnect(connection, actions);
await loadFromPrefs(actions);

syncXHRBreakpoints();
setupHelper({
store,
actions,
Expand Down
87 changes: 87 additions & 0 deletions src/components/SecondaryPanes/XHRBreakpoints.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

.xhr-input-form {
width: 100%;
}

.xhr-input {
width: 100%;
margin: 0;
border: 1px;
background-color: var(--theme-sidebar-background);
font-size: 12px;
padding: 0.5em 1.6em;
color: var(--theme-body-color);
outline: 0;
}

.xhr-input::placeholder {
font-style: italic;
color: var(--theme-comment);
}

.xhr-input:focus {
cursor: text;
}

.xhr-input-container {
display: flex;
border: 1px solid transparent;
}

.xhr-input-container.focused {
border: 1px solid var(--theme-highlight-blue);
}

:root.theme-dark .xhr-input-container.focused {
border: 1px solid var(--blue-50);
}

.xhr-input-container.error {
border: 1px solid red;
}

.xhr-container {
border-left: 4px solid transparent;
width: 100%;
color: var(--theme-body-color);
padding: 0.25em 1em;
background-color: var(--theme-body-background);
display: flex;
align-items: center;
position: relative;
min-height: var(--breakpoint-expression-height);
}

:root.theme-light .xhr-container:hover {
background-color: var(--theme-selection-background-hover);
}

:root.theme-dark .xhr-container:hover {
background-color: var(--theme-selection-background-hover);
}

.xhr-checkbox {
margin-left: 0px;
}

.xhr-label {
max-width: calc(100% - var(--breakpoint-expression-right-clear-space));
display: inline-block;
cursor: pointer;
flex-grow: 1;
text-overflow: ellipsis;
padding-inline-end: 8px;
font-size: 11px;
}

.xhr-container .close-btn {
offset-inline-end: 12px;
inset-inline-end: 12px;
offset-inline-start: auto;
inset-inline-start: auto;
position: absolute;
top: 8px;
}
Loading