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

Commit

Permalink
UI for XHR Breakpoints (#6934)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnshulMalik authored and darkwing committed Oct 23, 2018
1 parent fffcde6 commit 8ba7272
Show file tree
Hide file tree
Showing 24 changed files with 756 additions and 16 deletions.
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
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

0 comments on commit 8ba7272

Please sign in to comment.