From b61540ad3c81f295b4dea9cd94ff7d09d1282a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20G=C3=B6hrs?= Date: Tue, 9 May 2023 10:38:55 +0200 Subject: [PATCH] web: display notification if update available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is intended to nag the user into installing updates once they become available. Signed-off-by: Leonard Göhrs --- web/src/App.tsx | 2 + web/src/TacComponents.tsx | 188 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/web/src/App.tsx b/web/src/App.tsx index 221f9a9a..b57af7d6 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -32,6 +32,7 @@ import { useMqttSubscription } from "./mqtt"; import { ApiPickerButton, MqttButton } from "./MqttComponents"; import { RebootNotification, + UpdateNotification, ProgressNotification, LocatorNotification, } from "./TacComponents"; @@ -134,6 +135,7 @@ function Notifications() { + ); diff --git a/web/src/TacComponents.tsx b/web/src/TacComponents.tsx index 857007cb..6d5247f1 100644 --- a/web/src/TacComponents.tsx +++ b/web/src/TacComponents.tsx @@ -20,12 +20,15 @@ import { useEffect, useState, useRef } from "react"; import Alert from "@cloudscape-design/components/alert"; import Box from "@cloudscape-design/components/box"; import Cards from "@cloudscape-design/components/cards"; +import Checkbox from "@cloudscape-design/components/checkbox"; import ColumnLayout from "@cloudscape-design/components/column-layout"; import Container from "@cloudscape-design/components/container"; +import Form from "@cloudscape-design/components/form"; import Header from "@cloudscape-design/components/header"; import ProgressBar from "@cloudscape-design/components/progress-bar"; import SpaceBetween from "@cloudscape-design/components/space-between"; import Spinner from "@cloudscape-design/components/spinner"; +import Table from "@cloudscape-design/components/table"; import { MqttButton } from "./MqttComponents"; import { useMqttSubscription } from "./mqtt"; @@ -86,6 +89,27 @@ enum RaucInstallStep { Done, } +type Duration = { + secs: number; + nanos: number; +}; + +type UpstreamBundle = { + compatible: string; + version: string; + newer_than_installed: boolean; +}; + +type Channel = { + name: string; + display_name: string; + description: string; + url: string; + polling_interval?: Duration; + enabled: boolean; + bundle?: UpstreamBundle; +}; + export function SlotStatus() { const slot_status = useMqttSubscription("/v1/tac/update/slots"); @@ -179,6 +203,123 @@ export function SlotStatus() { } } +export function UpdateChannels() { + const channels_topic = useMqttSubscription>( + "/v1/tac/update/channels" + ); + + const channels = channels_topic !== undefined ? channels_topic : []; + + return ( + + Update Channels + + } + footer={ + + Reload + + } + /> + } + columnDefinitions={[ + { + id: "name", + header: "Name", + cell: (e) => e.display_name, + }, + { + id: "enabled", + header: "Enabled", + cell: (e) => , + }, + { + id: "description", + header: "Description", + cell: (e) => ( + + {e.description.split("\n").map((p) => ( + {p} + ))} + + ), + }, + { + id: "interval", + header: "Update Interval", + cell: (e) => { + if (!e.polling_interval) { + return "Never"; + } + + let seconds = e.polling_interval.secs; + let minutes = seconds / 60; + let hours = minutes / 60; + let days = hours / 24; + + if (Math.floor(days) === days) { + return days === 1 ? "Daily" : `Every ${days} Days`; + } + + if (Math.floor(hours) === hours) { + return hours === 1 ? "Hourly" : `Every ${hours} Hours`; + } + + if (Math.floor(days) === days) { + return minutes === 1 + ? "Once a minute" + : `Every ${minutes} Minutes`; + } + + return `Every ${seconds} Seconds`; + }, + }, + { + id: "upgrade", + header: "Upgrade", + cell: (e) => { + if (!e.enabled) { + return "Not enabled"; + } + + if (!e.bundle) { + return ; + } + + if (!e.bundle.newer_than_installed) { + return "Up to date"; + } + + return ( + + Upgrade + + ); + }, + }, + ]} + items={channels} + sortingDisabled + trackBy="name" + /> + ); +} + export function ProgressNotification() { const operation = useMqttSubscription("/v1/tac/update/operation"); const progress = useMqttSubscription("/v1/tac/update/progress"); @@ -275,12 +416,59 @@ export function UpdateContainer() { } > + ); } +export function UpdateNotification() { + const channels = useMqttSubscription>( + "/v1/tac/update/channels" + ); + + let updates = []; + + if (channels !== undefined) { + for (let ch of channels) { + if (ch.enabled && ch.bundle && ch.bundle.newer_than_installed) { + updates.push(ch); + } + } + } + + const install_buttons = updates.map((u) => ( + + Install new {u.display_name} bundle + + )); + + let text = + "There is a new operating system update available for installation"; + + if (updates.length > 1) { + text = + "There are new operating system updates available available for installation"; + } + + return ( + 0} + action={{install_buttons}} + header="Update your LXA TAC" + > + {text} + + ); +} + export function LocatorNotification() { const locator = useMqttSubscription("/v1/tac/display/locator");