diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /devtools/client/application/src/components/service-workers | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/application/src/components/service-workers')
9 files changed, 876 insertions, 0 deletions
diff --git a/devtools/client/application/src/components/service-workers/Registration.css b/devtools/client/application/src/components/service-workers/Registration.css new file mode 100644 index 0000000000..84b6de58e1 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/Registration.css @@ -0,0 +1,73 @@ +/* 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/. */ + +/* + * The current layout of a registration is + * + * +------+----------------------+----------------+ + * | Header - scope + timestamp | Unregister_btn | + * +------+----------------------+----------------| + * | worker 1 | + | worker 2 | + | ... | + +----------------------------------------------+ + | Unregister btn | + +----------------------------------------------+ + */ + +.registration { + line-height: 1.5; + font-size: var(--body-10-font-size); + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + grid-template-rows: minmax(calc(var(--base-unit) * 6), auto) 1fr auto; + grid-column-gap: calc(4 * var(--base-unit)); + grid-row-gap: calc(2 * var(--base-unit)); + grid-template-areas: "header header-controls" + "workers workers" + "footer-controls footer-controls"; +} + +/* vertical layout */ +@media(max-width: 700px) { + .registration__controls { + grid-area: footer-controls; + justify-self: end; + } +} + +/* wide layout */ +@media(min-width: 701px) { + .registration__controls { + grid-area: header-controls; + } +} + +.registration__header { + grid-area: header; +} + +.registration__scope { + font-size: var(--title-10-font-size); + font-weight: var(--title-10-font-weight); + user-select: text; + margin: 0; + + grid-area: scope; +} + +.registration__updated-time { + color: var(--theme-text-color-alt); + grid-area: timestamp; +} + +.registration__workers { + grid-area: workers; + list-style-type: none; + padding: 0; +} + +.registration__workers-item:not(:first-child) { + margin-block-start: calc(var(--base-unit) * 2); +} diff --git a/devtools/client/application/src/components/service-workers/Registration.js b/devtools/client/application/src/components/service-workers/Registration.js new file mode 100644 index 0000000000..97569f57e2 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/Registration.js @@ -0,0 +1,153 @@ +/* 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("resource://devtools/client/shared/vendor/react.js"); + +const { + connect, +} = require("resource://devtools/client/shared/vendor/react-redux.js"); +const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); + +const { + article, + aside, + h2, + header, + li, + p, + time, + ul, +} = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); + +const { + getUnicodeUrl, +} = require("resource://devtools/client/shared/unicode-url.js"); + +const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); +const Localized = createFactory(FluentReact.Localized); + +const Types = require("resource://devtools/client/application/src/types/index.js"); + +const { + unregisterWorker, +} = require("resource://devtools/client/application/src/actions/workers.js"); + +const UIButton = createFactory( + require("resource://devtools/client/application/src/components/ui/UIButton.js") +); + +const Worker = createFactory( + require("resource://devtools/client/application/src/components/service-workers/Worker.js") +); + +/** + * This component is dedicated to display a service worker registration, along + * the list of attached workers to it. + * It displays information about the registration as well as an Unregister + * button. + */ +class Registration extends PureComponent { + static get propTypes() { + return { + className: PropTypes.string, + isDebugEnabled: PropTypes.bool.isRequired, + registration: PropTypes.shape(Types.registration).isRequired, + // this prop get automatically injected via `connect` + dispatch: PropTypes.func.isRequired, + }; + } + + constructor(props) { + super(props); + + this.unregister = this.unregister.bind(this); + } + + unregister() { + this.props.dispatch(unregisterWorker(this.props.registration)); + } + + isActive() { + const { workers } = this.props.registration; + return workers.some( + x => x.state === Ci.nsIServiceWorkerInfo.STATE_ACTIVATED + ); + } + + formatScope(scope) { + const [, remainder] = getUnicodeUrl(scope).split("://"); + // remove the last slash from the url, if present + // or return the full scope if there's no remainder + return remainder ? remainder.replace(/\/$/, "") : scope; + } + + render() { + const { registration, isDebugEnabled, className } = this.props; + + const unregisterButton = this.isActive() + ? Localized( + { id: "serviceworker-worker-unregister" }, + UIButton({ + onClick: this.unregister, + className: "js-unregister-button", + }) + ) + : null; + + const lastUpdated = registration.lastUpdateTime + ? Localized( + { + id: "serviceworker-worker-updated", + // XXX: $date should normally be a Date object, but we pass the timestamp as a + // workaround. See Bug 1465718. registration.lastUpdateTime is in microseconds, + // convert to a valid timestamp in milliseconds by dividing by 1000. + $date: registration.lastUpdateTime / 1000, + time: time({ className: "js-sw-updated" }), + }, + p({ className: "registration__updated-time" }) + ) + : null; + + const scope = h2( + { + title: registration.scope, + className: "registration__scope js-sw-scope devtools-ellipsis-text", + }, + this.formatScope(registration.scope) + ); + + return li( + { className: className ? className : "" }, + article( + { className: "registration js-sw-container" }, + header({ className: "registration__header" }, scope, lastUpdated), + aside({ className: "registration__controls" }, unregisterButton), + // render list of workers + ul( + { className: "registration__workers" }, + registration.workers.map(worker => { + return li( + { + key: worker.id, + className: "registration__workers-item", + }, + Worker({ + worker, + isDebugEnabled, + }) + ); + }) + ) + ) + ); + } +} + +const mapDispatchToProps = dispatch => ({ dispatch }); +module.exports = connect(mapDispatchToProps)(Registration); diff --git a/devtools/client/application/src/components/service-workers/RegistrationList.css b/devtools/client/application/src/components/service-workers/RegistrationList.css new file mode 100644 index 0000000000..021ed7e351 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/RegistrationList.css @@ -0,0 +1,54 @@ +/* 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/. */ + +.aboutdebugging-plug { + padding-block: calc(var(--base-unit) * 3); + border-block-start: 1px solid var(--separator-color); + + /* display flex to handle showing the icon with ::before */ + display: flex; + flex-direction: row; + column-gap: calc(var(--base-unit) * 2); + align-items: baseline; + font-size: var(--body-10-font-size); + font-weight: var(--body-10-font-weight); +} + +.aboutdebugging-plug::before { + flex: 0 0 auto; + width: calc(var(--base-unit) * 4); + height: calc(var(--base-unit) * 4); + content: ""; + -moz-context-properties: fill; + fill: currentColor; + background-image: url(chrome://global/skin/icons/developer.svg); + /* the icon size is taller than the line-height of the text. Since the + text can occupy multiple lines, and we want to keep the icon aligned + with respect to the first line, instead of align-items: center in + .aboutdebugging-plug, we use baseline, and fine tune the position here. */ + position: relative; + top: 3px; +} + +.registrations-container { + flex-grow: 1; +} + +.registrations-container__list { + padding-inline-start: 0; +} + +.registrations-container__item { + list-style-type: none; + margin: 0; + padding: calc(var(--base-unit) * 5) 0; +} + +.registrations-container__item:first-child { + padding-top: 0; +} + +.registrations-container__item:not(:last-child) { + border-bottom: 1px solid var(--separator-color); +} diff --git a/devtools/client/application/src/components/service-workers/RegistrationList.js b/devtools/client/application/src/components/service-workers/RegistrationList.js new file mode 100644 index 0000000000..ed89c9cff3 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/RegistrationList.js @@ -0,0 +1,92 @@ +/* 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 { + openTrustedLink, +} = require("resource://devtools/client/shared/link.js"); +const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); +const { + createFactory, + PureComponent, +} = require("resource://devtools/client/shared/vendor/react.js"); +const { + a, + article, + footer, + h1, + p, + ul, +} = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); + +const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); +const Localized = createFactory(FluentReact.Localized); + +const Types = require("resource://devtools/client/application/src/types/index.js"); +const Registration = createFactory( + require("resource://devtools/client/application/src/components/service-workers/Registration.js") +); + +/** + * This component handles the list of service workers displayed in the application panel + * and also displays a suggestion to use about debugging for debugging other service + * workers. + */ +class RegistrationList extends PureComponent { + static get propTypes() { + return { + canDebugWorkers: PropTypes.bool.isRequired, + registrations: Types.registrationArray.isRequired, + }; + } + + render() { + const { canDebugWorkers, registrations } = this.props; + + return [ + article( + { + className: "registrations-container", + key: "registrations-container", + }, + Localized( + { id: "serviceworker-list-header" }, + h1({ + className: "app-page__title", + }) + ), + ul( + { className: "registrations-container__list" }, + registrations.map(registration => + Registration({ + key: registration.id, + isDebugEnabled: canDebugWorkers, + registration, + className: "registrations-container__item", + }) + ) + ) + ), + + footer( + { className: "aboutdebugging-plug" }, + Localized( + { + id: "serviceworker-list-aboutdebugging", + key: "serviceworkerlist-footer", + a: a({ + className: "aboutdebugging-plug__link", + onClick: () => openTrustedLink("about:debugging#workers"), + }), + }, + p({}) + ) + ), + ]; + } +} + +// Exports +module.exports = RegistrationList; diff --git a/devtools/client/application/src/components/service-workers/RegistrationListEmpty.js b/devtools/client/application/src/components/service-workers/RegistrationListEmpty.js new file mode 100644 index 0000000000..2454f121e8 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/RegistrationListEmpty.js @@ -0,0 +1,122 @@ +/* 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 { + openDocLink, + openTrustedLink, +} = require("resource://devtools/client/shared/link.js"); +const { + createFactory, + PureComponent, +} = require("resource://devtools/client/shared/vendor/react.js"); +const { + a, + article, + aside, + div, + h1, + img, + p, +} = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); + +const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); +const Localized = createFactory(FluentReact.Localized); + +const { + services, +} = require("resource://devtools/client/application/src/modules/application-services.js"); + +const DOC_URL = + "https://developer.mozilla.org/docs/Web/API/Service_Worker_API/Using_Service_Workers" + + "?utm_source=devtools&utm_medium=sw-panel-blank"; + +/** + * This component displays help information when no service workers are found for the + * current target. + */ +class RegistrationListEmpty extends PureComponent { + switchToConsole() { + services.selectTool("webconsole"); + } + + switchToDebugger() { + services.selectTool("jsdebugger"); + } + + openAboutDebugging() { + openTrustedLink("about:debugging#workers"); + } + + openDocumentation() { + openDocLink(DOC_URL); + } + + render() { + return article( + { className: "app-page__icon-container js-registration-list-empty" }, + aside( + {}, + Localized( + { + id: "sidebar-item-service-workers", + attrs: { + alt: true, + }, + }, + img({ + className: "app-page__icon", + src: "chrome://devtools/skin/images/debugging-workers.svg", + }) + ) + ), + div( + {}, + Localized( + { + id: "serviceworker-empty-intro2", + }, + h1({ className: "app-page__title" }) + ), + Localized( + { + id: "serviceworker-empty-suggestions2", + a: a({ + onClick: () => this.switchToConsole(), + }), + // NOTE: for <Localized> to parse the markup in the string, the + // markup needs to be actual HTML elements + span: a({ + onClick: () => this.switchToDebugger(), + }), + }, + p({}) + ), + p( + {}, + Localized( + { id: "serviceworker-empty-intro-link" }, + a({ + onClick: () => this.openDocumentation(), + }) + ) + ), + p( + {}, + Localized( + { id: "serviceworker-empty-suggestions-aboutdebugging2" }, + a({ + className: "js-trusted-link", + onClick: () => this.openAboutDebugging(), + }) + ) + ) + ) + ); + } +} + +// Exports +module.exports = RegistrationListEmpty; diff --git a/devtools/client/application/src/components/service-workers/Worker.css b/devtools/client/application/src/components/service-workers/Worker.css new file mode 100644 index 0000000000..e44b49ef6b --- /dev/null +++ b/devtools/client/application/src/components/service-workers/Worker.css @@ -0,0 +1,75 @@ +/* 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/. */ + + /* + * The current layout of a service worker item is + * + * +------------+------------------------------+ + * | Worker | script_name | + * | Icon |------------------------------| + * | | status start_button | + * +------------+------------------------------+ + */ + +.worker { + display: grid; + grid-template-columns: auto 1fr; + grid-template-areas: "icon source" + "icon misc"; + column-gap: calc(var(--base-unit) * 2); + row-gap: var(--base-unit); + + line-height: calc(var(--base-unit) * 4); + font-size: var(--body-10-font-size); +} + +.worker__icon { + grid-area: icon; +} + +.worker__icon-image { + width: calc(var(--base-unit) * 4); + height: calc(var(--base-unit) * 4); +} + +.worker__source { + grid-area: source; + user-select: text; +} + +.worker__misc { + grid-area: misc; +} + +.worker__status { + text-transform: capitalize; + --status-bg-color: transparent; + --status-border-color: transparent; +} + +.worker__status::before { + content: ""; + margin-inline-end: var(--base-unit); + width: calc(var(--base-unit) * 2); + height: calc(var(--base-unit) * 2); + display: inline-block; + background: var(--status-bg-color); + border: 1px solid var(--status-border-color); + border-radius: 100%; +} + +.worker__status--active { + --status-bg-color: var(--green-60); + --status-border-color: var(--green-60); +} + +.worker__status--waiting { + --status-bg-color: var(--theme-text-color-alt); + --status-border-color: var(--theme-text-color-alt); +} + +.worker__status--installing, .worker__status--default { + --status-bg-color: transparent; + --status-border-color: var(--theme-text-color-alt); +} diff --git a/devtools/client/application/src/components/service-workers/Worker.js b/devtools/client/application/src/components/service-workers/Worker.js new file mode 100644 index 0000000000..bc95e084a9 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/Worker.js @@ -0,0 +1,225 @@ +/* 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("resource://devtools/client/shared/vendor/react.js"); + +const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); +const { + connect, +} = require("resource://devtools/client/shared/vendor/react-redux.js"); + +const { + a, + img, + p, + section, + span, +} = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); + +const { + getUnicodeUrlPath, +} = require("resource://devtools/client/shared/unicode-url.js"); + +const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); +const Localized = createFactory(FluentReact.Localized); +const { + l10n, +} = require("resource://devtools/client/application/src/modules/l10n.js"); + +const { + services, +} = require("resource://devtools/client/application/src/modules/application-services.js"); +const Types = require("resource://devtools/client/application/src/types/index.js"); + +const { + startWorker, +} = require("resource://devtools/client/application/src/actions/workers.js"); + +const UIButton = createFactory( + require("resource://devtools/client/application/src/components/ui/UIButton.js") +); + +/** + * This component is dedicated to display a worker, more accurately a service worker, in + * the list of workers displayed in the application panel. It displays information about + * the worker as well as action links and buttons to interact with the worker (e.g. debug, + * unregister, update etc...). + */ +class Worker extends PureComponent { + static get propTypes() { + return { + isDebugEnabled: PropTypes.bool.isRequired, + worker: PropTypes.shape(Types.worker).isRequired, + // this prop get automatically injected via `connect` + dispatch: PropTypes.func.isRequired, + }; + } + + constructor(props) { + super(props); + + this.debug = this.debug.bind(this); + this.viewSource = this.viewSource.bind(this); + this.start = this.start.bind(this); + } + + debug() { + if (!this.isRunning()) { + console.log("Service workers cannot be debugged if they are not running"); + return; + } + + services.openWorkerInDebugger(this.props.worker.workerDescriptorFront); + } + + viewSource() { + if (!this.isRunning()) { + console.log( + "Service workers cannot be inspected if they are not running" + ); + return; + } + + services.viewWorkerSource(this.props.worker.workerDescriptorFront); + } + + start() { + if (!this.isActive() || this.isRunning()) { + console.log("Running or inactive service workers cannot be started"); + return; + } + + this.props.dispatch(startWorker(this.props.worker)); + } + + isRunning() { + // We know the worker is running if it has a worker actor. + return !!this.props.worker.workerDescriptorFront; + } + + isActive() { + return this.props.worker.state === Ci.nsIServiceWorkerInfo.STATE_ACTIVATED; + } + + getLocalizedStatus() { + if (this.isActive() && this.isRunning()) { + return l10n.getString("serviceworker-worker-status-running"); + } else if (this.isActive()) { + return l10n.getString("serviceworker-worker-status-stopped"); + } + // NOTE: this is already localized by the service worker front + // (strings are in debugger.properties) + return this.props.worker.stateText; + } + + getClassNameForStatus(baseClass) { + const { state } = this.props.worker; + + switch (state) { + case Ci.nsIServiceWorkerInfo.STATE_PARSED: + case Ci.nsIServiceWorkerInfo.STATE_INSTALLING: + return "worker__status--installing"; + case Ci.nsIServiceWorkerInfo.STATE_INSTALLED: + case Ci.nsIServiceWorkerInfo.STATE_ACTIVATING: + return "worker__status--waiting"; + case Ci.nsIServiceWorkerInfo.STATE_ACTIVATED: + return "worker__status--active"; + } + + return "worker__status--default"; + } + + formatSource(source) { + const parts = source.split("/"); + return getUnicodeUrlPath(parts[parts.length - 1]); + } + + renderInspectLink(url) { + // avoid rendering the inspect link if sw is not running + const isDisabled = !this.isRunning(); + // view source instead of debugging when debugging sw is not available + const callbackFn = this.props.isDebugEnabled ? this.debug : this.viewSource; + + const sourceUrl = span( + { className: "js-source-url" }, + this.formatSource(url) + ); + + return isDisabled + ? sourceUrl + : a( + { + onClick: callbackFn, + title: url, + href: "#", + className: "js-inspect-link", + }, + sourceUrl, + "\u00A0", // + Localized( + { + id: "serviceworker-worker-inspect-icon", + attrs: { + alt: true, + }, + }, + img({ + src: "chrome://devtools/skin/images/application-debug.svg", + }) + ) + ); + } + + renderStartButton() { + // avoid rendering the button at all for workers that are either running, + // or in a state that prevents them from starting (like waiting) + if (this.isRunning() || !this.isActive()) { + return null; + } + + return Localized( + { id: "serviceworker-worker-start3" }, + UIButton({ + onClick: this.start, + className: `js-start-button`, + size: "micro", + }) + ); + } + + render() { + const { worker } = this.props; + const statusText = this.getLocalizedStatus(); + const statusClassName = this.getClassNameForStatus(); + + return section( + { className: "worker js-sw-worker" }, + p( + { className: "worker__icon" }, + img({ + className: "worker__icon-image", + src: "chrome://devtools/skin/images/debugging-workers.svg", + }) + ), + p({ className: "worker__source" }, this.renderInspectLink(worker.url)), + p( + { className: "worker__misc" }, + span( + { className: `js-worker-status worker__status ${statusClassName}` }, + statusText + ), + " ", + this.renderStartButton() + ) + ); + } +} + +const mapDispatchToProps = dispatch => ({ dispatch }); +module.exports = connect(mapDispatchToProps)(Worker); diff --git a/devtools/client/application/src/components/service-workers/WorkersPage.js b/devtools/client/application/src/components/service-workers/WorkersPage.js new file mode 100644 index 0000000000..a44dd292f8 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/WorkersPage.js @@ -0,0 +1,71 @@ +/* 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("resource://devtools/client/shared/vendor/react.js"); +const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); +const { + section, +} = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); +const { + connect, +} = require("resource://devtools/client/shared/vendor/react-redux.js"); + +const Types = require("resource://devtools/client/application/src/types/index.js"); +const RegistrationList = createFactory( + require("resource://devtools/client/application/src/components/service-workers/RegistrationList.js") +); +const RegistrationListEmpty = createFactory( + require("resource://devtools/client/application/src/components/service-workers/RegistrationListEmpty.js") +); + +class WorkersPage extends PureComponent { + static get propTypes() { + return { + // mapped from state + canDebugWorkers: PropTypes.bool.isRequired, + domain: PropTypes.string.isRequired, + registrations: Types.registrationArray.isRequired, + }; + } + + render() { + const { canDebugWorkers, domain, registrations } = this.props; + + // Filter out workers from other domains + const domainWorkers = registrations.filter( + x => !!x.workers.length && new URL(x.workers[0].url).hostname === domain + ); + const isListEmpty = domainWorkers.length === 0; + + return section( + { + className: `app-page js-service-workers-page ${ + isListEmpty ? "app-page--empty" : "" + }`, + }, + isListEmpty + ? RegistrationListEmpty({}) + : RegistrationList({ + canDebugWorkers, + registrations: domainWorkers, + }) + ); + } +} + +function mapStateToProps(state) { + return { + canDebugWorkers: state.workers.canDebugWorkers, + domain: state.page.domain, + registrations: state.workers.list, + }; +} + +// Exports +module.exports = connect(mapStateToProps)(WorkersPage); diff --git a/devtools/client/application/src/components/service-workers/moz.build b/devtools/client/application/src/components/service-workers/moz.build new file mode 100644 index 0000000000..f9704b9df8 --- /dev/null +++ b/devtools/client/application/src/components/service-workers/moz.build @@ -0,0 +1,11 @@ +# 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( + "Registration.js", + "RegistrationList.js", + "RegistrationListEmpty.js", + "Worker.js", + "WorkersPage.js", +) |