Bug 1450067 - Show last update timestamp for a sw. r=nchevobbe
MozReview-Commit-ID: rul88NKcHZ
--- a/devtools/client/application/src/components/Worker.css
+++ b/devtools/client/application/src/components/Worker.css
@@ -4,16 +4,17 @@
/*
* The current layout of a service worker item is
*
* +----------------------------+----------------+
* | Service worker scope | Unregister_btn |
* +---+----------+-------------+----------------|
* | "Source" | script_name debug_link |
+ | | "Updated" update_time |
* |--------------+-------------+----------------|
* | "Status" | status start_link |
* +---+----------+-------------+----------------|
*/
.worker {
display: grid;
grid-template-rows: auto auto auto;
@@ -26,17 +27,17 @@
font-size: 1.2rem;
}
.worker:first-child {
padding-top: 0;
}
.worker:not(:last-child) {
- border-bottom: 1px solid var(--grey-30);
+ border-bottom: 1px solid var(--theme-body-color-alt);
}
.worker__header {
grid-column: 1/3;
display: grid;
grid-template-columns: 1fr auto;
grid-column-gap: 2rem;
align-items: center;
@@ -44,27 +45,31 @@
.worker__scope {
font-weight: bold;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
+.worker__meta-name {
+ color: var(--grey-50);
+ padding-inline-start: 4.5rem;
+}
+
.worker__data {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 1rem;
}
.worker__data > * {
margin: 0;
}
-.worker__meta-name {
- color: var(--grey-50);
- padding-inline-start: 4.5rem;
+.worker__data__updated {
+ color: var(--theme-body-color-alt);
}
.worker__unregister-button {
/* TODO: remove this once/if we have proper capitalization in the strings file */
text-transform: capitalize;
}
--- a/devtools/client/application/src/components/Worker.js
+++ b/devtools/client/application/src/components/Worker.js
@@ -1,17 +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 { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const { a, button, dd, dl, dt, header, li, section, span } = require("devtools/client/shared/vendor/react-dom-factories");
+const { a, br, button, dd, dl, dt, header, li, section, span, time } =
+ require("devtools/client/shared/vendor/react-dom-factories");
const Services = require("Services");
const { getUnicodeUrl, getUnicodeUrlPath } = require("devtools/client/shared/unicode-url");
loader.lazyRequireGetter(this, "DebuggerClient",
"devtools/shared/client/debugger-client", true);
loader.lazyRequireGetter(this, "gDevToolsBrowser",
"devtools/client/framework/devtools-browser", true);
@@ -131,32 +132,41 @@ class Worker extends Component {
},
Strings.GetStringFromName("debug"));
const startLink = !this.isRunning() ?
a({ onClick: this.start, className: "worker__start-link" },
Strings.GetStringFromName("start"))
: null;
+ const lastUpdated = worker.lastUpdateTime
+ ? span({ className: "worker__data__updated" },
+ "Updated ",
+ time({ className: "js-sw-updated"},
+ new Date(worker.lastUpdateTime / 1000).toLocaleString()))
+ : null;
+
return li({ className: "worker js-sw-container" },
header(
{ className: "worker__header" },
span({ title: worker.scope, className: "worker__scope js-sw-scope" },
this.formatScope(worker.scope)),
section(
{ className: "worker__controls" },
unregisterButton),
),
dl(
{ className: "worker__data" },
dt({ className: "worker__meta-name" }, "Source"),
dd({},
span({ title: worker.scope, className: "js-source-url" },
this.formatSource(worker.url)),
- debugLink),
+ debugLink,
+ lastUpdated ? br({}) : null,
+ lastUpdated ? lastUpdated : null),
dt({ className: "worker__meta-name" }, "Status"),
dd({},
Strings.GetStringFromName(status).toLowerCase(),
startLink)
)
);
}
}
--- a/devtools/client/application/test/browser_application_panel_list-single-worker.js
+++ b/devtools/client/application/test/browser_application_panel_list-single-worker.js
@@ -28,16 +28,20 @@ add_task(async function() {
await waitUntil(() => workerContainer.querySelector(".js-unregister-button"));
let scopeEl = workerContainer.querySelector(".js-sw-scope");
let expectedScope = "example.com/browser/devtools/client/application/test/" +
"service-workers/";
ok(scopeEl.textContent.startsWith(expectedScope),
"Service worker has the expected scope");
+ let updatedEl = workerContainer.querySelector(".js-sw-updated");
+ ok(updatedEl.textContent.includes(`${new Date().getFullYear()}`),
+ "Service worker has a last updated time");
+
info("Unregister the service worker");
await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
let registration = await content.wrappedJSObject.sw;
registration.unregister();
});
info("Wait until the service worker is removed from the application panel");
await waitUntil(() => getWorkerContainers(doc).length === 0);
--- a/devtools/server/actors/worker.js
+++ b/devtools/server/actors/worker.js
@@ -301,17 +301,18 @@ protocol.ActorClassWithSpec(serviceWorke
url: registration.scriptSpec,
installingWorker,
waitingWorker,
activeWorker,
fetch: newestWorker && newestWorker.fetch,
// - In e10s: only active registrations are available.
// - In non-e10s: registrations always have at least one worker, if the worker is
// active, the registration is active.
- active: isE10s ? true : !!activeWorker
+ active: isE10s ? true : !!activeWorker,
+ lastUpdateTime: registration.lastUpdateTime,
};
},
destroy() {
protocol.Actor.prototype.destroy.call(this);
Services.obs.removeObserver(this, PushService.subscriptionModifiedTopic);
this._registration.removeListener(this);
this._registration = null;
--- a/devtools/shared/client/root-client.js
+++ b/devtools/shared/client/root-client.js
@@ -143,17 +143,18 @@ RootClient.prototype = {
registrations.forEach(form => {
result.service.push({
name: form.url,
url: form.url,
scope: form.scope,
fetch: form.fetch,
registrationActor: form.actor,
- active: form.active
+ active: form.active,
+ lastUpdateTime: form.lastUpdateTime
});
});
workers.forEach(form => {
let worker = {
name: form.url,
url: form.url,
workerActor: form.actor