Loading devtools/client/debugger/new/dist/debugger.css +4 −5 Original line number Diff line number Diff line Loading @@ -2052,9 +2052,6 @@ menuseparator { white-space: nowrap; color: inherit; display: block; position: absolute; top: 0; left: 0; border-bottom: 1px solid var(--theme-splitter-color); } Loading Loading @@ -2091,7 +2088,6 @@ menuseparator { display: flex; flex: 1; flex-direction: column; height: 100%; } .sources-list { Loading Loading @@ -2237,6 +2233,10 @@ menuseparator { height: 100%; } .source-outline-panel.has-root .thread-header { margin-top: 4px; } .sources-list .managed-tree .tree .node .img.blackBox { mask: url("resource://devtools/client/debugger/new/images/blackBox.svg") no-repeat; mask-size: 100%; Loading Loading @@ -2265,7 +2265,6 @@ menuseparator { display: block; } .sources-list-custom-root .sources-list, .sources-list-custom-root .no-sources-message { position: absolute; top: 26px; Loading devtools/client/debugger/new/src/components/PrimaryPanes/Sources.css +4 −5 Original line number Diff line number Diff line Loading @@ -23,9 +23,6 @@ white-space: nowrap; color: inherit; display: block; position: absolute; top: 0; left: 0; border-bottom: 1px solid var(--theme-splitter-color); } Loading Loading @@ -62,7 +59,6 @@ display: flex; flex: 1; flex-direction: column; height: 100%; } .sources-list { Loading Loading @@ -208,6 +204,10 @@ height: 100%; } .source-outline-panel.has-root .thread-header { margin-top: 4px; } .sources-list .managed-tree .tree .node .img.blackBox { mask: url(/images/blackBox.svg) no-repeat; mask-size: 100%; Loading Loading @@ -236,7 +236,6 @@ display: block; } .sources-list-custom-root .sources-list, .sources-list-custom-root .no-sources-message { position: absolute; top: 26px; Loading devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js +2 −43 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import actions from "../../actions"; import AccessibleImage from "../shared/AccessibleImage"; import SourcesTreeItem from "./SourcesTreeItem"; import ManagedTree from "../shared/ManagedTree"; import Svg from "../shared/Svg"; // Utils import { Loading Loading @@ -69,7 +68,6 @@ type Props = { expanded: Set<string>, selectSource: typeof actions.selectSource, setExpandedState: typeof actions.setExpandedState, clearProjectDirectoryRoot: typeof actions.clearProjectDirectoryRoot, focusItem: typeof actions.focusItem, focused: TreeNode, workerCount: number Loading Loading @@ -216,30 +214,6 @@ class SourcesTree extends Component<Props, State> { ); } renderProjectRootHeader() { const { projectRoot } = this.props; if (!projectRoot) { return null; } const rootLabel = projectRoot.split("/").pop(); return ( <div key="root" className="sources-clear-root-container"> <button className="sources-clear-root" onClick={() => this.props.clearProjectDirectoryRoot()} title={L10N.getStr("removeDirectoryRoot.label")} > <Svg name="home" /> <Svg name="breadcrumb" /> <span className="sources-clear-root-label">{rootLabel}</span> </button> </div> ); } getRoots = () => { const { projectRoot } = this.props; const { sourceTree } = this.state; Loading @@ -249,7 +223,7 @@ class SourcesTree extends Component<Props, State> { // The "sourceTree.contents[0]" check ensures that there are contents // A custom root with no existing sources will be ignored if (projectRoot) { if (projectRoot && sourceContents) { if (sourceContents && sourceContents.name !== rootLabel) { return sourceContents.contents[0].contents; } Loading Loading @@ -351,28 +325,14 @@ class SourcesTree extends Component<Props, State> { } render() { const { projectRoot, worker } = this.props; const { worker } = this.props; if (!features.windowlessWorkers && worker) { return null; } if (this.isEmpty()) { if (projectRoot) { return this.renderPane( this.renderProjectRootHeader(), this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailableRoot")) ); } return this.renderPane( this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailable")) ); } return this.renderPane( this.renderThreadHeader(), this.renderProjectRootHeader(), <div key="tree" className="sources-list" onKeyDown={this.onKeyDown}> {this.renderTree()} </div> Loading Loading @@ -421,7 +381,6 @@ export default connect( { selectSource: actions.selectSource, setExpandedState: actions.setExpandedState, clearProjectDirectoryRoot: actions.clearProjectDirectoryRoot, focusItem: actions.focusItem } )(SourcesTree); devtools/client/debugger/new/src/components/PrimaryPanes/index.js +33 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import type { SourcesMapByThread } from "../../reducers/types"; import type { SelectedPrimaryPaneTabType } from "../../selectors"; import type { Thread } from "../../types"; import Svg from "../shared/Svg"; import "./Sources.css"; type State = { Loading @@ -42,6 +44,7 @@ type Props = { setPrimaryPaneTab: typeof actions.setPrimaryPaneTab, setActiveSearch: typeof actions.setActiveSearch, closeActiveSearch: typeof actions.closeActiveSearch, clearProjectDirectoryRoot: typeof actions.clearProjectDirectoryRoot, threads: Thread[] }; Loading Loading @@ -98,6 +101,30 @@ class PrimaryPanes extends Component<Props, State> { ]; } renderProjectRootHeader() { const { projectRoot } = this.props; if (!projectRoot) { return null; } const rootLabel = projectRoot.split("/").pop(); return ( <div key="root" className="sources-clear-root-container"> <button className="sources-clear-root" onClick={() => this.props.clearProjectDirectoryRoot()} title={L10N.getStr("removeDirectoryRoot.label")} > <Svg name="home" /> <Svg name="breadcrumb" /> <span className="sources-clear-root-label">{rootLabel}</span> </button> </div> ); } renderThreadSources() { return this.props.threads.map(({ actor }) => ( <SourcesTree thread={actor} key={actor} /> Loading @@ -123,7 +150,10 @@ class PrimaryPanes extends Component<Props, State> { })} hasFocusableContent > <div>{this.renderThreadSources()}</div> <div> {this.renderProjectRootHeader()} {this.renderThreadSources()} </div> <Outline alphabetizeOutline={this.state.alphabetizeOutline} onAlphabetizeClick={this.onAlphabetizeClick} Loading @@ -147,7 +177,8 @@ const connector = connect( { setPrimaryPaneTab: actions.setPrimaryPaneTab, setActiveSearch: actions.setActiveSearch, closeActiveSearch: actions.closeActiveSearch closeActiveSearch: actions.closeActiveSearch, clearProjectDirectoryRoot: actions.clearProjectDirectoryRoot } ); Loading devtools/client/debugger/new/src/components/PrimaryPanes/tests/PrimaryPanes.spec.js 0 → 100644 +72 −0 Original line number Diff line number Diff line /* 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/>. */ import React from "react"; import { shallow } from "enzyme"; import { showMenu } from "devtools-contextmenu"; import { copyToTheClipboard } from "../../../utils/clipboard"; import PrimaryPanes from ".."; jest.mock("devtools-contextmenu", () => ({ showMenu: jest.fn() })); jest.mock("../../../utils/clipboard", () => ({ copyToTheClipboard: jest.fn() })); describe("PrimaryPanes", () => { afterEach(() => { copyToTheClipboard.mockClear(); showMenu.mockClear(); }); describe("with custom root", () => { it("renders custom root source list", async () => { const { component } = render({ projectRoot: "mdn.com" }); expect(component).toMatchSnapshot(); }); it("calls clearProjectDirectoryRoot on click", async () => { const { component, props } = render({ projectRoot: "mdn" }); component.find(".sources-clear-root").simulate("click"); expect(props.clearProjectDirectoryRoot).toHaveBeenCalled(); }); it("renders empty custom root source list", async () => { const { component } = render({ projectRoot: "custom", sources: {} }); expect(component).toMatchSnapshot(); }); }); }); function generateDefaults(overrides) { return { horizontal: false, projectRoot: "", sourceSearchOn: false, setPrimaryPaneTab: jest.fn(), setActiveSearch: jest.fn(), closeActiveSearch: jest.fn(), clearProjectDirectoryRoot: jest.fn(), threads: [], ...overrides }; } function render(overrides = {}) { const props = generateDefaults(overrides); const component = shallow(<PrimaryPanes.WrappedComponent {...props} />); const defaultState = component.state(); const instance = component.instance(); instance.shouldComponentUpdate = () => true; return { component, props, defaultState, instance }; } Loading
devtools/client/debugger/new/dist/debugger.css +4 −5 Original line number Diff line number Diff line Loading @@ -2052,9 +2052,6 @@ menuseparator { white-space: nowrap; color: inherit; display: block; position: absolute; top: 0; left: 0; border-bottom: 1px solid var(--theme-splitter-color); } Loading Loading @@ -2091,7 +2088,6 @@ menuseparator { display: flex; flex: 1; flex-direction: column; height: 100%; } .sources-list { Loading Loading @@ -2237,6 +2233,10 @@ menuseparator { height: 100%; } .source-outline-panel.has-root .thread-header { margin-top: 4px; } .sources-list .managed-tree .tree .node .img.blackBox { mask: url("resource://devtools/client/debugger/new/images/blackBox.svg") no-repeat; mask-size: 100%; Loading Loading @@ -2265,7 +2265,6 @@ menuseparator { display: block; } .sources-list-custom-root .sources-list, .sources-list-custom-root .no-sources-message { position: absolute; top: 26px; Loading
devtools/client/debugger/new/src/components/PrimaryPanes/Sources.css +4 −5 Original line number Diff line number Diff line Loading @@ -23,9 +23,6 @@ white-space: nowrap; color: inherit; display: block; position: absolute; top: 0; left: 0; border-bottom: 1px solid var(--theme-splitter-color); } Loading Loading @@ -62,7 +59,6 @@ display: flex; flex: 1; flex-direction: column; height: 100%; } .sources-list { Loading Loading @@ -208,6 +204,10 @@ height: 100%; } .source-outline-panel.has-root .thread-header { margin-top: 4px; } .sources-list .managed-tree .tree .node .img.blackBox { mask: url(/images/blackBox.svg) no-repeat; mask-size: 100%; Loading Loading @@ -236,7 +236,6 @@ display: block; } .sources-list-custom-root .sources-list, .sources-list-custom-root .no-sources-message { position: absolute; top: 26px; Loading
devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js +2 −43 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import actions from "../../actions"; import AccessibleImage from "../shared/AccessibleImage"; import SourcesTreeItem from "./SourcesTreeItem"; import ManagedTree from "../shared/ManagedTree"; import Svg from "../shared/Svg"; // Utils import { Loading Loading @@ -69,7 +68,6 @@ type Props = { expanded: Set<string>, selectSource: typeof actions.selectSource, setExpandedState: typeof actions.setExpandedState, clearProjectDirectoryRoot: typeof actions.clearProjectDirectoryRoot, focusItem: typeof actions.focusItem, focused: TreeNode, workerCount: number Loading Loading @@ -216,30 +214,6 @@ class SourcesTree extends Component<Props, State> { ); } renderProjectRootHeader() { const { projectRoot } = this.props; if (!projectRoot) { return null; } const rootLabel = projectRoot.split("/").pop(); return ( <div key="root" className="sources-clear-root-container"> <button className="sources-clear-root" onClick={() => this.props.clearProjectDirectoryRoot()} title={L10N.getStr("removeDirectoryRoot.label")} > <Svg name="home" /> <Svg name="breadcrumb" /> <span className="sources-clear-root-label">{rootLabel}</span> </button> </div> ); } getRoots = () => { const { projectRoot } = this.props; const { sourceTree } = this.state; Loading @@ -249,7 +223,7 @@ class SourcesTree extends Component<Props, State> { // The "sourceTree.contents[0]" check ensures that there are contents // A custom root with no existing sources will be ignored if (projectRoot) { if (projectRoot && sourceContents) { if (sourceContents && sourceContents.name !== rootLabel) { return sourceContents.contents[0].contents; } Loading Loading @@ -351,28 +325,14 @@ class SourcesTree extends Component<Props, State> { } render() { const { projectRoot, worker } = this.props; const { worker } = this.props; if (!features.windowlessWorkers && worker) { return null; } if (this.isEmpty()) { if (projectRoot) { return this.renderPane( this.renderProjectRootHeader(), this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailableRoot")) ); } return this.renderPane( this.renderEmptyElement(L10N.getStr("sources.noSourcesAvailable")) ); } return this.renderPane( this.renderThreadHeader(), this.renderProjectRootHeader(), <div key="tree" className="sources-list" onKeyDown={this.onKeyDown}> {this.renderTree()} </div> Loading Loading @@ -421,7 +381,6 @@ export default connect( { selectSource: actions.selectSource, setExpandedState: actions.setExpandedState, clearProjectDirectoryRoot: actions.clearProjectDirectoryRoot, focusItem: actions.focusItem } )(SourcesTree);
devtools/client/debugger/new/src/components/PrimaryPanes/index.js +33 −2 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import type { SourcesMapByThread } from "../../reducers/types"; import type { SelectedPrimaryPaneTabType } from "../../selectors"; import type { Thread } from "../../types"; import Svg from "../shared/Svg"; import "./Sources.css"; type State = { Loading @@ -42,6 +44,7 @@ type Props = { setPrimaryPaneTab: typeof actions.setPrimaryPaneTab, setActiveSearch: typeof actions.setActiveSearch, closeActiveSearch: typeof actions.closeActiveSearch, clearProjectDirectoryRoot: typeof actions.clearProjectDirectoryRoot, threads: Thread[] }; Loading Loading @@ -98,6 +101,30 @@ class PrimaryPanes extends Component<Props, State> { ]; } renderProjectRootHeader() { const { projectRoot } = this.props; if (!projectRoot) { return null; } const rootLabel = projectRoot.split("/").pop(); return ( <div key="root" className="sources-clear-root-container"> <button className="sources-clear-root" onClick={() => this.props.clearProjectDirectoryRoot()} title={L10N.getStr("removeDirectoryRoot.label")} > <Svg name="home" /> <Svg name="breadcrumb" /> <span className="sources-clear-root-label">{rootLabel}</span> </button> </div> ); } renderThreadSources() { return this.props.threads.map(({ actor }) => ( <SourcesTree thread={actor} key={actor} /> Loading @@ -123,7 +150,10 @@ class PrimaryPanes extends Component<Props, State> { })} hasFocusableContent > <div>{this.renderThreadSources()}</div> <div> {this.renderProjectRootHeader()} {this.renderThreadSources()} </div> <Outline alphabetizeOutline={this.state.alphabetizeOutline} onAlphabetizeClick={this.onAlphabetizeClick} Loading @@ -147,7 +177,8 @@ const connector = connect( { setPrimaryPaneTab: actions.setPrimaryPaneTab, setActiveSearch: actions.setActiveSearch, closeActiveSearch: actions.closeActiveSearch closeActiveSearch: actions.closeActiveSearch, clearProjectDirectoryRoot: actions.clearProjectDirectoryRoot } ); Loading
devtools/client/debugger/new/src/components/PrimaryPanes/tests/PrimaryPanes.spec.js 0 → 100644 +72 −0 Original line number Diff line number Diff line /* 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/>. */ import React from "react"; import { shallow } from "enzyme"; import { showMenu } from "devtools-contextmenu"; import { copyToTheClipboard } from "../../../utils/clipboard"; import PrimaryPanes from ".."; jest.mock("devtools-contextmenu", () => ({ showMenu: jest.fn() })); jest.mock("../../../utils/clipboard", () => ({ copyToTheClipboard: jest.fn() })); describe("PrimaryPanes", () => { afterEach(() => { copyToTheClipboard.mockClear(); showMenu.mockClear(); }); describe("with custom root", () => { it("renders custom root source list", async () => { const { component } = render({ projectRoot: "mdn.com" }); expect(component).toMatchSnapshot(); }); it("calls clearProjectDirectoryRoot on click", async () => { const { component, props } = render({ projectRoot: "mdn" }); component.find(".sources-clear-root").simulate("click"); expect(props.clearProjectDirectoryRoot).toHaveBeenCalled(); }); it("renders empty custom root source list", async () => { const { component } = render({ projectRoot: "custom", sources: {} }); expect(component).toMatchSnapshot(); }); }); }); function generateDefaults(overrides) { return { horizontal: false, projectRoot: "", sourceSearchOn: false, setPrimaryPaneTab: jest.fn(), setActiveSearch: jest.fn(), closeActiveSearch: jest.fn(), clearProjectDirectoryRoot: jest.fn(), threads: [], ...overrides }; } function render(overrides = {}) { const props = generateDefaults(overrides); const component = shallow(<PrimaryPanes.WrappedComponent {...props} />); const defaultState = component.state(); const instance = component.instance(); instance.shouldComponentUpdate = () => true; return { component, props, defaultState, instance }; }