Skip to content

Commit

Permalink
Set page status for availability of an update
Browse files Browse the repository at this point in the history
Model this after cockpit-packagekit. ostree sends "change" events in
quick succession, and the first replies often don't include an available
update. To avoid flickering between "up to date" and "update available",
debounce the handler for 1s.

Rework the manifest to use a simple /updates path, and preload our page.

The test currently only works on fedora-coreos, as RHEL and CentOS
Atomic have a too old cockpit that doesn't support page statuses yet.

Closes #45
  • Loading branch information
martinpitt committed Jul 1, 2020
1 parent 8c0e5a1 commit f1e0d1f
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 8 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@patternfly/react-core": "3.158.3",
"moment": "2.27.0",
"react": "16.13.1",
"react-dom": "16.13.1"
"react-dom": "16.13.1",
"throttle-debounce": "2.2.1"
}
}
60 changes: 57 additions & 3 deletions src/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
DataToolbar, DataToolbarItem, DataToolbarContent,
} from '@patternfly/react-core/dist/esm/experimental';
import moment from 'moment';
import { debounce } from 'throttle-debounce';

import cockpit from 'cockpit';

Expand All @@ -65,6 +66,44 @@ function track_id(item) {
return key;
}

function format_version(deployment) {
var formated = "";
if (!deployment || !deployment.osname)
return;

if (deployment.version)
formated = deployment.version.v;

return cockpit.format("$0 $1", deployment.osname.v, formated);
}

// https://github.com/cockpit-project/cockpit/blob/master/pkg/lib/notifications.js
function set_page_status(status) {
cockpit.transport.control("notify", { page_status: status });
}

/* client.changed often happens several times at the start, avoid flickering */
const set_update_status = debounce(1000, versions => {
if (versions && versions.length > 0) {
/* if the latest version is booted, we are current */
if (versions[0].booted && versions[0].booted.v) {
set_page_status({
title: _("System is up to date"),
details: { icon: "fa fa-check-circle-o" }
});
} else {
/* report the available update */
set_page_status({
title: cockpit.format(_("Update available: $0"), format_version(versions[0])),
type: "warning",
});
}
} else {
console.warn("got invalid client.known_versions_for() result:", JSON.stringify(versions));
set_page_status(null);
}
});

/**
* Empty state for connecting and errors
*/
Expand Down Expand Up @@ -414,13 +453,26 @@ class Application extends React.Component {
}

this.setState({ curtain: { state: 'failed', failure: true, message, final } });
set_page_status(null);
};

client.addEventListener("connectionLost", (event, ex) => show_failure(ex));
client.addEventListener("changed", () => this.forceUpdate());

client.connect()
.then(() => { timeout = window.setTimeout(check_empty, 1000) })
.then(() => {
timeout = window.setTimeout(check_empty, 1000);

/* notify overview card */
set_page_status({
type: null,
title: _("Checking for package updates..."),
details: {
link: false,
icon: "spinner spinner-xs",
},
});
})
.fail(ex => {
window.clearTimeout(timeout);
show_failure(ex);
Expand Down Expand Up @@ -495,8 +547,10 @@ class Application extends React.Component {
/* TODO: support more than one OS */

/* successful, deployments are available */
const items = client.known_versions_for(this.state.os, this.state.origin.remote, this.state.origin.branch)
.map(item => {
const versions = client.known_versions_for(this.state.os, this.state.origin.remote, this.state.origin.branch);
set_update_status(versions);

const items = versions.map(item => {
const packages = client.packages(item);
if (packages)
packages.addEventListener("changed", () => this.setState({})); // re-render
Expand Down
9 changes: 5 additions & 4 deletions src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
},

"tools": {
"ostree": {
"label": "Software Updates",
"path": "index.html"
"index": {
"label": "Software Updates"
}
}
},

"preload": [ "index" ]
}
41 changes: 41 additions & 0 deletions test/check-ostree
Original file line number Diff line number Diff line change
Expand Up @@ -651,5 +651,46 @@ class OstreeCase(MachineCase):
self.assertIn("Reconnect", b.text(".pf-c-empty-state button"))
self.allow_authorize_journal_messages()

@skipImage("Too old cockpit-system", "rhel-atomic", "continuous-atomic")
def testPageStatus(self):
m = self.machine
b = self.browser

rhsmcertd_hack(m)

# preloading works, no updates available
self.login_and_go("/system")
b.wait_text("#page_status_notification_updates", "System is up to date")
self.assertEqual(b.attr("#page_status_notification_updates span:first-child", "class"),
"fa fa-check-circle-o")
# go to updates page
b.click("#page_status_notification_updates a")
b.enter_page("/updates")

# now generate an update
remove_pkg = m.execute("rpm -qa | grep socat").strip()
generate_new_commit(m, remove_pkg)
m.upload(["files/publickey.asc"], "/root/")
m.execute("ostree remote gpg-import local -k /root/publickey.asc")

# updates page sees the new version
b.click("#check-for-updates-btn")
b.wait_in_text(get_list_item(1) + " .version", "cockpit-base.2")

# overview page notices the new version as well
b.go("/system")
b.enter_page("/system")
b.wait_in_text("#page_status_notification_updates", "Update available:")
b.wait_in_text("#page_status_notification_updates", "cockpit-base.2")

# check with new session
b.logout()
self.login_and_go("/system")
b.wait_in_text("#page_status_notification_updates", "Update available:")
b.wait_in_text("#page_status_notification_updates", "cockpit-base.2")

self.allow_authorize_journal_messages()


if __name__ == "__main__":
test_main()

0 comments on commit f1e0d1f

Please sign in to comment.