diff --git a/src/data/supervisor/root.ts b/src/data/supervisor/root.ts new file mode 100644 index 0000000000..51fe449ecd --- /dev/null +++ b/src/data/supervisor/root.ts @@ -0,0 +1,58 @@ +import { HomeAssistant } from "../../types"; + +interface SupervisorBaseAvailableUpdates { + panel_path?: string; + update_type?: string; + version_latest?: string; +} + +interface SupervisorAddonAvailableUpdates + extends SupervisorBaseAvailableUpdates { + update_type?: "addon"; + icon?: string; + name?: string; +} + +interface SupervisorCoreAvailableUpdates + extends SupervisorBaseAvailableUpdates { + update_type?: "core"; +} + +interface SupervisorOsAvailableUpdates extends SupervisorBaseAvailableUpdates { + update_type?: "os"; +} + +interface SupervisorSupervisorAvailableUpdates + extends SupervisorBaseAvailableUpdates { + update_type?: "supervisor"; +} + +export type SupervisorAvailableUpdates = + | SupervisorAddonAvailableUpdates + | SupervisorCoreAvailableUpdates + | SupervisorOsAvailableUpdates + | SupervisorSupervisorAvailableUpdates; + +export interface SupervisorAvailableUpdatesResponse { + available_updates: SupervisorAvailableUpdates[]; +} + +export const fetchSupervisorAvailableUpdates = async ( + hass: HomeAssistant +): Promise => + ( + await hass.callWS({ + type: "supervisor/api", + endpoint: "/available_updates", + method: "get", + }) + ).available_updates; + +export const refreshSupervisorAvailableUpdates = async ( + hass: HomeAssistant +): Promise => + hass.callWS({ + type: "supervisor/api", + endpoint: "/refresh_updates", + method: "post", + }); diff --git a/src/data/supervisor/supervisor.ts b/src/data/supervisor/supervisor.ts index 20926b50ce..1a38c4cbe2 100644 --- a/src/data/supervisor/supervisor.ts +++ b/src/data/supervisor/supervisor.ts @@ -70,42 +70,6 @@ export interface Supervisor { localize: LocalizeFunc; } -interface SupervisorBaseAvailableUpdates { - panel_path?: string; - update_type?: string; - version_latest?: string; -} - -interface SupervisorAddonAvailableUpdates - extends SupervisorBaseAvailableUpdates { - update_type?: "addon"; - icon?: string; - name?: string; -} - -interface SupervisorCoreAvailableUpdates - extends SupervisorBaseAvailableUpdates { - update_type?: "core"; -} - -interface SupervisorOsAvailableUpdates extends SupervisorBaseAvailableUpdates { - update_type?: "os"; -} - -interface SupervisorSupervisorAvailableUpdates - extends SupervisorBaseAvailableUpdates { - update_type?: "supervisor"; -} - -export type SupervisorAvailableUpdates = - | SupervisorAddonAvailableUpdates - | SupervisorCoreAvailableUpdates - | SupervisorOsAvailableUpdates - | SupervisorSupervisorAvailableUpdates; - -export interface SupervisorAvailableUpdatesResponse { - available_updates: SupervisorAvailableUpdates[]; -} export const supervisorApiWsRequest = ( conn: Connection, request: supervisorApiRequest @@ -175,14 +139,3 @@ export const subscribeSupervisorEvents = ( getSupervisorEventCollection(hass.connection, key, endpoint).subscribe( onChange ); - -export const fetchSupervisorAvailableUpdates = async ( - hass: HomeAssistant -): Promise => - ( - await hass.callWS({ - type: "supervisor/api", - endpoint: "/supervisor/available_updates", - method: "get", - }) - ).available_updates; diff --git a/src/panels/config/dashboard/ha-config-dashboard.ts b/src/panels/config/dashboard/ha-config-dashboard.ts index 003e74bcae..7668df18fa 100644 --- a/src/panels/config/dashboard/ha-config-dashboard.ts +++ b/src/panels/config/dashboard/ha-config-dashboard.ts @@ -1,4 +1,6 @@ -import { mdiCloudLock, mdiMagnify } from "@mdi/js"; +import { mdiCloudLock, mdiDotsVertical, mdiMagnify } from "@mdi/js"; +import "@material/mwc-list/mwc-list-item"; +import type { ActionDetail } from "@material/mwc-list"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import { @@ -13,9 +15,14 @@ import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../components/ha-card"; import "../../../components/ha-icon-next"; +import "../../../components/ha-icon-button"; import "../../../components/ha-menu-button"; +import "../../../components/ha-button-menu"; import { CloudStatus } from "../../../data/cloud"; -import { SupervisorAvailableUpdates } from "../../../data/supervisor/supervisor"; +import { + refreshSupervisorAvailableUpdates, + SupervisorAvailableUpdates, +} from "../../../data/supervisor/root"; import { showQuickBar } from "../../../dialogs/quick-bar/show-dialog-quick-bar"; import { ExternalConfig, @@ -28,6 +35,8 @@ import "../ha-config-section"; import { configSections } from "../ha-panel-config"; import "./ha-config-navigation"; import "./ha-config-updates"; +import { fireEvent } from "../../../common/dom/fire_event"; +import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; @customElement("ha-config-dashboard") class HaConfigDashboard extends LitElement { @@ -40,6 +49,7 @@ class HaConfigDashboard extends LitElement { @property() public cloudStatus?: CloudStatus; + // null means not available @property() public supervisorUpdates?: SupervisorAvailableUpdates[] | null; @property() public showAdvanced!: boolean; @@ -70,6 +80,21 @@ class HaConfigDashboard extends LitElement { .path=${mdiMagnify} @click=${this._showQuickBar} > + + + + + ${this.hass.localize("ui.panel.config.updates.check_updates")} + + @@ -78,9 +103,9 @@ class HaConfigDashboard extends LitElement { .isWide=${this.isWide} full-width > - ${isComponentLoaded(this.hass, "hassio") && - this.supervisorUpdates === undefined - ? html`` + ${this.supervisorUpdates === undefined + ? // Hide everything until updates loaded + html`` : html`${this.supervisorUpdates?.length ? html` ) { + switch (ev.detail.index) { + case 0: + if (isComponentLoaded(this.hass, "hassio")) { + await refreshSupervisorAvailableUpdates(this.hass); + fireEvent(this, "ha-refresh-supervisor"); + return; + } + showAlertDialog(this, { + title: this.hass.localize( + "ui.panel.config.updates.check_unavailable.title" + ), + text: this.hass.localize( + "ui.panel.config.updates.check_unavailable.description" + ), + warning: true, + }); + break; + } + } + static get styles(): CSSResultGroup { return [ haStyle, diff --git a/src/panels/config/dashboard/ha-config-updates.ts b/src/panels/config/dashboard/ha-config-updates.ts index 5d94cccee2..418388bfbb 100644 --- a/src/panels/config/dashboard/ha-config-updates.ts +++ b/src/panels/config/dashboard/ha-config-updates.ts @@ -7,7 +7,7 @@ import { customElement, property, state } from "lit/decorators"; import "../../../components/ha-alert"; import "../../../components/ha-logo-svg"; import "../../../components/ha-svg-icon"; -import { SupervisorAvailableUpdates } from "../../../data/supervisor/supervisor"; +import { SupervisorAvailableUpdates } from "../../../data/supervisor/root"; import { buttonLinkStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import "../../../components/ha-icon-next"; diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index fa83f43105..6511ac47d2 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -32,7 +32,7 @@ import { CloudStatus, fetchCloudStatus } from "../../data/cloud"; import { fetchSupervisorAvailableUpdates, SupervisorAvailableUpdates, -} from "../../data/supervisor/supervisor"; +} from "../../data/supervisor/root"; import "../../layouts/hass-loading-screen"; import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page"; import { PageNavigation } from "../../layouts/hass-tabs-subpage"; @@ -42,6 +42,7 @@ declare global { // for fire event interface HASSDomEvents { "ha-refresh-cloud-status": undefined; + "ha-refresh-supervisor": undefined; } } @@ -446,6 +447,9 @@ class HaPanelConfig extends HassRouterPage { } if (isComponentLoaded(this.hass, "hassio")) { this._loadSupervisorUpdates(); + this.addEventListener("ha-refresh-supervisor", () => { + this._loadSupervisorUpdates(); + }); this.addEventListener("connection-status", (ev) => { if (ev.detail === "connected") { this._loadSupervisorUpdates(); diff --git a/src/translations/en.json b/src/translations/en.json index 2be6d3253a..42786857d5 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -998,6 +998,11 @@ "learn_more": "Learn more" }, "updates": { + "check_unavailable": { + "title": "Unable to check for updates", + "description": "You need to run the Home Assistant operating system to be able to check and install updates from the Home Assistant user interface." + }, + "check_updates": "Check for updates", "title": "{count} {count, plural,\n one {update}\n other {updates}\n}", "unable_to_fetch": "Unable to load updates", "version_available": "Version {version_available} is available",