Use localize in the Supervisor panel (#8515)

This commit is contained in:
Joakim Sørensen 2021-03-02 14:46:30 +01:00 committed by GitHub
parent 25a0be7672
commit 03b8c1348c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1169 additions and 520 deletions

View File

@ -15,6 +15,7 @@ import {
HassioAddonInfo,
HassioAddonRepository,
} from "../../../src/data/hassio/addon";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { HomeAssistant } from "../../../src/types";
import "../components/hassio-card-content";
import { filterAndSort } from "../components/hassio-filter-addons";
@ -23,6 +24,8 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioAddonRepositoryEl extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public repo!: HassioAddonRepository;
@property({ attribute: false }) public addons!: HassioAddonInfo[];
@ -54,7 +57,11 @@ class HassioAddonRepositoryEl extends LitElement {
return html`
<div class="content">
<p class="description">
No results found in "${repo.name}."
${this.supervisor.localize(
"store.no_results_found",
"repository",
repo.name
)}
</p>
</div>
`;
@ -83,11 +90,13 @@ class HassioAddonRepositoryEl extends LitElement {
: mdiPuzzle}
.iconTitle=${addon.installed
? addon.update_available
? "New version available"
: "Add-on is installed"
? this.supervisor.localize(
"common.new_version_available"
)
: this.supervisor.localize("addon.installed")
: addon.available
? "Add-on is not installed"
: "Add-on is not available on your system"}
? this.supervisor.localize("addon.not_installed")
: this.supervisor.localize("addon.not_available")}
.iconClass=${addon.installed
? addon.update_available
? "update"

View File

@ -96,15 +96,15 @@ class HassioAddonStore extends LitElement {
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item>
Repositories
${this.supervisor.localize("store.repositories")}
</mwc-list-item>
<mwc-list-item>
Reload
${this.supervisor.localize("common.reload")}
</mwc-list-item>
${this.hass.userData?.showAdvanced &&
atLeastVersion(this.hass.config.version, 0, 117)
? html`<mwc-list-item>
Registries
${this.supervisor.localize("store.registries")}
</mwc-list-item>`
: ""}
</ha-button-menu>
@ -125,11 +125,9 @@ class HassioAddonStore extends LitElement {
${!this.hass.userData?.showAdvanced
? html`
<div class="advanced">
Missing add-ons? Enable advanced mode on
<a href="/profile" target="_top">
your profile page
${this.supervisor.localize("store.missing_addons")}
</a>
.
</div>
`
: ""}
@ -161,6 +159,7 @@ class HassioAddonStore extends LitElement {
.repo=${repo}
.addons=${filteredAddons}
.filter=${filter!}
.supervisor=${this.supervisor}
></hassio-addon-repository>
`
: html``;
@ -190,13 +189,13 @@ class HassioAddonStore extends LitElement {
private async _manageRepositories() {
showRepositoriesDialog(this, {
repos: this.supervisor.addon.repositories,
supervisor: this.supervisor,
loadData: () => this._loadData(),
});
}
private async _manageRegistries() {
showRegistriesDialog(this);
showRegistriesDialog(this, { supervisor: this.supervisor });
}
private async _loadData() {

View File

@ -25,6 +25,7 @@ import {
fetchHassioHardwareAudio,
HassioHardwareAudioDevice,
} from "../../../../src/data/hassio/hardware";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
@ -34,6 +35,8 @@ import { hassioStyle } from "../../resources/hassio-style";
class HassioAddonAudio extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public addon!: HassioAddonDetails;
@internalProperty() private _error?: string;
@ -48,12 +51,16 @@ class HassioAddonAudio extends LitElement {
protected render(): TemplateResult {
return html`
<ha-card header="Audio">
<ha-card
.header=${this.supervisor.localize("addon.configuration.audio.header")}
>
<div class="card-content">
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
<paper-dropdown-menu
label="Input"
.label=${this.supervisor.localize(
"addon.configuration.audio.input"
)}
@iron-select=${this._setInputDevice}
>
<paper-listbox
@ -64,15 +71,17 @@ class HassioAddonAudio extends LitElement {
${this._inputDevices &&
this._inputDevices.map((item) => {
return html`
<paper-item device=${item.device || ""}
>${item.name}</paper-item
>
<paper-item device=${item.device || ""}>
${item.name}
</paper-item>
`;
})}
</paper-listbox>
</paper-dropdown-menu>
<paper-dropdown-menu
label="Output"
.label=${this.supervisor.localize(
"addon.configuration.audio.output"
)}
@iron-select=${this._setOutputDevice}
>
<paper-listbox
@ -93,7 +102,7 @@ class HassioAddonAudio extends LitElement {
</div>
<div class="card-actions">
<ha-progress-button @click=${this._saveSettings}>
Save
${this.supervisor.localize("common.save")}
</ha-progress-button>
</div>
</ha-card>
@ -152,7 +161,7 @@ class HassioAddonAudio extends LitElement {
const noDevice: HassioHardwareAudioDevice = {
device: "default",
name: "Default",
name: this.supervisor.localize("addon.configuration.audio.default"),
};
try {
@ -189,7 +198,7 @@ class HassioAddonAudio extends LitElement {
try {
await setHassioAddonOption(this.hass, this.addon.slug, data);
if (this.addon?.state === "started") {
await suggestAddonRestart(this, this.hass, this.addon);
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch {
this._error = "Failed to set addon audio device";

View File

@ -9,6 +9,7 @@ import {
} from "lit-element";
import "../../../../src/components/ha-circular-progress";
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { hassioStyle } from "../../resources/hassio-style";
@ -20,6 +21,8 @@ import "./hassio-addon-network";
class HassioAddonConfigDashboard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public addon?: HassioAddonDetails;
protected render(): TemplateResult {
@ -39,6 +42,7 @@ class HassioAddonConfigDashboard extends LitElement {
<hassio-addon-config
.hass=${this.hass}
.addon=${this.addon}
.supervisor=${this.supervisor}
></hassio-addon-config>
`
: ""}
@ -47,6 +51,7 @@ class HassioAddonConfigDashboard extends LitElement {
<hassio-addon-network
.hass=${this.hass}
.addon=${this.addon}
.supervisor=${this.supervisor}
></hassio-addon-network>
`
: ""}
@ -55,11 +60,12 @@ class HassioAddonConfigDashboard extends LitElement {
<hassio-addon-audio
.hass=${this.hass}
.addon=${this.addon}
.supervisor=${this.supervisor}
></hassio-addon-audio>
`
: ""}
`
: "This add-on does not expose configuration for you to mess with.... 👋"}
: this.supervisor.localize("addon.configuration.no_configuration")}
</div>
`;
}

View File

@ -32,6 +32,7 @@ import {
setHassioAddonOption,
} from "../../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { showConfirmationDialog } from "../../../../src/dialogs/generic/show-dialog-box";
import { haStyle } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
@ -46,6 +47,8 @@ class HassioAddonConfig extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) private _configHasChanged = false;
@property({ type: Boolean }) private _valid = true;
@ -90,17 +93,25 @@ class HassioAddonConfig extends LitElement {
<h1>${this.addon.name}</h1>
<ha-card>
<div class="header">
<h2>Configuration</h2>
<h2>
${this.supervisor.localize("addon.configuration.options.header")}
</h2>
<div class="card-menu">
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
<mwc-icon-button slot="trigger">
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item .disabled=${!this._canShowSchema}>
${this._yamlMode ? "Edit in UI" : "Edit in YAML"}
${this._yamlMode
? this.supervisor.localize(
"addon.configuration.options.edit_in_ui"
)
: this.supervisor.localize(
"addon.configuration.options.edit_in_yaml"
)}
</mwc-list-item>
<mwc-list-item class="warning">
Reset to defaults
${this.supervisor.localize("common.reset_defaults")}
</mwc-list-item>
</ha-button-menu>
</div>
@ -127,12 +138,20 @@ class HassioAddonConfig extends LitElement {
(this._canShowSchema && this.addon.schema) ||
this._valid
? ""
: html` <div class="errors">Invalid YAML</div> `}
: html`
<div class="errors">
${this.supervisor.localize(
"addon.configuration.options.invalid_yaml"
)}
</div>
`}
</div>
${hasHiddenOptions
? html`<ha-formfield
class="show-additional"
label="Show unused optional configuration options"
.label=${this.supervisor.localize(
"addon.configuration.options.show_unused_optional"
)}
>
<ha-switch
@change=${this._toggleOptional}
@ -146,7 +165,7 @@ class HassioAddonConfig extends LitElement {
@click=${this._saveTapped}
.disabled=${!this._configHasChanged || !this._valid}
>
Save
Save ${this.supervisor.localize("common.save")}
</ha-progress-button>
</div>
</ha-card>
@ -211,10 +230,10 @@ class HassioAddonConfig extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: this.addon.name,
text: "Are you sure you want to reset all your options?",
confirmText: "reset options",
dismissText: "no",
title: this.supervisor.localize("confirm.reset_options.title"),
text: this.supervisor.localize("confirm.reset_options.text"),
confirmText: this.supervisor.localize("common.reset_options"),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -236,9 +255,11 @@ class HassioAddonConfig extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
this._error = `Failed to reset addon configuration, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.common.update_available",
"error",
extractApiErrorMessage(err)
);
}
button.progress = false;
}
@ -262,12 +283,14 @@ class HassioAddonConfig extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
if (this.addon?.state === "started") {
await suggestAddonRestart(this, this.hass, this.addon);
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch (err) {
this._error = `Failed to save addon configuration, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.configuration.options.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
button.progress = false;
}

View File

@ -19,6 +19,7 @@ import {
setHassioAddonOption,
} from "../../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
@ -38,6 +39,8 @@ interface NetworkItemInput extends PaperInputElement {
class HassioAddonNetwork extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public addon!: HassioAddonDetails;
@internalProperty() private _error?: string;
@ -55,16 +58,30 @@ class HassioAddonNetwork extends LitElement {
}
return html`
<ha-card header="Network">
<ha-card
.header=${this.supervisor.localize(
"addon.configuration.network.header"
)}
>
<div class="card-content">
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
<table>
<tbody>
<tr>
<th>Container</th>
<th>Host</th>
<th>Description</th>
<th>
${this.supervisor.localize(
"addon.configuration.network.container"
)}
</th>
<th>
${this.supervisor.localize(
"addon.configuration.network.host"
)}
</th>
<th>
${this.supervisor.localize("common.description")}
</th>
</tr>
${this._config!.map((item) => {
return html`
@ -73,13 +90,15 @@ class HassioAddonNetwork extends LitElement {
<td>
<paper-input
@value-changed=${this._configChanged}
placeholder="disabled"
placeholder="${this.supervisor.localize(
"addon.configuration.network.disabled"
)}"
.value=${item.host ? String(item.host) : ""}
.container=${item.container}
no-label-float
></paper-input>
</td>
<td>${item.description}</td>
<td>${this._computeDescription(item)}</td>
</tr>
`;
})}
@ -88,10 +107,10 @@ class HassioAddonNetwork extends LitElement {
</div>
<div class="card-actions">
<ha-progress-button class="warning" @click=${this._resetTapped}>
Reset to defaults
${this.supervisor.localize("common.reset_defaults")}
</ha-progress-button>
<ha-progress-button @click=${this._saveTapped}>
Save
${this.supervisor.localize("common.save")}
</ha-progress-button>
</div>
</ha-card>
@ -105,6 +124,15 @@ class HassioAddonNetwork extends LitElement {
}
}
private _computeDescription = (item: NetworkItem): string => {
return (
this.addon.translations[this.hass.language]?.network?.[item.container]
?.description ||
this.addon.translations.en?.network?.[item.container]?.description ||
item.description
);
};
private _setNetworkConfig(): void {
const network = this.addon.network || {};
const description = this.addon.network_description || {};
@ -147,12 +175,14 @@ class HassioAddonNetwork extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
if (this.addon?.state === "started") {
await suggestAddonRestart(this, this.hass, this.addon);
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch (err) {
this._error = `Failed to set addon network configuration, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_reset",
"error",
extractApiErrorMessage(err)
);
}
button.progress = false;
@ -181,12 +211,14 @@ class HassioAddonNetwork extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
if (this.addon?.state === "started") {
await suggestAddonRestart(this, this.hass, this.addon);
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch (err) {
this._error = `Failed to set addon network configuration, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
button.progress = false;
}

View File

@ -1,3 +1,4 @@
import "../../../../src/components/ha-card";
import {
css,
CSSResult,
@ -19,11 +20,14 @@ import "../../../../src/layouts/hass-loading-screen";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { hassioStyle } from "../../resources/hassio-style";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
@customElement("hassio-addon-documentation-tab")
class HassioAddonDocumentationDashboard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public addon?: HassioAddonDetails;
@internalProperty() private _error?: string;
@ -81,9 +85,11 @@ class HassioAddonDocumentationDashboard extends LitElement {
this.addon!.slug
);
} catch (err) {
this._error = `Failed to get addon documentation, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.documentation.get_logs",
"error",
extractApiErrorMessage(err)
);
}
}
}

View File

@ -79,7 +79,6 @@ class HassioAddonDashboard extends LitElement {
const addonTabs: PageNavigation[] = [
{
name: "Info",
translationKey: "addon.panel.info",
path: `/hassio/addon/${this.addon.slug}/info`,
iconPath: mdiInformationVariant,
@ -88,7 +87,6 @@ class HassioAddonDashboard extends LitElement {
if (this.addon.documentation) {
addonTabs.push({
name: "Documentation",
translationKey: "addon.panel.documentation",
path: `/hassio/addon/${this.addon.slug}/documentation`,
iconPath: mdiFileDocument,
@ -98,13 +96,11 @@ class HassioAddonDashboard extends LitElement {
if (this.addon.version) {
addonTabs.push(
{
name: "Configuration",
translationKey: "addon.panel.configuration",
path: `/hassio/addon/${this.addon.slug}/config`,
iconPath: mdiCogs,
},
{
name: "Log",
translationKey: "addon.panel.log",
path: `/hassio/addon/${this.addon.slug}/logs`,
iconPath: mdiMathLog,

View File

@ -79,63 +79,6 @@ const STAGE_ICON = {
deprecated: mdiExclamationThick,
};
const PERMIS_DESC = {
stage: {
title: "Add-on Stage",
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
},
rating: {
title: "Add-on Security Rating",
description:
"Home Assistant provides a security rating to each of the add-ons, which indicates the risks involved when using this add-on. The more access an add-on requires on your system, the lower the score, thus raising the possible security risks.\n\nA score is on a scale from 1 to 6. Where 1 is the lowest score (considered the most insecure and highest risk) and a score of 6 is the highest score (considered the most secure and lowest risk).",
},
host_network: {
title: "Host Network",
description:
"Add-ons usually run in their own isolated network layer, which prevents them from accessing the network of the host operating system. In some cases, this network isolation can limit add-ons in providing their services and therefore, the isolation can be lifted by the add-on author, giving the add-on full access to the network capabilities of the host machine. This gives the add-on more networking capabilities but lowers the security, hence, the security rating of the add-on will be lowered when this option is used by the add-on.",
},
homeassistant_api: {
title: "Home Assistant API Access",
description:
"This add-on is allowed to access your running Home Assistant instance directly via the Home Assistant API. This mode handles authentication for the add-on as well, which enables an add-on to interact with Home Assistant without the need for additional authentication tokens.",
},
full_access: {
title: "Full Hardware Access",
description:
"This add-on is given full access to the hardware of your system, by request of the add-on author. Access is comparable to the privileged mode in Docker. Since this opens up possible security risks, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on.",
},
hassio_api: {
title: "Supervisor API Access",
description:
"The add-on was given access to the Supervisor API, by request of the add-on author. By default, the add-on can access general version information of your system. When the add-on requests 'manager' or 'admin' level access to the API, it will gain access to control multiple parts of your Home Assistant system. This permission is indicated by this badge and will impact the security score of the addon negatively.",
},
docker_api: {
title: "Full Docker Access",
description:
"The add-on author has requested the add-on to have management access to the Docker instance running on your system. This mode gives the add-on full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on.",
},
host_pid: {
title: "Host Processes Namespace",
description:
"Usually, the processes the add-on runs, are isolated from all other system processes. The add-on author has requested the add-on to have access to the system processes running on the host system instance, and allow the add-on to spawn processes on the host system as well. This mode gives the add-on full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on.",
},
apparmor: {
title: "AppArmor",
description:
"AppArmor ('Application Armor') is a Linux kernel security module that restricts add-ons capabilities like network access, raw socket access, and permission to read, write, or execute specific files.\n\nAdd-on authors can provide their security profiles, optimized for the add-on, or request it to be disabled. If AppArmor is disabled, it will raise security risks and therefore, has a negative impact on the security score of the add-on.",
},
auth_api: {
title: "Home Assistant Authentication",
description:
"An add-on can authenticate users against Home Assistant, allowing add-ons to give users the possibility to log into applications running inside add-ons, using their Home Assistant username/password. This badge indicates if the add-on author requests this capability.",
},
ingress: {
title: "Ingress",
description:
"This add-on is using Ingress to embed its interface securely into Home Assistant.",
},
};
@customElement("hassio-addon-info")
class HassioAddonInfo extends LitElement {
@property({ type: Boolean }) public narrow!: boolean;
@ -162,11 +105,11 @@ class HassioAddonInfo extends LitElement {
: undefined;
const metrics = [
{
description: "Add-on CPU Usage",
description: this.supervisor.localize("addon.dashboard.cpu_usage"),
value: this._metrics?.cpu_percent,
},
{
description: "Add-on RAM Usage",
description: this.supervisor.localize("addon.dashboard.ram_usage"),
value: this._metrics?.memory_percent,
tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString(
this._metrics?.memory_limit
@ -176,14 +119,28 @@ class HassioAddonInfo extends LitElement {
return html`
${this.addon.update_available
? html`
<ha-card header="Update available! 🎉">
<ha-card
.header="${this.supervisor.localize(
"common.update_available",
"count",
1
)}🎉"
>
<div class="card-content">
<hassio-card-content
.hass=${this.hass}
.title="${this.addon.name} ${this.addon
.version_latest} is available"
.description="You are currently running version ${this.addon
.version}"
.title="${this.supervisor.localize(
"addon.dashboard.new_update_available",
"name",
this.addon.name,
"version",
this.addon.version_latest
)}"
.description="${this.supervisor.localize(
"common.running_version",
"version",
this.addon.version
)}"
icon=${mdiArrowUpBoldCircle}
iconClass="update"
></hassio-card-content>
@ -194,29 +151,32 @@ class HassioAddonInfo extends LitElement {
)
? html`
<p class="warning">
This add-on is not compatible with the processor of
your device or the operating system you have installed
on your device.
${this.supervisor.localize(
"addon.dashboard.not_available_arch"
)}
</p>
`
: html`
<p class="warning">
You are running Home Assistant
${this.supervisor.core.version}, to update to this
version of the add-on you need at least version
${addonStoreInfo.homeassistant} of Home Assistant
${this.supervisor.localize(
"addon.dashboard.not_available_arch",
"core_version_installed",
this.supervisor.core.version,
"core_version_needed",
addonStoreInfo.homeassistant
)}
</p>
`
: ""}
</div>
<div class="card-actions">
<mwc-button @click=${this._updateClicked}>
Update
${this.supervisor.localize("common.update")}
</mwc-button>
${this.addon.changelog
? html`
<mwc-button @click=${this._openChangelog}>
Changelog
${this.supervisor.localize("addon.dashboard.changelog")}
</mwc-button>
`
: ""}
@ -227,12 +187,19 @@ class HassioAddonInfo extends LitElement {
${!this.addon.protected
? html`
<ha-card class="warning">
<h1 class="card-header">Warning: Protection mode is disabled!</h1>
<h1 class="card-header">${this.supervisor.localize(
"addon.dashboard.protection_mode.title"
)}
</h1>
<div class="card-content">
Protection mode on this add-on is disabled! This gives the add-on full access to the entire system, which adds security risks, and could damage your system when used incorrectly. Only disable the protection mode if you know, need AND trust the source of this add-on.
${this.supervisor.localize("addon.dashboard.protection_mode.content")}
</div>
<div class="card-actions protection-enable">
<mwc-button @click=${this._protectionToggled}>Enable Protection mode</mwc-button>
<mwc-button @click=${this._protectionToggled}>
${this.supervisor.localize(
"addon.dashboard.protection_mode.enable"
)}
</mwc-button>
</div>
</div>
</ha-card>
@ -249,14 +216,18 @@ class HassioAddonInfo extends LitElement {
${this._computeIsRunning
? html`
<ha-svg-icon
title="Add-on is running"
.title=${this.supervisor.localize(
"dashboard.addon_running"
)}
class="running"
.path=${mdiCircle}
></ha-svg-icon>
`
: html`
<ha-svg-icon
title="Add-on is stopped"
.title=${this.supervisor.localize(
"dashboard.addon_stopped"
)}
class="stopped"
.path=${mdiCircle}
></ha-svg-icon>
@ -270,21 +241,29 @@ class HassioAddonInfo extends LitElement {
? html`
Current version: ${this.addon.version}
<div class="changelog" @click=${this._openChangelog}>
(<span class="changelog-link">changelog</span>)
(<span class="changelog-link">
${this.supervisor.localize("addon.dashboard.changelog")} </span
>)
</div>
`
: html`<span class="changelog-link" @click=${this._openChangelog}
>Changelog</span
>`}
: html`<span class="changelog-link" @click=${this._openChangelog}>
${this.supervisor.localize("addon.dashboard.changelog")}
</span>`}
</div>
<div class="description light-color">
${this.addon.description}.<br />
Visit
<a href="${this.addon.url!}" target="_blank" rel="noreferrer">
${this.addon.name} page</a
>
for details.
${this.supervisor.localize(
"addon.dashboard.visit_addon_page",
"name",
html`<a
href="${this.addon.url!}"
target="_blank"
rel="noreferrer"
>
${this.addon.name}
</a>`
)}
</div>
<div class="addon-container">
<div>
@ -305,7 +284,9 @@ class HassioAddonInfo extends LitElement {
})}
@click=${this._showMoreInfo}
id="stage"
label="stage"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.stage"
)}
description=""
>
<ha-svg-icon
@ -331,7 +312,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="host_network"
label="host"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.host"
)}
description=""
>
<ha-svg-icon .path=${mdiNetwork}></ha-svg-icon>
@ -343,7 +326,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="full_access"
label="hardware"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.hardware"
)}
description=""
>
<ha-svg-icon .path=${mdiChip}></ha-svg-icon>
@ -355,7 +340,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="homeassistant_api"
label="hass"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.hass"
)}
description=""
>
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
@ -367,8 +354,12 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="hassio_api"
label="hassio"
.description=${this.addon.hassio_role}
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.hassio"
)}
.description=${this.supervisor.localize(
`addon.dashboard.capability.role.${this.addon.hassio_role}`
) || this.addon.hassio_role}
>
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
</ha-label-badge>
@ -379,7 +370,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="docker_api"
label="docker"
.label=".${this.supervisor.localize(
"addon.dashboard.capability.label.docker"
)}"
description=""
>
<ha-svg-icon .path=${mdiDocker}></ha-svg-icon>
@ -391,7 +384,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="host_pid"
label="host pid"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.host_pid"
)}
description=""
>
<ha-svg-icon .path=${mdiPound}></ha-svg-icon>
@ -404,7 +399,9 @@ class HassioAddonInfo extends LitElement {
@click=${this._showMoreInfo}
class=${this._computeApparmorClassName}
id="apparmor"
label="apparmor"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.apparmor"
)}
description=""
>
<ha-svg-icon .path=${mdiShield}></ha-svg-icon>
@ -416,7 +413,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="auth_api"
label="auth"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.auth"
)}
description=""
>
<ha-svg-icon .path=${mdiKey}></ha-svg-icon>
@ -428,7 +427,9 @@ class HassioAddonInfo extends LitElement {
<ha-label-badge
@click=${this._showMoreInfo}
id="ingress"
label="ingress"
.label=${this.supervisor.localize(
"addon.dashboard.capability.label.ingress"
)}
description=""
>
<ha-svg-icon
@ -449,10 +450,14 @@ class HassioAddonInfo extends LitElement {
>
<ha-settings-row ?three-line=${this.narrow}>
<span slot="heading">
Start on boot
${this.supervisor.localize(
"addon.dashboard.option.boot.title"
)}
</span>
<span slot="description">
Make the add-on start during a system boot
${this.supervisor.localize(
"addon.dashboard.option.boot.description"
)}
</span>
<ha-switch
@change=${this._startOnBootToggled}
@ -465,10 +470,14 @@ class HassioAddonInfo extends LitElement {
? html`
<ha-settings-row ?three-line=${this.narrow}>
<span slot="heading">
Watchdog
${this.supervisor.localize(
"addon.dashboard.option.watchdog.title"
)}
</span>
<span slot="description">
This will start the add-on if it crashes
${this.supervisor.localize(
"addon.dashboard.option.boot.description"
)}
</span>
<ha-switch
@change=${this._watchdogToggled}
@ -483,11 +492,14 @@ class HassioAddonInfo extends LitElement {
? html`
<ha-settings-row ?three-line=${this.narrow}>
<span slot="heading">
Auto update
${this.supervisor.localize(
"addon.dashboard.option.auto_update.title"
)}
</span>
<span slot="description">
Auto update the add-on when there is a new
version available
${this.supervisor.localize(
"addon.dashboard.option.boot.description"
)}
</span>
<ha-switch
@change=${this._autoUpdateToggled}
@ -497,21 +509,22 @@ class HassioAddonInfo extends LitElement {
</ha-settings-row>
`
: ""}
${this.addon.ingress
${!this._computeCannotIngressSidebar && this.addon.ingress
? html`
<ha-settings-row ?three-line=${this.narrow}>
<span slot="heading">
Show in sidebar
${this.supervisor.localize(
"addon.dashboard.option.ingress_panel.title"
)}
</span>
<span slot="description">
${this._computeCannotIngressSidebar
? "This option requires Home Assistant 0.92 or later."
: "Add this add-on to your sidebar"}
${this.supervisor.localize(
"addon.dashboard.option.ingress_panel.description"
)}
</span>
<ha-switch
@change=${this._panelToggled}
.checked=${this.addon.ingress_panel}
.disabled=${this._computeCannotIngressSidebar}
haptic
></ha-switch>
</ha-settings-row>
@ -521,10 +534,14 @@ class HassioAddonInfo extends LitElement {
? html`
<ha-settings-row ?three-line=${this.narrow}>
<span slot="heading">
Protection mode
${this.supervisor.localize(
"addon.dashboard.option.protected.title"
)}
</span>
<span slot="description">
Blocks elevated system access from the add-on
${this.supervisor.localize(
"addon.dashboard.option.protected.description"
)}
</span>
<ha-switch
@change=${this._protectionToggled}
@ -542,7 +559,7 @@ class HassioAddonInfo extends LitElement {
${this.addon.state === "started"
? html`<ha-settings-row ?three-line=${this.narrow}>
<span slot="heading">
Hostname
${this.supervisor.localize("addon.dashboard.hostname")}
</span>
<code slot="description">
${this.addon.hostname}
@ -569,17 +586,20 @@ class HassioAddonInfo extends LitElement {
)
? html`
<p class="warning">
This add-on is not compatible with the processor of your
device or the operating system you have installed on your
device.
${this.supervisor.localize(
"addon.dashboard.not_available_arch"
)}
</p>
`
: html`
<p class="warning">
You are running Home Assistant
${this.supervisor.core.version}, to install this add-on you
need at least version ${addonStoreInfo!.homeassistant} of
Home Assistant
${this.supervisor.localize(
"addon.dashboard.not_available_version",
"core_version_installed",
this.supervisor.core.version,
"core_version_needed",
addonStoreInfo!.homeassistant
)}
</p>
`
: ""}
@ -593,18 +613,18 @@ class HassioAddonInfo extends LitElement {
class="warning"
@click=${this._stopClicked}
>
Stop
${this.supervisor.localize("addon.dashboard.stop")}
</ha-progress-button>
<ha-progress-button
class="warning"
@click=${this._restartClicked}
>
Restart
${this.supervisor.localize("addon.dashboard.restart")}
</ha-progress-button>
`
: html`
<ha-progress-button @click=${this._startClicked}>
Start
${this.supervisor.localize("addon.dashboard.start")}
</ha-progress-button>
`
: html`
@ -612,7 +632,7 @@ class HassioAddonInfo extends LitElement {
.disabled=${!this.addon.available}
@click=${this._installClicked}
>
Install
${this.supervisor.localize("addon.dashboard.install")}
</ha-progress-button>
`}
</div>
@ -627,7 +647,9 @@ class HassioAddonInfo extends LitElement {
rel="noopener"
>
<mwc-button>
Open web UI
${this.supervisor.localize(
"addon.dashboard.open_web_ui"
)}
</mwc-button>
</a>
`
@ -635,7 +657,9 @@ class HassioAddonInfo extends LitElement {
${this._computeShowIngressUI
? html`
<mwc-button @click=${this._openIngress}>
Open web UI
${this.supervisor.localize(
"addon.dashboard.open_web_ui"
)}
</mwc-button>
`
: ""}
@ -643,7 +667,7 @@ class HassioAddonInfo extends LitElement {
class="warning"
@click=${this._uninstallClicked}
>
Uninstall
${this.supervisor.localize("addon.dashboard.uninstall")}
</ha-progress-button>
${this.addon.build
? html`
@ -652,7 +676,7 @@ class HassioAddonInfo extends LitElement {
.hass=${this.hass}
.path="hassio/addons/${this.addon.slug}/rebuild"
>
Rebuild
${this.supervisor.localize("addon.dashboard.rebuild")}
</ha-call-api-button>
`
: ""}`
@ -712,8 +736,21 @@ class HassioAddonInfo extends LitElement {
private _showMoreInfo(ev): void {
const id = ev.currentTarget.id;
showHassioMarkdownDialog(this, {
title: PERMIS_DESC[id].title,
content: PERMIS_DESC[id].description,
title: this.supervisor.localize(`addon.dashboard.capability.${id}.title`),
content:
id === "stage"
? this.supervisor.localize(
`addon.dashboard.capability.${id}.description`,
"icon_stable",
`<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon>`,
"icon_experimental",
`<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon>`,
"icon_deprecated",
`<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon>`
)
: this.supervisor.localize(
`addon.dashboard.capability.${id}.description`
),
});
}
@ -766,9 +803,11 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
this._error = `Failed to set addon option, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
}
@ -786,9 +825,11 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
this._error = `Failed to set addon option, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
}
@ -806,9 +847,11 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
this._error = `Failed to set addon option, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
}
@ -826,9 +869,11 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
this._error = `Failed to set addon security option, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
}
@ -846,9 +891,11 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
this._error = `Failed to set addon option, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
}
}
@ -859,12 +906,14 @@ class HassioAddonInfo extends LitElement {
this.addon.slug
);
showHassioMarkdownDialog(this, {
title: "Changelog",
title: this.supervisor.localize("addon.dashboard.changelog"),
content,
});
} catch (err) {
showAlertDialog(this, {
title: "Failed to get addon changelog",
title: this.supervisor.localize(
"addon.dashboard.action_error.get_changelog"
),
text: extractApiErrorMessage(err),
});
}
@ -884,7 +933,7 @@ class HassioAddonInfo extends LitElement {
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
showAlertDialog(this, {
title: "Failed to install addon",
title: this.supervisor.localize("addon.dashboard.action_error.install"),
text: extractApiErrorMessage(err),
});
}
@ -905,7 +954,7 @@ class HassioAddonInfo extends LitElement {
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
showAlertDialog(this, {
title: "Failed to stop addon",
title: this.supervisor.localize("addon.dashboard.action_error.stop"),
text: extractApiErrorMessage(err),
});
}
@ -926,7 +975,7 @@ class HassioAddonInfo extends LitElement {
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
showAlertDialog(this, {
title: "Failed to restart addon",
title: this.supervisor.localize("addon.dashboard.action_error.restart"),
text: extractApiErrorMessage(err),
});
}
@ -947,11 +996,15 @@ class HassioAddonInfo extends LitElement {
);
if (!validate.valid) {
await showConfirmationDialog(this, {
title: "Failed to start addon - configuration validation failed!",
title: this.supervisor.localize(
"addon.dashboard.action_error.start_invalid_config"
),
text: validate.message.split(" Got ")[0],
confirm: () => this._openConfiguration(),
confirmText: "Go to configuration",
dismissText: "Cancel",
confirmText: this.supervisor.localize(
"addon.dashboard.action_error.go_to_config"
),
dismissText: this.supervisor.localize("common.cancel"),
});
button.progress = false;
return;
@ -976,7 +1029,7 @@ class HassioAddonInfo extends LitElement {
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
showAlertDialog(this, {
title: "Failed to start addon",
title: this.supervisor.localize("addon.dashboard.action_error.start"),
text: extractApiErrorMessage(err),
});
}
@ -1014,7 +1067,9 @@ class HassioAddonInfo extends LitElement {
fireEvent(this, "hass-api-called", eventdata);
} catch (err) {
showAlertDialog(this, {
title: "Failed to uninstall addon",
title: this.supervisor.localize(
"addon.dashboard.action_error.uninstall"
),
text: extractApiErrorMessage(err),
});
}

View File

@ -9,6 +9,7 @@ import {
} from "lit-element";
import "../../../../src/components/ha-circular-progress";
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { hassioStyle } from "../../resources/hassio-style";
@ -18,6 +19,8 @@ import "./hassio-addon-logs";
class HassioAddonLogDashboard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public addon?: HassioAddonDetails;
protected render(): TemplateResult {
@ -28,6 +31,7 @@ class HassioAddonLogDashboard extends LitElement {
<div class="content">
<hassio-addon-logs
.hass=${this.hass}
.supervisor=${this.supervisor}
.addon=${this.addon}
></hassio-addon-logs>
</div>

View File

@ -15,6 +15,7 @@ import {
HassioAddonDetails,
} from "../../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import "../../components/hassio-ansi-to-html";
@ -24,6 +25,8 @@ import { hassioStyle } from "../../resources/hassio-style";
class HassioAddonLogs extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public addon!: HassioAddonDetails;
@internalProperty() private _error?: string;
@ -48,7 +51,9 @@ class HassioAddonLogs extends LitElement {
: ""}
</div>
<div class="card-actions">
<mwc-button @click=${this._refresh}>Refresh</mwc-button>
<mwc-button @click=${this._refresh}>
${this.supervisor.localize("common.refresh")}
</mwc-button>
</div>
</ha-card>
`;
@ -76,7 +81,11 @@ class HassioAddonLogs extends LitElement {
try {
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
} catch (err) {
this._error = `Failed to get addon logs, ${extractApiErrorMessage(err)}`;
this._error = this.supervisor.localize(
"addon.logs.get_logs",
"error",
extractApiErrorMessage(err)
);
}
}

View File

@ -44,7 +44,7 @@ class HassioCardContent extends LitElement {
${this.iconImage
? html`
<div class="icon_image ${this.iconClass}">
<img src="${this.iconImage}" title="${this.iconTitle}" />
<img src="${this.iconImage}" .title=${this.iconTitle} />
<div></div>
</div>
`

View File

@ -26,7 +26,7 @@ class SupervisorMetric extends LitElement {
<span slot="heading">
${this.description}
</span>
<div slot="description" title="${this.tooltip ?? ""}">
<div slot="description" .title=${this.tooltip ?? ""}>
<span class="value">
${roundedValue}%
</span>

View File

@ -69,7 +69,7 @@ export class HassioUpdate extends LitElement {
<div class="content">
<h1>
${this.supervisor.localize(
"dashboard.update_available",
"common.update_available",
"count",
updatesAvailable
)}
@ -211,7 +211,7 @@ export class HassioUpdate extends LitElement {
!ignoredStatusCodes.has(err.status_code)
) {
showAlertDialog(this, {
title: this.supervisor.localize("error.update_failed"),
title: this.supervisor.localize("common.error.update_failed"),
text: extractApiErrorMessage(err),
});
}

View File

@ -35,6 +35,7 @@ import {
updateNetworkInterface,
WifiConfiguration,
} from "../../../../src/data/hassio/network";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import {
showAlertDialog,
showConfirmationDialog,
@ -51,6 +52,8 @@ export class DialogHassioNetwork extends LitElement
implements HassDialog<HassioNetworkDialogParams> {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@internalProperty() private _accessPoints?: AccessPoints;
@internalProperty() private _curTabIndex = 0;
@ -73,7 +76,8 @@ export class DialogHassioNetwork extends LitElement
this._params = params;
this._dirty = false;
this._curTabIndex = 0;
this._interfaces = params.network.interfaces.sort((a, b) => {
this.supervisor = params.supervisor;
this._interfaces = params.supervisor.network.interfaces.sort((a, b) => {
return a.primary > b.primary ? -1 : 1;
});
this._interface = { ...this._interfaces[this._curTabIndex] };
@ -104,7 +108,7 @@ export class DialogHassioNetwork extends LitElement
<div slot="heading">
<ha-header-bar>
<span slot="title">
Network settings
${this.supervisor.localize("dialog.network.title")}
</span>
<mwc-icon-button slot="actionItems" dialogAction="cancel">
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
@ -139,7 +143,13 @@ export class DialogHassioNetwork extends LitElement
? html`
<ha-expansion-panel header="Wi-Fi" outlined>
${this._interface?.wifi?.ssid
? html`<p>Connected to: ${this._interface?.wifi?.ssid}</p>`
? html`<p>
${this.supervisor.localize(
"dialog.network.connected_to",
"ssid",
this._interface?.wifi?.ssid
)}
</p>`
: ""}
<mwc-button
class="scan"
@ -149,7 +159,7 @@ export class DialogHassioNetwork extends LitElement
${this._scanning
? html`<ha-circular-progress active size="small">
</ha-circular-progress>`
: "Scan for accesspoints"}
: this.supervisor.localize("dialog.network.scan_ap")}
</mwc-button>
${this._accessPoints &&
this._accessPoints.accesspoints &&
@ -181,7 +191,11 @@ export class DialogHassioNetwork extends LitElement
${this._wifiConfiguration
? html`
<div class="radio-row">
<ha-formfield label="open">
<ha-formfield
.label=${this.supervisor.localize(
"dialog.network.open"
)}
>
<ha-radio
@change=${this._handleRadioValueChangedAp}
.ap=${this._wifiConfiguration}
@ -193,7 +207,11 @@ export class DialogHassioNetwork extends LitElement
>
</ha-radio>
</ha-formfield>
<ha-formfield label="wep">
<ha-formfield
.label=${this.supervisor.localize(
"dialog.network.wep"
)}
>
<ha-radio
@change=${this._handleRadioValueChangedAp}
.ap=${this._wifiConfiguration}
@ -203,7 +221,11 @@ export class DialogHassioNetwork extends LitElement
>
</ha-radio>
</ha-formfield>
<ha-formfield label="wpa-psk">
<ha-formfield
.label=${this.supervisor.localize(
"dialog.network.wpa"
)}
>
<ha-radio
@change=${this._handleRadioValueChangedAp}
.ap=${this._wifiConfiguration}
@ -237,18 +259,21 @@ export class DialogHassioNetwork extends LitElement
: ""}
${this._dirty
? html`<div class="warning">
If you are changing the Wi-Fi, IP or gateway addresses, you might
lose the connection!
${this.supervisor.localize("dialog.network.warning")}
</div>`
: ""}
</div>
<div class="buttons">
<mwc-button label="close" @click=${this.closeDialog}> </mwc-button>
<mwc-button
.label=${this.supervisor.localize("common.cancel")}
@click=${this.closeDialog}
>
</mwc-button>
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
${this._processing
? html`<ha-circular-progress active size="small">
</ha-circular-progress>`
: "Save"}
: this.supervisor.localize("common.save")}
</mwc-button>
</div>`;
}
@ -285,7 +310,9 @@ export class DialogHassioNetwork extends LitElement
outlined
>
<div class="radio-row">
<ha-formfield label="DHCP">
<ha-formfield
.label=${this.supervisor.localize("dialog.network.dhcp")}
>
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
@ -295,7 +322,9 @@ export class DialogHassioNetwork extends LitElement
>
</ha-radio>
</ha-formfield>
<ha-formfield label="Static">
<ha-formfield
.label=${this.supervisor.localize("dialog.network.static")}
>
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
@ -305,7 +334,10 @@ export class DialogHassioNetwork extends LitElement
>
</ha-radio>
</ha-formfield>
<ha-formfield label="Disabled" class="warning">
<ha-formfield
.label=${this.supervisor.localize("dialog.network.disabled")}
class="warning"
>
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
@ -321,7 +353,7 @@ export class DialogHassioNetwork extends LitElement
<paper-input
class="flex-auto"
id="address"
label="IP address/Netmask"
.label=${this.supervisor.localize("dialog.network.ip_netmask")}
.version=${version}
.value=${this._toString(this._interface![version].address)}
@value-changed=${this._handleInputValueChanged}
@ -330,7 +362,7 @@ export class DialogHassioNetwork extends LitElement
<paper-input
class="flex-auto"
id="gateway"
label="Gateway address"
.label=${this.supervisor.localize("dialog.network.gateway")}
.version=${version}
.value=${this._interface![version].gateway}
@value-changed=${this._handleInputValueChanged}
@ -339,7 +371,7 @@ export class DialogHassioNetwork extends LitElement
<paper-input
class="flex-auto"
id="nameservers"
label="DNS servers"
.label=${this.supervisor.localize("dialog.network.dns_servers")}
.version=${version}
.value=${this._toString(this._interface![version].nameservers)}
@value-changed=${this._handleInputValueChanged}
@ -424,7 +456,7 @@ export class DialogHassioNetwork extends LitElement
);
} catch (err) {
showAlertDialog(this, {
title: "Failed to change network settings",
title: this.supervisor.localize("dialog.network.failed_to_change"),
text: extractApiErrorMessage(err),
});
this._processing = false;
@ -437,10 +469,9 @@ export class DialogHassioNetwork extends LitElement
private async _handleTabActivated(ev: CustomEvent): Promise<void> {
if (this._dirty) {
const confirm = await showConfirmationDialog(this, {
text:
"You have unsaved changes, these will get lost if you change tabs, do you want to continue?",
confirmText: "yes",
dismissText: "no",
text: this.supervisor.localize("dialog.network.unsaved"),
confirmText: this.supervisor.localize("common.yes"),
dismissText: this.supervisor.localize("common.no"),
});
if (!confirm) {
this.requestUpdate("_interface");

View File

@ -1,9 +1,9 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { NetworkInfo } from "../../../../src/data/hassio/network";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import "./dialog-hassio-network";
export interface HassioNetworkDialogParams {
network: NetworkInfo;
supervisor: Supervisor;
loadData: () => Promise<void>;
}

View File

@ -22,14 +22,18 @@ import {
fetchHassioDockerRegistries,
removeHassioDockerRegistry,
} from "../../../../src/data/hassio/docker";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { RegistriesDialogParams } from "./show-dialog-registries";
@customElement("dialog-hassio-registries")
class HassioRegistriesDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) private _registries?: {
registry: string;
username: string;
@ -55,8 +59,8 @@ class HassioRegistriesDialog extends LitElement {
.heading=${createCloseHeading(
this.hass,
this._addingRegistry
? "Add New Docker Registry"
: "Manage Docker Registries"
? this.supervisor.localize("dialog.registries.title_add")
: this.supervisor.localize("dialog.registries.title_manage")
)}
>
<div class="form">
@ -66,7 +70,9 @@ class HassioRegistriesDialog extends LitElement {
@value-changed=${this._inputChanged}
class="flex-auto"
name="registry"
label="Registry"
.label=${this.supervisor.localize(
"dialog.registries.registry"
)}
required
auto-validate
></paper-input>
@ -74,7 +80,9 @@ class HassioRegistriesDialog extends LitElement {
@value-changed=${this._inputChanged}
class="flex-auto"
name="username"
label="Username"
.label=${this.supervisor.localize(
"dialog.registries.username"
)}
required
auto-validate
></paper-input>
@ -82,7 +90,9 @@ class HassioRegistriesDialog extends LitElement {
@value-changed=${this._inputChanged}
class="flex-auto"
name="password"
label="Password"
.label=${this.supervisor.localize(
"dialog.registries.password"
)}
type="password"
required
auto-validate
@ -94,7 +104,7 @@ class HassioRegistriesDialog extends LitElement {
)}
@click=${this._addNewRegistry}
>
Add registry
${this.supervisor.localize("dialog.registries.add_registry")}
</mwc-button>
`
: html`${this._registries?.length
@ -103,11 +113,16 @@ class HassioRegistriesDialog extends LitElement {
<mwc-list-item class="option" hasMeta twoline>
<span>${entry.registry}</span>
<span slot="secondary"
>Username: ${entry.username}</span
>${this.supervisor.localize(
"dialog.registries.username"
)}:
${entry.username}</span
>
<mwc-icon-button
.entry=${entry}
title="Remove"
.title=${this.supervisor.localize(
"dialog.registries.remove"
)}
slot="meta"
@click=${this._removeRegistry}
>
@ -118,11 +133,17 @@ class HassioRegistriesDialog extends LitElement {
})
: html`
<mwc-list-item>
<span>No registries configured</span>
<span
>${this.supervisor.localize(
"dialog.registries.no_registries"
)}</span
>
</mwc-list-item>
`}
<mwc-button @click=${this._addRegistry}>
Add new registry
${this.supervisor.localize(
"dialog.registries.add_new_registry"
)}
</mwc-button> `}
</div>
</ha-dialog>
@ -134,8 +155,9 @@ class HassioRegistriesDialog extends LitElement {
this[`_${target.name}`] = target.value;
}
public async showDialog(_dialogParams: any): Promise<void> {
public async showDialog(dialogParams: RegistriesDialogParams): Promise<void> {
this._opened = true;
this.supervisor = dialogParams.supervisor;
await this._loadRegistries();
await this.updateComplete;
}
@ -178,7 +200,7 @@ class HassioRegistriesDialog extends LitElement {
this._addingRegistry = false;
} catch (err) {
showAlertDialog(this, {
title: "Failed to add registry",
title: this.supervisor.localize("dialog.registries.failed_to_add"),
text: extractApiErrorMessage(err),
});
}
@ -192,7 +214,7 @@ class HassioRegistriesDialog extends LitElement {
await this._loadRegistries();
} catch (err) {
showAlertDialog(this, {
title: "Failed to remove registry",
title: this.supervisor.localize("dialog.registries.failed_to_remove"),
text: extractApiErrorMessage(err),
});
}

View File

@ -1,10 +1,18 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import "./dialog-hassio-registries";
export const showRegistriesDialog = (element: HTMLElement): void => {
export interface RegistriesDialogParams {
supervisor: Supervisor;
}
export const showRegistriesDialog = (
element: HTMLElement,
dialogParams: RegistriesDialogParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-registries",
dialogImport: () => import("./dialog-hassio-registries"),
dialogParams: {},
dialogParams,
});
};

View File

@ -18,7 +18,7 @@ import {
} from "lit-element";
import memoizeOne from "memoize-one";
import "../../../../src/components/ha-circular-progress";
import "../../../../src/components/ha-dialog";
import { createCloseHeading } from "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-svg-icon";
import {
fetchHassioAddonsInfo,
@ -26,6 +26,7 @@ import {
} from "../../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { setSupervisorOption } from "../../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
@ -34,6 +35,8 @@ import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
class HassioRepositoriesDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) private _repos: HassioAddonRepository[] = [];
@property({ attribute: false })
@ -47,9 +50,11 @@ class HassioRepositoriesDialog extends LitElement {
@internalProperty() private _error?: string;
public async showDialog(_dialogParams: any): Promise<void> {
this._dialogParams = _dialogParams;
this._repos = _dialogParams.repos;
public async showDialog(
dialogParams: HassioRepositoryDialogParams
): Promise<void> {
this._dialogParams = dialogParams;
this.supervisor = dialogParams.supervisor;
this._opened = true;
await this.updateComplete;
}
@ -66,14 +71,19 @@ class HassioRepositoriesDialog extends LitElement {
);
protected render(): TemplateResult {
const repositories = this._filteredRepositories(this._repos);
const repositories = this._filteredRepositories(
this.supervisor.addon.repositories
);
return html`
<ha-dialog
.open=${this._opened}
@closing=${this.closeDialog}
scrimClickAction
escapeKeyAction
heading="Manage add-on repositories"
.heading=${createCloseHeading(
this.hass,
this.supervisor.localize("dialog.repositories.title")
)}
>
${this._error ? html`<div class="error">${this._error}</div>` : ""}
<div class="form">
@ -88,7 +98,9 @@ class HassioRepositoriesDialog extends LitElement {
</paper-item-body>
<mwc-icon-button
.slug=${repo.slug}
title="Remove"
.title=${this.supervisor.localize(
"dialog.repositories.remove"
)}
@click=${this._removeRepository}
>
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
@ -105,13 +117,13 @@ class HassioRepositoriesDialog extends LitElement {
<paper-input
class="flex-auto"
id="repository_input"
label="Add repository"
.label=${this.supervisor.localize("dialog.repositories.add")}
@keydown=${this._handleKeyAdd}
></paper-input>
<mwc-button @click=${this._addRepository}>
${this._prosessing
? html`<ha-circular-progress active></ha-circular-progress>`
: "Add"}
: this.supervisor.localize("dialog.repositories.add")}
</mwc-button>
</div>
</div>

View File

@ -1,9 +1,9 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { HassioAddonRepository } from "../../../../src/data/hassio/addon";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import "./dialog-hassio-repositories";
export interface HassioRepositoryDialogParams {
repos: HassioAddonRepository[];
supervisor: Supervisor;
loadData: () => Promise<void>;
}

View File

@ -4,6 +4,7 @@ import {
restartHassioAddon,
} from "../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import {
showAlertDialog,
showConfirmationDialog,
@ -13,20 +14,25 @@ import { HomeAssistant } from "../../../src/types";
export const suggestAddonRestart = async (
element: LitElement,
hass: HomeAssistant,
supervisor: Supervisor,
addon: HassioAddonDetails
): Promise<void> => {
const confirmed = await showConfirmationDialog(element, {
title: addon.name,
text: "Do you want to restart the add-on with your changes?",
confirmText: "restart add-on",
dismissText: "no",
title: supervisor.localize("common.restart_name", "name", addon.name),
text: supervisor.localize("dialog.restart_addon.text"),
confirmText: supervisor.localize("dialog.restart_addon.confirm_text"),
dismissText: supervisor.localize("common.cancel"),
});
if (confirmed) {
try {
await restartHassioAddon(hass, addon.slug);
} catch (err) {
showAlertDialog(element, {
title: "Failed to restart",
title: supervisor.localize(
"common.failed_to_restart_name",
"name",
addon.name
),
text: extractApiErrorMessage(err),
});
}

View File

@ -19,6 +19,7 @@ import {
} from "../../src/panels/my/ha-panel-my";
import { navigate } from "../../src/common/navigate";
import { HomeAssistant, Route } from "../../src/types";
import { Supervisor } from "../../src/data/supervisor/supervisor";
const REDIRECTS: Redirects = {
supervisor_logs: {
@ -48,7 +49,9 @@ const REDIRECTS: Redirects = {
class HassioMyRedirect extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public route!: Route;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public route!: Route;
@internalProperty() public _error?: TemplateResult | string;
@ -58,15 +61,17 @@ class HassioMyRedirect extends LitElement {
const redirect = REDIRECTS[path];
if (!redirect) {
this._error = html`This redirect is not supported by your Home Assistant
instance. Check the
<a
this._error = this.supervisor.localize(
"my.not_supported",
"link",
html`<a
target="_blank"
rel="noreferrer noopener"
href="https://my.home-assistant.io/faq.html#supported-pages"
>My Home Assistant FAQ</a
>
for the supported redirects and the version they where introduced.`;
${this.supervisor.localize("my.faq_link")}
</a>`
);
return;
}
@ -74,7 +79,7 @@ class HassioMyRedirect extends LitElement {
try {
url = this._createRedirectUrl(redirect);
} catch (err) {
this._error = "An unknown error occured";
this._error = this.supervisor.localize("my.error");
return;
}

View File

@ -55,8 +55,8 @@ import { hassioStyle } from "../resources/hassio-style";
interface CheckboxItem {
slug: string;
name: string;
checked: boolean;
name?: string;
}
@customElement("hassio-snapshots")
@ -84,13 +84,12 @@ class HassioSnapshots extends LitElement {
@internalProperty() private _folderList: CheckboxItem[] = [
{
slug: "homeassistant",
name: "Home Assistant configuration",
checked: true,
},
{ slug: "ssl", name: "SSL", checked: true },
{ slug: "share", name: "Share", checked: true },
{ slug: "media", name: "Media", checked: true },
{ slug: "addons/local", name: "Local add-ons", checked: true },
{ slug: "ssl", checked: true },
{ slug: "share", checked: true },
{ slug: "media", checked: true },
{ slug: "addons/local", checked: true },
];
@internalProperty() private _error = "";
@ -123,50 +122,50 @@ class HassioSnapshots extends LitElement {
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item>
Reload
${this.supervisor.localize("common.reload")}
</mwc-list-item>
${atLeastVersion(this.hass.config.version, 0, 116)
? html`<mwc-list-item>
Upload snapshot
${this.supervisor.localize("snapshot.upload_snapshot")}
</mwc-list-item>`
: ""}
</ha-button-menu>
<div class="content">
<h1>
Create Snapshot
${this.supervisor.localize("snapshot.create_snapshot")}
</h1>
<p class="description">
Snapshots allow you to easily backup and restore all data of your
Home Assistant instance.
${this.supervisor.localize("snapshot.description")}
</p>
<div class="card-group">
<ha-card>
<div class="card-content">
<paper-input
autofocus
label="Name"
.label=${this.supervisor.localize("snapshot.name")}
name="snapshotName"
.value=${this._snapshotName}
@value-changed=${this._handleTextValueChanged}
></paper-input>
Type:
${this.supervisor.localize("snapshot.type")}:
<paper-radio-group
name="snapshotType"
type="${this.supervisor.localize("snapshot.type")}"
.selected=${this._snapshotType}
@selected-changed=${this._handleRadioValueChanged}
>
<paper-radio-button name="full">
Full snapshot
${this.supervisor.localize("snapshot.full_snapshot")}
</paper-radio-button>
<paper-radio-button name="partial">
Partial snapshot
${this.supervisor.localize("snapshot.partial_snapshot")}
</paper-radio-button>
</paper-radio-group>
${this._snapshotType === "full"
? undefined
: html`
Folders:
${this.supervisor.localize("snapshot.folders")}:
${this._folderList.map(
(folder, idx) => html`
<paper-checkbox
@ -174,11 +173,13 @@ class HassioSnapshots extends LitElement {
.checked=${folder.checked}
@checked-changed=${this._folderChecked}
>
${folder.name}
${this.supervisor.localize(
`snapshot.folder.${folder.slug}`
)}
</paper-checkbox>
`
)}
Add-ons:
${this.supervisor.localize("snapshot.addons")}:
${this._addonList.map(
(addon, idx) => html`
<paper-checkbox
@ -191,18 +192,18 @@ class HassioSnapshots extends LitElement {
`
)}
`}
Security:
${this.supervisor.localize("snapshot.security")}:
<paper-checkbox
name="snapshotHasPassword"
.checked=${this._snapshotHasPassword}
@checked-changed=${this._handleCheckboxValueChanged}
>
Password protection
${this.supervisor.localize("snapshot.password_protection")}
</paper-checkbox>
${this._snapshotHasPassword
? html`
<paper-input
label="Password"
.label=${this.supervisor.localize("snapshot.password")}
type="password"
name="snapshotPassword"
.value=${this._snapshotPassword}
@ -217,18 +218,22 @@ class HassioSnapshots extends LitElement {
<div class="card-actions">
<ha-progress-button
@click=${this._createSnapshot}
title="${this.supervisor.info.state !== "running"
? `Creating a snapshot is not possible right now because the system is in ${this.supervisor.info.state} state.`
: ""}"
.title=${this.supervisor.info.state !== "running"
? this.supervisor.localize(
"snapshot.create_blocked_not_running",
"state",
this.supervisor.info.state
)
: ""}
.disabled=${this.supervisor.info.state !== "running"}
>
Create
${this.supervisor.localize("snapshot.create")}
</ha-progress-button>
</div>
</ha-card>
</div>
<h1>Available Snapshots</h1>
<h1>${this.supervisor.localize("snapshot.available_snapshots")}</h1>
<div class="card-group">
${this._snapshots === undefined
? undefined
@ -236,7 +241,7 @@ class HassioSnapshots extends LitElement {
? html`
<ha-card>
<div class="card-content">
You don't have any snapshots yet.
${this.supervisor.localize("snapshot.no_snapshots")}
</div>
</ha-card>
`
@ -337,8 +342,12 @@ class HassioSnapshots extends LitElement {
private async _createSnapshot(ev: CustomEvent): Promise<void> {
if (this.supervisor.info.state !== "running") {
await showAlertDialog(this, {
title: "Could not create snapshot",
text: `Creating a snapshot is not possible right now because the system is in ${this.supervisor.info.state} state.`,
title: this.supervisor.localize("snapshot.could_not_create"),
text: this.supervisor.localize(
"snapshot.create_blocked_not_running",
"state",
this.supervisor.info.state
),
});
}
const button = ev.currentTarget as any;
@ -346,7 +355,7 @@ class HassioSnapshots extends LitElement {
this._error = "";
if (this._snapshotHasPassword && !this._snapshotPassword.length) {
this._error = "Please enter a password.";
this._error = this.supervisor.localize("snapshot.enter_password");
button.progress = false;
return;
}
@ -395,7 +404,9 @@ class HassioSnapshots extends LitElement {
private _computeDetails(snapshot: HassioSnapshot) {
const type =
snapshot.type === "full" ? "Full snapshot" : "Partial snapshot";
snapshot.type === "full"
? this.supervisor.localize("snapshot.full_snapshot")
: this.supervisor.localize("snapshot.partial_snapshot");
return snapshot.protected ? `${type}, password protected` : type;
}

View File

@ -43,11 +43,11 @@ class HassioCoreInfo extends LitElement {
protected render(): TemplateResult | void {
const metrics = [
{
description: "Core CPU Usage",
description: this.supervisor.localize("system.core.cpu_usage"),
value: this._metrics?.cpu_percent,
},
{
description: "Core RAM Usage",
description: this.supervisor.localize("system.core.ram_usage"),
value: this._metrics?.memory_percent,
tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString(
this._metrics?.memory_limit
@ -61,7 +61,7 @@ class HassioCoreInfo extends LitElement {
<div>
<ha-settings-row>
<span slot="heading">
Version
${this.supervisor.localize("common.version")}
</span>
<span slot="description">
core-${this.supervisor.core.version}
@ -69,7 +69,7 @@ class HassioCoreInfo extends LitElement {
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
Newest Version
${this.supervisor.localize("common.newest_version")}
</span>
<span slot="description">
core-${this.supervisor.core.version_latest}
@ -77,10 +77,10 @@ class HassioCoreInfo extends LitElement {
${this.supervisor.core.update_available
? html`
<ha-progress-button
title="Update the core"
.title=${this.supervisor.localize("common.update")}
@click=${this._coreUpdate}
>
Update
${this.supervisor.localize("common.update")}
</ha-progress-button>
`
: ""}
@ -104,9 +104,13 @@ class HassioCoreInfo extends LitElement {
slot="primaryAction"
class="warning"
@click=${this._coreRestart}
title="Restart Home Assistant Core"
.title=${this.supervisor.localize(
"common.restart_name",
"name",
"Core"
)}
>
Restart Core
${this.supervisor.localize("common.restart_name", "name", "Core")}
</ha-progress-button>
</div>
</ha-card>
@ -126,10 +130,18 @@ class HassioCoreInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Restart Home Assistant Core",
text: "Are you sure you want to restart Home Assistant Core",
confirmText: "restart",
dismissText: "cancel",
title: this.supervisor.localize(
"confirm.restart.title",
"name",
"Home Assistant Core"
),
text: this.supervisor.localize(
"confirm.restart.text",
"name",
"Home Assistant Core"
),
confirmText: this.supervisor.localize("common.restart"),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -142,7 +154,11 @@ class HassioCoreInfo extends LitElement {
} catch (err) {
if (this.hass.connection.connected) {
showAlertDialog(this, {
title: "Failed to restart Home Assistant Core",
title: this.supervisor.localize(
"common.failed_to_restart_name",
"name",
"Home AssistantCore"
),
text: extractApiErrorMessage(err),
});
}

View File

@ -65,7 +65,7 @@ class HassioHostInfo extends LitElement {
const metrics = [
{
description: "Used Space",
description: this.supervisor.localize("system.host.used_space"),
value: this._getUsedSpace(
this.supervisor.host.disk_used,
this.supervisor.host.disk_total
@ -80,14 +80,13 @@ class HassioHostInfo extends LitElement {
${this.supervisor.host.features.includes("hostname")
? html`<ha-settings-row>
<span slot="heading">
Hostname
${this.supervisor.localize("system.host.hostname")}
</span>
<span slot="description">
${this.supervisor.host.hostname}
</span>
<mwc-button
title="Change the hostname"
label="Change"
.label=${this.supervisor.localize("system.host.change")}
@click=${this._changeHostnameClicked}
>
</mwc-button>
@ -96,14 +95,13 @@ class HassioHostInfo extends LitElement {
${this.supervisor.host.features.includes("network")
? html` <ha-settings-row>
<span slot="heading">
IP Address
${this.supervisor.localize("system.host.ip_address")}
</span>
<span slot="description">
${primaryIpAddress}
</span>
<mwc-button
title="Change the network"
label="Change"
.label=${this.supervisor.localize("system.host.change")}
@click=${this._changeNetworkClicked}
>
</mwc-button>
@ -112,18 +110,15 @@ class HassioHostInfo extends LitElement {
<ha-settings-row>
<span slot="heading">
Operating System
${this.supervisor.localize("system.host.operating_system")}
</span>
<span slot="description">
${this.supervisor.host.operating_system}
</span>
${this.supervisor.os.update_available
? html`
<ha-progress-button
title="Update the host OS"
@click=${this._osUpdate}
>
Update
<ha-progress-button @click=${this._osUpdate}>
${this.supervisor.localize("commmon.update")}
</ha-progress-button>
`
: ""}
@ -131,7 +126,7 @@ class HassioHostInfo extends LitElement {
${!this.supervisor.host.features.includes("hassos")
? html`<ha-settings-row>
<span slot="heading">
Docker version
${this.supervisor.localize("system.host.docker_version")}
</span>
<span slot="description">
${this.supervisor.info.docker}
@ -141,7 +136,7 @@ class HassioHostInfo extends LitElement {
${this.supervisor.host.deployment
? html`<ha-settings-row>
<span slot="heading">
Deployment
${this.supervisor.localize("system.host.deployment")}
</span>
<span slot="description">
${this.supervisor.host.deployment}
@ -154,7 +149,9 @@ class HassioHostInfo extends LitElement {
this.supervisor.host.disk_life_time >= 10
? html` <ha-settings-row>
<span slot="heading">
eMMC Lifetime Used
${this.supervisor.localize(
"system.host.emmc_lifetime_used"
)}
</span>
<span slot="description">
${this.supervisor.host.disk_life_time - 10}% -
@ -177,23 +174,18 @@ class HassioHostInfo extends LitElement {
<div class="card-actions">
${this.supervisor.host.features.includes("reboot")
? html`
<ha-progress-button
title="Reboot the host OS"
class="warning"
@click=${this._hostReboot}
>
Reboot Host
<ha-progress-button class="warning" @click=${this._hostReboot}>
${this.supervisor.localize("system.host.reboot_host")}
</ha-progress-button>
`
: ""}
${this.supervisor.host.features.includes("shutdown")
? html`
<ha-progress-button
title="Shutdown the host OS"
class="warning"
@click=${this._hostShutdown}
>
Shutdown Host
${this.supervisor.localize("system.host.shutdown_host")}
</ha-progress-button>
`
: ""}
@ -205,14 +197,12 @@ class HassioHostInfo extends LitElement {
<mwc-icon-button slot="trigger">
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item title="Show a list of hardware">
Hardware
<mwc-list-item>
${this.supervisor.localize("system.host.hardware")}
</mwc-list-item>
${this.supervisor.host.features.includes("hassos")
? html`<mwc-list-item
title="Load HassOS configs or updates from USB"
>
Import from USB
? html`<mwc-list-item>
${this.supervisor.localize("system.host.import_from_usb")}
</mwc-list-item>`
: ""}
</ha-button-menu>
@ -251,12 +241,14 @@ class HassioHostInfo extends LitElement {
try {
const content = await fetchHassioHardwareInfo(this.hass);
showHassioMarkdownDialog(this, {
title: "Hardware",
title: this.supervisor.localize("system.host.hardware"),
content: `<pre>${safeDump(content, { indent: 2 })}</pre>`,
});
} catch (err) {
showAlertDialog(this, {
title: "Failed to get hardware list",
title: this.supervisor.localize(
"system.host.failed_to_get_hardware_list"
),
text: extractApiErrorMessage(err),
});
}
@ -267,10 +259,10 @@ class HassioHostInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Reboot",
text: "Are you sure you want to reboot the host?",
confirmText: "reboot host",
dismissText: "no",
title: this.supervisor.localize("system.host.reboot_host"),
text: this.supervisor.localize("system.host.confirm_reboot"),
confirmText: this.supervisor.localize("system.host.reboot_host"),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -284,7 +276,7 @@ class HassioHostInfo extends LitElement {
// Ignore connection errors, these are all expected
if (err.status_code && !ignoredStatusCodes.has(err.status_code)) {
showAlertDialog(this, {
title: "Failed to reboot",
title: this.supervisor.localize("system.host.failed_to_reboot"),
text: extractApiErrorMessage(err),
});
}
@ -297,10 +289,10 @@ class HassioHostInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Shutdown",
text: "Are you sure you want to shutdown the host?",
confirmText: "shutdown host",
dismissText: "no",
title: this.supervisor.localize("system.host.shutdown_host"),
text: this.supervisor.localize("system.host.confirm_shutdown"),
confirmText: this.supervisor.localize("system.host.shutdown_host"),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -314,7 +306,7 @@ class HassioHostInfo extends LitElement {
// Ignore connection errors, these are all expected
if (err.status_code && !ignoredStatusCodes.has(err.status_code)) {
showAlertDialog(this, {
title: "Failed to shutdown",
title: this.supervisor.localize("system.host.failed_to_shutdown"),
text: extractApiErrorMessage(err),
});
}
@ -327,9 +319,19 @@ class HassioHostInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Update",
text: "Are you sure you want to update the OS?",
confirmText: "update os",
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",
});
@ -344,7 +346,11 @@ class HassioHostInfo extends LitElement {
} catch (err) {
if (this.hass.connection.connected) {
showAlertDialog(this, {
title: "Failed to update",
title: this.supervisor.localize(
"common.failed_to_update_name",
"name",
"Home Assistant Operating System"
),
text: extractApiErrorMessage(err),
});
}
@ -354,7 +360,7 @@ class HassioHostInfo extends LitElement {
private async _changeNetworkClicked(): Promise<void> {
showNetworkDialog(this, {
network: this.supervisor.network!,
supervisor: this.supervisor,
loadData: () => this._loadData(),
});
}
@ -362,10 +368,11 @@ class HassioHostInfo extends LitElement {
private async _changeHostnameClicked(): Promise<void> {
const curHostname: string = this.supervisor.host.hostname;
const hostname = await showPromptDialog(this, {
title: "Change Hostname",
inputLabel: "Please enter a new hostname:",
title: this.supervisor.localize("system.host.change_hostname"),
inputLabel: this.supervisor.localize("system.host.new_hostname"),
inputType: "string",
defaultValue: curHostname,
confirmText: this.supervisor.localize("common.update"),
});
if (hostname && hostname !== curHostname) {
@ -376,7 +383,7 @@ class HassioHostInfo extends LitElement {
});
} catch (err) {
showAlertDialog(this, {
title: "Setting hostname failed",
title: this.supervisor.localize("system.host.failed_to_set_hostname"),
text: extractApiErrorMessage(err),
});
}
@ -391,7 +398,9 @@ class HassioHostInfo extends LitElement {
});
} catch (err) {
showAlertDialog(this, {
title: "Failed to import from USB",
title: this.supervisor.localize(
"system.host.failed_to_import_from_usb"
),
text: extractApiErrorMessage(err),
});
}

View File

@ -37,54 +37,24 @@ import { documentationUrl } from "../../../src/util/documentation-url";
import "../components/supervisor-metric";
import { hassioStyle } from "../resources/hassio-style";
const UNSUPPORTED_REASON = {
container: {
title: "Containers known to cause issues",
url: "/more-info/unsupported/container",
},
dbus: { title: "DBUS", url: "/more-info/unsupported/dbus" },
docker_configuration: {
title: "Docker Configuration",
url: "/more-info/unsupported/docker_configuration",
},
docker_version: {
title: "Docker Version",
url: "/more-info/unsupported/docker_version",
},
job_conditions: {
title: "Ignored job conditions",
url: "/more-info/unsupported/job_conditions",
},
lxc: { title: "LXC", url: "/more-info/unsupported/lxc" },
network_manager: {
title: "Network Manager",
url: "/more-info/unsupported/network_manager",
},
os: { title: "Operating System", url: "/more-info/unsupported/os" },
privileged: {
title: "Supervisor is not privileged",
url: "/more-info/unsupported/privileged",
},
systemd: { title: "Systemd", url: "/more-info/unsupported/systemd" },
const UNSUPPORTED_REASON_URL = {
container: "/more-info/unsupported/container",
dbus: "/more-info/unsupported/dbus",
docker_configuration: "/more-info/unsupported/docker_configuration",
docker_version: "/more-info/unsupported/docker_version",
job_conditions: "/more-info/unsupported/job_conditions",
lxc: "/more-info/unsupported/lxc",
network_manager: "/more-info/unsupported/network_manager",
os: "/more-info/unsupported/os",
privileged: "/more-info/unsupported/privileged",
systemd: "/more-info/unsupported/systemd",
};
const UNHEALTHY_REASON = {
privileged: {
title: "Supervisor is not privileged",
url: "/more-info/unsupported/privileged",
},
supervisor: {
title: "Supervisor was not able to update",
url: "/more-info/unhealthy/supervisor",
},
setup: {
title: "Setup of the Supervisor failed",
url: "/more-info/unhealthy/setup",
},
docker: {
title: "The Docker environment is not working properly",
url: "/more-info/unhealthy/docker",
},
const UNHEALTHY_REASON_URL = {
privileged: "/more-info/unsupported/privileged",
supervisor: "/more-info/unhealthy/supervisor",
setup: "/more-info/unhealthy/setup",
docker: "/more-info/unhealthy/docker",
};
@customElement("hassio-supervisor-info")
@ -98,11 +68,11 @@ class HassioSupervisorInfo extends LitElement {
protected render(): TemplateResult | void {
const metrics = [
{
description: "Supervisor CPU Usage",
description: this.supervisor.localize("system.supervisor.cpu_usage"),
value: this._metrics?.cpu_percent,
},
{
description: "Supervisor RAM Usage",
description: this.supervisor.localize("system.supervisor.ram_usage"),
value: this._metrics?.memory_percent,
tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString(
this._metrics?.memory_limit
@ -115,7 +85,7 @@ class HassioSupervisorInfo extends LitElement {
<div>
<ha-settings-row>
<span slot="heading">
Version
${this.supervisor.localize("common.version")}
</span>
<span slot="description">
supervisor-${this.supervisor.supervisor.version}
@ -123,7 +93,7 @@ class HassioSupervisorInfo extends LitElement {
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
Newest Version
${this.supervisor.localize("common.newest_version")}
</span>
<span slot="description">
supervisor-${this.supervisor.supervisor.version_latest}
@ -131,17 +101,19 @@ class HassioSupervisorInfo extends LitElement {
${this.supervisor.supervisor.update_available
? html`
<ha-progress-button
title="Update the supervisor"
.title=${this.supervisor.localize(
"system.supervisor.update_supervisor"
)}
@click=${this._supervisorUpdate}
>
Update
${this.supervisor.localize("common.update")}
</ha-progress-button>
`
: ""}
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
Channel
${this.supervisor.localize("system.supervisor.channel")}
</span>
<span slot="description">
${this.supervisor.supervisor.channel}
@ -150,18 +122,26 @@ class HassioSupervisorInfo extends LitElement {
? html`
<ha-progress-button
@click=${this._toggleBeta}
title="Get stable updates for Home Assistant, supervisor and host"
.title=${this.supervisor.localize(
"system.supervisor.leave_beta_description"
)}
>
Leave beta channel
${this.supervisor.localize(
"system.supervisor.leave_beta_action"
)}
</ha-progress-button>
`
: this.supervisor.supervisor.channel === "stable"
? html`
<ha-progress-button
@click=${this._toggleBeta}
title="Get beta updates for Home Assistant (RCs), supervisor and host"
.title=${this.supervisor.localize(
"system.supervisor.join_beta_description"
)}
>
Join beta channel
${this.supervisor.localize(
"system.supervisor.join_beta_action"
)}
</ha-progress-button>
`
: ""}
@ -170,16 +150,20 @@ class HassioSupervisorInfo extends LitElement {
${this.supervisor.supervisor.supported
? html` <ha-settings-row three-line>
<span slot="heading">
Share Diagnostics
${this.supervisor.localize(
"system.supervisor.share_diagnostics"
)}
</span>
<div slot="description" class="diagnostics-description">
Share crash reports and diagnostic information.
${this.supervisor.localize(
"system.supervisor.share_diagnostics_description"
)}
<button
class="link"
title="Show more information about this"
.title=${this.supervisor.localize("common.show_more")}
@click=${this._diagnosticsInformationDialog}
>
Learn more
${this.supervisor.localize("common.learn_more")}
</button>
</div>
<ha-switch
@ -189,10 +173,12 @@ class HassioSupervisorInfo extends LitElement {
></ha-switch>
</ha-settings-row>`
: html`<div class="error">
You are running an unsupported installation.
${this.supervisor.localize(
"system.supervisor.unsupported_title"
)}
<button
class="link"
title="Learn more about how you can make your system compliant"
.title=${this.supervisor.localize("common.learn_more")}
@click=${this._unsupportedDialog}
>
Learn more
@ -200,10 +186,12 @@ class HassioSupervisorInfo extends LitElement {
</div>`}
${!this.supervisor.supervisor.healthy
? html`<div class="error">
Your installation is running in an unhealthy state.
${this.supervisor.localize(
"system.supervisor.unhealthy_title"
)}
<button
class="link"
title="Learn more about why your system is marked as unhealthy"
.title=${this.supervisor.localize("common.learn_more")}
@click=${this._unhealthyDialog}
>
Learn more
@ -227,16 +215,26 @@ class HassioSupervisorInfo extends LitElement {
<div class="card-actions">
<ha-progress-button
@click=${this._supervisorReload}
title="Reload parts of the Supervisor"
.title=${this.supervisor.localize(
"system.supervisor.reload_supervisor"
)}
>
Reload Supervisor
${this.supervisor.localize("system.supervisor.reload_supervisor")}
</ha-progress-button>
<ha-progress-button
class="warning"
@click=${this._supervisorRestart}
title="Restart the Supervisor"
.title=${this.supervisor.localize(
"common.restart_name",
"name",
"Supervisor"
)}
>
Restart Supervisor
${this.supervisor.localize(
"common.restart_name",
"name",
"Supervisor"
)}
</ha-progress-button>
</div>
</ha-card>
@ -257,23 +255,23 @@ class HassioSupervisorInfo extends LitElement {
if (this.supervisor.supervisor.channel === "stable") {
const confirmed = await showConfirmationDialog(this, {
title: "WARNING",
text: html` Beta releases are for testers and early adopters and can
contain unstable code changes.
title: this.supervisor.localize("system.supervisor.warning"),
text: html`${this.supervisor.localize("system.supervisor.beta_warning")}
<br />
<b>
Make sure you have backups of your data before you activate this
feature.
${this.supervisor.localize("system.supervisor.beta_backup")}
</b>
<br /><br />
This includes beta releases for:
${this.supervisor.localize("system.supervisor.beta_release_items")}
<li>Home Assistant Core</li>
<li>Home Assistant Supervisor</li>
<li>Home Assistant Operating System</li>
<br />
Do you want to join the beta channel?`,
confirmText: "join beta",
dismissText: "no",
${this.supervisor.localize("system.supervisor.join_beta_action")}`,
confirmText: this.supervisor.localize(
"system.supervisor.beta_join_confirm"
),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -291,7 +289,9 @@ class HassioSupervisorInfo extends LitElement {
await this._reloadSupervisor();
} catch (err) {
showAlertDialog(this, {
title: "Failed to set supervisor option",
title: this.supervisor.localize(
"system.supervisor.failed_to_set_option"
),
text: extractApiErrorMessage(err),
});
} finally {
@ -307,7 +307,7 @@ class HassioSupervisorInfo extends LitElement {
await this._reloadSupervisor();
} catch (err) {
showAlertDialog(this, {
title: "Failed to reload the supervisor",
title: this.supervisor.localize("system.supervisor.failed_to_reload"),
text: extractApiErrorMessage(err),
});
} finally {
@ -327,10 +327,18 @@ class HassioSupervisorInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Restart the Supervisor",
text: "Are you sure you want to restart the Supervisor",
confirmText: "restart",
dismissText: "cancel",
title: this.supervisor.localize(
"confirm.restart.title",
"name",
"Supervisor"
),
text: this.supervisor.localize(
"confirm.restart.text",
"name",
"Supervisor"
),
confirmText: this.supervisor.localize("common.restart"),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -342,7 +350,11 @@ class HassioSupervisorInfo extends LitElement {
await restartSupervisor(this.hass);
} catch (err) {
showAlertDialog(this, {
title: "Failed to restart the supervisor",
title: this.supervisor.localize(
"common.failed_to_restart_name",
"name",
"Supervisor"
),
text: extractApiErrorMessage(err),
});
} finally {
@ -355,10 +367,16 @@ class HassioSupervisorInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Update Supervisor",
text: `Are you sure you want to update supervisor to version ${this.supervisor.supervisor.version_latest}?`,
confirmText: "update",
dismissText: "cancel",
title: this.supervisor.localize("confirm.update", "name", "Supervisor"),
text: this.supervisor.localize(
"confirm.text",
"name",
"Supervisor",
"version",
this.supervisor.supervisor.version_latest
),
confirmText: this.supervisor.localize("common.update"),
dismissText: this.supervisor.localize("common.cancel"),
});
if (!confirmed) {
@ -373,7 +391,11 @@ class HassioSupervisorInfo extends LitElement {
});
} catch (err) {
showAlertDialog(this, {
title: "Failed to update the supervisor",
title: this.supervisor.localize(
"common.failed_to_update_name",
"name",
"Supervisor"
),
text: extractApiErrorMessage(err),
});
} finally {
@ -383,40 +405,41 @@ class HassioSupervisorInfo extends LitElement {
private async _diagnosticsInformationDialog(): Promise<void> {
await showAlertDialog(this, {
title: "Help Improve Home Assistant",
text: html`Would you want to automatically share crash reports and
diagnostic information when the supervisor encounters unexpected errors?
<br /><br />
This will allow us to fix the problems, the information is only
accessible to the Home Assistant Core team and will not be shared with
others.
<br /><br />
The data does not include any private/sensitive information and you can
disable this in settings at any time you want.`,
title: this.supervisor.localize(
"system.supervisor.share_diagonstics_title"
),
text: this.supervisor.localize(
"system.supervisor.share_diagonstics_description",
"line_break",
html`<br /><br />`
),
});
}
private async _unsupportedDialog(): Promise<void> {
await showAlertDialog(this, {
title: "You are running an unsupported installation",
text: html`Below is a list of issues found with your installation, click
on the links to learn how you can resolve the issues. <br /><br />
title: this.supervisor.localize("system.supervisor.unsupported_title"),
text: html`${this.supervisor.localize(
"system.supervisor.unsupported_description"
)} <br /><br />
<ul>
${this.supervisor.resolution.unsupported.map(
(issue) => html`
(reason) => html`
<li>
${UNSUPPORTED_REASON[issue]
${UNSUPPORTED_REASON_URL[reason]
? html`<a
href="${documentationUrl(
this.hass,
UNSUPPORTED_REASON[issue].url
UNSUPPORTED_REASON_URL[reason]
)}"
target="_blank"
rel="noreferrer"
>
${UNSUPPORTED_REASON[issue].title}
${this.supervisor.localize(
`system.supervisor.unsupported_reason.${reason}`
) || reason}
</a>`
: issue}
: reason}
</li>
`
)}
@ -426,26 +449,28 @@ class HassioSupervisorInfo extends LitElement {
private async _unhealthyDialog(): Promise<void> {
await showAlertDialog(this, {
title: "Your installation is unhealthy",
text: html`Running an unhealthy installation will cause issues. Below is a
list of issues found with your installation, click on the links to learn
how you can resolve the issues. <br /><br />
title: this.supervisor.localize("system.supervisor.unhealthy_title"),
text: html`${this.supervisor.localize(
"system.supervisor.unhealthy_description"
)} <br /><br />
<ul>
${this.supervisor.resolution.unhealthy.map(
(issue) => html`
(reason) => html`
<li>
${UNHEALTHY_REASON[issue]
${UNHEALTHY_REASON_URL[reason]
? html`<a
href="${documentationUrl(
this.hass,
UNHEALTHY_REASON[issue].url
UNHEALTHY_REASON_URL[reason]
)}"
target="_blank"
rel="noreferrer"
>
${UNHEALTHY_REASON[issue].title}
${this.supervisor.localize(
`system.supervisor.unhealthy_reason.${reason}`
) || reason}
</a>`
: issue}
: reason}
</li>
`
)}
@ -461,7 +486,9 @@ class HassioSupervisorInfo extends LitElement {
await setSupervisorOption(this.hass, data);
} catch (err) {
showAlertDialog(this, {
title: "Failed to set supervisor option",
title: this.supervisor.localize(
"system.supervisor.failed_to_set_option"
),
text: extractApiErrorMessage(err),
});
}

View File

@ -16,6 +16,7 @@ import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-card";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import { fetchHassioLogs } from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import "../../../src/layouts/hass-loading-screen";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types";
@ -58,6 +59,8 @@ const logProviders: LogProvider[] = [
class HassioSupervisorLog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@internalProperty() private _error?: string;
@internalProperty() private _selectedLogProvider = "supervisor";
@ -76,7 +79,7 @@ class HassioSupervisorLog extends LitElement {
${this.hass.userData?.showAdvanced
? html`
<paper-dropdown-menu
label="Log Provider"
.label=${this.supervisor.localize("system.log.log_provider")}
@iron-select=${this._setLogProvider}
>
<paper-listbox
@ -86,9 +89,9 @@ class HassioSupervisorLog extends LitElement {
>
${logProviders.map((provider) => {
return html`
<paper-item provider=${provider.key}
>${provider.name}</paper-item
>
<paper-item provider=${provider.key}>
${provider.name}
</paper-item>
`;
})}
</paper-listbox>
@ -98,14 +101,13 @@ class HassioSupervisorLog extends LitElement {
<div class="card-content" id="content">
${this._content
? html`<hassio-ansi-to-html
.content=${this._content}
></hassio-ansi-to-html>`
? html`<hassio-ansi-to-html .content=${this._content}>
</hassio-ansi-to-html>`
: html`<hass-loading-screen no-toolbar></hass-loading-screen>`}
</div>
<div class="card-actions">
<ha-progress-button @click=${this._refresh}>
Refresh
${this.supervisor.localize("common.refresh")}
</ha-progress-button>
</div>
</ha-card>
@ -134,9 +136,13 @@ class HassioSupervisorLog extends LitElement {
this._selectedLogProvider
);
} catch (err) {
this._error = `Failed to get supervisor logs, ${extractApiErrorMessage(
err
)}`;
this._error = this.supervisor.localize(
"system.log.get_logs",
"provider",
this._selectedLogProvider,
"error",
extractApiErrorMessage(err)
);
}
}

View File

@ -57,7 +57,10 @@ class HassioSystem extends LitElement {
.supervisor=${this.supervisor}
></hassio-host-info>
</div>
<hassio-supervisor-log .hass=${this.hass}></hassio-supervisor-log>
<hassio-supervisor-log
.hass=${this.hass}
.supervisor=${this.supervisor}
></hassio-supervisor-log>
</div>
</hass-tabs-subpage>
`;

View File

@ -3420,24 +3420,215 @@
},
"supervisor": {
"addon": {
"failed_to_reset": "Failed to reset add-on configuration, {error}",
"failed_to_save": "Failed to save add-on configuration, {error}",
"state": {
"installed": "Add-on is installed",
"not_installed": "Add-on is not installed",
"not_available": "Add-on is not available on your system"
},
"panel": {
"configuration": "Configuration",
"documentation": "Documentation",
"info": "Info",
"log": "Log"
},
"configuration": {
"no_configuration": "This add-on does not expose configuration for you to mess with...",
"audio": {
"header": "Audio",
"default": "Default",
"input": "Input",
"output": "Output"
},
"options": {
"header": "Options",
"edit_in_ui": "Edit in UI",
"edit_in_yaml": "Edit in YAML",
"invalid_yaml": "Invalid YAML",
"show_unused_optional": "Show unused optional configuration options"
},
"network": {
"container": "Container",
"disabled": "Disabled",
"header": "Network",
"host": "Host"
}
},
"dashboard": {
"changelog": "Changelog",
"cpu_usage": "Add-on CPU Usage",
"ram_usage": "Add-on RAM Usage",
"hostname": "Hostname",
"new_update_available": "{name} {version} is available",
"not_available_arch": "This add-on is not compatible with the processor of your device or the operating system you have installed on your device.",
"not_available_version": "You are unning Home Assistant {core_version_installed}, to update to this version of the add-on you need at least version {core_version_needed} of Home Assistan",
"visit_addon_page": "Visit the {name} page for more detals",
"restart": "restart",
"start": "start",
"stop": "stop",
"install": "install",
"uninstall": "uninstall",
"rebuild": "rebuild",
"open_web_ui": "Open web UI",
"protection_mode": {
"title": "Warning: Protection mode is disabled!",
"content": "Protection mode on this add-on is disabled! This gives the add-on full access to the entire system, which adds security risks, and could damage your system when used incorrectly. Only disable the protection mode if you know, need AND trust the source of this add-on.",
"enable": "Enable Protection mode"
},
"capability": {
"stage": {
"title": "Add-on Stage",
"description": "Add-ons can have one of three stages:\n\n{icon_stable} **Stable**: These are add-ons ready to be used in production.\n\n{icon_experimental} **Experimental**: These may contain bugs, and may be unfinished.\n\n{icon_deprecated} **Deprecated**: These add-ons will no longer receive any updates."
},
"rating": {
"title": "Add-on Security Rating",
"description": "Home Assistant provides a security rating to each of the add-ons, which indicates the risks involved when using this add-on. The more access an add-on requires on your system, the lower the score, thus raising the possible security risks.\n\nA score is on a scale from 1 to 6. Where 1 is the lowest score (considered the most insecure and highest risk) and a score of 6 is the highest score (considered the most secure and lowest risk)."
},
"host_network": {
"title": "Host Network",
"description": "Add-ons usually run in their own isolated network layer, which prevents them from accessing the network of the host operating system. In some cases, this network isolation can limit add-ons in providing their services and therefore, the isolation can be lifted by the add-on author, giving the add-on full access to the network capabilities of the host machine. This gives the add-on more networking capabilities but lowers the security, hence, the security rating of the add-on will be lowered when this option is used by the add-on."
},
"homeassistant_api": {
"title": "Home Assistant API Access",
"description": "This add-on is allowed to access your running Home Assistant instance directly via the Home Assistant API. This mode handles authentication for the add-on as well, which enables an add-on to interact with Home Assistant without the need for additional authentication tokens."
},
"full_access": {
"title": "Full Hardware Access",
"description": "This add-on is given full access to the hardware of your system, by request of the add-on author. Access is comparable to the privileged mode in Docker. Since this opens up possible security risks, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on."
},
"hassio_api": {
"title": "Supervisor API Access",
"description": "The add-on was given access to the Supervisor API, by request of the add-on author. By default, the add-on can access general version information of your system. When the add-on requests 'manager' or 'admin' level access to the API, it will gain access to control multiple parts of your Home Assistant system. This permission is indicated by this badge and will impact the security score of the add-on negatively."
},
"docker_api": {
"title": "Full Docker Access",
"description": "The add-on author has requested the add-on to have management access to the Docker instance running on your system. This mode gives the add-on full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on."
},
"host_pid": {
"title": "Host Processes Namespace",
"description": "Usually, the processes the add-on runs, are isolated from all other system processes. The add-on author has requested the add-on to have access to the system processes running on the host system instance, and allow the add-on to spawn processes on the host system as well. This mode gives the add-on full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on."
},
"apparmor": {
"title": "AppArmor",
"description": "AppArmor ('Application Armor') is a Linux kernel security module that restricts add-ons capabilities like network access, raw socket access, and permission to read, write, or execute specific files.\n\nAdd-on authors can provide their security profiles, optimized for the add-on, or request it to be disabled. If AppArmor is disabled, it will raise security risks and therefore, has a negative impact on the security score of the add-on."
},
"auth_api": {
"title": "Home Assistant Authentication",
"description": "An add-on can authenticate users against Home Assistant, allowing add-ons to give users the possibility to log into applications running inside add-ons, using their Home Assistant username/password. This badge indicates if the add-on author requests this capability."
},
"ingress": {
"title": "Ingress",
"description": "This add-on is using Ingress to embed its interface securely into Home Assistant."
},
"label": {
"stage": "stage",
"rating": "rating",
"hardware": "hardware",
"host": "host",
"hass": "hass",
"hassio": "hassio",
"docker": "docker",
"host_pid": "host pid",
"apparmor": "apparmor",
"auth": "auth",
"ingress": "ingress"
},
"role": {
"manager": "manager",
"default": "default",
"homeassistant": "homeassistant",
"backup": "backup",
"admin": "admin"
}
},
"option": {
"boot": {
"title": "Start on boot",
"description": "Make the add-on start during a system boot"
},
"watchdog": {
"title": "Watchdog",
"description": "This will start the add-on if it crashes"
},
"auto_update": {
"title": "Auto update",
"description": "Auto update the add-on when there is a new version available"
},
"ingress_panel": {
"title": "Show in sidebar",
"description": "Add this add-on to your sidebar"
},
"protected": {
"title": "Protection mode",
"description": "Blocks elevated system access from the add-on"
}
},
"action_error": {
"uninstall": "Failed to uninstall add-on",
"install": "Failed to install add-on",
"stop": "Failed to stop add-on",
"restart": "Failed to restart add-on",
"start": "Failed to start add-on",
"go_to_config": "Failed to start add-on - configuration validation failed!",
"start_invalid_config": "Go to configuration",
"validate_config": "Failed to validate add-on configuration",
"get_changelog": "Failed to get add-on changelog"
}
},
"documentation": {
"get_documentation": "Failed to get add-on documentation, {error}"
},
"logs": {
"get_logs": "Failed to get add-on logs, {error}"
}
},
"common": {
"cancel": "Cancel",
"cancel": "[%key:ui::common::cancel%]",
"yes": "[%key:ui::common::yes%]",
"no": "[%key:ui::common::no%]",
"description": "Description",
"failed_to_restart_name": "Failed to restart {name}",
"failed_to_update_name": "Failed to update {name}",
"learn_more": "Learn more",
"new_version_available": "New version available",
"newest_version": "Newest Version",
"refresh": "[%key:ui::common::refresh%]",
"release_notes": "Release notes",
"reload": "Reload",
"reset_defaults": "Reset to defaults",
"reset_options": "Reset options",
"restart_name": "Restart {name}",
"restart": "Restart",
"running_version": "You are currently running version {version}",
"save": "Save",
"show_more": "Show more information about this",
"update_available": "{count, plural,\n one {Update}\n other {{count} Updates}\n} pending",
"update": "Update",
"version": "Version"
"version": "Version",
"error": {
"unknown": "Unknown error",
"update_failed": "Update failed"
}
},
"confirm": {
"update": {
"title": "Update ${name}",
"title": "Update {name}",
"text": "Are you sure you want to update {name} to version {version}?"
},
"restart": {
"title": "[%key:supervisor::common::restart_name%]",
"text": "Are you sure you want to restart {name}?"
},
"reset_options": {
"title": "Reset options",
"text": "Are you sure you want to reset all your options?"
}
},
"dashboard": {
@ -3445,18 +3636,172 @@
"addon_running": "Add-on is running",
"addon_stopped": "Add-on is stopped",
"addons": "Add-ons",
"no_addons": "You don't have any add-ons installed yet. Head over to the add-on store to get started!",
"update_available": "{count, plural,\n one {Update}\n other {{count} Updates}\n} pending"
"no_addons": "You don't have any add-ons installed yet. Head over to the add-on store to get started!"
},
"error": {
"unknown": "Unknown error",
"update_failed": "Update failed"
"store": {
"missing_addons": "Missing add-ons? Enable advanced mode in your user profile page",
"no_results_found": "No results found in {repository}.",
"registries": "Registries",
"repositories": "Repositories"
},
"panel": {
"dashboard": "Dashboard",
"snapshots": "Snapshots",
"store": "Add-on Store",
"system": "System"
},
"my": {
"not_supported": "[%key:ui::panel::my::not_supported%]",
"faq_link": "[%key:ui::panel::my::faq_link%]",
"error": "[%key:ui::panel::my::error%]"
},
"system": {
"log": {
"log_provider": "Log Provider",
"get_logs": "Failed to get {provider} logs, {error}"
},
"supervisor": {
"cpu_usage": "Supervisor CPU Usage",
"ram_usage": "Supervisor RAM Usage",
"failed_to_set_option": "Failed to set Supervisor option",
"failed_to_reload": "Failed to reload the Supervisor",
"failed_to_update": "Failed to update the Supervisor",
"unsupported_title": "You are running an unsupported installation",
"unsupported_description": "Below is a list of issues found with your installation, click on the links to learn how you can resolve the issues.",
"unhealthy_title": "Your installation is unhealthy",
"unhealthy_description": "Running an unhealthy installation will cause issues. Below is a list of issues found with your installation, click on the links to learn how you can resolve the issues.",
"update_supervisor": "Update the Supervisor",
"channel": "Channel",
"leave_beta_action": "Leave beta channel",
"leave_beta_description": "Get stable updates for Home Assistant, Supervisor and host",
"join_beta_action": "Join beta channel",
"join_beta_description": "Get beta updates for Home Assistant (RCs), Supervisor and host",
"share_diagnostics": "Share Diagnostics",
"share_diagnostics_description": "Share crash reports and diagnostic information.",
"reload_supervisor": "Reload Supervisor",
"warning": "WARNING",
"beta_warning": "Beta releases are for testers and early adopters and can contain unstable code changes",
"beta_backup": "Make sure you have backups of your data before you activate this feature.",
"beta_release_items": "This includes beta releases for:",
"beta_join_confirm": "Do you want to join the beta channel?",
"share_diagonstics_title": "Help Improve Home Assistant",
"share_diagonstics_description": "Would you want to automatically share crash reports and diagnostic information when the Supervisor encounters unexpected errors? {line_break} This will allow us to fix the problems, the information is only accessible to the Home Assistant Core team and will not be shared with others.{line_break} The data does not include any private/sensitive information and you can disable this in settings at any time you want.",
"unsupported_reason": {
"container": "Containers known to cause issues",
"dbus": "DBUS",
"docker_configuration": "Docker Configuration",
"docker_version": "Docker Version",
"job_conditions": "Ignored job conditions",
"lxc": "LXC",
"network_manager": "Network Manager",
"os": "Operating System",
"privileged": "Supervisor is not privileged",
"systemd": "Systemd"
},
"unhealthy_reason": {
"privileged": "Supervisor is not privileged",
"supervisor": "Supervisor was not able to update",
"setup": "Setup of the Supervisor failed",
"docker": "The Docker environment is not working properly"
}
},
"host": {
"failed_to_get_hardware_list": "Failed to get hardware list",
"failed_to_reboot": "Failed to reboot the host",
"failed_to_shutdown": "Failed to shutdown the host",
"failed_to_set_hostname": "Setting hostname failed",
"failed_to_import_from_usb": "Failed to import from USB",
"used_space": "Used space",
"hostname": "Hostname",
"change_hostname": "Change Hostname",
"new_hostname": "Please enter a new hostname:",
"ip_address": "IP Address",
"change": "Change",
"operating_system": "Operating System",
"docker_version": "Docker version",
"deployment": "Deployment",
"emmc_lifetime_used": "eMMC Lifetime Used",
"reboot_host": "Reboot host",
"confirm_reboot": "Are you sure you want to reboot the host?",
"confirm_shutdown": "Are you sure you want to shutdown the host?",
"shutdown_host": "Shutdown host",
"hardware": "Hardware",
"import_from_usb": "Import from USB"
},
"core": {
"cpu_usage": "Core CPU Usage",
"ram_usage": "Core RAM Usage"
}
},
"snapshot": {
"description": "Snapshots allow you to easily backup and restore all data of your Home Assistant instance.",
"available_snapshots": "Available Snapshots",
"no_snapshots": "You don't have any snapshots yet.",
"create_blocked_not_running": "Creating a snapshot is not possible right now because the system is in {state} state.",
"could_not_create": "Could not create snapshot",
"upload_snapshot": "Upload snapshot",
"create_snapshot": "Create snapshot",
"create": "Create",
"name": "Name",
"type": "Type",
"security": "Security",
"full_snapshot": "Full snapshot",
"partial_snapshot": "Partial snapshot",
"addons": "Add-ons",
"folders": "Folders",
"password": "Password",
"password_protection": "Password protection",
"password_protected": "password protected",
"enter_password": "Please enter a password.",
"folder": {
"homeassistant": "Home Assistant configuration",
"ssl": "SSL",
"share": "Share",
"media": "Media",
"addons/local": "Local add-ons"
}
},
"dialog": {
"network": {
"title": "Network settings",
"connected_to": "Connected to {ssid}",
"scan_ap": "Scan for accesspoints",
"open": "Open",
"wep": "WEP",
"wpa": "wpa-psk",
"warning": "If you are changing the Wi-Fi, IP or gateway addresses, you might lose the connection!",
"static": "Static",
"dhcp": "DHCP",
"disabled": "Disabled",
"ip_netmask": "IP address/Netmask",
"gateway": "Gateway address",
"dns_servers": "DNS Servers",
"unsaved": "You have unsaved changes, these will get lost if you change tabs, do you want to continue?",
"failed_to_change": "Failed to change network settings"
},
"registries": {
"title_add": "Add New Container Registry",
"title_manage": "Manage Container Registries",
"registry": "Registry",
"username": "Username",
"password": "Password",
"no_registries": "No registries configured",
"add_registry": "Add registry",
"add_new_registry": "Add new registry",
"remove": "Remove",
"failed_to_add": "Failed to add registry",
"failed_to_remove": "Failed to remove registry"
},
"repositories": {
"title": "Manage add-on repositories",
"add": "Add",
"remove": "Remove"
},
"restart_addon": {
"confirm_text": "Restart add-on",
"text": "Do you want to restart the add-on with your changes?"
}
}
}
}