mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 19:56:42 +00:00
Move updates (#10626)
This commit is contained in:
parent
481da19c74
commit
e9f0967578
@ -1,3 +1,4 @@
|
|||||||
|
import "../../../src/components/ha-logo-svg";
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement } from "lit/decorators";
|
import { customElement } from "lit/decorators";
|
||||||
import "../../../src/components/ha-alert";
|
import "../../../src/components/ha-alert";
|
||||||
@ -10,6 +11,8 @@ const alerts: {
|
|||||||
dismissable?: boolean;
|
dismissable?: boolean;
|
||||||
action?: string;
|
action?: string;
|
||||||
rtl?: boolean;
|
rtl?: boolean;
|
||||||
|
iconSlot?: TemplateResult;
|
||||||
|
actionSlot?: TemplateResult;
|
||||||
}[] = [
|
}[] = [
|
||||||
{
|
{
|
||||||
title: "Test info alert",
|
title: "Test info alert",
|
||||||
@ -81,6 +84,18 @@ const alerts: {
|
|||||||
type: "warning",
|
type: "warning",
|
||||||
action: "save",
|
action: "save",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Slotted icon",
|
||||||
|
description: "Alert with slotted icon",
|
||||||
|
type: "warning",
|
||||||
|
iconSlot: html`<ha-logo-svg slot="icon"></ha-logo-svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Slotted action",
|
||||||
|
description: "Alert with slotted action",
|
||||||
|
type: "info",
|
||||||
|
actionSlot: html`<mwc-button slot="action" label="action"></mwc-button>`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Dismissable information (RTL)",
|
description: "Dismissable information (RTL)",
|
||||||
type: "info",
|
type: "info",
|
||||||
@ -117,7 +132,7 @@ export class DemoHaAlert extends LitElement {
|
|||||||
.actionText=${alert.action || ""}
|
.actionText=${alert.action || ""}
|
||||||
.rtl=${alert.rtl || false}
|
.rtl=${alert.rtl || false}
|
||||||
>
|
>
|
||||||
${alert.description}
|
${alert.iconSlot} ${alert.description} ${alert.actionSlot}
|
||||||
</ha-alert>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@ -145,6 +160,15 @@ export class DemoHaAlert extends LitElement {
|
|||||||
span {
|
span {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
ha-logo-svg {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
padding-right: 8px;
|
||||||
|
place-self: center;
|
||||||
|
}
|
||||||
|
mwc-button {
|
||||||
|
--mdc-theme-primary: var(--primary-text-color);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import {
|
import {
|
||||||
mdiArrowUpBoldCircle,
|
|
||||||
mdiCheckCircle,
|
mdiCheckCircle,
|
||||||
mdiChip,
|
mdiChip,
|
||||||
mdiCircle,
|
mdiCircle,
|
||||||
@ -49,7 +48,6 @@ import {
|
|||||||
startHassioAddon,
|
startHassioAddon,
|
||||||
stopHassioAddon,
|
stopHassioAddon,
|
||||||
uninstallHassioAddon,
|
uninstallHassioAddon,
|
||||||
updateHassioAddon,
|
|
||||||
validateHassioAddonOption,
|
validateHassioAddonOption,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import {
|
import {
|
||||||
@ -69,9 +67,8 @@ import { bytesToString } from "../../../../src/util/bytes-to-string";
|
|||||||
import "../../components/hassio-card-content";
|
import "../../components/hassio-card-content";
|
||||||
import "../../components/supervisor-metric";
|
import "../../components/supervisor-metric";
|
||||||
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
||||||
import { showDialogSupervisorUpdate } from "../../dialogs/update/show-dialog-update";
|
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
import { addonArchIsSupported } from "../../util/addon";
|
import { addonArchIsSupported, extractChangelog } from "../../util/addon";
|
||||||
|
|
||||||
const STAGE_ICON = {
|
const STAGE_ICON = {
|
||||||
stable: mdiCheckCircle,
|
stable: mdiCheckCircle,
|
||||||
@ -128,69 +125,23 @@ class HassioAddonInfo extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
${this.addon.update_available
|
${this.addon.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-card
|
<ha-alert
|
||||||
.header="${this.supervisor.localize(
|
.title=${this.supervisor.localize("common.update_available", {
|
||||||
"common.update_available",
|
count: 1,
|
||||||
"count",
|
})}
|
||||||
1
|
|
||||||
)}🎉"
|
|
||||||
>
|
>
|
||||||
<div class="card-content">
|
${this.supervisor.localize(
|
||||||
<hassio-card-content
|
"addon.dashboard.new_update_available",
|
||||||
.hass=${this.hass}
|
{ name: this.addon.name, version: this.addon.version_latest }
|
||||||
.title=${this.supervisor.localize(
|
)}
|
||||||
"addon.dashboard.new_update_available",
|
<a
|
||||||
"name",
|
href="/hassio/update-available/${this.addon.slug}"
|
||||||
this.addon.name,
|
slot="action"
|
||||||
"version",
|
>
|
||||||
this.addon.version_latest
|
<mwc-button .label=${this.supervisor.localize("common.review")}>
|
||||||
)}
|
|
||||||
.description=${this.supervisor.localize(
|
|
||||||
"common.running_version",
|
|
||||||
"version",
|
|
||||||
this.addon.version
|
|
||||||
)}
|
|
||||||
icon=${mdiArrowUpBoldCircle}
|
|
||||||
iconClass="update"
|
|
||||||
></hassio-card-content>
|
|
||||||
${!this.addon.available && addonStoreInfo
|
|
||||||
? !addonArchIsSupported(
|
|
||||||
this.supervisor.info.supported_arch,
|
|
||||||
this.addon.arch
|
|
||||||
)
|
|
||||||
? html`
|
|
||||||
<ha-alert alert-type="warning">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.not_available_arch"
|
|
||||||
)}
|
|
||||||
</ha-alert>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<ha-alert alert-type="warning">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.not_available_arch",
|
|
||||||
"core_version_installed",
|
|
||||||
this.supervisor.core.version,
|
|
||||||
"core_version_needed",
|
|
||||||
addonStoreInfo.homeassistant
|
|
||||||
)}
|
|
||||||
</ha-alert>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
${this.addon.changelog
|
|
||||||
? html`
|
|
||||||
<mwc-button @click=${this._openChangelog}>
|
|
||||||
${this.supervisor.localize("addon.dashboard.changelog")}
|
|
||||||
</mwc-button>
|
|
||||||
`
|
|
||||||
: html`<span></span>`}
|
|
||||||
<mwc-button @click=${this._updateClicked}>
|
|
||||||
${this.supervisor.localize("common.update")}
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</a>
|
||||||
</ha-card>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${!this.addon.protected
|
${!this.addon.protected
|
||||||
@ -899,22 +850,14 @@ class HassioAddonInfo extends LitElement {
|
|||||||
|
|
||||||
private async _openChangelog(): Promise<void> {
|
private async _openChangelog(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let content = await fetchHassioAddonChangelog(this.hass, this.addon.slug);
|
const content = await fetchHassioAddonChangelog(
|
||||||
if (
|
this.hass,
|
||||||
content.includes(`# ${this.addon.version}`) &&
|
this.addon.slug
|
||||||
content.includes(`# ${this.addon.version_latest}`)
|
);
|
||||||
) {
|
|
||||||
const newcontent = content.split(`# ${this.addon.version}`)[0];
|
|
||||||
if (newcontent.includes(`# ${this.addon.version_latest}`)) {
|
|
||||||
// Only change the content if the new version still exist
|
|
||||||
// if the changelog does not have the newests version on top
|
|
||||||
// this will not be true, and we don't modify the content
|
|
||||||
content = newcontent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showHassioMarkdownDialog(this, {
|
showHassioMarkdownDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.changelog"),
|
title: this.supervisor.localize("addon.dashboard.changelog"),
|
||||||
content,
|
content: extractChangelog(this.addon, content),
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
@ -989,33 +932,6 @@ class HassioAddonInfo extends LitElement {
|
|||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateClicked(): Promise<void> {
|
|
||||||
showDialogSupervisorUpdate(this, {
|
|
||||||
supervisor: this.supervisor,
|
|
||||||
name: this.addon.name,
|
|
||||||
version: this.addon.version_latest,
|
|
||||||
backupParams: {
|
|
||||||
name: `addon_${this.addon.slug}_${this.addon.version}`,
|
|
||||||
addons: [this.addon.slug],
|
|
||||||
homeassistant: false,
|
|
||||||
},
|
|
||||||
updateHandler: async () => this._updateAddon(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _updateAddon(): Promise<void> {
|
|
||||||
await updateHassioAddon(this.hass, this.addon.slug);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "addon",
|
|
||||||
});
|
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "update",
|
|
||||||
};
|
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _startClicked(ev: CustomEvent): Promise<void> {
|
private async _startClicked(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
@ -1244,6 +1160,13 @@ class HassioAddonInfo extends LitElement {
|
|||||||
align-self: end;
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ha-alert mwc-button {
|
||||||
|
--mdc-theme-primary: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
ha-chip {
|
ha-chip {
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
|
@ -158,7 +158,7 @@ export class HassioBackups extends LitElement {
|
|||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage-data-table
|
<hass-tabs-subpage-data-table
|
||||||
.tabs=${supervisorTabs}
|
.tabs=${supervisorTabs(this.hass)}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.localizeFunc=${this.supervisor.localize}
|
.localizeFunc=${this.supervisor.localize}
|
||||||
.searchLabel=${this.supervisor.localize("search")}
|
.searchLabel=${this.supervisor.localize("search")}
|
||||||
|
@ -20,7 +20,9 @@ class HassioAddons extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>${this.supervisor.localize("dashboard.addons")}</h1>
|
${!atLeastVersion(this.hass.config.version, 2021, 12)
|
||||||
|
? html` <h1>${this.supervisor.localize("dashboard.addons")}</h1> `
|
||||||
|
: ""}
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${!this.supervisor.supervisor.addons?.length
|
${!this.supervisor.supervisor.addons?.length
|
||||||
? html`
|
? html`
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { mdiStorePlus } from "@mdi/js";
|
import { mdiStorePlus } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import "../../../src/components/ha-fab";
|
import "../../../src/components/ha-fab";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
@ -27,7 +28,7 @@ class HassioDashboard extends LitElement {
|
|||||||
.localizeFunc=${this.supervisor.localize}
|
.localizeFunc=${this.supervisor.localize}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${supervisorTabs}
|
.tabs=${supervisorTabs(this.hass)}
|
||||||
main-page
|
main-page
|
||||||
supervisor
|
supervisor
|
||||||
hasFab
|
hasFab
|
||||||
@ -36,10 +37,14 @@ class HassioDashboard extends LitElement {
|
|||||||
${this.supervisor.localize("panel.dashboard")}
|
${this.supervisor.localize("panel.dashboard")}
|
||||||
</span>
|
</span>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<hassio-update
|
${!atLeastVersion(this.hass.config.version, 2021, 12)
|
||||||
.hass=${this.hass}
|
? html`
|
||||||
.supervisor=${this.supervisor}
|
<hassio-update
|
||||||
></hassio-update>
|
.hass=${this.hass}
|
||||||
|
.supervisor=${this.supervisor}
|
||||||
|
></hassio-update>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
<hassio-addons
|
<hassio-addons
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.supervisor=${this.supervisor}
|
||||||
|
@ -3,34 +3,18 @@ import { mdiHomeAssistant } from "@mdi/js";
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
|
||||||
import "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import {
|
|
||||||
extractApiErrorMessage,
|
|
||||||
HassioResponse,
|
|
||||||
ignoreSupervisorError,
|
|
||||||
} from "../../../src/data/hassio/common";
|
|
||||||
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
||||||
import {
|
import {
|
||||||
HassioHomeAssistantInfo,
|
HassioHomeAssistantInfo,
|
||||||
HassioSupervisorInfo,
|
HassioSupervisorInfo,
|
||||||
} from "../../../src/data/hassio/supervisor";
|
} from "../../../src/data/hassio/supervisor";
|
||||||
import { updateCore } from "../../../src/data/supervisor/core";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import {
|
|
||||||
Supervisor,
|
|
||||||
supervisorApiWsRequest,
|
|
||||||
} from "../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
|
||||||
showAlertDialog,
|
|
||||||
showConfirmationDialog,
|
|
||||||
} from "../../../src/dialogs/generic/show-dialog-box";
|
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import { showDialogSupervisorUpdate } from "../dialogs/update/show-dialog-update";
|
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
const computeVersion = (key: string, version: string): string =>
|
const computeVersion = (key: string, version: string): string =>
|
||||||
@ -73,26 +57,18 @@ export class HassioUpdate extends LitElement {
|
|||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Home Assistant Core",
|
"Home Assistant Core",
|
||||||
"core",
|
"core",
|
||||||
this.supervisor.core,
|
this.supervisor.core
|
||||||
"hassio/homeassistant/update",
|
|
||||||
`https://${
|
|
||||||
this.supervisor.core.version_latest.includes("b") ? "rc" : "www"
|
|
||||||
}.home-assistant.io/latest-release-notes/`
|
|
||||||
)}
|
)}
|
||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Supervisor",
|
"Supervisor",
|
||||||
"supervisor",
|
"supervisor",
|
||||||
this.supervisor.supervisor,
|
this.supervisor.supervisor
|
||||||
"hassio/supervisor/update",
|
|
||||||
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}`
|
|
||||||
)}
|
)}
|
||||||
${this.supervisor.host.features.includes("haos")
|
${this.supervisor.host.features.includes("haos")
|
||||||
? this._renderUpdateCard(
|
? this._renderUpdateCard(
|
||||||
"Operating System",
|
"Operating System",
|
||||||
"os",
|
"os",
|
||||||
this.supervisor.os,
|
this.supervisor.os
|
||||||
"hassio/os/update",
|
|
||||||
`https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}`
|
|
||||||
)
|
)
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
@ -103,9 +79,7 @@ export class HassioUpdate extends LitElement {
|
|||||||
private _renderUpdateCard(
|
private _renderUpdateCard(
|
||||||
name: string,
|
name: string,
|
||||||
key: string,
|
key: string,
|
||||||
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo,
|
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo
|
||||||
apiPath: string,
|
|
||||||
releaseNotesUrl: string
|
|
||||||
): TemplateResult {
|
): TemplateResult {
|
||||||
if (!object.update_available) {
|
if (!object.update_available) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -136,96 +110,15 @@ export class HassioUpdate extends LitElement {
|
|||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<a href=${releaseNotesUrl} target="_blank" rel="noreferrer">
|
<a href="/hassio/update-available/${key}">
|
||||||
<mwc-button>
|
<mwc-button .label=${this.supervisor.localize("common.review")}>
|
||||||
${this.supervisor.localize("common.release_notes")}
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</a>
|
</a>
|
||||||
<ha-progress-button
|
|
||||||
.apiPath=${apiPath}
|
|
||||||
.name=${name}
|
|
||||||
.key=${key}
|
|
||||||
.version=${object.version_latest}
|
|
||||||
@click=${this._confirmUpdate}
|
|
||||||
>
|
|
||||||
${this.supervisor.localize("common.update")}
|
|
||||||
</ha-progress-button>
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _confirmUpdate(ev): Promise<void> {
|
|
||||||
const item = ev.currentTarget;
|
|
||||||
if (item.key === "core") {
|
|
||||||
showDialogSupervisorUpdate(this, {
|
|
||||||
supervisor: this.supervisor,
|
|
||||||
name: "Home Assistant Core",
|
|
||||||
version: this.supervisor.core.version_latest,
|
|
||||||
backupParams: {
|
|
||||||
name: `core_${this.supervisor.core.version}`,
|
|
||||||
folders: ["homeassistant"],
|
|
||||||
homeassistant: true,
|
|
||||||
},
|
|
||||||
updateHandler: async () => this._updateCore(),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
item.progress = true;
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
|
||||||
title: this.supervisor.localize(
|
|
||||||
"confirm.update.title",
|
|
||||||
"name",
|
|
||||||
item.name
|
|
||||||
),
|
|
||||||
text: this.supervisor.localize(
|
|
||||||
"confirm.update.text",
|
|
||||||
"name",
|
|
||||||
item.name,
|
|
||||||
"version",
|
|
||||||
computeVersion(item.key, item.version)
|
|
||||||
),
|
|
||||||
confirmText: this.supervisor.localize("common.update"),
|
|
||||||
dismissText: this.supervisor.localize("common.cancel"),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
item.progress = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
|
||||||
await supervisorApiWsRequest(this.hass.connection, {
|
|
||||||
method: "post",
|
|
||||||
endpoint: item.apiPath.replace("hassio", ""),
|
|
||||||
timeout: null,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await this.hass.callApi<HassioResponse<void>>("POST", item.apiPath);
|
|
||||||
}
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: item.key,
|
|
||||||
});
|
|
||||||
} catch (err: any) {
|
|
||||||
// Only show an error if the status code was not expected (user behind proxy)
|
|
||||||
// or no status at all(connection terminated)
|
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.supervisor.localize("common.error.update_failed"),
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item.progress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _updateCore(): Promise<void> {
|
|
||||||
await updateCore(this.hass);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "core",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
|
@ -1,203 +0,0 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import "../../../../src/components/ha-alert";
|
|
||||||
import "../../../../src/components/ha-circular-progress";
|
|
||||||
import "../../../../src/components/ha-dialog";
|
|
||||||
import "../../../../src/components/ha-settings-row";
|
|
||||||
import "../../../../src/components/ha-switch";
|
|
||||||
import {
|
|
||||||
extractApiErrorMessage,
|
|
||||||
ignoreSupervisorError,
|
|
||||||
} from "../../../../src/data/hassio/common";
|
|
||||||
import { createHassioPartialBackup } from "../../../../src/data/hassio/backup";
|
|
||||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
|
||||||
import { SupervisorDialogSupervisorUpdateParams } from "./show-dialog-update";
|
|
||||||
|
|
||||||
@customElement("dialog-supervisor-update")
|
|
||||||
class DialogSupervisorUpdate extends LitElement {
|
|
||||||
public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _opened = false;
|
|
||||||
|
|
||||||
@state() private _createBackup = true;
|
|
||||||
|
|
||||||
@state() private _action: "backup" | "update" | null = null;
|
|
||||||
|
|
||||||
@state() private _error?: string;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private _dialogParams?: SupervisorDialogSupervisorUpdateParams;
|
|
||||||
|
|
||||||
public async showDialog(
|
|
||||||
params: SupervisorDialogSupervisorUpdateParams
|
|
||||||
): Promise<void> {
|
|
||||||
this._opened = true;
|
|
||||||
this._dialogParams = params;
|
|
||||||
await this.updateComplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog(): void {
|
|
||||||
this._action = null;
|
|
||||||
this._createBackup = true;
|
|
||||||
this._error = undefined;
|
|
||||||
this._dialogParams = undefined;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
public focus(): void {
|
|
||||||
this.updateComplete.then(() =>
|
|
||||||
(
|
|
||||||
this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement
|
|
||||||
)?.focus()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this._dialogParams) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<ha-dialog .open=${this._opened} scrimClickAction escapeKeyAction>
|
|
||||||
${this._action === null
|
|
||||||
? html`<slot name="heading">
|
|
||||||
<h2 id="title" class="header_title">
|
|
||||||
${this._dialogParams.supervisor.localize(
|
|
||||||
"confirm.update.title",
|
|
||||||
"name",
|
|
||||||
this._dialogParams.name
|
|
||||||
)}
|
|
||||||
</h2>
|
|
||||||
</slot>
|
|
||||||
<div>
|
|
||||||
${this._dialogParams.supervisor.localize(
|
|
||||||
"confirm.update.text",
|
|
||||||
"name",
|
|
||||||
this._dialogParams.name,
|
|
||||||
"version",
|
|
||||||
this._dialogParams.version
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ha-settings-row>
|
|
||||||
<span slot="heading">
|
|
||||||
${this._dialogParams.supervisor.localize(
|
|
||||||
"dialog.update.backup"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span slot="description">
|
|
||||||
${this._dialogParams.supervisor.localize(
|
|
||||||
"dialog.update.create_backup",
|
|
||||||
"name",
|
|
||||||
this._dialogParams.name
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<ha-switch
|
|
||||||
.checked=${this._createBackup}
|
|
||||||
haptic
|
|
||||||
@click=${this._toggleBackup}
|
|
||||||
>
|
|
||||||
</ha-switch>
|
|
||||||
</ha-settings-row>
|
|
||||||
<mwc-button @click=${this.closeDialog} slot="secondaryAction">
|
|
||||||
${this._dialogParams.supervisor.localize("common.cancel")}
|
|
||||||
</mwc-button>
|
|
||||||
<mwc-button
|
|
||||||
.disabled=${this._error !== undefined}
|
|
||||||
@click=${this._update}
|
|
||||||
slot="primaryAction"
|
|
||||||
>
|
|
||||||
${this._dialogParams.supervisor.localize("common.update")}
|
|
||||||
</mwc-button>`
|
|
||||||
: html`<ha-circular-progress alt="Updating" size="large" active>
|
|
||||||
</ha-circular-progress>
|
|
||||||
<p class="progress-text">
|
|
||||||
${this._action === "update"
|
|
||||||
? this._dialogParams.supervisor.localize(
|
|
||||||
"dialog.update.updating",
|
|
||||||
"name",
|
|
||||||
this._dialogParams.name,
|
|
||||||
"version",
|
|
||||||
this._dialogParams.version
|
|
||||||
)
|
|
||||||
: this._dialogParams.supervisor.localize(
|
|
||||||
"dialog.update.creating_backup",
|
|
||||||
"name",
|
|
||||||
this._dialogParams.name
|
|
||||||
)}
|
|
||||||
</p>`}
|
|
||||||
${this._error
|
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleBackup() {
|
|
||||||
this._createBackup = !this._createBackup;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _update() {
|
|
||||||
if (this._createBackup) {
|
|
||||||
this._action = "backup";
|
|
||||||
try {
|
|
||||||
await createHassioPartialBackup(
|
|
||||||
this.hass,
|
|
||||||
this._dialogParams!.backupParams
|
|
||||||
);
|
|
||||||
} catch (err: any) {
|
|
||||||
this._error = extractApiErrorMessage(err);
|
|
||||||
this._action = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._action = "update";
|
|
||||||
try {
|
|
||||||
await this._dialogParams!.updateHandler!();
|
|
||||||
} catch (err: any) {
|
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
|
||||||
this._error = extractApiErrorMessage(err);
|
|
||||||
this._action = null;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.closeDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
haStyleDialog,
|
|
||||||
css`
|
|
||||||
.form {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-settings-row {
|
|
||||||
margin-top: 32px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-circular-progress {
|
|
||||||
display: block;
|
|
||||||
margin: 32px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-text {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-supervisor-update": DialogSupervisorUpdate;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
|
|
||||||
export interface SupervisorDialogSupervisorUpdateParams {
|
|
||||||
supervisor: Supervisor;
|
|
||||||
name: string;
|
|
||||||
version: string;
|
|
||||||
backupParams: any;
|
|
||||||
updateHandler: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const showDialogSupervisorUpdate = (
|
|
||||||
element: HTMLElement,
|
|
||||||
dialogParams: SupervisorDialogSupervisorUpdateParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-supervisor-update",
|
|
||||||
dialogImport: () => import("./dialog-supervisor-update"),
|
|
||||||
dialogParams,
|
|
||||||
});
|
|
||||||
};
|
|
@ -34,6 +34,9 @@ const REDIRECTS: Redirects = {
|
|||||||
supervisor_store: {
|
supervisor_store: {
|
||||||
redirect: "/hassio/store",
|
redirect: "/hassio/store",
|
||||||
},
|
},
|
||||||
|
supervisor_addons: {
|
||||||
|
redirect: "/hassio/dashboard",
|
||||||
|
},
|
||||||
supervisor_addon: {
|
supervisor_addon: {
|
||||||
redirect: "/hassio/addon",
|
redirect: "/hassio/addon",
|
||||||
params: {
|
params: {
|
||||||
|
@ -35,6 +35,10 @@ class HassioRouter extends HassRouterPage {
|
|||||||
backups: "dashboard",
|
backups: "dashboard",
|
||||||
store: "dashboard",
|
store: "dashboard",
|
||||||
system: "dashboard",
|
system: "dashboard",
|
||||||
|
"update-available": {
|
||||||
|
tag: "update-available-dashboard",
|
||||||
|
load: () => import("./update-available/update-available-dashboard"),
|
||||||
|
},
|
||||||
addon: {
|
addon: {
|
||||||
tag: "hassio-addon-dashboard",
|
tag: "hassio-addon-dashboard",
|
||||||
load: () => import("./addon-view/hassio-addon-dashboard"),
|
load: () => import("./addon-view/hassio-addon-dashboard"),
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
import { mdiBackupRestore, mdiCogs, mdiViewDashboard } from "@mdi/js";
|
import {
|
||||||
|
mdiBackupRestore,
|
||||||
|
mdiCogs,
|
||||||
|
mdiPuzzle,
|
||||||
|
mdiViewDashboard,
|
||||||
|
} from "@mdi/js";
|
||||||
|
import { atLeastVersion } from "../../src/common/config/version";
|
||||||
import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage";
|
import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage";
|
||||||
|
import { HomeAssistant } from "../../src/types";
|
||||||
|
|
||||||
export const supervisorTabs: PageNavigation[] = [
|
export const supervisorTabs = (hass: HomeAssistant): PageNavigation[] => [
|
||||||
{
|
{
|
||||||
translationKey: "panel.dashboard",
|
translationKey: atLeastVersion(hass.config.version, 2021, 12)
|
||||||
|
? "panel.addons"
|
||||||
|
: "panel.dashboard",
|
||||||
path: `/hassio/dashboard`,
|
path: `/hassio/dashboard`,
|
||||||
iconPath: mdiViewDashboard,
|
iconPath: atLeastVersion(hass.config.version, 2021, 12)
|
||||||
|
? mdiPuzzle
|
||||||
|
: mdiViewDashboard,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
translationKey: "panel.backups",
|
translationKey: "panel.backups",
|
||||||
|
@ -2,7 +2,7 @@ import "@material/mwc-button";
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../src/components/ha-button-menu";
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
@ -12,7 +12,7 @@ import {
|
|||||||
fetchHassioStats,
|
fetchHassioStats,
|
||||||
HassioStats,
|
HassioStats,
|
||||||
} from "../../../src/data/hassio/common";
|
} from "../../../src/data/hassio/common";
|
||||||
import { restartCore, updateCore } from "../../../src/data/supervisor/core";
|
import { restartCore } from "../../../src/data/supervisor/core";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -22,7 +22,6 @@ import { haStyle } from "../../../src/resources/styles";
|
|||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import { bytesToString } from "../../../src/util/bytes-to-string";
|
import { bytesToString } from "../../../src/util/bytes-to-string";
|
||||||
import "../components/supervisor-metric";
|
import "../components/supervisor-metric";
|
||||||
import { showDialogSupervisorUpdate } from "../dialogs/update/show-dialog-update";
|
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
@customElement("hassio-core-info")
|
@customElement("hassio-core-info")
|
||||||
@ -67,14 +66,15 @@ class HassioCoreInfo extends LitElement {
|
|||||||
<span slot="description">
|
<span slot="description">
|
||||||
core-${this.supervisor.core.version_latest}
|
core-${this.supervisor.core.version_latest}
|
||||||
</span>
|
</span>
|
||||||
${this.supervisor.core.update_available
|
${!atLeastVersion(this.hass.config.version, 2021, 12) &&
|
||||||
|
this.supervisor.core.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<a href="/hassio/update-available/core">
|
||||||
.title=${this.supervisor.localize("common.update")}
|
<mwc-button
|
||||||
@click=${this._coreUpdate}
|
.label=${this.supervisor.localize("common.review")}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("common.update")}
|
</mwc-button>
|
||||||
</ha-progress-button>
|
</a>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
@ -160,27 +160,6 @@ class HassioCoreInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _coreUpdate(): Promise<void> {
|
|
||||||
showDialogSupervisorUpdate(this, {
|
|
||||||
supervisor: this.supervisor,
|
|
||||||
name: "Home Assistant Core",
|
|
||||||
version: this.supervisor.core.version_latest,
|
|
||||||
backupParams: {
|
|
||||||
name: `core_${this.supervisor.core.version}`,
|
|
||||||
folders: ["homeassistant"],
|
|
||||||
homeassistant: true,
|
|
||||||
},
|
|
||||||
updateHandler: async () => this._updateCore(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _updateCore(): Promise<void> {
|
|
||||||
await updateCore(this.hass);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "core",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
@ -239,6 +218,9 @@ class HassioCoreInfo extends LitElement {
|
|||||||
mwc-list-item ha-svg-icon {
|
mwc-list-item ha-svg-icon {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ import {
|
|||||||
configSyncOS,
|
configSyncOS,
|
||||||
rebootHost,
|
rebootHost,
|
||||||
shutdownHost,
|
shutdownHost,
|
||||||
updateOS,
|
|
||||||
} from "../../../src/data/hassio/host";
|
} from "../../../src/data/hassio/host";
|
||||||
import {
|
import {
|
||||||
fetchNetworkInfo,
|
fetchNetworkInfo,
|
||||||
@ -106,11 +105,15 @@ class HassioHostInfo extends LitElement {
|
|||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.host.operating_system}
|
${this.supervisor.host.operating_system}
|
||||||
</span>
|
</span>
|
||||||
${this.supervisor.os.update_available
|
${!atLeastVersion(this.hass.config.version, 2021, 12) &&
|
||||||
|
this.supervisor.os.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button @click=${this._osUpdate}>
|
<a href="/hassio/update-available/os">
|
||||||
${this.supervisor.localize("commmon.update")}
|
<mwc-button
|
||||||
</ha-progress-button>
|
.label=${this.supervisor.localize("common.review")}
|
||||||
|
>
|
||||||
|
</mwc-button>
|
||||||
|
</a>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
@ -333,50 +336,6 @@ class HassioHostInfo extends LitElement {
|
|||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _osUpdate(ev: CustomEvent): Promise<void> {
|
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
|
||||||
title: this.supervisor.localize(
|
|
||||||
"confirm.update.title",
|
|
||||||
"name",
|
|
||||||
"Home Assistant Operating System"
|
|
||||||
),
|
|
||||||
text: this.supervisor.localize(
|
|
||||||
"confirm.update.text",
|
|
||||||
"name",
|
|
||||||
"Home Assistant Operating System",
|
|
||||||
"version",
|
|
||||||
this.supervisor.os.version_latest
|
|
||||||
),
|
|
||||||
confirmText: this.supervisor.localize("common.update"),
|
|
||||||
dismissText: "no",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
button.progress = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateOS(this.hass);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", { collection: "os" });
|
|
||||||
} catch (err: any) {
|
|
||||||
if (this.hass.connection.connected) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.supervisor.localize(
|
|
||||||
"common.failed_to_update_name",
|
|
||||||
"name",
|
|
||||||
"Home Assistant Operating System"
|
|
||||||
),
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
button.progress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _changeNetworkClicked(): Promise<void> {
|
private async _changeNetworkClicked(): Promise<void> {
|
||||||
showNetworkDialog(this, {
|
showNetworkDialog(this, {
|
||||||
supervisor: this.supervisor,
|
supervisor: this.supervisor,
|
||||||
@ -494,6 +453,9 @@ class HassioHostInfo extends LitElement {
|
|||||||
mwc-list-item ha-svg-icon {
|
mwc-list-item ha-svg-icon {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
restartSupervisor,
|
restartSupervisor,
|
||||||
setSupervisorOption,
|
setSupervisorOption,
|
||||||
SupervisorOptions,
|
SupervisorOptions,
|
||||||
updateSupervisor,
|
|
||||||
} from "../../../src/data/hassio/supervisor";
|
} from "../../../src/data/hassio/supervisor";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import {
|
import {
|
||||||
@ -77,16 +76,15 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
<span slot="description">
|
<span slot="description">
|
||||||
supervisor-${this.supervisor.supervisor.version_latest}
|
supervisor-${this.supervisor.supervisor.version_latest}
|
||||||
</span>
|
</span>
|
||||||
${this.supervisor.supervisor.update_available
|
${!atLeastVersion(this.hass.config.version, 2021, 12) &&
|
||||||
|
this.supervisor.supervisor.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<a href="/hassio/update-available/supervisor">
|
||||||
.title=${this.supervisor.localize(
|
<mwc-button
|
||||||
"system.supervisor.update_supervisor"
|
.label=${this.supervisor.localize("common.review")}
|
||||||
)}
|
>
|
||||||
@click=${this._supervisorUpdate}
|
</mwc-button>
|
||||||
>
|
</a>
|
||||||
${this.supervisor.localize("common.update")}
|
|
||||||
</ha-progress-button>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
@ -337,51 +335,6 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _supervisorUpdate(ev: CustomEvent): Promise<void> {
|
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
|
||||||
title: this.supervisor.localize(
|
|
||||||
"confirm.update.title",
|
|
||||||
"name",
|
|
||||||
"Supervisor"
|
|
||||||
),
|
|
||||||
text: this.supervisor.localize(
|
|
||||||
"confirm.update.text",
|
|
||||||
"name",
|
|
||||||
"Supervisor",
|
|
||||||
"version",
|
|
||||||
this.supervisor.supervisor.version_latest
|
|
||||||
),
|
|
||||||
confirmText: this.supervisor.localize("common.update"),
|
|
||||||
dismissText: this.supervisor.localize("common.cancel"),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
button.progress = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await updateSupervisor(this.hass);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "supervisor",
|
|
||||||
});
|
|
||||||
} catch (err: any) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.supervisor.localize(
|
|
||||||
"common.failed_to_update_name",
|
|
||||||
"name",
|
|
||||||
"Supervisor"
|
|
||||||
),
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
button.progress = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _diagnosticsInformationDialog(): Promise<void> {
|
private async _diagnosticsInformationDialog(): Promise<void> {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
@ -513,6 +466,9 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class HassioSystem extends LitElement {
|
|||||||
.localizeFunc=${this.supervisor.localize}
|
.localizeFunc=${this.supervisor.localize}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${supervisorTabs}
|
.tabs=${supervisorTabs(this.hass)}
|
||||||
main-page
|
main-page
|
||||||
supervisor
|
supervisor
|
||||||
>
|
>
|
||||||
|
391
hassio/src/update-available/update-available-dashboard.ts
Normal file
391
hassio/src/update-available/update-available-dashboard.ts
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
import "@material/mwc-list/mwc-list-item";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import "../../../src/common/search/search-input";
|
||||||
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../src/components/ha-alert";
|
||||||
|
import "../../../src/components/ha-button-menu";
|
||||||
|
import "../../../src/components/ha-card";
|
||||||
|
import "../../../src/components/ha-checkbox";
|
||||||
|
import "../../../src/components/ha-expansion-panel";
|
||||||
|
import "../../../src/components/ha-icon-button";
|
||||||
|
import "../../../src/components/ha-markdown";
|
||||||
|
import "../../../src/components/ha-settings-row";
|
||||||
|
import "../../../src/components/ha-svg-icon";
|
||||||
|
import "../../../src/components/ha-switch";
|
||||||
|
import {
|
||||||
|
fetchHassioAddonChangelog,
|
||||||
|
fetchHassioAddonInfo,
|
||||||
|
HassioAddonDetails,
|
||||||
|
updateHassioAddon,
|
||||||
|
} from "../../../src/data/hassio/addon";
|
||||||
|
import {
|
||||||
|
createHassioPartialBackup,
|
||||||
|
HassioPartialBackupCreateParams,
|
||||||
|
} from "../../../src/data/hassio/backup";
|
||||||
|
import {
|
||||||
|
extractApiErrorMessage,
|
||||||
|
ignoreSupervisorError,
|
||||||
|
} from "../../../src/data/hassio/common";
|
||||||
|
import { updateOS } from "../../../src/data/hassio/host";
|
||||||
|
import { updateSupervisor } from "../../../src/data/hassio/supervisor";
|
||||||
|
import { updateCore } from "../../../src/data/supervisor/core";
|
||||||
|
import { StoreAddon } from "../../../src/data/supervisor/store";
|
||||||
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
|
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 { documentationUrl } from "../../../src/util/documentation-url";
|
||||||
|
import { addonArchIsSupported, extractChangelog } from "../util/addon";
|
||||||
|
|
||||||
|
const changelogUrl = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: string,
|
||||||
|
version: string
|
||||||
|
): string | undefined => {
|
||||||
|
if (entry === "core") {
|
||||||
|
return version?.includes("dev")
|
||||||
|
? "https://github.com/home-assistant/core/commits/dev"
|
||||||
|
: documentationUrl(hass, "/latest-release-notes/");
|
||||||
|
}
|
||||||
|
if (entry === "os") {
|
||||||
|
return version?.includes("dev")
|
||||||
|
? "https://github.com/home-assistant/operating-system/commits/dev"
|
||||||
|
: `https://github.com/home-assistant/operating-system/releases/tag/${version}`;
|
||||||
|
}
|
||||||
|
if (entry === "supervisor") {
|
||||||
|
return version?.includes("dev")
|
||||||
|
? "https://github.com/home-assistant/supervisor/commits/main"
|
||||||
|
: `https://github.com/home-assistant/supervisor/releases/tag/${version}`;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UpdateAvailableDashboard extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public supervisor!: Supervisor;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
|
@state() private _updateEntry?: string;
|
||||||
|
|
||||||
|
@state() private _changelogContent?: string;
|
||||||
|
|
||||||
|
@state() private _addonInfo?: HassioAddonDetails;
|
||||||
|
|
||||||
|
@state() private _createBackup = true;
|
||||||
|
|
||||||
|
@state() private _action: "backup" | "update" | null = null;
|
||||||
|
|
||||||
|
@state() private _error?: string;
|
||||||
|
|
||||||
|
private _isAddon = false;
|
||||||
|
|
||||||
|
private _addonStoreInfo = memoizeOne(
|
||||||
|
(slug: string, storeAddons: StoreAddon[]) =>
|
||||||
|
storeAddons.find((addon) => addon.slug === slug)
|
||||||
|
);
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._updateEntry) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
const name =
|
||||||
|
// @ts-ignore
|
||||||
|
this._addonInfo?.name || SUPERVISOR_UPDATE_NAMES[this._updateEntry];
|
||||||
|
const changelog = !this._isAddon
|
||||||
|
? changelogUrl(
|
||||||
|
this.hass,
|
||||||
|
this._updateEntry,
|
||||||
|
this.supervisor[this._updateEntry]?.version
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
return html`
|
||||||
|
<hass-subpage
|
||||||
|
.hass=${this.hass}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
.route=${this.route}
|
||||||
|
>
|
||||||
|
<ha-card
|
||||||
|
.header=${this.supervisor.localize("update_available.update_name", {
|
||||||
|
name,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div class="card-content">
|
||||||
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
|
${this._action === null
|
||||||
|
? html`
|
||||||
|
${this._changelogContent
|
||||||
|
? html`
|
||||||
|
<ha-expansion-panel header="Changelog" outlined>
|
||||||
|
<ha-markdown .content=${this._changelogContent}>
|
||||||
|
</ha-markdown>
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<div class="versions">
|
||||||
|
<p>
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"update_available.description",
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
version:
|
||||||
|
this._addonInfo?.version ||
|
||||||
|
this.supervisor[this._updateEntry]?.version,
|
||||||
|
newest_version:
|
||||||
|
this._addonInfo?.version_latest ||
|
||||||
|
this.supervisor[this._updateEntry]?.version_latest,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
${this._updateEntry === "core"
|
||||||
|
? html`
|
||||||
|
<i>
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"update_available.core_note",
|
||||||
|
{
|
||||||
|
version:
|
||||||
|
this._addonInfo?.version ||
|
||||||
|
this.supervisor[this._updateEntry]?.version,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</i>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
${!["os", "supervisor"].includes(this._updateEntry)
|
||||||
|
? html`
|
||||||
|
<ha-settings-row>
|
||||||
|
<ha-checkbox
|
||||||
|
slot="prefix"
|
||||||
|
.checked=${this._createBackup}
|
||||||
|
@click=${this._toggleBackup}
|
||||||
|
>
|
||||||
|
</ha-checkbox>
|
||||||
|
<span slot="heading">
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"update_available.create_backup"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</ha-settings-row>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`
|
||||||
|
: html`<ha-circular-progress alt="Updating" size="large" active>
|
||||||
|
</ha-circular-progress>
|
||||||
|
<p class="progress-text">
|
||||||
|
${this._action === "update"
|
||||||
|
? this.supervisor.localize("update_available.updating", {
|
||||||
|
name,
|
||||||
|
version:
|
||||||
|
this._addonInfo?.version_latest ||
|
||||||
|
this.supervisor[this._updateEntry]?.version_latest,
|
||||||
|
})
|
||||||
|
: this.supervisor.localize(
|
||||||
|
"update_available.creating_backup",
|
||||||
|
{ name }
|
||||||
|
)}
|
||||||
|
</p>`}
|
||||||
|
</div>
|
||||||
|
${this._action === null
|
||||||
|
? html`
|
||||||
|
<div class="card-actions">
|
||||||
|
${changelog
|
||||||
|
? html`<a
|
||||||
|
.href=${changelog}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<mwc-button
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"update_available.open_release_notes"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
</mwc-button>
|
||||||
|
</a>`
|
||||||
|
: ""}
|
||||||
|
<span></span>
|
||||||
|
<ha-progress-button
|
||||||
|
.disabled=${this._error !== undefined}
|
||||||
|
@click=${this._update}
|
||||||
|
raised
|
||||||
|
>
|
||||||
|
${this.supervisor.localize("common.update")}
|
||||||
|
</ha-progress-button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</ha-card>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this._updateEntry = this.route.path.substring(1, this.route.path.length);
|
||||||
|
this._isAddon = !["core", "os", "supervisor"].includes(this._updateEntry);
|
||||||
|
if (this._isAddon) {
|
||||||
|
this._loadAddonData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _loadAddonData() {
|
||||||
|
try {
|
||||||
|
this._addonInfo = await fetchHassioAddonInfo(
|
||||||
|
this.hass,
|
||||||
|
this._updateEntry!
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this._updateEntry,
|
||||||
|
text: extractApiErrorMessage(err),
|
||||||
|
confirm: () => history.back(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const addonStoreInfo =
|
||||||
|
!this._addonInfo.detached && !this._addonInfo.available
|
||||||
|
? this._addonStoreInfo(
|
||||||
|
this._addonInfo.slug,
|
||||||
|
this.supervisor.store.addons
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (this._addonInfo.changelog) {
|
||||||
|
try {
|
||||||
|
const content = await fetchHassioAddonChangelog(
|
||||||
|
this.hass,
|
||||||
|
this._updateEntry!
|
||||||
|
);
|
||||||
|
this._changelogContent = extractChangelog(this._addonInfo, content);
|
||||||
|
} catch (err) {
|
||||||
|
this._error = extractApiErrorMessage(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._addonInfo.available && addonStoreInfo) {
|
||||||
|
if (
|
||||||
|
!addonArchIsSupported(
|
||||||
|
this.supervisor.info.supported_arch,
|
||||||
|
this._addonInfo.arch
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this._error = this.supervisor.localize(
|
||||||
|
"addon.dashboard.not_available_arch"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this._error = this.supervisor.localize(
|
||||||
|
"addon.dashboard.not_available_arch",
|
||||||
|
{
|
||||||
|
core_version_installed: this.supervisor.core.version,
|
||||||
|
core_version_needed: addonStoreInfo.homeassistant,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleBackup() {
|
||||||
|
this._createBackup = !this._createBackup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _update() {
|
||||||
|
if (this._createBackup) {
|
||||||
|
let backupArgs: HassioPartialBackupCreateParams;
|
||||||
|
if (this._isAddon) {
|
||||||
|
backupArgs = {
|
||||||
|
name: `addon_${this._updateEntry}_${this._addonInfo?.version}`,
|
||||||
|
addons: [this._updateEntry!],
|
||||||
|
homeassistant: false,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
backupArgs = {
|
||||||
|
name: `${this._updateEntry}_${this._addonInfo?.version}`,
|
||||||
|
folders: ["homeassistant"],
|
||||||
|
homeassistant: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._action = "backup";
|
||||||
|
try {
|
||||||
|
await createHassioPartialBackup(this.hass, backupArgs);
|
||||||
|
} catch (err: any) {
|
||||||
|
this._error = extractApiErrorMessage(err);
|
||||||
|
this._action = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._action = "update";
|
||||||
|
try {
|
||||||
|
if (this._isAddon) {
|
||||||
|
await updateHassioAddon(this.hass, this._updateEntry!);
|
||||||
|
} else if (this._updateEntry === "core") {
|
||||||
|
await updateCore(this.hass);
|
||||||
|
} else if (this._updateEntry === "os") {
|
||||||
|
await updateOS(this.hass);
|
||||||
|
} else if (this._updateEntry === "supervisor") {
|
||||||
|
await updateSupervisor(this.hass);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
|
this._error = extractApiErrorMessage(err);
|
||||||
|
this._action = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
history.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
hass-subpage {
|
||||||
|
--app-header-background-color: background-color: var(--primary-background-color);
|
||||||
|
}
|
||||||
|
ha-card {
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 16px;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
ha-settings-row {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.card-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-circular-progress {
|
||||||
|
display: block;
|
||||||
|
margin: 32px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("update-available-dashboard", UpdateAvailableDashboard);
|
@ -1,7 +1,30 @@
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { HassioAddonDetails } from "../../../src/data/hassio/addon";
|
||||||
import { SupervisorArch } from "../../../src/data/supervisor/supervisor";
|
import { SupervisorArch } from "../../../src/data/supervisor/supervisor";
|
||||||
|
|
||||||
export const addonArchIsSupported = memoizeOne(
|
export const addonArchIsSupported = memoizeOne(
|
||||||
(supported_archs: SupervisorArch[], addon_archs: SupervisorArch[]) =>
|
(supported_archs: SupervisorArch[], addon_archs: SupervisorArch[]) =>
|
||||||
addon_archs.some((arch) => supported_archs.includes(arch))
|
addon_archs.some((arch) => supported_archs.includes(arch))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const extractChangelog = (
|
||||||
|
addon: HassioAddonDetails,
|
||||||
|
content: string
|
||||||
|
): string => {
|
||||||
|
if (content.startsWith("# Changelog")) {
|
||||||
|
content = content.substr(12, content.length);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
content.includes(`# ${addon.version}`) &&
|
||||||
|
content.includes(`# ${addon.version_latest}`)
|
||||||
|
) {
|
||||||
|
const newcontent = content.split(`# ${addon.version}`)[0];
|
||||||
|
if (newcontent.includes(`# ${addon.version_latest}`)) {
|
||||||
|
// Only change the content if the new version still exist
|
||||||
|
// if the changelog does not have the newests version on top
|
||||||
|
// this will not be true, and we don't modify the content
|
||||||
|
content = newcontent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
@ -51,27 +51,31 @@ class HaAlert extends LitElement {
|
|||||||
[this.alertType]: true,
|
[this.alertType]: true,
|
||||||
})}"
|
})}"
|
||||||
>
|
>
|
||||||
<div class="icon ${this.title ? "" : "no-title"}">
|
<slot name="icon">
|
||||||
<ha-svg-icon .path=${ALERT_ICONS[this.alertType]}></ha-svg-icon>
|
<div class="icon ${this.title ? "" : "no-title"}">
|
||||||
</div>
|
<ha-svg-icon .path=${ALERT_ICONS[this.alertType]}></ha-svg-icon>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
${this.title ? html`<div class="title">${this.title}</div>` : ""}
|
${this.title ? html`<div class="title">${this.title}</div>` : ""}
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="action">
|
<div class="action">
|
||||||
${this.actionText
|
<slot name="action">
|
||||||
? html`<mwc-button
|
${this.actionText
|
||||||
@click=${this._action_clicked}
|
? html`<mwc-button
|
||||||
.label=${this.actionText}
|
@click=${this._action_clicked}
|
||||||
></mwc-button>`
|
.label=${this.actionText}
|
||||||
: this.dismissable
|
></mwc-button>`
|
||||||
? html`<ha-icon-button
|
: this.dismissable
|
||||||
@click=${this._dismiss_clicked}
|
? html`<ha-icon-button
|
||||||
label="Dismiss alert"
|
@click=${this._dismiss_clicked}
|
||||||
.path=${mdiClose}
|
label="Dismiss alert"
|
||||||
></ha-icon-button>`
|
.path=${mdiClose}
|
||||||
: ""}
|
></ha-icon-button>`
|
||||||
|
: ""}
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -107,14 +111,14 @@ class HaAlert extends LitElement {
|
|||||||
content: "";
|
content: "";
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
.icon {
|
slot > .icon {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
.icon.no-title {
|
.icon.no-title {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
.issue-type.rtl > .icon {
|
.issue-type.rtl > slot > .icon {
|
||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
@ -142,28 +146,28 @@ class HaAlert extends LitElement {
|
|||||||
ha-icon-button {
|
ha-icon-button {
|
||||||
--mdc-icon-button-size: 36px;
|
--mdc-icon-button-size: 36px;
|
||||||
}
|
}
|
||||||
.issue-type.info > .icon {
|
.issue-type.info > slot > .icon {
|
||||||
color: var(--info-color);
|
color: var(--info-color);
|
||||||
}
|
}
|
||||||
.issue-type.info::before {
|
.issue-type.info::before {
|
||||||
background-color: var(--info-color);
|
background-color: var(--info-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue-type.warning > .icon {
|
.issue-type.warning > slot > .icon {
|
||||||
color: var(--warning-color);
|
color: var(--warning-color);
|
||||||
}
|
}
|
||||||
.issue-type.warning::before {
|
.issue-type.warning::before {
|
||||||
background-color: var(--warning-color);
|
background-color: var(--warning-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue-type.error > .icon {
|
.issue-type.error > slot > .icon {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
.issue-type.error::before {
|
.issue-type.error::before {
|
||||||
background-color: var(--error-color);
|
background-color: var(--error-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue-type.success > .icon {
|
.issue-type.success > slot > .icon {
|
||||||
color: var(--success-color);
|
color: var(--success-color);
|
||||||
}
|
}
|
||||||
.issue-type.success::before {
|
.issue-type.success::before {
|
||||||
|
51
src/components/ha-logo-svg.ts
Normal file
51
src/components/ha-logo-svg.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { css, CSSResultGroup, LitElement, svg, SVGTemplateResult } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
|
||||||
|
@customElement("ha-logo-svg")
|
||||||
|
export class HaLogoSvg extends LitElement {
|
||||||
|
protected render(): SVGTemplateResult {
|
||||||
|
return svg`
|
||||||
|
<svg version="1.1" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs>
|
||||||
|
<path id="a" d="m44.041 343.22v-133.64h-34.753a9.333 9.333 0 0 1-6.655-15.876l187.01-190.21c4.517-4.594 11.903-4.657 16.498-0.14l0.12 0.12 97.601 98.794v-18.297a7.778 7.778 0 0 1 7.778-7.778h32.41a7.778 7.778 0 0 1 7.779 7.778v67.138l41.568 42.618a9.333 9.333 0 0 1-6.682 15.85h-34.886v133.64a7.778 7.778 0 0 1-7.778 7.778h-292.23a7.778 7.778 0 0 1-7.778-7.778zm206.39-163.26a15.029 15.029 0 0 0 1.46-6.486c0-8.308-6.71-15.043-14.989-15.043-8.278 0-14.989 6.735-14.989 15.043s6.711 15.044 14.99 15.044c2.314 0 4.505-0.527 6.462-1.467l21.518 21.596v20.918l-26.981 27.078v-19.84a15.046 15.046 0 0 0 9.993-14.187c0-8.308-6.711-15.044-14.99-15.044-8.278 0-14.99 6.736-14.99 15.044 0 6.55 4.172 12.122 9.994 14.187v29.868l-24.983 25.073v-147.28l20.519-20.592a14.886 14.886 0 0 0 6.462 1.466c8.279 0 14.99-6.735 14.99-15.044 0-8.308-6.711-15.043-14.99-15.043-8.278 0-14.989 6.735-14.989 15.043 0 2.323 0.524 4.522 1.46 6.486l-18.448 18.515-18.449-18.515a15.029 15.029 0 0 0 1.46-6.486c0-8.308-6.71-15.043-14.989-15.043-8.278 0-14.989 6.735-14.989 15.043 0 8.309 6.711 15.044 14.99 15.044 2.314 0 4.505-0.527 6.462-1.466l20.518 20.592v105.16l-35.974-36.104v-28.865a15.046 15.046 0 0 0 9.993-14.187c0-8.309-6.711-15.044-14.99-15.044-8.278 0-14.99 6.735-14.99 15.044 0 6.55 4.172 12.122 9.994 14.187v18.837l-27.98-28.081v-27.863a15.046 15.046 0 0 0 9.993-14.187c0-8.308-6.711-15.044-14.99-15.044-8.278 0-14.99 6.736-14.99 15.044 0 6.55 4.172 12.122 9.994 14.187v32.017l30.907 31.018h-17.77c-2.058-5.843-7.61-10.029-14.137-10.029-8.278 0-14.99 6.735-14.99 15.043 0 8.309 6.712 15.044 14.99 15.044 6.527 0 12.08-4.186 14.137-10.03h27.763l43.04 43.196v75.074l-22.983-23.066v-28.866a15.046 15.046 0 0 0 9.993-14.187c0-8.308-6.711-15.043-14.99-15.043-8.278 0-14.99 6.735-14.99 15.043 0 6.55 4.172 12.122 9.994 14.187v18.837l-33.439-33.558a15.029 15.029 0 0 0 1.461-6.486c0-8.308-6.71-15.043-14.99-15.043-8.278 0-14.989 6.735-14.989 15.043s6.711 15.043 14.99 15.043c2.314 0 4.506-0.526 6.462-1.466l33.439 33.559h-17.77c-2.058-5.843-7.61-10.03-14.137-10.03-8.278 0-14.99 6.736-14.99 15.044s6.712 15.043 14.99 15.043c6.527 0 12.079-4.186 14.137-10.029h27.763l27.98 28.081h14.132l28.98-29.083h26.763c2.058 5.842 7.61 10.028 14.137 10.028 8.278 0 14.99-6.735 14.99-15.043s-6.712-15.043-14.99-15.043c-6.527 0-12.079 4.186-14.137 10.029h-30.902l-26.91 27.006v-32.951l32.049-32.164h51.746c2.058 5.843 7.61 10.029 14.136 10.029 8.279 0 14.99-6.735 14.99-15.043 0-8.309-6.711-15.044-14.99-15.044-6.526 0-12.078 4.186-14.136 10.03h-41.755l29.908-30.016v-25.072l21.517-21.596a14.886 14.886 0 0 0 6.463 1.467c8.278 0 14.99-6.736 14.99-15.044s-6.712-15.043-14.99-15.043-14.99 6.735-14.99 15.043c0 2.323 0.525 4.522 1.461 6.486l-14.451 14.504v-45.917a15.046 15.046 0 0 0 9.993-14.187c0-8.309-6.711-15.044-14.99-15.044-8.278 0-14.99 6.735-14.99 15.044 0 6.55 4.172 12.122 9.994 14.187v45.915l-14.452-14.504zm-129.45 143.95c-3.311 0-5.996-2.694-5.996-6.017s2.685-6.017 5.996-6.017c3.312 0 5.996 2.694 5.996 6.017s-2.684 6.017-5.996 6.017zm43.97-45.13c-3.312 0-5.997-2.694-5.997-6.017s2.685-6.017 5.996-6.017c3.312 0 5.996 2.694 5.996 6.017s-2.684 6.017-5.996 6.017zm-51.964-7.02c-3.312 0-5.996-2.694-5.996-6.017s2.684-6.017 5.996-6.017c3.311 0 5.996 2.694 5.996 6.017s-2.685 6.017-5.996 6.017zm-4.997-50.144c-3.311 0-5.995-2.694-5.995-6.018 0-3.323 2.684-6.017 5.995-6.017 3.312 0 5.996 2.694 5.996 6.017 0 3.324-2.684 6.018-5.996 6.018zm124.91 7.02c-3.311 0-5.995-2.694-5.995-6.017 0-3.324 2.684-6.018 5.995-6.018 3.312 0 5.996 2.694 5.996 6.018 0 3.323-2.684 6.017-5.996 6.017zm67.952 46.133c-3.31 0-5.995-2.694-5.995-6.017 0-3.324 2.684-6.018 5.995-6.018 3.312 0 5.996 2.694 5.996 6.018 0 3.323-2.684 6.017-5.996 6.017zm-25.981 48.138c-3.312 0-5.996-2.694-5.996-6.017s2.684-6.017 5.996-6.017c3.311 0 5.996 2.694 5.996 6.017s-2.685 6.017-5.996 6.017zm27.98-143.41c-3.311 0-5.996-2.695-5.996-6.018s2.685-6.017 5.996-6.017 5.996 2.694 5.996 6.017-2.685 6.018-5.996 6.018zm-32.977-39.113c-3.311 0-5.996-2.694-5.996-6.017 0-3.324 2.685-6.018 5.996-6.018 3.312 0 5.996 2.694 5.996 6.018 0 3.323-2.684 6.017-5.996 6.017zm-39.972-24.07c-3.311 0-5.995-2.693-5.995-6.017 0-3.323 2.684-6.017 5.995-6.017 3.312 0 5.996 2.694 5.996 6.017 0 3.324-2.684 6.018-5.996 6.018zm-63.955 0c-3.31 0-5.995-2.693-5.995-6.017 0-3.323 2.684-6.017 5.995-6.017 3.312 0 5.996 2.694 5.996 6.017 0 3.324-2.684 6.018-5.996 6.018zm-51.963 23.067c-3.311 0-5.996-2.694-5.996-6.017 0-3.324 2.685-6.018 5.996-6.018s5.996 2.694 5.996 6.018c0 3.323-2.685 6.017-5.996 6.017zm37.973 37.107c-3.311 0-5.995-2.694-5.995-6.017 0-3.324 2.684-6.018 5.995-6.018 3.312 0 5.996 2.694 5.996 6.018 0 3.323-2.684 6.017-5.996 6.017zm84.94 3.009c-3.31 0-5.995-2.695-5.995-6.018s2.684-6.017 5.995-6.017c3.312 0 5.996 2.694 5.996 6.017s-2.684 6.018-5.996 6.018z"/>
|
||||||
|
</defs>
|
||||||
|
<g fill="none" fill-rule="evenodd">
|
||||||
|
<rect width="500" height="500" ry="40.911" fill="#41bdf5" fill-rule="evenodd" stroke-width="5.8497"/>
|
||||||
|
<g transform="translate(52 70)">
|
||||||
|
<mask id="b" fill="#fff">
|
||||||
|
<use xlink:href="#a"/>
|
||||||
|
</mask>
|
||||||
|
<g fill="#FFF" mask="url(#b)">
|
||||||
|
<path d="M0 0h396v351H0z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: var(--ha-icon-display, inline-flex);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: middle;
|
||||||
|
fill: currentcolor;
|
||||||
|
width: var(--mdc-icon-size, 24px);
|
||||||
|
height: var(--mdc-icon-size, 24px);
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-logo-svg": HaLogoSvg;
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ import {
|
|||||||
} from "../external_app/external_config";
|
} from "../external_app/external_config";
|
||||||
import { actionHandler } from "../panels/lovelace/common/directives/action-handler-directive";
|
import { actionHandler } from "../panels/lovelace/common/directives/action-handler-directive";
|
||||||
import { haStyleScrollbar } from "../resources/styles";
|
import { haStyleScrollbar } from "../resources/styles";
|
||||||
import type { HomeAssistant, PanelInfo } from "../types";
|
import type { HomeAssistant, PanelInfo, Route } from "../types";
|
||||||
import "./ha-icon";
|
import "./ha-icon";
|
||||||
import "./ha-icon-button";
|
import "./ha-icon-button";
|
||||||
import "./ha-menu-button";
|
import "./ha-menu-button";
|
||||||
@ -189,6 +189,8 @@ class HaSidebar extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
|
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@property() public route!: Route;
|
||||||
|
|
||||||
@property({ type: Boolean }) public alwaysExpand = false;
|
@property({ type: Boolean }) public alwaysExpand = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public editMode = false;
|
@property({ type: Boolean }) public editMode = false;
|
||||||
@ -351,12 +353,19 @@ class HaSidebar extends LitElement {
|
|||||||
this._hiddenPanels
|
this._hiddenPanels
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Show the update-available as beeing part of configuration
|
||||||
|
const selectedPanel = this.route.path?.startsWith(
|
||||||
|
"/hassio/update-available"
|
||||||
|
)
|
||||||
|
? "config"
|
||||||
|
: this.hass.panelUrl;
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return html`
|
return html`
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
attr-for-selected="data-panel"
|
attr-for-selected="data-panel"
|
||||||
class="ha-scrollbar"
|
class="ha-scrollbar"
|
||||||
.selected=${this.hass.panelUrl}
|
.selected=${selectedPanel}
|
||||||
@focusin=${this._listboxFocusIn}
|
@focusin=${this._listboxFocusIn}
|
||||||
@focusout=${this._listboxFocusOut}
|
@focusout=${this._listboxFocusOut}
|
||||||
@scroll=${this._listboxScroll}
|
@scroll=${this._listboxScroll}
|
||||||
|
@ -70,6 +70,42 @@ export interface Supervisor {
|
|||||||
localize: LocalizeFunc;
|
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 = <T>(
|
export const supervisorApiWsRequest = <T>(
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
request: supervisorApiRequest
|
request: supervisorApiRequest
|
||||||
@ -139,3 +175,14 @@ export const subscribeSupervisorEvents = (
|
|||||||
getSupervisorEventCollection(hass.connection, key, endpoint).subscribe(
|
getSupervisorEventCollection(hass.connection, key, endpoint).subscribe(
|
||||||
onChange
|
onChange
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const fetchSupervisorAvailableUpdates = async (
|
||||||
|
hass: HomeAssistant
|
||||||
|
): Promise<SupervisorAvailableUpdates[]> =>
|
||||||
|
(
|
||||||
|
await hass.callWS<SupervisorAvailableUpdatesResponse>({
|
||||||
|
type: "supervisor/api",
|
||||||
|
endpoint: "/supervisor/available_updates",
|
||||||
|
method: "get",
|
||||||
|
})
|
||||||
|
).available_updates;
|
||||||
|
@ -88,6 +88,7 @@ class HomeAssistantMain extends LitElement {
|
|||||||
<ha-sidebar
|
<ha-sidebar
|
||||||
.hass=${hass}
|
.hass=${hass}
|
||||||
.narrow=${sidebarNarrow}
|
.narrow=${sidebarNarrow}
|
||||||
|
.route=${this.route}
|
||||||
.editMode=${this._sidebarEditMode}
|
.editMode=${this._sidebarEditMode}
|
||||||
.alwaysExpand=${sidebarNarrow ||
|
.alwaysExpand=${sidebarNarrow ||
|
||||||
this.hass.dockedSidebar === "docked"}
|
this.hass.dockedSidebar === "docked"}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "./ha-config-updates";
|
||||||
import { mdiCloudLock } from "@mdi/js";
|
import { mdiCloudLock } from "@mdi/js";
|
||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
@ -35,10 +36,16 @@ class HaConfigDashboard extends LitElement {
|
|||||||
>
|
>
|
||||||
<div slot="header">${this.hass.localize("ui.panel.config.header")}</div>
|
<div slot="header">${this.hass.localize("ui.panel.config.header")}</div>
|
||||||
|
|
||||||
<div slot="introduction">
|
<div class="intro" slot="introduction">
|
||||||
${this.hass.localize("ui.panel.config.introduction")}
|
${this.hass.localize("ui.panel.config.introduction")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${isComponentLoaded(this.hass, "hassio")
|
||||||
|
? html`<ha-config-updates
|
||||||
|
.hass=${this.hass}
|
||||||
|
slot="introduction"
|
||||||
|
></ha-config-updates>`
|
||||||
|
: ""}
|
||||||
${this.cloudStatus && isComponentLoaded(this.hass, "cloud")
|
${this.cloudStatus && isComponentLoaded(this.hass, "cloud")
|
||||||
? html`
|
? html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
@ -134,6 +141,9 @@ class HaConfigDashboard extends LitElement {
|
|||||||
.promo-advanced a {
|
.promo-advanced a {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
.intro {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
120
src/panels/config/dashboard/ha-config-updates.ts
Normal file
120
src/panels/config/dashboard/ha-config-updates.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
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,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../components/ha-alert";
|
||||||
|
import "../../../components/ha-logo-svg";
|
||||||
|
import "../../../components/ha-svg-icon";
|
||||||
|
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||||
|
import {
|
||||||
|
fetchSupervisorAvailableUpdates,
|
||||||
|
SupervisorAvailableUpdates,
|
||||||
|
} from "../../../data/supervisor/supervisor";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
|
export const SUPERVISOR_UPDATE_NAMES = {
|
||||||
|
core: "Home Assistant Core",
|
||||||
|
os: "Home Assistant Operating System",
|
||||||
|
supervisor: "Home Assistant Supervisor",
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("ha-config-updates")
|
||||||
|
class HaConfigUpdates extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _supervisorUpdates?: SupervisorAvailableUpdates[];
|
||||||
|
|
||||||
|
@state() private _error?: string;
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues): void {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this._loadSupervisorUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${this._error
|
||||||
|
? html`<ha-alert
|
||||||
|
.title=${this.hass.localize(
|
||||||
|
"ui.panel.config.updates.unable_to_fetch"
|
||||||
|
)}
|
||||||
|
alert-type="error"
|
||||||
|
>
|
||||||
|
${this._error}
|
||||||
|
</ha-alert>`
|
||||||
|
: ""}
|
||||||
|
${this._supervisorUpdates?.map(
|
||||||
|
(update) => html`
|
||||||
|
<ha-alert
|
||||||
|
.title=${update.update_type === "addon"
|
||||||
|
? update.name
|
||||||
|
: SUPERVISOR_UPDATE_NAMES[update.update_type!]}
|
||||||
|
>
|
||||||
|
<span slot="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>`}
|
||||||
|
</span>
|
||||||
|
${this.hass.localize("ui.panel.config.updates.version_available", {
|
||||||
|
version_available: update.version_latest,
|
||||||
|
})}
|
||||||
|
<a href="/hassio${update.panel_path}" slot="action">
|
||||||
|
<mwc-button
|
||||||
|
.label=${this.hass.localize("ui.panel.config.updates.review")}
|
||||||
|
>
|
||||||
|
</mwc-button>
|
||||||
|
</a>
|
||||||
|
</ha-alert>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _loadSupervisorUpdates(): Promise<void> {
|
||||||
|
try {
|
||||||
|
this._supervisorUpdates = await fetchSupervisorAvailableUpdates(
|
||||||
|
this.hass
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
this._error = extractApiErrorMessage(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
place-self: center;
|
||||||
|
}
|
||||||
|
img,
|
||||||
|
ha-svg-icon,
|
||||||
|
ha-logo-svg {
|
||||||
|
width: var(--mdc-icon-size, 32px);
|
||||||
|
height: var(--mdc-icon-size, 32px);
|
||||||
|
padding-right: 12px;
|
||||||
|
display: block;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-config-updates": HaConfigUpdates;
|
||||||
|
}
|
||||||
|
}
|
@ -926,6 +926,11 @@
|
|||||||
},
|
},
|
||||||
"learn_more": "Learn more"
|
"learn_more": "Learn more"
|
||||||
},
|
},
|
||||||
|
"updates": {
|
||||||
|
"unable_to_fetch": "Unable to fetch available updates",
|
||||||
|
"version_available": "Version {version_available} is available",
|
||||||
|
"review": "review"
|
||||||
|
},
|
||||||
"areas": {
|
"areas": {
|
||||||
"caption": "Areas",
|
"caption": "Areas",
|
||||||
"description": "Group devices and entities into areas",
|
"description": "Group devices and entities into areas",
|
||||||
@ -4178,6 +4183,7 @@
|
|||||||
"save": "[%key:ui::common::save%]",
|
"save": "[%key:ui::common::save%]",
|
||||||
"close": "[%key:ui::common::close%]",
|
"close": "[%key:ui::common::close%]",
|
||||||
"menu": "[%key:ui::common::menu%]",
|
"menu": "[%key:ui::common::menu%]",
|
||||||
|
"review": "[%key:ui::panel::config::updates::review%]",
|
||||||
"show_more": "Show more information about this",
|
"show_more": "Show more information about this",
|
||||||
"update_available": "{count, plural,\n one {Update}\n other {{count} updates}\n} pending",
|
"update_available": "{count, plural,\n one {Update}\n other {{count} updates}\n} pending",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
@ -4187,11 +4193,16 @@
|
|||||||
"update_failed": "Update failed"
|
"update_failed": "Update failed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"update_available": {
|
||||||
|
"update_name": "Update {name}",
|
||||||
|
"open_release_notes": "Open release notes",
|
||||||
|
"create_backup": "Create backup before updating",
|
||||||
|
"description": "There is an update available for the {name}. You have {version} installed. Click update to update to version {newest_version}",
|
||||||
|
"core_note": "The supervisor will roll back to version {version} if your instance does not come up after the update.",
|
||||||
|
"updating": "Updating {name} to version {version}",
|
||||||
|
"creating_backup": "Creating backup of {name}"
|
||||||
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"update": {
|
|
||||||
"title": "Update {name}",
|
|
||||||
"text": "Are you sure you want to update {name} to version {version}?"
|
|
||||||
},
|
|
||||||
"restart": {
|
"restart": {
|
||||||
"title": "[%key:supervisor::common::restart_name%]",
|
"title": "[%key:supervisor::common::restart_name%]",
|
||||||
"text": "Are you sure you want to restart {name}?"
|
"text": "Are you sure you want to restart {name}?"
|
||||||
@ -4215,6 +4226,7 @@
|
|||||||
"repositories": "Repositories"
|
"repositories": "Repositories"
|
||||||
},
|
},
|
||||||
"panel": {
|
"panel": {
|
||||||
|
"addons": "Add-ons",
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"backups": "Backups",
|
"backups": "Backups",
|
||||||
"store": "Add-on Store",
|
"store": "Add-on Store",
|
||||||
@ -4382,12 +4394,6 @@
|
|||||||
"confirm_text": "Restart add-on",
|
"confirm_text": "Restart add-on",
|
||||||
"text": "Do you want to restart the add-on with your changes?"
|
"text": "Do you want to restart the add-on with your changes?"
|
||||||
},
|
},
|
||||||
"update": {
|
|
||||||
"backup": "Backup",
|
|
||||||
"create_backup": "Create a backup of {name} before updating",
|
|
||||||
"updating": "Updating {name} to version {version}",
|
|
||||||
"creating_backup": "Creating backup of {name}"
|
|
||||||
},
|
|
||||||
"hardware": {
|
"hardware": {
|
||||||
"title": "Hardware",
|
"title": "Hardware",
|
||||||
"search": "Search hardware",
|
"search": "Search hardware",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user