mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-02 05:57:54 +00:00
Use the update integration to provide updates
This commit is contained in:
parent
604b79696e
commit
9ea8e13c87
@ -45,7 +45,6 @@ import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box";
|
||||
import "../../../src/layouts/hass-loading-screen";
|
||||
import "../../../src/layouts/hass-subpage";
|
||||
import "../../../src/layouts/hass-tabs-subpage";
|
||||
import { SUPERVISOR_UPDATE_NAMES } from "../../../src/panels/config/dashboard/ha-config-updates";
|
||||
import { HomeAssistant, Route } from "../../../src/types";
|
||||
import { addonArchIsSupported, extractChangelog } from "../util/addon";
|
||||
|
||||
@ -57,6 +56,12 @@ declare global {
|
||||
|
||||
type updateType = "os" | "supervisor" | "core" | "addon";
|
||||
|
||||
const SUPERVISOR_UPDATE_NAMES = {
|
||||
core: "Home Assistant Core",
|
||||
os: "Home Assistant Operating System",
|
||||
supervisor: "Home Assistant Supervisor",
|
||||
};
|
||||
|
||||
const changelogUrl = (
|
||||
entry: updateType,
|
||||
version: string
|
||||
|
37
src/data/update.ts
Normal file
37
src/data/update.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export interface UpdateDescription {
|
||||
identifier: string;
|
||||
name: string;
|
||||
domain: string;
|
||||
current_version: string;
|
||||
available_version: string;
|
||||
changelog_content: string | null;
|
||||
changelog_url: string | null;
|
||||
icon_url: string | null;
|
||||
supports_backup: boolean;
|
||||
}
|
||||
|
||||
export interface SkipUpdateParams {
|
||||
domain: string;
|
||||
version: string;
|
||||
identifier: string;
|
||||
}
|
||||
|
||||
export interface PerformUpdateParams extends SkipUpdateParams {
|
||||
backup?: boolean;
|
||||
}
|
||||
|
||||
export const fetchUpdateInfo = (
|
||||
hass: HomeAssistant
|
||||
): Promise<UpdateDescription[]> => hass.callWS({ type: "update/info" });
|
||||
|
||||
export const skipUpdate = (
|
||||
hass: HomeAssistant,
|
||||
params: SkipUpdateParams
|
||||
): Promise<void> => hass.callWS({ type: "update/skip", ...params });
|
||||
|
||||
export const performUpdate = (
|
||||
hass: HomeAssistant,
|
||||
params: PerformUpdateParams
|
||||
): Promise<void> => hass.callWS({ type: "update/update", ...params });
|
211
src/dialogs/update-dialog/ha-update-dialog.ts
Normal file
211
src/dialogs/update-dialog/ha-update-dialog.ts
Normal file
@ -0,0 +1,211 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeRTL } from "../../common/util/compute_rtl";
|
||||
import "../../components/ha-alert";
|
||||
import "../../components/ha-checkbox";
|
||||
import "../../components/ha-circular-progress";
|
||||
import { createCloseHeading } from "../../components/ha-dialog";
|
||||
import "../../components/ha-faded";
|
||||
import "../../components/ha-formfield";
|
||||
import "../../components/ha-icon-button";
|
||||
import "../../components/ha-markdown";
|
||||
import {
|
||||
performUpdate,
|
||||
skipUpdate,
|
||||
UpdateDescription,
|
||||
} from "../../data/update";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { UpdateDialogParams } from "./show-ha-update-dialog";
|
||||
|
||||
@customElement("ha-update-dialog")
|
||||
export class HaUpdateDialog extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _opened = false;
|
||||
|
||||
@state() private _updating = false;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
@state() private _update!: UpdateDescription;
|
||||
|
||||
_refreshCallback!: () => void;
|
||||
|
||||
public async showDialog(dialogParams: UpdateDialogParams): Promise<void> {
|
||||
this._opened = true;
|
||||
this._update = dialogParams.update;
|
||||
this._refreshCallback = dialogParams.refreshCallback;
|
||||
}
|
||||
|
||||
public async closeDialog(): Promise<void> {
|
||||
this._opened = false;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._opened) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@closed=${this.closeDialog}
|
||||
scrimClickAction
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize("ui.panel.config.updates.dialog.title", {
|
||||
name: this._update.name,
|
||||
})
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error" .rtl=${computeRTL(this.hass)}>
|
||||
${this._error}
|
||||
</ha-alert>`
|
||||
: ""}
|
||||
${!this._updating
|
||||
? html`
|
||||
${this._update.changelog_content
|
||||
? html`
|
||||
<ha-faded>
|
||||
<ha-markdown .content=${this._update.changelog_content}>
|
||||
</ha-markdown>
|
||||
</ha-faded>
|
||||
`
|
||||
: ""}
|
||||
${this._update.changelog_url
|
||||
? html`<a href=${this._update.changelog_url} target="_blank">
|
||||
Full changelog
|
||||
</a> `
|
||||
: ""}
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.updates.dialog.description",
|
||||
{
|
||||
name: this._update.name,
|
||||
version: this._update.current_version,
|
||||
newest_version: this._update.available_version,
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
${this._update.supports_backup
|
||||
? html`
|
||||
<ha-formfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.updates.dialog.create_backup"
|
||||
)}
|
||||
>
|
||||
<ha-checkbox checked></ha-checkbox>
|
||||
</ha-formfield>
|
||||
`
|
||||
: ""}
|
||||
`
|
||||
: html`<ha-circular-progress alt="Updating" size="large" active>
|
||||
</ha-circular-progress>
|
||||
<p class="progress-text">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.updates.dialog.updating",
|
||||
{
|
||||
name: this._update.name,
|
||||
version: this._update.available_version,
|
||||
}
|
||||
)}
|
||||
</p>`}
|
||||
</div>
|
||||
${!this._updating
|
||||
? html`
|
||||
<mwc-button slot="secondaryAction" @click=${this._skipUpdate}>
|
||||
${this.hass.localize("ui.common.skip")}
|
||||
</mwc-button>
|
||||
<mwc-button
|
||||
.disabled=${this._updating}
|
||||
slot="primaryAction"
|
||||
@click=${this._performUpdate}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.updates.dialog.update")}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
get _shouldCreateBackup(): boolean {
|
||||
if (!this._update.supports_backup) {
|
||||
return false;
|
||||
}
|
||||
const checkbox = this.shadowRoot?.querySelector("ha-checkbox");
|
||||
if (checkbox) {
|
||||
return checkbox.checked;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _performUpdate() {
|
||||
this._error = undefined;
|
||||
this._updating = true;
|
||||
try {
|
||||
await performUpdate(this.hass, {
|
||||
domain: this._update.domain,
|
||||
identifier: this._update.identifier,
|
||||
version: this._update.available_version,
|
||||
backup: this._shouldCreateBackup,
|
||||
});
|
||||
} catch (err: any) {
|
||||
this._error = err.message;
|
||||
this._updating = false;
|
||||
return;
|
||||
}
|
||||
this._updating = false;
|
||||
this._refreshCallback();
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
private async _skipUpdate() {
|
||||
this._error = undefined;
|
||||
try {
|
||||
await skipUpdate(this.hass, {
|
||||
domain: this._update.domain,
|
||||
identifier: this._update.identifier,
|
||||
version: this._update.available_version,
|
||||
});
|
||||
} catch (err: any) {
|
||||
this._error = err.message;
|
||||
return;
|
||||
}
|
||||
|
||||
this._refreshCallback();
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-circular-progress {
|
||||
display: block;
|
||||
margin: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ha-markdown {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-update-dialog": HaUpdateDialog;
|
||||
}
|
||||
}
|
18
src/dialogs/update-dialog/show-ha-update-dialog.ts
Normal file
18
src/dialogs/update-dialog/show-ha-update-dialog.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { UpdateDescription } from "../../data/update";
|
||||
|
||||
export interface UpdateDialogParams {
|
||||
update: UpdateDescription;
|
||||
refreshCallback: () => void;
|
||||
}
|
||||
|
||||
export const showUpdateDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: UpdateDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "ha-update-dialog",
|
||||
dialogImport: () => import("./ha-update-dialog"),
|
||||
dialogParams,
|
||||
});
|
||||
};
|
@ -26,10 +26,6 @@ import "../../../components/ha-menu-button";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { CloudStatus } from "../../../data/cloud";
|
||||
import {
|
||||
refreshSupervisorAvailableUpdates,
|
||||
SupervisorAvailableUpdates,
|
||||
} from "../../../data/supervisor/root";
|
||||
import { showQuickBar } from "../../../dialogs/quick-bar/show-dialog-quick-bar";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
@ -38,10 +34,11 @@ 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";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import { UpdateDescription } from "../../../data/update";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
|
||||
const randomTip = (hass: HomeAssistant) => {
|
||||
const weighted: string[] = [];
|
||||
@ -114,14 +111,12 @@ class HaConfigDashboard extends LitElement {
|
||||
@property() public cloudStatus?: CloudStatus;
|
||||
|
||||
// null means not available
|
||||
@property() public supervisorUpdates?: SupervisorAvailableUpdates[] | null;
|
||||
@property() public updates?: UpdateDescription[] | null;
|
||||
|
||||
@property() public showAdvanced!: boolean;
|
||||
|
||||
@state() private _tip?: string;
|
||||
|
||||
private _notifyUpdates = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-app-layout>
|
||||
@ -160,20 +155,23 @@ class HaConfigDashboard extends LitElement {
|
||||
.isWide=${this.isWide}
|
||||
full-width
|
||||
>
|
||||
${this.supervisorUpdates === undefined
|
||||
? // Hide everything until updates loaded
|
||||
html``
|
||||
: html`${this.supervisorUpdates?.length
|
||||
${this.updates === undefined
|
||||
? html`<ha-alert .rtl=${computeRTL(this.hass)}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.updates.checking_updates"
|
||||
)}
|
||||
</ha-alert>`
|
||||
: this.updates?.length
|
||||
? html`<ha-card>
|
||||
<ha-config-updates
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.supervisorUpdates=${this.supervisorUpdates}
|
||||
.updates=${this.updates}
|
||||
></ha-config-updates>
|
||||
</ha-card>`
|
||||
: ""}
|
||||
<ha-card>
|
||||
${this.narrow && this.supervisorUpdates?.length
|
||||
${this.narrow && this.updates?.length
|
||||
? html`<div class="title">
|
||||
${this.hass.localize("panel.config")}
|
||||
</div>`
|
||||
@ -203,7 +201,7 @@ class HaConfigDashboard extends LitElement {
|
||||
.showAdvanced=${this.showAdvanced}
|
||||
.pages=${configSections.dashboard}
|
||||
></ha-config-navigation>
|
||||
</ha-card>`}
|
||||
</ha-card>
|
||||
<div class="tips">
|
||||
<ha-svg-icon .path=${mdiLightbulbOutline}></ha-svg-icon>
|
||||
<span class="tip-word">Tip!</span>
|
||||
@ -220,22 +218,6 @@ class HaConfigDashboard extends LitElement {
|
||||
if (!this._tip && changedProps.has("hass")) {
|
||||
this._tip = randomTip(this.hass);
|
||||
}
|
||||
|
||||
if (!changedProps.has("supervisorUpdates") || !this._notifyUpdates) {
|
||||
return;
|
||||
}
|
||||
this._notifyUpdates = false;
|
||||
if (this.supervisorUpdates?.length) {
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.config.updates.updates_refreshed"
|
||||
),
|
||||
});
|
||||
} else {
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.panel.config.updates.no_new_updates"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _showQuickBar(): void {
|
||||
@ -248,18 +230,16 @@ class HaConfigDashboard extends LitElement {
|
||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
if (isComponentLoaded(this.hass, "hassio")) {
|
||||
this._notifyUpdates = true;
|
||||
await refreshSupervisorAvailableUpdates(this.hass);
|
||||
fireEvent(this, "ha-refresh-supervisor");
|
||||
if (isComponentLoaded(this.hass, "update")) {
|
||||
fireEvent(this, "ha-refresh-updates");
|
||||
return;
|
||||
}
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.updates.check_unavailable.title"
|
||||
"ui.panel.config.updates.update_not_loaded.title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.updates.check_unavailable.description"
|
||||
"ui.panel.config.updates.update_not_loaded.description"
|
||||
),
|
||||
warning: true,
|
||||
});
|
||||
|
@ -1,21 +1,48 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiPackageVariant } from "@mdi/js";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-logo-svg";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { SupervisorAvailableUpdates } from "../../../data/supervisor/root";
|
||||
import { UpdateDescription } from "../../../data/update";
|
||||
import { showUpdateDialog } from "../../../dialogs/update-dialog/show-ha-update-dialog";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../../../components/ha-icon-next";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
|
||||
export const SUPERVISOR_UPDATE_NAMES = {
|
||||
core: "Home Assistant Core",
|
||||
os: "Home Assistant Operating System",
|
||||
supervisor: "Home Assistant Supervisor",
|
||||
};
|
||||
const sortUpdates = memoizeOne((a: UpdateDescription, b: UpdateDescription) => {
|
||||
if (a.domain === "hassio" && b.domain === "hassio") {
|
||||
if (a.identifier === "core") {
|
||||
return -1;
|
||||
}
|
||||
if (b.identifier === "core") {
|
||||
return 1;
|
||||
}
|
||||
if (a.identifier === "supervisor") {
|
||||
return -1;
|
||||
}
|
||||
if (b.identifier === "supervisor") {
|
||||
return 1;
|
||||
}
|
||||
if (a.identifier === "os") {
|
||||
return -1;
|
||||
}
|
||||
if (b.identifier === "os") {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (a.domain === "hassio") {
|
||||
return -1;
|
||||
}
|
||||
if (b.domain === "hassio") {
|
||||
return 1;
|
||||
}
|
||||
return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
|
||||
});
|
||||
|
||||
@customElement("ha-config-updates")
|
||||
class HaConfigUpdates extends LitElement {
|
||||
@ -24,62 +51,62 @@ class HaConfigUpdates extends LitElement {
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@property({ attribute: false })
|
||||
public supervisorUpdates?: SupervisorAvailableUpdates[] | null;
|
||||
public updates?: UpdateDescription[] | null;
|
||||
|
||||
@state() private _showAll = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.supervisorUpdates?.length) {
|
||||
if (!this.updates?.length) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
// Make sure the first updates shown are for the Supervisor
|
||||
const sortedUpdates = this.updates.sort((a, b) => sortUpdates(a, b));
|
||||
|
||||
const updates =
|
||||
this._showAll || this.supervisorUpdates.length <= 3
|
||||
? this.supervisorUpdates
|
||||
: this.supervisorUpdates.slice(0, 2);
|
||||
this._showAll || sortedUpdates.length <= 3
|
||||
? sortedUpdates
|
||||
: sortedUpdates.slice(0, 2);
|
||||
|
||||
return html`
|
||||
<div class="title">
|
||||
${this.hass.localize("ui.panel.config.updates.title", {
|
||||
count: this.supervisorUpdates.length,
|
||||
count: sortedUpdates.length,
|
||||
})}
|
||||
</div>
|
||||
${updates.map(
|
||||
(update) => html`
|
||||
<a href="/hassio${update.panel_path}">
|
||||
<paper-icon-item>
|
||||
<paper-icon-item @click=${this._showUpdate} .update=${update}>
|
||||
<span slot="item-icon" class="icon">
|
||||
${update.update_type === "addon"
|
||||
? update.icon
|
||||
? html`<img src="/api/hassio${update.icon}" />`
|
||||
: html`<ha-svg-icon
|
||||
.path=${mdiPackageVariant}
|
||||
></ha-svg-icon>`
|
||||
: html`<ha-logo-svg></ha-logo-svg>`}
|
||||
<img
|
||||
src=${update.icon_url ||
|
||||
brandsUrl({
|
||||
domain: update.domain,
|
||||
type: "icon",
|
||||
useFallback: true,
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})}
|
||||
/>
|
||||
</span>
|
||||
<paper-item-body two-line>
|
||||
${update.update_type === "addon"
|
||||
? update.name
|
||||
: SUPERVISOR_UPDATE_NAMES[update.update_type!]}
|
||||
${update.name}
|
||||
<div secondary>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.updates.version_available",
|
||||
{
|
||||
version_available: update.version_latest,
|
||||
version_available: update.available_version,
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</paper-item-body>
|
||||
${!this.narrow ? html`<ha-icon-next></ha-icon-next>` : ""}
|
||||
</paper-icon-item>
|
||||
</a>
|
||||
`
|
||||
)}
|
||||
${!this._showAll && this.supervisorUpdates.length >= 4
|
||||
${!this._showAll && this.updates.length >= 4
|
||||
? html`
|
||||
<button class="show-more" @click=${this._showAllClicked}>
|
||||
${this.hass.localize("ui.panel.config.updates.more_updates", {
|
||||
count: this.supervisorUpdates!.length - updates.length,
|
||||
count: this.updates!.length - updates.length,
|
||||
})}
|
||||
</button>
|
||||
`
|
||||
@ -91,6 +118,14 @@ class HaConfigUpdates extends LitElement {
|
||||
this._showAll = true;
|
||||
}
|
||||
|
||||
private _showUpdate(ev) {
|
||||
const update = ev.currentTarget.update as UpdateDescription;
|
||||
showUpdateDialog(this, {
|
||||
update,
|
||||
refreshCallback: () => fireEvent(this, "ha-refresh-updates"),
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup[] {
|
||||
return [
|
||||
css`
|
||||
@ -139,6 +174,9 @@ class HaConfigUpdates extends LitElement {
|
||||
outline: none;
|
||||
text-decoration: underline;
|
||||
}
|
||||
paper-icon-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -27,20 +27,18 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { listenMediaQuery } from "../../common/dom/media_query";
|
||||
import { CloudStatus, fetchCloudStatus } from "../../data/cloud";
|
||||
import {
|
||||
fetchSupervisorAvailableUpdates,
|
||||
SupervisorAvailableUpdates,
|
||||
} from "../../data/supervisor/root";
|
||||
import { fetchUpdateInfo, UpdateDescription } from "../../data/update";
|
||||
import "../../layouts/hass-loading-screen";
|
||||
import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page";
|
||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||
import { HomeAssistant, Route } from "../../types";
|
||||
import { showToast } from "../../util/toast";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"ha-refresh-cloud-status": undefined;
|
||||
"ha-refresh-supervisor": undefined;
|
||||
"ha-refresh-updates": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ -407,7 +405,7 @@ class HaPanelConfig extends HassRouterPage {
|
||||
|
||||
@state() private _cloudStatus?: CloudStatus;
|
||||
|
||||
@state() private _supervisorUpdates?: SupervisorAvailableUpdates[] | null;
|
||||
@state() private _updates?: UpdateDescription[] | null;
|
||||
|
||||
private _listeners: Array<() => void> = [];
|
||||
|
||||
@ -443,18 +441,18 @@ class HaPanelConfig extends HassRouterPage {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (isComponentLoaded(this.hass, "hassio")) {
|
||||
this._loadSupervisorUpdates();
|
||||
this.addEventListener("ha-refresh-supervisor", () => {
|
||||
this._loadSupervisorUpdates();
|
||||
if (isComponentLoaded(this.hass, "update")) {
|
||||
this._loadUpdates();
|
||||
this.addEventListener("ha-refresh-updates", () => {
|
||||
this._loadUpdates();
|
||||
});
|
||||
this.addEventListener("connection-status", (ev) => {
|
||||
if (ev.detail === "connected") {
|
||||
this._loadSupervisorUpdates();
|
||||
this._loadUpdates();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._supervisorUpdates = null;
|
||||
this._updates = null;
|
||||
}
|
||||
this.addEventListener("ha-refresh-cloud-status", () =>
|
||||
this._updateCloudStatus()
|
||||
@ -486,7 +484,7 @@ class HaPanelConfig extends HassRouterPage {
|
||||
isWide,
|
||||
narrow: this.narrow,
|
||||
cloudStatus: this._cloudStatus,
|
||||
supervisorUpdates: this._supervisorUpdates,
|
||||
updates: this._updates,
|
||||
});
|
||||
} else {
|
||||
el.route = this.routeTail;
|
||||
@ -495,7 +493,7 @@ class HaPanelConfig extends HassRouterPage {
|
||||
el.isWide = isWide;
|
||||
el.narrow = this.narrow;
|
||||
el.cloudStatus = this._cloudStatus;
|
||||
el.supervisorUpdates = this._supervisorUpdates;
|
||||
el.updates = this._updates;
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,13 +512,33 @@ class HaPanelConfig extends HassRouterPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async _loadSupervisorUpdates(): Promise<void> {
|
||||
private async _loadUpdates(): Promise<void> {
|
||||
const _showToast = this._updates !== undefined;
|
||||
|
||||
if (_showToast) {
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.panel.config.updates.checking_updates"),
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
this._supervisorUpdates = await fetchSupervisorAvailableUpdates(
|
||||
this.hass
|
||||
);
|
||||
this._updates = await fetchUpdateInfo(this.hass);
|
||||
} catch (err) {
|
||||
this._supervisorUpdates = null;
|
||||
this._updates = null;
|
||||
}
|
||||
|
||||
if (_showToast) {
|
||||
if (this._updates?.length) {
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.config.updates.updates_refreshed"
|
||||
),
|
||||
});
|
||||
} else {
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.panel.config.updates.no_new_updates"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1047,18 +1047,27 @@
|
||||
"learn_more": "Learn more"
|
||||
},
|
||||
"updates": {
|
||||
"check_unavailable": {
|
||||
"update_not_loaded": {
|
||||
"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."
|
||||
"description": "You need to enable the update integrtion to be able to check and install updates from the Home Assistant user interface."
|
||||
},
|
||||
"check_updates": "Check for updates",
|
||||
"checking_updates": "Checking for available updates",
|
||||
"no_new_updates": "No new updates found",
|
||||
"updates_refreshed": "Updates refreshed",
|
||||
"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",
|
||||
"more_updates": "+{count} updates",
|
||||
"show": "show"
|
||||
"show": "show",
|
||||
"dialog": {
|
||||
"title": "[%key:supervisor::update_available::update_name%]",
|
||||
"create_backup": "[%key:supervisor::update_available::create_backup%]",
|
||||
"open_changelog": "Open changelog",
|
||||
"updating": "[%key:supervisor::update_available::updating%]",
|
||||
"update": "[%key:supervisor::common::update%]",
|
||||
"description": "[%key:supervisor::update_available::description%]"
|
||||
}
|
||||
},
|
||||
"areas": {
|
||||
"caption": "Areas",
|
||||
|
Loading…
x
Reference in New Issue
Block a user