diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index d550943727..f7b47f9813 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -7,31 +7,23 @@ trigger: - "*" pr: none variables: - - name: versionBuilder - value: "5.2" - - group: github + - name: versionWheels + value: '1.1-3.7-alpine3.10' + - name: versionNode + value: '12.1' - group: twine +resources: + repositories: + - repository: azure + type: github + name: 'home-assistant/ci-azure' + endpoint: 'home-assistant' + stages: - stage: "Validate" jobs: - - job: "VersionValidate" - pool: - vmImage: "ubuntu-latest" - steps: - - task: UsePythonVersion@0 - displayName: "Use Python 3.7" - inputs: - versionSpec: "3.7" - - script: | - setup_version="$(python setup.py -V)" - branch_version="$(Build.SourceBranchName)" - - if [ "${setup_version}" != "${branch_version}" ]; then - echo "Version of tag ${branch_version} don't match with ${setup_version}!" - exit 1 - fi - displayName: "Check version of branch/tag" + - template: templates/azp-job-version.yaml@azure - stage: "Build" jobs: @@ -44,9 +36,9 @@ stages: inputs: versionSpec: "3.7" - task: NodeTool@0 - displayName: "Use Node 12.1" + displayName: "Use Node $(versionNode)" inputs: - versionSpec: "12.1" + versionSpec: "$(versionNode)" - script: pip install twine wheel displayName: "Install tools" - script: | @@ -55,3 +47,18 @@ stages: script/release displayName: "Build and release package" + - template: templates/azp-job-wheels.yaml@azure + parameters: + builderVersion: '$(versionWheels)' + builderApk: 'build-base' + wheelsLocal: true + preBuild: + - task: NodeTool@0 + displayName: "Use Node $(versionNode)" + inputs: + versionSpec: "$(versionNode)" + - script: | + set -e + + yarn install + script/build_frontend diff --git a/cast/script/upload b/cast/script/upload index 95f46032cf..fc22529ceb 100755 --- a/cast/script/upload +++ b/cast/script/upload @@ -1,3 +1,5 @@ # Run it twice, second time we just delete. aws s3 sync dist s3://cast.home-assistant.io --acl public-read -aws s3 sync dist s3://cast.home-assistant.io --acl public-read --delete +# Don't delete as it might break open sites that need to load code splitted things. +# aws s3 sync dist s3://cast.home-assistant.io --acl public-read --delete +# Todo : update JS first, HTML last. diff --git a/cast/src/html/launcher-faq.html.template b/cast/src/html/launcher-faq.html.template index 85ecbb0079..20640e8b54 100644 --- a/cast/src/html/launcher-faq.html.template +++ b/cast/src/html/launcher-faq.html.template @@ -118,7 +118,42 @@

-
How does Home Assistant Cast work?
+
+ Why does Home Assistant Cast require me to authorize my Home Assistant + instance? +
+
+

+ You're currently looking at the Home Assistant Cast launcher + application. This is a standalone application to launch Home Assistant + Cast on your Chromecast. Because Chromecasts do not allow us to log in + to Home Assistant, we need to supply authentication to it from the + launcher. This authentication is obtained when you authorize your + instance. Your authentication credentials will remain in your browser + and on your Cast device. +

+

+ Your authentication credentials or Home Assistant url are never sent + to the Cloud. You can validate this behavior in + the source code. +

+

+ The launcher application exists to make it possible to use Home + Assistant Cast with older versions of Home Assistant. +

+

+ Starting with Home Assistant 0.97, Home Assistant Cast is also built + into the Lovelace UI as a special entities card row. Since the + Lovelace UI already has authentication, you will be able to start + casting right away. +

+
+ +
Wat does Home Assistant Cast do?

Home Assistant Cast is a receiver application for the Chromecast. When diff --git a/cast/src/html/launcher.html.template b/cast/src/html/launcher.html.template index da036e54eb..25b2eba1a5 100644 --- a/cast/src/html/launcher.html.template +++ b/cast/src/html/launcher.html.template @@ -42,10 +42,13 @@ })(); diff --git a/cast/src/html/receiver.html.template b/cast/src/html/receiver.html.template index 9b6170abcd..3e1da1fa12 100644 --- a/cast/src/html/receiver.html.template +++ b/cast/src/html/receiver.html.template @@ -9,4 +9,10 @@ font-size: initial; } + diff --git a/cast/src/launcher/layout/hc-cast.ts b/cast/src/launcher/layout/hc-cast.ts index 02a5ed2b5b..25c1d3bdb2 100644 --- a/cast/src/launcher/layout/hc-cast.ts +++ b/cast/src/launcher/layout/hc-cast.ts @@ -158,16 +158,6 @@ class HcCast extends LitElement { protected updated(changedProps) { super.updated(changedProps); - if (this.castManager && this.castManager.status) { - const selectEl = this.shadowRoot!.querySelector("select"); - if (selectEl) { - this.shadowRoot!.querySelector("select")!.value = - this.castManager.castConnectedToOurHass && - !this.castManager.status.showDemo - ? this.castManager.status.lovelacePath || "" - : ""; - } - } this.toggleAttribute( "hide-icons", this.lovelaceConfig diff --git a/cast/src/receiver/layout/hc-lovelace.ts b/cast/src/receiver/layout/hc-lovelace.ts index 4a41175dc9..0be9488a54 100644 --- a/cast/src/receiver/layout/hc-lovelace.ts +++ b/cast/src/receiver/layout/hc-lovelace.ts @@ -16,8 +16,10 @@ import "./hc-launch-screen"; @customElement("hc-lovelace") class HcLovelace extends LitElement { @property() public hass!: HomeAssistant; + @property() public lovelaceConfig!: LovelaceConfig; - @property() public viewPath?: string; + + @property() public viewPath?: string | number; protected render(): TemplateResult | void { const index = this._viewIndex; @@ -50,10 +52,11 @@ class HcLovelace extends LitElement { protected updated(changedProps) { super.updated(changedProps); + if (changedProps.has("viewPath") || changedProps.has("lovelaceConfig")) { const index = this._viewIndex; - if (index) { + if (index !== undefined) { this.shadowRoot!.querySelector("hui-view")!.style.background = this.lovelaceConfig.views[index].background || this.lovelaceConfig.background || @@ -64,7 +67,7 @@ class HcLovelace extends LitElement { private get _viewIndex() { const selectedView = this.viewPath; - const selectedViewInt = parseInt(selectedView!, 10); + const selectedViewInt = parseInt(selectedView as string, 10); for (let i = 0; i < this.lovelaceConfig.views.length; i++) { if ( this.lovelaceConfig.views[i].path === selectedView || @@ -77,7 +80,6 @@ class HcLovelace extends LitElement { } static get styles(): CSSResult { - // We're applying a 10% transform so it all shows a little bigger. return css` :host { min-height: 100vh; diff --git a/cast/src/receiver/layout/hc-main.ts b/cast/src/receiver/layout/hc-main.ts index b67bf96077..0171dae5bb 100644 --- a/cast/src/receiver/layout/hc-main.ts +++ b/cast/src/receiver/layout/hc-main.ts @@ -1,10 +1,10 @@ -import { HassElement } from "../../../../src/state/hass-element"; import { getAuth, createConnection, UnsubscribeFunc, } from "home-assistant-js-websocket"; import { customElement, TemplateResult, html, property } from "lit-element"; +import { HassElement } from "../../../../src/state/hass-element"; import { HassMessage, ConnectMessage, @@ -26,9 +26,13 @@ import { isNavigationClick } from "../../../../src/common/dom/is-navigation-clic @customElement("hc-main") export class HcMain extends HassElement { @property() private _showDemo = false; + @property() private _lovelaceConfig?: LovelaceConfig; - @property() private _lovelacePath: string | null = null; + + @property() private _lovelacePath: string | number | null = null; + @property() private _error?: string; + private _unsubLovelace?: UnsubscribeFunc; public processIncomingMessage(msg: HassMessage) { @@ -53,7 +57,7 @@ export class HcMain extends HassElement { `; } - if (!this._lovelaceConfig || !this._lovelacePath) { + if (!this._lovelaceConfig || this._lovelacePath === null) { return html` ` : html``} diff --git a/src/cards/ha-weather-card.js b/src/cards/ha-weather-card.js index df593e3243..3a86d465e1 100644 --- a/src/cards/ha-weather-card.js +++ b/src/cards/ha-weather-card.js @@ -285,7 +285,7 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { hail: "hass:weather-hail", lightning: "hass:weather-lightning", "lightning-rainy": "hass:weather-lightning-rainy", - partlycloudy: "hass:weather-partlycloudy", + partlycloudy: "hass:weather-partly-cloudy", pouring: "hass:weather-pouring", rainy: "hass:weather-rainy", snowy: "hass:weather-snowy", diff --git a/src/cast/receiver_messages.ts b/src/cast/receiver_messages.ts index d491c593e2..529d5e4e70 100644 --- a/src/cast/receiver_messages.ts +++ b/src/cast/receiver_messages.ts @@ -1,10 +1,10 @@ // Nessages to be processed inside the Cast Receiver app +import { Auth } from "home-assistant-js-websocket"; import { CastManager } from "./cast_manager"; import { BaseCastMessage } from "./types"; import { CAST_DEV_HASS_URL, CAST_DEV } from "./const"; -import { Auth } from "home-assistant-js-websocket"; export interface GetStatusMessage extends BaseCastMessage { type: "get_status"; @@ -19,7 +19,7 @@ export interface ConnectMessage extends BaseCastMessage { export interface ShowLovelaceViewMessage extends BaseCastMessage { type: "show_lovelace_view"; - viewPath: string | null; + viewPath: string | number | null; } export interface ShowDemoMessage extends BaseCastMessage { @@ -64,7 +64,6 @@ export const ensureConnectedCastSession = (cast: CastManager, auth: Auth) => { if (cast.castConnectedToOurHass) { unsub(); resolve(); - return; } }); diff --git a/src/cast/sender_messages.ts b/src/cast/sender_messages.ts index 83e85b80bc..2dc7ab2438 100644 --- a/src/cast/sender_messages.ts +++ b/src/cast/sender_messages.ts @@ -7,7 +7,7 @@ export interface ReceiverStatusMessage extends BaseCastMessage { connected: boolean; showDemo: boolean; hassUrl?: string; - lovelacePath?: string | null; + lovelacePath?: string | number | null; } export type SenderMessage = ReceiverStatusMessage; diff --git a/src/components/ha-markdown.js b/src/components/ha-markdown.js index 14b345d2e2..02c31e84d9 100644 --- a/src/components/ha-markdown.js +++ b/src/components/ha-markdown.js @@ -3,11 +3,7 @@ import { EventsMixin } from "../mixins/events-mixin"; let loaded = null; -/** - * White list allowed svg tag. - * Only put in the tag used in QR code, can be extend in future. - */ -const svgWhiteList = ["svg", "path"]; +const tagWhiteList = ["svg", "path", "ha-icon"]; /* * @appliesMixin EventsMixin @@ -16,12 +12,8 @@ class HaMarkdown extends EventsMixin(PolymerElement) { static get properties() { return { content: { - type: String, observer: "_render", - }, - allowSvg: { - type: Boolean, - value: false, + type: String, }, }; } @@ -51,7 +43,9 @@ class HaMarkdown extends EventsMixin(PolymerElement) { } _render() { - if (this._scriptLoaded === 0 || this._renderScheduled) return; + if (this._scriptLoaded === 0 || this._renderScheduled) { + return; + } this._renderScheduled = true; @@ -62,14 +56,13 @@ class HaMarkdown extends EventsMixin(PolymerElement) { if (this._scriptLoaded === 1) { this.innerHTML = this.filterXSS( this.marked(this.content, { + breaks: true, gfm: true, tables: true, - breaks: true, }), { - onIgnoreTag: this.allowSvg - ? (tag, html) => (svgWhiteList.indexOf(tag) >= 0 ? html : null) - : null, + onIgnoreTag: (tag, html) => + tagWhiteList.indexOf(tag) >= 0 ? html : null, } ); this._resize(); diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index fb315ed235..1f031913e5 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -36,21 +36,21 @@ const SHOW_AFTER_SPACER = ["config", "developer-tools", "hassio"]; const SUPPORT_SCROLL_IF_NEEDED = "scrollIntoViewIfNeeded" in document.body; -const SORT_VALUE = { +const SORT_VALUE_URL_PATHS = { map: 1, logbook: 2, history: 3, "developer-tools": 9, hassio: 10, - configuration: 11, + config: 11, }; const panelSorter = (a, b) => { - const aBuiltIn = a.component_name in SORT_VALUE; - const bBuiltIn = b.component_name in SORT_VALUE; + const aBuiltIn = a.url_path in SORT_VALUE_URL_PATHS; + const bBuiltIn = b.url_path in SORT_VALUE_URL_PATHS; if (aBuiltIn && bBuiltIn) { - return SORT_VALUE[a.component_name] - SORT_VALUE[b.component_name]; + return SORT_VALUE_URL_PATHS[a.url_path] - SORT_VALUE_URL_PATHS[b.url_path]; } if (aBuiltIn) { return -1; @@ -81,7 +81,7 @@ const computePanels = (hass: HomeAssistant): [PanelInfo[], PanelInfo[]] => { if (!panel.title) { return; } - (SHOW_AFTER_SPACER.includes(panel.component_name) + (SHOW_AFTER_SPACER.includes(panel.url_path) ? afterSpacer : beforeSpacer ).push(panel); diff --git a/src/data/ws-templates.ts b/src/data/ws-templates.ts new file mode 100644 index 0000000000..aec9903803 --- /dev/null +++ b/src/data/ws-templates.ts @@ -0,0 +1,20 @@ +import { Connection, UnsubscribeFunc } from "home-assistant-js-websocket"; + +interface RenderTemplateResult { + result: string; +} + +export const subscribeRenderTemplate = ( + conn: Connection, + onChange: (result: string) => void, + params: { + template: string; + entity_ids?: string | string[]; + variables?: object; + } +): Promise => { + return conn.subscribeMessage( + (msg: RenderTemplateResult) => onChange(msg.result), + { type: "render_template", ...params } + ); +}; diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index b338d26fbc..e1dfdbe577 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -37,7 +37,7 @@ class StepFlowAbort extends LitElement {

${description ? html` - + ` : ""}
diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index 5ecc457a40..801854ff49 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -56,7 +56,7 @@ class StepFlowCreateEntry extends LitElement {
${description ? html` - + ` : ""}

Created config for ${step.title}.

diff --git a/src/dialogs/config-flow/step-flow-external.ts b/src/dialogs/config-flow/step-flow-external.ts index 2dca5b5921..51175ce755 100644 --- a/src/dialogs/config-flow/step-flow-external.ts +++ b/src/dialogs/config-flow/step-flow-external.ts @@ -51,7 +51,7 @@ class StepFlowExternal extends LitElement {

${description ? html` - + ` : ""}
diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts index 3f5b93825b..9e24395f33 100644 --- a/src/dialogs/config-flow/step-flow-form.ts +++ b/src/dialogs/config-flow/step-flow-form.ts @@ -79,7 +79,7 @@ class StepFlowForm extends LitElement { : ""} ${description ? html` - + ` : ""} ); updateStates(newStates: HassEntities); addEntities(entites: Entity | Entity[], replace?: boolean); - mockWS(type: string, callback: (msg: any) => any); + mockWS( + type: string, + callback: (msg: any, onChange?: (response: any) => void) => any + ); mockAPI(path: string | RegExp, callback: MockRestCallback); mockEvent(event); mockTheme(theme: { [key: string]: string } | null); @@ -108,7 +111,7 @@ export const provideHass = ( console.error(`Unknown WS command: ${msg.type}`); } }, - sendMessagePromise: (msg) => { + sendMessagePromise: async (msg) => { const callback = wsCommands[msg.type]; return callback ? callback(msg) @@ -119,6 +122,17 @@ export const provideHass = ( } is not implemented in provide_hass.`, }); }, + subscribeMessage: async (onChange, msg) => { + const callback = wsCommands[msg.type]; + return callback + ? callback(msg, onChange) + : Promise.reject({ + code: "command_not_mocked", + message: `WS Command ${ + msg.type + } is not implemented in provide_hass.`, + }); + }, subscribeEvents: async ( // @ts-ignore callback, diff --git a/src/panels/config/server_control/ha-config-section-server-control.js b/src/panels/config/server_control/ha-config-section-server-control.js index 20d130498f..d1e7fb9c41 100644 --- a/src/panels/config/server_control/ha-config-section-server-control.js +++ b/src/panels/config/server_control/ha-config-section-server-control.js @@ -128,6 +128,13 @@ class HaConfigSectionServerControl extends LocalizeMixin(PolymerElement) { hidden$="[[!scriptLoaded(hass)]]" >[[localize('ui.panel.config.server_control.section.reloading.script')]] + [[localize('ui.panel.config.server_control.section.reloading.scene')]] +
@@ -200,6 +207,10 @@ class HaConfigSectionServerControl extends LocalizeMixin(PolymerElement) { return isComponentLoaded(hass, "script"); } + sceneLoaded(hass) { + return isComponentLoaded(hass, "scene"); + } + validateConfig() { this.validating = true; this.validateLog = ""; diff --git a/src/panels/lovelace/cards/hui-markdown-card.ts b/src/panels/lovelace/cards/hui-markdown-card.ts index b41bd5455e..0df7737f5a 100644 --- a/src/panels/lovelace/cards/hui-markdown-card.ts +++ b/src/panels/lovelace/cards/hui-markdown-card.ts @@ -8,12 +8,15 @@ import { CSSResult, } from "lit-element"; import { classMap } from "lit-html/directives/class-map"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; import "../../../components/ha-card"; import "../../../components/ha-markdown"; +import { HomeAssistant } from "../../../types"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { MarkdownCardConfig } from "./types"; +import { subscribeRenderTemplate } from "../../../data/ws-templates"; @customElement("hui-markdown-card") export class HuiMarkdownCard extends LitElement implements LovelaceCard { @@ -27,11 +30,16 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard { } @property() private _config?: MarkdownCardConfig; + @property() private _content?: string = ""; + @property() private _unsubRenderTemplate?: Promise; + @property() private _hass?: HomeAssistant; public getCardSize(): number { - return ( - this._config!.content.split("\n").length + (this._config!.title ? 1 : 0) - ); + return this._config === undefined + ? 3 + : this._config.card_size === undefined + ? this._config.content.split("\n").length + (this._config.title ? 1 : 0) + : this._config.card_size; } public setConfig(config: MarkdownCardConfig): void { @@ -40,6 +48,20 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard { } this._config = config; + + this._disconnect(); + if (this._hass) { + this._connect(); + } + } + + public disconnectedCallback() { + this._disconnect(); + } + + public set hass(hass) { + this._hass = hass; + this._connect(); } protected render(): TemplateResult | void { @@ -53,12 +75,47 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard { class="markdown ${classMap({ "no-header": !this._config.title, })}" - .content="${this._config.content}" + .content="${this._content}" > `; } + private async _connect() { + if (!this._unsubRenderTemplate && this._hass && this._config) { + this._unsubRenderTemplate = subscribeRenderTemplate( + this._hass.connection, + (result) => { + this._content = result; + }, + { + template: this._config.content, + entity_ids: this._config.entity_id, + } + ); + this._unsubRenderTemplate.catch(() => { + this._content = this._config!.content; + this._unsubRenderTemplate = undefined; + }); + } + } + + private async _disconnect() { + if (this._unsubRenderTemplate) { + try { + const unsub = await this._unsubRenderTemplate; + this._unsubRenderTemplate = undefined; + await unsub(); + } catch (e) { + if (e.code === "not_found") { + // If we get here, the connection was probably already closed. Ignore. + } else { + throw e; + } + } + } + } + static get styles(): CSSResult { return css` ha-markdown { diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 1ad9f31c53..12f0a441c3 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -118,6 +118,8 @@ export interface MarkdownCardConfig extends LovelaceCardConfig { type: "markdown"; content: string; title?: string; + card_size?: number; + entity_ids?: string | string[]; } export interface MediaControlCardConfig extends LovelaceCardConfig { diff --git a/src/panels/lovelace/editor/card-editor/hui-card-editor.ts b/src/panels/lovelace/editor/card-editor/hui-card-editor.ts new file mode 100644 index 0000000000..5e10eafeb6 --- /dev/null +++ b/src/panels/lovelace/editor/card-editor/hui-card-editor.ts @@ -0,0 +1,281 @@ +import { + html, + css, + LitElement, + TemplateResult, + CSSResult, + customElement, + property, +} from "lit-element"; + +import yaml from "js-yaml"; + +import "@material/mwc-button"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardConfig } from "../../../../data/lovelace"; +import { LovelaceCardEditor } from "../../types"; +import { getCardElementTag } from "../../common/get-card-element-tag"; + +import "../../components/hui-yaml-editor"; +// This is not a duplicate import, one is for types, one is for element. +// tslint:disable-next-line +import { HuiYamlEditor } from "../../components/hui-yaml-editor"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { EntityConfig } from "../../entity-rows/types"; + +declare global { + interface HASSDomEvents { + "entities-changed": { + entities: EntityConfig[]; + }; + "config-changed": { + config: LovelaceCardConfig; + error?: string; + }; + } +} + +export interface UIConfigChangedEvent extends Event { + detail: { + config: LovelaceCardConfig; + }; +} + +@customElement("hui-card-editor") +export class HuiCardEditor extends LitElement { + @property() public hass?: HomeAssistant; + + @property() private _yaml?: string; + @property() private _config?: LovelaceCardConfig; + @property() private _configElement?: LovelaceCardEditor; + @property() private _configElType?: string; + @property() private _GUImode: boolean = true; + // Error: Configuration broken - do not save + @property() private _error?: string; + // Warning: GUI editor can't handle configuration - ok to save + @property() private _warning?: string; + @property() private _loading: boolean = false; + + public get yaml(): string { + return this._yaml || ""; + } + public set yaml(_yaml: string) { + this._yaml = _yaml; + try { + this._config = yaml.safeLoad(this.yaml); + this._updateConfigElement(); + setTimeout(() => { + if (this._yamlEditor) { + this._yamlEditor.codemirror.refresh(); + } + }, 1); + this._error = undefined; + } catch (err) { + this._error = err.message; + } + fireEvent(this, "config-changed", { + config: this.value!, + error: this._error, + }); + } + + public get value(): LovelaceCardConfig | undefined { + return this._config; + } + public set value(config: LovelaceCardConfig | undefined) { + if (JSON.stringify(config) !== JSON.stringify(this._config || {})) { + this.yaml = yaml.safeDump(config); + } + } + + public get hasError(): boolean { + return this._error !== undefined; + } + + private get _yamlEditor(): HuiYamlEditor { + return this.shadowRoot!.querySelector("hui-yaml-editor")!; + } + + public toggleMode() { + this._GUImode = !this._GUImode; + } + + protected render(): TemplateResult { + return html` +
+ ${this._GUImode + ? html` +
+ ${this._loading + ? html` + + ` + : this._configElement} +
+ ` + : html` +
+ +
+ `} + ${this._error + ? html` +
+ ${this._error} +
+ ` + : ""} + ${this._warning + ? html` +
+ ${this._warning} +
+ ` + : ""} +
+ + + +
+
+ `; + } + + protected updated(changedProperties) { + super.updated(changedProperties); + + if (changedProperties.has("_GUImode")) { + if (this._GUImode === false) { + // Refresh code editor when switching to yaml mode + this._yamlEditor.codemirror.refresh(); + this._yamlEditor.codemirror.focus(); + } + fireEvent(this as HTMLElement, "iron-resize"); + } + } + + private _handleUIConfigChanged(ev: UIConfigChangedEvent) { + ev.stopPropagation(); + const config = ev.detail.config; + this.value = config; + } + private _handleYAMLChanged(ev) { + ev.stopPropagation(); + const newYaml = ev.detail.value; + if (newYaml !== this.yaml) { + this.yaml = newYaml; + } + } + + private async _updateConfigElement(): Promise { + if (!this.value) { + return; + } + + const cardType = this.value.type; + let configElement = this._configElement; + try { + this._error = undefined; + this._warning = undefined; + + if (this._configElType !== cardType) { + // If the card type has changed, we need to load a new GUI editor + if (!this.value.type) { + throw new Error("No card type defined"); + } + + const tag = getCardElementTag(cardType); + + // Check if the card type exists + const elClass = customElements.get(tag); + if (!elClass) { + throw new Error(`Unknown card type encountered: ${cardType}.`); + } + + this._loading = true; + // Check if a GUI editor exists + if (elClass && elClass.getConfigElement) { + configElement = await elClass.getConfigElement(); + } else { + configElement = undefined; + throw Error(`WARNING: No GUI editor available for: ${cardType}`); + } + + this._configElement = configElement; + this._configElType = cardType; + } + + // Setup GUI editor and check that it can handle the current config + try { + this._configElement!.setConfig(this.value); + } catch (err) { + throw Error(`WARNING: ${err.message}`); + } + + // Perform final setup + this._configElement!.hass = this.hass; + this._configElement!.addEventListener("config-changed", (ev) => + this._handleUIConfigChanged(ev as UIConfigChangedEvent) + ); + + return; + } catch (err) { + if (err.message.startsWith("WARNING:")) { + this._warning = err.message.substr(8); + } else { + this._error = err; + } + this._GUImode = false; + } finally { + this._loading = false; + fireEvent(this, "iron-resize"); + } + } + + static get styles(): CSSResult { + return css` + :host { + display: flex; + } + .wrapper { + width: 100%; + } + .gui-editor, + .yaml-editor { + padding: 8px 0px; + } + .error { + color: #ef5350; + } + .warning { + color: #ffa726; + } + .buttons { + text-align: right; + padding: 8px 0px; + } + paper-spinner { + display: block; + margin: auto; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-card-editor": HuiCardEditor; + } +} diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index 6caebb4255..33422e952d 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -12,6 +12,7 @@ import { HomeAssistant } from "../../../../types"; import { LovelaceCardConfig } from "../../../../data/lovelace"; import { getCardElementTag } from "../../common/get-card-element-tag"; import { CardPickTarget } from "../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; const cards = [ { name: "Alarm panel", type: "alarm-panel" }, @@ -60,6 +61,9 @@ export class HuiCardPicker extends LitElement { `; })}
+
+ MANUAL CARD +
`; } @@ -85,6 +89,12 @@ export class HuiCardPicker extends LitElement { ]; } + private _manualPicked(): void { + fireEvent(this, "config-changed", { + config: { type: "" }, + }); + } + private _cardPicked(ev: Event): void { const type = (ev.currentTarget! as CardPickTarget).type; const tag = getCardElementTag(type); @@ -97,7 +107,7 @@ export class HuiCardPicker extends LitElement { config = { ...config, ...cardConfig }; } - this.cardPicked!(config); + fireEvent(this, "config-changed", { config }); } } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index c0a058aeca..4ef5ea2eee 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -1,7 +1,9 @@ import { + css, html, LitElement, TemplateResult, + CSSResultArray, customElement, property, } from "lit-element"; @@ -9,11 +11,17 @@ import { import { HomeAssistant } from "../../../../types"; import { HASSDomEvent } from "../../../../common/dom/fire_event"; import { LovelaceCardConfig } from "../../../../data/lovelace"; -import "./hui-edit-card"; -import "./hui-dialog-pick-card"; +import "./hui-card-editor"; +// tslint:disable-next-line +import { HuiCardEditor } from "./hui-card-editor"; +import "./hui-card-preview"; +import "./hui-card-picker"; import { EditCardDialogParams } from "./show-edit-card-dialog"; import { addCard, replaceCard } from "../config-util"; +import "../../../../components/dialog/ha-paper-dialog"; +import { haStyleDialog } from "../../../../resources/styles"; + declare global { // for fire event interface HASSDomEvents { @@ -33,72 +41,227 @@ export class HuiDialogEditCard extends LitElement { @property() private _cardConfig?: LovelaceCardConfig; - @property() private _newCard?: boolean; - - constructor() { - super(); - this._cardPicked = this._cardPicked.bind(this); - this._cancel = this._cancel.bind(this); - this._save = this._save.bind(this); - } + @property() private _saving: boolean = false; + @property() private _error?: string; public async showDialog(params: EditCardDialogParams): Promise { this._params = params; const [view, card] = params.path; - this._newCard = card !== undefined ? false : true; this._cardConfig = card !== undefined ? params.lovelace.config.views[view].cards![card] : undefined; } + private get _cardEditorEl(): HuiCardEditor | null { + return this.shadowRoot!.querySelector("hui-card-editor"); + } + protected render(): TemplateResult | void { if (!this._params) { return html``; } - if (!this._cardConfig) { - // Card picker - return html` - - `; - } + return html` - - + +

+ ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.header")} +

+ + ${this._cardConfig === undefined + ? html` + + ` + : html` +
+
+ +
+
+ + ${this._error + ? html` + + ` + : ``} +
+
+ `} +
+
+ + ${this.hass!.localize("ui.common.cancel")} + + + ${this._saving + ? html` + + ` + : this.hass!.localize("ui.common.save")} + +
+
`; } - private _cardPicked(cardConf: LovelaceCardConfig): void { - this._cardConfig = cardConf; + static get styles(): CSSResultArray { + return [ + haStyleDialog, + css` + :host { + --code-mirror-max-height: calc(100vh - 176px); + } + + @media all and (max-width: 450px), all and (max-height: 500px) { + /* overrule the ha-style-dialog max-height on small screens */ + ha-paper-dialog { + max-height: 100%; + height: 100%; + } + } + + @media all and (min-width: 660px) { + ha-paper-dialog { + width: 845px; + } + } + + ha-paper-dialog { + max-width: 845px; + } + + .center { + margin-left: auto; + margin-right: auto; + } + + .content { + display: flex; + flex-direction: column; + margin: 0 -10px; + } + .content hui-card-preview { + margin: 4px auto; + max-width: 390px; + } + .content .element-editor { + margin: 0 10px; + } + + @media (min-width: 1200px) { + ha-paper-dialog { + max-width: none; + width: 1000px; + } + + .content { + flex-direction: row; + } + .content > * { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + } + .content hui-card-preview { + padding: 8px 0; + margin: auto 10px; + max-width: 500px; + } + } + + mwc-button paper-spinner { + width: 14px; + height: 14px; + margin-right: 20px; + } + .hidden { + display: none; + } + .element-editor { + margin-bottom: 8px; + } + .blur { + filter: blur(2px) grayscale(100%); + } + .element-preview { + position: relative; + } + .element-preview paper-spinner { + top: 50%; + left: 50%; + position: absolute; + z-index: 10; + } + hui-card-preview { + padding-top: 8px; + margin-bottom: 4px; + display: block; + width: 100%; + } + `, + ]; } - private _cancel(): void { + private _handleConfigChanged(ev) { + this._cardConfig = ev.detail.config; + this._error = ev.detail.error; + } + + private _close(): void { this._params = undefined; this._cardConfig = undefined; + this._error = undefined; } - private async _save(cardConf: LovelaceCardConfig): Promise { + private get _canSave(): boolean { + if (this._saving) { + return false; + } + if (this._cardConfig === undefined) { + return false; + } + if (this._cardEditorEl && this._cardEditorEl.hasError) { + return false; + } + return true; + } + + private async _save(): Promise { const lovelace = this._params!.lovelace; + this._saving = true; await lovelace.saveConfig( this._params!.path.length === 1 - ? addCard(lovelace.config, this._params!.path as [number], cardConf) + ? addCard( + lovelace.config, + this._params!.path as [number], + this._cardConfig! + ) : replaceCard( lovelace.config, this._params!.path as [number, number], - cardConf + this._cardConfig! ) ); + this._saving = false; + this._close(); } } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts deleted file mode 100644 index 49d80a6fd7..0000000000 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - html, - css, - LitElement, - TemplateResult, - CSSResult, - customElement, -} from "lit-element"; -import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; - -import "../../../../components/dialog/ha-paper-dialog"; - -import { haStyleDialog } from "../../../../resources/styles"; - -import "./hui-card-picker"; -import { HomeAssistant } from "../../../../types"; -import { LovelaceCardConfig } from "../../../../data/lovelace"; - -@customElement("hui-dialog-pick-card") -export class HuiDialogPickCard extends LitElement { - public hass?: HomeAssistant; - public cardPicked?: (cardConf: LovelaceCardConfig) => void; - public closeDialog?: () => void; - - protected render(): TemplateResult | void { - return html` - -

- ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.header")} -

- - - -
- MANUAL CARD -
-
- `; - } - - private _openedChanged(ev): void { - if (!ev.detail.value) { - this.closeDialog!(); - } - } - - private _skipPick() { - this.cardPicked!({ type: "" }); - } - - static get styles(): CSSResult[] { - return [ - haStyleDialog, - css` - @media all and (max-width: 450px), all and (max-height: 500px) { - /* overrule the ha-style-dialog max-height on small screens */ - ha-paper-dialog { - max-height: 100%; - height: 100%; - } - } - - @media all and (min-width: 660px) { - ha-paper-dialog { - width: 650px; - } - } - - ha-paper-dialog { - max-width: 650px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hui-dialog-pick-card": HuiDialogPickCard; - } -} diff --git a/src/panels/lovelace/editor/card-editor/hui-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-edit-card.ts deleted file mode 100644 index efe7ce09ac..0000000000 --- a/src/panels/lovelace/editor/card-editor/hui-edit-card.ts +++ /dev/null @@ -1,493 +0,0 @@ -import { - html, - css, - LitElement, - PropertyValues, - TemplateResult, - CSSResult, - customElement, - property, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import yaml from "js-yaml"; - -import { haStyleDialog } from "../../../../resources/styles"; - -import "@polymer/paper-spinner/paper-spinner"; -import "@polymer/paper-dialog/paper-dialog"; -import "../../../../components/dialog/ha-paper-dialog"; -// This is not a duplicate import, one is for types, one is for element. -// tslint:disable-next-line -import { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog"; -import "@material/mwc-button"; -import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; -import { HomeAssistant } from "../../../../types"; -import { LovelaceCardConfig } from "../../../../data/lovelace"; -import { fireEvent } from "../../../../common/dom/fire_event"; - -import "../../components/hui-yaml-editor"; -// This is not a duplicate import, one is for types, one is for element. -// tslint:disable-next-line -import { HuiYamlEditor } from "../../components/hui-yaml-editor"; -import "./hui-card-preview"; -// This is not a duplicate import, one is for types, one is for element. -// tslint:disable-next-line -import { HuiCardPreview } from "./hui-card-preview"; -import { LovelaceCardEditor, Lovelace } from "../../types"; -import { ConfigError } from "../types"; -import { EntityConfig } from "../../entity-rows/types"; -import { getCardElementTag } from "../../common/get-card-element-tag"; -import { afterNextRender } from "../../../../common/util/render-status"; - -declare global { - interface HASSDomEvents { - "entities-changed": { - entities: EntityConfig[]; - }; - "config-changed": { - config: LovelaceCardConfig; - }; - } -} - -@customElement("hui-edit-card") -export class HuiEditCard extends LitElement { - @property() public hass?: HomeAssistant; - - @property() public cardConfig?: LovelaceCardConfig; - - public lovelace?: Lovelace; - - public closeDialog?: () => void; - - public saveCard?: (cardConf: LovelaceCardConfig) => Promise; - - public newCard?: boolean; - - @property() private _configElement?: LovelaceCardEditor | null; - - @property() private _uiEditor?: boolean; - - @property() private _cardConfig?: LovelaceCardConfig; - - @property() private _configState?: string; - - @property() private _loading?: boolean; - - @property() private _saving: boolean; - - @property() private _errorMsg?: TemplateResult; - - private get _dialog(): HaPaperDialog { - return this.shadowRoot!.querySelector("ha-paper-dialog")!; - } - - private get _previewEl(): HuiCardPreview { - return this.shadowRoot!.querySelector("hui-card-preview")!; - } - - // tslint:disable-next-line - private __cardYaml: string | undefined; - - private get _cardYaml(): string | undefined { - if (!this.__cardYaml) { - this.__cardYaml = yaml.safeDump(this._cardConfig); - } - return this.__cardYaml; - } - - private set _cardYaml(yml: string | undefined) { - this.__cardYaml = yml; - } - - public constructor() { - super(); - this._saving = false; - } - - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); - - if (!changedProperties.has("cardConfig")) { - return; - } - - this._cardConfig = undefined; - this._cardYaml = undefined; - this._configState = "OK"; - this._uiEditor = true; - this._errorMsg = undefined; - this._configElement = undefined; - - this._loading = true; - this._loadConfigElement(this.cardConfig!); - } - - protected render(): TemplateResult | void { - let content; - let preview; - if (this._configElement !== undefined) { - content = html` -
- ${this._uiEditor - ? this._configElement - : html` - - `} -
- `; - - preview = html` - - `; - } - - return html` - -

- ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.header")} -

- - - ${this._errorMsg - ? html` -
${this._errorMsg}
- ` - : ""} -
${content}${preview}
-
- ${!this._loading - ? html` -
- ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_card.toggle_editor" - )} - ${this.hass!.localize("ui.common.cancel")} - - - ${this.hass!.localize("ui.common.save")} - -
- ` - : ""} -
- `; - } - - private async _loadedDialog(): Promise { - await this.updateComplete; - this._loading = false; - this._resizeDialog(); - if (!this._uiEditor) { - afterNextRender(() => { - this.yamlEditor.codemirror.refresh(); - this._resizeDialog(); - this.yamlEditor.codemirror.focus(); - }); - } - } - - private async _resizeDialog(): Promise { - await this.updateComplete; - fireEvent(this._dialog as HTMLElement, "iron-resize"); - } - - private async _save(): Promise { - if (!this._isConfigValid()) { - alert("Your config is not valid, please fix your config before saving."); - return; - } - - if (!this._isConfigChanged()) { - this.closeDialog!(); - return; - } - - this._saving = true; - - try { - await this.saveCard!(this._cardConfig!); - this._cardYaml = undefined; - this.closeDialog!(); - } catch (err) { - alert(`Saving failed: ${err.message}`); - } finally { - this._saving = false; - } - } - - private _handleYamlChanged(ev: CustomEvent): void { - try { - this._cardConfig = yaml.safeLoad(ev.detail.value); - this._updatePreview(this._cardConfig!); - this._configState = "OK"; - } catch (err) { - this._configState = "YAML_ERROR"; - this._setPreviewError({ - type: "YAML Error", - message: err, - }); - } - } - - private _handleUIConfigChanged(value: LovelaceCardConfig): void { - this._cardConfig = value; - this._updatePreview(value); - } - - private async _updatePreview(config: LovelaceCardConfig): Promise { - await this.updateComplete; - - if (!this._previewEl) { - return; - } - - this._previewEl.config = config; - - if (this._loading) { - this._loadedDialog(); - } else { - this._resizeDialog(); - } - } - - private _setPreviewError(error: ConfigError): void { - if (!this._previewEl) { - return; - } - this._previewEl.error = error; - - this._resizeDialog(); - } - - private async _toggleEditor(): Promise { - this._cardYaml = undefined; - if (this._uiEditor) { - this._uiEditor = false; - } else if (this._configElement) { - const success = await this._loadConfigElement(this._cardConfig!); - if (!success) { - this._loadedDialog(); - } else { - this._uiEditor = true; - this._configElement.setConfig(this._cardConfig!); - } - } - this._resizeDialog(); - } - - private _isConfigValid(): boolean { - if (!this._cardConfig) { - return false; - } - if (this._configState === "OK") { - return true; - } else { - return false; - } - } - - private _isConfigChanged(): boolean { - if (this.newCard) { - return true; - } - return JSON.stringify(this._cardConfig) !== JSON.stringify(this.cardConfig); - } - - private async _loadConfigElement(conf: LovelaceCardConfig): Promise { - if (!conf) { - return false; - } - - this._errorMsg = undefined; - this._loading = true; - this._configElement = undefined; - - const tag = getCardElementTag(conf.type); - - const elClass = customElements.get(tag); - let configElement; - - this._cardConfig = conf; - - if (elClass && elClass.getConfigElement) { - configElement = await elClass.getConfigElement(); - } else { - this._updatePreview(conf); - this._uiEditor = false; - this._configElement = null; - return false; - } - - try { - configElement.setConfig(conf); - } catch (err) { - this._errorMsg = html` - Your config is not supported by the UI editor:
${err.message}
Falling back to YAML editor. - `; - this._updatePreview(conf); - this._uiEditor = false; - this._configElement = null; - return false; - } - - configElement.hass = this.hass; - configElement.addEventListener("config-changed", (ev) => - this._handleUIConfigChanged(ev.detail.config) - ); - this._configElement = configElement; - await this.updateComplete; - this._updatePreview(conf); - return true; - } - - private _openedChanged(ev): void { - if (!ev.detail.value) { - this.closeDialog!(); - } - } - - private get yamlEditor(): HuiYamlEditor { - return this.shadowRoot!.querySelector("hui-yaml-editor")!; - } - - static get styles(): CSSResult[] { - return [ - haStyleDialog, - css` - :host { - --code-mirror-max-height: calc(100vh - 176px); - } - - @media all and (max-width: 450px), all and (max-height: 500px) { - /* overrule the ha-style-dialog max-height on small screens */ - ha-paper-dialog { - max-height: 100%; - height: 100%; - } - } - - @media all and (min-width: 660px) { - ha-paper-dialog { - width: 845px; - } - } - - ha-paper-dialog { - max-width: 845px; - } - - .center { - margin-left: auto; - margin-right: auto; - } - - .content { - display: flex; - flex-direction: column; - margin: 0 -10px; - } - .content hui-card-preview { - margin-top: 16px; - margin: 0 auto; - max-width: 390px; - } - .content .element-editor { - margin: 0 10px; - } - - @media (min-width: 1200px) { - ha-paper-dialog { - max-width: none; - width: 1000px; - } - - .content { - flex-direction: row; - } - .content > * { - flex-basis: 0; - flex-grow: 1; - flex-shrink: 1; - min-width: 0; - } - .content hui-card-preview { - padding-top: 0; - margin: 0 10px; - max-width: 490px; - } - } - - .margin-bot { - margin-bottom: 24px; - } - mwc-button paper-spinner { - width: 14px; - height: 14px; - margin-right: 20px; - } - paper-spinner { - display: none; - } - paper-spinner[active] { - display: block; - } - .hidden { - display: none; - } - .element-editor { - margin-bottom: 8px; - } - .error { - color: #ef5350; - border-bottom: 1px solid #ef5350; - } - hui-card-preview { - padding-top: 8px; - margin-bottom: 4px; - display: block; - } - .toggle-button { - margin-right: auto; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hui-edit-card": HuiEditCard; - } -} diff --git a/src/panels/lovelace/entity-rows/types.ts b/src/panels/lovelace/entity-rows/types.ts index eada7193b5..19ba7b134f 100644 --- a/src/panels/lovelace/entity-rows/types.ts +++ b/src/panels/lovelace/entity-rows/types.ts @@ -30,7 +30,7 @@ export interface CastConfig { type: "cast"; icon: string; name: string; - view: string; + view: string | number; // Hide the row if either unsupported browser or no API available. hide_if_unavailable: boolean; } diff --git a/src/panels/lovelace/hui-view.ts b/src/panels/lovelace/hui-view.ts index f70fec8818..ffba5b5331 100644 --- a/src/panels/lovelace/hui-view.ts +++ b/src/panels/lovelace/hui-view.ts @@ -184,6 +184,7 @@ export class HUIView extends LitElement { protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); + const hass = this.hass!; const lovelace = this.lovelace!; if (lovelace.editMode && !editCodeLoaded) { @@ -191,6 +192,7 @@ export class HUIView extends LitElement { import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable"); } + const hassChanged = changedProperties.has("hass"); let editModeChanged = false; let configChanged = false; @@ -205,21 +207,38 @@ export class HUIView extends LitElement { if (configChanged) { this._createBadges(lovelace.config.views[this.index!]); - } else if (changedProperties.has("hass")) { + } else if (hassChanged) { this._badges.forEach((badge) => { const { element, entityId } = badge; - element.hass = this.hass!; - element.state = this.hass!.states[entityId]; + element.hass = hass; + element.state = hass.states[entityId]; }); } if (configChanged || editModeChanged || changedProperties.has("columns")) { this._createCards(lovelace.config.views[this.index!]); - } else if (changedProperties.has("hass")) { + } else if (hassChanged) { this._cards.forEach((element) => { element.hass = this.hass; }); } + + const oldHass = changedProperties.get("hass") as this["hass"] | undefined; + + if ( + configChanged || + editModeChanged || + (hassChanged && + oldHass && + (hass.themes !== oldHass.themes || + hass.selectedTheme !== oldHass.selectedTheme)) + ) { + applyThemesOnElement( + this, + hass.themes, + lovelace.config.views[this.index!].theme + ); + } } private _addCard(): void { @@ -311,8 +330,6 @@ export class HUIView extends LitElement { }); this._cards = elements; - - applyThemesOnElement(root, this.hass!.themes, config.theme); } private _rebuildCard( diff --git a/src/panels/lovelace/special-rows/hui-cast-row.ts b/src/panels/lovelace/special-rows/hui-cast-row.ts index 02034f8bc3..a71ae295fc 100644 --- a/src/panels/lovelace/special-rows/hui-cast-row.ts +++ b/src/panels/lovelace/special-rows/hui-cast-row.ts @@ -23,11 +23,13 @@ class HuiCastRow extends LitElement implements EntityRow { public hass!: HomeAssistant; @property() private _config?: CastConfig; + @property() private _castManager?: CastManager | null; + @property() private _noHTTPS = false; public setConfig(config: CastConfig): void { - if (!config || !config.view) { + if (!config || config.view === undefined || config.view === null) { throw new Error("Invalid Configuration: 'view' required"); } @@ -66,6 +68,8 @@ class HuiCastRow extends LitElement implements EntityRow { SHOW @@ -120,6 +124,7 @@ class HuiCastRow extends LitElement implements EntityRow { :host { display: flex; align-items: center; + overflow: visible; } ha-icon { padding: 8px; @@ -127,7 +132,6 @@ class HuiCastRow extends LitElement implements EntityRow { } .flex { flex: 1; - overflow: hidden; margin-left: 16px; display: flex; justify-content: space-between; @@ -144,6 +148,7 @@ class HuiCastRow extends LitElement implements EntityRow { align-items: center; } google-cast-launcher { + margin-right: 0.57em; cursor: pointer; display: inline-block; height: 24px; diff --git a/src/panels/profile/ha-mfa-module-setup-flow.js b/src/panels/profile/ha-mfa-module-setup-flow.js index 8f9081fcca..8139c87e3f 100644 --- a/src/panels/profile/ha-mfa-module-setup-flow.js +++ b/src/panels/profile/ha-mfa-module-setup-flow.js @@ -91,7 +91,6 @@ class HaMfaModuleSetupFlow extends LocalizeMixin(EventsMixin(PolymerElement)) { > diff --git a/src/panels/profile/ha-panel-profile.js b/src/panels/profile/ha-panel-profile.js deleted file mode 100644 index dfd2a3f6c0..0000000000 --- a/src/panels/profile/ha-panel-profile.js +++ /dev/null @@ -1,193 +0,0 @@ -import "@polymer/app-layout/app-header-layout/app-header-layout"; -import "@polymer/app-layout/app-header/app-header"; -import "@polymer/paper-item/paper-item-body"; -import "@polymer/paper-item/paper-item"; -import "@material/mwc-button"; -import "@polymer/app-layout/app-toolbar/app-toolbar"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../../components/ha-card"; -import "../../components/ha-menu-button"; -import "../../resources/ha-style"; - -import { getOptimisticFrontendUserDataCollection } from "../../data/frontend"; - -import { EventsMixin } from "../../mixins/events-mixin"; -import LocalizeMixin from "../../mixins/localize-mixin"; - -import "./ha-change-password-card"; -import "./ha-mfa-modules-card"; -import "./ha-advanced-mode-card"; -import "./ha-refresh-tokens-card"; -import "./ha-long-lived-access-tokens-card"; - -import "./ha-pick-language-row"; -import "./ha-pick-theme-row"; -import "./ha-push-notifications-row"; -import "./ha-force-narrow-row"; - -/* - * @appliesMixin EventsMixin - * @appliesMixin LocalizeMixin - */ -class HaPanelProfile extends EventsMixin(LocalizeMixin(PolymerElement)) { - static get template() { - return html` - - - - - - -
[[localize('panel.profile')]]
-
-
- -
- -
- [[localize('ui.panel.profile.current_user', 'fullName', - hass.user.name)]] - -
- - - - - - - - -
- [[localize('ui.panel.profile.logout')]] -
-
- - - - - - - - - - -
-
- `; - } - - static get properties() { - return { - hass: Object, - narrow: Boolean, - _refreshTokens: Array, - _coreUserData: Object, - }; - } - - connectedCallback() { - super.connectedCallback(); - this._refreshRefreshTokens(); - this._unsubCoreData = getOptimisticFrontendUserDataCollection( - this.hass.connection, - "core" - ).subscribe((coreUserData) => { - this._coreUserData = coreUserData; - }); - } - - disconnectedCallback() { - super.disconnectedCallback(); - if (this._unsubCoreData) { - this._unsubCoreData(); - this._unsubCoreData = undefined; - } - } - - async _refreshRefreshTokens() { - this._refreshTokens = await this.hass.callWS({ - type: "auth/refresh_tokens", - }); - } - - _handleLogOut() { - this.fire("hass-logout"); - } - - _canChangePassword(user) { - return user.credentials.some( - (cred) => cred.auth_provider_type === "homeassistant" - ); - } - - _isAdmin(user) { - return user.is_admin; - } - - _showNarrowRow(dockedSidebar, narrow) { - return dockedSidebar === "auto" ? !narrow : true; - } -} - -customElements.define("ha-panel-profile", HaPanelProfile); diff --git a/src/panels/profile/ha-panel-profile.ts b/src/panels/profile/ha-panel-profile.ts new file mode 100644 index 0000000000..2bdc22955e --- /dev/null +++ b/src/panels/profile/ha-panel-profile.ts @@ -0,0 +1,200 @@ +import "@polymer/app-layout/app-header-layout/app-header-layout"; +import "@polymer/app-layout/app-header/app-header"; +import "@polymer/paper-item/paper-item-body"; +import "@polymer/paper-item/paper-item"; +import "@material/mwc-button"; +import "@polymer/app-layout/app-toolbar/app-toolbar"; + +import "../../components/ha-card"; +import "../../components/ha-menu-button"; +import "../../resources/ha-style"; + +import { + getOptimisticFrontendUserDataCollection, + CoreFrontendUserData, +} from "../../data/frontend"; + +import "./ha-change-password-card"; +import "./ha-mfa-modules-card"; +import "./ha-advanced-mode-card"; +import "./ha-refresh-tokens-card"; +import "./ha-long-lived-access-tokens-card"; + +import "./ha-pick-language-row"; +import "./ha-pick-theme-row"; +import "./ha-push-notifications-row"; +import "./ha-force-narrow-row"; +import { + LitElement, + TemplateResult, + html, + CSSResultArray, + css, + property, +} from "lit-element"; +import { haStyle } from "../../resources/styles"; +import { HomeAssistant } from "../../types"; +import { fireEvent } from "../../common/dom/fire_event"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; + +class HaPanelProfile extends LitElement { + @property() public hass!: HomeAssistant; + @property() public narrow!: boolean; + @property() private _refreshTokens?: unknown[]; + @property() private _coreUserData?: CoreFrontendUserData | null; + private _unsubCoreData?: UnsubscribeFunc; + + public connectedCallback() { + super.connectedCallback(); + this._refreshRefreshTokens(); + this._unsubCoreData = getOptimisticFrontendUserDataCollection( + this.hass.connection, + "core" + ).subscribe((coreUserData) => { + this._coreUserData = coreUserData; + }); + } + + public disconnectedCallback() { + super.disconnectedCallback(); + if (this._unsubCoreData) { + this._unsubCoreData(); + this._unsubCoreData = undefined; + } + } + + protected render(): TemplateResult | void { + return html` + + + + +
${this.hass.localize("panel.profile")}
+
+
+ +
+ +
+ ${this.hass.localize( + "ui.panel.profile.current_user", + "fullName", + this.hass.user!.name + )} + ${this.hass.user!.is_owner + ? this.hass.localize("ui.panel.profile.is_owner") + : ""} +
+ + + + ${this.hass.dockedSidebar !== "auto" || !this.narrow + ? html` + + ` + : ""} + + +
+ + ${this.hass.localize("ui.panel.profile.logout")} + +
+
+ + ${this.hass.user!.credentials.some( + (cred) => cred.auth_provider_type === "homeassistant" + ) + ? html` + + ` + : ""} + + + + ${this.hass.user!.is_admin + ? html` + + ` + : ""} + + + + +
+
+ `; + } + + private async _refreshRefreshTokens() { + this._refreshTokens = await this.hass.callWS({ + type: "auth/refresh_tokens", + }); + } + + private _handleLogOut() { + fireEvent(this, "hass-logout"); + } + + static get styles(): CSSResultArray { + return [ + haStyle, + css` + :host { + -ms-user-select: initial; + -webkit-user-select: initial; + -moz-user-select: initial; + } + + .content { + display: block; + max-width: 600px; + margin: 0 auto; + } + + .content > * { + display: block; + margin: 24px 0; + } + + .promo-advanced { + text-align: center; + color: var(--secondary-text-color); + } + `, + ]; + } +} + +customElements.define("ha-panel-profile", HaPanelProfile); diff --git a/src/translations/en.json b/src/translations/en.json index 611cbedfc2..5bf46057d8 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -620,7 +620,8 @@ "core": "Reload core", "group": "Reload groups", "automation": "Reload automations", - "script": "Reload scripts" + "script": "Reload scripts", + "scene": "Reload scenes" }, "server_management": { "heading": "Server management", diff --git a/translations/af.json b/translations/af.json index f82a3831f3..acb4546466 100644 --- a/translations/af.json +++ b/translations/af.json @@ -624,6 +624,9 @@ }, "values": { "header": "Knooppuntwaardes" + }, + "node_config": { + "set_config_parameter": "Stel Config-parameter in" } }, "users": { diff --git a/translations/ar.json b/translations/ar.json index abf1f463b7..6693680118 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -536,7 +536,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "إدارة شبكة Z-Wave" + "description": "إدارة شبكة Z-Wave", + "node_config": { + "set_config_parameter": "تعيين معلمة التكوين" + } }, "users": { "caption": "المستخدمين", diff --git a/translations/bg.json b/translations/bg.json index c8b2aeaa5f..f9cf622f13 100644 --- a/translations/bg.json +++ b/translations/bg.json @@ -624,6 +624,9 @@ }, "values": { "header": "Стойности на устройсто" + }, + "node_config": { + "set_config_parameter": "Задайте параметър Config" } }, "users": { diff --git a/translations/bs.json b/translations/bs.json index 3e35cd6da1..8c11d0de8a 100644 --- a/translations/bs.json +++ b/translations/bs.json @@ -273,7 +273,10 @@ }, "config": { "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "Podesite parametar Config" + } } } }, diff --git a/translations/cs.json b/translations/cs.json index 8f7c5cc2a7..251fcd04f3 100644 --- a/translations/cs.json +++ b/translations/cs.json @@ -351,7 +351,7 @@ "header": "Konfigurace a správa serveru", "introduction": "Moc dobře víme, že změna konfigurace může být velmi únavným procesem. Tato sekce se proto pokusí udělat váš život alespoň trochu jednodušší.", "core_config": { - "edit_requires_storage": "Editori pois käytöstä, koska asetukset on määritelty configuration.yaml:ssä", + "edit_requires_storage": "Editor je zakázán, protože konfigurace je uložena v configuration.yaml.", "location_name": "Název instalace Home Assistant", "latitude": "Zeměpisná šířka", "longitude": "Zeměpisná délka", @@ -588,7 +588,18 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Spravujte svou síť Z-Wave" + "description": "Spravujte svou síť Z-Wave", + "services": { + "test_network": "Testovat síť", + "save_config": "Uložit konfiguraci" + }, + "common": { + "unknown": "neznámý" + }, + "node_config": { + "seconds": "sekund", + "set_config_parameter": "Nastavte konfigurační parametr" + } }, "users": { "caption": "Uživatelé", @@ -711,6 +722,25 @@ "device_tracker_picked": "Sledovat zařízení", "device_tracker_pick": "Vyberte zařízení, které chcete sledovat" } + }, + "server_control": { + "section": { + "validation": { + "check_config": "Zkontrolujte konfiguraci", + "valid": "Konfigurace je v pořádku!", + "invalid": "Konfigurace není v pořádku!" + }, + "reloading": { + "heading": "Konfigurace se načítá", + "core": "Znovu načíst jádro", + "group": "Znovu načíst skupiny", + "automation": "Znovu načíst automatizace", + "script": "Znovu načíst skripty" + }, + "server_management": { + "heading": "Správa serveru" + } + } } }, "profile": { diff --git a/translations/cy.json b/translations/cy.json index a0dc27319f..a5878c0a9a 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -575,7 +575,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Rheoli eich rhwydwaith Z-Wave" + "description": "Rheoli eich rhwydwaith Z-Wave", + "node_config": { + "set_config_parameter": "Gosod Paramedr Ffurfweddu" + } }, "cloud": { "description_login": "Wedi mewngofnodi fel {email}", diff --git a/translations/de.json b/translations/de.json index 980d38c6c0..db99b48dae 100644 --- a/translations/de.json +++ b/translations/de.json @@ -320,7 +320,7 @@ "title": "Ereignisse" }, "templates": { - "title": "Templates" + "title": "Vorlage" }, "mqtt": { "title": "MQTT" @@ -349,10 +349,10 @@ "introduction": "Hier ist es möglich, deine Komponenten und Home Assistant zu konfigurieren. Noch ist nicht alles über die GUI einstellbar, aber wir arbeiten daran.", "core": { "caption": "Allgemein", - "description": "Überprüfe deine Konfigurationsdatei und steuere den Server", + "description": "Bearbeite die allgemeine Konfiguration von Home Assistant", "section": { "core": { - "header": "Einstellungen und Serversteuerung", + "header": "Allgemeine Einstellungen", "introduction": "Die Konfiguration zu ändern ist ein mühsamer Prozess. Das wissen wir. Dieser Bereich versucht dir das Leben etwas leichter zu gestalten.", "core_config": { "edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.", @@ -602,7 +602,7 @@ "network_starting": "Z-Wave Netzwerk wird gestartet ...", "network_starting_note": "Dies kann je nach Größe des Netzwerks eine Weile dauern.", "network_started": "Z-Wave Netzwerk gestartet", - "network_started_note_some_queried": "Wache Knoten wurden abgefragt. Schlafende knoten werden abgefragt wenn sie aufwachen.", + "network_started_note_some_queried": "Aktive Knoten wurden abgefragt. Schlafende Knoten werden abgefragt, sobald sie aktiv werden.", "network_started_note_all_queried": "Alle Knoten wurden abgefragt." }, "services": { @@ -620,10 +620,22 @@ "common": { "value": "Wert", "instance": "Instanz", - "index": "Index" + "index": "Index", + "unknown": "Unbekannt", + "wakeup_interval": "Aufwachintervall" }, "values": { "header": "Knotenwerte" + }, + "node_config": { + "header": "Knotenkonfiguration", + "seconds": "Sekunden", + "set_wakeup": "Aufwachintervall einrichten", + "config_parameter": "Konfigurationsparameter", + "config_value": "Konfigurationswert", + "true": "Richtig", + "false": "Falsch", + "set_config_parameter": "Konfiguration speichern" } }, "users": { @@ -750,18 +762,18 @@ }, "server_control": { "caption": "Serversteuerung", - "description": "Neustarten und Stoppen des Home Assistant-Servers", + "description": "Neustarten und Stoppen des Home Assistant Servers", "section": { "validation": { "heading": "Konfiguration überprüfen", - "introduction": "Überprüfe deine Konfiguration wenn du kürzlich Änderungen vorgenommen hast und sicherstellen möchtest, dass alle Änderungen gültig sind", + "introduction": "Überprüfe deine Konfiguration, wenn du kürzlich Änderungen vorgenommen hast und sicherstellen möchtest, dass alle Änderungen gültig sind", "check_config": "Konfiguration prüfen", "valid": "Konfiguration in Ordnung", "invalid": "Konfiguration ungültig" }, "reloading": { "heading": "Konfiguration neu laden", - "introduction": "Einige Komponenten von Home Assistant können ohne einen Neustart neu geladen werden. \"Neu laden\" entlädt dabei die aktuelle Konfiguration und lädt die Neue.", + "introduction": "Einige Komponenten von Home Assistant können ohne einen Neustart neu geladen werden. \"Neu laden\" entlädt dabei die aktuelle Konfiguration und lädt die neue Konfiguration.", "core": "Hauptsystem neu laden", "group": "Gruppen neu laden", "automation": "Automatisierungen neu laden", @@ -1358,7 +1370,7 @@ "away": "Abwesend", "boost": "Maximal", "comfort": "Komfort", - "home": "Zuhause", + "home": "Zu Hause", "sleep": "Schlafen", "activity": "Aktivität" }, diff --git a/translations/el.json b/translations/el.json index dec7feffb0..f1070e0c07 100644 --- a/translations/el.json +++ b/translations/el.json @@ -588,7 +588,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Διαχειριστείτε το δίκτυο Z-Wave" + "description": "Διαχειριστείτε το δίκτυο Z-Wave", + "node_config": { + "set_config_parameter": "Ορίστε την παράμετρο διαμόρφωσης" + } }, "users": { "caption": "Χρήστες", diff --git a/translations/es-419.json b/translations/es-419.json index b624043637..adcd4e960f 100644 --- a/translations/es-419.json +++ b/translations/es-419.json @@ -588,7 +588,10 @@ }, "zwave": { "caption": "", - "description": "Administrar su red Z-Wave" + "description": "Administrar su red Z-Wave", + "node_config": { + "set_config_parameter": "Establecer parámetro de configuración" + } }, "users": { "caption": "Usuarios", diff --git a/translations/es.json b/translations/es.json index 8633b2f60d..aee3f14b92 100644 --- a/translations/es.json +++ b/translations/es.json @@ -349,7 +349,7 @@ "introduction": "Aquí puedes configurar tus componentes y Home Assistant. Aún no es posible configurar todo desde la interfaz de usuario, pero estamos trabajando en ello.", "core": { "caption": "Configuración general", - "description": "Valida tu archivo de configuración y controla el servidor", + "description": "Cambiar la configuración general de Home Assistant", "section": { "core": { "header": "Configuración y control del servidor", @@ -620,10 +620,22 @@ "common": { "value": "Valor", "instance": "Instancia", - "index": "Índice" + "index": "Índice", + "unknown": "Desconocido", + "wakeup_interval": "Intervalo de activación" }, "values": { "header": "Valores del nodo" + }, + "node_config": { + "header": "Opciones de configuración de nodo", + "seconds": "segundos", + "set_wakeup": "Configurar el intervalo de activación", + "config_parameter": "Parámetro de configuración", + "config_value": "Valor de configuración", + "true": "Cierto", + "false": "Falso", + "set_config_parameter": "Establecer parámetro de configuración" } }, "users": { diff --git a/translations/et.json b/translations/et.json index 469040dc40..590f5f3d78 100644 --- a/translations/et.json +++ b/translations/et.json @@ -583,7 +583,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Halda oma Z-Wave võrku" + "description": "Halda oma Z-Wave võrku", + "node_config": { + "set_config_parameter": "Seadista parameeter Config" + } }, "users": { "caption": "Kasutajad", diff --git a/translations/eu.json b/translations/eu.json index ee64e427eb..21cc5e4165 100644 --- a/translations/eu.json +++ b/translations/eu.json @@ -299,7 +299,10 @@ "description": "Scriptak sortu eta editatu" }, "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "Ezarri konfigurazio-parametroa" + } }, "automation": { "picker": { diff --git a/translations/fa.json b/translations/fa.json index 5501be4934..aa3b1c3810 100644 --- a/translations/fa.json +++ b/translations/fa.json @@ -522,7 +522,10 @@ } }, "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "تنظیم پارامتر تنظیم کنید" + } }, "users": { "caption": "کاربران", diff --git a/translations/fi.json b/translations/fi.json index 600a72583a..fdeaba1cc3 100644 --- a/translations/fi.json +++ b/translations/fi.json @@ -594,6 +594,9 @@ "test_network": "Testaa verkkoyhteys", "save_config": "Tallenna asetukset", "cancel_command": "Peruuta komento" + }, + "node_config": { + "set_config_parameter": "Aseta asetusparametri" } }, "users": { @@ -1263,7 +1266,7 @@ "notify": "Ilmoita", "plant": "Kasvi", "proximity": "Läheisyys", - "remote": "Etä", + "remote": "Kauko-ohjaus", "scene": "Skene", "script": "Skripti", "sensor": "Sensori", diff --git a/translations/fr.json b/translations/fr.json index bfd060bf1f..cd9cb58d63 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -160,7 +160,7 @@ "not_home": "Absent" }, "fan": { - "off": "Arrêt", + "off": "Éteint", "on": "Marche" }, "group": { @@ -179,7 +179,7 @@ "problem": "Problème" }, "input_boolean": { - "off": "Arrêt", + "off": "Arrêté", "on": "Marche" }, "light": { @@ -191,7 +191,7 @@ "unlocked": "Déverrouillé" }, "media_player": { - "off": "Arrêt", + "off": "Éteint", "on": "Marche", "playing": "Lecture en cours", "paused": "En pause", @@ -594,13 +594,15 @@ "caption": "Z-Wave", "description": "Gérez votre réseau Z-Wave", "network_management": { - "header": "Gestion de réseau Z-Wave" + "header": "Gestion de réseau Z-Wave", + "introduction": "Exécutez les commandes qui affectent le réseau Z-Wave. Vous ne saurez pas si la plupart des commandes ont réussi, mais vous pouvez consulter le journal OZW pour essayer de le savoir." }, "network_status": { "network_stopped": "Réseau Z-Wave arrêté", "network_starting": "Démarrage du réseau Z-Wave...", "network_starting_note": "Ceci peut prendre un certain temps en fonction du débit de votre réseau.", "network_started": "Le réseau Z-Wave a été démarré", + "network_started_note_some_queried": "Les nœuds éveillés ont été interrogés. Les nœuds en veille seront interrogés à leur réveil.", "network_started_note_all_queried": "Tous les nœuds ont été interrogés." }, "services": { @@ -608,6 +610,7 @@ "stop_network": "Arrêter le réseau", "heal_network": "Soigner le réseau", "test_network": "Tester le réseau", + "soft_reset": "Redémarrage", "save_config": "Enregistrer la configuration", "add_node_secure": "Ajouter un nœud sécurisé", "add_node": "Ajouter un nœud", @@ -617,10 +620,22 @@ "common": { "value": "Valeur", "instance": "Instance", - "index": "Indice" + "index": "Indice", + "unknown": "Inconnu", + "wakeup_interval": "Intervalle de réveil" }, "values": { "header": "Valeurs des nœuds" + }, + "node_config": { + "header": "Options de configuration du nœud", + "seconds": "Secondes", + "set_wakeup": "Définir l'intervalle de réveil", + "config_parameter": "Paramètre de configuration", + "config_value": "Valeur de configuration", + "true": "Vrai", + "false": "Faux", + "set_config_parameter": "Définir le paramètre de configuration" } }, "users": { @@ -746,15 +761,19 @@ } }, "server_control": { + "caption": "Contrôle du serveur", + "description": "Redémarrez et arrêtez le serveur Home Assistant", "section": { "validation": { "heading": "Validation de la configuration", + "introduction": "Validez votre configuration si vous l'avez récemment modifiée et que vous voulez vous assurer que tout est valide", "check_config": "Vérifiez la configuration", "valid": "Configuration valide !", "invalid": "Configuration invalide" }, "reloading": { "heading": "Rechargement de la configuration", + "introduction": "Certaines parties de Home Assistant peuvent être rechargées sans nécessiter un redémarrage. Appuyer sur \"recharger\" déchargera leur configuration actuelle et chargera la nouvelle.", "core": "Recharger le noyau", "group": "Recharger les groupes", "automation": "Recharger les automatisations", @@ -762,6 +781,7 @@ }, "server_management": { "heading": "Gestion du serveur", + "introduction": "Contrôlez votre serveur Home Assistant ... depuis Home Assistant.", "restart": "Redémarrer", "stop": "Arrêter" } @@ -839,7 +859,8 @@ }, "logout": "Déconnexion", "force_narrow": { - "header": "Toujours cacher la barre latérale" + "header": "Toujours cacher la barre latérale", + "description": "Cela masquera la barre latérale par défaut, semblable à l'expérience mobile." } }, "page-authorize": { @@ -1257,7 +1278,7 @@ "dialogs": { "more_info_settings": { "save": "Sauvegarder", - "name": "Surcharge du nom", + "name": "Outrepasser le nom", "entity_id": "ID de l'entité" }, "more_info_control": { diff --git a/translations/he.json b/translations/he.json index fec5bb97dc..18cd5d43b3 100644 --- a/translations/he.json +++ b/translations/he.json @@ -141,7 +141,8 @@ "high_demand": "ביקוש גבוה", "heat_pump": "משאבת חום", "gas": "גז", - "manual": "מדריך ל" + "manual": "מדריך ל", + "heat_cool": "חימום\/קירור" }, "configurator": { "configure": "הגדר", @@ -323,6 +324,9 @@ }, "mqtt": { "title": "MQTT" + }, + "info": { + "title": "מידע" } } }, @@ -588,7 +592,51 @@ }, "zwave": { "caption": "Z-Wave", - "description": "נהל את רשת ה- Z-Wave שלך" + "description": "נהל את רשת ה- Z-Wave שלך", + "network_management": { + "header": "ניהול רשת ה Z-Wave", + "introduction": "הפעל פקודות המשפיעות על רשת ה-Z Wave. לא תקבל משוב אם רוב הפקודות הצליחו, אך באפשרותך לבדוק את יומן ה-OZW כדי לנסות לגלות." + }, + "network_status": { + "network_stopped": "רשת ה Z-Wave נעצרה", + "network_starting": "מפעיל את רשת ה Z-Wave", + "network_starting_note": "הדבר עשוי להימשך זמן מה בהתאם לגודל הרשת.", + "network_started": "רשת ה Z-Wave הופעלה", + "network_started_note_some_queried": "רכיבים דלוקים נבדקו. רכיבים כבויים יבדקו כאשר ידלקו.", + "network_started_note_all_queried": "כל הרכיבים נבדקו" + }, + "services": { + "start_network": "הפעל רשת", + "stop_network": "עצור רשת", + "heal_network": "ריפוי רשת", + "test_network": "בדיקת רשת", + "soft_reset": "איפוס רך", + "save_config": "שמור קונפיגורציה", + "add_node_secure": "הוסף רכיב מאובטח", + "add_node": "הוסף רכיב", + "remove_node": "הסר רכיב", + "cancel_command": "ביטול פקודה" + }, + "common": { + "value": "ערך תצורה", + "instance": "פרמטר", + "index": "אינדקס", + "unknown": "לא ידוע", + "wakeup_interval": "מרווח פעולה" + }, + "values": { + "header": "ערכים" + }, + "node_config": { + "header": "עריכת קונפיגורציה", + "seconds": "שניות", + "set_wakeup": "בחירת מרווח פעולה", + "config_parameter": "פרמטר תצורה", + "config_value": "ערך תצורה", + "true": "True", + "false": "False", + "set_config_parameter": "הגדר פרמטר Config" + } }, "users": { "caption": "משתמשים", @@ -667,7 +715,7 @@ }, "area_registry": { "caption": "מאגר האזורים", - "description": "סקירה של כל האזורים בביתך.", + "description": "סקירה של כל האזורים בביתך", "picker": { "header": "מאגר האזורים", "introduction": "אזורים משמשים לארגון המיקום של ההתקנים. Home Assistant יעשה שימוש במידע זה בכדי לסייע לך בארגון הממשק, ההרשאות והאינטגרציות שלך עם מערכות אחרות.", @@ -711,6 +759,33 @@ "device_tracker_picked": "עקוב אחר מכשיר", "device_tracker_pick": "בחר מכשיר למעקב" } + }, + "server_control": { + "caption": "בקרת שרת", + "description": "שליטה על שרת ה Home Assistant", + "section": { + "validation": { + "heading": "בדיקת הקונפיגורציה", + "introduction": "אמת את הקונפיגורציה שלך אם ביצעת לאחרונה שינויים מסוימים וברצונך לוודא שהיא תקינה", + "check_config": "בדיקת הקונפיגורציה", + "valid": "קונפיגורציה תקינה!", + "invalid": "קונפיגורציה לא תקנית" + }, + "reloading": { + "heading": "טען מחדש קונפיגורציה", + "introduction": "חלקים מסוימים של Home Assistant יכולים להטען מחדש ללא צורך בהפעלה מחדש.\nטעינה מחדש תשנה את הקונפיגורציה הנוכחית ותטען קונפיגורציה חדשה.", + "core": "טען מחדש את הליבה", + "group": "טען מחדש קבוצות", + "automation": "טען מחדש אוטומציות", + "script": "טען מחדש סקריפטים" + }, + "server_management": { + "heading": "ניהול שרת", + "introduction": "לשלוט על שרת הHome Assistant שלך... מHome Assistant.", + "restart": "אתחול", + "stop": "עצור" + } + } } }, "profile": { @@ -781,6 +856,11 @@ "step_done": "הגדרה בוצעה עבור {step}", "close": "סגור", "submit": "שלח" + }, + "logout": "התנתק", + "force_narrow": { + "header": "הסתר תמיד את הסרגל הצדדי", + "description": "פעולה זו תסתיר את הסרגל הצדדי כברירת מחדל, בדומה לחוויה בנייד." } }, "page-authorize": { @@ -1137,7 +1217,8 @@ "fan_mode": "מצב מאורר", "swing_mode": "מצב נדנוד", "away_mode": "מצב מחוץ לבית", - "aux_heat": "מסייע חום" + "aux_heat": "מסייע חום", + "preset_mode": "מצב מוגדר" }, "lock": { "code": "קוד", @@ -1282,6 +1363,24 @@ "off": "כבוי", "on": "דולק", "auto": "Auto" + }, + "preset_mode": { + "none": "לא נבחר", + "eco": "חסכון", + "away": "לא בבית", + "boost": "מוגבר", + "comfort": "נוחות", + "home": "בבית", + "sleep": "שינה", + "activity": "פעילות" + }, + "hvac_action": { + "off": "כבוי", + "heating": "חימום", + "cooling": "קירור", + "drying": "מייבש", + "idle": "כבוי", + "fan": "מאוורר" } } }, diff --git a/translations/hi.json b/translations/hi.json index 35182fea34..c07e46a548 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -132,7 +132,10 @@ }, "config": { "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "कॉन्फ़िगरेशन पैरामीटर सेट करें" + } }, "automation": { "editor": { diff --git a/translations/hr.json b/translations/hr.json index e9353c4116..d11a04e80f 100644 --- a/translations/hr.json +++ b/translations/hr.json @@ -515,7 +515,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Upravljajte mrežom Z-Wave" + "description": "Upravljajte mrežom Z-Wave", + "node_config": { + "set_config_parameter": "Postavite parametar Config" + } }, "users": { "caption": "Korisnici", diff --git a/translations/id.json b/translations/id.json index ead891769d..3abe79957d 100644 --- a/translations/id.json +++ b/translations/id.json @@ -562,7 +562,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Kelola jaringan Z-Wave anda" + "description": "Kelola jaringan Z-Wave anda", + "node_config": { + "set_config_parameter": "Setel Parameter Konfigurasi" + } }, "users": { "caption": "Pengguna", diff --git a/translations/is.json b/translations/is.json index d083116b93..d8b88fff08 100644 --- a/translations/is.json +++ b/translations/is.json @@ -562,7 +562,8 @@ "cancel_command": "Hætta við skipun" }, "node_config": { - "seconds": "sekúndur" + "seconds": "sekúndur", + "set_config_parameter": "Stilltu Config Parameter" } }, "users": { diff --git a/translations/it.json b/translations/it.json index 4e9d85df5c..d7b0431e1d 100644 --- a/translations/it.json +++ b/translations/it.json @@ -324,6 +324,9 @@ }, "mqtt": { "title": "MQTT" + }, + "info": { + "title": "Info" } } }, @@ -590,9 +593,49 @@ "zwave": { "caption": "Z-Wave", "description": "Gestisci la tua rete Z-Wave", + "network_management": { + "header": "Gestione della rete Z-Wave", + "introduction": "Eseguire comandi che interessano la rete Z-Wave. Non otterrete un feedback sul successo della maggior parte dei comandi, ma potete controllare il Log OZW per cercare di scoprirlo." + }, "network_status": { + "network_stopped": "Rete Z-Wave arrestata", "network_starting": "Inizializzazione della rete Z-Wave...", - "network_started": "Rete Z-Wave inizializzata" + "network_starting_note": "Questo potrebbe richiedere del tempo a seconda delle dimensioni della tua rete.", + "network_started": "Rete Z-Wave inizializzata", + "network_started_note_some_queried": "Sono stati interrogati i nodi attivi. I nodi dormienti verranno interrogati quando si attiveranno.", + "network_started_note_all_queried": "Tutti i nodi sono stati interrogati." + }, + "services": { + "start_network": "Avvia la rete", + "stop_network": "Ferma la rete", + "heal_network": "Testa la rete", + "test_network": "Testa la rete", + "soft_reset": "Soft Reset", + "save_config": "Salva configurazione", + "add_node_secure": "Aggiungi nodo sicuro", + "add_node": "Aggiungi Nodo", + "remove_node": "Rimuovi nodo", + "cancel_command": "Annulla Comando" + }, + "common": { + "value": "Valore", + "instance": "Esempio", + "index": "Indice", + "unknown": "sconosciuto", + "wakeup_interval": "Intervallo di sveglia" + }, + "values": { + "header": "Valori del nodo" + }, + "node_config": { + "header": "Opzioni di configurazione del nodo", + "seconds": "secondi", + "set_wakeup": "Imposta intervallo di riattivazione", + "config_parameter": "Parametro di configurazione", + "config_value": "Valore di configurazione", + "true": "Vero", + "false": "False", + "set_config_parameter": "Imposta parametro di configurazione" } }, "users": { @@ -716,6 +759,33 @@ "device_tracker_picked": "Traccia dispositivo", "device_tracker_pick": "Scegli il dispositivo da tracciare" } + }, + "server_control": { + "caption": "Gestione del server", + "description": "Riavviare e arrestare il server Home Assistant", + "section": { + "validation": { + "heading": "Convalida della configurazione", + "introduction": "Convalidare la configurazione se di recente sono state apportate alcune modifiche alla configurazione e si desidera assicurarsi che sia tutto valido", + "check_config": "Controlla la configurazione", + "valid": "Configurazione valida!", + "invalid": "Configurazione non valida" + }, + "reloading": { + "heading": "Ricaricamento della configurazione", + "introduction": "Alcune parti di Home Assistant possono essere ricaricate senza richiedere il riavvio. Cliccando su ricarica si rimuoverà la loro configurazione corrente e si caricherà quella nuova.", + "core": "Ricarica core", + "group": "Ricarica i gruppi", + "automation": "Ricarica automazioni", + "script": "Ricarica script" + }, + "server_management": { + "heading": "Gestione del server", + "introduction": "Controllare il server Home Assistant... da Home Assistant.", + "restart": "Riavviare", + "stop": "Stop" + } + } } }, "profile": { @@ -1147,7 +1217,8 @@ "fan_mode": "Ventilazione", "swing_mode": "Modo oscillazione", "away_mode": "Modalità Assente", - "aux_heat": "Riscaldamento ausiliario" + "aux_heat": "Riscaldamento ausiliario", + "preset_mode": "Preset" }, "lock": { "code": "Codice", @@ -1296,6 +1367,8 @@ "preset_mode": { "none": "Nessuna", "eco": "Eco", + "away": "Fuori Casa", + "boost": "Boost", "comfort": "Comfort", "home": "Casa", "sleep": "Sleep", @@ -1303,6 +1376,7 @@ }, "hvac_action": { "off": "Spento", + "heating": "Riscaldamento", "cooling": "Raffreddamento", "drying": "Asciugatura", "idle": "Inattivo", diff --git a/translations/ja.json b/translations/ja.json index e75dc0f5da..f630a3380a 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -322,7 +322,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Z-waveネットワークを管理します" + "description": "Z-waveネットワークを管理します", + "node_config": { + "set_config_parameter": "構成パラメーターの設定" + } }, "users": { "caption": "ユーザー", diff --git a/translations/ko.json b/translations/ko.json index e2b729e13a..32011d7e7b 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -602,7 +602,7 @@ "network_starting": "Z-Wave 네트워크 시작 중...", "network_starting_note": "네트워크 규모에 따라 다소 시간이 걸릴 수 있습니다.", "network_started": "Z-Wave 네트워크 시작됨", - "network_started_note_some_queried": "절전 모드 해제 노드가 쿼리되었습니다. 절전 노드는 절전 모드 해제 시 쿼리됩니다.", + "network_started_note_some_queried": "절전모드 해제 노드가 쿼리되었습니다. 절전모드 노드는 절전모드 해제 상태일 때 쿼리됩니다.", "network_started_note_all_queried": "모든 노드가 쿼리되었습니다." }, "services": { @@ -621,8 +621,8 @@ "value": "값", "instance": "인스턴스", "index": "색인", - "unknown": "알 수 없슴", - "wakeup_interval": "절전 모드 해제 간격" + "unknown": "알 수 없음", + "wakeup_interval": "절전모드 해제 간격" }, "values": { "header": "노드 값" @@ -630,7 +630,7 @@ "node_config": { "header": "노드 구성 옵션", "seconds": "초", - "set_wakeup": "절전 모드 해제 간격 설정", + "set_wakeup": "절전모드 해제 간격 설정", "config_parameter": "구성 파라메터", "config_value": "구성 값", "true": "참", diff --git a/translations/lb.json b/translations/lb.json index e8ca12e030..df50b0b8e3 100644 --- a/translations/lb.json +++ b/translations/lb.json @@ -620,10 +620,22 @@ "common": { "value": "Wäert", "instance": "Instanz", - "index": "Index" + "index": "Index", + "unknown": "Onbekannt", + "wakeup_interval": "Intervall fir z'erwächen" }, "values": { "header": "Wäerter vum Apparat" + }, + "node_config": { + "header": "Node Konfiguratioun Optiounen", + "seconds": "Sekonnen", + "set_wakeup": "Intervall fir z'erwächen définéieren", + "config_parameter": "Konfiguratioun's Parameter", + "config_value": "Konfiguratioun's Wäert", + "true": "Richteg", + "false": "Falsch", + "set_config_parameter": "Konfiguratioun's Parameter setzen" } }, "users": { @@ -747,6 +759,33 @@ "device_tracker_picked": "Aparat suivéieren", "device_tracker_pick": "Wielt den Apparat aus fir ze suivéieren" } + }, + "server_control": { + "caption": "Kontroll vum Server", + "description": "Start an Stop vum Home Assistant Server", + "section": { + "validation": { + "heading": "Validatioun vun der Konfiguratioun", + "introduction": "Validéiert är Konfiguratioun wann Dir viru kuerzem e puer Ännerungen an ärer Konfiguratioun gemaacht hutt a wëllt sécher sinn datt alles gëlteg ass", + "check_config": "Konfiguratioun iwwerpréiwen", + "valid": "Konfiguratioun gëlteg!", + "invalid": "Konfiguratioun ongëlteg" + }, + "reloading": { + "heading": "Konfiguratioun gëtt frësch gelueden", + "introduction": "E puer Deeler vum Home Assistant kënne frësch geluede ginn ouni datt een Neistart néideg ass. Klick op nei luede fir di aktuell Konfiguratioun z'entlueden an di nei Konfiguratioun ze lueden.", + "core": "Kär néi lueden", + "group": "Gruppe nei lueden", + "automation": "Automatisme nei lueden", + "script": "Skripte nei lueden" + }, + "server_management": { + "heading": "Serververwaltung", + "introduction": "Kontrolléiert ären Home Assistant Server ... vun Home Assistant aus.", + "restart": "Neistart", + "stop": "Stop" + } + } } }, "profile": { diff --git a/translations/lt.json b/translations/lt.json index 5c31f66676..b93c976870 100644 --- a/translations/lt.json +++ b/translations/lt.json @@ -168,7 +168,10 @@ }, "config": { "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "Nustatykite parametrą „Config“" + } }, "automation": { "editor": { diff --git a/translations/lv.json b/translations/lv.json index 2a62aaddf5..81f4eb010d 100644 --- a/translations/lv.json +++ b/translations/lv.json @@ -562,6 +562,9 @@ "description": "Pārvaldiet Z-Wave tīklu", "services": { "save_config": "Saglabāt konfigurāciju" + }, + "node_config": { + "set_config_parameter": "Iestatīt konfigurācijas parametru" } }, "users": { diff --git a/translations/nn.json b/translations/nn.json index cb39456a4e..433b5247f2 100644 --- a/translations/nn.json +++ b/translations/nn.json @@ -587,7 +587,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Administrer Z-Wave-nettverket ditt" + "description": "Administrer Z-Wave-nettverket ditt", + "node_config": { + "set_config_parameter": "Angi konfigurasjonsparameter" + } }, "users": { "caption": "Brukarar", @@ -974,8 +977,8 @@ "entity_non_numeric": "Oppføringa er ikkje numerisk: {entity}" }, "changed_toast": { - "message": "Lovelace konfigurasjonen blei oppdatert, ønskjer du å oppfriske?", - "refresh": "Oppfrisk" + "message": "Lovelace konfigurasjonen vart oppdatert. Ønsker du å friske opp?", + "refresh": "Friske opp" }, "reload_lovelace": "Omlast Lovelace" }, diff --git a/translations/pt-BR.json b/translations/pt-BR.json index c8fa0628f9..302f6c331a 100644 --- a/translations/pt-BR.json +++ b/translations/pt-BR.json @@ -624,6 +624,9 @@ }, "values": { "header": "Valores de nó" + }, + "node_config": { + "set_config_parameter": "Definir o parâmetro de configuração" } }, "users": { diff --git a/translations/pt.json b/translations/pt.json index 82a10eeec2..c2461ee138 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -588,7 +588,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Gerir a sua rede Z-Wave" + "description": "Gerir a sua rede Z-Wave", + "node_config": { + "set_config_parameter": "Definir o parâmetro de configuração" + } }, "users": { "caption": "Utilizadores", diff --git a/translations/ro.json b/translations/ro.json index 6c043b5466..ce6ee18846 100644 --- a/translations/ro.json +++ b/translations/ro.json @@ -624,6 +624,9 @@ }, "values": { "header": "Valoare nod" + }, + "node_config": { + "set_config_parameter": "Setați parametrul de configurare" } }, "users": { diff --git a/translations/ru.json b/translations/ru.json index cb75cd3af3..c212e3a30b 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -397,7 +397,7 @@ }, "customize": { "caption": "Кастомизация", - "description": "Настраивайте Ваши объекты", + "description": "Настраивайте атрибуты объектов", "picker": { "header": "Кастомизация", "introduction": "Настройка атрибутов объектов. Добавленные или изменённые настройки сразу же вступают в силу. Удаленные настройки вступят в силу после обновления объекта." @@ -761,12 +761,12 @@ } }, "server_control": { - "caption": "Управление сервером", - "description": "Перезапуск или остановка Home Assistant", + "caption": "Сервер", + "description": "Управляйте сервером Home Assistant", "section": { "validation": { "heading": "Проверка конфигурации", - "introduction": "Проверьте файлы конфигурации, если Вы внесли в них изменения", + "introduction": "Проверьте файлы конфигурации, если Вы внесли в них изменения.", "check_config": "Начать проверку", "valid": "Конфигурация выполнена верно", "invalid": "Ошибка в конфигурации" @@ -781,7 +781,7 @@ }, "server_management": { "heading": "Управление сервером", - "introduction": "Управляйте Вашим сервером Home Assistant... из Home Assistant", + "introduction": "Управляйте Вашим сервером Home Assistant... из Home Assistant.", "restart": "Перезапустить", "stop": "Остановить" } diff --git a/translations/sk.json b/translations/sk.json index 9b619b10ad..9495eef6e5 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -588,7 +588,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Spravujte svoju Z-Wave sieť" + "description": "Spravujte svoju Z-Wave sieť", + "node_config": { + "set_config_parameter": "Nastavte konfiguračný parameter" + } }, "users": { "caption": "Používatelia", diff --git a/translations/sl.json b/translations/sl.json index 9e526c9b90..6a635aa2e1 100644 --- a/translations/sl.json +++ b/translations/sl.json @@ -624,6 +624,9 @@ }, "values": { "header": "Vrednosti vozlišča" + }, + "node_config": { + "set_config_parameter": "Nastavite Config Parameter" } }, "users": { diff --git a/translations/sr-Latn.json b/translations/sr-Latn.json index 752344ee96..83b934edfd 100644 --- a/translations/sr-Latn.json +++ b/translations/sr-Latn.json @@ -22,7 +22,10 @@ }, "config": { "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "Подесите параметар Цонфиг" + } }, "automation": { "editor": { diff --git a/translations/sr.json b/translations/sr.json index d56598be8a..caa98b86fb 100644 --- a/translations/sr.json +++ b/translations/sr.json @@ -63,7 +63,10 @@ }, "config": { "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "Подесите параметар Цонфиг" + } }, "users": { "editor": { diff --git a/translations/sv.json b/translations/sv.json index fee76ff512..4595b5e3f6 100644 --- a/translations/sv.json +++ b/translations/sv.json @@ -597,22 +597,41 @@ "network_stopped": "Z-Wave-nätverk stoppat", "network_starting": "Startar Z-Wave-nätverk...", "network_starting_note": "Detta kan ta ett tag beroende på storleken på ditt nätverk.", - "network_started": "Z-Wave nätverk startat" + "network_started": "Z-Wave nätverk startat", + "network_started_note_some_queried": "Vakna noder har frågats. Vilande noder frågas när de vaknar.", + "network_started_note_all_queried": "Alla noder har frågats." }, "services": { "start_network": "Starta Nätverket", "stop_network": "Stoppa nätverket", + "heal_network": "Reparera nätverk", + "test_network": "Testa nätverk", + "soft_reset": "Mjuk återställning", + "save_config": "Spara konfiguration", + "add_node_secure": "Lägg till nod med säkerhet", + "add_node": "Lägg till nod", + "remove_node": "Ta bort nod", "cancel_command": "Avbryt kommandot" }, "common": { "value": "Värde", "instance": "Instans", - "index": "Index" + "index": "Index", + "unknown": "okänt", + "wakeup_interval": "Uppvakningsintervall" + }, + "values": { + "header": "Nodvärden" }, "node_config": { + "header": "Alternativ för nodkonfiguration", "seconds": "Sekunder", + "set_wakeup": "Ställ in uppvakningsintervall", + "config_parameter": "Konfigurera parameter", + "config_value": "Konfigurera värde", "true": "Sant", - "false": "Falskt" + "false": "Falskt", + "set_config_parameter": "Ställ in konfigurations parameter" } }, "users": { @@ -738,11 +757,26 @@ } }, "server_control": { + "caption": "Serverhantering", + "description": "Starta om och stoppa Home Assistant-servern", "section": { + "validation": { + "heading": "Validering av konfiguration", + "introduction": "Kontrollera din konfiguration om du nyligen gjort ändringar och du vill säkerställa att den är giltig", + "check_config": "Kontrollera konfigurationen", + "valid": "Konfigurationen är giltig!", + "invalid": "Konfigurationen är inte giltig" + }, "reloading": { - "introduction": "Vissa delar av Home Assistant kan laddas om utan att en omstart krävs. Att trycka på \"ladda om\" innebär att den nuvarande konfiguration inaktiveras och den nya laddas." + "heading": "Konfigurationen laddas om", + "introduction": "Vissa delar av Home Assistant kan laddas om utan att en omstart krävs. Att trycka på \"ladda om\" innebär att den nuvarande konfiguration inaktiveras och den nya laddas.", + "core": "Ladda om kärnan", + "group": "Ladda om grupper", + "automation": "Ladda om automationer", + "script": "Ladda om skript" }, "server_management": { + "heading": "Serverhantering", "introduction": "Kontrollera din Home Assistant-server ... från Home Assistant.", "restart": "Starta om", "stop": "Stoppa" diff --git a/translations/ta.json b/translations/ta.json index bcc4c774b3..3835b310c2 100644 --- a/translations/ta.json +++ b/translations/ta.json @@ -245,7 +245,10 @@ }, "config": { "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "node_config": { + "set_config_parameter": "கட்டமைப்பு அளவுருவை அமைக்கவும்" + } } } }, diff --git a/translations/te.json b/translations/te.json index 3d1bfd15c3..f72ba2b915 100644 --- a/translations/te.json +++ b/translations/te.json @@ -454,7 +454,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "మీ Z- వేవ్ నెట్వర్క్ని నిర్వహించండి" + "description": "మీ Z- వేవ్ నెట్వర్క్ని నిర్వహించండి", + "node_config": { + "set_config_parameter": "కాన్ఫిగర్ పారామితిని సెట్ చేయండి" + } }, "users": { "caption": "వినియోగదారులు", diff --git a/translations/th.json b/translations/th.json index e66a62b11b..76d4f65421 100644 --- a/translations/th.json +++ b/translations/th.json @@ -588,7 +588,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "จัดการเครือข่าย Z-Wave" + "description": "จัดการเครือข่าย Z-Wave", + "node_config": { + "set_config_parameter": "ตั้งค่าพารามิเตอร์การกำหนดค่า" + } }, "users": { "caption": "ผู้ใช้", diff --git a/translations/uk.json b/translations/uk.json index df076956fe..fe60fc659b 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -565,7 +565,10 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Керуйте мережею Z-Wave" + "description": "Керуйте мережею Z-Wave", + "node_config": { + "set_config_parameter": "Встановити параметр налаштування" + } }, "users": { "caption": "Користувачі", diff --git a/translations/vi.json b/translations/vi.json index c96c925a28..9800f1d89b 100644 --- a/translations/vi.json +++ b/translations/vi.json @@ -277,7 +277,8 @@ "default": { "unknown": "KB", "unavailable": "KKD", - "error": "Lỗi" + "error": "Lỗi", + "entity_not_found": "Không tìm thấy thực thể" }, "alarm_control_panel": { "armed": "VT", @@ -600,6 +601,13 @@ "common": { "value": "Giá trị", "index": "Mục lục" + }, + "node_config": { + "config_parameter": "Cấu hình tham số", + "config_value": "Giá trị cấu hình", + "true": "Đúng", + "false": "Sai", + "set_config_parameter": "Đặt tham số cấu hình" } }, "users": { @@ -712,6 +720,8 @@ } }, "server_control": { + "caption": "Điều khiển máy chủ", + "description": "Khởi động lại và dừng máy chủ Home Assistant", "section": { "validation": { "heading": "Xác nhận cấu hình", @@ -725,7 +735,14 @@ "introduction": "Một số phần của Home Assistant có thể tải lại mà không yêu cầu khởi động lại. Nhấn nút tải lại sẽ gỡ bỏ cấu hình hiện tại của nó và tải một cấu hình mới.", "core": "Tải lại lõi", "group": "Tải lại nhóm", - "automation": "Tải lại Tự động hóa" + "automation": "Tải lại Tự động hóa", + "script": "Tải lại Kịch bản" + }, + "server_management": { + "heading": "Quản lý máy chủ", + "introduction": "Kiểm soát máy chủ Home Assistant của bạn từ Home Assistant.", + "restart": "Khởi động lại", + "stop": "Dừng" } } } @@ -927,7 +944,9 @@ "intro": "Xin chào {name} , chào mừng bạn đến với Home Assistant. Bạn muốn đặt tên nhà của bạn thế nào?", "intro_location": "Chúng tôi muốn biết nơi bạn sống. Thông tin này sẽ giúp hiển thị thông tin và thiết lập tự động dựa trên mặt trời. Dữ liệu này không bao giờ được chia sẻ bên ngoài mạng của bạn.", "intro_location_detect": "Chúng tôi có thể giúp bạn điền thông tin này bằng cách yêu cầu một lần cho dịch vụ bên ngoài.", - "location_name_default": "Nhà" + "location_name_default": "Nhà", + "button_detect": "Phát hiện", + "finish": "Kế tiếp" } }, "lovelace": { @@ -943,6 +962,7 @@ "go_to_integrations_page": "Chuyển đến trang tích hợp." }, "picture-elements": { + "hold": "Giữ:", "tap": "Nhấn:", "navigate_to": "Điều hướng đến {location}", "toggle": "Chuyển đổi {name}", @@ -1000,7 +1020,12 @@ "warning": { "entity_not_found": "Thực thể không có sẵn: {entity}", "entity_non_numeric": "Thực thể không phải là số: {entity}" - } + }, + "changed_toast": { + "message": "Cấu hình Lovelace đã được cập nhật, bạn có muốn làm mới không?", + "refresh": "Làm tươi" + }, + "reload_lovelace": "Tải lại Lovelace" }, "page-demo": { "cards": { @@ -1016,6 +1041,9 @@ "kitchen": "Phòng bếp", "patio": "Sân trong", "hallway": "Hành lang" + }, + "unit": { + "minutes_abbr": "phút" } } } @@ -1126,7 +1154,8 @@ "fan_mode": "Chế độ quạt", "swing_mode": "Chế độ swing", "away_mode": "Chế độ đi vắng", - "aux_heat": "Nhiệt phụ trợ" + "aux_heat": "Nhiệt phụ trợ", + "preset_mode": "Đặt trước" }, "lock": { "code": "Mã", @@ -1278,7 +1307,9 @@ "away": "Đi vắng", "boost": "Tăng cường", "comfort": "Thoải mái", - "home": "Ở nhà" + "home": "Ở nhà", + "sleep": "Ngủ", + "activity": "Hoạt động" }, "hvac_action": { "off": "Tắt", diff --git a/translations/zh-Hans.json b/translations/zh-Hans.json index 447bd5fdd7..5a6c3d30ff 100644 --- a/translations/zh-Hans.json +++ b/translations/zh-Hans.json @@ -605,6 +605,9 @@ "common": { "value": "值", "instance": "实例" + }, + "node_config": { + "set_config_parameter": "设置配置参数" } }, "users": { diff --git a/yarn.lock b/yarn.lock index a151976961..01f93bb54b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -847,10 +847,10 @@ dependencies: "@material/feature-targeting" "^0.44.1" -"@mdi/svg@3.7.95": - version "3.7.95" - resolved "https://registry.yarnpkg.com/@mdi/svg/-/svg-3.7.95.tgz#178207f08cb91dc9111afef7e748aefe41b54019" - integrity sha512-5ZStRxq4PFATwurnjN1CgCGCfP8nwJfHuqUozTMaF/qKC7rlSBS0Sm+VQQDmlJBO3JjiG+dQgd7ZdtanI/w/mw== +"@mdi/svg@3.9.97": + version "3.9.97" + resolved "https://registry.yarnpkg.com/@mdi/svg/-/svg-3.9.97.tgz#653fb2249e47c62bd89664ab1479eb5e16a3051c" + integrity sha512-ppU8jzKWZIau6DPWywZPtcDw1y5o+EopdtomfpYS96kLf1Lu7qEnIBeh+7QQUjhepKSexO/XW11/mMGecFkOdw== "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1"