Bug 1565171 - Add routing support part 2: Implement a page switcher component r=nchevobbe

This patch implements a page switcher component (`PageContainer`) and a new Redux substate (`UiState`) to handle which page is shown. At the moment, only service workers page is supported. The aim of this patch is to enable support to add new pages later on and be able to switch between them easily.

Differential Revision: https://phabricator.services.mozilla.com/D39897

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Belén Albeza 2019-07-31 11:15:55 +00:00
Родитель b2fe6b48ce
Коммит 2b561d0edd
21 изменённых файлов: 213 добавлений и 30 удалений

Просмотреть файл

@ -6,5 +6,6 @@
const workers = require("./workers");
const page = require("./page");
const ui = require("./ui");
Object.assign(exports, workers, page);
Object.assign(exports, workers, page, ui);

Просмотреть файл

@ -5,5 +5,6 @@
DevToolsModules(
'index.js',
'page.js',
'ui.js',
'workers.js',
)

Просмотреть файл

@ -0,0 +1,18 @@
/* 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/. */
"use strict";
const { UPDATE_SELECTED_PAGE } = require("../constants");
function updateSelectedPage(selectedPage) {
return {
type: UPDATE_SELECTED_PAGE,
selectedPage,
};
}
module.exports = {
updateSelectedPage,
};

Просмотреть файл

@ -14,7 +14,7 @@ const { main } = require("devtools/client/shared/vendor/react-dom-factories");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
const WorkersPage = createFactory(require("./service-workers/WorkersPage"));
const PageContainer = createFactory(require("./layout/PageContainer"));
/**
* This is the main component for the application panel.
@ -31,7 +31,7 @@ class App extends PureComponent {
return LocalizationProvider(
{ bundles: fluentBundles },
main({ className: `application` }, WorkersPage({}))
main({ className: `application` }, PageContainer({}))
);
}
}

Просмотреть файл

@ -0,0 +1,44 @@
/* 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/. */
"use strict";
const {
createFactory,
PureComponent,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { PAGE_TYPES } = require("../../constants");
const WorkersPage = createFactory(require("../service-workers/WorkersPage"));
class PageContainer extends PureComponent {
static get propTypes() {
return {
page: PropTypes.oneOf(Object.values(PAGE_TYPES)),
};
}
render() {
let component = null;
switch (this.props.page) {
case PAGE_TYPES.SERVICE_WORKERS:
component = WorkersPage({});
break;
}
return component;
}
}
function mapStateToProps(state) {
return {
page: state.ui.selectedPage,
};
}
module.exports = connect(mapStateToProps)(PageContainer);

Просмотреть файл

@ -0,0 +1,7 @@
# 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/.
DevToolsModules(
'PageContainer.js',
)

Просмотреть файл

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'layout',
'service-workers',
'ui',
]

Просмотреть файл

@ -1,3 +1,7 @@
/* 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/. */
/* these styles com from Photon. Keep in mind that the "default" style is not used
in panels, and we should use the "micro" instead for default, stand-alone buttons. */

Просмотреть файл

@ -1,3 +1,7 @@
/* 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/. */
"use strict";
const { PureComponent } = require("devtools/client/shared/vendor/react");

Просмотреть файл

@ -5,10 +5,20 @@
"use strict";
const actionTypes = {
// page substate
UPDATE_DOMAIN: "UPDATE_DOMAIN",
// ui substate
UPDATE_SELECTED_PAGE: "UPDATE_SELECTED_PAGE",
// workers substate
UPDATE_CAN_DEBUG_WORKERS: "UPDATE_CAN_DEBUG_WORKERS",
UPDATE_WORKERS: "UPDATE_WORKERS",
};
const PAGE_TYPES = {
SERVICE_WORKERS: "service-workers",
};
const DEFAULT_PAGE = PAGE_TYPES.SERVICE_WORKERS;
// flatten constants
module.exports = Object.assign({}, actionTypes);
module.exports = Object.assign({}, { DEFAULT_PAGE, PAGE_TYPES }, actionTypes);

Просмотреть файл

@ -10,12 +10,14 @@ const { createStore } = require("devtools/client/shared/vendor/redux");
const rootReducer = require("./reducers/index");
const { WorkersState } = require("./reducers/workers-state");
const { PageState } = require("./reducers/page-state");
const { UiState } = require("./reducers/ui-state");
function configureStore() {
// Prepare initial state.
const initialState = {
workers: new WorkersState(),
page: new PageState(),
ui: new UiState(),
};
return createStore(rootReducer, initialState);

Просмотреть файл

@ -7,8 +7,10 @@
const { combineReducers } = require("devtools/client/shared/vendor/redux");
const { workersReducer } = require("./workers-state");
const { pageReducer } = require("./page-state");
const { uiReducer } = require("./ui-state");
module.exports = combineReducers({
workers: workersReducer,
page: pageReducer,
ui: uiReducer,
});

Просмотреть файл

@ -5,5 +5,6 @@
DevToolsModules(
'index.js',
'page-state.js',
'ui-state.js',
'workers-state.js',
)

Просмотреть файл

@ -0,0 +1,27 @@
/* 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/. */
"use strict";
const { DEFAULT_PAGE, UPDATE_SELECTED_PAGE } = require("../constants");
function UiState() {
return {
selectedPage: DEFAULT_PAGE,
};
}
function uiReducer(state = UiState(), action) {
switch (action.type) {
case UPDATE_SELECTED_PAGE:
return Object.assign({}, state, { selectedPage: action.selectedPage });
default:
return state;
}
}
module.exports = {
UiState,
uiReducer,
};

Просмотреть файл

@ -5,7 +5,7 @@ exports[`App renders the expected snapshot 1`] = `
<main
className="application"
>
<Connect(WorkersPage) />
<Connect(PageContainer) />
</main>
</LocalizationProvider>
`;

Просмотреть файл

@ -1,16 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {
workersReducer,
} = require("devtools/client/application/src/reducers/workers-state");
const {
pageReducer,
} = require("devtools/client/application/src/reducers/page-state");
exports.reducers = {
workers: workersReducer,
page: pageReducer,
};

Просмотреть файл

@ -3,20 +3,14 @@
"use strict";
const {
reducers,
} = require("devtools/client/application/test/components/helpers/helper-reducer");
const {
createStore,
combineReducers,
} = require("devtools/client/shared/vendor/redux");
const reducers = require("devtools/client/application/src/reducers/index");
const { createStore } = require("devtools/client/shared/vendor/redux");
/**
* Prepare the store for use in testing.
*/
function setupStore({ preloadedState } = {}) {
const store = createStore(combineReducers(reducers), preloadedState);
const store = createStore(reducers, preloadedState);
return store;
}

Просмотреть файл

@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PageContainer renders nothing when an invalid page is selected 1`] = `""`;
exports[`PageContainer renders nothing when no page is selected 1`] = `""`;
exports[`PageContainer renders the WorkersPage component when workers page is selected 1`] = `<Connect(WorkersPage) />`;

Просмотреть файл

@ -0,0 +1,53 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Import libs
const { shallow } = require("enzyme");
const { createFactory } = require("react");
// Import setupStore with imported & combined reducers
const {
setupStore,
} = require("devtools/client/application/test/components/helpers/helpers");
const PageContainer = createFactory(
require("devtools/client/application/src/components/layout/PageContainer")
);
const { PAGE_TYPES } = require("devtools/client/application/src/constants");
/**
* Test for workerListEmpty.js component
*/
describe("PageContainer", () => {
function buildStoreWithSelectedPage(selectedPage) {
return setupStore({
preloadedState: {
ui: {
selectedPage,
},
},
});
}
it("renders the WorkersPage component when workers page is selected", () => {
const store = buildStoreWithSelectedPage(PAGE_TYPES.SERVICE_WORKERS);
const wrapper = shallow(PageContainer({ store })).dive();
expect(wrapper).toMatchSnapshot();
});
it("renders nothing when no page is selected", () => {
const store = buildStoreWithSelectedPage(null);
const wrapper = shallow(PageContainer({ store })).dive();
expect(wrapper).toMatchSnapshot();
});
it("renders nothing when an invalid page is selected", () => {
const store = buildStoreWithSelectedPage("foo");
const wrapper = shallow(PageContainer({ store })).dive();
expect(wrapper).toMatchSnapshot();
});
});

Просмотреть файл

@ -0,0 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {
updateSelectedPage,
} = require("devtools/client/application/src/actions/ui.js");
const {
uiReducer,
UiState,
} = require("devtools/client/application/src/reducers/ui-state.js");
add_task(async function() {
info("Test ui reducer: UPDATE_SELECTED_PAGE action");
const state = UiState();
const action = updateSelectedPage("foo");
const newState = uiReducer(state, action);
equal(newState.selectedPage, "foo");
});

Просмотреть файл

@ -5,4 +5,5 @@ firefox-appdir = browser
skip-if = toolkit == 'android'
[test_page_reducer.js]
[test_ui_reducer.js]
[test_workers_reducer.js]