From c89e17ac0048ba614490ff208e417bb0793c41ad Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Fri, 27 Nov 2020 00:32:35 +0000 Subject: [PATCH 01/38] [ci skip] Translation update --- translations/frontend/cs.json | 8 ++++---- translations/frontend/de.json | 6 +++--- translations/frontend/en.json | 26 +++++++++++++++++++------- translations/frontend/fi.json | 9 +++++---- translations/frontend/it.json | 34 +++++++++++++++++----------------- translations/frontend/ja.json | 1 + translations/frontend/nl.json | 2 +- translations/frontend/tr.json | 4 ++-- 8 files changed, 52 insertions(+), 38 deletions(-) diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index b7f8c295fc..da824008c5 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -587,7 +587,7 @@ "by_service": "službou", "entries_not_found": "Nenalezeny žádné záznamy.", "messages": { - "became_unavailable": "stalo se nedostupným", + "became_unavailable": "bylo nedostupné", "changed_to_state": "změněno na {state}", "cleared_device_class": "zrušeno (nebylo zjištěno {device_class})", "detected_device_class": "zjištěno {device_class}", @@ -1068,7 +1068,7 @@ "delete_confirm": "Opravdu smazat?", "duplicate": "Duplikovat", "header": "Akce", - "introduction": "Akce jsou to, co Home Assistant provede při spuštění automatizace. \n\n [Více informací o akcích.] (Https://home-assistant.io/docs/automation/action/)", + "introduction": "Akce jsou to, co Home Assistant provede při spuštění automatizace.", "learn_more": "Další informace o akcích", "name": "Akce", "type_select": "Typ akce", @@ -1150,7 +1150,7 @@ "delete_confirm": "Opravdu smazat?", "duplicate": "Duplikovat", "header": "Podmínky", - "introduction": "Podmínky jsou volitelnou součástí automatizačního pravidla a mohou být použity k zabránění spuštění akce. Podmínky vypadají velmi podobně jako spouštěče, ale jsou velmi odlišné. Spouštěč se podívá na události, ke kterým dochází v systému, zatímco podmínka se zabývá pouze tím, jak systém vypadá právě teď. Pro spouštěč se může jevit že je spínač zapnutý. Stav může vidět pouze tehdy, je-li přepínač aktuálně zapnutý nebo vypnutý. \n\n [Další informace o podmínkách.] (Https://home-assistant.io/docs/scripts/conditions/)", + "introduction": "Podmínky jsou volitelné a pokud nejsou všechny splněny, zabrání dalšímu provádění automatizace.", "learn_more": "Další informace o podmínkách", "name": "Podmínka", "type_select": "Typ podmínky", @@ -1254,7 +1254,7 @@ "delete_confirm": "Opravdu smazat?", "duplicate": "Duplikovat", "header": "Spouštěče", - "introduction": "Spouštěče spouštějí zpracování automatizačního pravidla. Pro stejné pravidlo je možné zadat více spouštěčů. Po spuštění spouštěče ověří Home Assistant případné podmínky a zavolá akci. \n\n [Další informace o spouštěčích.] (Https://home-assistant.io/docs/automation/trigger/)", + "introduction": "Spouštěče spouštějí automatizaci. Pro jednu automatizaci je možné zadat více spouštěčů. Po spuštění ověří Home Assistant případné podmínky a zavolá akci.", "learn_more": "Další informace o spouštěčích", "name": "Spouštěč", "type_select": "Typ spouštěče", diff --git a/translations/frontend/de.json b/translations/frontend/de.json index 2806d3ce24..aee1f37303 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -1398,7 +1398,7 @@ }, "blueprint": { "add": { - "error_no_url": "Bitte gebe die URL des Blueprints ein.", + "error_no_url": "Bitte gebe die URL des Bauplans ein.", "header": "Neuen Bauplan hinzufügen", "import_btn": "Bauplan importieren", "import_header": "{name}({domain}) importieren", @@ -1407,7 +1407,7 @@ "save_btn": "Bauplan speichern", "saving": "Bauplan wir gespeichert...", "unsupported_blueprint": "Dieser Bauplan wird nicht unterstützt", - "url": "URL des Blueprints" + "url": "URL des Bauplans" }, "caption": "Baupläne", "description": "Baupläne verwalten", @@ -3401,7 +3401,7 @@ }, "enable_shortcuts": { "description": "Aktiviere oder deaktiviere Tastaturkürzel, um verschiedene Aktionen in der Benutzeroberfläche auszuführen.", - "header": "Tastatürkürzel" + "header": "Tastaturkürzel" }, "force_narrow": { "description": "Dies blendet die Seitenleiste standardmäßig aus, ähnlich der Nutzung auf Mobilgeräten.", diff --git a/translations/frontend/en.json b/translations/frontend/en.json index c3141096b0..201bcaf492 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -1239,7 +1239,7 @@ "edit_ui": "Edit with UI", "edit_yaml": "Edit as YAML", "enable_disable": "Enable/Disable automation", - "introduction": "Use automations to bring your home alive.", + "introduction": "Use automations to bring your home to live.", "load_error_not_editable": "Only automations in automations.yaml are editable.", "load_error_unknown": "Error loading automation ({err_no}).", "max": { @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "Please enter the URL of the blueprint.", + "file_name": "Local blueprint file name", "header": "Add new blueprint", "import_btn": "Import blueprint", - "import_header": "Import {name} ({domain})", + "import_header": "Import \"{name}\" (type: {domain})", "import_introduction": "You can import blueprints of other users from Github and the community forums. Enter the URL of the blueprint below.", "importing": "Importing blueprint...", + "raw_blueprint": "Blueprint content", "save_btn": "Save blueprint", "saving": "Saving blueprint...", "unsupported_blueprint": "This blueprint is not supported", @@ -1412,15 +1414,19 @@ "caption": "Blueprints", "description": "Manage blueprints", "overview": { - "add_blueprint": "Add blueprint", + "add_blueprint": "Import blueprint", "confirm_delete_header": "Delete this blueprint?", - "confirm_delete_text": "Are you sure you want to delete this blueprint", + "confirm_delete_text": "Are you sure you want to delete this blueprint?", + "delete_blueprint": "Delete blueprint", "header": "Blueprint Editor", "headers": { + "domain": "Domain", + "file_name": "File name", "name": "Name" }, "introduction": "The blueprint editor allows you to create and edit blueprints.", - "learn_more": "Learn more about blueprints" + "learn_more": "Learn more about blueprints", + "use_blueprint": "Create automation" } }, "cloud": { @@ -2209,7 +2215,7 @@ "without_device": "Entities without device" }, "icon": "Icon", - "introduction": "Use scenes to bring your home alive.", + "introduction": "Use scenes to bring your home to live.", "load_error_not_editable": "Only scenes in scenes.yaml are editable.", "load_error_unknown": "Error loading scene ({err_no}).", "name": "Name", @@ -2414,6 +2420,7 @@ "users_privileges_note": "The user group feature is a work in progress. The user will be unable to administer the instance via the UI. We're still auditing all management API endpoints to ensure that they correctly limit access to administrators." }, "zha": { + "add_device": "Add Device", "add_device_page": { "discovered_text": "Devices will show up here once discovered.", "discovery_text": "Discovered devices will show up here. Follow the instructions for your device(s) and place the device(s) in pairing mode.", @@ -2474,6 +2481,7 @@ "unbind_button_label": "Unbind Group" }, "groups": { + "add_group": "Add Group", "add_members": "Add Members", "adding_members": "Adding Members", "caption": "Groups", @@ -2516,7 +2524,11 @@ "hint_wakeup": "Some devices such as Xiaomi sensors have a wake up button that you can press at ~5 second intervals that keep devices awake while you interact with them.", "introduction": "Run ZHA commands that affect a single device. Pick a device to see a list of available commands." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Visualization", + "header": "Network Visualization" + } }, "zone": { "add_zone": "Add Zone", diff --git a/translations/frontend/fi.json b/translations/frontend/fi.json index f1bd0def23..0d7ca879ab 100644 --- a/translations/frontend/fi.json +++ b/translations/frontend/fi.json @@ -1171,7 +1171,7 @@ "trigger": "Laukaisin" }, "event": { - "context_user_pick": "Lisää käyttäjä", + "context_user_pick": "Valitse käyttäjä", "context_user_picked": "Käyttäjän laukaisutapahtuma", "context_users": "Rajoita tapahtumiin, jotka ovat käynnistäneet", "event_data": "Tapahtuman tietosisältö", @@ -2113,6 +2113,7 @@ "person": "Lataa henkilöt uudelleen", "ping": "Lataa ping-binaarianturin entiteetit uudelleen", "reload": "Lataa uudelleen {domain}", + "rest": "Uudelleenlataa rest-entiteetit ja ilmoita palveluiden kuuntelijoille", "rpi_gpio": "Lataa Raspberry Pi GPIO -entiteetit uudelleen", "scene": "Lataa tilanteet uudelleen", "script": "Lataa skriptit uudelleen", @@ -2862,7 +2863,7 @@ }, "raw_editor": { "confirm_remove_config_text": "Lovelace käyttöliittymän näkymät luodaan automaattisesti alueistasi ja laitteistasi, jos poistat nykyisen määrityksen.", - "confirm_remove_config_title": "Haluatko varmasti poistaa Lovelace-käyttöliittymän asetukset? Lovelace käyttöliittymän asetukset luodaan automaattisesti alueistasi ja laitteistasi.", + "confirm_remove_config_title": "Haluatko varmasti poistaa Lovelace-käyttöliittymän asetukset?", "confirm_unsaved_changes": "Sinulla on tallentamattomia muutoksia. Haluatko varmasti poistua?", "confirm_unsaved_comments": "Asetuksesi sisältää kommentoituja rivejä. Kommentoituja rivejä ei tallenneta. Haluatko jatkaa?", "error_invalid_config": "Asetuksesi ovat virheelliset: {error}", @@ -2906,7 +2907,7 @@ }, "menu": { "close": "Sulje", - "configure_ui": "Määrittele käyttöliittymä", + "configure_ui": "Muokkaa käyttöliittymää", "exit_edit_mode": "Poistu käyttöliittymän muokkaustilasta", "help": "Apua", "refresh": "Päivitä", @@ -2915,7 +2916,7 @@ }, "reload_lovelace": "Lataa Lovelace uudelleen", "reload_resources": { - "refresh_body": "Sinun täytyy päivittää sivu viimeistelläksesi uudelleenlatauksen, haluatko päivittää nyt?", + "refresh_body": "Sinun täytyy päivittää sivu viimeistelläksesi uudelleenlatauksen. Haluatko päivittää nyt?", "refresh_header": "Haluatko päivittää?" }, "unused_entities": { diff --git a/translations/frontend/it.json b/translations/frontend/it.json index 2fdeed38db..d449157c8a 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -217,7 +217,7 @@ "closing": "In chiusura", "open": "Aperta", "opening": "In apertura", - "stopped": "Arrestato" + "stopped": "Arrestata" }, "default": { "off": "Spento", @@ -234,18 +234,18 @@ }, "group": { "closed": "Chiusi", - "closing": "Chiusura", + "closing": "In Chiusura", "home": "A casa", - "locked": "Bloccato", + "locked": "Bloccati", "not_home": "Fuori casa", "off": "Spento", "ok": "OK", "on": "Acceso", "open": "Aperti", - "opening": "Apertura", + "opening": "In Apertura", "problem": "Problema", - "stopped": "Fermato", - "unlocked": "Sbloccato" + "stopped": "Fermati", + "unlocked": "Sbloccati" }, "input_boolean": { "off": "Spento", @@ -332,13 +332,13 @@ "zwave": { "default": { "dead": "Disattivo", - "initializing": "Avvio", + "initializing": "In avvio", "ready": "Pronto", "sleeping": "In attesa" }, "query_stage": { "dead": "Disattivo ({query_stage})", - "initializing": "Avvio ({query_stage})" + "initializing": "In avvio ({query_stage})" } } }, @@ -1051,7 +1051,7 @@ }, "automation": { "caption": "Automazioni", - "description": "Gestisci le automazioni", + "description": "Gestisci le Automazioni", "dialog_new": { "blueprint": { "use_blueprint": "Usa un progetto" @@ -1070,7 +1070,7 @@ "actions": { "add": "Aggiungi azione", "delete": "Elimina", - "delete_confirm": "Sicuro di voler eliminare?", + "delete_confirm": "Sei sicuro di voler eliminare questo?", "duplicate": "Duplica", "header": "Azioni", "introduction": "Le azioni sono ciò che Home Assistant eseguirà quando un'attivazione (o trigger) avvia un'automazione.", @@ -1157,7 +1157,7 @@ "conditions": { "add": "Aggiungi condizione", "delete": "Elimina", - "delete_confirm": "Sicuro di voler eliminare?", + "delete_confirm": "Sei sicuro di voler eliminare questo?", "duplicate": "Duplica", "header": "Condizioni", "introduction": "Le condizioni sono facoltative e impediranno un'ulteriore esecuzione se non saranno soddisfatte tutte.", @@ -1181,8 +1181,8 @@ "label": "Non" }, "numeric_state": { - "above": "Superiore", - "below": "Inferiore", + "above": "Maggiore di", + "below": "Minore di", "label": "Valore numerico", "value_template": "Valore modello (opzionale)" }, @@ -1209,7 +1209,7 @@ "time": { "after": "Dopo", "before": "Prima", - "label": "Tempo", + "label": "Ora", "type_input": "Valore di un aiutante data/ora", "type_value": "Tempo fisso", "weekdays": { @@ -1319,7 +1319,7 @@ "to": "A" }, "sun": { - "event": "Evento", + "event": "Evento:", "label": "Sole", "offset": "Scostamento (opzionale)", "sunrise": "Alba", @@ -1351,7 +1351,7 @@ "zone": { "enter": "Entrata", "entity": "Entità con posizione", - "event": "Evento", + "event": "Evento:", "label": "Zona", "leave": "Uscita", "zone": "Zona" @@ -1593,7 +1593,7 @@ }, "common": { "editor": { - "confirm_unsaved": "Hai dei cambiamenti non salvati. Sei sicuro di voler andare via?" + "confirm_unsaved": "Hai dei cambiamenti non salvati. Sei sicuro di voler uscire?" } }, "core": { diff --git a/translations/frontend/ja.json b/translations/frontend/ja.json index a32e8cfe4b..4fb5a5e1e5 100644 --- a/translations/frontend/ja.json +++ b/translations/frontend/ja.json @@ -1135,6 +1135,7 @@ "blueprint": { "blueprint_to_use": "使用する設計図", "header": "設計図", + "inputs": "入力", "manage_blueprints": "設計図の管理", "no_blueprints": "設計図はありません", "no_inputs": "この設計図には入力がありません。" diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 60887b19fc..e1f5c38864 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -2677,7 +2677,7 @@ "attributes": "Attributen", "current_entities": "Huidige entiteiten", "description1": "Stelt de weergave van een apparaat in Home Assistant in.", - "description2": "Er vindt geen communicatie met het daadwerkelijke apparaat plaat.", + "description2": "Er vindt geen communicatie met het daadwerkelijke apparaat plaats.", "entity": "Entiteit", "filter_attributes": "Filter attributen", "filter_entities": "Filter entiteiten", diff --git a/translations/frontend/tr.json b/translations/frontend/tr.json index 3d8e4a9c31..b696637aef 100644 --- a/translations/frontend/tr.json +++ b/translations/frontend/tr.json @@ -2284,7 +2284,7 @@ } }, "server_control": { - "caption": "Server Kontrolleri", + "caption": "Sunucu Kontrolleri", "description": "Home Assistant sunucusunu yeniden başlatın veya durdurun", "section": { "reloading": { @@ -2326,7 +2326,7 @@ "confirm_restart": "Home Assistant'ı yeniden başlatmak istediğinizden emin misiniz?", "confirm_stop": "Home Assistant'ı durdurmak istediğinizden emin misin?", "heading": "Sunucu yönetimi", - "introduction": "Home Assistant sunucunuzu kontrol edin.. Home Assistant üzerinden", + "introduction": "Home Assistant sunucunuzu kontrol edin... Home Assistant üzerinden", "restart": "Yeniden başlat", "stop": "Durdur" }, From c261b5c1ce137ef2391950a82cacd2e59d91d069 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Fri, 27 Nov 2020 09:41:47 +0100 Subject: [PATCH 02/38] Display HA username + flags in user config (#7705) --- src/data/user.ts | 1 + src/panels/config/users/dialog-add-user.ts | 5 +- src/panels/config/users/dialog-user-detail.ts | 5 +- src/panels/config/users/ha-config-users.ts | 46 +++++++++++++------ src/translations/en.json | 13 ++++-- 5 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/data/user.ts b/src/data/user.ts index bd35ff1896..ea295dc6db 100644 --- a/src/data/user.ts +++ b/src/data/user.ts @@ -9,6 +9,7 @@ export const GROUPS = [SYSTEM_GROUP_ID_USER, SYSTEM_GROUP_ID_ADMIN]; export interface User { id: string; + username: string | null; name: string; is_owner: boolean; is_active: boolean; diff --git a/src/panels/config/users/dialog-add-user.ts b/src/panels/config/users/dialog-add-user.ts index 7d291e9307..f88d4a476a 100644 --- a/src/panels/config/users/dialog-add-user.ts +++ b/src/panels/config/users/dialog-add-user.ts @@ -98,7 +98,7 @@ export class DialogAddUser extends LitElement { class="name" name="name" .label=${this.hass.localize( - "ui.panel.config.users.add_user.name" + "ui.panel.config.users.editor.name" )} .value=${this._name} required @@ -113,7 +113,7 @@ export class DialogAddUser extends LitElement { class="username" name="username" .label=${this.hass.localize( - "ui.panel.config.users.add_user.username" + "ui.panel.config.users.editor.username" )} .value=${this._username} required @@ -259,6 +259,7 @@ export class DialogAddUser extends LitElement { return; } + user.username = this._username; this._params!.userAddedCallback(user); this._close(); } diff --git a/src/panels/config/users/dialog-user-detail.ts b/src/panels/config/users/dialog-user-detail.ts index e773364652..d46a4cf24b 100644 --- a/src/panels/config/users/dialog-user-detail.ts +++ b/src/panels/config/users/dialog-user-detail.ts @@ -67,7 +67,10 @@ class DialogUserDetail extends LitElement {
${this._error ? html`
${this._error}
` : ""}
- ${this.hass.localize("ui.panel.config.users.editor.id")}: ${user.id} + ${this.hass.localize("ui.panel.config.users.editor.id")}: + ${user.id}
+ ${this.hass.localize("ui.panel.config.users.editor.username")}: + ${user.username}
${user.is_owner diff --git a/src/panels/config/users/ha-config-users.ts b/src/panels/config/users/ha-config-users.ts index 496d634200..c870804c7f 100644 --- a/src/panels/config/users/ha-config-users.ts +++ b/src/panels/config/users/ha-config-users.ts @@ -35,14 +35,15 @@ export class HaConfigUsers extends LitElement { @property() public route!: Route; private _columns = memoizeOne( - (_language): DataTableColumnContainer => { - return { + (narrow: boolean, _language): DataTableColumnContainer => { + const columns: DataTableColumnContainer = { name: { title: this.hass.localize( "ui.panel.config.users.picker.headers.name" ), sortable: true, filterable: true, + width: "25%", direction: "asc", grows: true, template: (name) => html` @@ -50,32 +51,45 @@ export class HaConfigUsers extends LitElement { this.hass!.localize("ui.panel.config.users.editor.unnamed_user")} `, }, + username: { + title: this.hass.localize( + "ui.panel.config.users.picker.headers.username" + ), + sortable: true, + filterable: true, + width: "20%", + direction: "asc", + template: (username) => html` + ${username || + this.hass!.localize("ui.panel.config.users.editor.unnamed_user")} + `, + }, group_ids: { title: this.hass.localize( "ui.panel.config.users.picker.headers.group" ), sortable: true, filterable: true, - width: "30%", + width: "20%", template: (groupIds) => html` ${this.hass.localize(`groups.${groupIds[0]}`)} `, }, - system_generated: { + }; + if (!narrow) { + columns.system_generated = { title: this.hass.localize( "ui.panel.config.users.picker.headers.system" ), type: "icon", - width: "80px", sortable: true, filterable: true, - template: (generated) => html` - ${generated - ? html` ` - : ""} - `, - }, - }; + width: "160px", + template: (generated) => + generated ? html` ` : "", + }; + } + return columns; } ); @@ -92,7 +106,7 @@ export class HaConfigUsers extends LitElement { .route=${this.route} backPath="/config" .tabs=${configSections.persons} - .columns=${this._columns(this.hass.language)} + .columns=${this._columns(this.narrow, this.hass.language)} .data=${this._users} @row-click=${this._editUser} hasFab @@ -112,6 +126,12 @@ export class HaConfigUsers extends LitElement { private async _fetchUsers() { this._users = await fetchUsers(this.hass); + + this._users.forEach(function (user) { + if (user.is_owner) { + user.group_ids.unshift("owner"); + } + }); } private _editUser(ev: HASSDomEvent) { diff --git a/src/translations/en.json b/src/translations/en.json index f3fb442eac..df894c5333 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -89,6 +89,7 @@ } }, "groups": { + "owner": "Owner", "system-admin": "Administrators", "system-users": "Users", "system-read-only": "Read-Only Users" @@ -1991,15 +1992,19 @@ "users_privileges_note": "The user group feature is a work in progress. The user will be unable to administer the instance via the UI. We're still auditing all management API endpoints to ensure that they correctly limit access to administrators.", "picker": { "headers": { - "name": "Name", + "name": "Display name", + "username": "Username", "group": "Group", - "system": "System" + "system": "System generated", + "is_active": "Active", + "is_owner": "Owner" }, "add_user": "Add user" }, "editor": { "caption": "View user", - "name": "Name", + "name": "Display name", + "username": "Username", "change_password": "Change password", "new_password": "New Password", "password_changed": "Password was changed successfully", @@ -2020,8 +2025,6 @@ }, "add_user": { "caption": "Add user", - "name": "Name", - "username": "Username", "password": "Password", "password_confirm": "Confirm Password", "password_not_match": "Passwords don't match", From 0494a9d410071efd75c5f7b04984c79a3b2afabe Mon Sep 17 00:00:00 2001 From: Kendell R Date: Fri, 27 Nov 2020 10:23:41 -0800 Subject: [PATCH 03/38] Update skeleton height for compact header (#7827) Co-authored-by: Bram Kragten --- src/html/index.html.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/html/index.html.template b/src/html/index.html.template index 4628170fe9..a21eef0737 100644 --- a/src/html/index.html.template +++ b/src/html/index.html.template @@ -42,7 +42,7 @@ #ha-init-skeleton::before { display: block; content: ""; - height: 112px; + height: 56px; background-color: #THEMEC; } html { From cae94175fe517760c4cd0a29dde1da7492ba3303 Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Sat, 28 Nov 2020 00:32:35 +0000 Subject: [PATCH 04/38] [ci skip] Translation update --- translations/frontend/de.json | 13 +++- translations/frontend/en.json | 13 ++-- translations/frontend/es.json | 24 +++++-- translations/frontend/hu.json | 16 ++++- translations/frontend/nb.json | 26 +++++-- translations/frontend/pl.json | 20 ++++-- translations/frontend/ro.json | 110 +++++++++++++++++++++++++++-- translations/frontend/ru.json | 8 ++- translations/frontend/zh-Hans.json | 18 ++++- translations/frontend/zh-Hant.json | 22 ++++-- 10 files changed, 229 insertions(+), 41 deletions(-) diff --git a/translations/frontend/de.json b/translations/frontend/de.json index aee1f37303..167d8ed95b 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -1417,10 +1417,13 @@ "confirm_delete_text": "Bist du sicher, dass du diesen Bauplan löschen möchtest?", "header": "Bauplan-Editor", "headers": { + "domain": "Domain", + "file_name": "Dateiname", "name": "Name" }, "introduction": "Mit dem Bauplan-Editor kannst du Baupläne erstellen und bearbeiten.", - "learn_more": "Erfahre mehr über Baupläne" + "learn_more": "Erfahre mehr über Baupläne", + "use_blueprint": "Automatisierung erstellen" } }, "cloud": { @@ -2414,6 +2417,7 @@ "users_privileges_note": "Benutzergruppen sind derzeit noch in Entwicklung. Der Benutzer wird nicht in der Lage sein, Änderungen an der Instanz über das UI vorzunehmen. Derzeit überprüfen wir noch alle API Endpunkte um sicherzustellen dass diese nur von Administratoren genutzt werden können." }, "zha": { + "add_device": "Gerät hinzufügen", "add_device_page": { "discovered_text": "Geräte werden hier angezeigt sobald sie erkannt worden sind.", "discovery_text": "Erkannte Geräte werden hier angezeigt. Befolgen Sie die Anweisungen für Ihr Gerät und versetzen Sie das Gerät in den Pairing-Modus.", @@ -2474,6 +2478,7 @@ "unbind_button_label": "Gruppe auflösen" }, "groups": { + "add_group": "Gruppe hinzufügen", "add_members": "Mitglieder hinzufügen", "adding_members": "Füge Mitglieder hinzu", "caption": "Gruppen", @@ -2516,7 +2521,11 @@ "hint_wakeup": "Einige Geräte, z. B. Xiaomi-Sensoren, verfügen über eine Wecktaste, die in Intervallen von ~5 Sekunden gedrückt werden kann, um die Geräte wach zu halten, während mit ihnen interagiert wird.", "introduction": "ZHA-Befehle ausführen, die sich auf ein einzelnes Gerät auswirken. Wählen Sie ein Gerät aus, um eine Liste der verfügbaren Befehle anzuzeigen." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Visualisierung", + "header": "Netzwerkvisualisierung" + } }, "zone": { "add_zone": "Zone hinzufügen", diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 201bcaf492..b9453e072b 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Owner", "system-admin": "Administrators", "system-read-only": "Read-Only Users", "system-users": "Users" @@ -2399,7 +2400,7 @@ "delete_user": "Delete user", "group": "Group", "id": "ID", - "name": "Name", + "name": "Display name", "new_password": "New Password", "owner": "Owner", "password_changed": "Password was changed successfully", @@ -2407,14 +2408,18 @@ "system_generated_users_not_editable": "Unable to update system generated users.", "system_generated_users_not_removable": "Unable to remove system generated users.", "unnamed_user": "Unnamed User", - "update_user": "Update" + "update_user": "Update", + "username": "Username" }, "picker": { "add_user": "Add user", "headers": { "group": "Group", - "name": "Name", - "system": "System" + "is_active": "Active", + "is_owner": "Owner", + "name": "Display name", + "system": "System generated", + "username": "Username" } }, "users_privileges_note": "The user group feature is a work in progress. The user will be unable to administer the instance via the UI. We're still auditing all management API endpoints to ensure that they correctly limit access to administrators." diff --git a/translations/frontend/es.json b/translations/frontend/es.json index d253696fce..ce0c96f4ec 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -1147,7 +1147,7 @@ }, "alias": "Nombre", "blueprint": { - "blueprint_to_use": "Plano a utilizar", + "blueprint_to_use": "Plano a usar", "header": "Plano", "inputs": "Entradas", "manage_blueprints": "Administrar planos", @@ -1239,7 +1239,7 @@ "edit_ui": "Editar con la interfaz de usuario", "edit_yaml": "Editar como YAML", "enable_disable": "Activar/Desactivar automatización", - "introduction": "Utiliza automatizaciones para darle vida a tu hogar.", + "introduction": "Usa automatizaciones para darle vida a tu hogar.", "load_error_not_editable": "Solo las automatizaciones en automations.yaml son editables.", "load_error_unknown": "Error al cargar la automatización ({err_no}).", "max": { @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "Por favor, introduce la URL del plano.", + "file_name": "Nombre de archivo del plano local", "header": "Añadir nuevo plano", "import_btn": "Importar plano", - "import_header": "Importar {name} ({domain})", + "import_header": "Importar {name} (tipo: {domain})", "import_introduction": "Puedes importar planos de otros usuarios desde Github y los foros de la comunidad. Introduce la URL del plano a continuación.", "importing": "Importando plano...", + "raw_blueprint": "Contenido del plano", "save_btn": "Guardar plano", "saving": "Guardando plano...", "unsupported_blueprint": "Este plano no es compatible", @@ -1412,15 +1414,19 @@ "caption": "Planos", "description": "Administrar planos", "overview": { - "add_blueprint": "Añadir plano", + "add_blueprint": "Importar plano", "confirm_delete_header": "¿Eliminar este plano?", "confirm_delete_text": "¿Estás seguro de que quieres borrar este plano?", + "delete_blueprint": "Eliminar plano", "header": "Editor de planos", "headers": { + "domain": "Dominio", + "file_name": "Nombre de archivo", "name": "Nombre" }, "introduction": "El editor de planos te permite crear y editar planos.", - "learn_more": "Más información sobre planos" + "learn_more": "Más información sobre planos", + "use_blueprint": "Crear automatización" } }, "cloud": { @@ -2414,6 +2420,7 @@ "users_privileges_note": "El grupo de usuarios es un trabajo en progreso. El usuario no podrá administrar la instancia a través de la IU. Todavía estamos auditando todos los endpoints de la API de administración para garantizar que se limita correctamente el acceso sólo a los administradores." }, "zha": { + "add_device": "Añadir dispositivo", "add_device_page": { "discovered_text": "Los dispositivos aparecerán aquí una vez descubiertos.", "discovery_text": "Los dispositivos detectados aparecerán aquí. Ponlos en modo emparejamiento siguiendo sus instrucciones.", @@ -2474,6 +2481,7 @@ "unbind_button_label": "Desvincular grupo" }, "groups": { + "add_group": "Añadir grupo", "add_members": "Añadir miembros", "adding_members": "Agregar miembros", "caption": "Grupos", @@ -2516,7 +2524,11 @@ "hint_wakeup": "Algunos dispositivos, como los sensores Xiaomi, tienen un botón de activación que puedes presionar a intervalos de ~ 5 segundos para mantener los dispositivos despiertos mientras interactúas con ellos.", "introduction": "Ejecuta comandos ZHA que afecten a un único dispositivo. Elije un dispositivo para ver una lista de comandos disponibles." }, - "title": "Domótica Zigbee" + "title": "Domótica Zigbee", + "visualization": { + "caption": "Visualización", + "header": "Visualización de la red" + } }, "zone": { "add_zone": "Añadir zona", diff --git a/translations/frontend/hu.json b/translations/frontend/hu.json index 31e658680a..67bb01fae1 100644 --- a/translations/frontend/hu.json +++ b/translations/frontend/hu.json @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "Add meg a tervrajz URL címét.", + "file_name": "Helyi tervrajz neve", "header": "Új tervrajz hozzáadása", "import_btn": "Tervrajz importálása", "import_header": "{name} importálása ({domain})", "import_introduction": "Importálhatod más felhasználók tervrajzait a Githubról és a közösségi fórumról. Írd be alább a terv URL címét.", "importing": "Tervrajz importálása...", + "raw_blueprint": "Tervrajz tartalma", "save_btn": "Tervrajz mentése", "saving": "Tervrajz mentése...", "unsupported_blueprint": "Ez a tervrajz nem támogatott", @@ -1415,12 +1417,16 @@ "add_blueprint": "Tervrajz hozzáadása", "confirm_delete_header": "Törlöd ezt a tervrajzot?", "confirm_delete_text": "Biztosan törölni szeretnéd ezt a tervrajzot?", + "delete_blueprint": "Tervrajz törlése", "header": "Tervrajz szerkesztő", "headers": { + "domain": "Tartomány", + "file_name": "Fájl név", "name": "Név" }, "introduction": "A tervrajz-szerkesztő lehetővé teszi tervrajzok létrehozását és szerkesztését.", - "learn_more": "Tudj meg többet a tervrajzokról" + "learn_more": "Tudj meg többet a tervrajzokról", + "use_blueprint": "Automatizálás létrehozása" } }, "cloud": { @@ -2414,6 +2420,7 @@ "users_privileges_note": "A felhasználói csoport funkció jelenleg is fejlesztés alatt áll. A felhasználó nem tudja kezelni a példányt a felhasználói felületen keresztül. Folyamatosan ellenőrizzük az összes felügyeleti API-végpontot annak érdekében, hogy azok helyesen korlátozzák a hozzáférést az adminisztrátorok részére." }, "zha": { + "add_device": "Eszköz hozzáadása", "add_device_page": { "discovered_text": "Az eszközök itt fognak megjelenni, ha felfedezésre kerültek.", "discovery_text": "A felfedezett eszközök itt fognak megjelenni. A készülékek használati utasításai alapján állítsd őket párosítási módba.", @@ -2474,6 +2481,7 @@ "unbind_button_label": "Csoport bontás" }, "groups": { + "add_group": "Csoport hozzáadása", "add_members": "Tagok hozzáadása", "adding_members": "Tagok hozzáadása", "caption": "Csoportok", @@ -2516,7 +2524,11 @@ "hint_wakeup": "Egyes eszközöknek, például a Xiaomi szenzoroknak van ébresztő gombjuk, amit kb. 5 másodperces szünetekkel nyomkodva éber állapotban tarthatók a kommunikáció idejére.", "introduction": "Egy eszközt érintő ZHA parancs futtatása. Válassz ki egy eszközt az elérhető parancsok megtekintéséhez." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Megjelenítés", + "header": "Hálózati megjelenítés" + } }, "zone": { "add_zone": "Zóna hozzáadása", diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index 2b9bdef79d..132cd56af7 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -1239,7 +1239,7 @@ "edit_ui": "Rediger med brukergrensesnittet", "edit_yaml": "Rediger som YAML", "enable_disable": "Aktivere/deaktivere automasjon", - "introduction": "Bruk automasjon for å få liv i hjemmet ditt", + "introduction": "Bruk automatisering for å bringe hjemmet ditt til live.", "load_error_not_editable": "Kun automasjoner i automations.yaml kan redigeres", "load_error_unknown": "Feil ved lasting av automasjon ({err_no}).", "max": { @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "Vennligst skriv inn URL-en til blueprint", + "file_name": "Lokalt blueprint filnavn", "header": "Legg til ny blueprint", "import_btn": "Importer blueprint", - "import_header": "Importer {name} ({domain})", + "import_header": "Importer {name} (type: {domain})", "import_introduction": "Du kan importere blueprints av andre brukere fra Github og fellesskapsforumet. Skriv inn URL-en til blueprint nedenfor.", "importing": "Importerer blueprint...", + "raw_blueprint": "Blueprint innhold", "save_btn": "Lagre blueprint", "saving": "Lagrer blueprint...", "unsupported_blueprint": "Denne blueprinten støttes ikke", @@ -1412,15 +1414,19 @@ "caption": "Blueprints", "description": "Administrer blueprints", "overview": { - "add_blueprint": "Legg til blueprint", + "add_blueprint": "Importer blueprint", "confirm_delete_header": "Slette denne blueprint'en?", - "confirm_delete_text": "Er du sikker på at du vil slette denne blueprint'en", + "confirm_delete_text": "Er du sikker på at du vil slette denne blueprint", + "delete_blueprint": "Slett blueprint", "header": "Blueprint Editor", "headers": { + "domain": "Domene", + "file_name": "Filnavn", "name": "Navn" }, "introduction": "Med blueprint editor kan du opprette og redigere blueprints", - "learn_more": "Lær mer om blueprint" + "learn_more": "Lær mer om blueprint", + "use_blueprint": "Opprett automasjon" } }, "cloud": { @@ -2209,7 +2215,7 @@ "without_device": "Entiteter uten enhet" }, "icon": "Ikon", - "introduction": "Bruk scener for å gjøre hjemmet ditt mer levende.", + "introduction": "Bruk scener for å bringe hjemmet ditt til live.", "load_error_not_editable": "Bare scener i scenes.yaml kan redigeres.", "load_error_unknown": "Feil ved lasting av scene ({err_no}).", "name": "Navn", @@ -2414,6 +2420,7 @@ "users_privileges_note": "Brukergruppefunksjonen er et pågående arbeid. Brukeren vil ikke kunne administrere forekomsten via brukergrensesnittet. Vi overvåker fortsatt alle administrasjons-API-endepunkter for å sikre at de begrenser tilgangen til administratorer på riktig måte." }, "zha": { + "add_device": "Legg til enhet", "add_device_page": { "discovered_text": "Enheter vises her når de er oppdaget.", "discovery_text": "Automatisk oppdagede enheter vises her. Følg instruksjonene for enheten(e) og sett enheten(e) i paringsmodus.", @@ -2474,6 +2481,7 @@ "unbind_button_label": "Frigi gruppe" }, "groups": { + "add_group": "Legg til gruppe", "add_members": "Legg til medlemmer", "adding_members": "Legger til medlemmer", "caption": "Grupper", @@ -2516,7 +2524,11 @@ "hint_wakeup": "Noen enheter, for eksempel Xiaomi-sensorer, har en vekkingsknapp som du kan trykke på med intervaller på ~ 5 sekunder for å holde enheter våkne mens du samhandler med dem.", "introduction": "Kjør ZHA-kommandoer som påvirker en enkelt enhet. Velg en enhet for å se en liste over tilgjengelige kommandoer." }, - "title": "ZigBee Hjemmeautomasjon" + "title": "ZigBee Hjemmeautomasjon", + "visualization": { + "caption": "Visualisering", + "header": "Nettverksvisualisering" + } }, "zone": { "add_zone": "Legg til sone", diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index 474ce1eb19..9af6104470 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "Wprowadź adres URL schematu.", + "file_name": "Nazwa lokalnego pliku schematu", "header": "Dodaj nowy schemat", "import_btn": "Importuj schemat", - "import_header": "Importuj {name} ({domain})", + "import_header": "Importuj \"{name}\" (typ: {domain})", "import_introduction": "Możesz importować schematy innych użytkowników z Githuba i forów społecznościowych. Wprowadź poniżej adres URL schematu.", "importing": "Importowanie schematu...", + "raw_blueprint": "Zawartość schematu", "save_btn": "Zapisz schemat", "saving": "Zapisywanie schematu...", "unsupported_blueprint": "Ten schemat nie jest obsługiwany", @@ -1412,15 +1414,19 @@ "caption": "Schematy", "description": "Zarządzaj schematami", "overview": { - "add_blueprint": "Dodaj schemat", + "add_blueprint": "Importuj schemat", "confirm_delete_header": "Usunąć ten schemat?", "confirm_delete_text": "Czy na pewno chcesz usunąć ten schemat?", + "delete_blueprint": "Usuń schemat", "header": "Edytor schematów", "headers": { + "domain": "Domena", + "file_name": "Nazwa pliku", "name": "Nazwa" }, "introduction": "Edytor schematów pozwala tworzyć i edytować schematy", - "learn_more": "Dowiedz się więcej o schematach" + "learn_more": "Dowiedz się więcej o schematach", + "use_blueprint": "Utwórz automatyzację" } }, "cloud": { @@ -2414,6 +2420,7 @@ "users_privileges_note": "Prace nad grupami użytkowników trwają. Użytkownik nie może administrować instancją za pomocą interfejsu użytkownika. Nadal kontrolujemy wszystkie punkty końcowe interfejsu API zarządzania, aby upewnić się, że poprawnie ograniczają dostęp tylko dla administratorów." }, "zha": { + "add_device": "Dodaj urządzenie", "add_device_page": { "discovered_text": "Urządzenia pojawią się tutaj, jak tylko zostaną wykryte.", "discovery_text": "Wykryte urządzenia pojawią się tutaj. Postępuj zgodnie z instrukcjami dla urządzeń, by wprowadzić je w tryb parowania.", @@ -2474,6 +2481,7 @@ "unbind_button_label": "Usuń powiązanie grupy" }, "groups": { + "add_group": "Dodaj grupę", "add_members": "Dodaj członków", "adding_members": "Dodawanie członków", "caption": "Grupy", @@ -2516,7 +2524,11 @@ "hint_wakeup": "Niektóre urządzenia, takie jak czujniki Xiaomi, mają przycisk wybudzania, który można naciskać w odstępach co około 5 sekund, dzięki czemu urządzenia pozostają w stanie czuwania podczas interakcji z nimi.", "introduction": "Uruchom polecenia ZHA, które wpływają na pojedyncze urządzenie. Wybierz urządzenie, aby wyświetlić listę dostępnych poleceń." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Wizualizacja", + "header": "Wizualizacja sieci" + } }, "zone": { "add_zone": "Dodaj strefę", diff --git a/translations/frontend/ro.json b/translations/frontend/ro.json index 6bd0548b8a..0fb42b56da 100644 --- a/translations/frontend/ro.json +++ b/translations/frontend/ro.json @@ -835,6 +835,7 @@ "description": "Privire de ansamblu asupra tuturor zonelor din casa ta.", "editor": { "create": "Creează", + "default_name": "Zona nouă", "delete": "Șterge", "update": "Actualizare" }, @@ -843,12 +844,13 @@ "header": "Zone", "integrations_page": "Pagina de integrari", "introduction": "Zonele sunt folosite pentru a organiza unde sunt dispozitivele. Aceste informații vor fi utilizate de către Home Assistant pentru a vă ajuta să vă organizați interfața, permisiunile și integrarea cu alte sisteme.", - "introduction2": "Pentru a plasa dispozitive într-o zonă, utilizați link-ul de mai jos pentru a naviga la pagina de integrare și apoi faceți clic pe o integrare configurată pentru a ajunge la cardurile dispozitivului." + "introduction2": "Pentru a plasa dispozitive într-o zonă, utilizați link-ul de mai jos pentru a naviga la pagina de integrare și apoi faceți clic pe o integrare configurată pentru a ajunge la cardurile dispozitivului.", + "no_areas": "Se pare că nu ai nici o zonă încă!" } }, "automation": { "caption": "Automatizări", - "description": "Creați și editați scripturi", + "description": "Gestionarea automatizărilor", "editor": { "actions": { "add": "Adăugați o acțiune", @@ -942,7 +944,8 @@ "device": { "extra_fields": { "above": "De mai sus", - "below": "De mai jos" + "below": "De mai jos", + "for": "Durată" }, "label": "Dispozitiv" }, @@ -1035,6 +1038,7 @@ "label": "Dispozitiv" }, "event": { + "context_user_pick": "Selectare utilizatorul", "event_data": "Date eveniment", "event_type": "Tip eveniment", "label": "Eveniment" @@ -1125,23 +1129,63 @@ "show_info_automation": "Afișați informații despre automatizare" } }, + "blueprint": { + "add": { + "url": "Adresa URL a planului" + }, + "overview": { + "add_blueprint": "Importați planul", + "confirm_delete_text": "Sigur doriți să ștergeți acest plan?" + } + }, "cloud": { "account": { "alexa": { "config_documentation": "Documentație de configurare", + "enable_ha_skill": "Activați abilitatea Home Assistant pentru Alexa", "manage_entities": "Gestionați entități", "state_reporting_error": "Imposibil de {enable_disable} stare raport.", - "sync_entities_error": "Sincronizarea entităților nu a reușit:" + "sync_entities": "Sincronizează entități", + "sync_entities_error": "Sincronizarea entităților nu a reușit:", + "title": "Alexa" }, + "fetching_subscription": "Preluare abonament...", "google": { "config_documentation": "Documentație de configurare", "sync_entities_404_message": "Sincronizarea entităților cu Google nu a reușit, cereți Google \"Hey Google, sync my devices\" să vă sincronizeze entitățile." + }, + "not_connected": "Nu este conectat", + "remote": { + "certificate_info": "Informații despre certificat", + "link_learn_how_it_works": "Aflați cum funcționează" } }, "caption": "Home Assistant Cloud", "description_features": "Controlați-vă casa de la distanta, integrați-vă cu Alexa și Asistentul Google.", "description_login": "Logat ca {email}", - "description_not_login": "Nu sunteți conectat (ă)" + "description_not_login": "Nu sunteți conectat (ă)", + "forgot_password": { + "instructions": "Introduceți adresa de e-mail și vă vom trimite un link pentru a vă reseta parola.", + "subtitle": "Ti-ai uitat parola", + "title": "Parolă uitată" + }, + "login": { + "alert_email_confirm_necessary": "Trebuie să vă confirmați adresa de e-mail înainte de a vă conecta.", + "alert_password_change_required": "Trebuie să vă schimbați parola înainte de a vă conecta.", + "email": "E-mail", + "email_error_msg": "E-mail invalid", + "forgot_password": "Ați uitat parola?", + "introduction": "Home Assistant Cloud vă oferă o conexiune la distanță sigură la instanța dvs. în timp ce sunteți departe de casă. De asemenea, vă permite să vă conectați cu servicii numai cloud: Amazon Alexa și Google Assistant.", + "introduction2": "Acest serviciu este administrat de partenerul nostru ", + "introduction2a": ", o companie fondată de fondatorii Home Assistant și Hass.io.", + "introduction3": "Home Assistant Cloud este un serviciu de abonament cu o perioadă de încercare gratuită de o lună. Nu sunt necesare informații de plată.", + "learn_more_link": "Aflați mai multe despre Cloud Assistant Home", + "password": "Parolă", + "password_error_msg": "Parolele au cel puțin 8 caractere", + "sign_in": "Conectează-te", + "start_trial": "Începeți perioada de încercare gratuită de 1 lună", + "trial_info": "Nu sunt necesare informații de plată" + } }, "core": { "caption": "General", @@ -1337,6 +1381,19 @@ "license": "Publicat sub licenta Apache 2.0", "server": "Server", "source": "Sursă:", + "system_health": { + "checks": { + "homeassistant": { + "hassio": "HassOS", + "installation_type": "Tipul de instalare", + "timezone": "Fus orar", + "version": "Versiune" + }, + "lovelace": { + "resources": "Resurse" + } + } + }, "title": "Info" }, "integration_panel_move": { @@ -1632,6 +1689,7 @@ "heading": "Reîncărcarea configurației YAML", "introduction": "Unele părți din Home Assistant se pot reîncărca fără a necesita o repornire. Apăsarea reîncărcării va descărca configurația actuală și va încărca noua configurație.", "person": "Reîncărcare persoane", + "rest": "Reîncărcați entitățile în repaus și notificați serviciile", "scene": "Reîncărcați scenarii", "script": "Reîncărcați script-uri", "zone": "Reîncărcare zone" @@ -2040,6 +2098,10 @@ "state_equal": "Starea este egala cu", "state_not_equal": "Starea nu este egala cu" }, + "config": { + "optional": "Opțional", + "required": "Necesar" + }, "entities": { "description": "Cardul Entities este cel mai comun tip de card. Acesta grupează elementele împreună în liste.", "edit_special_row": "Vizualizați detaliile acestui rând făcând clic pe butonul de editare", @@ -2064,11 +2126,20 @@ "name": "Entitate" }, "gauge": { - "description": "Cardul Gauge este un card de bază care permite vizualizarea vizuală a datelor senzorilor." + "description": "Cardul Gauge este un card de bază care permite vizualizarea vizuală a datelor senzorilor.", + "severity": { + "green": "Verde", + "red": "Roşu", + "yellow": "Galben" + } }, "generic": { + "aspect_ratio": "Raport de aspect", "attribute": "Atribut", + "camera_image": "Entitate cameră", + "camera_view": "Vizualizare cameră", "double_tap_action": "Acțiune atingere dublă", + "entities": "Entități", "entity": "Entitate", "hold_action": "Suspendare acțiunii", "hours_to_show": "Ore de afișat", @@ -2078,14 +2149,23 @@ "manual": "Manual", "manual_description": "Trebuie să adăugați un card personalizat sau doriți doar să scrieți manual yaml?", "maximum": "Maximă", + "minimum": "Valoare minimă", + "name": "Nume", "no_theme": "Nicio temă", + "refresh_interval": "Interval de reîmprospătare", "search": "Căutare", "secondary_info_attribute": "Atribut informații secundare", + "show_icon": "Afișați pictograma?", + "show_name": "Arată numele?", + "show_state": "Arată de starea?", "state": "Stare", + "theme": "Tema", + "title": "Titlu", "unit": "Unitate", "url": "Url" }, "glance": { + "columns": "Coloane", "description": "Cardul Glance este util pentru a grupa mai mulți senzori într-o imagine de ansamblu compactă.", "name": "Privire rapida" }, @@ -2108,12 +2188,15 @@ }, "map": { "dark_mode": "Modul întunecat?", + "default_zoom": "Zoom implicit", "description": "Cardul Map care vă permite să afișați entități pe o hartă.", "geo_location_sources": "Surse de geolocalizare", "hours_to_show": "Ore de afisat", - "name": "Hartă" + "name": "Hartă", + "source": "Sursă" }, "markdown": { + "content": "Conţinut", "description": "Cardul Markdown este utilizat pentru a reda Markdown." }, "media-control": { @@ -2137,6 +2220,8 @@ }, "sensor": { "description": "Cardul Senzor vă oferă o imagine de ansamblu rapidă a stării senzorilor cu un grafic opțional pentru a vizualiza schimbarea în timp.", + "graph_detail": "Detaliu grafic", + "graph_type": "Tip grafic", "name": "Senzor", "show_more_detail": "Afișați mai multe detalii" }, @@ -2194,6 +2279,13 @@ } }, "header": "Editați interfața utilizator", + "header-footer": { + "types": { + "graph": { + "name": "Grafic" + } + } + }, "menu": { "open": "Deschideți meniul Lovelace UI", "raw_editor": "Editor de configurare brut" @@ -2577,6 +2669,10 @@ "link_promo": "Aflați mai multe despre teme", "primary_color": "Culoare primară", "reset": "Resetați" + }, + "vibrate": { + "description": "Activați sau dezactivați vibrațiile de pe acest dispozitiv atunci când controlați dispozitivele.", + "header": "Vibrați" } }, "shopping-list": { diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index 95b90d2c8e..d211e8f75a 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -2363,6 +2363,7 @@ "users_privileges_note": "Функционал пользователей всё ещё в стадии разработки. В дальнейшем пользователи не смогут администрировать сервер через пользовательский интерфейс. Мы все еще проверяем все конечные точки API управления, чтобы убедиться, что они правильно ограничивают доступ." }, "zha": { + "add_device": "Добавить устройство", "add_device_page": { "discovered_text": "Устройства появятся здесь, когда будут обнаружены.", "discovery_text": "Здесь будут отображаться обнаруженные устройства. Следуйте инструкциям для Вашего устройства, чтобы включить режим сопряжения.", @@ -2423,6 +2424,7 @@ "unbind_button_label": "Отвязать группу" }, "groups": { + "add_group": "Добавить группу", "add_members": "Добавить участников", "adding_members": "Добавление участников", "caption": "Группы", @@ -2465,7 +2467,11 @@ "hint_wakeup": "Некоторые устройства, такие как датчики Xiaomi, имеют кнопку пробуждения, которую Вы можете нажимать с интервалом ~ 5 секунд, чтобы держать устройства в активном состоянии во время взаимодействия с ними.", "introduction": "Команды ZHA, которые влияют на одно устройство. Выберите устройство, чтобы увидеть список доступных команд." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Визуализация", + "header": "Визуализация сети" + } }, "zone": { "add_zone": "Добавить зону", diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index 48236e5603..98a1ed3039 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "请输入 Blueprint 的网址。", + "file_name": "本地 Blueprint 文件名", "header": "添加新的 Blueprint", "import_btn": "导入 Blueprint", - "import_header": "导入 {name} ({domain})", + "import_header": "导入 \"{name}\" (类型为 {domain})", "import_introduction": "您可以从 Github 和社区论坛导入其他用户的 Blueprint。请在下方输入 Blueprint 的网址。", "importing": "正在导入 Blueprint...", + "raw_blueprint": "Blueprint 内容", "save_btn": "保存 Blueprint", "saving": "正在保存 Blueprint...", "unsupported_blueprint": "此 Blueprint 不受支持", @@ -1415,12 +1417,16 @@ "add_blueprint": "添加 Blueprint", "confirm_delete_header": "删除此 Blueprint?", "confirm_delete_text": "您确定要删除此 Blueprint 吗?", + "delete_blueprint": "删除 Blueprint", "header": "Blueprint 编辑器", "headers": { + "domain": "域", + "file_name": "文件名", "name": "名称" }, "introduction": "Blueprint 编辑器方便您创建和编辑 Blueprint。", - "learn_more": "详细了解 Blueprint" + "learn_more": "详细了解 Blueprint", + "use_blueprint": "创建自动化" } }, "cloud": { @@ -2414,6 +2420,7 @@ "users_privileges_note": "用户组功能正在开发中。该功能使普通用户无法通过 UI 进行管理操作。我们正在审计所有管理 API,确保其仅限管理员访问。" }, "zha": { + "add_device": "添加设备", "add_device_page": { "discovered_text": "发现的设备会立即显示在这里。", "discovery_text": "发现的设备将显示在这里。请按照设备的说明进行操作,将设备置于配对模式。", @@ -2474,6 +2481,7 @@ "unbind_button_label": "取消绑定群组" }, "groups": { + "add_group": "添加群组", "add_members": "添加成员", "adding_members": "添加成员中", "caption": "群组", @@ -2516,7 +2524,11 @@ "hint_wakeup": "小米传感器等某些设备具有唤醒按钮,您可以每隔约 5 秒按一下此按钮,以便在与设备交互时保持设备唤醒。", "introduction": "运行影响单个设备的 ZHA 命令。请选择设备以查看可用命令列表。" }, - "title": "Zigbee 家庭自动化" + "title": "Zigbee 家庭自动化", + "visualization": { + "caption": "可视化", + "header": "网络可视化" + } }, "zone": { "add_zone": "添加地点", diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index db4565edec..0e57b9faae 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -1399,11 +1399,13 @@ "blueprint": { "add": { "error_no_url": "請輸入 Blueprint 之 URL。", + "file_name": "區域 Blueprint 檔案名稱", "header": "新增 Blueprint", "import_btn": "匯入 Blueprint", - "import_header": "匯入 {name} ({domain})", + "import_header": "匯入 \"{name}\" (類型:{domain})", "import_introduction": "可以自 Github 及社群論壇匯入其他使用者的 Blueprint。於下方輸入 Blueprint 之URL。", "importing": "正在匯入 Blueprint...", + "raw_blueprint": "Blueprint 內容", "save_btn": "儲存 Blueprint", "saving": "正在儲存 Blueprint...", "unsupported_blueprint": "不支援此 Blueprint", @@ -1412,15 +1414,19 @@ "caption": "Blueprint", "description": "管理 Blueprint", "overview": { - "add_blueprint": "新增 Blueprint", + "add_blueprint": "匯入 Blueprint", "confirm_delete_header": "刪除此 Blueprint?", - "confirm_delete_text": "確定要刪除此 Blueprint", + "confirm_delete_text": "確定要刪除此 Blueprint?", + "delete_blueprint": "刪除 Blueprint", "header": "Blueprint 編輯器", "headers": { + "domain": "實體類群", + "file_name": "檔案名稱", "name": "名稱" }, "introduction": "Blueprint 編輯器可允許新增與編輯 Blueprint。", - "learn_more": "詳細了解 Blueprint" + "learn_more": "詳細了解 Blueprint", + "use_blueprint": "新增自動化" } }, "cloud": { @@ -2414,6 +2420,7 @@ "users_privileges_note": "使用者群組功能仍在開發中。將無法透過 UI 進行使用者管理,仍在檢視所有管理 API Endpoint 以確保能夠正確符合管理員存取需求。" }, "zha": { + "add_device": "新增設備", "add_device_page": { "discovered_text": "在探索到裝置後將顯示於此處。", "discovery_text": "所發現的設備將會顯示於此。跟隨設備的指示並將其設定為配對模式。", @@ -2474,6 +2481,7 @@ "unbind_button_label": "解除綁定群組" }, "groups": { + "add_group": "新增群組", "add_members": "新增成員", "adding_members": "新增成員", "caption": "群組", @@ -2516,7 +2524,11 @@ "hint_wakeup": "在您進行互動時某些裝置(例如小米感應器)有喚醒按鈕、可藉由每隔約 5 秒按一下、以保持該裝置處於喚醒狀態。", "introduction": "執行 ZHA 命命將影響單一設備。選擇設備以檢視該設備可使用之命令。" }, - "title": "Zigbee 家庭自動化" + "title": "Zigbee 家庭自動化", + "visualization": { + "caption": "形象化", + "header": "網路形象化" + } }, "zone": { "add_zone": "新增區域", From b5724ed343e34bb26dea40559b49ddf4af9676cf Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sat, 28 Nov 2020 17:22:42 +0100 Subject: [PATCH 05/38] Make fab blue (#7839) --- src/components/ha-fab.ts | 20 +++++++++++++++++ .../media-player/ha-media-player-browse.ts | 10 ++++----- .../config/areas/ha-config-areas-dashboard.ts | 6 ++--- .../automation/blueprint-automation-editor.ts | 22 ------------------- .../config/automation/ha-automation-editor.ts | 13 +++++------ .../config/automation/ha-automation-picker.ts | 6 ++--- .../automation/manual-automation-editor.ts | 22 ------------------- .../config/blueprint/ha-blueprint-overview.ts | 6 ++--- .../config/helpers/ha-config-helpers.ts | 6 ++--- .../integrations/ha-config-integrations.ts | 6 ++--- .../ozw/ozw-config-dashboard.ts | 1 - .../ozw/ozw-network-dashboard.ts | 1 - .../ozw/ozw-network-nodes.ts | 1 - .../integration-panels/ozw/ozw-node-config.ts | 1 - .../ozw/ozw-node-dashboard.ts | 1 - .../zha/zha-config-dashboard.ts | 6 ++--- .../zha/zha-groups-dashboard.ts | 6 ++--- .../ha-config-lovelace-dashboards.ts | 6 ++--- .../resources/ha-config-lovelace-resources.ts | 6 ++--- src/panels/config/person/ha-config-person.ts | 6 ++--- src/panels/config/scene/ha-scene-dashboard.ts | 6 ++--- src/panels/config/scene/ha-scene-editor.ts | 10 ++++----- src/panels/config/script/ha-script-editor.ts | 10 ++++----- src/panels/config/script/ha-script-picker.ts | 6 ++--- src/panels/config/tags/ha-config-tags.ts | 6 ++--- src/panels/config/users/ha-config-users.ts | 6 ++--- src/panels/config/zone/ha-config-zone.ts | 6 ++--- .../unused-entities/hui-unused-entities.ts | 10 ++++----- .../lovelace/views/default-view-editable.ts | 2 +- src/panels/lovelace/views/hui-masonry-view.ts | 8 +++---- src/panels/lovelace/views/hui-panel-view.ts | 8 +++---- 31 files changed, 99 insertions(+), 131 deletions(-) create mode 100644 src/components/ha-fab.ts diff --git a/src/components/ha-fab.ts b/src/components/ha-fab.ts new file mode 100644 index 0000000000..f0917173a0 --- /dev/null +++ b/src/components/ha-fab.ts @@ -0,0 +1,20 @@ +import type { Fab } from "@material/mwc-fab"; +import "@material/mwc-fab"; +import { customElement } from "lit-element"; +import { Constructor } from "../types"; + +const MwcFab = customElements.get("mwc-fab") as Constructor; + +@customElement("ha-fab") +export class HaFab extends MwcFab { + protected firstUpdated(changedProperties) { + super.firstUpdated(changedProperties); + this.style.setProperty("--mdc-theme-secondary", "var(--primary-color)"); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-fab": HaFab; + } +} diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index 93a5ca25e4..f1fbfab1d6 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -1,5 +1,5 @@ import "@material/mwc-button/mwc-button"; -import "@material/mwc-fab/mwc-fab"; +import "../ha-fab"; import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list-item"; import { mdiArrowLeft, mdiClose, mdiPlay, mdiPlus } from "@mdi/js"; @@ -170,7 +170,7 @@ export class HaMediaPlayerBrowse extends LitElement { > ${this._narrow && currentItem?.can_play ? html` - + ` : ""}
@@ -927,7 +927,7 @@ export class HaMediaPlayerBrowse extends LitElement { transition: width 0.4s, height 0.4s, padding-bottom 0.4s; } - mwc-fab { + ha-fab { position: absolute; --mdc-theme-secondary: var(--primary-color); bottom: -20px; @@ -1011,7 +1011,7 @@ export class HaMediaPlayerBrowse extends LitElement { margin-bottom: 0; } - :host([scroll]) mwc-fab { + :host([scroll]) ha-fab { bottom: 4px; right: 4px; --mdc-fab-box-shadow: none; diff --git a/src/panels/config/areas/ha-config-areas-dashboard.ts b/src/panels/config/areas/ha-config-areas-dashboard.ts index b9de85cb27..66cea0e01b 100644 --- a/src/panels/config/areas/ha-config-areas-dashboard.ts +++ b/src/panels/config/areas/ha-config-areas-dashboard.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { mdiPlus } from "@mdi/js"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; @@ -124,7 +124,7 @@ export class HaConfigAreasDashboard extends LitElement { icon="hass:help-circle" @click=${this._showHelp} > - - + `; } diff --git a/src/panels/config/automation/blueprint-automation-editor.ts b/src/panels/config/automation/blueprint-automation-editor.ts index 2a966254b0..9229069d09 100644 --- a/src/panels/config/automation/blueprint-automation-editor.ts +++ b/src/panels/config/automation/blueprint-automation-editor.ts @@ -278,17 +278,9 @@ export class HaBlueprintAutomationEditor extends LitElement { ha-card { overflow: hidden; } - .errors { - padding: 20px; - font-weight: bold; - color: var(--error-color); - } .padding { padding: 16px; } - .content { - padding-bottom: 20px; - } .blueprint-picker-container { padding: 16px; display: flex; @@ -317,20 +309,6 @@ export class HaBlueprintAutomationEditor extends LitElement { :host(:not([narrow])) ha-settings-row ha-selector { width: 50%; } - mwc-fab { - position: relative; - bottom: calc(-80px - env(safe-area-inset-bottom)); - transition: bottom 0.3s; - } - mwc-fab.dirty { - bottom: 0; - } - .selected_menu_item { - color: var(--primary-color); - } - li[role="separator"] { - border-bottom-color: var(--divider-color); - } `, ]; } diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index a544fc3215..5db46262a8 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { mdiCheck, mdiContentDuplicate, @@ -271,7 +271,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
` : ""} - - + `; } @@ -524,21 +524,18 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { .content { padding-bottom: 20px; } - span[slot="introduction"] a { - color: var(--primary-color); - } p { margin-bottom: 0; } ha-entity-toggle { margin-right: 8px; } - mwc-fab { + ha-fab { position: relative; bottom: calc(-80px - env(safe-area-inset-bottom)); transition: bottom 0.3s; } - mwc-fab.dirty { + ha-fab.dirty { bottom: 0; } .selected_menu_item { diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index e333c5c542..616c4b4b2f 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import { mdiPlus, mdiHelpCircle } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; @@ -170,7 +170,7 @@ class HaAutomationPicker extends LitElement { - - + `; } diff --git a/src/panels/config/automation/manual-automation-editor.ts b/src/panels/config/automation/manual-automation-editor.ts index d32fdf2dae..a3ad1219db 100644 --- a/src/panels/config/automation/manual-automation-editor.ts +++ b/src/panels/config/automation/manual-automation-editor.ts @@ -309,14 +309,6 @@ export class HaManualAutomationEditor extends LitElement { ha-card { overflow: hidden; } - .errors { - padding: 20px; - font-weight: bold; - color: var(--error-color); - } - .content { - padding-bottom: 20px; - } span[slot="introduction"] a { color: var(--primary-color); } @@ -326,20 +318,6 @@ export class HaManualAutomationEditor extends LitElement { ha-entity-toggle { margin-right: 8px; } - mwc-fab { - position: relative; - bottom: calc(-80px - env(safe-area-inset-bottom)); - transition: bottom 0.3s; - } - mwc-fab.dirty { - bottom: 0; - } - .selected_menu_item { - color: var(--primary-color); - } - li[role="separator"] { - border-bottom-color: var(--divider-color); - } `, ]; } diff --git a/src/panels/config/blueprint/ha-blueprint-overview.ts b/src/panels/config/blueprint/ha-blueprint-overview.ts index 4da528173e..ce732ab17d 100644 --- a/src/panels/config/blueprint/ha-blueprint-overview.ts +++ b/src/panels/config/blueprint/ha-blueprint-overview.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import { mdiPlus, mdiHelpCircle, mdiDelete, mdiRobot } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; @@ -174,7 +174,7 @@ class HaBlueprintOverview extends LitElement { - - + `; } diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts index 68da162f1c..5c0fea1581 100644 --- a/src/panels/config/helpers/ha-config-helpers.ts +++ b/src/panels/config/helpers/ha-config-helpers.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { mdiPlus } from "@mdi/js"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; @@ -158,7 +158,7 @@ export class HaConfigHelpers extends LitElement { "ui.panel.config.helpers.picker.no_helpers" )} > - - + `; } diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts index 1759a0a21a..d448668b46 100644 --- a/src/panels/config/integrations/ha-config-integrations.ts +++ b/src/panels/config/integrations/ha-config-integrations.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical, mdiPlus } from "@mdi/js"; @@ -474,7 +474,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { ` : ""} - - + `; } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts index bbf4ba6188..f99c451ca4 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-config-dashboard.ts @@ -1,5 +1,4 @@ import "@material/mwc-button/mwc-button"; -import "@material/mwc-fab"; import { mdiCheckCircle, mdiCircle, mdiCloseCircle, mdiZWave } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts index fccaa04a7f..655d1fae01 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-dashboard.ts @@ -1,5 +1,4 @@ import "@material/mwc-button/mwc-button"; -import "@material/mwc-fab"; import { mdiCheckCircle, mdiCircle, mdiCloseCircle } from "@mdi/js"; import { css, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts index bd796519a4..53155318c4 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-nodes.ts @@ -1,5 +1,4 @@ import "@material/mwc-button/mwc-button"; -import "@material/mwc-fab"; import { mdiAlert, mdiCheck } from "@mdi/js"; import { CSSResult, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts index 5eb89a30bb..3cb884f0d7 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts @@ -1,5 +1,4 @@ import "@material/mwc-button/mwc-button"; -import "@material/mwc-fab"; import { css, CSSResultArray, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index 7ac930d8b4..38f94c906f 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -1,5 +1,4 @@ import "@material/mwc-button/mwc-button"; -import "@material/mwc-fab"; import { css, CSSResultArray, diff --git a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts index 10d68ef551..29d956ceb4 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts @@ -1,6 +1,6 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import "@material/mwc-fab"; +import "../../../../../components/ha-fab"; import { css, CSSResultArray, @@ -88,13 +88,13 @@ class ZHAConfigDashboard extends LitElement { : ""} - - + `; diff --git a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts index 3ece6f2a7c..909cb7aecf 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts @@ -1,5 +1,5 @@ import "@material/mwc-button"; -import "@material/mwc-fab"; +import "../../../../../components/ha-fab"; import "../../../../../components/ha-icon-button"; import memoizeOne from "memoize-one"; import { @@ -127,14 +127,14 @@ export class ZHAGroupsDashboard extends LitElement { clickable > - - + `; diff --git a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts index a0dd5f05dc..87af0ef6bf 100644 --- a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts +++ b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../../components/ha-fab"; import { mdiPlus } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; import { @@ -223,7 +223,7 @@ export class HaConfigLovelaceDashboards extends LitElement { hasFab clickable > - - + `; } diff --git a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts index 96a9faa036..c0f81a18f7 100644 --- a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts +++ b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../../components/ha-fab"; import { mdiPlus } from "@mdi/js"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; @@ -103,7 +103,7 @@ export class HaConfigLovelaceRescources extends LitElement { hasFab clickable > - - + `; } diff --git a/src/panels/config/person/ha-config-person.ts b/src/panels/config/person/ha-config-person.ts index 3ae66b1d24..013b7dabd8 100644 --- a/src/panels/config/person/ha-config-person.ts +++ b/src/panels/config/person/ha-config-person.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { mdiPlus } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; @@ -146,14 +146,14 @@ class HaConfigPerson extends LitElement { ` : ""} - - + `; } diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index fdbc0c3f23..879f1893cd 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import { mdiPlus, mdiHelpCircle } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; @@ -152,14 +152,14 @@ class HaSceneDashboard extends LitElement { - - + `; diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 1781e62ac9..73b0d2cae6 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -25,7 +25,7 @@ import "../../../components/device/ha-device-picker"; import "../../../components/entity/ha-entities-picker"; import "../../../components/ha-card"; import "../../../components/ha-icon-input"; -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { computeDeviceName, DeviceRegistryEntry, @@ -403,7 +403,7 @@ export class HaSceneEditor extends SubscribeMixin( ` : ""} - - + `; } @@ -786,12 +786,12 @@ export class HaSceneEditor extends SubscribeMixin( span[slot="introduction"] a { color: var(--primary-color); } - mwc-fab { + ha-fab { position: relative; bottom: calc(-80px - env(safe-area-inset-bottom)); transition: bottom 0.3s; } - mwc-fab.dirty { + ha-fab.dirty { bottom: 0; } `, diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 5dd2a99083..1ed2095ef8 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { mdiCheck, mdiContentSave, @@ -388,7 +388,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { ` : ``} - - + `; } @@ -690,12 +690,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { span[slot="introduction"] a { color: var(--primary-color); } - mwc-fab { + ha-fab { position: relative; bottom: calc(-80px - env(safe-area-inset-bottom)); transition: bottom 0.3s; } - mwc-fab.dirty { + ha-fab.dirty { bottom: 0; } .selected_menu_item { diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index d261cc82f5..6718ef9682 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -16,7 +16,7 @@ import { fireEvent } from "../../../common/dom/fire_event"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { computeRTL } from "../../../common/util/compute_rtl"; import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table"; -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { triggerScript } from "../../../data/script"; import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/hass-tabs-subpage-data-table"; @@ -147,7 +147,7 @@ class HaScriptPicker extends LitElement { - - + `; diff --git a/src/panels/config/tags/ha-config-tags.ts b/src/panels/config/tags/ha-config-tags.ts index 9a30fc06fe..50c971eb10 100644 --- a/src/panels/config/tags/ha-config-tags.ts +++ b/src/panels/config/tags/ha-config-tags.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import { mdiCog, @@ -207,14 +207,14 @@ export class HaConfigTags extends SubscribeMixin(LitElement) { - - + `; } diff --git a/src/panels/config/users/ha-config-users.ts b/src/panels/config/users/ha-config-users.ts index c870804c7f..55dbb018e2 100644 --- a/src/panels/config/users/ha-config-users.ts +++ b/src/panels/config/users/ha-config-users.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import { mdiPlus } from "@mdi/js"; import { customElement, @@ -112,14 +112,14 @@ export class HaConfigUsers extends LitElement { hasFab clickable > - - + `; } diff --git a/src/panels/config/zone/ha-config-zone.ts b/src/panels/config/zone/ha-config-zone.ts index c96a3ec8f1..94864843bf 100644 --- a/src/panels/config/zone/ha-config-zone.ts +++ b/src/panels/config/zone/ha-config-zone.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import { mdiPencil, mdiPencilOff, mdiPlus } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; @@ -255,14 +255,14 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ` : ""} - - + `; } diff --git a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts index d9e0ea7b77..b13d38e4f1 100644 --- a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts +++ b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts @@ -1,4 +1,4 @@ -import "@material/mwc-fab"; +import "../../../../components/ha-fab"; import { css, CSSResult, @@ -108,13 +108,13 @@ export class HuiUnusedEntities extends LitElement { selected: this._selectedEntities.length, })}" > - - + `; } @@ -189,12 +189,12 @@ export class HuiUnusedEntities extends LitElement { padding-right: 16px; padding-left: calc(16px + env(safe-area-inset-left)); } - mwc-fab { + ha-fab { position: relative; bottom: calc(-80px - env(safe-area-inset-bottom)); transition: bottom 0.3s; } - .fab.selected mwc-fab { + .fab.selected ha-fab { bottom: 0; } `; diff --git a/src/panels/lovelace/views/default-view-editable.ts b/src/panels/lovelace/views/default-view-editable.ts index 8fbb84c0be..d32e0774b4 100644 --- a/src/panels/lovelace/views/default-view-editable.ts +++ b/src/panels/lovelace/views/default-view-editable.ts @@ -1,3 +1,3 @@ // hui-view dependencies for when in edit mode. -import "@material/mwc-fab"; +import "../../../components/ha-fab"; import "../components/hui-card-options"; diff --git a/src/panels/lovelace/views/hui-masonry-view.ts b/src/panels/lovelace/views/hui-masonry-view.ts index 548b3d55b2..b160ef9766 100644 --- a/src/panels/lovelace/views/hui-masonry-view.ts +++ b/src/panels/lovelace/views/hui-masonry-view.ts @@ -83,7 +83,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
${this.lovelace?.editMode ? html` - - + ` : ""} `; @@ -296,7 +296,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement { margin: 4px 4px 8px; } - mwc-fab { + ha-fab { position: sticky; float: right; right: calc(16px + env(safe-area-inset-right)); @@ -304,7 +304,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement { z-index: 1; } - mwc-fab.rtl { + ha-fab.rtl { float: left; right: auto; left: calc(16px + env(safe-area-inset-left)); diff --git a/src/panels/lovelace/views/hui-panel-view.ts b/src/panels/lovelace/views/hui-panel-view.ts index 0edfff7799..f9884543dc 100644 --- a/src/panels/lovelace/views/hui-panel-view.ts +++ b/src/panels/lovelace/views/hui-panel-view.ts @@ -75,7 +75,7 @@ export class PanelView extends LitElement implements LovelaceViewElement { ${this._card} ${this.lovelace?.editMode && this.cards.length === 0 ? html` - - + ` : ""} `; @@ -137,7 +137,7 @@ export class PanelView extends LitElement implements LovelaceViewElement { height: 100%; } - mwc-fab { + ha-fab { position: sticky; float: right; right: calc(16px + env(safe-area-inset-right)); @@ -145,7 +145,7 @@ export class PanelView extends LitElement implements LovelaceViewElement { z-index: 1; } - mwc-fab.rtl { + ha-fab.rtl { float: left; right: auto; left: calc(16px + env(safe-area-inset-left)); From 4c4db46aa8f2809166c3dc65f03ead8ed20c175e Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Sun, 29 Nov 2020 00:32:38 +0000 Subject: [PATCH 06/38] [ci skip] Translation update --- translations/frontend/cs.json | 29 +++++++++++++++++-------- translations/frontend/es.json | 15 ++++++++----- translations/frontend/et.json | 35 ++++++++++++++++++++++-------- translations/frontend/fr.json | 35 +++++++++++++++++++++++------- translations/frontend/nl.json | 28 ++++++++++++------------ translations/frontend/pl.json | 13 +++++++---- translations/frontend/ru.json | 9 ++++++-- translations/frontend/zh-Hans.json | 13 +++++++---- translations/frontend/zh-Hant.json | 13 +++++++---- 9 files changed, 131 insertions(+), 59 deletions(-) diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index da824008c5..9c3fd24d21 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Vlastník", "system-admin": "Správci", "system-read-only": "Uživatelé jen pro čtení", "system-users": "Uživatelé" @@ -1229,7 +1230,7 @@ "edit_ui": "Upravit pomocí uživatelského rozhraní", "edit_yaml": "Upravit jako YAML", "enable_disable": "Povolit / zakázat automatizaci", - "introduction": "Použijte automatizace k oživení svého domova", + "introduction": "Pomocí automatizací oživte svůj domov.", "load_error_not_editable": "Lze upravovat pouze automatizace v automations.yaml.", "load_error_unknown": "Chyba při načítání automatizace ({err_no}).", "max": { @@ -1391,7 +1392,7 @@ "error_no_url": "Zadejte adresu URL šablonky konfigurace", "header": "Přidat novou šablonku konfigurace", "import_btn": "Importovat šablonku konfigurace", - "import_header": "Importovat {name} ({domain})", + "import_header": "Importovat \"{name}\" (typ: {domain})", "import_introduction": "Z Githubu a komunitních fór můžete importovat šablonky konfigurace sdílené ostatními uživateli. Zadejte adresu URL šablonky konfigurace.", "importing": "Importuje se šablonka konfigurace", "save_btn": "Uložit šablonku konfigurace", @@ -1399,10 +1400,10 @@ "url": "URL šablonky konfigurace" }, "overview": { - "add_blueprint": "Přidat šablonku konfigurace", "confirm_delete_header": "Odstranit tuto šablonku konfigurace?", - "confirm_delete_text": "Opravdu chcete smazat tuto šablonku konfigurace?", "headers": { + "domain": "Doména", + "file_name": "Název souboru", "name": "Jméno" }, "learn_more": "Další informace o šablonkách konfigurace" @@ -2378,7 +2379,7 @@ "delete_user": "Odstranit uživatele", "group": "Skupina", "id": "ID", - "name": "Jméno", + "name": "Zobrazované jméno", "new_password": "Nové heslo", "owner": "Vlastník", "password_changed": "Heslo bylo změněno", @@ -2386,19 +2387,24 @@ "system_generated_users_not_editable": "Nelze aktualizovat uživatele generované systémem.", "system_generated_users_not_removable": "Nelze odebrat uživatele generované systémem.", "unnamed_user": "Nepojmenovaný uživatel", - "update_user": "Aktualizovat" + "update_user": "Aktualizovat", + "username": "Uživatelské jméno" }, "picker": { "add_user": "Přidat uživatele", "headers": { "group": "Skupina", - "name": "Název", - "system": "Systémový" + "is_active": "Aktivní", + "is_owner": "Vlastník", + "name": "Zobrazované jméno", + "system": "Vygenerovaný systémem", + "username": "Uživatelské jméno" } }, "users_privileges_note": "Skupiny uživatelů jsou v přípravě. Uživatel je nebude moci spravovat prostřednictvím uživatelského rozhraní. Stále kontrolujeme API pro správu, abychom zajistili, že správně omezuje přístup pouze pro administrátory." }, "zha": { + "add_device": "Přidat zařízení", "add_device_page": { "discovered_text": "Jakmile se objeví nalezne, zobrazí se zde.", "discovery_text": "Zde se objeví nalezená zařízení. Postupujte dle pokynů pro vaše zařízení a uveďte je do režimu párování.", @@ -2459,6 +2465,7 @@ "unbind_button_label": "Odpojit skupinu" }, "groups": { + "add_group": "Přidat do skupiny", "add_members": "Přidání členů", "adding_members": "Přidání členů", "caption": "Skupiny", @@ -2501,7 +2508,11 @@ "hint_wakeup": "Některá zařízení, jako jsou senzory Xiaomi, mají tlačítko probuzení, které můžete stisknout v intervalu ~ 5 sekund, které udržuje zařízení probuzené, když s nimi komunikujete.", "introduction": "Spouštějte ZHA příkazy, které ovlivňují specifické zařízení. Vyberte zařízení pro zobrazení seznamu dostupných příkazů." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Vizualizace", + "header": "Vizualizace sítě" + } }, "zone": { "add_zone": "Přidat zónu", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index ce0c96f4ec..e7b0499ff7 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Propietario", "system-admin": "Administradores", "system-read-only": "Usuarios de solo lectura", "system-users": "Usuarios" @@ -2215,7 +2216,7 @@ "without_device": "Entidades sin dispositivo" }, "icon": "Icono", - "introduction": "Usa escenas para dar vida a tu hogar.", + "introduction": "Usa escenas para darle vida a tu hogar.", "load_error_not_editable": "Solo las escenas de scenes.yaml son editables.", "load_error_unknown": "Error al cargar la escena ({err_no}).", "name": "Nombre", @@ -2399,7 +2400,7 @@ "delete_user": "Eliminar usuario", "group": "Grupo", "id": "ID", - "name": "Nombre", + "name": "Nombre para mostrar", "new_password": "Nueva contraseña", "owner": "Propietario", "password_changed": "La contraseña se ha cambiado correctamente", @@ -2407,14 +2408,18 @@ "system_generated_users_not_editable": "No se pueden actualizar los usuarios generados por el sistema.", "system_generated_users_not_removable": "No se pueden eliminar los usuarios generados por el sistema.", "unnamed_user": "Usuario sin nombre", - "update_user": "Actualizar" + "update_user": "Actualizar", + "username": "Nombre de usuario" }, "picker": { "add_user": "Añadir usuario", "headers": { "group": "Grupo", - "name": "Nombre", - "system": "Sistema" + "is_active": "Activo", + "is_owner": "Propietario", + "name": "Nombre para mostrar", + "system": "Generado por el sistema", + "username": "Nombre de usuario" } }, "users_privileges_note": "El grupo de usuarios es un trabajo en progreso. El usuario no podrá administrar la instancia a través de la IU. Todavía estamos auditando todos los endpoints de la API de administración para garantizar que se limita correctamente el acceso sólo a los administradores." diff --git a/translations/frontend/et.json b/translations/frontend/et.json index 7e92253f03..fa58be1404 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Omanik", "system-admin": "Administraatorid", "system-read-only": "Ainult lugemisõigusega kasutajad", "system-users": "Kasutajad" @@ -967,7 +968,7 @@ "manuf": "{manufacturer} järgi", "no_area": "Ala puudub", "power_source": "Toiteallikas", - "quirk": "Erim", + "quirk": "Pistikäpp", "services": { "reconfigure": "Taasseadista (tervenda) ZHA seade. Kasuta seda, kui seadmega on probleeme. Kui seade on akutoitega, siis veendu, et see oleks ärkvel ja oleks valmis käske vastu võtma.", "remove": "Eemalda seade Zigbee võrgust.", @@ -1399,11 +1400,13 @@ "blueprint": { "add": { "error_no_url": "Sisesta kavandi URL.", + "file_name": "Kohaliku kavandifaili nimi", "header": "Uue kavandi lisamine", "import_btn": "Impordi kavand", - "import_header": "Impordi {name} ( {domain} )", + "import_header": "Impordi {name} ( type:{domain} )", "import_introduction": "Teiste kasutajate kavandeid saad importida Githubist ja kogukonna foorumitest. Sisesta alloleva kavandi URL.", "importing": "Kavandi importimine ...", + "raw_blueprint": "Kavandi sisu", "save_btn": "Salvesta kavand", "saving": "Kavandi salvestamine ...", "unsupported_blueprint": "Seda kavandit ei toetata", @@ -1412,15 +1415,19 @@ "caption": "", "description": "Kavandite haldamine", "overview": { - "add_blueprint": "Lisa kavand", + "add_blueprint": "Laadi kavand", "confirm_delete_header": "Kas kustutada see kavand?", "confirm_delete_text": "Kas soovid kindlasti selle kavandi kustutada?", + "delete_blueprint": "Kustuta kavand", "header": "Kavandi redaktor", "headers": { + "domain": "Domeen", + "file_name": "Faili nimi", "name": "Nimi" }, "introduction": "Kavandite redaktor võimaldab luua ja muuta kavandeid.", - "learn_more": "Lisateave kavandite kohta" + "learn_more": "Lisateave kavandite kohta", + "use_blueprint": "Loo automatiseering" } }, "cloud": { @@ -2393,7 +2400,7 @@ "delete_user": "Kustuta kasutaja", "group": "Grupp", "id": "ID", - "name": "Nimi", + "name": "Kuvatav nimi", "new_password": "Uus salasõna", "owner": "Omanik", "password_changed": "Salasõna muutmine õnnestus", @@ -2401,19 +2408,24 @@ "system_generated_users_not_editable": "Süsteemi loodud kasutajaid ei saa värskendada.", "system_generated_users_not_removable": "Süsteemi loodud kasutajaid ei saa eemaldada.", "unnamed_user": "Nimetu kasutaja", - "update_user": "Uuenda" + "update_user": "Uuenda", + "username": "Kasutajanimi" }, "picker": { "add_user": "Lisa kasutaja", "headers": { "group": "Grupp", - "name": "Nimi", - "system": "Süsteem" + "is_active": "Aktiivne", + "is_owner": "Omanik", + "name": "Kuvatav nimi", + "system": "Süsteemi poolt loodud", + "username": "Kasutajanimi" } }, "users_privileges_note": "Kasutajarühma funktsioon on pooleli. Kasutajal ei ole võimalik kasutajaliidese kaudu Home Assistanti hallata. Auditeerime endiselt kõiki haldus-API lõpp-punkte tagamaks, et need lubaks juurdepääsu ainult administraatoritele." }, "zha": { + "add_device": "Lisa seade", "add_device_page": { "discovered_text": "Seadmed ilmuvad siia kui avastatakse.", "discovery_text": "Leitud seadmed kuvatakse siin. Järgige seadme(te) juhiseid ja pange seade või seadmed sidumisrežiimile.", @@ -2474,6 +2486,7 @@ "unbind_button_label": "Sidesta grupp lahti" }, "groups": { + "add_group": "Lisa grupp", "add_members": "Lisa liikmeid", "adding_members": "Liikmete lisamine", "caption": "Grupid", @@ -2516,7 +2529,11 @@ "hint_wakeup": "Mõnel seadmel (näiteks Xiaomi anduritel) on äratusnupp mida saate vajutada ~ 5-sekundiliste intervallidega ja mis hoiab seadmeid ärkvel kui te nendega suhtlete.", "introduction": "Käivitage ZHA käsud, mis mõjutavad ühte seadet. Saadaolevate käskude loendi kuvamiseks valige seade." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Visualiseerimine", + "header": "Võrgu visualiseerimine" + } }, "zone": { "add_zone": "Lisa tsoon", diff --git a/translations/frontend/fr.json b/translations/frontend/fr.json index 86a2c715f2..f7236fd21b 100644 --- a/translations/frontend/fr.json +++ b/translations/frontend/fr.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Propriétaire", "system-admin": "Administrateurs", "system-read-only": "Utilisateurs en lecture seule", "system-users": "Utilisateurs" @@ -593,7 +594,7 @@ "cleared_device_class": "effacé (no {device_class} detected)", "detected_device_class": "détecté {device_class}", "rose": "aube", - "set": "Défini", + "set": "Coucher", "turned_off": "éteint", "turned_on": "activé", "was_at_home": "Présent", @@ -882,6 +883,7 @@ "navigation": { "areas": "Zones", "automation": "Automatisations", + "blueprint": "Plans", "core": "Général", "customize": "Customisations", "devices": "Appareils", @@ -1398,27 +1400,34 @@ "blueprint": { "add": { "error_no_url": "Veuillez entrer l'URL du plan", + "file_name": "Nom du fichier de plan local", "header": "Ajouter un nouveau plan", "import_btn": "Importer un plan", - "import_header": "Importer {name} ({domain})", + "import_header": "Importer \" {name} \" (type: {domain} )", "import_introduction": "Vous pouvez importer les plans d'autres utilisateurs de Github et des forums de la communauté. Entrez l'URL du plan ci-dessous.", "importing": "Importation du plan ...", + "raw_blueprint": "Contenu du plan", "save_btn": "Sauver le plan", "saving": "Enregistrement du plan ...", + "unsupported_blueprint": "Ce plan n'est pas pris en charge", "url": "URL du plan" }, "caption": "Plans", "description": "Gérer les plans", "overview": { - "add_blueprint": "Ajouter un plan", + "add_blueprint": "Importer un plan", "confirm_delete_header": "Supprimer ce plan ?", "confirm_delete_text": "Êtes-vous sûr de vouloir supprimer ce plan ?", + "delete_blueprint": "Supprimer le plan", "header": "Éditeur de plans", "headers": { + "domain": "Domaine", + "file_name": "Nom de fichier", "name": "Nom" }, "introduction": "L’éditeur de plans vous permet de créer et de modifier des plans.", - "learn_more": "En savoir plus sur les plans" + "learn_more": "En savoir plus sur les plans", + "use_blueprint": "Créer une automatisation" } }, "cloud": { @@ -1869,7 +1878,7 @@ "devices": "{count} {count, plural,\n zero {appareil}\n one {appareil}\n other {appareils}\n}", "documentation": "Documentation", "entities": "{count} {count, plural,\n zero {entité}\n one {entité}\n other {entités}\n}", - "entity_unavailable": "entité indisponible", + "entity_unavailable": "Entité indisponible", "firmware": "Firmware: {version}", "hub": "Connecté via", "manuf": "par {manufacturer}", @@ -2399,19 +2408,24 @@ "system_generated_users_not_editable": "Impossible de mettre à jour les utilisateurs générés par le système.", "system_generated_users_not_removable": "Impossible de supprimer les utilisateurs générés par le système.", "unnamed_user": "Utilisateur sans nom", - "update_user": "Mise à jour" + "update_user": "Mise à jour", + "username": "Nom d'utilisateur" }, "picker": { "add_user": "Ajouter un utilisateur", "headers": { "group": "Groupe", + "is_active": "Actif", + "is_owner": "Propriétaire", "name": "Nom", - "system": "Système" + "system": "Généré par le système", + "username": "Nom d'utilisateur" } }, "users_privileges_note": "La fonctionnalité de groupe d'utilisateurs est en cours de développement. L'utilisateur ne pourra pas gérer l'instance via l'interface. Nous vérifions toujours tous les points terminaisons d'API pour assurer que les accès soient limités aux administrateurs." }, "zha": { + "add_device": "Ajouter un appareil", "add_device_page": { "discovered_text": "Les appareils s'afficheront ici une fois découverts.", "discovery_text": "Les appareils découverts apparaîtront ici. Suivez les instructions pour votre / vos appareil(s) et placez-le(s) en mode de couplage.", @@ -2472,6 +2486,7 @@ "unbind_button_label": "Délier Groupe" }, "groups": { + "add_group": "Ajouter un groupe", "add_members": "Ajouter des membres", "adding_members": "Ajout de membres", "caption": "Groupes", @@ -2514,7 +2529,11 @@ "hint_wakeup": "Certains appareils, tels que les capteurs Xiaomi, disposent d'un bouton de réveil sur lequel vous pouvez appuyer à environ 5 secondes d'intervalle pour que les appareils restent éveillés lorsque vous interagissez avec eux.", "introduction": "Exécutez les commandes ZHA qui affectent un seul périphérique. Choisissez un appareil pour voir une liste des commandes disponibles." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Visualisation", + "header": "Visualisation du réseau" + } }, "zone": { "add_zone": "Ajouter une zone", diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index e1f5c38864..8f01075292 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -1056,11 +1056,11 @@ "use_blueprint": "Gebruik een blauwdruk" }, "header": "Een nieuwe automatisering maken", - "how": "Hoe wilt u uw nieuwe automatisering creëren?", + "how": "Hoe wil je je nieuwe automatisering maken?", "start_empty": "Begin met een lege automatisering", "thingtalk": { "create": "Creëer", - "header": "Beschrijf de automatisering die u wilt creëren", + "header": "Beschrijf de automatisering die je wilt maken", "input_label": "Wat moet deze automatisering doen?", "intro": "En we zullen proberen het voor je te maken. Bijvoorbeeld: doe de lichten uit als ik wegga." } @@ -1148,10 +1148,10 @@ "blueprint": { "blueprint_to_use": "Blauwdruk om te gebruiken", "header": "Blauwdruk", - "inputs": "Ingangen", + "inputs": "Inputs", "manage_blueprints": "Beheer blauwdrukken", "no_blueprints": "Je hebt geen blauwdrukken", - "no_inputs": "Deze blauwdruk heeft geen invoer." + "no_inputs": "Deze blauwdruk heeft geen inputs." }, "conditions": { "add": "Voorwaarde toevoegen", @@ -1371,7 +1371,7 @@ "headers": { "name": "Naam" }, - "introduction": "Met de automatiseringsbewerker kun je automatiseringen maken en bewerken. Volg de link hieronder om er zeker van te zijn dat je Home Assistant juist hebt geconfigureerd.", + "introduction": "Met de automatiseringseditor editor kun je automatiseringen maken en bewerken. Volg de link hieronder om er zeker van te zijn dat je Home Assistant juist hebt geconfigureerd.", "learn_more": "Meer informatie over automatiseringen", "no_automations": "We konden geen bewerkbare automatiseringen vinden", "only_editable": "Alleen automatiseringen in automations.yaml kunnen worden bewerkt.", @@ -1411,12 +1411,12 @@ "description": "Beheer blauwdrukken", "overview": { "confirm_delete_header": "Deze blauwdruk verwijderen?", - "confirm_delete_text": "Weet u zeker dat u deze blauwdruk wilt verwijderen?", + "confirm_delete_text": "Weet je zeker dat je deze blauwdruk wilt verwijderen?", "header": "Blauwdrukeditor", "headers": { "name": "Naam" }, - "introduction": "Met de blauwdrukeditor kunt u blauwdrukken maken en bewerken.", + "introduction": "Met de blauwdrukeditor kunt je blauwdrukken maken en bewerken.", "learn_more": "Meer informatie over blauwdrukken" } }, @@ -1573,7 +1573,7 @@ "feature_google_home": "Integratie met Google Assistent", "feature_remote_control": "Beheer van Home Assistant van buitenaf", "feature_webhook_apps": "Eenvoudige integratie met webhook gebaseerde apps zoals OwnTracks", - "headline": "Start uw gratis proefperiode", + "headline": "Start je gratis proefperiode", "information": "Maak een account om uw gratis proefperiode van een maand te starten met Home Assistant Cloud. Geen betalingsinformatie nodig.", "information2": "De proefversie geeft u toegang tot alle voordelen van Home Assistant Cloud, waaronder:", "information3": "Deze service wordt uitgevoerd door onze partner", @@ -1722,7 +1722,7 @@ "enable_selected": { "button": "Geselecteerde inschakelen", "confirm_text": "Dit maakt ze weer beschikbaar in Home Assistant als ze nu zijn uitgeschakeld.", - "confirm_title": "Wilt u het volgende inschakelen {number} {number, plural,\n one {entiteit}\n other {entiteiten}\n}?" + "confirm_title": "Wilt je {number} {number, plural,\n one {entiteit}\n other {entiteiten}\n} inschakelen?" }, "filter": { "filter": "filter", @@ -2093,7 +2093,7 @@ "header": "Node Configuratie", "help_source": "Configuratieparameterbeschrijvingen en helptekst worden geleverd door het OpenZWave-project.", "introduction": "Beheer de verschillende configuratieparameters voor een Z-Wave-Node.", - "wakeup_help": "Batterijgevoede Nodes moeten wakker zijn om hun configuratie te wijzigen. Als de Node niet wakker is, zal OpenZWave proberen de configuratie van de Node bij te werken de volgende keer dat het ontwaakt, wat meerdere uren (of dagen) later kan zijn. Volg deze stappen om uw apparaat uit de slaapstand te halen:" + "wakeup_help": "Batterijgevoede Nodes moeten wakker zijn om hun configuratie te wijzigen. Als de Node niet wakker is, zal OpenZWave proberen de configuratie van de Node bij te werken de volgende keer dat het ontwaakt, wat meerdere uren (of dagen) later kan zijn. Volg deze stappen om je apparaat uit de slaapstand te halen:" }, "node_metadata": { "product_manual": "Producthandleiding" @@ -2340,7 +2340,7 @@ "add_tag": "Tag toevoegen", "automation_title": "Tag {name} is gescand", "caption": "Tags", - "confirm_remove": "Weet u zeker dat u tag {tag} wilt verwijderen?", + "confirm_remove": "Weet je zeker dat je tag {tag} wilt verwijderen?", "confirm_remove_title": "Tag verwijderen?", "create_automation": "Creëer automatisering met tag", "description": "Beheer tags", @@ -3086,7 +3086,7 @@ "migrate": { "header": "Configuratie incompatibel", "migrate": "Configuratie migreren", - "para_migrate": "Home Assistant kan automatisch ID's aan al uw kaarten en weergaven toevoegen door op de knop 'Configuratie migreren' te drukken.", + "para_migrate": "Home Assistant kan automatisch ID's aan al je kaarten en weergaven toevoegen door op de knop 'Configuratie migreren' te drukken.", "para_no_id": "Dit element heeft geen ID. Voeg een ID toe aan dit element in 'ui-lovelace.yaml'." }, "move_card": { @@ -3094,7 +3094,7 @@ }, "raw_editor": { "confirm_remove_config_text": "We zullen je Lovelace gebruikersinterface automatisch genereren met je gebieden en apparaten als je de huidige Lovelace gebruikersinterface verwijdert.", - "confirm_remove_config_title": "Weet u zeker dat u uw Lovelace UI-configuratie wilt verwijderen?", + "confirm_remove_config_title": "Weet je zeker dat je je Lovelace UI-configuratie wilt verwijderen?", "confirm_unsaved_changes": "Er zijn nog niet-opgeslagen wijzigingen, weet je zeker dat je wilt afsluiten?", "confirm_unsaved_comments": "Uw configuratie bevat opmerkingen, deze worden niet opgeslagen. Wil je doorgaan?", "error_invalid_config": "Uw configuratie is niet geldig: {error}", @@ -3349,7 +3349,7 @@ }, "intro": "Ben je klaar om je huis wakker te maken, je privacy terug te winnen en deel te nemen aan een wereldwijde gemeenschap van knutselaars?", "restore": { - "description": "Als alternatief kunt u herstellen vanaf een eerdere snapshot", + "description": "Je kunt ook herstellen vanaf een eerdere snapshot.", "hide_log": "Verberg volledig logboek", "in_progress": "Herstel in uitvoering", "show_log": "Volledig logboek weergeven" diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index 9af6104470..b7f99e86b8 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Właściciel", "system-admin": "Administratorzy", "system-read-only": "Użytkownicy (tylko odczyt)", "system-users": "Użytkownicy" @@ -2399,7 +2400,7 @@ "delete_user": "Usuń użytkownika", "group": "Grupa", "id": "Identyfikator", - "name": "Nazwa", + "name": "Wyświetlana nazwa", "new_password": "Nowe hasło", "owner": "Właściciel", "password_changed": "Hasło zostało zmienione pomyślnie", @@ -2407,14 +2408,18 @@ "system_generated_users_not_editable": "Nie można zaktualizować użytkowników generowanych przez system.", "system_generated_users_not_removable": "Nie można usunąć użytkowników wygenerowanych przez system.", "unnamed_user": "Nienazwany użytkownik", - "update_user": "Aktualizuj" + "update_user": "Aktualizuj", + "username": "Nazwa użytkownika" }, "picker": { "add_user": "Dodaj użytkownika", "headers": { "group": "Grupa", - "name": "Nazwa", - "system": "System" + "is_active": "Aktywny", + "is_owner": "Właściciel", + "name": "Wyświetlana nazwa", + "system": "Wygenerowany przez system", + "username": "Nazwa użytkownika" } }, "users_privileges_note": "Prace nad grupami użytkowników trwają. Użytkownik nie może administrować instancją za pomocą interfejsu użytkownika. Nadal kontrolujemy wszystkie punkty końcowe interfejsu API zarządzania, aby upewnić się, że poprawnie ograniczają dostęp tylko dla administratorów." diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index d211e8f75a..b68d87709d 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Владелец", "system-admin": "Администраторы", "system-read-only": "Системные пользователи", "system-users": "Пользователи" @@ -2350,14 +2351,18 @@ "system_generated_users_not_editable": "Системные пользователи защищены от редактирования", "system_generated_users_not_removable": "Системные пользователи защищены от удаления", "unnamed_user": "Безымянный пользователь", - "update_user": "Обновить" + "update_user": "Обновить", + "username": "Логин" }, "picker": { "add_user": "Добавить пользователя", "headers": { "group": "Группа", + "is_active": "Активен", + "is_owner": "Владелец", "name": "Имя", - "system": "Системный" + "system": "Системный", + "username": "Логин" } }, "users_privileges_note": "Функционал пользователей всё ещё в стадии разработки. В дальнейшем пользователи не смогут администрировать сервер через пользовательский интерфейс. Мы все еще проверяем все конечные точки API управления, чтобы убедиться, что они правильно ограничивают доступ." diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index 98a1ed3039..e8ca6a96bd 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "所有者", "system-admin": "管理员", "system-read-only": "只读用户", "system-users": "用户" @@ -2399,7 +2400,7 @@ "delete_user": "删除用户", "group": "群组", "id": "ID", - "name": "名称", + "name": "显示名称", "new_password": "新密码", "owner": "所有者", "password_changed": "密码修改成功", @@ -2407,14 +2408,18 @@ "system_generated_users_not_editable": "无法更新系统生成的用户。", "system_generated_users_not_removable": "无法删除系统生成的用户。", "unnamed_user": "未命名的用户", - "update_user": "更新" + "update_user": "更新", + "username": "用户名" }, "picker": { "add_user": "添加用户", "headers": { "group": "群组", - "name": "名称", - "system": "系统" + "is_active": "已激活", + "is_owner": "所有者", + "name": "显示名称", + "system": "系统生成", + "username": "用户名" } }, "users_privileges_note": "用户组功能正在开发中。该功能使普通用户无法通过 UI 进行管理操作。我们正在审计所有管理 API,确保其仅限管理员访问。" diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index 0e57b9faae..344a8dce13 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "擁有者", "system-admin": "管理員", "system-read-only": "唯讀使用者", "system-users": "使用者" @@ -2399,7 +2400,7 @@ "delete_user": "刪除使用者", "group": "群組", "id": "ID", - "name": "名稱", + "name": "顯示名稱", "new_password": "新密碼", "owner": "擁有者", "password_changed": "密碼變更成功", @@ -2407,14 +2408,18 @@ "system_generated_users_not_editable": "無法更新系統產生的使用者", "system_generated_users_not_removable": "無法移除系統產生的使用者", "unnamed_user": "未命名的使用者", - "update_user": "更新" + "update_user": "更新", + "username": "使用者名稱" }, "picker": { "add_user": "新增使用者", "headers": { "group": "群組", - "name": "名稱", - "system": "系統" + "is_active": "啟用", + "is_owner": "擁有者", + "name": "顯示名稱", + "system": "系統產生", + "username": "使用者名稱" } }, "users_privileges_note": "使用者群組功能仍在開發中。將無法透過 UI 進行使用者管理,仍在檢視所有管理 API Endpoint 以確保能夠正確符合管理員存取需求。" From 7ceb6eb50deb04046106d40476e4424f959d3493 Mon Sep 17 00:00:00 2001 From: Marc Randolph Date: Sun, 29 Nov 2020 09:13:55 -0600 Subject: [PATCH 07/38] Apply existing theme variables to unthemed items (#7844) --- src/dialogs/notifications/notification-item-template.ts | 2 +- src/panels/developer-tools/ha-panel-developer-tools.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialogs/notifications/notification-item-template.ts b/src/dialogs/notifications/notification-item-template.ts index bde508416d..f6b5d319d8 100644 --- a/src/dialogs/notifications/notification-item-template.ts +++ b/src/dialogs/notifications/notification-item-template.ts @@ -46,7 +46,7 @@ export class HuiNotificationItemTemplate extends LitElement { } .actions { - border-top: 1px solid #e8e8e8; + border-top: 1px solid var(--divider-color, #e8e8e8); padding: 5px 16px; } diff --git a/src/panels/developer-tools/ha-panel-developer-tools.ts b/src/panels/developer-tools/ha-panel-developer-tools.ts index e8c8317e17..630853e5ca 100644 --- a/src/panels/developer-tools/ha-panel-developer-tools.ts +++ b/src/panels/developer-tools/ha-panel-developer-tools.ts @@ -109,7 +109,7 @@ class PanelDeveloperTools extends LitElement { ha-tabs { margin-left: max(env(safe-area-inset-left), 24px); margin-right: max(env(safe-area-inset-right), 24px); - --paper-tabs-selection-bar-color: #fff; + --paper-tabs-selection-bar-color: var(--text-primary-color, #fff); text-transform: uppercase; } `, From fe31d15d27ce08ca8183d73a44b580182d5063e0 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sun, 29 Nov 2020 22:00:51 +0100 Subject: [PATCH 08/38] Add UI for setting an area on entity level (#7837) --- .../dialogs/network/dialog-hassio-network.ts | 10 +- src/components/ha-area-picker.ts | 12 +++ src/components/ha-expansion-panel.ts | 6 +- src/data/entity_registry.ts | 2 + .../blueprint/dialog-import-blueprint.ts | 23 ++--- .../device-detail/ha-device-info-card.ts | 2 +- .../dialog-device-registry-detail.ts | 14 +-- .../show-dialog-device-registry-detail.ts | 4 +- .../config/devices/ha-config-device-page.ts | 2 +- .../entities/entity-registry-basic-editor.ts | 50 +++++++++- .../entities/entity-registry-settings.ts | 95 ++++++++++++++++++- .../config/entities/ha-config-entities.ts | 68 ++++++++++++- src/translations/en.json | 1 + 13 files changed, 246 insertions(+), 43 deletions(-) rename src/{dialogs => panels/config/devices}/device-registry-detail/dialog-device-registry-detail.ts (90%) rename src/{dialogs => panels/config/devices}/device-registry-detail/show-dialog-device-registry-detail.ts (86%) diff --git a/hassio/src/dialogs/network/dialog-hassio-network.ts b/hassio/src/dialogs/network/dialog-hassio-network.ts index 382cc0ede3..6a8deb6088 100644 --- a/hassio/src/dialogs/network/dialog-hassio-network.ts +++ b/hassio/src/dialogs/network/dialog-hassio-network.ts @@ -137,8 +137,7 @@ export class DialogHassioNetwork extends LitElement )} ${this._interface?.type === "wireless" ? html` - - Wi-Fi + ${this._interface?.wifi?.ssid ? html`

Connected to: ${this._interface?.wifi?.ssid}

` : ""} @@ -281,8 +280,10 @@ export class DialogHassioNetwork extends LitElement private _renderIPConfiguration(version: string) { return html` - - IPv${version.charAt(version.length - 1)} +
{ + return this._areas?.find((area) => area.area_id === areaId); + }); + private _clearValue(ev: Event) { ev.stopPropagation(); this._setValue(""); diff --git a/src/components/ha-expansion-panel.ts b/src/components/ha-expansion-panel.ts index b74022032d..f328e3590e 100644 --- a/src/components/ha-expansion-panel.ts +++ b/src/components/ha-expansion-panel.ts @@ -19,12 +19,14 @@ class HaExpansionPanel extends LitElement { @property({ type: Boolean, reflect: true }) outlined = false; + @property() header?: string; + @query(".container") private _container!: HTMLDivElement; protected render(): TemplateResult { return html`
- + ${this.header} `} - - ${this.hass.localize( - "ui.panel.config.blueprint.add.raw_blueprint" - )} +
${this._result.raw_data}
` : html`${this.hass.localize( @@ -201,15 +199,8 @@ class DialogImportBlueprint extends LitElement { } } - static get styles(): CSSResult[] { - return [ - haStyleDialog, - css` - ha-expansion-panel { - --expansion-panel-summary-padding: 0; - } - `, - ]; + static get styles(): CSSResult { + return haStyleDialog; } } diff --git a/src/panels/config/devices/device-detail/ha-device-info-card.ts b/src/panels/config/devices/device-detail/ha-device-info-card.ts index ae81de81c2..5e4de8859e 100644 --- a/src/panels/config/devices/device-detail/ha-device-info-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-info-card.ts @@ -12,7 +12,7 @@ import { computeDeviceName, DeviceRegistryEntry, } from "../../../../data/device_registry"; -import { loadDeviceRegistryDetailDialog } from "../../../../dialogs/device-registry-detail/show-dialog-device-registry-detail"; +import { loadDeviceRegistryDetailDialog } from "../device-registry-detail/show-dialog-device-registry-detail"; import { HomeAssistant } from "../../../../types"; @customElement("ha-device-info-card") diff --git a/src/dialogs/device-registry-detail/dialog-device-registry-detail.ts b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts similarity index 90% rename from src/dialogs/device-registry-detail/dialog-device-registry-detail.ts rename to src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts index 4bc68af3a2..ba05ad3c66 100644 --- a/src/dialogs/device-registry-detail/dialog-device-registry-detail.ts +++ b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts @@ -3,8 +3,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import "../../components/ha-dialog"; -import "../../components/ha-area-picker"; +import "../../../../components/ha-dialog"; +import "../../../../components/ha-area-picker"; import { CSSResult, @@ -18,11 +18,11 @@ import { } from "lit-element"; import { DeviceRegistryDetailDialogParams } from "./show-dialog-device-registry-detail"; -import { HomeAssistant } from "../../types"; -import { PolymerChangedEvent } from "../../polymer-types"; -import { computeDeviceName } from "../../data/device_registry"; -import { fireEvent } from "../../common/dom/fire_event"; -import { haStyleDialog } from "../../resources/styles"; +import { HomeAssistant } from "../../../../types"; +import { PolymerChangedEvent } from "../../../../polymer-types"; +import { computeDeviceName } from "../../../../data/device_registry"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { haStyleDialog } from "../../../../resources/styles"; @customElement("dialog-device-registry-detail") class DialogDeviceRegistryDetail extends LitElement { diff --git a/src/dialogs/device-registry-detail/show-dialog-device-registry-detail.ts b/src/panels/config/devices/device-registry-detail/show-dialog-device-registry-detail.ts similarity index 86% rename from src/dialogs/device-registry-detail/show-dialog-device-registry-detail.ts rename to src/panels/config/devices/device-registry-detail/show-dialog-device-registry-detail.ts index 4a603f629c..383446906b 100644 --- a/src/dialogs/device-registry-detail/show-dialog-device-registry-detail.ts +++ b/src/panels/config/devices/device-registry-detail/show-dialog-device-registry-detail.ts @@ -1,8 +1,8 @@ -import { fireEvent } from "../../common/dom/fire_event"; +import { fireEvent } from "../../../../common/dom/fire_event"; import { DeviceRegistryEntry, DeviceRegistryEntryMutableParams, -} from "../../data/device_registry"; +} from "../../../../data/device_registry"; export interface DeviceRegistryDetailDialogParams { device: DeviceRegistryEntry; diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index a8809ec5f9..84ed1860c5 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -35,7 +35,7 @@ import { findRelated, RelatedResult } from "../../../data/search"; import { loadDeviceRegistryDetailDialog, showDeviceRegistryDetailDialog, -} from "../../../dialogs/device-registry-detail/show-dialog-device-registry-detail"; +} from "./device-registry-detail/show-dialog-device-registry-detail"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/hass-error-screen"; import "../../../layouts/hass-tabs-subpage"; diff --git a/src/panels/config/entities/entity-registry-basic-editor.ts b/src/panels/config/entities/entity-registry-basic-editor.ts index 79d4bcb07b..f40044f1b0 100644 --- a/src/panels/config/entities/entity-registry-basic-editor.ts +++ b/src/panels/config/entities/entity-registry-basic-editor.ts @@ -20,9 +20,16 @@ import { import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; import type { PolymerChangedEvent } from "../../../polymer-types"; import type { HomeAssistant } from "../../../types"; +import "../../../components/ha-area-picker"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { + DeviceRegistryEntry, + subscribeDeviceRegistry, +} from "../../../data/device_registry"; +import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; @customElement("ha-registry-basic-editor") -export class HaEntityRegistryBasicEditor extends LitElement { +export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; @property() public entry!: ExtEntityRegistryEntry; @@ -31,16 +38,26 @@ export class HaEntityRegistryBasicEditor extends LitElement { @internalProperty() private _entityId!: string; + @internalProperty() private _areaId?: string; + @internalProperty() private _disabledBy!: string | null; + private _deviceLookup?: Record; + + @internalProperty() private _device?: DeviceRegistryEntry; + @internalProperty() private _submitting?: boolean; public async updateEntry(): Promise { this._submitting = true; const params: Partial = { new_entity_id: this._entityId.trim(), + area_id: this._areaId || null, }; - if (this._disabledBy === null || this._disabledBy === "user") { + if ( + this.entry.disabled_by !== this._disabledBy && + (this._disabledBy === null || this._disabledBy === "user") + ) { params.disabled_by = this._disabledBy; } try { @@ -70,6 +87,20 @@ export class HaEntityRegistryBasicEditor extends LitElement { } } + public hassSubscribe(): UnsubscribeFunc[] { + return [ + subscribeDeviceRegistry(this.hass.connection!, (devices) => { + this._deviceLookup = {}; + for (const device of devices) { + this._deviceLookup[device.id] = device; + } + if (!this._device && this.entry.device_id) { + this._device = this._deviceLookup[this.entry.device_id]; + } + }), + ]; + } + protected updated(changedProperties: PropertyValues) { super.updated(changedProperties); if (!changedProperties.has("entry")) { @@ -79,6 +110,11 @@ export class HaEntityRegistryBasicEditor extends LitElement { this._origEntityId = this.entry.entity_id; this._entityId = this.entry.entity_id; this._disabledBy = this.entry.disabled_by; + this._areaId = this.entry.area_id; + this._device = + this.entry.device_id && this._deviceLookup + ? this._deviceLookup[this.entry.device_id] + : undefined; } } @@ -105,6 +141,12 @@ export class HaEntityRegistryBasicEditor extends LitElement { .invalid=${invalidDomainUpdate} .disabled=${this._submitting} > +
): void { this._entityId = ev.detail.value; } diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index 0912c6331f..b15bf6bffb 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -1,6 +1,6 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-input/paper-input"; -import { HassEntity } from "home-assistant-js-websocket"; +import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, CSSResult, @@ -31,9 +31,18 @@ import type { PolymerChangedEvent } from "../../../polymer-types"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; import { domainIcon } from "../../../common/entity/domain_icon"; +import "../../../components/ha-area-picker"; +import { + DeviceRegistryEntry, + subscribeDeviceRegistry, + updateDeviceRegistryEntry, +} from "../../../data/device_registry"; +import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; +import "../../../components/ha-expansion-panel"; +import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail"; @customElement("entity-registry-settings") -export class EntityRegistrySettings extends LitElement { +export class EntityRegistrySettings extends SubscribeMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; @property() public entry!: ExtEntityRegistryEntry; @@ -44,14 +53,34 @@ export class EntityRegistrySettings extends LitElement { @internalProperty() private _entityId!: string; + @internalProperty() private _areaId?: string | null; + @internalProperty() private _disabledBy!: string | null; + private _deviceLookup?: Record; + + @internalProperty() private _device?: DeviceRegistryEntry; + @internalProperty() private _error?: string; @internalProperty() private _submitting?: boolean; private _origEntityId!: string; + public hassSubscribe(): UnsubscribeFunc[] { + return [ + subscribeDeviceRegistry(this.hass.connection!, (devices) => { + this._deviceLookup = {}; + for (const device of devices) { + this._deviceLookup[device.id] = device; + } + if (this.entry.device_id) { + this._device = this._deviceLookup[this.entry.device_id]; + } + }), + ]; + } + protected updated(changedProperties: PropertyValues) { super.updated(changedProperties); if (changedProperties.has("entry")) { @@ -59,8 +88,13 @@ export class EntityRegistrySettings extends LitElement { this._name = this.entry.name || ""; this._icon = this.entry.icon || ""; this._origEntityId = this.entry.entity_id; + this._areaId = this.entry.area_id; this._entityId = this.entry.entity_id; this._disabledBy = this.entry.disabled_by; + this._device = + this.entry.device_id && this._deviceLookup + ? this._deviceLookup[this.entry.device_id] + : undefined; } } @@ -117,6 +151,13 @@ export class EntityRegistrySettings extends LitElement { .invalid=${invalidDomainUpdate} .disabled=${this._submitting} > + ${!this.entry.device_id + ? html`` + : ""}
+ + ${this.entry.device_id + ? html` +

+ By default the entities of a device are in the same area as the + device. If you change the area of this entity, it will no longer + follow the area of the device. +

+ ${this._areaId + ? html`Follow device area` + : this._device + ? html`Change device area` + : ""} +
` + : ""}
{ + await updateDeviceRegistryEntry(this.hass, this._device!.id, updates); + }, + }); + } + private async _updateEntry(): Promise { this._submitting = true; const params: Partial = { name: this._name.trim() || null, icon: this._icon.trim() || null, + area_id: this._areaId || null, new_entity_id: this._entityId.trim(), }; - if (this._disabledBy === null || this._disabledBy === "user") { + if ( + this.entry.disabled_by !== this._disabledBy && + (this._disabledBy === null || this._disabledBy === "user") + ) { params.disabled_by = this._disabledBy; } try { diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 3a474c4efb..b8e0ee77da 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -62,6 +62,14 @@ import { } from "./show-dialog-entity-editor"; import { haStyle } from "../../../resources/styles"; import { UNAVAILABLE } from "../../../data/entity"; +import { + DeviceRegistryEntry, + subscribeDeviceRegistry, +} from "../../../data/device_registry"; +import { + AreaRegistryEntry, + subscribeAreaRegistry, +} from "../../../data/area_registry"; export interface StateEntity extends EntityRegistryEntry { readonly?: boolean; @@ -73,6 +81,7 @@ export interface EntityRow extends StateEntity { unavailable: boolean; restored: boolean; status: string; + area?: string; } @customElement("ha-config-entities") @@ -87,6 +96,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { @internalProperty() private _entities?: EntityRegistryEntry[]; + @internalProperty() private _devices?: DeviceRegistryEntry[]; + + @internalProperty() private _areas: AreaRegistryEntry[] = []; + @internalProperty() private _stateEntities: StateEntity[] = []; @property() public _entries?: ConfigEntry[]; @@ -201,6 +214,15 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { template: (platform) => this.hass.localize(`component.${platform}.title`) || platform, }, + area: { + title: this.hass.localize( + "ui.panel.config.entities.picker.headers.area" + ), + sortable: true, + hidden: narrow, + filterable: true, + width: "15%", + }, status: { title: this.hass.localize( "ui.panel.config.entities.picker.headers.status" @@ -255,6 +277,8 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { private _filteredEntities = memoize( ( entities: EntityRegistryEntry[], + devices: DeviceRegistryEntry[] | undefined, + areas: AreaRegistryEntry[] | undefined, stateEntities: StateEntity[], filters: URLSearchParams, showDisabled: boolean, @@ -262,21 +286,42 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { showReadOnly: boolean ): EntityRow[] => { const result: EntityRow[] = []; + // If nothing gets filtered, this is our correct count of entities let startLength = entities.length + stateEntities.length; - entities = showReadOnly ? entities.concat(stateEntities) : entities; + const areaLookup: { [areaId: string]: AreaRegistryEntry } = {}; + const deviceLookup: { [deviceId: string]: DeviceRegistryEntry } = {}; + + if (areas) { + for (const area of areas) { + areaLookup[area.area_id] = area; + } + if (devices) { + for (const device of devices) { + deviceLookup[device.id] = device; + } + } + } + + entities.forEach((entity) => { + return entity; + }); + + let filteredEntities = showReadOnly + ? entities.concat(stateEntities) + : entities; filters.forEach((value, key) => { switch (key) { case "config_entry": - entities = entities.filter( + filteredEntities = filteredEntities.filter( (entity) => entity.config_entry_id === value ); // If we have an active filter and `showReadOnly` is true, the length of `entities` is correct. // If however, the read-only entities were not added before, we need to check how many would // have matched the active filter and add that number to the count. - startLength = entities.length; + startLength = filteredEntities.length; if (!showReadOnly) { startLength += stateEntities.filter( (entity) => entity.config_entry_id === value @@ -287,13 +332,17 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { }); if (!showDisabled) { - entities = entities.filter((entity) => !entity.disabled_by); + filteredEntities = filteredEntities.filter( + (entity) => !entity.disabled_by + ); } - for (const entry of entities) { + for (const entry of filteredEntities) { const entity = this.hass.states[entry.entity_id]; const unavailable = entity?.state === UNAVAILABLE; const restored = entity?.attributes.restored; + const areaId = entry.area_id ?? deviceLookup[entry.device_id!]?.area_id; + const area = areaId ? areaLookup[areaId] : undefined; if (!showUnavailable && unavailable) { continue; @@ -309,6 +358,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { this.hass.localize("state.default.unavailable"), unavailable, restored, + area: area ? area.name : undefined, status: restored ? this.hass.localize( "ui.panel.config.entities.picker.status.restored" @@ -345,6 +395,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { subscribeEntityRegistry(this.hass.connection!, (entities) => { this._entities = entities; }), + subscribeDeviceRegistry(this.hass.connection!, (devices) => { + this._devices = devices; + }), + subscribeAreaRegistry(this.hass.connection, (areas) => { + this._areas = areas; + }), ]; } @@ -372,6 +428,8 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { const entityData = this._filteredEntities( this._entities, + this._devices, + this._areas, this._stateEntities, this._searchParms, this._showDisabled, diff --git a/src/translations/en.json b/src/translations/en.json index df894c5333..eceb15c8e3 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1830,6 +1830,7 @@ "name": "Name", "entity_id": "Entity ID", "integration": "Integration", + "area": "Area", "status": "Status" }, "selected": "{number} selected", From 335354d962d94f58eee6ecd8b4a3fd12e2ae89e7 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Sun, 29 Nov 2020 16:33:46 -0500 Subject: [PATCH 09/38] Enhance ZHA device pairing feedback (#7843) Co-authored-by: Bram Kragten --- src/data/zha.ts | 21 +++ .../zha/zha-add-devices-page.ts | 29 ++-- .../zha/zha-device-pairing-status-card.ts | 147 ++++++++++++++++++ src/translations/en.json | 10 ++ 4 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts diff --git a/src/data/zha.ts b/src/data/zha.ts index 5f4cb3aa18..96c8166a24 100644 --- a/src/data/zha.ts +++ b/src/data/zha.ts @@ -27,6 +27,7 @@ export interface ZHADevice { device_type: string; signature: any; neighbors: Neighbor[]; + pairing_status?: string; } export interface Neighbor { @@ -270,3 +271,23 @@ export const addGroup = ( group_name: groupName, members: membersToAdd, }); + +export const INITIALIZED = "INITIALIZED"; +export const INTERVIEW_COMPLETE = "INTERVIEW_COMPLETE"; +export const CONFIGURED = "CONFIGURED"; +export const PAIRED = "PAIRED"; +export const INCOMPLETE_PAIRING_STATUSES = [ + PAIRED, + CONFIGURED, + INTERVIEW_COMPLETE, +]; + +export const DEVICE_JOINED = "device_joined"; +export const RAW_DEVICE_INITIALIZED = "raw_device_initialized"; +export const DEVICE_FULLY_INITIALIZED = "device_fully_initialized"; +export const DEVICE_MESSAGE_TYPES = [ + DEVICE_JOINED, + RAW_DEVICE_INITIALIZED, + DEVICE_FULLY_INITIALIZED, +]; +export const LOG_OUTPUT = "log_output"; diff --git a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts index 6c2fdcc897..7f56d95d9e 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts @@ -14,13 +14,17 @@ import { } from "lit-element"; import "../../../../../components/ha-service-description"; import "@polymer/paper-input/paper-textarea"; -import { ZHADevice } from "../../../../../data/zha"; import "../../../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../../../resources/styles"; import { HomeAssistant, Route } from "../../../../../types"; -import "./zha-device-card"; +import "./zha-device-pairing-status-card"; import { zhaTabs } from "./zha-config-dashboard"; import { IronAutogrowTextareaElement } from "@polymer/iron-autogrow-textarea"; +import { + DEVICE_MESSAGE_TYPES, + LOG_OUTPUT, + ZHADevice, +} from "../../../../../data/zha"; @customElement("zha-add-devices-page") class ZHAAddDevicesPage extends LitElement { @@ -34,7 +38,10 @@ class ZHAAddDevicesPage extends LitElement { @internalProperty() private _error?: string; - @internalProperty() private _discoveredDevices: ZHADevice[] = []; + @internalProperty() private _discoveredDevices: Record< + string, + ZHADevice + > = {}; @internalProperty() private _formattedEvents = ""; @@ -64,7 +71,7 @@ class ZHAAddDevicesPage extends LitElement { super.disconnectedCallback(); this._unsubscribe(); this._error = undefined; - this._discoveredDevices = []; + this._discoveredDevices = {}; this._formattedEvents = ""; } @@ -115,7 +122,7 @@ class ZHAAddDevicesPage extends LitElement {
${this._error ? html`
${this._error}
` : ""}
- ${this._discoveredDevices.length < 1 + ${Object.keys(this._discoveredDevices).length < 1 ? html`

@@ -133,15 +140,15 @@ class ZHAAddDevicesPage extends LitElement {

` : html` - ${this._discoveredDevices.map( + ${Object.values(this._discoveredDevices).map( (device) => html` - + > ` )} `} @@ -164,7 +171,7 @@ class ZHAAddDevicesPage extends LitElement { } private _handleMessage(message: any): void { - if (message.type === "log_output") { + if (message.type === LOG_OUTPUT) { this._formattedEvents += message.log_entry.message + "\n"; if (this.shadowRoot) { const paperTextArea = this.shadowRoot.querySelector("paper-textarea"); @@ -175,8 +182,8 @@ class ZHAAddDevicesPage extends LitElement { } } } - if (message.type && message.type === "device_fully_initialized") { - this._discoveredDevices.push(message.device_info); + if (message.type && DEVICE_MESSAGE_TYPES.includes(message.type)) { + this._discoveredDevices[message.device_info.ieee] = message.device_info; } } diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts new file mode 100644 index 0000000000..c6b4181e85 --- /dev/null +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts @@ -0,0 +1,147 @@ +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-listbox/paper-listbox"; +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, + internalProperty, + TemplateResult, +} from "lit-element"; +import "../../../../../components/buttons/ha-call-service-button"; +import "../../../../../components/entity/state-badge"; +import "../../../../../components/ha-card"; +import "../../../../../components/ha-service-description"; +import { + CONFIGURED, + INCOMPLETE_PAIRING_STATUSES, + INITIALIZED, + INTERVIEW_COMPLETE, + ZHADevice, +} from "../../../../../data/zha"; +import { haStyle } from "../../../../../resources/styles"; +import { HomeAssistant } from "../../../../../types"; +import "../../../../../components/ha-area-picker"; +import { formatAsPaddedHex } from "./functions"; +import "./zha-device-card"; +import { classMap } from "lit-html/directives/class-map"; + +@customElement("zha-device-pairing-status-card") +class ZHADevicePairingStatusCard extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public device?: ZHADevice; + + @property({ type: Boolean }) public narrow?: boolean; + + @internalProperty() private _showHelp = false; + + protected render(): TemplateResult { + if (!this.hass || !this.device) { + return html``; + } + + return html` +
+

+ ${this.hass!.localize( + `ui.panel.config.zha.device_pairing_card.${this.device.pairing_status}` + )} +

+

+ ${this.hass!.localize( + `ui.panel.config.zha.device_pairing_card.${this.device.pairing_status}_status_text` + )} +

+
+
+ ${[INTERVIEW_COMPLETE, CONFIGURED].includes( + this.device.pairing_status! + ) + ? html` +
${this.device.model}
+
+ ${this.hass.localize( + "ui.dialogs.zha_device_info.manuf", + "manufacturer", + this.device.manufacturer + )} +
+ ` + : html``} +
+ ${INCOMPLETE_PAIRING_STATUSES.includes(this.device.pairing_status!) + ? html` +
IEEE: ${this.device.ieee}
+
+ NWK: ${formatAsPaddedHex(this.device.nwk)} +
+ ` + : html``} +
+ ${this.device.pairing_status === INITIALIZED + ? html` + + ` + : html``} +
+
+ `; + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + .discovered { + --ha-card-border-color: var(--primary-color); + } + .discovered.initialized { + --ha-card-border-color: var(--success-color); + } + .discovered .header { + background: var(--primary-color); + color: var(--text-primary-color); + padding: 8px; + text-align: center; + margin-bottom: 20px; + } + .discovered.initialized .header { + background: var(--success-color); + } + h1 { + margin: 0; + } + h4 { + margin: 0; + } + .text, + .manuf, + .model { + color: var(--secondary-text-color); + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-device-pairing-status-card": ZHADevicePairingStatusCard; + } +} diff --git a/src/translations/en.json b/src/translations/en.json index eceb15c8e3..e1902f4fc3 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2198,6 +2198,16 @@ "issue_zigbee_command": "Issue Zigbee Command", "help_command_dropdown": "Select a command to interact with." }, + "device_pairing_card": { + "PAIRED": "Device Found", + "PAIRED_status_text": "Starting Interview", + "INTERVIEW_COMPLETE": "Interview Complete", + "INTERVIEW_COMPLETE_status_text": "Configuring", + "CONFIGURED": "Configuration Complete", + "CONFIGURED_status_text": "Initializing", + "INITIALIZED": "Initialization Complete", + "INITIALIZED_status_text": "The device is ready to use" + }, "network": { "caption": "Network" }, From 7d4cad90bc99122f034ac4723efd8426b10048ba Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Sun, 29 Nov 2020 15:37:13 -0600 Subject: [PATCH 10/38] Show attribute value when 0 (#7842) Co-authored-by: Bram Kragten --- src/panels/lovelace/special-rows/hui-attribute-row.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/panels/lovelace/special-rows/hui-attribute-row.ts b/src/panels/lovelace/special-rows/hui-attribute-row.ts index 97a44d2867..aa95125acc 100644 --- a/src/panels/lovelace/special-rows/hui-attribute-row.ts +++ b/src/panels/lovelace/special-rows/hui-attribute-row.ts @@ -57,7 +57,8 @@ class HuiAttributeRow extends LitElement implements LovelaceRow { return html`
- ${this._config.prefix} ${attribute || "-"} ${this._config.suffix} + ${this._config.prefix} ${attribute ?? "-"} + ${this._config.suffix}
`; From 98175d5c72686bd09d2a0c8d2831b86c2ce0d52f Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Mon, 30 Nov 2020 00:32:50 +0000 Subject: [PATCH 11/38] [ci skip] Translation update --- translations/frontend/de.json | 4 +- translations/frontend/en.json | 11 +++++ translations/frontend/fr.json | 5 +- translations/frontend/is.json | 89 +++++++++++++++++++++++++++++++++-- translations/frontend/it.json | 37 +++++++++++---- 5 files changed, 127 insertions(+), 19 deletions(-) diff --git a/translations/frontend/de.json b/translations/frontend/de.json index 167d8ed95b..35c5636361 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -932,7 +932,7 @@ "telegram": "Telegram-Benachrichtigungsdienst neu laden", "template": "Templates neu laden", "trend": "Trend Entitäten neu laden", - "universal": "Universelle Medien Player Entitäten neu laden ", + "universal": "Universelle Medien Player Entitäten neu laden", "zone": "Zonen neu laden" }, "server_control": { @@ -1239,7 +1239,7 @@ "edit_ui": "Mit der Benutzeroberfläche bearbeiten", "edit_yaml": "Als YAML bearbeiten", "enable_disable": "Automatisierung aktivieren / deaktivieren", - "introduction": "Benutze Automatisierungen, um deinem Zuhause Leben einzuhauchen", + "introduction": "Benutze Automatisierungen, um deinem Zuhause Leben einzuhauchen.", "load_error_not_editable": "Nur Automatisierungen in automations.yaml sind editierbar.", "load_error_unknown": "Fehler beim Laden der Automatisierung ({err_no}).", "max": { diff --git a/translations/frontend/en.json b/translations/frontend/en.json index b9453e072b..6a1115a5d4 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -1744,6 +1744,7 @@ }, "header": "Entities", "headers": { + "area": "Area", "entity_id": "Entity ID", "integration": "Integration", "name": "Name", @@ -2471,6 +2472,16 @@ "value": "Value" }, "description": "Zigbee Home Automation network management", + "device_pairing_card": { + "CONFIGURED": "Configuration Complete", + "CONFIGURED_status_text": "Initializing", + "INITIALIZED": "Initialization Complete", + "INITIALIZED_status_text": "The device is ready to use", + "INTERVIEW_COMPLETE": "Interview Complete", + "INTERVIEW_COMPLETE_status_text": "Configuring", + "PAIRED": "Device Found", + "PAIRED_status_text": "Starting Interview" + }, "devices": { "header": "Zigbee Home Automation - Device" }, diff --git a/translations/frontend/fr.json b/translations/frontend/fr.json index f7236fd21b..4e224cd049 100644 --- a/translations/frontend/fr.json +++ b/translations/frontend/fr.json @@ -2827,7 +2827,7 @@ "views": { "dayGridDay": "Jour", "dayGridMonth": "Mois", - "listWeek": "liste" + "listWeek": "Liste" } }, "conditional": { @@ -2987,7 +2987,8 @@ }, "picture-glance": { "description": "La carte Coup d'œil affiche une image et les états d'entité correspondants sous forme d'icône. Les entités sur le côté droit permettent de basculer entre les actions, d'autres affichent la boîte de dialogue plus d'informations.", - "name": "Coup d'œil en image" + "name": "Coup d'œil en image", + "state_entity": "État entité" }, "picture": { "description": "La carte Image vous permet de définir une image à utiliser pour la navigation vers divers chemins de votre interface ou d'appeler un service.", diff --git a/translations/frontend/is.json b/translations/frontend/is.json index b9f039f33d..697d184834 100644 --- a/translations/frontend/is.json +++ b/translations/frontend/is.json @@ -6,6 +6,7 @@ } }, "groups": { + "owner": "Eigandi", "system-admin": "Stjórnendur", "system-read-only": "Notendur með lesaðgang", "system-users": "Notendur" @@ -471,14 +472,17 @@ "back": "Til baka", "cancel": "Hætta við", "close": "Loka", + "continue": "Halda áfram", "delete": "Eyða", "error_required": "Skilyrt", "loading": "Hleð", "menu": "Valmynd", "next": "Næsta", "no": "Nei", + "not_now": "Ekki núna", "previous": "Fyrri", "refresh": "Endurnýja", + "rename": "Endurnefna", "save": "Vista", "skip": "Sleppa", "undo": "Afturkalla", @@ -523,10 +527,18 @@ "loading_history": "Hleð stöðusögu...", "no_history_found": "Engin stöðusaga fannst." }, + "logbook": { + "messages": { + "was_closed": "var lokað", + "was_opened": "var opnað" + } + }, "media-browser": { "choose_player": "Veldu spilara", "class": { - "music": "Tónlist" + "music": "Tónlist", + "podcast": "Hlaðvarp", + "tv_show": "Sjónvarpsþáttur" } }, "related-items": { @@ -543,6 +555,7 @@ "week": "{count} {count, plural,\n one {vika}\n other {vikur}\n}" }, "future": "Eftir {time}", + "just_now": "Rétt í þessu", "never": "Aldrei", "past": "{time} síðan" }, @@ -664,6 +677,13 @@ "tags": "Strikamerki", "users": "Notendur", "zone": "Svæði" + }, + "reload": { + "homekit": "Endurhlaða HomeKit" + }, + "server_control": { + "restart": "Endurræsa", + "stop": "Stöðva" } } }, @@ -911,6 +931,7 @@ "label": "Tæki" }, "event": { + "context_user_pick": "Veldu notanda", "event_data": "Viðburðargögn", "event_type": "Gerð viðburðar", "label": "Viðburður" @@ -1008,6 +1029,7 @@ "blueprint": { "overview": { "headers": { + "file_name": "Skráarnafn", "name": "Nafn" } } @@ -1247,9 +1269,25 @@ "info": { "built_using": "Byggt með", "caption": "Upplýsingar", + "copy_raw": "Hrár texti", "documentation": "Skjölun", "icons_by": "Smátákn eftir", "integrations": "Samþættingar", + "system_health": { + "checks": { + "homeassistant": { + "docker": "Docker", + "hassio": "HassOS", + "os_name": "Nafn stýrikerfis", + "os_version": "Stýrikerfisútgáfa", + "timezone": "Tímabelti", + "version": "Útgáfa" + }, + "lovelace": { + "mode": "Hamur" + } + } + }, "title": "Upplýsingar" }, "integration_panel_move": { @@ -1380,6 +1418,11 @@ "ozw": { "common": { "zwave": "Z-Wave" + }, + "nodes_table": { + "manufacturer": "Framleiðandi", + "model": "Gerð", + "zwave_plus": "Z-Wave Plus" } }, "person": { @@ -1494,7 +1537,15 @@ }, "tags": { "detail": { - "description": "Lýsing" + "create": "Stofna", + "delete": "Eyða", + "description": "Lýsing", + "name": "Nafn", + "update": "Uppfæra" + }, + "edit": "Breyta", + "headers": { + "name": "Nafn" } }, "users": { @@ -1504,6 +1555,7 @@ "name": "Nafn", "password": "Lykilorð", "password_confirm": "Staðfesta lykilorð", + "password_not_match": "Lykilorð passa ekki saman", "username": "Notandanafn" }, "caption": "Notendur", @@ -1522,14 +1574,17 @@ "new_password": "Nýtt lykilorð", "owner": "Eigandi", "unnamed_user": "Ónefndur notandi", - "update_user": "Uppfæra" + "update_user": "Uppfæra", + "username": "Notandanafn" }, "picker": { "add_user": "Bæta við notanda", "headers": { "group": "Hópur", + "is_owner": "Eigandi", "name": "Nafn", - "system": "Kerfi" + "system": "Kerfi", + "username": "Notandanafn" } } }, @@ -1725,6 +1780,11 @@ "refresh": "Endurnýja" }, "editor": { + "action-editor": { + "actions": { + "more-info": "Frekari upplýsingar" + } + }, "card": { "alarm-panel": { "available_states": "Tiltækar stöður" @@ -1750,7 +1810,14 @@ "required": "Skilyrt" }, "entities": { - "name": "Einingar" + "entity_row": { + "button": "Hnappur", + "weblink": "Veftengill" + }, + "name": "Einingar", + "secondary_info_values": { + "brightness": "Birtustig" + } }, "entity-filter": { "name": "Eininga sía" @@ -1852,6 +1919,11 @@ "domain": "Lén", "no_description": "Engin lýsing tiltæk." }, + "common": { + "add": "Bæta við", + "clear": "Hreinsa", + "edit": "Breyta" + }, "edit_card": { "add": "Bæta við spjaldi", "clear": "Tæma", @@ -2125,6 +2197,9 @@ "dropdown_label": "Mælaborð", "header": "Mælaborð" }, + "enable_shortcuts": { + "header": "Flýtilyklar" + }, "force_narrow": { "description": "Þetta mun fela hliðarstikuna með sambærilegum hætti og á snjalltækum.", "header": "Alltaf fela hliðarstikuna" @@ -2148,6 +2223,7 @@ "header": "Langlífir aðgangstókar", "last_used": "Síðast notaður þann {date} frá {location}", "learn_auth_requests": "Lærðu hvernig á að útbúa auðkenndar beiðnir.", + "name": "Nafn", "not_used": "Hefur aldrei verið notaður", "prompt_copy_token": "Afritaðu aðgangstókann þinn en hann verður ekki birtur aftur.", "prompt_name": "Nafn?" @@ -2186,6 +2262,9 @@ "header": "Loka tengingu sjálfkrafa" }, "themes": { + "dark_mode": { + "auto": "Sjálfvirkt" + }, "dropdown_label": "Þema", "error_no_theme": "Engar þemu í boði.", "header": "Þema", diff --git a/translations/frontend/it.json b/translations/frontend/it.json index d449157c8a..bf03373b3e 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Proprietario", "system-admin": "Amministratori", "system-read-only": "Utenti di sola lettura", "system-users": "Utenti" @@ -1239,7 +1240,7 @@ "edit_ui": "Modifica con l'Interfaccia Utente", "edit_yaml": "Modifica come YAML", "enable_disable": "Abilitare/Disabilitare l'automazione", - "introduction": "Usa le automazioni per dare vita alla tua casa.", + "introduction": "Usa le automazioni per far vivere la tua casa.", "load_error_not_editable": "Solo le Automazioni in automations.yaml sono modificabili.", "load_error_unknown": "Errore durante il caricamento dell'Automazione ({err_no}).", "max": { @@ -1399,11 +1400,13 @@ "blueprint": { "add": { "error_no_url": "Inserisci l'URL del progetto.", + "file_name": "Nome del file di progetto locale", "header": "Aggiungi un nuovo progetto", "import_btn": "Importa progetto", - "import_header": "Importa {name} ({domain})", + "import_header": "Importa \"{name}\" (tipo: {domain})", "import_introduction": "Puoi importare progetti di altri utenti da Github e dai forum della comunità. Immettere l'URL del progetto di seguito.", "importing": "Importazione del progetto in corso ...", + "raw_blueprint": "Contenuto del progetto", "save_btn": "Salva progetto", "saving": "Salvataggio del progetto in corso ...", "unsupported_blueprint": "Questo progetto non è supportato", @@ -1412,15 +1415,19 @@ "caption": "Progetti", "description": "Gestisci i progetti", "overview": { - "add_blueprint": "Aggiungi progetto", + "add_blueprint": "Importa progetto", "confirm_delete_header": "Eliminare questo progetto?", "confirm_delete_text": "Sei sicuro di voler eliminare questo progetto?", + "delete_blueprint": "Elimina progetto", "header": "Editor del progetto", "headers": { + "domain": "Dominio", + "file_name": "Nome file", "name": "Nome" }, "introduction": "L'editor del progetto consente di creare e modificare i progetti.", - "learn_more": "Per saperne di più sui progetti" + "learn_more": "Per saperne di più sui progetti", + "use_blueprint": "Crea automazione" } }, "cloud": { @@ -2209,7 +2216,7 @@ "without_device": "Entità senza dispositivo" }, "icon": "Icona", - "introduction": "Usa le scene per dare vita alla tua casa.", + "introduction": "Usa le scene per far vivere la tua casa.", "load_error_not_editable": "Solo le scene in scene.yaml sono modificabili.", "load_error_unknown": "Errore durante il caricamento della scena ({err_no}).", "name": "Nome", @@ -2393,7 +2400,7 @@ "delete_user": "Elimina utente", "group": "Gruppo", "id": "ID", - "name": "Nome", + "name": "Nome da visualizzare", "new_password": "Nuova password", "owner": "Proprietario", "password_changed": "La password è stata modificata con successo", @@ -2401,19 +2408,24 @@ "system_generated_users_not_editable": "Impossibile aggiornare gli utenti generati dal sistema.", "system_generated_users_not_removable": "Impossibile rimuovere gli utenti generati dal sistema.", "unnamed_user": "Utente senza nome", - "update_user": "Aggiorna" + "update_user": "Aggiorna", + "username": "Nome utente" }, "picker": { "add_user": "Aggiungi utente", "headers": { "group": "Gruppo", - "name": "Nome", - "system": "Sistema" + "is_active": "Attivo", + "is_owner": "Proprietario", + "name": "Nome da visualizzare", + "system": "Generato dal sistema", + "username": "Nome utente" } }, "users_privileges_note": "La funzionalità del gruppo di utenti è in fase di elaborazione. L'utente non sarà in grado di amministrare l'istanza tramite l'Interfaccia Utente. Stiamo ancora verificando tutti gli endpoint dell'API di gestione per garantire che limitino correttamente l'accesso solo agli amministratori." }, "zha": { + "add_device": "Aggiungi dispositivo", "add_device_page": { "discovered_text": "I dispositivi verranno visualizzati qui una volta rilevati.", "discovery_text": "I dispositivi rilevati verranno visualizzati qui. Seguire le istruzioni per il / i dispositivo / i e posizionare il / i dispositivo / i in modalità accoppiamento.", @@ -2474,6 +2486,7 @@ "unbind_button_label": "Scollega gruppo" }, "groups": { + "add_group": "Aggiungi gruppo", "add_members": "Aggiungi membri", "adding_members": "Aggiunta di membri", "caption": "Gruppi", @@ -2516,7 +2529,11 @@ "hint_wakeup": "Alcuni dispositivi, come i sensori Xiaomi, hanno un pulsante di riattivazione che è possibile premere a intervalli di 5 secondi che mantengono i dispositivi svegli mentre si interagisce con loro.", "introduction": "Eseguire i comandi ZHA che interessano un singolo dispositivo. Scegliere un dispositivo per visualizzare un elenco di comandi disponibili." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "Visualizzazione", + "header": "Visualizzazione di rete" + } }, "zone": { "add_zone": "Aggiungi zona", From 08f4aa9d10575c91d62db18430d3626eb8b6773f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 30 Nov 2020 10:59:04 +0100 Subject: [PATCH 12/38] Use balloons as default pic for header. (#7850) --- src/panels/lovelace/header-footer/hui-picture-header-footer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/header-footer/hui-picture-header-footer.ts b/src/panels/lovelace/header-footer/hui-picture-header-footer.ts index 23b25e6470..c7c949be7f 100644 --- a/src/panels/lovelace/header-footer/hui-picture-header-footer.ts +++ b/src/panels/lovelace/header-footer/hui-picture-header-footer.ts @@ -25,7 +25,7 @@ export class HuiPictureHeaderFooter extends LitElement public static getStubConfig(): Record { return { image: - "https://www.home-assistant.io/images/merchandise/shirt-frontpage.png", + "https://www.home-assistant.io/images/lovelace/header-footer/balloons-header.png", tap_action: { action: "none" }, hold_action: { action: "none" }, }; From 8d7ba19a08e16a4a71011869834dda767242d242 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Mon, 30 Nov 2020 05:05:54 -0500 Subject: [PATCH 13/38] Add ZHA fab for adding device when filtered by ZHA (#7848) --- .../devices/ha-config-devices-dashboard.ts | 53 +++++++++---- .../config/entities/ha-config-entities.ts | 74 +++++++++++++------ 2 files changed, 89 insertions(+), 38 deletions(-) diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index 7e954b5dbc..c75a8c6f95 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -1,3 +1,4 @@ +import { mdiPlus } from "@mdi/js"; import { customElement, html, @@ -10,6 +11,7 @@ import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; import { LocalizeFunc } from "../../../common/translations/localize"; +import { computeRTL } from "../../../common/util/compute_rtl"; import { DataTableColumnContainer, DataTableRowData, @@ -96,7 +98,7 @@ export class HaConfigDeviceDashboard extends LitElement { } ); - private _devices = memoizeOne( + private _devicesAndFilterDomains = memoizeOne( ( devices: DeviceRegistryEntry[], entries: ConfigEntry[], @@ -136,13 +138,17 @@ export class HaConfigDeviceDashboard extends LitElement { areaLookup[area.area_id] = area; } + const filterDomains: string[] = []; + filters.forEach((value, key) => { - switch (key) { - case "config_entry": - outputDevices = outputDevices.filter((device) => - device.config_entries.includes(value) - ); - break; + if (key === "config_entry") { + outputDevices = outputDevices.filter((device) => + device.config_entries.includes(value) + ); + const configEntry = entries.find((entry) => entry.entry_id === value); + if (configEntry) { + filterDomains.push(configEntry.domain); + } } }); @@ -176,7 +182,7 @@ export class HaConfigDeviceDashboard extends LitElement { }; }); - return outputDevices; + return { devicesOutput: outputDevices, filteredDomains: filterDomains }; } ); @@ -286,6 +292,16 @@ export class HaConfigDeviceDashboard extends LitElement { } protected render(): TemplateResult { + const { devicesOutput, filteredDomains } = this._devicesAndFilterDomains( + this.devices, + this.entries, + this.entities, + this.areas, + this._searchParms, + this.hass.localize + ); + const includeZHAFab = filteredDomains.includes("zha"); + return html` + ${includeZHAFab + ? html` + + + + ` + : html``} `; } diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index b8e0ee77da..91897b3422 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -1,6 +1,6 @@ import "@material/mwc-list/mwc-list-item"; import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; -import { mdiFilterVariant } from "@mdi/js"; +import { mdiFilterVariant, mdiPlus } from "@mdi/js"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-icon-item"; @@ -70,6 +70,7 @@ import { AreaRegistryEntry, subscribeAreaRegistry, } from "../../../data/area_registry"; +import { computeRTL } from "../../../common/util/compute_rtl"; export interface StateEntity extends EntityRegistryEntry { readonly?: boolean; @@ -274,7 +275,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { }) ); - private _filteredEntities = memoize( + private _filteredEntitiesAndDomains = memoize( ( entities: EntityRegistryEntry[], devices: DeviceRegistryEntry[] | undefined, @@ -283,8 +284,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { filters: URLSearchParams, showDisabled: boolean, showUnavailable: boolean, - showReadOnly: boolean - ): EntityRow[] => { + showReadOnly: boolean, + entries?: ConfigEntry[] + ) => { const result: EntityRow[] = []; // If nothing gets filtered, this is our correct count of entities @@ -312,22 +314,33 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { ? entities.concat(stateEntities) : entities; + const filteredDomains: string[] = []; + filters.forEach((value, key) => { - switch (key) { - case "config_entry": - filteredEntities = filteredEntities.filter( + if (key === "config_entry") { + filteredEntities = filteredEntities.filter( + (entity) => entity.config_entry_id === value + ); + // If we have an active filter and `showReadOnly` is true, the length of `entities` is correct. + // If however, the read-only entities were not added before, we need to check how many would + // have matched the active filter and add that number to the count. + startLength = filteredEntities.length; + if (!showReadOnly) { + startLength += stateEntities.filter( (entity) => entity.config_entry_id === value - ); - // If we have an active filter and `showReadOnly` is true, the length of `entities` is correct. - // If however, the read-only entities were not added before, we need to check how many would - // have matched the active filter and add that number to the count. - startLength = filteredEntities.length; - if (!showReadOnly) { - startLength += stateEntities.filter( - (entity) => entity.config_entry_id === value - ).length; - } - break; + ).length; + } + + if (!entries) { + this._loadConfigEntries(); + return; + } + + const configEntry = entries.find((entry) => entry.entry_id === value); + + if (configEntry) { + filteredDomains.push(configEntry.domain); + } } }); @@ -376,7 +389,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { } this._numHiddenEntities = startLength - result.length; - return result; + return { filteredEntities: result, filteredDomains: filteredDomains }; } ); @@ -426,7 +439,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { this._entries ); - const entityData = this._filteredEntities( + const { + filteredEntities, + filteredDomains, + } = this._filteredEntitiesAndDomains( this._entities, this._devices, this._areas, @@ -434,9 +450,11 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { this._searchParms, this._showDisabled, this._showUnavailable, - this._showReadOnly + this._showReadOnly, + this._entries ); + const includeZHAFab = filteredDomains.includes("zha"); const headerToolbar = this._selectedEntities.length ? html`

@@ -642,13 +660,14 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { .route=${this.route} .tabs=${configSections.integrations} .columns=${this._columns(this.narrow, this.hass.language)} - .data=${entityData} + .data=${filteredEntities} .filter=${this._filter} selectable clickable @selection-changed=${this._handleSelectionChanged} @row-click=${this._openEditEntry} id="entity_id" + .hasFab=${includeZHAFab} >

${headerToolbar}
+ ${includeZHAFab + ? html` + + + + ` + : html``} `; } From 0e362b851be4765fb06f199a5e3545e711a1ee7d Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Tue, 1 Dec 2020 00:32:47 +0000 Subject: [PATCH 14/38] [ci skip] Translation update --- translations/frontend/cs.json | 11 +++ translations/frontend/de.json | 18 +++- translations/frontend/es.json | 11 +++ translations/frontend/et.json | 11 +++ translations/frontend/it.json | 53 +++++++----- translations/frontend/ko.json | 87 +++++++++++++++++-- translations/frontend/lb.json | 131 ++++++++++++++++++++++++++++- translations/frontend/nb.json | 24 +++++- translations/frontend/nl.json | 41 ++++++--- translations/frontend/pl.json | 11 +++ translations/frontend/pt.json | 116 ++++++++++++++++++++++--- translations/frontend/ru.json | 11 +++ translations/frontend/uk.json | 3 + translations/frontend/zh-Hant.json | 11 +++ 14 files changed, 480 insertions(+), 59 deletions(-) diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index 9c3fd24d21..cd92ab7bf1 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -1723,6 +1723,7 @@ }, "header": "Entity", "headers": { + "area": "Oblast", "entity_id": "ID entity", "integration": "Integrace", "name": "Název", @@ -2450,6 +2451,16 @@ "value": "Hodnota" }, "description": "Správa Zigbee Home Automation", + "device_pairing_card": { + "CONFIGURED": "Nastavení dokončeno", + "CONFIGURED_status_text": "Inicializuji", + "INITIALIZED": "Inicializace dokončena", + "INITIALIZED_status_text": "Zařízení je připraveno k použití", + "INTERVIEW_COMPLETE": "Dotazování dokončeno", + "INTERVIEW_COMPLETE_status_text": "Nastavuji", + "PAIRED": "Zařízení nalezeno", + "PAIRED_status_text": "Začínám dotazování" + }, "devices": { "header": "Zigbee Home Automation - Zařízení" }, diff --git a/translations/frontend/de.json b/translations/frontend/de.json index 35c5636361..5ec1908ded 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Besitzer", "system-admin": "Administratoren", "system-read-only": "Nur-Lesen Benutzer", "system-users": "Benutzer" @@ -1740,6 +1741,7 @@ }, "header": "Entitäten", "headers": { + "area": "Bereich", "entity_id": "Entitäts-ID", "integration": "Integration", "name": "Name", @@ -2404,14 +2406,18 @@ "system_generated_users_not_editable": "Systemgenerierte Benutzer können nicht aktualisiert werden.", "system_generated_users_not_removable": "Vom System generierte Benutzer können nicht entfernt werden.", "unnamed_user": "Unbenannter Benutzer", - "update_user": "Aktualisieren" + "update_user": "Aktualisieren", + "username": "Benutzername" }, "picker": { "add_user": "Benutzer hinzufügen", "headers": { "group": "Gruppe", + "is_active": "Aktiv", + "is_owner": "Besitzer", "name": "Name", - "system": "System" + "system": "System", + "username": "Benutzername" } }, "users_privileges_note": "Benutzergruppen sind derzeit noch in Entwicklung. Der Benutzer wird nicht in der Lage sein, Änderungen an der Instanz über das UI vorzunehmen. Derzeit überprüfen wir noch alle API Endpunkte um sicherzustellen dass diese nur von Administratoren genutzt werden können." @@ -2463,6 +2469,14 @@ "value": "Wert" }, "description": "Zigbee Home Automation Netzwerkmanagement", + "device_pairing_card": { + "CONFIGURED": "Konfiguration abgeschlossen", + "CONFIGURED_status_text": "Initialisieren", + "INITIALIZED": "Initialisierung abgeschlossen", + "INITIALIZED_status_text": "Das Gerät ist einsatzbereit", + "INTERVIEW_COMPLETE_status_text": "Konfigurieren", + "PAIRED": "Gerät gefunden" + }, "devices": { "header": "Zigbee Home Automation - Gerät" }, diff --git a/translations/frontend/es.json b/translations/frontend/es.json index e7b0499ff7..43f3b62782 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -1744,6 +1744,7 @@ }, "header": "Entidades", "headers": { + "area": "Área", "entity_id": "ID de entidad", "integration": "Integración", "name": "Nombre", @@ -2471,6 +2472,16 @@ "value": "Valor" }, "description": "Administración de red de Domótica Zigbee", + "device_pairing_card": { + "CONFIGURED": "Configuración completada", + "CONFIGURED_status_text": "Inicializando", + "INITIALIZED": "Inicialización completada", + "INITIALIZED_status_text": "El dispositivo está listo para ser usado", + "INTERVIEW_COMPLETE": "Entrevista completada", + "INTERVIEW_COMPLETE_status_text": "Configurando", + "PAIRED": "Dispositivo encontrado", + "PAIRED_status_text": "Iniciando entrevista" + }, "devices": { "header": "Domótica Zigbee - Dispositivo" }, diff --git a/translations/frontend/et.json b/translations/frontend/et.json index fa58be1404..829de8071c 100644 --- a/translations/frontend/et.json +++ b/translations/frontend/et.json @@ -1744,6 +1744,7 @@ }, "header": "Olemid", "headers": { + "area": "Ala", "entity_id": "Olemi ID", "integration": "Sidumine", "name": "Nimi", @@ -2471,6 +2472,16 @@ "value": "Väärtus" }, "description": "Zigbee Home Automation võrgu haldamine", + "device_pairing_card": { + "CONFIGURED": "Seadistamine on lõpetatud", + "CONFIGURED_status_text": "Lähtestan", + "INITIALIZED": "Lähtestamine on lõpetatud", + "INITIALIZED_status_text": "Seade on kasutamiseks valmis", + "INTERVIEW_COMPLETE": "Küsitlemine on lõpetatud", + "INTERVIEW_COMPLETE_status_text": "Seadistan", + "PAIRED": "Seade on leitud", + "PAIRED_status_text": "Alustan küsitlemist" + }, "devices": { "header": "Zigbee Home Automation - Seade" }, diff --git a/translations/frontend/it.json b/translations/frontend/it.json index bf03373b3e..10c794ee1d 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -1744,6 +1744,7 @@ }, "header": "Entità", "headers": { + "area": "Area", "entity_id": "ID entità", "integration": "Integrazione", "name": "Nome", @@ -2471,6 +2472,16 @@ "value": "Valore" }, "description": "Gestione rete Zigbee Home Automation", + "device_pairing_card": { + "CONFIGURED": "Configurazione completata", + "CONFIGURED_status_text": "Inizializzazione", + "INITIALIZED": "Inizializzazione completata", + "INITIALIZED_status_text": "Il dispositivo è pronto per l'uso", + "INTERVIEW_COMPLETE": "Interrogazione completata", + "INTERVIEW_COMPLETE_status_text": "Configurazione", + "PAIRED": "Dispositivo trovato", + "PAIRED_status_text": "Inizio interrogazione" + }, "devices": { "header": "Zigbee Home Automation - Dispositivo" }, @@ -2811,8 +2822,8 @@ "card": { "alarm-panel": { "available_states": "Stati disponibili", - "description": "La scheda del pannello di allarme consente di Attivare e Disattivare le tue integrazioni del pannello di controllo di allarme.", - "name": "Pannello di allarme" + "description": "La scheda del Pannello di Allarme consente di attivare e disattivare le tue integrazioni del pannello di controllo allarme.", + "name": "Pannello di Allarme" }, "button": { "default_action_help": "L'azione predefinita dipende dalle capacità dell'entità, verrà attivata o disattivata o verranno mostrate più informazioni.", @@ -2876,7 +2887,7 @@ "toggle": "Attiva/disattiva entità." }, "entity-filter": { - "description": "La scheda Filtro Entità consente di definire un elenco di entità che si desidera monitorare solo in un determinato stato.", + "description": "La scheda Filtro Entità consente di definire un elenco di entità che si desidera monitorare quando sono solamente in un determinato stato.", "name": "Filtro Entità" }, "entity": { @@ -2884,10 +2895,10 @@ "name": "Entità" }, "gauge": { - "description": "La scheda Indicatore è una scheda di base che consente di visualizzare visivamente i dati del sensore.", + "description": "La scheda Indicatore è una scheda di base che consente di visualizzare i dati di un sensore.", "name": "Indicatore", "severity": { - "define": "Definire la gravità?", + "define": "Definire l'intensità?", "green": "Verde", "red": "Rosso", "yellow": "Giallo" @@ -2899,15 +2910,15 @@ "camera_image": "Entità Fotocamera", "camera_view": "Vista fotocamera", "double_tap_action": "Azione doppio tocco", - "entities": "Entità", - "entity": "Entità", - "hold_action": "Azione di attesa", + "entities": "Molte Entità", + "entity": "Singola Entità", + "hold_action": "Azione tocco prolungato", "hours_to_show": "Ore da mostrare", "icon": "Icona", "icon_height": "Altezza icona", "image": "Percorso immagine", "manual": "Manuale", - "manual_description": "Devi aggiungere una scheda personalizzata o semplicemente si vuole scrivere manualmente il file in yaml?", + "manual_description": "Devi aggiungere una scheda personalizzata o vuoi semplicemente scrivere manualmente il file in yaml?", "maximum": "Massimo", "minimum": "Minimo", "name": "Nome", @@ -2920,7 +2931,7 @@ "show_state": "Mostrare lo stato?", "state": "Stato", "state_color": "Colorare le icone in base allo stato?", - "tap_action": "Tocca Azione", + "tap_action": "Azione tocco", "theme": "Tema", "title": "Titolo", "unit": "Unità", @@ -2937,27 +2948,27 @@ }, "history-graph": { "description": "La scheda Grafico Storico consente di visualizzare un grafico per ciascuna delle entità elencate.", - "name": "Grafico cronologico" + "name": "Grafico Storico" }, "horizontal-stack": { "description": "La scheda Pila Orizzontale consente di raggruppare insieme più schede, in modo che siano sempre l'una accanto all'altra nello spazio di una colonna.", "name": "Pila orizzontale" }, "humidifier": { - "description": "La scheda Umidificatore fornisce il controllo della tua entità umidificatore, consentendo di modificare l'umidità e la modalità dell'entità.", + "description": "La scheda Umidificatore fornisce il controllo della tua entità umidificatore. Ti consente di modificare l'umidità e la modalità di funzionamento dell'entità.", "name": "Umidificatore" }, "iframe": { - "description": "La scheda Pagina Web consente di incorporare la pagina Web preferita direttamente in Home Assistant.", - "name": "Pagina web" + "description": "La scheda Pagina Web consente di incorporare la tua pagina web preferita direttamente in Home Assistant.", + "name": "Pagina Web" }, "light": { "description": "La scheda Luce consente di modificare la luminosità della luce.", "name": "Luce" }, "logbook": { - "description": "La scheda del Diario di bordo mostra un elenco di eventi per le entità.", - "name": "Diario di bordo" + "description": "La scheda Registro mostra un elenco di eventi per le entità.", + "name": "Registro" }, "map": { "dark_mode": "Modalità scura?", @@ -2970,7 +2981,7 @@ }, "markdown": { "content": "Contenuto", - "description": "La scheda Ribassi viene utilizzata per presentare i ribassi.", + "description": "La scheda Markdown viene utilizzata per eseguire il rendering di testo scritto in linguaggio Markdown per una gradevole formattazione della visualizzazione.", "name": "Markdown" }, "media-control": { @@ -2987,7 +2998,7 @@ }, "picture-glance": { "description": "La scheda Occhiata Immagine mostra un'immagine e gli stati dell'entità corrispondenti come una icona. Le entità sul lato destro consentono azioni di commutazione, altre mostrano più informazioni di dialogo.", - "name": "Vista immagine", + "name": "Sguardo d'Immagine", "state_entity": "Stato Entità" }, "picture": { @@ -2996,7 +3007,7 @@ }, "plant-status": { "description": "La scheda dello Stato della Pianta è per tutti gli adorabili botanici là fuori.", - "name": "Stato pianta" + "name": "Stato della Pianta" }, "sensor": { "description": "La scheda Sensore offre una rapida panoramica dello stato dei sensori con un grafico opzionale per visualizzare il cambiamento nel tempo.", @@ -3006,7 +3017,7 @@ "show_more_detail": "Mostra ulteriori dettagli" }, "shopping-list": { - "description": "La scheda della Lista della Spesa consente di aggiungere, modificare, selezionare e cancellare gli articoli dalla lista della spesa.", + "description": "La scheda Lista della Spesa consente di aggiungere, modificare, selezionare e cancellare gli articoli dalla tua lista della spesa.", "integration_not_loaded": "Questa carta richiede l'integrazione \"shopping_list\" per essere configurata.", "name": "Lista della spesa" }, @@ -3055,7 +3066,7 @@ "options": "Altre opzioni", "pick_card": "Quale scheda vorresti aggiungere?", "pick_card_view_title": "Quale scheda vorresti aggiungere alla tua vista {name}?", - "search_cards": "Schede di ricerca", + "search_cards": "Cerca schede", "show_code_editor": "Mostra Editor di Codice", "show_visual_editor": "Mostra Editor Visivo", "toggle_editor": "Attiva / disattiva l'editor", diff --git a/translations/frontend/ko.json b/translations/frontend/ko.json index b9ed4235c9..efeaee9c67 100644 --- a/translations/frontend/ko.json +++ b/translations/frontend/ko.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "소유자", "system-admin": "관리자", "system-read-only": "읽기 전용 사용자", "system-users": "사용자" @@ -332,13 +333,13 @@ "zwave": { "default": { "dead": "응답없음", - "initializing": "초기화중", + "initializing": "초기화 중", "ready": "준비", "sleeping": "절전모드" }, "query_stage": { "dead": "응답없음 ({query_stage})", - "initializing": "초기화중 ({query_stage})" + "initializing": "초기화 중 ({query_stage})" } } }, @@ -747,6 +748,7 @@ "edit": "구성요소 편집", "history": "기록 내용", "last_changed": "최근 변경 됨", + "last_updated": "최근 업데이트 됨", "person": { "create_zone": "현재 위치로 지역 만들기" }, @@ -807,6 +809,7 @@ "navigation": { "areas": "영역", "automation": "자동화", + "blueprint": "블루프린트", "core": "일반", "customize": "사용자화", "devices": "기기", @@ -972,6 +975,13 @@ "automation": { "caption": "자동화", "description": "자동화를 관리합니다", + "dialog_new": { + "start_empty": "빈 자동화로 시작하기", + "thingtalk": { + "create": "만들기", + "input_label": "이 자동화로 무엇을 하시겠습니까?" + } + }, "editor": { "actions": { "add": "동작 추가", @@ -1052,6 +1062,14 @@ "unsupported_action": "UI 미지원 동작: {action}" }, "alias": "이름", + "blueprint": { + "blueprint_to_use": "사용할 블루프린트", + "header": "블루프린트", + "inputs": "입력", + "manage_blueprints": "블루프린트 관리", + "no_blueprints": "블루프린트가 존재하지 않습니다", + "no_inputs": "이 블루프린트에는 입력이 없습니다." + }, "conditions": { "add": "조건 추가", "delete": "삭제", @@ -1268,6 +1286,39 @@ "show_info_automation": "자동화에 대한 정보 표시" } }, + "blueprint": { + "add": { + "error_no_url": "블루프린트의 URL 을 입력해주세요.", + "file_name": "로컬 블루프린트 파일 이름", + "header": "새로운 블루프린트 추가", + "import_btn": "블루프린트 가져오기", + "import_header": "\"{name}\" (유형: {domain}) 가져오기", + "import_introduction": "Github 및 커뮤니티 포럼에서 다른 사용자의 블루프린트를 가져올 수 있습니다. 블루프린트의 URL 을 하단의 입력란에 입력해주세요.", + "importing": "블루프린트를 가져오는 중 ...", + "raw_blueprint": "블루프린트 내용", + "save_btn": "블루프린트 저장하기", + "saving": "블루프린트 저장 중 ...", + "unsupported_blueprint": "이 블루프린트는 지원되지 않습니다.", + "url": "블루프린트의 URL" + }, + "caption": "블루프린트", + "description": "블루프린트를 관리합니다", + "overview": { + "add_blueprint": "블루프린트 가져오기", + "confirm_delete_header": "이 블루프린트를 삭제하시겠습니까?", + "confirm_delete_text": "이 블루프린트를 삭제하시겠습니까?", + "delete_blueprint": "블루프린트 삭제", + "header": "블루프린트 편집기", + "headers": { + "domain": "도메인", + "file_name": "파일 이름", + "name": "이름" + }, + "introduction": "블루프린트 편집기를 사용하면 블루프린트를 만들고 편집할 수 있습니다.", + "learn_more": "블루프린트에 대해 더 알아보기", + "use_blueprint": "자동화 만들기" + } + }, "cloud": { "account": { "alexa": { @@ -1572,6 +1623,7 @@ }, "header": "구성요소", "headers": { + "area": "영역", "entity_id": "구성요소 ID", "integration": "통합 구성요소", "name": "이름", @@ -2174,18 +2226,23 @@ "system_generated_users_not_editable": "시스템 자동 생성 사용자는 업데이트할 수 없습니다.", "system_generated_users_not_removable": "시스템 자동 생성 사용자는 제거할 수 없습니다.", "unnamed_user": "이름이 없는 사용자", - "update_user": "업데이트" + "update_user": "업데이트", + "username": "사용자 이름" }, "picker": { "headers": { "group": "그룹", + "is_active": "활성화", + "is_owner": "소유자", "name": "이름", - "system": "시스템" + "system": "시스템", + "username": "사용자 이름" } }, "users_privileges_note": "사용자 그룹 기능은 현재 작업 중이며, 사용자는 UI 를 통해 인스턴스를 관리할 수 없습니다. 모든 사용자 관리 API 엔드포인트가 관리자에 대한 액세스를 올바르게 제한하는지를 확인하는 중입니다." }, "zha": { + "add_device": "기기 추가", "add_device_page": { "discovered_text": "기기가 발견되면 여기에 표시됩니다.", "discovery_text": "발견된 기기가 여기에 표시됩니다. 기기의 설명서를 참고하여 기기를 페어링 모드로 설정해주세요.", @@ -2231,6 +2288,16 @@ "value": "값" }, "description": "Zigbee Home Automation 네트워크를 관리합니다", + "device_pairing_card": { + "CONFIGURED": "구성이 완료되었습니다", + "CONFIGURED_status_text": "초기화 중", + "INITIALIZED": "초기화가 완료되었습니다", + "INITIALIZED_status_text": "기기를 사용할 준비가 되었습니다", + "INTERVIEW_COMPLETE": "인터뷰가 완료되었습니다", + "INTERVIEW_COMPLETE_status_text": "구성 중", + "PAIRED": "기기가 발견되었습니다", + "PAIRED_status_text": "인터뷰 시작 중" + }, "devices": { "header": "Zigbee Home Automation - 기기" }, @@ -2246,6 +2313,7 @@ "unbind_button_label": "그룹 바인딩 해제" }, "groups": { + "add_group": "그룹 추가", "add_members": "구성 기기 추가", "adding_members": "구성 기기 추가", "caption": "그룹", @@ -2288,7 +2356,11 @@ "hint_wakeup": "Xiaomi 센서와 같은 일부 기기는 상호 작용하는 동안 기기의 절전 모드 해제가 가능한 약 5초 동안 누를 수 있는 절전 해제 버튼이 있습니다.", "introduction": "단일 기기에 영향을 주는 ZHA 명령을 실행합니다. 사용 가능한 명령 목록을 보려면 기기를 선택해주세요." }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation", + "visualization": { + "caption": "시각화", + "header": "네트워크 시각화" + } }, "zone": { "add_zone": "지역 추가", @@ -2457,6 +2529,8 @@ "filter_attributes": "속성 필터", "filter_entities": "구성요소 필터", "filter_states": "상태 필터", + "last_changed": "최근 변경 됨", + "last_updated": "최근 업데이트 됨", "more_info": "정보 더보기", "no_entities": "구성요소가 없습니다", "set_state": "상태 설정", @@ -2706,7 +2780,8 @@ }, "picture-glance": { "description": "그림 한눈에 보기 카드는 이미지와 해당 구성요소의 상태가 아이콘으로 표시됩니다. 오른쪽의 구성요소는 토글 작업을 허용하고 다른 구성요소는 추가 정보 대화상자를 표시합니다.", - "name": "그림 한눈에 보기" + "name": "그림 한눈에 보기", + "state_entity": "상태 구성요소" }, "picture": { "description": "그림 카드를 사용하면 인터페이스의 다양한 경로를 탐색하거나 서비스를 호출하는 데 사용할 이미지를 설정할 수 있습니다.", diff --git a/translations/frontend/lb.json b/translations/frontend/lb.json index f6ca81caa6..ad5794565c 100644 --- a/translations/frontend/lb.json +++ b/translations/frontend/lb.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Besëtzer", "system-admin": "Administrateuren", "system-read-only": "Benotzer mat nëmmen Lies Rechter", "system-users": "Benotzer" @@ -547,6 +548,11 @@ "clear": "Läschen", "show_areas": "Beräicher uweisen" }, + "blueprint-picker": { + "add_user": "Benotzer erstellen", + "remove_user": "Benotzer läschen", + "select_blueprint": "Plang auswielen" + }, "data-table": { "no-data": "Keng Donnée", "search": "Sichen" @@ -716,6 +722,7 @@ "enabled_cause": "Desaktivéiert duerch {cause}.", "enabled_description": "Deaktivéiert Entitéiten ginn net am Home Assistant bäigesat.", "enabled_label": "Entitéit aktivéieren", + "enabled_restart_confirm": "Start Home Assistant nei fir dës Entitéiten z'aktivéieren", "entity_id": "ID vun der Entitéit", "icon": "Ikon", "icon_error": "Ikonen sollten am format 'prefix:numm' sinn, Beispill: 'mdi:home'", @@ -788,6 +795,11 @@ }, "more_info_control": { "controls": "Kontrollen", + "cover": { + "close_cover": "Paart zoumaachen", + "open_cover": "Paart opmaachen", + "open_tilt_cover": "Paart op Kipp stelle" + }, "details": "Detailler", "dismiss": "Dialog ofbriechen", "edit": "Entitéit änneren", @@ -851,6 +863,29 @@ }, "quick-bar": { "commands": { + "navigation": { + "areas": "Beräicher", + "automation": "Automatisme", + "blueprint": "Pläng", + "core": "Generell", + "customize": "Personaliséierungen", + "devices": "Apparate", + "entities": "Entitéite", + "helpers": "Helfer", + "info": "Info", + "integrations": "Integratioune", + "logs": "Logs", + "lovelace": "Lovelace Tableau de Bord", + "navigate_to": "Navigéieren zu {panel}", + "navigate_to_config": "Navigéieren zu {panel} Konfiguratioun", + "person": "Persoune", + "scene": "Zeene", + "script": "Skripte", + "server_control": "Server Kontrolle", + "tags": "Tags", + "users": "Benotzer", + "zone": "Zone" + }, "reload": { "automation": "Automatisme frësch lueden", "command_line": "Kommando Zeilen Entitéite frësch lueden", @@ -993,6 +1028,20 @@ "automation": { "caption": "Automatismen", "description": "Automatismen verwalten", + "dialog_new": { + "blueprint": { + "use_blueprint": "Plang benotzen" + }, + "header": "Nei Automatisme erstellen", + "how": "Wéi wëlls du deng nei Automatisme erstellen?", + "start_empty": "Mat enger eideler Automatisme ufänken", + "thingtalk": { + "create": "Erstellen", + "header": "Beschréif den Automatisme deen soll erstallt ginn", + "input_label": "Wat soll dësen Automatisme maachen?", + "intro": "A mir probéieren et fir dech z'erstellen. Zum Beispill: Schalt Luuchten aus wann ech fort ginn." + } + }, "editor": { "actions": { "add": "Aktioun dobäisetzen", @@ -1073,6 +1122,14 @@ "unsupported_action": "Keng UI Ënnerstëtzung fir Aktioun: {action}" }, "alias": "Numm", + "blueprint": { + "blueprint_to_use": "Plang fir ze benotzen", + "header": "Plang", + "inputs": "Agab", + "manage_blueprints": "Pläng verwalten", + "no_blueprints": "Du hues kee Plang", + "no_inputs": "Dëse Plang huet keng Agab." + }, "conditions": { "add": "Konditioun dobäisetzen", "delete": "Läschen", @@ -1315,6 +1372,39 @@ } } }, + "blueprint": { + "add": { + "error_no_url": "Gëff d'URL vum Plang un.", + "file_name": "Lokal Plang Datei Numm", + "header": "Neie Plang erstellen", + "import_btn": "Plang importéieren", + "import_header": "Import \"{name}\" (typ: {domain})", + "import_introduction": "Du kanns Pl¨ng vun aaner Github Benotzer an Community Forumer importéieren. Gëff d'URL vum Plang an.", + "importing": "Plang gëtt importéiert...", + "raw_blueprint": "Plang Inhalt", + "save_btn": "Plang späicheren", + "saving": "Plang gëtt gespäichert...", + "unsupported_blueprint": "Dëse Plang gëtt net ënnerstëtzt", + "url": "URL vum Plang" + }, + "caption": "Pläng", + "description": "Pläng verwalten", + "overview": { + "add_blueprint": "Plang importéieren", + "confirm_delete_header": "Dëse Plang läschen?", + "confirm_delete_text": "Sécher fir dëse Plang ze läsche?", + "delete_blueprint": "Plang läschen", + "header": "Plang Editeur", + "headers": { + "domain": "Domain", + "file_name": "Datei Numm", + "name": "Numm" + }, + "introduction": "De Plang Editeur erlabt et Pläng z'erstellen an ze veränneren.", + "learn_more": "Méi iwwert Plèang léieren", + "use_blueprint": "Automatisme erstellen" + } + }, "cloud": { "account": { "alexa": { @@ -1628,6 +1718,7 @@ }, "header": "Entitéiten", "headers": { + "area": "Beräich", "entity_id": "ID vun der Entitéit", "integration": "Integratioun", "name": "Numm", @@ -1689,6 +1780,8 @@ "info": { "built_using": "Erstallt mat", "caption": "Info", + "copy_github": "Fir Github", + "copy_raw": "Rengen Text", "custom_uis": "Personaliséierte Benotzer Interface:", "description": "Informatioune zu denger Home Assistant Installation uweisen", "developed_by": "Entwéckelt vun enger ganzer Rei fantastesche Leit.", @@ -2152,6 +2245,8 @@ }, "picker": { "add_script": "Neie Skript erstellen", + "duplicate": "Duplizéieren", + "duplicate_script": "Skript duplizéieren", "edit_script": "Skript änneren", "header": "Skript Editeur", "headers": { @@ -2283,18 +2378,24 @@ "system_generated_users_not_editable": "Net méiglech System generéiert Benotzer z'aktualiséieren.", "system_generated_users_not_removable": "Ka keng System generéiert Benotzer läschen.", "unnamed_user": "Benotzer ouni Numm", - "update_user": "Aktualiséieren" + "update_user": "Aktualiséieren", + "username": "Benotzernumm" }, "picker": { + "add_user": "Benotzer erstellen", "headers": { "group": "Grupp", + "is_active": "Aktiv", + "is_owner": "Besëtzer", "name": "Numm", - "system": "System" + "system": "System", + "username": "Benotzernumm" } }, "users_privileges_note": "Benotzer Gruppp ass nach \"Work in progress\". De Benotzer kann d'Instanz net via UI verwalten. MIr sin mat engem Audit am gaang vun all Management API Endpunkt fir sécher ze stellen dass déi den accès richteg op Administrateuren limitéieren." }, "zha": { + "add_device": "Apparat dobäisetzen", "add_device_page": { "discovered_text": "Apparater tauchen hei op soubaal se entdeckt sinn.", "discovery_text": "Entdeckten Apparater tauchen op dëser Platz op. Suivéiert d'Instruktiounen fir är Apparater an aktivéiert den Kupplung's Mod.", @@ -2340,6 +2441,16 @@ "value": "Wäert" }, "description": "Gestioun vum Zigbee Home Automation Reseau", + "device_pairing_card": { + "CONFIGURED": "Konfiguratioun fäerdeg", + "CONFIGURED_status_text": "Initialiséiert", + "INITIALIZED": "Initialiséierung fäerdeg", + "INITIALIZED_status_text": "Den Apparat ass prett fir ze benotzen", + "INTERVIEW_COMPLETE": "Interview fäerdeg", + "INTERVIEW_COMPLETE_status_text": "Konfiguréiert", + "PAIRED": "Apparat fonnt", + "PAIRED_status_text": "Interview fänkt un" + }, "devices": { "header": "Zigbee Haus Automatismen - Apparat" }, @@ -2355,6 +2466,7 @@ "unbind_button_label": "Grupp opléisen" }, "groups": { + "add_group": "Grupp dobäisetzen", "add_members": "Membere bäisetzen", "adding_members": "Membere gi bäigesat", "caption": "Gruppe", @@ -2397,7 +2509,11 @@ "hint_wakeup": "Verschidden Apparater wéi Xiaomi Sensoren hunn ee klenge Knäppchen deen een an Intervalle vu ~5s drécke ka fir dass den Apparat un bléift wärend der Interaktioun.", "introduction": "ZHA Kommandoe ausféieren déi nëmmen een Apparat betreffen. Wielt een Apparat aus fir seng Lëscht vun verfügbare Kommandoe ze gesinn." }, - "title": "Zigbee Haus Automatismen" + "title": "Zigbee Haus Automatismen", + "visualization": { + "caption": "Visualisatioun", + "header": "Visualisatioun vum Netzwierk" + } }, "zone": { "add_zone": "Zon dobäisetzen", @@ -2566,6 +2682,8 @@ "filter_attributes": "Attributer filteren", "filter_entities": "Entitéite filteren", "filter_states": "Zoustänn filteren", + "last_changed": "Läscht Ännerung", + "last_updated": "Läscht Aktualiséierung", "more_info": "Méi Info", "no_entities": "Keng Entitéiten", "set_state": "Zoustand setzen", @@ -2817,6 +2935,9 @@ "description": "Luucht Kaart erlaabt et d'Hellegkeet vun de Luuchten ze veränneren.", "name": "Luucht" }, + "logbook": { + "name": "Logbuch" + }, "map": { "dark_mode": "Däischteren Modus", "default_zoom": "Standard Zoom", @@ -2939,6 +3060,7 @@ }, "header": "UI änneren", "header-footer": { + "choose_header_footer": "{typ} auswielen", "footer": "Fousszeilen", "header": "Entête", "types": { @@ -2947,6 +3069,9 @@ }, "graph": { "name": "Graph" + }, + "picture": { + "name": "Bild" } } }, diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index 132cd56af7..b159b3d98c 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Eier", "system-admin": "Administratorer", "system-read-only": "Brukere med lesetilgang", "system-users": "Brukere" @@ -1743,6 +1744,7 @@ }, "header": "Entiteter", "headers": { + "area": "Område", "entity_id": "Entitets-ID", "integration": "Integrasjon", "name": "Navn", @@ -2399,7 +2401,7 @@ "delete_user": "Slett bruker", "group": "Gruppe", "id": "Id", - "name": "Navn", + "name": "Visningsnavn", "new_password": "Nytt passord", "owner": "Eier", "password_changed": "Passordet ble endret", @@ -2407,14 +2409,18 @@ "system_generated_users_not_editable": "Kan ikke oppdatere systemopprettede brukere.", "system_generated_users_not_removable": "Kan ikke fjerne systemopprettede brukere.", "unnamed_user": "Bruker uten navn", - "update_user": "Oppdater" + "update_user": "Oppdater", + "username": "Brukernavn" }, "picker": { "add_user": "Legg til bruker", "headers": { "group": "Gruppe", - "name": "Navn", - "system": "" + "is_active": "Aktiv", + "is_owner": "Eier", + "name": "Visningsnavn", + "system": "System generert", + "username": "Brukernavn" } }, "users_privileges_note": "Brukergruppefunksjonen er et pågående arbeid. Brukeren vil ikke kunne administrere forekomsten via brukergrensesnittet. Vi overvåker fortsatt alle administrasjons-API-endepunkter for å sikre at de begrenser tilgangen til administratorer på riktig måte." @@ -2466,6 +2472,16 @@ "value": "Verdi" }, "description": "ZigBee Hjemmeautomasjon nettverksadministrasjon", + "device_pairing_card": { + "CONFIGURED": "Konfigurasjonen er fullført", + "CONFIGURED_status_text": "Initialiserer", + "INITIALIZED": "Initialiseringen er fullført", + "INITIALIZED_status_text": "Enheten er klar til bruk", + "INTERVIEW_COMPLETE": "Intervju fullført", + "INTERVIEW_COMPLETE_status_text": "Konfigurerer", + "PAIRED": "Enhet funnet", + "PAIRED_status_text": "Starter intervju" + }, "devices": { "header": "ZigBee Hjemmeautomasjon - Enhet" }, diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 8f01075292..9e41528e69 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Eigenaar", "system-admin": "Beheerders", "system-read-only": "Alleen-lezen gebruikers", "system-users": "Gebruikers" @@ -1400,7 +1401,7 @@ "error_no_url": "Voer de URL van de blauwdruk in.", "header": "Voeg een nieuwe blauwdruk toe", "import_btn": "Blauwdruk importeren", - "import_header": "Importeer {name} ( {domain} )", + "import_header": "Importeer \"{name}\" (type: {domain})", "import_introduction": "U kunt blauwdrukken van andere gebruikers importeren vanuit Github en de communityforums. Voer de URL van de blauwdruk hieronder in.", "importing": "Blauwdruk importeren ...", "save_btn": "Bewaar blauwdruk", @@ -1410,14 +1411,18 @@ "caption": "Blauwdrukken", "description": "Beheer blauwdrukken", "overview": { + "add_blueprint": "Blauwdruk importeren", "confirm_delete_header": "Deze blauwdruk verwijderen?", "confirm_delete_text": "Weet je zeker dat je deze blauwdruk wilt verwijderen?", "header": "Blauwdrukeditor", "headers": { + "domain": "Domein", + "file_name": "Bestandsnaam", "name": "Naam" }, "introduction": "Met de blauwdrukeditor kunt je blauwdrukken maken en bewerken.", - "learn_more": "Meer informatie over blauwdrukken" + "learn_more": "Meer informatie over blauwdrukken", + "use_blueprint": "Automatisering maken" } }, "cloud": { @@ -1734,6 +1739,7 @@ }, "header": "Entiteiten", "headers": { + "area": "Gebied", "entity_id": "Entiteits-ID", "integration": "Integratie", "name": "Naam", @@ -1864,11 +1870,11 @@ "delete": "Verwijder", "delete_button": "Verwijder {integration}.", "delete_confirm": "Weet je zeker dat je deze integratie wilt verwijderen?", - "device_unavailable": "apparaat niet beschikbaar", + "device_unavailable": "Apparaat niet beschikbaar", "devices": "{count} {count, plural,\n one {apparaat}\n other {apparaten}\n}", "documentation": "Documentatie", "entities": "{count} {count, plural,\n one {entiteit}\n other {entiteiten}\n}", - "entity_unavailable": "entiteit niet beschikbaar", + "entity_unavailable": "Entiteit niet beschikbaar", "firmware": "Firmware: {version}", "hub": "Verbonden via", "manuf": "door {manufacturer}", @@ -2390,7 +2396,7 @@ "delete_user": "Verwijder gebruiker", "group": "Groep", "id": "ID", - "name": "Naam", + "name": "Weergavenaam", "new_password": "Nieuw wachtwoord", "owner": "Eigenaar", "password_changed": "Het wachtwoord is gewijzigd!", @@ -2398,19 +2404,24 @@ "system_generated_users_not_editable": "Kan door het systeem gegenereerde gebruikers niet bijwerken.", "system_generated_users_not_removable": "Kan door het systeem gegenereerde gebruikers niet verwijderen.", "unnamed_user": "Naamloze gebruiker", - "update_user": "Bijwerken" + "update_user": "Bijwerken", + "username": "Gebruikersnaam" }, "picker": { "add_user": "Gebruiker toevoegen", "headers": { "group": "Groep", - "name": "Naam", - "system": "Systeem" + "is_active": "Actief", + "is_owner": "Eigenaar", + "name": "Weergavenaam", + "system": "Systeem gegenereerd", + "username": "Gebruikersnaam" } }, "users_privileges_note": "Gebruikersgroepen zijn nog in ontwikkeling. De gebruiker kan de instantie niet beheren via de interface. We controleren nog steeds alle beheer API eindpunten om ervoor te zorgen dat ze de toegang tot beheerders correct beperken." }, "zha": { + "add_device": "Apparaat toevoegen", "add_device_page": { "discovered_text": "Apparaten zullen hier verschijnen zodra ze zijn ontdekt.", "discovery_text": "Gevonden apparaten worden hier weergegeven. Volg de instructies voor je apparaat of apparaten en plaats het apparaat of de apparaten in de koppelingsmodus.", @@ -2456,6 +2467,14 @@ "value": "Waarde" }, "description": "Zigbee Home Automation netwerkbeheer", + "device_pairing_card": { + "CONFIGURED": "Configuratie voltooid", + "CONFIGURED_status_text": "Initialiseren", + "INITIALIZED": "Initialisatie voltooid", + "INITIALIZED_status_text": "Het apparaat is klaar voor gebruik", + "INTERVIEW_COMPLETE_status_text": "Configureren", + "PAIRED": "Apparaat gevonden" + }, "devices": { "header": "Zigbee Home Automation - Apparaat" }, @@ -2471,6 +2490,7 @@ "unbind_button_label": "Ontkoppel groep" }, "groups": { + "add_group": "Groep toevoegen", "add_members": "Leden toevoegen", "adding_members": "Leden toevoegen", "caption": "Groepen", @@ -2967,7 +2987,8 @@ }, "picture-glance": { "description": "De Picture Glance-kaart toont een afbeelding en de bijbehorende entiteitstoestanden als een pictogram. De entiteiten aan de rechterkant staan schakelacties toe, andere tonen het dialoogvenster met meer informatie.", - "name": "Afbeelding oogopslag" + "name": "Afbeelding oogopslag", + "state_entity": "Status entiteit" }, "picture": { "description": "Met de Picture-kaart kunt u een afbeelding instellen voor navigatie naar verschillende paden in uw interface of om een service te activeren.", @@ -3178,7 +3199,7 @@ "attribute_not_found": "Kenmerk {attribute} niet beschikbaar in: {entity}", "entity_non_numeric": "Entiteit is niet-numeriek: {entity}", "entity_not_found": "Entiteit niet beschikbaar: {entity}", - "entity_unavailable": "{entity} is momenteel niet beschikbaar", + "entity_unavailable": "Entiteit is momenteel niet beschikbaar: {entity}", "starting": "Home Assistant is aan het opstarten, wellicht is nog niet alles beschikbaar" } }, diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index b7f99e86b8..7488181fb0 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -1744,6 +1744,7 @@ }, "header": "Rejestr encji", "headers": { + "area": "Obszar", "entity_id": "Identyfikator encji", "integration": "Integracja", "name": "Nazwa", @@ -2471,6 +2472,16 @@ "value": "Wartość" }, "description": "Zarządzanie siecią Zigbee Home Automation", + "device_pairing_card": { + "CONFIGURED": "Konfigurowanie zakończona", + "CONFIGURED_status_text": "Inicjalizacja", + "INITIALIZED": "Inicjalizacja zakończona", + "INITIALIZED_status_text": "Urządzenie jest gotowe do użycia", + "INTERVIEW_COMPLETE": "Odpytywanie zakończone", + "INTERVIEW_COMPLETE_status_text": "Konfigurowanie", + "PAIRED": "Znaleziono urządzenie", + "PAIRED_status_text": "Rozpoczęcie odpytywania" + }, "devices": { "header": "Zigbee Home Automation - urządzenie" }, diff --git a/translations/frontend/pt.json b/translations/frontend/pt.json index 26c9d57269..86b6d54144 100644 --- a/translations/frontend/pt.json +++ b/translations/frontend/pt.json @@ -7,6 +7,7 @@ } }, "groups": { + "owner": "Proprietário", "system-admin": "Administradores", "system-read-only": "Utilizadores só com permissões de leitura", "system-users": "Utilizadores" @@ -547,6 +548,11 @@ "clear": "Limpar", "show_areas": "Mostrar áreas" }, + "blueprint-picker": { + "add_user": "Adicionar um utilizador", + "remove_user": "Remover utilizador", + "select_blueprint": "Escolhe um projeto" + }, "data-table": { "no-data": "Dados do evento", "search": "Procurar" @@ -732,15 +738,15 @@ "enabled_label": "Ativar entidade", "enabled_restart_confirm": "Reinicie o Home Assistant para ativar as entidades", "entity_id": "Identificação da entidade", - "icon": "Substituição do ícone", + "icon": "Ícone", "icon_error": "Os ícones devem estar no formato 'prefixo:nome do ícone', por exemplo 'mdi:home'.", - "name": "Substituição do nome", + "name": "Nome", "note": "Nota: isto pode ainda não funcionar com todas as integrações.", "unavailable": "Esta entidade não está atualmente disponível.", "update": "Atualizar" }, "faq": "Documentação", - "no_unique_id": "Esta entidade não tem uma identificação única, portanto suas configurações não podem ser geridas a partir da UI. Para mais informações, ver {faq_link}.", + "no_unique_id": "Esta entidade (\"{entity_id}\") não tem uma identificação única, portanto suas configurações não podem ser geridas a partir da UI. Para mais informações, ver {faq_link}.", "related": "Relacionadas", "settings": "Definições" }, @@ -872,6 +878,7 @@ "navigation": { "areas": "Áreas", "automation": "Automação", + "blueprint": "Projecto", "core": "Geral", "customize": "Personalização", "devices": "Dispositivos", @@ -1041,6 +1048,20 @@ "automation": { "caption": "Automação", "description": "Gerir Automações", + "dialog_new": { + "blueprint": { + "use_blueprint": "Utilize o projeto" + }, + "header": "Criar uma automatização", + "how": "Como quer criar uma automatização?", + "start_empty": "Começar com uma automatização vazia", + "thingtalk": { + "create": "Criar", + "header": "Descreva a automatização que pretende criar", + "input_label": "O que deve fazer esta automatização?", + "intro": "E nós vamos tentar criar por ti. Por exemplo: Desliga as luzes quando eu sair." + } + }, "editor": { "actions": { "add": "Adicionar ação", @@ -1121,6 +1142,14 @@ "unsupported_action": "Ação não suportada: {action}" }, "alias": "Nome", + "blueprint": { + "blueprint_to_use": "Projeto a usar", + "header": "Projeto", + "inputs": "Entrada", + "manage_blueprints": "Gerir projetos", + "no_blueprints": "Tu nao tens nenhum projeto", + "no_inputs": "Este projeto não tem nenhuma entrada" + }, "conditions": { "add": "Acrescentar condição", "delete": "Apagar", @@ -1206,7 +1235,7 @@ "edit_ui": "Editar com IU", "edit_yaml": "Editar como YAML", "enable_disable": "Habilitar/desabilitar automação", - "introduction": "Crie automações para dar vida à sua casa", + "introduction": "Utilize automações para dar vida à sua casa", "load_error_not_editable": "Apenas as automações em automations.yaml são editáveis.", "load_error_unknown": "Erro ao carregar a automação ({err_no}).", "max": { @@ -1358,6 +1387,39 @@ } } }, + "blueprint": { + "add": { + "error_no_url": "Por favor introduza o URL do projeto", + "file_name": "Nome do ficheiro do projeto local", + "header": "Adicionar novo projeto", + "import_btn": "Importar projeto", + "import_header": "Importar \"{name}\" (tipo: {domain})", + "import_introduction": "Você pode importar projetos de outros utilizadores pelo Github e pelo fórum da comunidade. introduza o URL do projeto abaixo", + "importing": "A importar projeto...", + "raw_blueprint": "Conteúdo do projeto", + "save_btn": "Projeto guardado", + "saving": "A guardar projecto...", + "unsupported_blueprint": "Projeto não suportado", + "url": "URL do projeto" + }, + "caption": "Projeto", + "description": "Gerir projeto", + "overview": { + "add_blueprint": "Importar projeto", + "confirm_delete_header": "Apagar projeto", + "confirm_delete_text": "Tem a certeza que pretende apagar este projeto?", + "delete_blueprint": "Excluir projeto", + "header": "Editor de projetos", + "headers": { + "domain": "Domínio", + "file_name": "Nome do ficheiro", + "name": "Nome" + }, + "introduction": "Este editor de projetos permite criar e editar projetos.", + "learn_more": "Aprenda mais sobre projetos", + "use_blueprint": "Criar automação" + } + }, "cloud": { "account": { "alexa": { @@ -1670,6 +1732,7 @@ }, "header": "Entidades", "headers": { + "area": "Área", "entity_id": "ID da Entidade", "integration": "Integração", "name": "Nome", @@ -1682,7 +1745,7 @@ "confirm_partly_text": "Você pode remover apenas {removable} das {selected} entidades selecionadas. As entidades só podem ser removidas quando a integração deixar de suportá-las. Por vezes é necessário reiniciar o Home Assistant antes de poder remover as entidades de uma integração removida. Tem a certeza de que deseja remover as entidades removíveis?", "confirm_partly_title": "Apenas {number} {number, plural,\n uma {selected entity} pode ser removida \n outras {selected entities} podem ser removidas \n}.", "confirm_text": "Deve remover da configuração do Lovelace e das automações se contêm estas entidades", - "confirm_title": "Deseja remover {number} entidades?" + "confirm_title": "Deseja remover {number} {number, plural,\n one {entidade}\n other {entidades}\n}?" }, "search": "Procurar entidades", "selected": "Selecionou {number}", @@ -1732,6 +1795,7 @@ "built_using": "Construído com", "caption": "Informação", "copy_github": "Para GitHub", + "copy_raw": "Texto simples", "custom_uis": "IUs personalizados:", "description": "Ver informações sobre a instalação do Home Assistant", "developed_by": "Desenvolvido por um punhado de pessoas incríveis.", @@ -2126,7 +2190,7 @@ "without_device": "Entidades sem dispositivo" }, "icon": "Ícone", - "introduction": "Crie cenários para dar vida à sua casa.", + "introduction": "Utilize cenários para dar vida à sua casa.", "load_error_not_editable": "Apenas cenários em scenes.yaml são editáveis.", "load_error_unknown": "Erro ao carregar cena ({err_no}).", "name": "Nome", @@ -2309,7 +2373,7 @@ "delete_user": "Apagar utilizador", "group": "Grupo", "id": "ID", - "name": "Nome", + "name": "Nome em Exibição", "new_password": "Nova senha", "owner": "Proprietário", "password_changed": "A senha foi alterada com sucesso", @@ -2317,19 +2381,24 @@ "system_generated_users_not_editable": "Não foi possível atualizar os utilizadores gerados pelo sistema.", "system_generated_users_not_removable": "Não é possível remover utilizadores gerados pelo sistema.", "unnamed_user": "Utilizador sem nome", - "update_user": "Atualizar" + "update_user": "Atualizar", + "username": "Nome de Utilizador" }, "picker": { "add_user": "Adicionar Utilizador", "headers": { "group": "Grupo", - "name": "Nome", - "system": "Sistema" + "is_active": "Ativo", + "is_owner": "Proprietário", + "name": "Nome em Exibição", + "system": "Gerado pelo sistema", + "username": "Nome de Utilizador" } }, "users_privileges_note": "O grupo de utilizadores é um trabalho em progresso. O utilizador não poderá administrar a instância por meio da interface de utilizador. Ainda estamos a auditar todos os endpoints da API de gestão para garantir que eles limitam corretamente o acesso aos administradores." }, "zha": { + "add_device": "Adicionar Dispositivo", "add_device_page": { "discovered_text": "Os dispositivos aparecem aqui uma vez descobertos.", "discovery_text": "Os dispositivos descobertos aparecerão aqui. Siga as instruções para o(s) seu(s) dispositivo(s) e coloque o(s) dispositivo(s) em modo de emparelhamento.", @@ -2375,6 +2444,16 @@ "value": "Valor" }, "description": "Gestão de rede Zigbee Home Automation", + "device_pairing_card": { + "CONFIGURED": "Configuração Completa", + "CONFIGURED_status_text": "A inicializar", + "INITIALIZED": "Inicialização completa", + "INITIALIZED_status_text": "O dispositivo está pronto para uso", + "INTERVIEW_COMPLETE": "Entrevista Completa", + "INTERVIEW_COMPLETE_status_text": "Configurando", + "PAIRED": "Dispositivo encontrado", + "PAIRED_status_text": "A iniciar entrevista" + }, "devices": { "header": "Zigbee Home Automation - Dispositivo" }, @@ -2390,6 +2469,7 @@ "unbind_button_label": "Desvincular grupo" }, "groups": { + "add_group": "Adicionar grupo", "add_members": "Adicionar membros", "adding_members": "A Adicionar membros", "caption": "Grupos", @@ -2432,7 +2512,11 @@ "hint_wakeup": "Alguns dispositivos, como os sensores Xiaomi, têm um botão de ativação que você pode pressionar em intervalos de ~ 5 segundos para manter os dispositivos acordados enquanto você interage com eles.", "introduction": "Execute comandos ZHA que afetem um único dispositivo. Escolha um dispositivo para ver uma lista de comandos disponíveis." }, - "title": "Automação residencial zigbee" + "title": "Automação residencial zigbee", + "visualization": { + "caption": "Visualização", + "header": "Visualização de rede" + } }, "zone": { "add_zone": "Adicionar zona", @@ -2622,6 +2706,7 @@ "reset": "Redefinir para modelo de demonstração", "result_type": "Tipo de resultado", "template_extensions": "Extensões de templates do Home Assistant", + "time": "Este modelo atualiza ao início de cada minuto", "title": "Template", "unknown_error_template": "Erro desconhecido ao processar o template" } @@ -2688,7 +2773,7 @@ } }, "changed_toast": { - "message": "A configuração do Lovelace foi atualizada para este painel, gostaria de atualizar?", + "message": "A configuração do Lovelace foi atualizada para este painel, gostaria de atualizar para verificar as alterações?", "refresh": "Atualizar" }, "editor": { @@ -2852,6 +2937,10 @@ "description": "O cartão Luz permite alterar o brilho da luz.", "name": "Luz" }, + "logbook": { + "description": "O cartão dos registos mostra a lista de eventos para as entidades", + "name": "Registos" + }, "map": { "dark_mode": "Modo escuro?", "default_zoom": "Zoom padrão", @@ -2880,7 +2969,8 @@ }, "picture-glance": { "description": "O cartão Vista de imagem mostra uma imagem e os estados das entidades correspondentes como um ícone. As entidades do lado direito permitem alternar ações, outras mostram a opção mais informações.", - "name": "Vista sobre imagem" + "name": "Vista sobre imagem", + "state_entity": "Estado da entidade" }, "picture": { "description": "O cartão de imagem permite definir uma imagem a ser usada para navegação em vários pontos na sua interface ou para chamar um serviço.", diff --git a/translations/frontend/ru.json b/translations/frontend/ru.json index b68d87709d..2cdf4bc2e0 100644 --- a/translations/frontend/ru.json +++ b/translations/frontend/ru.json @@ -1687,6 +1687,7 @@ }, "header": "Объекты", "headers": { + "area": "Помещение", "entity_id": "ID объекта", "integration": "Интеграция", "name": "Название", @@ -2414,6 +2415,16 @@ "value": "Значение" }, "description": "Управление сетью Zigbee Home Automation", + "device_pairing_card": { + "CONFIGURED": "Настройка завершена", + "CONFIGURED_status_text": "Инициализация", + "INITIALIZED": "Инициализация завершена", + "INITIALIZED_status_text": "Устройство готово к использованию", + "INTERVIEW_COMPLETE": "Опрос завершен", + "INTERVIEW_COMPLETE_status_text": "Настройка", + "PAIRED": "Найдено устройство", + "PAIRED_status_text": "Опрос начат" + }, "devices": { "header": "Zigbee Home Automation - Устройство" }, diff --git a/translations/frontend/uk.json b/translations/frontend/uk.json index dc18d54118..23dfa07277 100644 --- a/translations/frontend/uk.json +++ b/translations/frontend/uk.json @@ -2876,6 +2876,9 @@ "dropdown_label": "Панель", "header": "Панель" }, + "enable_shortcuts": { + "header": "Гарячі клавіші" + }, "force_narrow": { "description": "Це дозволить приховати бічну панель за замовчуванням, як і для мобільних пристроїв.", "header": "Завжди приховувати бічну панель" diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index 344a8dce13..00af6fe5cd 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -1744,6 +1744,7 @@ }, "header": "實體", "headers": { + "area": "分區", "entity_id": "實體 ID", "integration": "整合", "name": "名稱", @@ -2471,6 +2472,16 @@ "value": "數值" }, "description": "Zigbee 家庭自動化網路管理", + "device_pairing_card": { + "CONFIGURED": "設定完成", + "CONFIGURED_status_text": "初始化中", + "INITIALIZED": "初始化完成", + "INITIALIZED_status_text": "設備已準備就緒", + "INTERVIEW_COMPLETE": "探訪完成", + "INTERVIEW_COMPLETE_status_text": "設定中", + "PAIRED": "找到設備", + "PAIRED_status_text": "開始探訪" + }, "devices": { "header": "Zigbee 家庭自動化 - 設備" }, From 3ebf816ce20ef8230fe867aa0c9cc0399e045eb7 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 1 Dec 2020 22:51:15 +0100 Subject: [PATCH 15/38] Fix height of `ha-icon-input` (#7767) --- src/components/ha-icon-input.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/ha-icon-input.ts b/src/components/ha-icon-input.ts index 83761e6c40..11f310c91f 100644 --- a/src/components/ha-icon-input.ts +++ b/src/components/ha-icon-input.ts @@ -60,8 +60,9 @@ export class HaIconInput extends LitElement { static get styles() { return css` ha-icon { - position: relative; - bottom: 4px; + position: absolute; + bottom: 2px; + right: 0; } `; } From 295390c8e9110ad9ceb58db8f42e22bc25df107c Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Wed, 2 Dec 2020 00:32:30 +0000 Subject: [PATCH 16/38] [ci skip] Translation update --- translations/frontend/cs.json | 3 ++- translations/frontend/zh-Hans.json | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/translations/frontend/cs.json b/translations/frontend/cs.json index cd92ab7bf1..01c1bbdf87 100644 --- a/translations/frontend/cs.json +++ b/translations/frontend/cs.json @@ -1406,7 +1406,8 @@ "file_name": "Název souboru", "name": "Jméno" }, - "learn_more": "Další informace o šablonkách konfigurace" + "learn_more": "Další informace o šablonkách konfigurace", + "use_blueprint": "Vytvořit automatizaci" } }, "cloud": { diff --git a/translations/frontend/zh-Hans.json b/translations/frontend/zh-Hans.json index e8ca6a96bd..917bcb3805 100644 --- a/translations/frontend/zh-Hans.json +++ b/translations/frontend/zh-Hans.json @@ -1744,6 +1744,7 @@ }, "header": "实体", "headers": { + "area": "区域", "entity_id": "实体 ID", "integration": "集成", "name": "名称", @@ -2471,6 +2472,16 @@ "value": "值" }, "description": "Zigbee 智能家居(ZHA) 网络管理", + "device_pairing_card": { + "CONFIGURED": "配置完成", + "CONFIGURED_status_text": "正在初始化", + "INITIALIZED": "初始化完成", + "INITIALIZED_status_text": "设备可以使用了", + "INTERVIEW_COMPLETE": "协商完成", + "INTERVIEW_COMPLETE_status_text": "正在配置", + "PAIRED": "发现设备", + "PAIRED_status_text": "开始协商" + }, "devices": { "header": "Zigbee 家庭自动化 - 设备" }, From c485ea9d7b368745adce4440161f55229fed2ca4 Mon Sep 17 00:00:00 2001 From: Josh McCarty Date: Wed, 2 Dec 2020 03:51:56 -0700 Subject: [PATCH 17/38] Add number formatting to counter entity state display (#7868) --- src/common/entity/compute_state_display.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/entity/compute_state_display.ts b/src/common/entity/compute_state_display.ts index 7a2bf77f2a..f946d34015 100644 --- a/src/common/entity/compute_state_display.ts +++ b/src/common/entity/compute_state_display.ts @@ -67,6 +67,10 @@ export const computeStateDisplay = ( } } + if (domain === "counter") { + return formatNumber(compareState, language); + } + return ( // Return device class translation (stateObj.attributes.device_class && From 25f7cbea5acf25ea010948ec9e831662c4162e64 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 2 Dec 2020 12:10:31 +0100 Subject: [PATCH 18/38] Add target selector (#7864) Co-authored-by: Paulus Schoutsen --- src/common/ensure-array.ts | 6 + .../device/ha-area-devices-picker.ts | 4 +- src/components/device/ha-device-picker.ts | 29 +- src/components/entity/ha-entity-picker.ts | 12 + src/components/ha-area-picker.ts | 225 ++++++- src/components/ha-button-toggle-group.ts | 46 +- .../ha-selector/ha-selector-action.ts | 45 ++ .../ha-selector/ha-selector-area.ts | 73 ++- .../ha-selector/ha-selector-entity.ts | 9 +- .../ha-selector/ha-selector-target.ts | 153 +++++ src/components/ha-selector/ha-selector.ts | 2 + src/components/ha-target-picker.ts | 595 ++++++++++++++++++ src/data/automation.ts | 4 +- src/data/script.ts | 6 +- src/data/selector.ts | 43 +- src/data/target.ts | 5 + .../automation/blueprint-automation-editor.ts | 12 +- .../config/automation/ha-automation-editor.ts | 2 + src/panels/config/ha-config-section.ts | 6 +- src/translations/en.json | 10 + 20 files changed, 1224 insertions(+), 63 deletions(-) create mode 100644 src/common/ensure-array.ts create mode 100644 src/components/ha-selector/ha-selector-action.ts create mode 100644 src/components/ha-selector/ha-selector-target.ts create mode 100644 src/components/ha-target-picker.ts create mode 100644 src/data/target.ts diff --git a/src/common/ensure-array.ts b/src/common/ensure-array.ts new file mode 100644 index 0000000000..43d3dbb1f5 --- /dev/null +++ b/src/common/ensure-array.ts @@ -0,0 +1,6 @@ +export const ensureArray = (value?: any) => { + if (!value || Array.isArray(value)) { + return value; + } + return [value]; +}; diff --git a/src/components/device/ha-area-devices-picker.ts b/src/components/device/ha-area-devices-picker.ts index bfd61e7479..ed3d5c25f3 100644 --- a/src/components/device/ha-area-devices-picker.ts +++ b/src/components/device/ha-area-devices-picker.ts @@ -139,7 +139,7 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { private _filteredDevices: DeviceRegistryEntry[] = []; - private _getDevices = memoizeOne( + private _getAreasWithDevices = memoizeOne( ( devices: DeviceRegistryEntry[], areas: AreaRegistryEntry[], @@ -277,7 +277,7 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { if (!this._devices || !this._areas || !this._entities) { return html``; } - const areas = this._getDevices( + const areas = this._getAreasWithDevices( this._devices, this._areas, this._entities, diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index bc43292268..fa7f1e70f1 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -111,6 +111,18 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { @property({ type: Boolean }) private _opened?: boolean; + public open() { + this.updateComplete.then(() => { + (this.shadowRoot?.querySelector("vaadin-combo-box-light") as any)?.open(); + }); + } + + public focus() { + this.updateComplete.then(() => { + this.shadowRoot?.querySelector("paper-input")?.focus(); + }); + } + private _getDevices = memoizeOne( ( devices: DeviceRegistryEntry[], @@ -126,14 +138,17 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { } const deviceEntityLookup: DeviceEntityLookup = {}; - for (const entity of entities) { - if (!entity.device_id) { - continue; + + if (includeDomains || excludeDomains || includeDeviceClasses) { + for (const entity of entities) { + if (!entity.device_id) { + continue; + } + if (!(entity.device_id in deviceEntityLookup)) { + deviceEntityLookup[entity.device_id] = []; + } + deviceEntityLookup[entity.device_id].push(entity); } - if (!(entity.device_id in deviceEntityLookup)) { - deviceEntityLookup[entity.device_id] = []; - } - deviceEntityLookup[entity.device_id].push(entity); } const areaLookup: { [areaId: string]: AreaRegistryEntry } = {}; diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index 6b06f855c2..c83c6a44e3 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -101,6 +101,18 @@ export class HaEntityPicker extends LitElement { @query("vaadin-combo-box-light", true) private _comboBox!: HTMLElement; + public open() { + this.updateComplete.then(() => { + (this.shadowRoot?.querySelector("vaadin-combo-box-light") as any)?.open(); + }); + } + + public focus() { + this.updateComplete.then(() => { + this.shadowRoot?.querySelector("paper-input")?.focus(); + }); + } + private _initedStates = false; private _states: HassEntity[] = []; diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index d0ab2410c1..7a9cb710d1 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -29,6 +29,17 @@ import { SubscribeMixin } from "../mixins/subscribe-mixin"; import { PolymerChangedEvent } from "../polymer-types"; import { HomeAssistant } from "../types"; import memoizeOne from "memoize-one"; +import { + DeviceEntityLookup, + DeviceRegistryEntry, + subscribeDeviceRegistry, +} from "../data/device_registry"; +import { + EntityRegistryEntry, + subscribeEntityRegistry, +} from "../data/entity_registry"; +import { computeDomain } from "../common/entity/compute_domain"; +import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker"; const rowRenderer = ( root: HTMLElement, @@ -71,39 +82,225 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { @property() public placeholder?: string; - @property() public _areas?: AreaRegistryEntry[]; - @property({ type: Boolean, attribute: "no-add" }) public noAdd?: boolean; + /** + * Show only areas with entities from specific domains. + * @type {Array} + * @attr include-domains + */ + @property({ type: Array, attribute: "include-domains" }) + public includeDomains?: string[]; + + /** + * Show no areas with entities of these domains. + * @type {Array} + * @attr exclude-domains + */ + @property({ type: Array, attribute: "exclude-domains" }) + public excludeDomains?: string[]; + + /** + * Show only areas with entities of these device classes. + * @type {Array} + * @attr include-device-classes + */ + @property({ type: Array, attribute: "include-device-classes" }) + public includeDeviceClasses?: string[]; + + @property() public deviceFilter?: HaDevicePickerDeviceFilterFunc; + + @property() public entityFilter?: (entity: EntityRegistryEntry) => boolean; + + @internalProperty() private _areas?: AreaRegistryEntry[]; + + @internalProperty() private _devices?: DeviceRegistryEntry[]; + + @internalProperty() private _entities?: EntityRegistryEntry[]; + @internalProperty() private _opened?: boolean; public hassSubscribe(): UnsubscribeFunc[] { return [ subscribeAreaRegistry(this.hass.connection!, (areas) => { - this._areas = this.noAdd - ? areas - : [ - ...areas, - { - area_id: "add_new", - name: this.hass.localize("ui.components.area-picker.add_new"), - }, - ]; + this._areas = areas; + }), + subscribeDeviceRegistry(this.hass.connection!, (devices) => { + this._devices = devices; + }), + subscribeEntityRegistry(this.hass.connection!, (entities) => { + this._entities = entities; }), ]; } + public open() { + this.updateComplete.then(() => { + (this.shadowRoot?.querySelector("vaadin-combo-box-light") as any)?.open(); + }); + } + + public focus() { + this.updateComplete.then(() => { + this.shadowRoot?.querySelector("paper-input")?.focus(); + }); + } + + private _getAreas = memoizeOne( + ( + areas: AreaRegistryEntry[], + devices: DeviceRegistryEntry[], + entities: EntityRegistryEntry[], + includeDomains: this["includeDomains"], + excludeDomains: this["excludeDomains"], + includeDeviceClasses: this["includeDeviceClasses"], + deviceFilter: this["deviceFilter"], + entityFilter: this["entityFilter"], + noAdd: this["noAdd"] + ): AreaRegistryEntry[] => { + const deviceEntityLookup: DeviceEntityLookup = {}; + let inputDevices: DeviceRegistryEntry[] | undefined; + let inputEntities: EntityRegistryEntry[] | undefined; + + if (includeDomains || excludeDomains || includeDeviceClasses) { + for (const entity of entities) { + if (!entity.device_id) { + continue; + } + if (!(entity.device_id in deviceEntityLookup)) { + deviceEntityLookup[entity.device_id] = []; + } + deviceEntityLookup[entity.device_id].push(entity); + } + inputDevices = devices; + inputEntities = entities.filter((entity) => entity.area_id); + } else if (deviceFilter) { + inputDevices = devices; + } else if (entityFilter) { + inputEntities = entities.filter((entity) => entity.area_id); + } + + if (includeDomains) { + inputDevices = inputDevices!.filter((device) => { + const devEntities = deviceEntityLookup[device.id]; + if (!devEntities || !devEntities.length) { + return false; + } + return deviceEntityLookup[device.id].some((entity) => + includeDomains.includes(computeDomain(entity.entity_id)) + ); + }); + inputEntities = inputEntities!.filter((entity) => + includeDomains.includes(computeDomain(entity.entity_id)) + ); + } + + if (excludeDomains) { + inputDevices = inputDevices!.filter((device) => { + const devEntities = deviceEntityLookup[device.id]; + if (!devEntities || !devEntities.length) { + return true; + } + return entities.every( + (entity) => + !excludeDomains.includes(computeDomain(entity.entity_id)) + ); + }); + inputEntities = inputEntities!.filter( + (entity) => !excludeDomains.includes(computeDomain(entity.entity_id)) + ); + } + + if (includeDeviceClasses) { + inputDevices = inputDevices!.filter((device) => { + const devEntities = deviceEntityLookup[device.id]; + if (!devEntities || !devEntities.length) { + return false; + } + return deviceEntityLookup[device.id].some((entity) => { + const stateObj = this.hass.states[entity.entity_id]; + if (!stateObj) { + return false; + } + return ( + stateObj.attributes.device_class && + includeDeviceClasses.includes(stateObj.attributes.device_class) + ); + }); + }); + inputEntities = inputEntities!.filter((entity) => { + const stateObj = this.hass.states[entity.entity_id]; + return ( + stateObj.attributes.device_class && + includeDeviceClasses.includes(stateObj.attributes.device_class) + ); + }); + } + + if (deviceFilter) { + inputDevices = inputDevices!.filter((device) => deviceFilter!(device)); + } + + if (entityFilter) { + entities = entities.filter((entity) => entityFilter!(entity)); + } + + let outputAreas = areas; + + let areaIds: string[] | undefined; + + if (inputDevices) { + areaIds = inputDevices + .filter((device) => device.area_id) + .map((device) => device.area_id!); + } + + if (inputEntities) { + areaIds = (areaIds ?? []).concat( + inputEntities + .filter((entity) => entity.area_id) + .map((entity) => entity.area_id!) + ); + } + + if (areaIds) { + outputAreas = areas.filter((area) => areaIds!.includes(area.area_id)); + } + + return noAdd + ? outputAreas + : [ + ...outputAreas, + { + area_id: "add_new", + name: this.hass.localize("ui.components.area-picker.add_new"), + }, + ]; + } + ); + protected render(): TemplateResult { - if (!this._areas) { + if (!this._devices || !this._areas || !this._entities) { return html``; } + const areas = this._getAreas( + this._areas, + this._devices, + this._entities, + this.includeDomains, + this.excludeDomains, + this.includeDeviceClasses, + this.deviceFilter, + this.entityFilter, + this.noAdd + ); return html` ` : ""} - ${this._areas.length > 0 + ${areas.length > 0 ? html` - ${this.buttons.map( - (button) => html` - - - - ` + ${this.buttons.map((button) => + button.iconPath + ? html` + + ` + : html`${button.label}` )}
`; @@ -49,13 +55,15 @@ export class HaButtonToggleGroup extends LitElement { --mdc-icon-button-size: var(--button-toggle-size, 36px); --mdc-icon-size: var(--button-toggle-icon-size, 20px); } - mwc-icon-button { + mwc-icon-button, + mwc-button { border: 1px solid var(--primary-color); border-right-width: 0px; position: relative; cursor: pointer; } - mwc-icon-button::before { + mwc-icon-button::before, + mwc-button::before { top: 0; left: 0; width: 100%; @@ -67,17 +75,21 @@ export class HaButtonToggleGroup extends LitElement { content: ""; transition: opacity 15ms linear, background-color 15ms linear; } - mwc-icon-button[active]::before { + mwc-icon-button[active]::before, + mwc-button[active]::before { opacity: var(--mdc-icon-button-ripple-opacity, 0.12); } - mwc-icon-button:first-child { + mwc-icon-button:first-child, + mwc-button:first-child { border-radius: 4px 0 0 4px; } - mwc-icon-button:last-child { + mwc-icon-button:last-child, + mwc-button:last-child { border-radius: 0 4px 4px 0; border-right-width: 1px; } - mwc-icon-button:only-child { + mwc-icon-button:only-child, + mwc-button:only-child { border-radius: 4px; border-right-width: 1px; } diff --git a/src/components/ha-selector/ha-selector-action.ts b/src/components/ha-selector/ha-selector-action.ts new file mode 100644 index 0000000000..c6e06e3a12 --- /dev/null +++ b/src/components/ha-selector/ha-selector-action.ts @@ -0,0 +1,45 @@ +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, +} from "lit-element"; +import { HomeAssistant } from "../../types"; +import { ActionSelector } from "../../data/selector"; +import { Action } from "../../data/script"; +import "../../panels/config/automation/action/ha-automation-action"; + +@customElement("ha-selector-action") +export class HaActionSelector extends LitElement { + @property() public hass!: HomeAssistant; + + @property() public selector!: ActionSelector; + + @property() public value?: Action; + + @property() public label?: string; + + protected render() { + return html``; + } + + static get styles(): CSSResult { + return css` + ha-automation-action { + display: block; + margin-bottom: 16px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-selector-action": HaActionSelector; + } +} diff --git a/src/components/ha-selector/ha-selector-area.ts b/src/components/ha-selector/ha-selector-area.ts index fb3a051b69..d3f7d2f6a7 100644 --- a/src/components/ha-selector/ha-selector-area.ts +++ b/src/components/ha-selector/ha-selector-area.ts @@ -1,7 +1,16 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { + customElement, + html, + internalProperty, + LitElement, + property, +} from "lit-element"; import { HomeAssistant } from "../../types"; import { AreaSelector } from "../../data/selector"; import "../ha-area-picker"; +import { ConfigEntry, getConfigEntries } from "../../data/config_entries"; +import { DeviceRegistryEntry } from "../../data/device_registry"; +import { EntityRegistryEntry } from "../../data/entity_registry"; @customElement("ha-selector-area") export class HaAreaSelector extends LitElement { @@ -13,14 +22,76 @@ export class HaAreaSelector extends LitElement { @property() public label?: string; + @internalProperty() public _configEntries?: ConfigEntry[]; + + protected updated(changedProperties) { + if (changedProperties.has("selector")) { + const oldSelector = changedProperties.get("selector"); + if ( + oldSelector !== this.selector && + this.selector.area.device?.integration + ) { + this._loadConfigEntries(); + } + } + } + protected render() { return html` this._filterDevices(device)} + .entityFilter=${(entity) => this._filterEntities(entity)} + .includeDeviceClasses=${this.selector.area.entity?.device_class + ? [this.selector.area.entity.device_class] + : undefined} + .includeDomains=${this.selector.area.entity?.domain + ? [this.selector.area.entity.domain] + : undefined} >`; } + + private _filterEntities(entity: EntityRegistryEntry): boolean { + if (this.selector.area.entity?.integration) { + if (entity.platform !== this.selector.area.entity.integration) { + return false; + } + } + return true; + } + + private _filterDevices(device: DeviceRegistryEntry): boolean { + if ( + this.selector.area.device?.manufacturer && + device.manufacturer !== this.selector.area.device.manufacturer + ) { + return false; + } + if ( + this.selector.area.device?.model && + device.model !== this.selector.area.device.model + ) { + return false; + } + if (this.selector.area.device?.integration) { + if ( + !this._configEntries?.some((entry) => + device.config_entries.includes(entry.entry_id) + ) + ) { + return false; + } + } + return true; + } + + private async _loadConfigEntries() { + this._configEntries = (await getConfigEntries(this.hass)).filter( + (entry) => entry.domain === this.selector.area.device?.integration + ); + } } declare global { diff --git a/src/components/ha-selector/ha-selector-entity.ts b/src/components/ha-selector/ha-selector-entity.ts index c32f995ae4..e6bfba75b5 100644 --- a/src/components/ha-selector/ha-selector-entity.ts +++ b/src/components/ha-selector/ha-selector-entity.ts @@ -19,7 +19,7 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { @property() public selector!: EntitySelector; - @internalProperty() private _entities?: Record; + @internalProperty() private _entityPlaformLookup?: Record; @property() public value?: any; @@ -45,7 +45,7 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { } entityLookup[confEnt.entity_id] = confEnt.platform; } - this._entities = entityLookup; + this._entityPlaformLookup = entityLookup; }), ]; } @@ -66,8 +66,9 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { } if (this.selector.entity.integration) { if ( - !this._entities || - this._entities[entity.entity_id] !== this.selector.entity.integration + !this._entityPlaformLookup || + this._entityPlaformLookup[entity.entity_id] !== + this.selector.entity.integration ) { return false; } diff --git a/src/components/ha-selector/ha-selector-target.ts b/src/components/ha-selector/ha-selector-target.ts new file mode 100644 index 0000000000..aa6d2cfdb5 --- /dev/null +++ b/src/components/ha-selector/ha-selector-target.ts @@ -0,0 +1,153 @@ +import { + css, + CSSResult, + customElement, + html, + internalProperty, + LitElement, + property, +} from "lit-element"; +import { HomeAssistant } from "../../types"; +import { TargetSelector } from "../../data/selector"; +import { ConfigEntry, getConfigEntries } from "../../data/config_entries"; +import { DeviceRegistryEntry } from "../../data/device_registry"; +import "../ha-target-picker"; +import "@material/mwc-list/mwc-list-item"; +import "@polymer/paper-input/paper-input"; +import "@material/mwc-list/mwc-list"; +import { + EntityRegistryEntry, + subscribeEntityRegistry, +} from "../../data/entity_registry"; +import { Target } from "../../data/target"; +import "@material/mwc-tab-bar/mwc-tab-bar"; +import "@material/mwc-tab/mwc-tab"; +import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; +import { SubscribeMixin } from "../../mixins/subscribe-mixin"; + +@customElement("ha-selector-target") +export class HaTargetSelector extends SubscribeMixin(LitElement) { + @property() public hass!: HomeAssistant; + + @property() public selector!: TargetSelector; + + @property() public value?: Target; + + @property() public label?: string; + + @internalProperty() private _entityPlaformLookup?: Record; + + @internalProperty() private _configEntries?: ConfigEntry[]; + + public hassSubscribe(): UnsubscribeFunc[] { + return [ + subscribeEntityRegistry(this.hass.connection!, (entities) => { + const entityLookup = {}; + for (const confEnt of entities) { + if (!confEnt.platform) { + continue; + } + entityLookup[confEnt.entity_id] = confEnt.platform; + } + this._entityPlaformLookup = entityLookup; + }), + ]; + } + + protected updated(changedProperties) { + if (changedProperties.has("selector")) { + const oldSelector = changedProperties.get("selector"); + if ( + oldSelector !== this.selector && + this.selector.target.device?.integration + ) { + this._loadConfigEntries(); + } + } + } + + protected render() { + return html` this._filterDevices(device)} + .entityRegFilter=${(entity: EntityRegistryEntry) => + this._filterRegEntities(entity)} + .entityFilter=${(entity: HassEntity) => this._filterEntities(entity)} + .includeDeviceClasses=${this.selector.target.entity?.device_class + ? [this.selector.target.entity.device_class] + : undefined} + .includeDomains=${this.selector.target.entity?.domain + ? [this.selector.target.entity.domain] + : undefined} + >`; + } + + private _filterEntities(entity: HassEntity): boolean { + if (this.selector.target.entity?.integration) { + if ( + !this._entityPlaformLookup || + this._entityPlaformLookup[entity.entity_id] !== + this.selector.target.entity.integration + ) { + return false; + } + } + return true; + } + + private _filterRegEntities(entity: EntityRegistryEntry): boolean { + if (this.selector.target.entity?.integration) { + if (entity.platform !== this.selector.target.entity.integration) { + return false; + } + } + return true; + } + + private _filterDevices(device: DeviceRegistryEntry): boolean { + if ( + this.selector.target.device?.manufacturer && + device.manufacturer !== this.selector.target.device.manufacturer + ) { + return false; + } + if ( + this.selector.target.device?.model && + device.model !== this.selector.target.device.model + ) { + return false; + } + if (this.selector.target.device?.integration) { + if ( + !this._configEntries?.some((entry) => + device.config_entries.includes(entry.entry_id) + ) + ) { + return false; + } + } + return true; + } + + private async _loadConfigEntries() { + this._configEntries = (await getConfigEntries(this.hass)).filter( + (entry) => entry.domain === this.selector.target.device?.integration + ); + } + + static get styles(): CSSResult { + return css` + ha-target-picker { + margin: 0 -8px; + display: block; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-selector-target": HaTargetSelector; + } +} diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts index 5e607d61fd..3c88b2da25 100644 --- a/src/components/ha-selector/ha-selector.ts +++ b/src/components/ha-selector/ha-selector.ts @@ -5,9 +5,11 @@ import { HomeAssistant } from "../../types"; import "./ha-selector-entity"; import "./ha-selector-device"; import "./ha-selector-area"; +import "./ha-selector-target"; import "./ha-selector-number"; import "./ha-selector-boolean"; import "./ha-selector-time"; +import "./ha-selector-action"; import { Selector } from "../../data/selector"; @customElement("ha-selector") diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts new file mode 100644 index 0000000000..487e557568 --- /dev/null +++ b/src/components/ha-target-picker.ts @@ -0,0 +1,595 @@ +import { + css, + CSSResult, + customElement, + html, + internalProperty, + LitElement, + property, + query, + unsafeCSS, +} from "lit-element"; +import { HomeAssistant } from "../types"; +// @ts-ignore +import chipStyles from "@material/chips/dist/mdc.chips.min.css"; +import { + mdiSofa, + mdiDevices, + mdiClose, + mdiPlus, + mdiUnfoldMoreVertical, +} from "@mdi/js"; +import "./ha-svg-icon"; +import "./ha-icon"; +import "@material/mwc-icon-button/mwc-icon-button"; +import { classMap } from "lit-html/directives/class-map"; +import "@material/mwc-button/mwc-button"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { + AreaRegistryEntry, + subscribeAreaRegistry, +} from "../data/area_registry"; +import { + DeviceRegistryEntry, + subscribeDeviceRegistry, +} from "../data/device_registry"; +import { + EntityRegistryEntry, + subscribeEntityRegistry, +} from "../data/entity_registry"; +import { SubscribeMixin } from "../mixins/subscribe-mixin"; +import { computeStateName } from "../common/entity/compute_state_name"; +import { stateIcon } from "../common/entity/state_icon"; +import { fireEvent } from "../common/dom/fire_event"; +import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker"; +import { computeDomain } from "../common/entity/compute_domain"; +import { Target } from "../data/target"; +import { ensureArray } from "../common/ensure-array"; +import "./entity/ha-entity-picker"; +import "./device/ha-device-picker"; +import "./ha-area-picker"; +import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker"; +import "@polymer/paper-tooltip/paper-tooltip"; + +@customElement("ha-target-picker") +export class HaTargetPicker extends SubscribeMixin(LitElement) { + @property() public hass!: HomeAssistant; + + @property() public value?: Target; + + @property() public label?: string; + + /** + * Show only targets with entities from specific domains. + * @type {Array} + * @attr include-domains + */ + @property({ type: Array, attribute: "include-domains" }) + public includeDomains?: string[]; + + /** + * Show only targets with entities of these device classes. + * @type {Array} + * @attr include-device-classes + */ + @property({ type: Array, attribute: "include-device-classes" }) + public includeDeviceClasses?: string[]; + + @property() public deviceFilter?: HaDevicePickerDeviceFilterFunc; + + @property() public entityRegFilter?: (entity: EntityRegistryEntry) => boolean; + + @property() public entityFilter?: HaEntityPickerEntityFilterFunc; + + @internalProperty() private _areas?: { [areaId: string]: AreaRegistryEntry }; + + @internalProperty() private _devices?: { + [deviceId: string]: DeviceRegistryEntry; + }; + + @internalProperty() private _entities?: EntityRegistryEntry[]; + + @internalProperty() private _addMode?: "area_id" | "entity_id" | "device_id"; + + @query("#input") private _inputElement?; + + public hassSubscribe(): UnsubscribeFunc[] { + return [ + subscribeAreaRegistry(this.hass.connection!, (areas) => { + const areaLookup: { [areaId: string]: AreaRegistryEntry } = {}; + for (const area of areas) { + areaLookup[area.area_id] = area; + } + this._areas = areaLookup; + }), + subscribeDeviceRegistry(this.hass.connection!, (devices) => { + const deviceLookup: { [deviceId: string]: DeviceRegistryEntry } = {}; + for (const device of devices) { + deviceLookup[device.id] = device; + } + this._devices = deviceLookup; + }), + subscribeEntityRegistry(this.hass.connection!, (entities) => { + this._entities = entities; + }), + ]; + } + + protected render() { + if (!this._areas || !this._devices || !this._entities) { + return html``; + } + return html`
+ ${ensureArray(this.value?.area_id)?.map((area_id) => { + const area = this._areas![area_id]; + return this._renderChip( + "area_id", + area_id, + area?.name || area_id, + undefined, + mdiSofa + ); + })} + ${ensureArray(this.value?.device_id)?.map((device_id) => { + const device = this._devices![device_id]; + return this._renderChip( + "device_id", + device_id, + device?.name || device_id, + undefined, + mdiDevices + ); + })} + ${ensureArray(this.value?.entity_id)?.map((entity_id) => { + const entity = this.hass.states[entity_id]; + return this._renderChip( + "entity_id", + entity_id, + entity ? computeStateName(entity) : entity_id, + entity ? stateIcon(entity) : undefined + ); + })} +
+ ${this._renderPicker()} +
+
+
+ + + + ${this.hass.localize( + "ui.components.target-picker.add_area_id" + )} + + +
+
+
+ + + + ${this.hass.localize( + "ui.components.target-picker.add_device_id" + )} + + +
+
+
+ + + + ${this.hass.localize( + "ui.components.target-picker.add_entity_id" + )} + + +
+
`; + } + + private async _showPicker(ev) { + this._addMode = ev.currentTarget.type; + await this.updateComplete; + setTimeout(() => { + this._inputElement?.open(); + this._inputElement?.focus(); + }, 0); + } + + private _renderChip( + type: string, + id: string, + name: string, + icon?: string, + iconPath?: string + ) { + return html` +
+ ${iconPath + ? html`` + : ""} + ${icon + ? html`` + : ""} + + + ${name} + + + ${type === "entity_id" + ? "" + : html` + + + + ${this.hass.localize( + `ui.components.target-picker.expand_${type}` + )} + `} + + + + + ${this.hass.localize( + `ui.components.target-picker.remove_${type}` + )} + +
+ `; + } + + private _renderPicker() { + switch (this._addMode) { + case "area_id": + return html``; + case "device_id": + return html``; + case "entity_id": + return html``; + } + return html``; + } + + private _targetPicked(ev) { + ev.stopPropagation(); + if (!ev.detail.value) { + return; + } + const value = ev.detail.value; + const target = ev.currentTarget; + target.value = ""; + this._addMode = undefined; + fireEvent(this, "value-changed", { + value: this.value + ? { + ...this.value, + [target.type]: this.value[target.type] + ? [...ensureArray(this.value[target.type]), value] + : value, + } + : { [target.type]: value }, + }); + } + + private _handleExpand(ev) { + const target = ev.currentTarget as any; + const newDevices: string[] = []; + const newEntities: string[] = []; + if (target.type === "area_id") { + Object.values(this._devices!).forEach((device) => { + if ( + device.area_id === target.id && + !this.value!.device_id?.includes(device.id) && + this._deviceMeetsFilter(device) + ) { + newDevices.push(device.id); + } + }); + this._entities!.forEach((entity) => { + if ( + entity.area_id === target.id && + !this.value!.entity_id?.includes(entity.entity_id) && + this._entityRegMeetsFilter(entity) + ) { + newEntities.push(entity.entity_id); + } + }); + } else if (target.type === "device_id") { + this._entities!.forEach((entity) => { + if ( + entity.device_id === target.id && + !this.value!.entity_id?.includes(entity.entity_id) && + this._entityRegMeetsFilter(entity) + ) { + newEntities.push(entity.entity_id); + } + }); + } else { + return; + } + let value = this.value; + if (newEntities.length) { + value = this._addItems(value, "entity_id", newEntities); + } + if (newDevices.length) { + value = this._addItems(value, "device_id", newDevices); + } + value = this._removeItem(value, target.type, target.id); + fireEvent(this, "value-changed", { value }); + } + + private _handleRemove(ev) { + const target = ev.currentTarget as any; + fireEvent(this, "value-changed", { + value: this._removeItem(this.value, target.type, target.id), + }); + } + + private _addItems( + value: this["value"], + type: string, + ids: string[] + ): this["value"] { + return { + ...value, + [type]: value![type] ? ensureArray(value![type])!.concat(ids) : ids, + }; + } + + private _removeItem( + value: this["value"], + type: string, + id: string + ): this["value"] { + return { + ...value, + [type]: ensureArray(value![type])!.filter((val) => val !== id), + }; + } + + private _deviceMeetsFilter(device: DeviceRegistryEntry): boolean { + const devEntities = this._entities?.filter( + (entity) => entity.device_id === device.id + ); + if (this.includeDomains) { + if (!devEntities || !devEntities.length) { + return false; + } + if ( + !devEntities.some((entity) => + this.includeDomains!.includes(computeDomain(entity.entity_id)) + ) + ) { + return false; + } + } + + if (this.includeDeviceClasses) { + if (!devEntities || !devEntities.length) { + return false; + } + if ( + !devEntities.some((entity) => { + const stateObj = this.hass.states[entity.entity_id]; + if (!stateObj) { + return false; + } + return ( + stateObj.attributes.device_class && + this.includeDeviceClasses!.includes( + stateObj.attributes.device_class + ) + ); + }) + ) { + return false; + } + } + + if (this.deviceFilter) { + return this.deviceFilter(device); + } + return true; + } + + private _entityRegMeetsFilter(entity: EntityRegistryEntry): boolean { + if ( + this.includeDomains && + !this.includeDomains.includes(computeDomain(entity.entity_id)) + ) { + return false; + } + if (this.includeDeviceClasses) { + const stateObj = this.hass.states[entity.entity_id]; + if (!stateObj) { + return false; + } + if ( + !stateObj.attributes.device_class || + !this.includeDeviceClasses!.includes(stateObj.attributes.device_class) + ) { + return false; + } + } + if (this.entityRegFilter) { + return this.entityRegFilter(entity); + } + return true; + } + + static get styles(): CSSResult { + return css` + ${unsafeCSS(chipStyles)} + .mdc-chip { + color: var(--primary-text-color); + } + .items { + z-index: 2; + } + .mdc-chip.add { + color: rgba(0, 0, 0, 0.87); + } + .mdc-chip:not(.add) { + cursor: default; + } + .mdc-chip mwc-icon-button { + --mdc-icon-button-size: 24px; + display: flex; + align-items: center; + outline: none; + } + .mdc-chip mwc-icon-button ha-svg-icon { + border-radius: 50%; + background: var(--secondary-text-color); + } + .mdc-chip__icon.mdc-chip__icon--trailing { + width: 16px; + height: 16px; + --mdc-icon-size: 14px; + color: var(--card-background-color); + } + .mdc-chip__icon--leading { + display: flex; + align-items: center; + justify-content: center; + --mdc-icon-size: 20px; + border-radius: 50%; + padding: 6px; + margin-left: -14px !important; + } + .expand-btn { + margin-right: 0; + } + .mdc-chip.area_id:not(.add) { + border: 2px solid #fed6a4; + background: var(--card-background-color); + } + .mdc-chip.area_id:not(.add) .mdc-chip__icon--leading, + .mdc-chip.area_id.add { + background: #fed6a4; + } + .mdc-chip.device_id:not(.add) { + border: 2px solid #a8e1fb; + background: var(--card-background-color); + } + .mdc-chip.device_id:not(.add) .mdc-chip__icon--leading, + .mdc-chip.device_id.add { + background: #a8e1fb; + } + .mdc-chip.entity_id:not(.add) { + border: 2px solid #d2e7b9; + background: var(--card-background-color); + } + .mdc-chip.entity_id:not(.add) .mdc-chip__icon--leading, + .mdc-chip.entity_id.add { + background: #d2e7b9; + } + .mdc-chip:hover { + z-index: 5; + } + paper-tooltip { + min-width: 200px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-target-picker": HaTargetPicker; + } +} diff --git a/src/data/automation.ts b/src/data/automation.ts index 88ee3f847c..272416abb0 100644 --- a/src/data/automation.ts +++ b/src/data/automation.ts @@ -6,7 +6,7 @@ import { navigate } from "../common/navigate"; import { Context, HomeAssistant } from "../types"; import { BlueprintInput } from "./blueprint"; import { DeviceCondition, DeviceTrigger } from "./device_automation"; -import { Action } from "./script"; +import { Action, MODES } from "./script"; export interface AutomationEntity extends HassEntityBase { attributes: HassEntityAttributeBase & { @@ -26,7 +26,7 @@ export interface ManualAutomationConfig { trigger: Trigger[]; condition?: Condition[]; action: Action[]; - mode?: "single" | "restart" | "queued" | "parallel"; + mode?: typeof MODES[number]; max?: number; } diff --git a/src/data/script.ts b/src/data/script.ts index cb434d7dfc..a7cfa7506a 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -7,13 +7,13 @@ import { navigate } from "../common/navigate"; import { HomeAssistant } from "../types"; import { Condition, Trigger } from "./automation"; -export const MODES = ["single", "restart", "queued", "parallel"]; +export const MODES = ["single", "restart", "queued", "parallel"] as const; export const MODES_MAX = ["queued", "parallel"]; export interface ScriptEntity extends HassEntityBase { attributes: HassEntityAttributeBase & { last_triggered: string; - mode: "single" | "restart" | "queued" | "parallel"; + mode: typeof MODES[number]; current?: number; max?: number; }; @@ -23,7 +23,7 @@ export interface ScriptConfig { alias: string; sequence: Action[]; icon?: string; - mode?: "single" | "restart" | "queued" | "parallel"; + mode?: typeof MODES[number]; max?: number; } diff --git a/src/data/selector.ts b/src/data/selector.ts index ab56f9f016..82749ae90c 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -2,9 +2,11 @@ export type Selector = | EntitySelector | DeviceSelector | AreaSelector + | TargetSelector | NumberSelector | BooleanSelector - | TimeSelector; + | TimeSelector + | ActionSelector; export interface EntitySelector { entity: { @@ -19,13 +21,41 @@ export interface DeviceSelector { integration?: string; manufacturer?: string; model?: string; - entity?: EntitySelector["entity"]; + entity?: { + domain?: EntitySelector["entity"]["domain"]; + device_class?: EntitySelector["entity"]["device_class"]; + }; }; } export interface AreaSelector { - // eslint-disable-next-line @typescript-eslint/ban-types - area: {}; + area: { + entity?: { + integration?: EntitySelector["entity"]["integration"]; + domain?: EntitySelector["entity"]["domain"]; + device_class?: EntitySelector["entity"]["device_class"]; + }; + device?: { + integration?: DeviceSelector["device"]["integration"]; + manufacturer?: DeviceSelector["device"]["manufacturer"]; + model?: DeviceSelector["device"]["model"]; + }; + }; +} + +export interface TargetSelector { + target: { + entity?: { + integration?: EntitySelector["entity"]["integration"]; + domain?: EntitySelector["entity"]["domain"]; + device_class?: EntitySelector["entity"]["device_class"]; + }; + device?: { + integration?: DeviceSelector["device"]["integration"]; + manufacturer?: DeviceSelector["device"]["manufacturer"]; + model?: DeviceSelector["device"]["model"]; + }; + }; } export interface NumberSelector { @@ -47,3 +77,8 @@ export interface TimeSelector { // eslint-disable-next-line @typescript-eslint/ban-types time: {}; } + +export interface ActionSelector { + // eslint-disable-next-line @typescript-eslint/ban-types + action: {}; +} diff --git a/src/data/target.ts b/src/data/target.ts new file mode 100644 index 0000000000..afddff0688 --- /dev/null +++ b/src/data/target.ts @@ -0,0 +1,5 @@ +export interface Target { + entity_id?: string[]; + device_id?: string[]; + area_id?: string[]; +} diff --git a/src/panels/config/automation/blueprint-automation-editor.ts b/src/panels/config/automation/blueprint-automation-editor.ts index 9229069d09..88702161b4 100644 --- a/src/panels/config/automation/blueprint-automation-editor.ts +++ b/src/panels/config/automation/blueprint-automation-editor.ts @@ -63,7 +63,7 @@ export class HaBlueprintAutomationEditor extends LitElement { protected render() { const blueprint = this._blueprint; - return html` + return html` ${!this.narrow ? html` ${this.config.alias} ` : ""} @@ -119,7 +119,7 @@ export class HaBlueprintAutomationEditor extends LitElement { - + ${this.hass.localize( "ui.panel.config.automation.editor.blueprint.header" @@ -185,6 +185,7 @@ export class HaBlueprintAutomationEditor extends LitElement { >` : html`
diff --git a/src/translations/en.json b/src/translations/en.json index e1902f4fc3..ce51d4fd3f 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -334,6 +334,16 @@ "show_attributes": "Show attributes" } }, + "target-picker": { + "expand_area_id": "Expand this area in the seperate devices and entities that it contains. After expanding it will not update the devices and entities when the area changes.", + "expand_device_id": "Expand this device in seperate entities. After expanding it will not update the entities when the device changes.", + "remove_area_id": "Remove area", + "remove_device_id": "Remove device", + "remove_entity_id": "Remove entity", + "add_area_id": "Pick area", + "add_device_id": "Pick device", + "add_entity_id": "Pick entity" + }, "user-picker": { "no_user": "No user", "add_user": "Add user", From daaf2b179622d0ce874038f4fbc898241e53ac84 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 12:11:47 +0100 Subject: [PATCH 19/38] Ensure push notification description reacts to language change (#7856) --- src/panels/profile/ha-push-notifications-row.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/panels/profile/ha-push-notifications-row.js b/src/panels/profile/ha-push-notifications-row.js index 528a447298..f564d8754f 100644 --- a/src/panels/profile/ha-push-notifications-row.js +++ b/src/panels/profile/ha-push-notifications-row.js @@ -25,7 +25,7 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) { >[[localize('ui.panel.profile.push_notifications.header')]]
- [[_description(_platformLoaded, _pushSupported)]] + [[localize(_descrLocalizeKey)]] Date: Wed, 2 Dec 2020 15:22:17 +0100 Subject: [PATCH 20/38] Ensure "false" is set as default for "continue_on_timeout" (#7862) --- .../action/types/ha-automation-action-wait_for_trigger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts b/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts index e12af7d52a..ca720af2a9 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts @@ -39,7 +39,7 @@ export class HaWaitForTriggerAction extends LitElement )} >
From ca7b8b8b4c5c1caa277348ecbd70b122ac6e1e00 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 15:33:11 +0100 Subject: [PATCH 21/38] Add option to deactivate a user (#7757) --- hassio/src/dashboard/hassio-update.ts | 4 +- src/data/user.ts | 1 + .../config/entities/ha-config-entities.ts | 8 ++- src/panels/config/users/dialog-user-detail.ts | 72 +++++++++++++------ src/panels/config/users/ha-config-users.ts | 38 +++++++--- src/translations/en.json | 3 +- 6 files changed, 89 insertions(+), 37 deletions(-) diff --git a/hassio/src/dashboard/hassio-update.ts b/hassio/src/dashboard/hassio-update.ts index b8d9cef96b..b2c8bb8bd9 100644 --- a/hassio/src/dashboard/hassio-update.ts +++ b/hassio/src/dashboard/hassio-update.ts @@ -74,9 +74,7 @@ export class HassioUpdate extends LitElement { "Supervisor", this.supervisor.supervisor, "hassio/supervisor/update", - `https://github.com//home-assistant/hassio/releases/tag/${ - this.supervisor.supervisor.version_latest - }` + `https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}` )} ${this.supervisor.host.features.includes("hassos") ? this._renderUpdateCard( diff --git a/src/data/user.ts b/src/data/user.ts index ea295dc6db..5fe1f4f259 100644 --- a/src/data/user.ts +++ b/src/data/user.ts @@ -20,6 +20,7 @@ export interface User { export interface UpdateUserParams { name?: User["name"]; + is_active?: User["is_active"]; group_ids?: User["group_ids"]; } diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 91897b3422..b8436d1b74 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -189,9 +189,11 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { ? (name, entity: any) => html` ${name}
- ${entity.entity_id} | - ${this.hass.localize(`component.${entity.platform}.title`) || - entity.platform} +
+ ${entity.entity_id} | + ${this.hass.localize(`component.${entity.platform}.title`) || + entity.platform} +
` : undefined, }, diff --git a/src/panels/config/users/dialog-user-detail.ts b/src/panels/config/users/dialog-user-detail.ts index d46a4cf24b..b854da0666 100644 --- a/src/panels/config/users/dialog-user-detail.ts +++ b/src/panels/config/users/dialog-user-detail.ts @@ -13,6 +13,7 @@ import { } from "lit-element"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; import { createCloseHeading } from "../../../components/ha-dialog"; +import "../../../components/ha-help-tooltip"; import "../../../components/ha-formfield"; import "../../../components/ha-switch"; import { adminChangePassword } from "../../../data/auth"; @@ -37,6 +38,8 @@ class DialogUserDetail extends LitElement { @internalProperty() private _isAdmin?: boolean; + @internalProperty() private _isActive?: boolean; + @internalProperty() private _error?: string; @internalProperty() private _params?: UserDetailDialogParams; @@ -48,6 +51,7 @@ class DialogUserDetail extends LitElement { this._error = undefined; this._name = params.entry.name || ""; this._isAdmin = params.entry.group_ids.includes(SYSTEM_GROUP_ID_ADMIN); + this._isActive = params.entry.is_active; await this.updateComplete; } @@ -91,15 +95,6 @@ class DialogUserDetail extends LitElement { ` : ""} - ${user.is_active - ? html` - ${this.hass.localize( - "ui.panel.config.users.editor.active" - )} - ` - : ""}
- - + - - + + + +
${!this._isAdmin ? html`
@@ -129,6 +128,27 @@ class DialogUserDetail extends LitElement { )} ` : ""} +
+ + + + + + +
@@ -192,11 +212,16 @@ class DialogUserDetail extends LitElement { this._isAdmin = ev.target.checked; } + private async _activeChanged(ev): Promise { + this._isActive = ev.target.checked; + } + private async _updateEntry() { this._submitting = true; try { await this._params!.updateEntry({ name: this._name.trim(), + is_active: this._isActive, group_ids: [ this._isAdmin ? SYSTEM_GROUP_ID_ADMIN : SYSTEM_GROUP_ID_USER, ], @@ -293,8 +318,13 @@ class DialogUserDetail extends LitElement { .state:not(:first-child) { margin-left: 8px; } - ha-switch { - margin-top: 8px; + .row { + display: flex; + padding: 8px 0; + } + ha-help-tooltip { + margin-left: 4px; + position: relative; } `, ]; diff --git a/src/panels/config/users/ha-config-users.ts b/src/panels/config/users/ha-config-users.ts index 55dbb018e2..db920b223f 100644 --- a/src/panels/config/users/ha-config-users.ts +++ b/src/panels/config/users/ha-config-users.ts @@ -46,10 +46,17 @@ export class HaConfigUsers extends LitElement { width: "25%", direction: "asc", grows: true, - template: (name) => html` - ${name || - this.hass!.localize("ui.panel.config.users.editor.unnamed_user")} - `, + template: (name, user: any) => + narrow + ? html` ${name}
+
+ ${user.username} | + ${this.hass.localize(`groups.${user.group_ids[0]}`)} +
` + : html` ${name || + this.hass!.localize( + "ui.panel.config.users.editor.unnamed_user" + )}`, }, username: { title: this.hass.localize( @@ -59,6 +66,7 @@ export class HaConfigUsers extends LitElement { filterable: true, width: "20%", direction: "asc", + hidden: narrow, template: (username) => html` ${username || this.hass!.localize("ui.panel.config.users.editor.unnamed_user")} @@ -71,13 +79,24 @@ export class HaConfigUsers extends LitElement { sortable: true, filterable: true, width: "20%", + direction: "asc", + hidden: narrow, template: (groupIds) => html` ${this.hass.localize(`groups.${groupIds[0]}`)} `, }, - }; - if (!narrow) { - columns.system_generated = { + is_active: { + title: this.hass.localize( + "ui.panel.config.users.picker.headers.is_active" + ), + type: "icon", + sortable: true, + filterable: true, + width: "80px", + template: (is_active) => + is_active ? html` ` : "", + }, + system_generated: { title: this.hass.localize( "ui.panel.config.users.picker.headers.system" ), @@ -87,8 +106,9 @@ export class HaConfigUsers extends LitElement { width: "160px", template: (generated) => generated ? html` ` : "", - }; - } + }, + }; + return columns; } ); diff --git a/src/translations/en.json b/src/translations/en.json index ce51d4fd3f..77ac8443e3 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2032,7 +2032,8 @@ "system_generated_users_not_removable": "Unable to remove system generated users.", "system_generated_users_not_editable": "Unable to update system generated users.", "unnamed_user": "Unnamed User", - "confirm_user_deletion": "Are you sure you want to delete {name}?" + "confirm_user_deletion": "Are you sure you want to delete {name}?", + "active_tooltip": "Controls if user can login" }, "add_user": { "caption": "Add user", From faaef31b9f497190b88a3c2875fe4e10eccaffcf Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 15:35:38 +0100 Subject: [PATCH 22/38] Show proper error message if username already used (#7866) --- src/panels/config/users/dialog-add-user.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panels/config/users/dialog-add-user.ts b/src/panels/config/users/dialog-add-user.ts index f88d4a476a..04c65c7738 100644 --- a/src/panels/config/users/dialog-add-user.ts +++ b/src/panels/config/users/dialog-add-user.ts @@ -241,7 +241,7 @@ export class DialogAddUser extends LitElement { user = userResponse.user; } catch (err) { this._loading = false; - this._error = err.code; + this._error = err.message; return; } @@ -255,7 +255,7 @@ export class DialogAddUser extends LitElement { } catch (err) { await deleteUser(this.hass, user.id); this._loading = false; - this._error = err.code; + this._error = err.message; return; } From 3bdab738c62773616199479c137e8a37739e47f2 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 2 Dec 2020 15:40:35 +0100 Subject: [PATCH 23/38] Support disabling devices (#7715) Co-authored-by: Bram Kragten --- src/components/device/ha-device-picker.ts | 4 +- src/data/device_registry.ts | 2 + .../dialog-device-registry-detail.ts | 47 ++- .../config/devices/ha-config-device-page.ts | 61 +++- .../devices/ha-config-devices-dashboard.ts | 284 +++++++++++++++++- src/translations/en.json | 21 +- 6 files changed, 399 insertions(+), 20 deletions(-) diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index fa7f1e70f1..34897f2c5a 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -156,7 +156,9 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { areaLookup[area.area_id] = area; } - let inputDevices = [...devices]; + let inputDevices = devices.filter( + (device) => device.id === this.value || !device.disabled_by + ); if (includeDomains) { inputDevices = inputDevices.filter((device) => { diff --git a/src/data/device_registry.ts b/src/data/device_registry.ts index 215110df1f..7d52f8dea9 100644 --- a/src/data/device_registry.ts +++ b/src/data/device_registry.ts @@ -17,6 +17,7 @@ export interface DeviceRegistryEntry { area_id?: string; name_by_user?: string; entry_type: "service" | null; + disabled_by: string | null; } export interface DeviceEntityLookup { @@ -26,6 +27,7 @@ export interface DeviceEntityLookup { export interface DeviceRegistryEntryMutableParams { area_id?: string | null; name_by_user?: string | null; + disabled_by?: string | null; } export const fallbackDeviceName = ( diff --git a/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts index ba05ad3c66..4fd6abcb7c 100644 --- a/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts +++ b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts @@ -19,10 +19,11 @@ import { import { DeviceRegistryDetailDialogParams } from "./show-dialog-device-registry-detail"; import { HomeAssistant } from "../../../../types"; +import type { HaSwitch } from "../../../../components/ha-switch"; import { PolymerChangedEvent } from "../../../../polymer-types"; import { computeDeviceName } from "../../../../data/device_registry"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { haStyleDialog } from "../../../../resources/styles"; +import { haStyle, haStyleDialog } from "../../../../resources/styles"; @customElement("dialog-device-registry-detail") class DialogDeviceRegistryDetail extends LitElement { @@ -36,6 +37,8 @@ class DialogDeviceRegistryDetail extends LitElement { @internalProperty() private _areaId?: string; + @internalProperty() private _disabledBy!: string | null; + @internalProperty() private _submitting?: boolean; public async showDialog( @@ -45,6 +48,7 @@ class DialogDeviceRegistryDetail extends LitElement { this._error = undefined; this._nameByUser = this._params.device.name_by_user || ""; this._areaId = this._params.device.area_id; + this._disabledBy = this._params.device.disabled_by; await this.updateComplete; } @@ -80,6 +84,32 @@ class DialogDeviceRegistryDetail extends LitElement { .value=${this._areaId} @value-changed=${this._areaPicked} > +
+ + +
+
+ ${this.hass.localize("ui.panel.config.devices.enabled_label")} +
+
+ ${this._disabledBy && this._disabledBy !== "user" + ? this.hass.localize( + "ui.panel.config.devices.enabled_cause", + "cause", + this.hass.localize( + `config_entry.disabled_by.${this._disabledBy}` + ) + ) + : ""} + ${this.hass.localize( + "ui.panel.config.devices.enabled_description" + )} +
+
+
{ this._submitting = true; try { await this._params!.updateEntry({ name_by_user: this._nameByUser.trim() || null, area_id: this._areaId || null, + disabled_by: this._disabledBy || null, }); this._params = undefined; } catch (err) { @@ -128,6 +163,7 @@ class DialogDeviceRegistryDetail extends LitElement { static get styles(): CSSResult[] { return [ + haStyle, haStyleDialog, css` .form { @@ -139,6 +175,15 @@ class DialogDeviceRegistryDetail extends LitElement { .error { color: var(--error-color); } + ha-switch { + margin-right: 16px; + } + .row { + margin-top: 8px; + color: var(--primary-text-color); + display: flex; + align-items: center; + } `, ]; } diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 84ed1860c5..560e1bc4e9 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -246,6 +246,26 @@ export class HaConfigDevicePage extends LitElement { .devices=${this.devices} .device=${device} > + ${ + device.disabled_by + ? html` +
+

+ ${this.hass.localize( + "ui.panel.config.devices.enabled_cause", + "cause", + device.disabled_by + )} +

+
+
+ + ${this.hass.localize("ui.common.enable")} + +
+ ` + : html`` + } ${this._renderIntegrationInfo(device, integrations)} @@ -272,9 +292,14 @@ export class HaConfigDevicePage extends LitElement { )} @@ -342,9 +367,16 @@ export class HaConfigDevicePage extends LitElement { @@ -415,9 +447,14 @@ export class HaConfigDevicePage extends LitElement { )} @@ -632,6 +669,12 @@ export class HaConfigDevicePage extends LitElement { }); } + private async _enableDevice(): Promise { + await updateDeviceRegistryEntry(this.hass, this.deviceId, { + disabled_by: null, + }); + } + static get styles(): CSSResult { return css` .container { diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index c75a8c6f95..a8d7794aaa 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -1,5 +1,8 @@ -import { mdiPlus } from "@mdi/js"; +import { mdiPlus, mdiFilterVariant } from "@mdi/js"; +import "@material/mwc-list/mwc-list-item"; import { + css, + CSSResult, customElement, html, internalProperty, @@ -7,7 +10,9 @@ import { property, TemplateResult, } from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import memoizeOne from "memoize-one"; +import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; import { HASSDomEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; import { LocalizeFunc } from "../../../common/translations/localize"; @@ -18,6 +23,7 @@ import { RowClickedEvent, } from "../../../components/data-table/ha-data-table"; import "../../../components/entity/ha-battery-icon"; +import "../../../components/ha-button-menu"; import { AreaRegistryEntry } from "../../../data/area_registry"; import { ConfigEntry } from "../../../data/config_entries"; import { @@ -34,6 +40,7 @@ import { domainToName } from "../../../data/integration"; import "../../../layouts/hass-tabs-subpage-data-table"; import { HomeAssistant, Route } from "../../../types"; import { configSections } from "../ha-panel-config"; +import { haStyle } from "../../../resources/styles"; interface DeviceRowData extends DeviceRegistryEntry { device?: DeviceRowData; @@ -64,6 +71,12 @@ export class HaConfigDeviceDashboard extends LitElement { window.location.search ); + @internalProperty() private _showDisabled = false; + + @internalProperty() private _filter = ""; + + @internalProperty() private _numHiddenDevices = 0; + private _activeFilters = memoizeOne( ( entries: ConfigEntry[], @@ -74,6 +87,10 @@ export class HaConfigDeviceDashboard extends LitElement { filters.forEach((value, key) => { switch (key) { case "config_entry": { + // If we are requested to show the devices for a given config entry, + // also show the disabled ones by default. + this._showDisabled = true; + const configEntry = entries.find( (entry) => entry.entry_id === value ); @@ -105,6 +122,7 @@ export class HaConfigDeviceDashboard extends LitElement { entities: EntityRegistryEntry[], areas: AreaRegistryEntry[], filters: URLSearchParams, + showDisabled: boolean, localize: LocalizeFunc ) => { // Some older installations might have devices pointing at invalid entryIDs @@ -117,6 +135,9 @@ export class HaConfigDeviceDashboard extends LitElement { deviceLookup[device.id] = device; } + // If nothing gets filtered, this is our correct count of devices + let startLength = outputDevices.length; + const deviceEntityLookup: DeviceEntityLookup = {}; for (const entity of entities) { if (!entity.device_id) { @@ -145,6 +166,7 @@ export class HaConfigDeviceDashboard extends LitElement { outputDevices = outputDevices.filter((device) => device.config_entries.includes(value) ); + startLength = outputDevices.length; const configEntry = entries.find((entry) => entry.entry_id === value); if (configEntry) { filterDomains.push(configEntry.domain); @@ -152,6 +174,10 @@ export class HaConfigDeviceDashboard extends LitElement { } }); + if (!showDisabled) { + outputDevices = outputDevices.filter((device) => !device.disabled_by); + } + outputDevices = outputDevices.map((device) => { return { ...device, @@ -182,6 +208,7 @@ export class HaConfigDeviceDashboard extends LitElement { }; }); + this._numHiddenDevices = startLength - outputDevices.length; return { devicesOutput: outputDevices, filteredDomains: filterDomains }; } ); @@ -298,9 +325,119 @@ export class HaConfigDeviceDashboard extends LitElement { this.entities, this.areas, this._searchParms, + this._showDisabled, this.hass.localize ); const includeZHAFab = filteredDomains.includes("zha"); + const activeFilters = this._activeFilters( + this.entries, + this._searchParms, + this.hass.localize + ); + + const headerToolbar = html` + ${activeFilters + ? html`
+ ${this.narrow + ? html`
+ + + ${this.hass.localize( + "ui.panel.config.filtering.filtering_by" + )} + ${activeFilters.join(", ")} + ${this._numHiddenDevices + ? "(" + + this.hass.localize( + "ui.panel.config.devices.picker.filter.hidden_devices", + "number", + this._numHiddenDevices + ) + + ")" + : ""} + +
` + : `${this.hass.localize( + "ui.panel.config.filtering.filtering_by" + )} ${activeFilters.join(", ")} + ${ + this._numHiddenDevices + ? "(" + + this.hass.localize( + "ui.panel.config.devices.picker.filter.hidden_devices", + "number", + this._numHiddenDevices + ) + + ")" + : "" + } + `} + ${this.hass.localize( + "ui.panel.config.filtering.clear" + )} +
` + : ""} + ${this._numHiddenDevices && !activeFilters + ? html`
+ ${this.narrow + ? html`
+ + + ${this.hass.localize( + "ui.panel.config.devices.picker.filter.hidden_devices", + "number", + this._numHiddenDevices + )} + +
` + : `${this.hass.localize( + "ui.panel.config.devices.picker.filter.hidden_devices", + "number", + this._numHiddenDevices + )}`} + ${this.hass.localize( + "ui.panel.config.devices.picker.filter.show_all" + )} +
` + : ""} + + + + + + + ${this.hass!.localize( + "ui.panel.config.devices.picker.filter.show_disabled" + )} + + + `; return html`
` : html``} +
+ ${headerToolbar} +
`; } @@ -363,6 +505,136 @@ export class HaConfigDeviceDashboard extends LitElement { const deviceId = ev.detail.id; navigate(this, `/config/devices/device/${deviceId}`); } + + private _showDisabledChanged(ev: CustomEvent) { + if (ev.detail.source !== "property") { + return; + } + this._showDisabled = ev.detail.selected; + } + + private _handleSearchChange(ev: CustomEvent) { + this._filter = ev.detail.value; + } + + private _clearFilter() { + navigate(this, window.location.pathname, true); + } + + private _showAll() { + this._showDisabled = true; + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + hass-loading-screen { + --app-header-background-color: var(--sidebar-background-color); + --app-header-text-color: var(--sidebar-text-color); + } + a { + color: var(--primary-color); + } + h2 { + margin-top: 0; + font-family: var(--paper-font-headline_-_font-family); + -webkit-font-smoothing: var( + --paper-font-headline_-_-webkit-font-smoothing + ); + font-size: var(--paper-font-headline_-_font-size); + font-weight: var(--paper-font-headline_-_font-weight); + letter-spacing: var(--paper-font-headline_-_letter-spacing); + line-height: var(--paper-font-headline_-_line-height); + opacity: var(--dark-primary-opacity); + } + p { + font-family: var(--paper-font-subhead_-_font-family); + -webkit-font-smoothing: var( + --paper-font-subhead_-_-webkit-font-smoothing + ); + font-weight: var(--paper-font-subhead_-_font-weight); + line-height: var(--paper-font-subhead_-_line-height); + } + ha-data-table { + width: 100%; + --data-table-border-width: 0; + } + :host(:not([narrow])) ha-data-table { + height: calc(100vh - 1px - var(--header-height)); + display: block; + } + ha-button-menu { + margin-right: 8px; + } + .table-header { + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid rgba(var(--rgb-primary-text-color), 0.12); + } + search-input { + margin-left: 16px; + flex-grow: 1; + position: relative; + top: 2px; + } + .search-toolbar search-input { + margin-left: 8px; + top: 1px; + } + .search-toolbar { + display: flex; + justify-content: space-between; + align-items: center; + color: var(--secondary-text-color); + } + .search-toolbar ha-button-menu { + position: static; + } + .selected-txt { + font-weight: bold; + padding-left: 16px; + } + .table-header .selected-txt { + margin-top: 20px; + } + .search-toolbar .selected-txt { + font-size: 16px; + } + .header-btns > mwc-button, + .header-btns > ha-icon-button { + margin: 8px; + } + .active-filters { + color: var(--primary-text-color); + position: relative; + display: flex; + align-items: center; + padding: 2px 2px 2px 8px; + margin-left: 4px; + font-size: 14px; + } + .active-filters ha-icon { + color: var(--primary-color); + } + .active-filters mwc-button { + margin-left: 8px; + } + .active-filters::before { + background-color: var(--primary-color); + opacity: 0.12; + border-radius: 4px; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + content: ""; + } + `, + ]; + } } declare global { diff --git a/src/translations/en.json b/src/translations/en.json index 77ac8443e3..46a4aaf94b 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1755,11 +1755,15 @@ "name": "Name", "update": "Update", "no_devices": "No devices", + "enabled_label": "Enable device", + "enabled_cause": "Disabled by {cause}.", + "enabled_description": "Disabled devices will not be shown and entities belonging to the device will be disabled and not added to Home Assistant.", "automation": { "automations": "Automations", "no_automations": "No automations", "unknown_automation": "Unknown automation", "create": "Create automation with device", + "create_disable": "Can't create automation with disabled device", "triggers": { "caption": "Do something when...", "no_triggers": "No triggers", @@ -1780,12 +1784,14 @@ "script": { "scripts": "Scripts", "no_scripts": "No scripts", - "create": "Create script with device" + "create": "Create script with device", + "create_disable": "Can't create script with disabled device" }, "scene": { "scenes": "Scenes", "no_scenes": "No scenes", - "create": "Create scene with device" + "create": "Create scene with device", + "create_disable": "Can't create scene with disabled device" }, "cant_edit": "You can only edit items that are created in the UI.", "device_not_found": "Device not found.", @@ -1811,7 +1817,16 @@ "no_area": "No area" }, "delete": "Delete", - "confirm_delete": "Are you sure you want to delete this device?" + "confirm_delete": "Are you sure you want to delete this device?", + "picker": { + "search": "Search devices", + "filter": { + "filter": "Filter", + "show_disabled": "Show disabled devices", + "hidden_devices": "{number} hidden {number, plural,\n one {device}\n other {devices}\n}", + "show_all": "Show all" + } + } }, "entities": { "caption": "Entities", From c4f850cb14dec2cecb5f30c02486c08517daf319 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 15:45:24 +0100 Subject: [PATCH 24/38] Cleanup created user if person creation is cancelled (#7865) --- src/panels/config/person/dialog-person-detail.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/panels/config/person/dialog-person-detail.ts b/src/panels/config/person/dialog-person-detail.ts index 67802ea928..d9edab630f 100644 --- a/src/panels/config/person/dialog-person-detail.ts +++ b/src/panels/config/person/dialog-person-detail.ts @@ -68,6 +68,8 @@ class DialogPersonDetail extends LitElement { @internalProperty() private _submitting = false; + @internalProperty() private _personExists = false; + private _deviceTrackersAvailable = memoizeOne((hass) => { return Object.keys(hass.states).some( (entityId) => @@ -79,6 +81,7 @@ class DialogPersonDetail extends LitElement { this._params = params; this._error = undefined; if (this._params.entry) { + this._personExists = true; this._name = this._params.entry.name || ""; this._userId = this._params.entry.user_id || undefined; this._deviceTrackers = this._params.entry.device_trackers || []; @@ -88,6 +91,7 @@ class DialogPersonDetail extends LitElement { : undefined; this._isAdmin = this._user?.group_ids.includes(SYSTEM_GROUP_ID_ADMIN); } else { + this._personExists = false; this._name = ""; this._userId = undefined; this._user = undefined; @@ -398,6 +402,7 @@ class DialogPersonDetail extends LitElement { await this._params!.updateEntry(values); } else { await this._params!.createEntry(values); + this._personExists = true; } this._params = undefined; } catch (err) { @@ -422,6 +427,14 @@ class DialogPersonDetail extends LitElement { } private _close(): void { + // If we do not have a person ID yet (= person creation dialog was just cancelled), but + // we already created a user ID for it, delete it now to not have it "free floating". + if (!this._personExists && this._userId) { + deleteUser(this.hass, this._userId); + this._params?.refreshUsers(); + this._userId = undefined; + } + this._params = undefined; } From 3313572606005cc576a9845c9738a3a7fd571693 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 16:00:49 +0100 Subject: [PATCH 25/38] Improve password change card (#7756) Co-authored-by: Bram Kragten --- src/panels/profile/ha-change-password-card.js | 154 -------------- src/panels/profile/ha-change-password-card.ts | 195 ++++++++++++++++++ src/translations/en.json | 5 +- 3 files changed, 199 insertions(+), 155 deletions(-) delete mode 100644 src/panels/profile/ha-change-password-card.js create mode 100644 src/panels/profile/ha-change-password-card.ts diff --git a/src/panels/profile/ha-change-password-card.js b/src/panels/profile/ha-change-password-card.js deleted file mode 100644 index d2a51d4722..0000000000 --- a/src/panels/profile/ha-change-password-card.js +++ /dev/null @@ -1,154 +0,0 @@ -import "@material/mwc-button"; -import "@polymer/paper-dialog/paper-dialog"; -import "../../components/ha-circular-progress"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "../../components/ha-card"; -import LocalizeMixin from "../../mixins/localize-mixin"; -import "../../styles/polymer-ha-style"; - -/* - * @appliesMixin LocalizeMixin - */ -class HaChangePasswordCard extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - -
- -
- - - - -
-
- - -
-
-
- `; - } - - static get properties() { - return { - hass: Object, - - _loading: { - type: Boolean, - value: false, - }, - - // Error message when can't talk to server etc - _statusMsg: String, - _errorMsg: String, - - _currentPassword: String, - _password1: String, - _password2: String, - }; - } - - ready() { - super.ready(); - this.addEventListener("keypress", (ev) => { - this._statusMsg = null; - if (ev.keyCode === 13) { - this._changePassword(); - } - }); - } - - async _changePassword() { - this._statusMsg = null; - if (!this._currentPassword || !this._password1 || !this._password2) return; - - if (this._password1 !== this._password2) { - this._errorMsg = "New password confirmation doesn't match"; - return; - } - - if (this._currentPassword === this._password1) { - this._errorMsg = "New password must be different than current password"; - return; - } - - this._loading = true; - this._errorMsg = null; - - try { - await this.hass.callWS({ - type: "config/auth_provider/homeassistant/change_password", - current_password: this._currentPassword, - new_password: this._password1, - }); - - this.setProperties({ - _statusMsg: "Password changed successfully", - _currentPassword: null, - _password1: null, - _password2: null, - }); - } catch (err) { - this._errorMsg = err.message; - } - - this._loading = false; - } -} - -customElements.define("ha-change-password-card", HaChangePasswordCard); diff --git a/src/panels/profile/ha-change-password-card.ts b/src/panels/profile/ha-change-password-card.ts new file mode 100644 index 0000000000..06c66fe3d4 --- /dev/null +++ b/src/panels/profile/ha-change-password-card.ts @@ -0,0 +1,195 @@ +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-dialog/paper-dialog"; +import { + css, + CSSResult, + customElement, + html, + internalProperty, + LitElement, + property, + PropertyValues, + TemplateResult, +} from "lit-element"; +import "@material/mwc-button"; +import "../../components/ha-circular-progress"; +import "../../components/ha-card"; +import { haStyle } from "../../resources/styles"; +import type { HomeAssistant } from "../../types"; + +@customElement("ha-change-password-card") +class HaChangePasswordCard extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @internalProperty() private _loading = false; + + @internalProperty() private _statusMsg?: string; + + @internalProperty() private _errorMsg?: string; + + @internalProperty() private _currentPassword?: string; + + @internalProperty() private _password?: string; + + @internalProperty() private _passwordConfirm?: string; + + protected render(): TemplateResult { + return html` +
+ +
+ ${this._errorMsg + ? html`
${this._errorMsg}
` + : ""} + ${this._statusMsg + ? html`
${this._statusMsg}
` + : ""} + + + + ${this._currentPassword + ? html` + ` + : ""} +
+ +
+ ${this._loading + ? html`
+ +
` + : html`${this.hass.localize( + "ui.panel.profile.change_password.submit" + )}`} +
+
+
+ `; + } + + private _currentPasswordChanged(ev: CustomEvent) { + this._currentPassword = ev.detail.value; + } + + private _newPasswordChanged(ev: CustomEvent) { + this._password = ev.detail.value; + } + + private _newPasswordConfirmChanged(ev: CustomEvent) { + this._passwordConfirm = ev.detail.value; + } + + protected firstUpdated(changedProps: PropertyValues) { + super.firstUpdated(changedProps); + this.addEventListener("keypress", (ev) => { + this._statusMsg = undefined; + if (ev.keyCode === 13) { + this._changePassword(); + } + }); + } + + private async _changePassword() { + this._statusMsg = undefined; + if (!this._currentPassword || !this._password || !this._passwordConfirm) { + return; + } + + if (this._password !== this._passwordConfirm) { + this._errorMsg = this.hass.localize( + "ui.panel.profile.change_password.error_new_mismatch" + ); + return; + } + + if (this._currentPassword === this._password) { + this._errorMsg = this.hass.localize( + "ui.panel.profile.change_password.error_new_is_old" + ); + return; + } + + this._loading = true; + this._errorMsg = undefined; + + try { + await this.hass.callWS({ + type: "config/auth_provider/homeassistant/change_password", + current_password: this._currentPassword, + new_password: this._password, + }); + } catch (err) { + this._errorMsg = err.message; + return; + } finally { + this._loading = false; + } + + this._statusMsg = this.hass.localize( + "ui.panel.profile.change_password.success" + ); + this._currentPassword = undefined; + this._password = undefined; + this._passwordConfirm = undefined; + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + .error { + color: var(--error-color); + } + .status { + color: var(--primary-color); + } + #currentPassword { + margin-top: -8px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-change-password-card": HaChangePasswordCard; + } +} diff --git a/src/translations/en.json b/src/translations/en.json index 46a4aaf94b..68282dd703 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2897,7 +2897,10 @@ "new_password": "New Password", "confirm_new_password": "Confirm New Password", "error_required": "Required", - "submit": "Submit" + "submit": "Submit", + "error_new_mismatch": "Entered new password values do not match", + "error_new_is_old": "New password must be different than current password", + "success": "Password changed successfully" }, "mfa": { "header": "Multi-factor Authentication Modules", From a0ef60de491e02551fd84a1863e7db8d92b51658 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Wed, 2 Dec 2020 07:14:46 -0800 Subject: [PATCH 26/38] Make card picker border follow standards (#7162) --- src/panels/lovelace/editor/card-editor/hui-card-picker.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 f68b99e1f5..dbc034b7a9 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -353,8 +353,7 @@ export class HuiCardPicker extends LitElement { max-width: 500px; display: flex; flex-direction: column; - border-radius: 4px; - border: 1px solid var(--divider-color); + border-radius: var(--ha-card-border-radius); background: var(--primary-background-color, #fafafa); cursor: pointer; box-sizing: border-box; @@ -408,6 +407,11 @@ export class HuiCardPicker extends LitElement { width: 100%; height: 100%; z-index: 1; + border: var(--ha-card-border-width, 1px) solid var( + --ha-card-border-color, + var(--divider-color) + ); + border-radius: var(--ha-card-border-radius); } .manual { From bbea38d227daa09ccb1c92e69d847888e115e3db Mon Sep 17 00:00:00 2001 From: Zack Barett Date: Wed, 2 Dec 2020 09:19:01 -0600 Subject: [PATCH 27/38] Lovelace Card Editor: Preview Background (#7678) --- .../lovelace/editor/card-editor/hui-dialog-edit-card.ts | 4 ++++ 1 file changed, 4 insertions(+) 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 9d03370036..58ce8ceb74 100755 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -450,6 +450,10 @@ export class HuiDialogEditCard extends LitElement } .element-preview { position: relative; + height: max-content; + background: var(--primary-background-color); + padding: 4px; + border-radius: 4px; } .element-preview ha-circular-progress { top: 50%; From faec063f34a342c17e84450251dc91caaf24e67e Mon Sep 17 00:00:00 2001 From: Kendell R Date: Wed, 2 Dec 2020 07:22:20 -0800 Subject: [PATCH 28/38] Add --masonry-view-card-margin (#7395) --- src/panels/lovelace/cards/hui-horizontal-stack-card.ts | 2 +- src/panels/lovelace/cards/hui-vertical-stack-card.ts | 2 +- src/panels/lovelace/views/hui-masonry-view.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts index 2ae05adaf1..306217a398 100644 --- a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts +++ b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts @@ -29,7 +29,7 @@ class HuiHorizontalStackCard extends HuiStackCard { } #root > * { flex: 1 1 0; - margin: 0 4px; + margin: var(--horizontal-stack-card-margin, var(--stack-card-margin, 0 4px)); min-width: 0; } #root > *:first-child { diff --git a/src/panels/lovelace/cards/hui-vertical-stack-card.ts b/src/panels/lovelace/cards/hui-vertical-stack-card.ts index 81ac8dd930..77f34ddc91 100644 --- a/src/panels/lovelace/cards/hui-vertical-stack-card.ts +++ b/src/panels/lovelace/cards/hui-vertical-stack-card.ts @@ -29,7 +29,7 @@ class HuiVerticalStackCard extends HuiStackCard { height: 100%; } #root > * { - margin: 4px 0 4px 0; + margin: var(--vertical-stack-card-margin, var(--stack-card-margin, 4px 0)); } #root > *:first-child { margin-top: 0; diff --git a/src/panels/lovelace/views/hui-masonry-view.ts b/src/panels/lovelace/views/hui-masonry-view.ts index b160ef9766..b123d3060a 100644 --- a/src/panels/lovelace/views/hui-masonry-view.ts +++ b/src/panels/lovelace/views/hui-masonry-view.ts @@ -293,7 +293,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement { .column > * { display: block; - margin: 4px 4px 8px; + margin: var(--masonry-view-card-margin, 4px 4px 8px); } ha-fab { From 5e481880bdcbfe2ba12e8e5ad556f8d8d462f45b Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 16:34:59 +0100 Subject: [PATCH 29/38] Allow empty entities array with entity-filter (#7854) --- src/panels/lovelace/cards/hui-entities-card.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 445b5b0bb5..696532a881 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -109,7 +109,7 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { } public setConfig(config: EntitiesCardConfig): void { - if (!config || !config.entities.length) { + if (!config.entities || !Array.isArray(config.entities)) { throw new Error("Entities must be specified"); } From dbdced09715e12ffb6edbd3248275a89e1377a7f Mon Sep 17 00:00:00 2001 From: Adam Ernst Date: Wed, 2 Dec 2020 09:36:21 -0600 Subject: [PATCH 30/38] Improve descriptions for Configuration entries (#7606) --- src/translations/en.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/translations/en.json b/src/translations/en.json index 68282dd703..815119a1fb 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -797,7 +797,7 @@ }, "areas": { "caption": "Areas", - "description": "Manage areas in your home", + "description": "Group devices into areas", "data_table": { "area": "Area", "devices": "Devices" @@ -827,7 +827,7 @@ }, "tags": { "caption": "Tags", - "description": "Manage tags", + "description": "Trigger automations when a NFC tag, QR code, etc. is scanned", "learn_more": "Learn more about tags", "no_tags": "No tags", "add_tag": "Add tag", @@ -858,7 +858,7 @@ }, "helpers": { "caption": "Helpers", - "description": "Manage elements that help build automations", + "description": "Elements that help build automations", "types": { "input_text": "Text", "input_number": "Number", @@ -886,7 +886,7 @@ }, "core": { "caption": "General", - "description": "Change your general Home Assistant configuration", + "description": "Unit system, location, time zone & other general parameters", "section": { "core": { "header": "General Configuration", @@ -915,7 +915,7 @@ "caption": "Info", "copy_raw": "Raw Text", "copy_github": "For GitHub", - "description": "View info about your Home Assistant installation", + "description": "Version, system health and links to documentation", "home_assistant_logo": "Home Assistant logo", "path_configuration": "Path to configuration.yaml: {path}", "developed_by": "Developed by a bunch of awesome people.", @@ -950,7 +950,7 @@ }, "lovelace": { "caption": "Lovelace Dashboards", - "description": "Manage your Lovelace Dashboards", + "description": "Create customized sets of cards to control your home", "dashboards": { "default_dashboard": "This is the default dashboard", "caption": "Dashboards", @@ -1105,7 +1105,7 @@ }, "automation": { "caption": "Automations", - "description": "Manage automations", + "description": "Create custom behavior rules for your home", "picker": { "header": "Automation Editor", "introduction": "The automation editor allows you to create and edit automations. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.", @@ -1485,7 +1485,7 @@ }, "script": { "caption": "Scripts", - "description": "Manage scripts", + "description": "Execute a sequence of actions", "picker": { "header": "Script Editor", "introduction": "The script editor allows you to create and edit scripts. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.", @@ -1535,7 +1535,7 @@ }, "scene": { "caption": "Scenes", - "description": "Manage scenes", + "description": "Capture device states and easily recall them later", "activated": "Activated scene {name}.", "picker": { "header": "Scene Editor", @@ -1581,7 +1581,7 @@ "cloud": { "description_login": "Logged in as {email}", "description_not_login": "Not logged in", - "description_features": "Control away from home, integrate with Alexa and Google Assistant.", + "description_features": "Control home when away and integrate with Alexa and Google Assistant", "login": { "title": "Cloud Login", "introduction": "Home Assistant Cloud provides you with a secure remote connection to your instance while away from home. It also allows you to connect with cloud-only services: Amazon Alexa and Google Assistant.", @@ -1748,7 +1748,7 @@ "devices": { "add_prompt": "No {name} have been added using this device yet. You can add one by clicking the + button above.", "caption": "Devices", - "description": "Manage connected devices", + "description": "Manage configured devices", "device_info": "Device info", "unnamed_device": "Unnamed device", "unknown_error": "Unknown error", @@ -1941,7 +1941,7 @@ }, "integrations": { "caption": "Integrations", - "description": "Manage integrations", + "description": "Manage integrations with services, devices, ...", "integration": "integration", "discovered": "Discovered", "attention": "Attention required", From 2ab1c6e9a91bf36e308263160f8e9dcff8c1e912 Mon Sep 17 00:00:00 2001 From: Philip Allgaier Date: Wed, 2 Dec 2020 16:57:19 +0100 Subject: [PATCH 31/38] Make media player card work as square + add to gallery + icon pos tweaks (#7727) --- gallery/src/data/media_players.ts | 8 +- .../src/demos/demo-hui-media-control-card.ts | 10 ++ .../lovelace/cards/hui-media-control-card.ts | 138 +++++++++--------- src/panels/lovelace/components/hui-marquee.ts | 2 +- 4 files changed, 84 insertions(+), 74 deletions(-) diff --git a/gallery/src/data/media_players.ts b/gallery/src/data/media_players.ts index 07dc174e8c..1d343c5bad 100644 --- a/gallery/src/data/media_players.ts +++ b/gallery/src/data/media_players.ts @@ -7,8 +7,8 @@ export const createMediaPlayerEntities = () => [ media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)", media_artist: "Technohead", // Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media + - // Select Source + Stop + Clear + Play + Shuffle Set + Browse Media - supported_features: 195135, + // Select Source + Stop + Clear + Play + Shuffle Set + supported_features: 64063, entity_picture: "/images/album_cover_2.jpg", media_duration: 300, media_position: 50, @@ -24,8 +24,8 @@ export const createMediaPlayerEntities = () => [ media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)", media_artist: "Technohead", // Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media + - // Select Source + Stop + Clear + Play + Shuffle Set - supported_features: 64063, + // Select Source + Stop + Clear + Play + Shuffle Set + Browse Media + supported_features: 195135, entity_picture: "/images/album_cover.jpg", media_duration: 300, media_position: 0, diff --git a/gallery/src/demos/demo-hui-media-control-card.ts b/gallery/src/demos/demo-hui-media-control-card.ts index 2847ee3e61..1f12c851bc 100644 --- a/gallery/src/demos/demo-hui-media-control-card.ts +++ b/gallery/src/demos/demo-hui-media-control-card.ts @@ -146,6 +146,16 @@ const CONFIGS = [ entity: media_player.receiver_off `, }, + { + heading: "Grid Full Size", + config: ` + - type: grid + columns: 1 + cards: + - type: media-control + entity: media_player.music_paused + `, + }, ]; class DemoHuiMediControlCard extends PolymerElement { diff --git a/src/panels/lovelace/cards/hui-media-control-card.ts b/src/panels/lovelace/cards/hui-media-control-card.ts index 63ff8f492f..104dc85b00 100644 --- a/src/panels/lovelace/cards/hui-media-control-card.ts +++ b/src/panels/lovelace/cards/hui-media-control-card.ts @@ -246,78 +246,73 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { ${!isUnavailable && (mediaDescription || stateObj.attributes.media_title || showControls) ? html` -
- ${!mediaDescription && !stateObj.attributes.media_title - ? "" - : html` -
- - ${!stateObj.attributes.media_title - ? "" - : mediaDescription} -
- `} - ${!showControls - ? "" - : html` -
- ${controls!.map( - (control) => html` - - ` - )} - ${supportsFeature(stateObj, SUPPORT_BROWSE_MEDIA) - ? html` - +
+ ${!mediaDescription && !stateObj.attributes.media_title + ? "" + : html` +
+ + ${!stateObj.attributes.media_title + ? "" + : mediaDescription} +
+ `} + ${!showControls + ? "" + : html` +
+ ${controls!.map( + (control) => html` + + .icon=${control.icon} + action=${control.action} + @click=${this._handleClick} + > ` - : ""} -
+ )} + ${supportsFeature(stateObj, SUPPORT_BROWSE_MEDIA) + ? html` + + ` + : ""} +
+ `} +
+ ${!this._showProgressBar + ? "" + : html` + `}
- ${!this._showProgressBar - ? "" - : html` - - `} ` : ""} @@ -635,6 +630,11 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { .player { position: relative; padding: 16px; + height: 100%; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: space-between; color: var(--text-primary-color); transition-property: color, padding; transition-duration: 0.4s; @@ -671,7 +671,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { mwc-icon-button.browse-media { position: absolute; - right: 0; + right: 4px; --mdc-icon-size: 24px; } @@ -693,7 +693,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { .more-info { position: absolute; top: 4px; - right: 0px; + right: 4px; } .media-info { diff --git a/src/panels/lovelace/components/hui-marquee.ts b/src/panels/lovelace/components/hui-marquee.ts index 907b5fc602..29bd5bd0da 100644 --- a/src/panels/lovelace/components/hui-marquee.ts +++ b/src/panels/lovelace/components/hui-marquee.ts @@ -72,7 +72,7 @@ class HuiMarquee extends LitElement { display: flex; position: relative; align-items: center; - height: 1em; + height: 1.2em; contain: strict; } From 8e4ceb7d489d66589483cc2d949e7a8b1f2734c0 Mon Sep 17 00:00:00 2001 From: Zack Barett Date: Wed, 2 Dec 2020 10:08:18 -0600 Subject: [PATCH 32/38] Fix View Background Colors (#7823) --- src/panels/lovelace/hui-root.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 49faa0dcf1..fcb491068d 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -793,10 +793,6 @@ class HUIRoot extends LitElement { ha-app-layout { min-height: 100%; - background: var( - --lovelace-background, - var(--primary-background-color) - ); } ha-tabs { width: 100%; @@ -884,6 +880,12 @@ class HUIRoot extends LitElement { .menu-link { text-decoration: none; } + hui-view { + background: var( + --lovelace-background, + var(--primary-background-color) + ); + } `, ]; } From 7b392b626b13c3902bf5894ecf91fdc7dd7026ec Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 2 Dec 2020 17:16:46 +0100 Subject: [PATCH 33/38] Hardcode history card stub entity to sun.sun (#7760) --- .../lovelace/cards/hui-history-graph-card.ts | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/panels/lovelace/cards/hui-history-graph-card.ts b/src/panels/lovelace/cards/hui-history-graph-card.ts index bcd37e8386..d034811e07 100644 --- a/src/panels/lovelace/cards/hui-history-graph-card.ts +++ b/src/panels/lovelace/cards/hui-history-graph-card.ts @@ -16,7 +16,6 @@ import "../../../components/state-history-charts"; import { CacheConfig, getRecentWithCache } from "../../../data/cached-history"; import { HistoryResult } from "../../../data/history"; import { HomeAssistant } from "../../../types"; -import { findEntities } from "../common/find-entites"; import { hasConfigOrEntitiesChanged } from "../common/has-changed"; import { processConfigEntities } from "../common/process-config-entities"; import { EntityConfig } from "../entity-rows/types"; @@ -30,22 +29,9 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard { return document.createElement("hui-history-graph-card-editor"); } - public static getStubConfig( - hass: HomeAssistant, - entities: string[], - entitiesFallback: string[] - ): HistoryGraphCardConfig { - const includeDomains = ["sensor"]; - const maxEntities = 1; - const foundEntities = findEntities( - hass, - maxEntities, - entities, - entitiesFallback, - includeDomains - ); - - return { type: "history-graph", entities: foundEntities }; + public static getStubConfig(): HistoryGraphCardConfig { + // Hard coded to sun.sun to prevent high server load when it would pick an entity with a lot of state changes + return { type: "history-graph", entities: ["sun.sun"] }; } @property({ attribute: false }) public hass?: HomeAssistant; @@ -71,12 +57,12 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard { } public setConfig(config: HistoryGraphCardConfig): void { - if (!config.entities.length) { - throw new Error("Entities must be specified"); + if (!config.entities || !Array.isArray(config.entities)) { + throw new Error("Entities need to be an array"); } - if (config.entities && !Array.isArray(config.entities)) { - throw new Error("Entities need to be an array"); + if (!config.entities.length) { + throw new Error("You must include at least one entity"); } this._config = config; From ba907851154aa5a2a1250b420515731f670cb0ed Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 2 Dec 2020 17:46:30 +0100 Subject: [PATCH 34/38] Fix card picker cards (#7871) --- .../lovelace/editor/card-editor/hui-card-picker.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) 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 dbc034b7a9..48fbdecdfa 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -353,10 +353,9 @@ export class HuiCardPicker extends LitElement { max-width: 500px; display: flex; flex-direction: column; - border-radius: var(--ha-card-border-radius); + border-radius: var(--ha-card-border-radius, 4px); background: var(--primary-background-color, #fafafa); cursor: pointer; - box-sizing: border-box; position: relative; } @@ -374,7 +373,6 @@ export class HuiCardPicker extends LitElement { --ha-card-background, var(--card-background-color, white) ); - border-radius: 0 0 4px 4px; border-bottom: 1px solid var(--divider-color); } @@ -407,11 +405,10 @@ export class HuiCardPicker extends LitElement { width: 100%; height: 100%; z-index: 1; - border: var(--ha-card-border-width, 1px) solid var( - --ha-card-border-color, - var(--divider-color) - ); - border-radius: var(--ha-card-border-radius); + box-sizing: border-box; + border: var(--ha-card-border-width, 1px) solid + var(--ha-card-border-color, var(--divider-color)); + border-radius: var(--ha-card-border-radius, 4px); } .manual { From 8c655883fe6600e7dbce185ec229f8c467fb30dd Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 2 Dec 2020 18:20:29 +0100 Subject: [PATCH 35/38] Add device disabled reason (#7873) --- src/translations/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/translations/en.json b/src/translations/en.json index 815119a1fb..2b5db5c7a8 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -98,7 +98,8 @@ "disabled_by": { "user": "User", "integration": "Integration", - "config_entry": "Config Entry" + "config_entry": "Config Entry", + "device": "Device" } }, "ui": { From e0c4dc08a14b5af9f541f556035a04fcd53a3f71 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 2 Dec 2020 18:21:51 +0100 Subject: [PATCH 36/38] Tooltip tweak target picker (#7870) --- src/components/ha-target-picker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts index 487e557568..68a6e0701e 100644 --- a/src/components/ha-target-picker.ts +++ b/src/components/ha-target-picker.ts @@ -268,7 +268,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { > - ${this.hass.localize( `ui.components.target-picker.expand_${type}` )} Date: Wed, 2 Dec 2020 19:31:06 +0100 Subject: [PATCH 37/38] Add more device disabled ui (#7874) --- .../device-detail/ha-device-entities-card.ts | 13 +- .../config/devices/ha-config-device-page.ts | 217 +++++++++--------- .../devices/ha-config-devices-dashboard.ts | 29 ++- .../entities/entity-registry-settings.ts | 12 +- src/translations/en.json | 10 +- 5 files changed, 166 insertions(+), 115 deletions(-) diff --git a/src/panels/config/devices/device-detail/ha-device-entities-card.ts b/src/panels/config/devices/device-detail/ha-device-entities-card.ts index d37fd2eaf5..9f74efeef2 100644 --- a/src/panels/config/devices/device-detail/ha-device-entities-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -8,7 +8,6 @@ import { html, LitElement, property, - internalProperty, PropertyValues, TemplateResult, } from "lit-element"; @@ -31,7 +30,7 @@ export class HaDeviceEntitiesCard extends LitElement { @property() public entities!: EntityRegistryStateEntry[]; - @internalProperty() private _showDisabled = false; + @property() public showDisabled = false; private _entityRows: Array = []; @@ -68,7 +67,7 @@ export class HaDeviceEntitiesCard extends LitElement { })} ${disabledEntities.length - ? !this._showDisabled + ? !this.showDisabled ? html`