Compare commits

...

99 Commits

Author SHA1 Message Date
Bram Kragten
a9d926e80a Bumped version to 20201229.1 2021-01-05 20:38:52 +01:00
Philip Allgaier
c41369c89c Add EN fallback text for dismiss button (#8068) 2021-01-05 20:38:36 +01:00
Philip Allgaier
656bef3da9 Prevent relative time text wrapping in more-info-sun (#8051) 2021-01-05 20:38:18 +01:00
Bram Kragten
3d7ee6a4df Merge pull request #8048 from home-assistant/dev 2020-12-29 23:23:58 +01:00
Bram Kragten
d844c89b94 Merge branch 'master' into dev 2020-12-29 23:12:14 +01:00
Bram Kragten
177ea2b85a Bumped version to 20201229.0 2020-12-29 23:09:00 +01:00
Marc Mueller
50c5c15f49 Update group reload string (#7938)
* Update group reload string

* Update src/translations/en.json

Co-authored-by: Philip Allgaier <philip.allgaier@gmx.de>

* Update rest reload string

Co-authored-by: Philip Allgaier <philip.allgaier@gmx.de>
2020-12-29 23:03:44 +01:00
Philip Allgaier
1810760dc7 Mark entity ID as optional for button card (#7967) 2020-12-29 23:02:47 +01:00
Joakim Sørensen
4635b92e3f Fix add-on stage icon rendering (#7981) 2020-12-29 22:59:07 +01:00
Jochen Mehlhorn
1c652626eb Fix typo in hassio-supervisor-info.ts (#7907)
Fix typo in "unhealthy state" warning
2020-12-29 22:58:29 +01:00
Philip Allgaier
2000cfb1db Correct tabs for customizations page (#7990) 2020-12-29 22:52:58 +01:00
Philip Allgaier
f4d07828e7 Minor follow-up tweaks for PR 7947 (#7955) 2020-12-29 22:52:20 +01:00
Philip Allgaier
95b552671c Fix border radius for labeled slider (#7929) 2020-12-29 22:50:09 +01:00
Philip Allgaier
ef3bc3efe1 Do not render "No Area" in device table to reduce clutter (#7986) 2020-12-29 22:46:47 +01:00
Philip Allgaier
371ad899f5 Handle sorting with "undefined" (move always to bottom) (#7985) 2020-12-29 22:45:39 +01:00
plafü
2c54158d84 Fixes typo: 'bring to live'>'bring to life' (#8000) 2020-12-29 22:44:21 +01:00
quthla
5d9e30bbdc Fix translation of home state (#8015) 2020-12-29 22:43:41 +01:00
Marc Randolph
e477fd567d Button text is swapped on Lovelace raw YAML exit window (#8038)
Button text is swapped compared to the same thing elsewhere: d23165d06a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts (L311)
2020-12-29 22:38:31 +01:00
Philip Allgaier
6a6c2937fe Ensure consistent spelling of "ID" (#8042) 2020-12-29 22:36:28 +01:00
HomeAssistant Azure
09e17c4da8 [ci skip] Translation update 2020-12-29 00:32:26 +00:00
HomeAssistant Azure
fd00469d11 [ci skip] Translation update 2020-12-28 00:32:37 +00:00
HomeAssistant Azure
cbbeb795f3 [ci skip] Translation update 2020-12-27 00:32:32 +00:00
HomeAssistant Azure
bba40e0da8 [ci skip] Translation update 2020-12-25 00:32:32 +00:00
HomeAssistant Azure
d23165d06a [ci skip] Translation update 2020-12-24 00:33:07 +00:00
HomeAssistant Azure
405fef6f03 [ci skip] Translation update 2020-12-23 00:32:49 +00:00
HomeAssistant Azure
588f217826 [ci skip] Translation update 2020-12-22 00:32:27 +00:00
HomeAssistant Azure
3d8b7cf80e [ci skip] Translation update 2020-12-21 00:32:26 +00:00
HomeAssistant Azure
c0ef923ad3 [ci skip] Translation update 2020-12-20 00:32:26 +00:00
HomeAssistant Azure
3df44fc71e [ci skip] Translation update 2020-12-19 00:33:33 +00:00
HomeAssistant Azure
c1965492d9 [ci skip] Translation update 2020-12-18 00:32:38 +00:00
HomeAssistant Azure
1f56ffde80 [ci skip] Translation update 2020-12-17 00:33:13 +00:00
Georgi Kirichkov
f335fdc002 Fixes a typo in hassio-supervisor-info.ts (#7987)
An "a" was missing in installtion
2020-12-16 10:28:21 +01:00
HomeAssistant Azure
0c914b5ec8 [ci skip] Translation update 2020-12-16 00:32:25 +00:00
Philip Allgaier
d767b06858 Fix spelling error (#7961)
Fixes https://github.com/home-assistant/frontend/issues/7958
2020-12-15 07:22:06 -06:00
Fabian Affolter
d4e49f3944 Update entry (#7978) 2020-12-15 09:49:26 +01:00
HomeAssistant Azure
7dfc5b3faf [ci skip] Translation update 2020-12-15 00:32:22 +00:00
HomeAssistant Azure
8a88033ab9 [ci skip] Translation update 2020-12-14 00:32:42 +00:00
HomeAssistant Azure
7b06b38c94 [ci skip] Translation update 2020-12-13 00:32:43 +00:00
Bram Kragten
5409752817 20201212.0 (#7952)
* [ci skip] Translation update

* Add link to the community forums to find more blueprints (#7947)

* Add link to the community forums to find more blueprints

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Fix `ha-relative-time` usage for tags and sun (#7944)

* Bumped version to 20201212.0

Co-authored-by: HomeAssistant Azure <hello@home-assistant.io>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Philip Allgaier <mail@spacegaier.de>
2020-12-12 20:57:28 +01:00
Bram Kragten
909f3a3005 Bumped version to 20201212.0 2020-12-12 20:48:44 +01:00
Philip Allgaier
4930532c7b Fix ha-relative-time usage for tags and sun (#7944) 2020-12-12 20:46:56 +01:00
Bram Kragten
8a42e65c6a Add link to the community forums to find more blueprints (#7947)
* Add link to the community forums to find more blueprints

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-12-12 20:38:10 +01:00
HomeAssistant Azure
5d4121a9b4 [ci skip] Translation update 2020-12-11 00:32:17 +00:00
Bram Kragten
a70e6c49a1 Merge pull request #7940 from home-assistant/dev
20201210.0
2020-12-10 16:56:08 +01:00
Bram Kragten
3d83d5f4b5 Bumped version to 20201210.0 2020-12-10 15:57:13 +01:00
Philip Allgaier
f9dece0743 Add copy YAML (automation & script) fallback without navigator.clipboard (#7900) 2020-12-10 15:55:57 +01:00
Bram Kragten
ac0871d0e8 Use correct device name in target picker (#7939) 2020-12-10 15:12:33 +01:00
HomeAssistant Azure
ffc19e591d [ci skip] Translation update 2020-12-10 00:32:24 +00:00
HomeAssistant Azure
c53380ca3d [ci skip] Translation update 2020-12-09 00:32:38 +00:00
Bram Kragten
7c74a2026a Correct tabs helpers page (#7928)
Fixes https://github.com/home-assistant/frontend/issues/7926
2020-12-08 11:47:30 +01:00
HomeAssistant Azure
adaed438d9 [ci skip] Translation update 2020-12-08 00:32:29 +00:00
uvjustin
baf38305cb Remove use of named groups in regexp (#7921) 2020-12-07 15:18:27 +01:00
HomeAssistant Azure
8254712521 [ci skip] Translation update 2020-12-07 00:33:14 +00:00
HomeAssistant Azure
53214781e3 [ci skip] Translation update 2020-12-06 00:32:39 +00:00
HomeAssistant Azure
88cbbbdf65 [ci skip] Translation update 2020-12-05 00:33:30 +00:00
Bram Kragten
c10dca9c7b Merge pull request #7910 from home-assistant/dev 2020-12-04 21:46:54 +01:00
Bram Kragten
7f2ebb4bde Bumped version to 20201204.0 2020-12-04 21:33:37 +01:00
Bram Kragten
f1abb60e4a Add message when no matches for selectors, clear config when deleted (#7906) 2020-12-04 20:49:24 +01:00
Bram Kragten
e014c7aff6 Entity is not required for button card (#7909)
Fixes https://github.com/home-assistant/frontend/issues/7908
2020-12-04 12:02:58 -06:00
Bram Kragten
b79c03433e Don't update device picker while open (#7903) 2020-12-04 12:05:01 +01:00
HomeAssistant Azure
34eb4d974d [ci skip] Translation update 2020-12-04 00:32:26 +00:00
Zack Barett
3264be3c5e Move main function to events on hui-view for custom views to use (#7861) 2020-12-03 18:16:55 -06:00
Bram Kragten
655f4f75fb Change import blueprint fab icon (#7894) 2020-12-03 22:41:13 +01:00
Bram Kragten
4383f31696 Translation logic tweaks (#7901)
* Translation logic tweaks

* Comments
2020-12-03 22:29:52 +01:00
Paulus Schoutsen
99eb15d15e Improve blueprint translations (#7892) 2020-12-03 18:08:14 +01:00
Bram Kragten
2682c6e150 Merge pull request #7891 from home-assistant/dev 2020-12-03 17:22:08 +01:00
Bram Kragten
3a5d854e6d Bumped version to 20201203.0 2020-12-03 17:00:56 +01:00
Bram Kragten
1e90c6387c More BP tweaks (#7884) 2020-12-03 09:59:43 -06:00
Philip Allgaier
2cca25f4d0 Navigate back to area overview after area deletion (#7890) 2020-12-03 16:52:44 +01:00
Bram Kragten
565724d201 Fix translation race condition? (#7885) 2020-12-03 16:52:09 +01:00
Bram Kragten
3e4955becd UI tweaks for BP (#7883)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-12-03 14:18:17 +01:00
Philip Allgaier
7b560c727f Adjust text since entities can now be in areas too (#7880) 2020-12-03 14:05:16 +01:00
HomeAssistant Azure
35abd9dfdb [ci skip] Translation update 2020-12-03 00:32:38 +00:00
Bram Kragten
b7ccf3e0e5 Merge pull request #7875 from home-assistant/dev 2020-12-02 19:51:36 +01:00
Bram Kragten
0d9ab8fdd0 Bumped version to 20201202.0 2020-12-02 19:31:43 +01:00
Bram Kragten
303f9290a8 Add more device disabled ui (#7874) 2020-12-02 19:31:06 +01:00
Bram Kragten
e0c4dc08a1 Tooltip tweak target picker (#7870) 2020-12-02 11:21:51 -06:00
Bram Kragten
8c655883fe Add device disabled reason (#7873) 2020-12-02 18:20:29 +01:00
Bram Kragten
ba90785115 Fix card picker cards (#7871) 2020-12-02 17:46:30 +01:00
Bram Kragten
7b392b626b Hardcode history card stub entity to sun.sun (#7760) 2020-12-02 10:16:46 -06:00
Zack Barett
8e4ceb7d48 Fix View Background Colors (#7823) 2020-12-02 17:08:18 +01:00
Philip Allgaier
2ab1c6e9a9 Make media player card work as square + add to gallery + icon pos tweaks (#7727) 2020-12-02 16:57:19 +01:00
Adam Ernst
dbdced0971 Improve descriptions for Configuration entries (#7606) 2020-12-02 16:36:21 +01:00
Philip Allgaier
5e481880bd Allow empty entities array with entity-filter (#7854) 2020-12-02 16:34:59 +01:00
Kendell R
faec063f34 Add --masonry-view-card-margin (#7395) 2020-12-02 16:22:20 +01:00
Zack Barett
bbea38d227 Lovelace Card Editor: Preview Background (#7678) 2020-12-02 16:19:01 +01:00
Kendell R
a0ef60de49 Make card picker border follow standards (#7162) 2020-12-02 16:14:46 +01:00
Philip Allgaier
3313572606 Improve password change card (#7756)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-12-02 16:00:49 +01:00
Philip Allgaier
c4f850cb14 Cleanup created user if person creation is cancelled (#7865) 2020-12-02 15:45:24 +01:00
Erik Montnemery
3bdab738c6 Support disabling devices (#7715)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-12-02 15:40:35 +01:00
Philip Allgaier
faaef31b9f Show proper error message if username already used (#7866) 2020-12-02 15:35:38 +01:00
Philip Allgaier
ca7b8b8b4c Add option to deactivate a user (#7757) 2020-12-02 15:33:11 +01:00
Philip Allgaier
9ca84e0694 Ensure "false" is set as default for "continue_on_timeout" (#7862) 2020-12-02 15:22:17 +01:00
Philip Allgaier
daaf2b1796 Ensure push notification description reacts to language change (#7856) 2020-12-02 12:11:47 +01:00
Bram Kragten
25f7cbea5a Add target selector (#7864)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-12-02 12:10:31 +01:00
Josh McCarty
c485ea9d7b Add number formatting to counter entity state display (#7868) 2020-12-02 11:51:56 +01:00
HomeAssistant Azure
295390c8e9 [ci skip] Translation update 2020-12-02 00:32:30 +00:00
Bram Kragten
3ebf816ce2 Fix height of ha-icon-input (#7767) 2020-12-01 22:51:15 +01:00
Bram Kragten
50e7410002 Merge pull request #7833 from home-assistant/dev 2020-11-27 00:16:56 +01:00
125 changed files with 7412 additions and 1920 deletions

View File

@@ -14,7 +14,7 @@ This is the repository for the official [Home Assistant](https://home-assistant.
- Development: [Instructions](https://developers.home-assistant.io/docs/frontend/development/)
- Production build: `script/build_frontend`
- Gallery: `cd gallery && script/develop_gallery`
- Hass.io: [Instructions](https://developers.home-assistant.io/docs/en/hassio_hass.html)
- Supervisor: [Instructions](https://developers.home-assistant.io/docs/supervisor/developing)
## Frontend development

View File

@@ -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,

View File

@@ -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 {

View File

@@ -69,7 +69,7 @@ const STAGE_ICON = {
const PERMIS_DESC = {
stage: {
title: "Add-on Stage",
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon .path='${STAGE_ICON.stable}'></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon .path='${STAGE_ICON.experimental}'></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon .path='${STAGE_ICON.deprecated}'></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
},
rating: {
title: "Add-on Security Rating",

View File

@@ -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(

View File

@@ -178,7 +178,7 @@ class HassioSupervisorInfo extends LitElement {
</div>`}
${!this.supervisor.supervisor.healthy
? html`<div class="error">
Your installtion is running in an unhealthy state.
Your installation is running in an unhealthy state.
<button
class="link"
title="Learn more about why your system is marked as unhealthy"

View File

@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20201126.0",
version="20201229.1",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",

View File

@@ -0,0 +1,6 @@
export const ensureArray = (value?: any) => {
if (!value || Array.isArray(value)) {
return value;
}
return [value];
};

View File

@@ -67,6 +67,10 @@ export const computeStateDisplay = (
}
}
if (domain === "counter") {
return formatNumber(compareState, language);
}
return (
// Return device class translation
(stateObj.attributes.device_class &&

View File

@@ -1,8 +1,12 @@
export const copyToClipboard = (str) => {
const el = document.createElement("textarea");
el.value = str;
document.body.appendChild(el);
el.select();
document.execCommand("copy");
document.body.removeChild(el);
if (navigator.clipboard) {
navigator.clipboard.writeText(str);
} else {
const el = document.createElement("textarea");
el.value = str;
document.body.appendChild(el);
el.select();
document.execCommand("copy");
document.body.removeChild(el);
}
};

View File

@@ -98,6 +98,12 @@ export class HaDataTable extends LitElement {
@property({ type: Boolean }) public hasFab = false;
/**
* Add an extra row at the bottom of the data table
* @type {TemplateResult}
*/
@property({ attribute: false }) public appendRow?;
@property({ type: Boolean, attribute: "auto-height" })
public autoHeight = false;
@@ -126,6 +132,8 @@ export class HaDataTable extends LitElement {
@query("slot[name='header']") private _header!: HTMLSlotElement;
private _items: DataTableRowData[] = [];
private _checkableRowsCount?: number;
private _checkedRows: string[] = [];
@@ -318,10 +326,13 @@ export class HaDataTable extends LitElement {
@scroll=${this._saveScrollPos}
>
${scroll({
items: !this.hasFab
? this._filteredData
: [...this._filteredData, ...[{ empty: true }]],
items: this._items,
renderItem: (row: DataTableRowData, index) => {
if (row.append) {
return html`
<div class="mdc-data-table__row">${row.content}</div>
`;
}
if (row.empty) {
return html` <div class="mdc-data-table__row"></div> `;
}
@@ -447,6 +458,20 @@ export class HaDataTable extends LitElement {
if (this.curRequest !== curRequest) {
return;
}
if (this.appendRow || this.hasFab) {
this._items = [...data];
if (this.appendRow) {
this._items.push({ append: true, content: this.appendRow });
}
if (this.hasFab) {
this._items.push({ empty: true });
}
} else {
this._items = data;
}
this._filteredData = data;
}

View File

@@ -58,6 +58,14 @@ const sortData = (
valB = valB.toUpperCase();
}
// Ensure "undefined" is always sorted to the bottom
if (valA === undefined && valB !== undefined) {
return 1;
}
if (valB === undefined && valA !== undefined) {
return -1;
}
if (valA < valB) {
return sort * -1;
}

View File

@@ -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,

View File

@@ -1,4 +1,5 @@
import "../ha-icon-button";
import "../ha-svg-icon";
import "@material/mwc-icon-button/mwc-icon-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
@@ -12,6 +13,8 @@ import {
html,
LitElement,
property,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
@@ -35,6 +38,7 @@ import {
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import { PolymerChangedEvent } from "../../polymer-types";
import { HomeAssistant } from "../../types";
import { mdiClose, mdiMenuUp, mdiMenuDown } from "@mdi/js";
interface Device {
name: string;
@@ -111,6 +115,10 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
@property({ type: Boolean })
private _opened?: boolean;
@query("vaadin-combo-box-light", true) private _comboBox!: HTMLElement;
private _init = false;
private _getDevices = memoizeOne(
(
devices: DeviceRegistryEntry[],
@@ -122,18 +130,27 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
deviceFilter: this["deviceFilter"]
): Device[] => {
if (!devices.length) {
return [];
return [
{
id: "",
area: "",
name: this.hass.localize("ui.components.device-picker.no_devices"),
},
];
}
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 } = {};
@@ -141,7 +158,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) => {
@@ -208,6 +227,15 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
: this.hass.localize("ui.components.device-picker.no_area"),
};
});
if (!outputDevices.length) {
return [
{
id: "",
area: "",
name: this.hass.localize("ui.components.device-picker.no_match"),
},
];
}
if (outputDevices.length === 1) {
return outputDevices;
}
@@ -215,6 +243,18 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
}
);
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();
});
}
public hassSubscribe(): UnsubscribeFunc[] {
return [
subscribeDeviceRegistry(this.hass.connection!, (devices) => {
@@ -229,25 +269,33 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
];
}
protected updated(changedProps: PropertyValues) {
if (
(!this._init && this.devices && this.areas && this.entities) ||
(changedProps.has("_opened") && this._opened)
) {
this._init = true;
(this._comboBox as any).items = this._getDevices(
this.devices!,
this.areas!,
this.entities!,
this.includeDomains,
this.excludeDomains,
this.includeDeviceClasses,
this.deviceFilter
);
}
}
protected render(): TemplateResult {
if (!this.devices || !this.areas || !this.entities) {
return html``;
}
const devices = this._getDevices(
this.devices,
this.areas,
this.entities,
this.includeDomains,
this.excludeDomains,
this.includeDeviceClasses,
this.deviceFilter
);
return html`
<vaadin-combo-box-light
item-value-path="id"
item-id-path="id"
item-label-path="name"
.items=${devices}
.value=${this._value}
.renderer=${rowRenderer}
@opened-changed=${this._openedChanged}
@@ -265,34 +313,30 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
>
${this.value
? html`
<ha-icon-button
aria-label=${this.hass.localize(
<mwc-icon-button
.label=${this.hass.localize(
"ui.components.device-picker.clear"
)}
slot="suffix"
class="clear-button"
icon="hass:close"
@click=${this._clearValue}
no-ripple
>
Clear
</ha-icon-button>
`
: ""}
${devices.length > 0
? html`
<ha-icon-button
aria-label=${this.hass.localize(
"ui.components.device-picker.show_devices"
)}
slot="suffix"
class="toggle-button"
.icon=${this._opened ? "hass:menu-up" : "hass:menu-down"}
>
Toggle
</ha-icon-button>
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</mwc-icon-button>
`
: ""}
<mwc-icon-button
.label=${this.hass.localize(
"ui.components.device-picker.show_devices"
)}
slot="suffix"
class="toggle-button"
>
<ha-svg-icon
.path=${this._opened ? mdiMenuUp : mdiMenuDown}
></ha-svg-icon>
</mwc-icon-button>
</paper-input>
</vaadin-combo-box-light>
`;
@@ -329,7 +373,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
static get styles(): CSSResult {
return css`
paper-input > ha-icon-button {
paper-input > mwc-icon-button {
--mdc-icon-button-size: 24px;
padding: 2px;
color: var(--secondary-text-color);

View File

@@ -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[] = [];
@@ -153,6 +165,24 @@ export class HaEntityPicker extends LitElement {
);
}
if (!states.length) {
return [
{
entity_id: "",
state: "",
last_changed: "",
last_updated: "",
context: { id: "", user_id: null },
attributes: {
friendly_name: this.hass!.localize(
"ui.components.entity.entity-picker.no_match"
),
icon: "mdi:magnify",
},
},
];
}
return states;
}
);
@@ -203,7 +233,6 @@ export class HaEntityPicker extends LitElement {
.label=${this.label === undefined
? this.hass.localize("ui.components.entity.entity-picker.entity")
: this.label}
.value=${this._value}
.disabled=${this.disabled}
class="input"
autocapitalize="none"

View File

@@ -1,4 +1,5 @@
import "./ha-icon-button";
import "./ha-svg-icon";
import "@material/mwc-icon-button/mwc-icon-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
@@ -14,6 +15,8 @@ import {
property,
internalProperty,
TemplateResult,
PropertyValues,
query,
} from "lit-element";
import { fireEvent } from "../common/dom/fire_event";
import {
@@ -29,6 +32,18 @@ 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";
import { mdiClose, mdiMenuDown, mdiMenuUp } from "@mdi/js";
const rowRenderer = (
root: HTMLElement,
@@ -71,31 +86,250 @@ 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;
@query("vaadin-combo-box-light", true) private _comboBox!: HTMLElement;
private _init = false;
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[] => {
if (!areas.length) {
return [
{
area_id: "",
name: this.hass.localize("ui.components.area-picker.no_areas"),
},
];
}
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) {
inputEntities = inputEntities!.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));
}
if (!outputAreas.length) {
outputAreas = [
{
area_id: "",
name: this.hass.localize("ui.components.area-picker.no_match"),
},
];
}
return noAdd
? outputAreas
: [
...outputAreas,
{
area_id: "add_new",
name: this.hass.localize("ui.components.area-picker.add_new"),
},
];
}
);
protected updated(changedProps: PropertyValues) {
if (
(!this._init && this._devices && this._areas && this._entities) ||
(changedProps.has("_opened") && this._opened)
) {
this._init = true;
(this._comboBox as any).items = this._getAreas(
this._areas!,
this._devices!,
this._entities!,
this.includeDomains,
this.excludeDomains,
this.includeDeviceClasses,
this.deviceFilter,
this.entityFilter,
this.noAdd
);
}
}
protected render(): TemplateResult {
if (!this._areas) {
if (!this._devices || !this._areas || !this._entities) {
return html``;
}
return html`
@@ -103,7 +337,6 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
item-value-path="area_id"
item-id-path="area_id"
item-label-path="name"
.items=${this._areas}
.value=${this._value}
.renderer=${rowRenderer}
@opened-changed=${this._openedChanged}
@@ -124,34 +357,28 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
>
${this.value
? html`
<ha-icon-button
aria-label=${this.hass.localize(
<mwc-icon-button
.label=${this.hass.localize(
"ui.components.area-picker.clear"
)}
slot="suffix"
class="clear-button"
icon="hass:close"
@click=${this._clearValue}
no-ripple
>
${this.hass.localize("ui.components.area-picker.clear")}
</ha-icon-button>
`
: ""}
${this._areas.length > 0
? html`
<ha-icon-button
aria-label=${this.hass.localize(
"ui.components.area-picker.show_areas"
)}
slot="suffix"
class="toggle-button"
.icon=${this._opened ? "hass:menu-up" : "hass:menu-down"}
>
${this.hass.localize("ui.components.area-picker.toggle")}
</ha-icon-button>
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</mwc-icon-button>
`
: ""}
<mwc-icon-button
.label=${this.hass.localize("ui.components.area-picker.toggle")}
slot="suffix"
class="toggle-button"
>
<ha-svg-icon
.path=${this._opened ? mdiMenuUp : mdiMenuDown}
></ha-svg-icon>
</mwc-icon-button>
</paper-input>
</vaadin-combo-box-light>
`;
@@ -227,7 +454,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
static get styles(): CSSResult {
return css`
paper-input > ha-icon-button {
paper-input > mwc-icon-button {
--mdc-icon-button-size: 24px;
padding: 2px;
color: var(--secondary-text-color);

View File

@@ -52,6 +52,7 @@ class HaBluePrintPicker extends LitElement {
.label=${this.label ||
this.hass.localize("ui.components.blueprint-picker.label")}
.disabled=${this.disabled}
horizontal-align="left"
>
<paper-listbox
slot="dropdown-content"
@@ -110,6 +111,9 @@ class HaBluePrintPicker extends LitElement {
paper-listbox {
min-width: 200px;
}
paper-item {
cursor: pointer;
}
`;
}
}

View File

@@ -11,6 +11,7 @@ import {
import { fireEvent } from "../common/dom/fire_event";
import type { ToggleButton } from "../types";
import "./ha-svg-icon";
import "@material/mwc-button/mwc-button";
@customElement("ha-button-toggle-group")
export class HaButtonToggleGroup extends LitElement {
@@ -21,17 +22,22 @@ export class HaButtonToggleGroup extends LitElement {
protected render(): TemplateResult {
return html`
<div>
${this.buttons.map(
(button) => html`
<mwc-icon-button
.label=${button.label}
.value=${button.value}
?active=${this.active === button.value}
@click=${this._handleClick}
>
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
</mwc-icon-button>
`
${this.buttons.map((button) =>
button.iconPath
? html`<mwc-icon-button
.label=${button.label}
.value=${button.value}
?active=${this.active === button.value}
@click=${this._handleClick}
>
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
</mwc-icon-button>`
: html`<mwc-button
.value=${button.value}
?active=${this.active === button.value}
@click=${this._handleClick}
>${button.label}</mwc-button
>`
)}
</div>
`;
@@ -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;
}

View File

@@ -127,7 +127,7 @@ class HaHLSPlayer extends LitElement {
// Parse playlist assuming it is a master playlist. Match group 1 is whether hevc, match group 2 is regular playlist url
// See https://tools.ietf.org/html/rfc8216 for HLS spec details
const playlistRegexp = /#EXT-X-STREAM-INF:.*?(?:CODECS=".*?(?<isHevc>hev1|hvc1)?\..*?".*?)?(?:\n|\r\n)(?<streamUrl>.+)/g;
const playlistRegexp = /#EXT-X-STREAM-INF:.*?(?:CODECS=".*?(hev1|hvc1)?\..*?".*?)?(?:\n|\r\n)(.+)/g;
const match = playlistRegexp.exec(masterPlaylist);
const matchTwice = playlistRegexp.exec(masterPlaylist);
@@ -136,17 +136,13 @@ class HaHLSPlayer extends LitElement {
let playlist_url: string;
if (match !== null && matchTwice === null) {
// Only send the regular playlist url if we match exactly once
playlist_url = new URL(match.groups!.streamUrl, this.url).href;
playlist_url = new URL(match[2], this.url).href;
} else {
playlist_url = this.url;
}
// If codec is HEVC and ExoPlayer is supported, use ExoPlayer.
if (
this._useExoPlayer &&
match !== null &&
match.groups!.isHevc !== undefined
) {
if (this._useExoPlayer && match !== null && match[1] !== undefined) {
this._renderHLSExoPlayer(playlist_url);
} else if (hls.isSupported()) {
this._renderHLSPolyfill(videoEl, hls, playlist_url);

View File

@@ -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;
}
`;
}

View File

@@ -10,7 +10,6 @@ class HaLabeledSlider extends PolymerElement {
<style>
:host {
display: block;
border-radius: 4px;
}
.title {
@@ -30,6 +29,7 @@ class HaLabeledSlider extends PolymerElement {
ha-slider {
flex-grow: 1;
background-image: var(--ha-slider-background);
border-radius: 4px;
}
</style>

View File

@@ -13,7 +13,7 @@ import type { HomeAssistant } from "../types";
class HaRelativeTime extends UpdatingElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public datetime?: string;
@property({ attribute: false }) public datetime?: string | Date;
private _interval?: number;

View File

@@ -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`<ha-automation-action
.actions=${this.value || []}
.hass=${this.hass}
></ha-automation-action>`;
}
static get styles(): CSSResult {
return css`
ha-automation-action {
display: block;
margin-bottom: 16px;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-action": HaActionSelector;
}
}

View File

@@ -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,77 @@ 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`<ha-area-picker
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
no-add
.deviceFilter=${(device) => 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}
></ha-area-picker>`;
}
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 &&
!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 {

View File

@@ -63,7 +63,8 @@ export class HaDeviceSelector extends LitElement {
}
if (this.selector.device.integration) {
if (
!this._configEntries?.some((entry) =>
this._configEntries &&
!this._configEntries.some((entry) =>
device.config_entries.includes(entry.entry_id)
)
) {

View File

@@ -19,7 +19,7 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) {
@property() public selector!: EntitySelector;
@internalProperty() private _entities?: Record<string, string>;
@internalProperty() private _entityPlaformLookup?: Record<string, string>;
@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;
}

View File

@@ -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<string, string>;
@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`<ha-target-picker
.hass=${this.hass}
.value=${this.value}
.deviceFilter=${(device) => 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}
></ha-target-picker>`;
}
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;
}
}

View File

@@ -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")

View File

@@ -18,11 +18,6 @@ export class HaSettingsRow extends LitElement {
protected render(): SVGTemplateResult {
return html`
<style>
paper-item-body {
padding-right: 16px;
}
</style>
<paper-item-body
?two-line=${!this.threeLine}
?three-line=${this.threeLine}
@@ -43,6 +38,14 @@ export class HaSettingsRow extends LitElement {
align-self: auto;
align-items: center;
}
paper-item-body {
padding: 8px 16px 8px 0;
}
paper-item-body[two-line] {
min-height: calc(
var(--paper-item-body-two-line-min-height, 72px) - 16px
);
}
:host([narrow]) {
align-items: normal;
flex-direction: column;
@@ -52,6 +55,9 @@ export class HaSettingsRow extends LitElement {
::slotted(ha-switch) {
padding: 16px 0;
}
div[secondary] {
white-space: normal;
}
`;
}
}

View File

@@ -0,0 +1,605 @@
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 {
computeDeviceName,
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`<div class="mdc-chip-set items">
${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 ? computeDeviceName(device, this.hass) : 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
);
})}
</div>
${this._renderPicker()}
<div class="mdc-chip-set">
<div
class="mdc-chip area_id add"
.type=${"area_id"}
@click=${this._showPicker}
>
<div class="mdc-chip__ripple"></div>
<ha-svg-icon
class="mdc-chip__icon mdc-chip__icon--leading"
.path=${mdiPlus}
></ha-svg-icon>
<span role="gridcell">
<span role="button" tabindex="0" class="mdc-chip__primary-action">
<span class="mdc-chip__text"
>${this.hass.localize(
"ui.components.target-picker.add_area_id"
)}</span
>
</span>
</span>
</div>
<div
class="mdc-chip device_id add"
.type=${"device_id"}
@click=${this._showPicker}
>
<div class="mdc-chip__ripple"></div>
<ha-svg-icon
class="mdc-chip__icon mdc-chip__icon--leading"
.path=${mdiPlus}
></ha-svg-icon>
<span role="gridcell">
<span role="button" tabindex="0" class="mdc-chip__primary-action">
<span class="mdc-chip__text"
>${this.hass.localize(
"ui.components.target-picker.add_device_id"
)}</span
>
</span>
</span>
</div>
<div
class="mdc-chip entity_id add"
.type=${"entity_id"}
@click=${this._showPicker}
>
<div class="mdc-chip__ripple"></div>
<ha-svg-icon
class="mdc-chip__icon mdc-chip__icon--leading"
.path=${mdiPlus}
></ha-svg-icon>
<span role="gridcell">
<span role="button" tabindex="0" class="mdc-chip__primary-action">
<span class="mdc-chip__text"
>${this.hass.localize(
"ui.components.target-picker.add_entity_id"
)}</span
>
</span>
</span>
</div>
</div>`;
}
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`
<div
class="mdc-chip ${classMap({
[type]: true,
})}"
>
${iconPath
? html`<ha-svg-icon
class="mdc-chip__icon mdc-chip__icon--leading"
.path=${iconPath}
></ha-svg-icon>`
: ""}
${icon
? html`<ha-icon
class="mdc-chip__icon mdc-chip__icon--leading"
.icon=${icon}
></ha-icon>`
: ""}
<span role="gridcell">
<span role="button" tabindex="0" class="mdc-chip__primary-action">
<span class="mdc-chip__text">${name}</span>
</span>
</span>
${type === "entity_id"
? ""
: html` <span role="gridcell">
<mwc-icon-button
class="expand-btn mdc-chip__icon mdc-chip__icon--trailing"
tabindex="-1"
role="button"
.label=${"Expand"}
.id=${id}
.type=${type}
@click=${this._handleExpand}
>
<ha-svg-icon .path=${mdiUnfoldMoreVertical}></ha-svg-icon>
</mwc-icon-button>
<paper-tooltip class="expand" animation-delay="0"
>${this.hass.localize(
`ui.components.target-picker.expand_${type}`
)}</paper-tooltip
>
</span>`}
<span role="gridcell">
<mwc-icon-button
class="mdc-chip__icon mdc-chip__icon--trailing"
tabindex="-1"
role="button"
.label=${"Remove"}
.id=${id}
.type=${type}
@click=${this._handleRemove}
>
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</mwc-icon-button>
<paper-tooltip animation-delay="0"
>${this.hass.localize(
`ui.components.target-picker.remove_${type}`
)}</paper-tooltip
>
</span>
</div>
`;
}
private _renderPicker() {
switch (this._addMode) {
case "area_id":
return html`<ha-area-picker
.hass=${this.hass}
id="input"
.type=${"area_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_area_id"
)}
no-add
.deviceFilter=${this.deviceFilter}
.entityFilter=${this.entityRegFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
@value-changed=${this._targetPicked}
></ha-area-picker>`;
case "device_id":
return html`<ha-device-picker
.hass=${this.hass}
id="input"
.type=${"device_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_device_id"
)}
.deviceFilter=${this.deviceFilter}
.entityFilter=${this.entityRegFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
@value-changed=${this._targetPicked}
></ha-device-picker>`;
case "entity_id":
return html`<ha-entity-picker
.hass=${this.hass}
id="input"
.type=${"entity_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_entity_id"
)}
.entityFilter=${this.entityFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
@value-changed=${this._targetPicked}
></ha-entity-picker>`;
}
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"] {
const newVal = ensureArray(value![type])!.filter((val) => val !== id);
if (newVal.length) {
return {
...value,
[type]: newVal,
};
}
const val = { ...value }!;
delete val[type];
if (Object.keys(val).length) {
return val;
}
return undefined;
}
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.expand {
min-width: 200px;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-target-picker": HaTargetPicker;
}
}

View File

@@ -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;
}

View File

@@ -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 = (

View File

@@ -124,13 +124,17 @@ export const getLogbookMessage = (
switch (domain) {
case "device_tracker":
case "person":
return state === "not_home"
? hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_away`)
: hass.localize(
`${LOGBOOK_LOCALIZE_PATH}.was_at_state`,
"state",
state
);
if (state === "not_home") {
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_away`);
}
if (state === "home") {
return hass.localize(`${LOGBOOK_LOCALIZE_PATH}.was_at_home`);
}
return hass.localize(
`${LOGBOOK_LOCALIZE_PATH}.was_at_state`,
"state",
state
);
case "sun":
return state === "above_horizon"

View File

@@ -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;
}

View File

@@ -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: {};
}

5
src/data/target.ts Normal file
View File

@@ -0,0 +1,5 @@
export interface Target {
entity_id?: string[];
device_id?: string[];
area_id?: string[];
}

View File

@@ -20,6 +20,7 @@ export interface User {
export interface UpdateUserParams {
name?: User["name"];
is_active?: User["is_active"];
group_ids?: User["group_ids"];
}

View File

@@ -17,17 +17,17 @@ import "../../components/ha-switch";
import { PolymerChangedEvent } from "../../polymer-types";
import { haStyleDialog } from "../../resources/styles";
import { HomeAssistant } from "../../types";
import { DialogParams } from "./show-dialog-box";
import { DialogBoxParams } from "./show-dialog-box";
@customElement("dialog-box")
class DialogBox extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@internalProperty() private _params?: DialogParams;
@internalProperty() private _params?: DialogBoxParams;
@internalProperty() private _value?: string;
public async showDialog(params: DialogParams): Promise<void> {
public async showDialog(params: DialogBoxParams): Promise<void> {
this._params = params;
if (params.prompt) {
this._value = params.defaultValue;
@@ -55,8 +55,8 @@ class DialogBox extends LitElement {
return html`
<ha-dialog
open
?scrimClickAction=${this._params.prompt}
?escapeKeyAction=${this._params.prompt}
?scrimClickAction=${confirmPrompt}
?escapeKeyAction=${confirmPrompt}
@closed=${this._dialogClosed}
defaultAction="ignore"
.heading=${this._params.title
@@ -140,10 +140,10 @@ class DialogBox extends LitElement {
}
private _dialogClosed(ev) {
if (ev.detail.action === "ignore") {
if (this._params?.prompt && ev.detail.action === "ignore") {
return;
}
this.closeDialog();
this._dismiss();
}
private _close(): void {

View File

@@ -1,31 +1,31 @@
import { TemplateResult } from "lit-html";
import { fireEvent } from "../../common/dom/fire_event";
interface BaseDialogParams {
interface BaseDialogBoxParams {
confirmText?: string;
text?: string | TemplateResult;
title?: string;
warning?: boolean;
}
export interface AlertDialogParams extends BaseDialogParams {
export interface AlertDialogParams extends BaseDialogBoxParams {
confirm?: () => void;
}
export interface ConfirmationDialogParams extends BaseDialogParams {
export interface ConfirmationDialogParams extends BaseDialogBoxParams {
dismissText?: string;
confirm?: () => void;
cancel?: () => void;
}
export interface PromptDialogParams extends BaseDialogParams {
export interface PromptDialogParams extends BaseDialogBoxParams {
inputLabel?: string;
inputType?: string;
defaultValue?: string;
confirm?: (out?: string) => void;
}
export interface DialogParams
export interface DialogBoxParams
extends ConfirmationDialogParams,
PromptDialogParams {
confirm?: (out?: string) => void;
@@ -37,10 +37,10 @@ export const loadGenericDialog = () => import("./dialog-box");
const showDialogHelper = (
element: HTMLElement,
dialogParams: DialogParams,
dialogParams: DialogBoxParams,
extra?: {
confirmation?: DialogParams["confirmation"];
prompt?: DialogParams["prompt"];
confirmation?: DialogBoxParams["confirmation"];
prompt?: DialogBoxParams["prompt"];
}
) =>
new Promise((resolve) => {

View File

@@ -44,7 +44,7 @@ class MoreInfoSun extends LitElement {
>
<ha-relative-time
.hass=${this.hass}
.datetimeObj=${item === "ris" ? risingDate : settingDate}
.datetime=${item === "ris" ? risingDate : settingDate}
></ha-relative-time>
</div>
<div class="value">
@@ -80,6 +80,7 @@ class MoreInfoSun extends LitElement {
}
ha-relative-time {
display: inline-block;
white-space: nowrap;
}
ha-relative-time::first-letter {
text-transform: lowercase;

View File

@@ -60,6 +60,12 @@ export class HaTabsSubpageDataTable extends LitElement {
*/
@property({ type: Boolean }) public hasFab = false;
/**
* Add an extra row at the bottom of the data table
* @type {TemplateResult}
*/
@property({ attribute: false }) public appendRow?;
/**
* Field with a unique id per entry in data.
* @type {String}
@@ -171,6 +177,7 @@ export class HaTabsSubpageDataTable extends LitElement {
.noDataText=${this.noDataText}
.dir=${computeRTLDirection(this.hass)}
.clickable=${this.clickable}
.appendRow=${this.appendRow}
>
${!this.narrow
? html`

View File

@@ -17,6 +17,7 @@ import { PolymerChangedEvent } from "../../../polymer-types";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { AreaRegistryDetailDialogParams } from "./show-dialog-area-registry-detail";
import { navigate } from "../../../common/navigate";
class DialogAreaDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -154,6 +155,8 @@ class DialogAreaDetail extends LitElement {
} finally {
this._submitting = false;
}
navigate(this, "/config/areas/dashboard");
}
static get styles(): CSSResult[] {

View File

@@ -39,7 +39,7 @@ export class HaWaitForTriggerAction extends LitElement
)}
>
<ha-switch
.checked=${continue_on_timeout}
.checked=${continue_on_timeout ?? true}
@change=${this._continueChanged}
></ha-switch>
</ha-formfield>

View File

@@ -18,13 +18,9 @@ import "@polymer/paper-input/paper-textarea";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import "../../../components/entity/ha-entity-toggle";
import "@material/mwc-button/mwc-button";
import "./trigger/ha-automation-trigger";
import "./condition/ha-automation-condition";
import "./action/ha-automation-action";
import { fireEvent } from "../../../common/dom/fire_event";
import { haStyle } from "../../../resources/styles";
import { HassEntity } from "home-assistant-js-websocket";
import { navigate } from "../../../common/navigate";
import {
BlueprintOrError,
Blueprints,
@@ -63,7 +59,7 @@ export class HaBlueprintAutomationEditor extends LitElement {
protected render() {
const blueprint = this._blueprint;
return html`<ha-config-section .isWide=${this.isWide}>
return html`<ha-config-section vertical .isWide=${this.isWide}>
${!this.narrow
? html` <span slot="header">${this.config.alias}</span> `
: ""}
@@ -119,7 +115,7 @@ export class HaBlueprintAutomationEditor extends LitElement {
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<ha-config-section vertical .isWide=${this.isWide}>
<span slot="header"
>${this.hass.localize(
"ui.panel.config.automation.editor.blueprint.header"
@@ -144,11 +140,6 @@ export class HaBlueprintAutomationEditor extends LitElement {
"ui.panel.config.automation.editor.blueprint.no_blueprints"
)
: html`<ha-circular-progress active></ha-circular-progress>`}
<mwc-button @click=${this._navigateBlueprints}>
${this.hass.localize(
"ui.panel.config.automation.editor.blueprint.manage_blueprints"
)}
</mwc-button>
</div>
${this.config.use_blueprint.path
@@ -157,41 +148,37 @@ export class HaBlueprintAutomationEditor extends LitElement {
There is an error in this Blueprint: ${blueprint.error}
</p>`
: html`${blueprint?.metadata.description
? html`<p>${blueprint.metadata.description}</p>`
? html`<p class="card-content pre-line">
${blueprint.metadata.description}
</p>`
: ""}
${blueprint?.metadata?.input &&
Object.keys(blueprint.metadata.input).length
? html`<h3>
${this.hass.localize(
"ui.panel.config.automation.editor.blueprint.inputs"
)}
</h3>
${Object.entries(blueprint.metadata.input).map(
([key, value]) =>
html`<ha-settings-row .narrow=${this.narrow}>
<span slot="heading">${value?.name || key}</span>
<span slot="description"
>${value?.description}</span
>
${value?.selector
? html`<ha-selector
.hass=${this.hass}
.selector=${value.selector}
.key=${key}
.value=${(this.config.use_blueprint.input &&
this.config.use_blueprint.input[key]) ||
value?.default}
@value-changed=${this._inputChanged}
></ha-selector>`
: html`<paper-input
.key=${key}
.value=${this.config.use_blueprint.input &&
this.config.use_blueprint.input[key]}
@value-changed=${this._inputChanged}
no-label-float
></paper-input>`}
</ha-settings-row>`
)}`
? Object.entries(blueprint.metadata.input).map(
([key, value]) =>
html`<ha-settings-row .narrow=${this.narrow}>
<span slot="heading">${value?.name || key}</span>
<span slot="description">${value?.description}</span>
${value?.selector
? html`<ha-selector
.hass=${this.hass}
.selector=${value.selector}
.key=${key}
.value=${(this.config.use_blueprint.input &&
this.config.use_blueprint.input[key]) ||
value?.default}
@value-changed=${this._inputChanged}
></ha-selector>`
: html`<paper-input
.key=${key}
required
.value=${this.config.use_blueprint.input &&
this.config.use_blueprint.input[key]}
@value-changed=${this._inputChanged}
no-label-float
></paper-input>`}
</ha-settings-row>`
)
: html`<p class="padding">
${this.hass.localize(
"ui.panel.config.automation.editor.blueprint.no_inputs"
@@ -237,12 +224,18 @@ export class HaBlueprintAutomationEditor extends LitElement {
) {
return;
}
const input = { ...this.config.use_blueprint.input, [key]: value };
if (value === "" || value === undefined) {
delete input[key];
}
fireEvent(this, "value-changed", {
value: {
...this.config!,
use_blueprint: {
...this.config.use_blueprint,
input: { ...this.config.use_blueprint.input, [key]: value },
input,
},
},
});
@@ -267,25 +260,18 @@ export class HaBlueprintAutomationEditor extends LitElement {
});
}
private _navigateBlueprints() {
navigate(this, "/config/blueprint");
}
static get styles(): CSSResult[] {
return [
haStyle,
css`
ha-card {
overflow: hidden;
}
.padding {
padding: 16px;
}
.pre-line {
white-space: pre-line;
}
.blueprint-picker-container {
padding: 16px;
display: flex;
align-items: center;
justify-content: space-between;
}
h3 {
margin: 16px;
@@ -304,10 +290,10 @@ export class HaBlueprintAutomationEditor extends LitElement {
border-top: 1px solid var(--divider-color);
}
:host(:not([narrow])) ha-settings-row paper-input {
width: 50%;
width: 60%;
}
:host(:not([narrow])) ha-settings-row ha-selector {
width: 50%;
width: 60%;
}
`,
];

View File

@@ -32,6 +32,7 @@ import "../../../components/ha-svg-icon";
import "../../../components/ha-yaml-editor";
import { showToast } from "../../../util/toast";
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
import { copyToClipboard } from "../../../common/util/copy-clipboard";
import {
AutomationConfig,
AutomationEntity,
@@ -206,6 +207,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
? html`<blueprint-automation-editor
.hass=${this.hass}
.narrow=${this.narrow}
.isWide=${this.isWide}
.stateObj=${stateObj}
.config=${this._config}
@value-changed=${this._valueChanged}
@@ -213,6 +215,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
: html`<manual-automation-editor
.hass=${this.hass}
.narrow=${this.narrow}
.isWide=${this.isWide}
.stateObj=${stateObj}
.config=${this._config}
@value-changed=${this._valueChanged}
@@ -394,7 +397,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
private async _copyYaml() {
if (this._editor?.yaml) {
navigator.clipboard.writeText(this._editor.yaml);
copyToClipboard(this._editor.yaml);
}
}

View File

@@ -12,6 +12,7 @@ import {
internalProperty,
query,
TemplateResult,
css,
} from "lit-element";
import "../../../components/ha-dialog";
import { haStyleDialog } from "../../../resources/styles";
@@ -73,7 +74,9 @@ class DialogImportBlueprint extends LitElement {
this._result.blueprint.metadata.domain
)}
<br />
${this._result.blueprint.metadata.description}
<p class="pre-line">
${this._result.blueprint.metadata.description}
</p>
${this._result.validation_errors
? html`
<p class="error">
@@ -104,7 +107,16 @@ class DialogImportBlueprint extends LitElement {
<pre>${this._result.raw_data}</pre>
</ha-expansion-panel>`
: html`${this.hass.localize(
"ui.panel.config.blueprint.add.import_introduction"
"ui.panel.config.blueprint.add.import_introduction_link",
"community_link",
html`<a
href="https://www.home-assistant.io/get-blueprints"
target="_blank"
rel="noreferrer noopener"
>${this.hass.localize(
"ui.panel.config.blueprint.add.community_forums"
)}</a
>`
)}<paper-input
id="input"
.label=${this.hass.localize(
@@ -199,8 +211,15 @@ class DialogImportBlueprint extends LitElement {
}
}
static get styles(): CSSResult {
return haStyleDialog;
static get styles(): CSSResult[] {
return [
haStyleDialog,
css`
.pre-line {
white-space: pre-line;
}
`,
];
}
}

View File

@@ -1,6 +1,6 @@
import "../../../components/ha-fab";
import "@material/mwc-icon-button";
import { mdiPlus, mdiHelpCircle, mdiDelete, mdiRobot } from "@mdi/js";
import { mdiHelpCircle, mdiDelete, mdiRobot, mdiDownload } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip";
import {
CSSResult,
@@ -112,7 +112,6 @@ class HaBlueprintOverview extends LitElement {
create: {
title: "",
type: narrow ? "icon-button" : undefined,
width: narrow ? undefined : "180px",
template: (_, blueprint: any) =>
blueprint.error
? ""
@@ -126,8 +125,9 @@ class HaBlueprintOverview extends LitElement {
"ui.panel.config.blueprint.overview.use_blueprint"
)}
@click=${(ev) => this._createNew(ev)}
><ha-svg-icon .path=${mdiRobot}></ha-svg-icon
></mwc-icon-button>`
>
<ha-svg-icon .path=${mdiRobot}></ha-svg-icon>
</mwc-icon-button>`
: html`<mwc-button
.blueprint=${blueprint}
@click=${(ev) => this._createNew(ev)}
@@ -170,6 +170,23 @@ class HaBlueprintOverview extends LitElement {
"ui.panel.config.blueprint.overview.no_blueprints"
)}
hasFab
.appendRow=${html` <div
class="mdc-data-table__cell"
style="width: 100%; text-align: center;"
role="cell"
>
<a
href="https://www.home-assistant.io/get-blueprints"
target="_blank"
rel="noreferrer noopener"
>
<mwc-button
>${this.hass.localize(
"ui.panel.config.blueprint.overview.discover_more"
)}</mwc-button
>
</a>
</div>`}
>
<mwc-icon-button slot="toolbar-icon" @click=${this._showHelp}>
<ha-svg-icon .path=${mdiHelpCircle}></ha-svg-icon>
@@ -182,7 +199,7 @@ class HaBlueprintOverview extends LitElement {
extended
@click=${this._addBlueprint}
>
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDownload}></ha-svg-icon>
</ha-fab>
</hass-tabs-subpage-data-table>
`;
@@ -195,7 +212,10 @@ class HaBlueprintOverview extends LitElement {
${this.hass.localize("ui.panel.config.blueprint.overview.introduction")}
<p>
<a
href="${documentationUrl(this.hass, "/docs/blueprint/editor/")}"
href="${documentationUrl(
this.hass,
"/docs/automation/using_blueprints/"
)}"
target="_blank"
rel="noreferrer"
>

View File

@@ -92,7 +92,7 @@ class HaConfigCustomize extends LocalizeMixin(PolymerElement) {
}
_computeTabs() {
return configSections.general;
return configSections.advanced;
}
computeEntities(hass) {

View File

@@ -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<LovelaceRow | HuiErrorCard> = [];
@@ -68,7 +67,7 @@ export class HaDeviceEntitiesCard extends LitElement {
})}
</div>
${disabledEntities.length
? !this._showDisabled
? !this.showDisabled
? html`
<button
class="show-more"
@@ -119,7 +118,7 @@ export class HaDeviceEntitiesCard extends LitElement {
}
private _toggleShowDisabled() {
this._showDisabled = !this._showDisabled;
this.showDisabled = !this.showDisabled;
}
private _renderEntity(entry: EntityRegistryStateEntry): TemplateResult {
@@ -227,3 +226,9 @@ export class HaDeviceEntitiesCard extends LitElement {
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-device-entities-card": HaDeviceEntitiesCard;
}
}

View File

@@ -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}
></ha-area-picker>
<div class="row">
<ha-switch
.checked=${!this._disabledBy}
@change=${this._disabledByChanged}
>
</ha-switch>
<div>
<div>
${this.hass.localize("ui.panel.config.devices.enabled_label")}
</div>
<div class="secondary">
${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"
)}
</div>
</div>
</div>
</div>
</div>
<mwc-button
@@ -109,12 +139,17 @@ class DialogDeviceRegistryDetail extends LitElement {
this._areaId = event.detail.value;
}
private _disabledByChanged(ev: Event): void {
this._disabledBy = (ev.target as HaSwitch).checked ? null : "user";
}
private async _updateEntry(): Promise<void> {
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;
}
`,
];
}

View File

@@ -46,6 +46,7 @@ import "./device-detail/ha-device-entities-card";
import "./device-detail/ha-device-info-card";
import { showDeviceAutomationDialog } from "./device-detail/show-dialog-device-automation";
import { brandsUrl } from "../../../util/brands-url";
import { haStyle } from "../../../resources/styles";
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
stateName?: string | null;
@@ -246,6 +247,28 @@ export class HaConfigDevicePage extends LitElement {
.devices=${this.devices}
.device=${device}
>
${
device.disabled_by
? html`
<div>
<p class="warning">
${this.hass.localize(
"ui.panel.config.devices.enabled_cause",
"cause",
this.hass.localize(
`ui.panel.config.devices.disabled_by.${device.disabled_by}`
)
)}
</p>
</div>
<div class="card-actions" slot="actions">
<mwc-button unelevated @click=${this._enableDevice}>
${this.hass.localize("ui.common.enable")}
</mwc-button>
</div>
`
: html``
}
${this._renderIntegrationInfo(device, integrations)}
</ha-device-info-card>
@@ -255,6 +278,7 @@ export class HaConfigDevicePage extends LitElement {
<ha-device-entities-card
.hass=${this.hass}
.entities=${entities}
.showDisabled=${device.disabled_by !== null}
>
</ha-device-entities-card>
`
@@ -272,9 +296,14 @@ export class HaConfigDevicePage extends LitElement {
)}
<ha-icon-button
@click=${this._showAutomationDialog}
title=${this.hass.localize(
"ui.panel.config.devices.automation.create"
)}
.disabled=${device.disabled_by}
title=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.automation.create_disabled"
)
: this.hass.localize(
"ui.panel.config.devices.automation.create"
)}
icon="hass:plus-circle"
></ha-icon-button>
</h1>
@@ -342,9 +371,16 @@ export class HaConfigDevicePage extends LitElement {
<ha-icon-button
@click=${this._createScene}
title=${this.hass.localize(
"ui.panel.config.devices.scene.create"
)}
.disabled=${device.disabled_by}
title=${
device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.scene.create_disabled"
)
: this.hass.localize(
"ui.panel.config.devices.scene.create"
)
}
icon="hass:plus-circle"
></ha-icon-button>
</h1>
@@ -415,9 +451,14 @@ export class HaConfigDevicePage extends LitElement {
)}
<ha-icon-button
@click=${this._showScriptDialog}
title=${this.hass.localize(
"ui.panel.config.devices.script.create"
)}
.disabled=${device.disabled_by}
title=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.script.create_disabled"
)
: this.hass.localize(
"ui.panel.config.devices.script.create"
)}
icon="hass:plus-circle"
></ha-icon-button>
</h1>
@@ -632,128 +673,137 @@ export class HaConfigDevicePage extends LitElement {
});
}
static get styles(): CSSResult {
return css`
.container {
display: flex;
flex-wrap: wrap;
margin: auto;
max-width: 1000px;
margin-top: 32px;
margin-bottom: 32px;
}
private async _enableDevice(): Promise<void> {
await updateDeviceRegistryEntry(this.hass, this.deviceId, {
disabled_by: null,
});
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
}
static get styles(): CSSResult[] {
return [
haStyle,
css`
.container {
display: flex;
flex-wrap: wrap;
margin: auto;
max-width: 1000px;
margin-top: 32px;
margin-bottom: 32px;
}
.card-header ha-icon-button {
margin-right: -8px;
color: var(--primary-color);
height: auto;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.device-info {
padding: 16px;
}
.card-header ha-icon-button {
margin-right: -8px;
color: var(--primary-color);
height: auto;
}
.show-more {
}
.device-info {
padding: 16px;
}
h1 {
margin: 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);
}
.show-more {
}
.header {
display: flex;
justify-content: space-between;
}
h1 {
margin: 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);
}
.column,
.fullwidth {
padding: 8px;
box-sizing: border-box;
}
.column {
width: 33%;
flex-grow: 1;
}
.fullwidth {
width: 100%;
flex-grow: 1;
}
.header {
display: flex;
justify-content: space-between;
}
.header-right {
align-self: center;
}
.column,
.fullwidth {
padding: 8px;
box-sizing: border-box;
}
.column {
width: 33%;
flex-grow: 1;
}
.fullwidth {
width: 100%;
flex-grow: 1;
}
.header-right img {
height: 30px;
}
.header-right {
align-self: center;
}
.header-right {
display: flex;
}
.header-right img {
height: 30px;
}
.header-right:first-child {
width: 100%;
justify-content: flex-end;
}
.header-right {
display: flex;
}
.header-right > *:not(:first-child) {
margin-left: 16px;
}
.header-right:first-child {
width: 100%;
justify-content: flex-end;
}
.battery {
align-self: center;
align-items: center;
display: flex;
}
.header-right > *:not(:first-child) {
margin-left: 16px;
}
.column > *:not(:first-child) {
margin-top: 16px;
}
.battery {
align-self: center;
align-items: center;
display: flex;
}
:host([narrow]) .column {
width: 100%;
}
.column > *:not(:first-child) {
margin-top: 16px;
}
:host([narrow]) .container {
margin-top: 0;
}
:host([narrow]) .column {
width: 100%;
}
paper-item {
cursor: pointer;
font-size: var(--paper-font-body1_-_font-size);
}
:host([narrow]) .container {
margin-top: 0;
}
paper-item.no-link {
cursor: default;
}
paper-item {
cursor: pointer;
font-size: var(--paper-font-body1_-_font-size);
}
a {
text-decoration: none;
color: var(--primary-color);
}
paper-item.no-link {
cursor: default;
}
ha-card {
padding-bottom: 8px;
}
a {
text-decoration: none;
color: var(--primary-color);
}
ha-card a {
color: var(--primary-text-color);
}
`;
ha-card {
padding-bottom: 8px;
}
ha-card a {
color: var(--primary-text-color);
}
`,
];
}
}

View File

@@ -1,5 +1,9 @@
import { mdiPlus } from "@mdi/js";
import { mdiPlus, mdiFilterVariant, mdiCancel } from "@mdi/js";
import "@material/mwc-list/mwc-list-item";
import "@polymer/paper-tooltip/paper-tooltip";
import {
css,
CSSResult,
customElement,
html,
internalProperty,
@@ -7,7 +11,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 +24,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 +41,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 +72,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 +88,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 +123,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 +136,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 +167,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 +175,10 @@ export class HaConfigDeviceDashboard extends LitElement {
}
});
if (!showDisabled) {
outputDevices = outputDevices.filter((device) => !device.disabled_by);
}
outputDevices = outputDevices.map((device) => {
return {
...device,
@@ -162,9 +189,7 @@ export class HaConfigDeviceDashboard extends LitElement {
),
model: device.model || "<unknown>",
manufacturer: device.manufacturer || "<unknown>",
area: device.area_id
? areaLookup[device.area_id].name
: this.hass.localize("ui.panel.config.devices.data_table.no_area"),
area: device.area_id ? areaLookup[device.area_id].name : undefined,
integration: device.config_entries.length
? device.config_entries
.filter((entId) => entId in entryLookup)
@@ -182,16 +207,19 @@ export class HaConfigDeviceDashboard extends LitElement {
};
});
this._numHiddenDevices = startLength - outputDevices.length;
return { devicesOutput: outputDevices, filteredDomains: filterDomains };
}
);
private _columns = memoizeOne(
(narrow: boolean): DataTableColumnContainer => {
(narrow: boolean, showDisabled: boolean): DataTableColumnContainer => {
const columns: DataTableColumnContainer = narrow
? {
name: {
title: "Device",
title: this.hass.localize(
"ui.panel.config.devices.data_table.device"
),
sortable: true,
filterable: true,
direction: "asc",
@@ -277,6 +305,24 @@ export class HaConfigDeviceDashboard extends LitElement {
: html` - `;
},
};
if (showDisabled) {
columns.disabled_by = {
title: "",
type: "icon",
template: (disabled_by) =>
disabled_by
? html`<div
tabindex="0"
style="display:inline-block; position: relative;"
>
<ha-svg-icon .path=${mdiCancel}></ha-svg-icon>
<paper-tooltip animation-delay="0" position="left">
${this.hass.localize("ui.panel.config.devices.disabled")}
</paper-tooltip>
</div>`
: "",
};
}
return columns;
}
);
@@ -298,9 +344,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`
<search-input
no-label-float
no-underline
@value-changed=${this._handleSearchChange}
.filter=${this._filter}
.label=${this.hass.localize("ui.panel.config.devices.picker.search")}
></search-input
>${activeFilters
? html`<div class="active-filters">
${this.narrow
? html` <div>
<ha-icon icon="hass:filter-variant"></ha-icon>
<paper-tooltip animation-delay="0" position="left">
${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
) +
")"
: ""}
</paper-tooltip>
</div>`
: `${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
) +
")"
: ""
}
`}
<mwc-button @click=${this._clearFilter}
>${this.hass.localize(
"ui.panel.config.filtering.clear"
)}</mwc-button
>
</div>`
: ""}
${this._numHiddenDevices && !activeFilters
? html`<div class="active-filters">
${this.narrow
? html` <div>
<ha-icon icon="hass:filter-variant"></ha-icon>
<paper-tooltip animation-delay="0" position="left">
${this.hass.localize(
"ui.panel.config.devices.picker.filter.hidden_devices",
"number",
this._numHiddenDevices
)}
</paper-tooltip>
</div>`
: `${this.hass.localize(
"ui.panel.config.devices.picker.filter.hidden_devices",
"number",
this._numHiddenDevices
)}`}
<mwc-button @click=${this._showAll}
>${this.hass.localize(
"ui.panel.config.devices.picker.filter.show_all"
)}</mwc-button
>
</div>`
: ""}
<ha-button-menu corner="BOTTOM_START" multi>
<mwc-icon-button
slot="trigger"
.label=${this.hass!.localize(
"ui.panel.config.devices.picker.filter.filter"
)}
.title=${this.hass!.localize(
"ui.panel.config.devices.picker.filter.filter"
)}
>
<ha-svg-icon .path=${mdiFilterVariant}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item
@request-selected="${this._showDisabledChanged}"
graphic="control"
.selected=${this._showDisabled}
>
<ha-checkbox
slot="graphic"
.checked=${this._showDisabled}
></ha-checkbox>
${this.hass!.localize(
"ui.panel.config.devices.picker.filter.show_disabled"
)}
</mwc-list-item>
</ha-button-menu>
`;
return html`
<hass-tabs-subpage-data-table
@@ -311,13 +467,9 @@ export class HaConfigDeviceDashboard extends LitElement {
: "/config"}
.tabs=${configSections.integrations}
.route=${this.route}
.columns=${this._columns(this.narrow)}
.columns=${this._columns(this.narrow, this._showDisabled)}
.data=${devicesOutput}
.activeFilters=${this._activeFilters(
this.entries,
this._searchParms,
this.hass.localize
)}
.filter=${this._filter}
@row-click=${this._handleRowClicked}
clickable
.hasFab=${includeZHAFab}
@@ -333,6 +485,15 @@ export class HaConfigDeviceDashboard extends LitElement {
</ha-fab>
</a>`
: html``}
<div
class=${classMap({
"search-toolbar": this.narrow,
"table-header": !this.narrow,
})}
slot="header"
>
${headerToolbar}
</div>
</hass-tabs-subpage-data-table>
`;
}
@@ -363,6 +524,136 @@ export class HaConfigDeviceDashboard extends LitElement {
const deviceId = ev.detail.id;
navigate(this, `/config/devices/device/${deviceId}`);
}
private _showDisabledChanged(ev: CustomEvent<RequestSelectedDetail>) {
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 {

View File

@@ -111,10 +111,19 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
return html`
${!stateObj
? html`
<div class="container">
<div class="container warning">
${this.hass!.localize(
"ui.dialogs.entity_registry.editor.unavailable"
)}
${this._device?.disabled_by
? html`<br />${this.hass!.localize(
"ui.dialogs.entity_registry.editor.device_disabled"
)}<br /><mwc-button @click=${this._openDeviceSettings}>
${this.hass!.localize(
"ui.dialogs.entity_registry.editor.open_device_settings"
)}
</mwc-button>`
: ""}
</div>
`
: ""}
@@ -161,6 +170,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
<div class="row">
<ha-switch
.checked=${!this._disabledBy}
.disabled=${this._device?.disabled_by}
@change=${this._disabledByChanged}
>
</ha-switch>

View File

@@ -189,9 +189,11 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
? (name, entity: any) =>
html`
${name}<br />
${entity.entity_id} |
${this.hass.localize(`component.${entity.platform}.title`) ||
entity.platform}
<div class="secondary">
${entity.entity_id} |
${this.hass.localize(`component.${entity.platform}.title`) ||
entity.platform}
</div>
`
: undefined,
},

View File

@@ -5,6 +5,8 @@ import { classMap } from "lit-html/directives/class-map";
export class HaConfigSection extends LitElement {
@property() public isWide = false;
@property({ type: Boolean }) public vertical = false;
protected render() {
return html`
<div
@@ -16,8 +18,8 @@ export class HaConfigSection extends LitElement {
<div
class="together layout ${classMap({
narrow: !this.isWide,
vertical: !this.isWide,
horizontal: this.isWide,
vertical: this.vertical || !this.isWide,
horizontal: !this.vertical && this.isWide,
})}"
>
<div class="intro"><slot name="introduction"></slot></div>

View File

@@ -148,7 +148,7 @@ export class HaConfigHelpers extends LitElement {
.narrow=${this.narrow}
back-path="/config"
.route=${this.route}
.tabs=${configSections.automation}
.tabs=${configSections.helpers}
.columns=${this._columns(this.narrow, this.hass.language)}
.data=${this._getItems(this._stateItems)}
@row-click=${this._openEditDialog}

View File

@@ -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;
}

View File

@@ -35,6 +35,7 @@ import "../../../components/ha-icon-input";
import "../../../components/ha-svg-icon";
import "../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
import { copyToClipboard } from "../../../common/util/copy-clipboard";
import {
Action,
deleteScript,
@@ -545,7 +546,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
private async _copyYaml() {
if (this._editor?.yaml) {
navigator.clipboard.writeText(this._editor.yaml);
copyToClipboard(this._editor.yaml);
}
}

View File

@@ -84,7 +84,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
${tag.last_scanned_datetime
? html`<ha-relative-time
.hass=${this.hass}
.datetimeObj=${tag.last_scanned_datetime}
.datetime=${tag.last_scanned_datetime}
></ha-relative-time>`
: this.hass.localize("ui.panel.config.tags.never_scanned")}
</div>`
@@ -103,7 +103,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
${last_scanned_datetime
? html`<ha-relative-time
.hass=${this.hass}
.datetimeObj=${last_scanned_datetime}
.datetime=${last_scanned_datetime}
></ha-relative-time>`
: this.hass.localize("ui.panel.config.tags.never_scanned")}
`,

View File

@@ -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;
}

View File

@@ -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 {
</span>
`
: ""}
${user.is_active
? html`
<span class="state"
>${this.hass.localize(
"ui.panel.config.users.editor.active"
)}</span
>
`
: ""}
</div>
<div class="form">
<paper-input
@@ -110,17 +105,21 @@ class DialogUserDetail extends LitElement {
"ui.panel.config.users.editor.name"
)}"
></paper-input>
<ha-formfield
.label=${this.hass.localize("ui.panel.config.users.editor.admin")}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
<div class="row">
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.users.editor.admin"
)}
.dir=${computeRTLDirection(this.hass)}
>
</ha-switch>
</ha-formfield>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-formfield>
</div>
${!this._isAdmin
? html`
<br />
@@ -129,6 +128,27 @@ class DialogUserDetail extends LitElement {
)}
`
: ""}
<div class="row">
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.users.editor.active"
)}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isActive}
@change=${this._activeChanged}
>
</ha-switch>
</ha-formfield>
<ha-help-tooltip
.label=${this.hass.localize(
"ui.panel.config.users.editor.active_tooltip"
)}
>
</ha-help-tooltip>
</div>
</div>
</div>
@@ -192,11 +212,16 @@ class DialogUserDetail extends LitElement {
this._isAdmin = ev.target.checked;
}
private async _activeChanged(ev): Promise<void> {
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;
}
`,
];

View File

@@ -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}<br />
<div class="secondary">
${user.username} |
${this.hass.localize(`groups.${user.group_ids[0]}`)}
</div>`
: 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`<ha-icon icon="hass:check"> </ha-icon>` : "",
},
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`<ha-icon icon="hass:check"> </ha-icon>` : "",
};
}
},
};
return columns;
}
);

View File

@@ -84,9 +84,6 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
}
public setConfig(config: ButtonCardConfig): void {
if (!config.entity) {
throw new Error("Entity must be specified");
}
if (config.entity && !isValidEntityId(config.entity)) {
throw new Error("Invalid entity");
}

View File

@@ -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");
}

View File

@@ -2,7 +2,14 @@ import { customElement } from "lit-element";
import { HuiButtonCard } from "./hui-button-card";
@customElement("hui-entity-button-card")
class HuiEntityButtonCard extends HuiButtonCard {}
class HuiEntityButtonCard extends HuiButtonCard {
public setConfig(config): void {
if (!config.entity) {
throw new Error("Entity must be specified");
}
super.setConfig(config);
}
}
declare global {
interface HTMLElementTagNameMap {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -246,78 +246,73 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
${!isUnavailable &&
(mediaDescription || stateObj.attributes.media_title || showControls)
? html`
<div
class="title-controls"
style=${styleMap({
paddingRight: isOffState
? "0"
: `${this._cardHeight - 40}px`,
})}
>
${!mediaDescription && !stateObj.attributes.media_title
? ""
: html`
<div class="media-info">
<hui-marquee
.text=${stateObj.attributes.media_title ||
mediaDescription}
.active=${this._marqueeActive}
@mouseover=${this._marqueeMouseOver}
@mouseleave=${this._marqueeMouseLeave}
></hui-marquee>
${!stateObj.attributes.media_title
? ""
: mediaDescription}
</div>
`}
${!showControls
? ""
: html`
<div class="controls">
${controls!.map(
(control) => html`
<ha-icon-button
.title=${this.hass.localize(
`ui.card.media_player.${control.action}`
)}
.icon=${control.icon}
action=${control.action}
@click=${this._handleClick}
></ha-icon-button>
`
)}
${supportsFeature(stateObj, SUPPORT_BROWSE_MEDIA)
? html`
<mwc-icon-button
class="browse-media"
<div>
<div class="title-controls">
${!mediaDescription && !stateObj.attributes.media_title
? ""
: html`
<div class="media-info">
<hui-marquee
.text=${stateObj.attributes.media_title ||
mediaDescription}
.active=${this._marqueeActive}
@mouseover=${this._marqueeMouseOver}
@mouseleave=${this._marqueeMouseLeave}
></hui-marquee>
${!stateObj.attributes.media_title
? ""
: mediaDescription}
</div>
`}
${!showControls
? ""
: html`
<div class="controls">
${controls!.map(
(control) => html`
<ha-icon-button
.title=${this.hass.localize(
"ui.card.media_player.browse_media"
`ui.card.media_player.${control.action}`
)}
@click=${this._handleBrowseMedia}
><ha-svg-icon
.path=${mdiPlayBoxMultiple}
></ha-svg-icon
></mwc-icon-button>
.icon=${control.icon}
action=${control.action}
@click=${this._handleClick}
></ha-icon-button>
`
: ""}
</div>
)}
${supportsFeature(stateObj, SUPPORT_BROWSE_MEDIA)
? html`
<mwc-icon-button
class="browse-media"
.title=${this.hass.localize(
"ui.card.media_player.browse_media"
)}
@click=${this._handleBrowseMedia}
><ha-svg-icon
.path=${mdiPlayBoxMultiple}
></ha-svg-icon
></mwc-icon-button>
`
: ""}
</div>
`}
</div>
${!this._showProgressBar
? ""
: html`
<paper-progress
.max=${stateObj.attributes.media_duration}
style=${styleMap({
"--paper-progress-active-color":
this._foregroundColor || "var(--accent-color)",
cursor: supportsFeature(stateObj, SUPPORT_SEEK)
? "pointer"
: "initial",
})}
@click=${this._handleSeek}
></paper-progress>
`}
</div>
${!this._showProgressBar
? ""
: html`
<paper-progress
.max=${stateObj.attributes.media_duration}
style=${styleMap({
"--paper-progress-active-color":
this._foregroundColor || "var(--accent-color)",
cursor: supportsFeature(stateObj, SUPPORT_SEEK)
? "pointer"
: "initial",
})}
@click=${this._handleSeek}
></paper-progress>
`}
`
: ""}
</div>
@@ -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 {

View File

@@ -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;

View File

@@ -1,7 +1,8 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import "@material/mwc-icon-button";
import "../../../components/ha-button-menu";
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import "@material/mwc-list/mwc-list-item";
import { mdiArrowDown, mdiArrowUp, mdiDotsVertical } from "@mdi/js";
import {
css,
CSSResult,
@@ -9,21 +10,20 @@ import {
html,
LitElement,
property,
TemplateResult,
queryAssignedNodes,
TemplateResult,
} from "lit-element";
import { HomeAssistant } from "../../../types";
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
import { swapCard, moveCard, addCard, deleteCard } from "../editor/config-util";
import { confDeleteCard } from "../editor/delete-card";
import { Lovelace, LovelaceCard } from "../types";
import { computeCardSize } from "../common/compute-card-size";
import { mdiDotsVertical, mdiArrowDown, mdiArrowUp } from "@mdi/js";
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import { showSelectViewDialog } from "../editor/select-view/show-select-view-dialog";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-button-menu";
import { saveConfig } from "../../../data/lovelace";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { HomeAssistant } from "../../../types";
import { showSaveSuccessToast } from "../../../util/toast-saved-success";
import { computeCardSize } from "../common/compute-card-size";
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
import { addCard, deleteCard, moveCard, swapCard } from "../editor/config-util";
import { showSelectViewDialog } from "../editor/select-view/show-select-view-dialog";
import { Lovelace, LovelaceCard } from "../types";
@customElement("hui-card-options")
export class HuiCardOptions extends LitElement {
@@ -168,11 +168,7 @@ export class HuiCardOptions extends LitElement {
}
private _editCard(): void {
showEditCardDialog(this, {
lovelaceConfig: this.lovelace!.config,
saveConfig: this.lovelace!.saveConfig,
path: this.path!,
});
fireEvent(this, "ll-edit-card", { path: this.path! });
}
private _cardUp(): void {
@@ -229,7 +225,7 @@ export class HuiCardOptions extends LitElement {
}
private _deleteCard(): void {
confDeleteCard(this, this.hass!, this.lovelace!, this.path!);
fireEvent(this, "ll-delete-card", { path: this.path! });
}
}

View File

@@ -72,7 +72,7 @@ class HuiMarquee extends LitElement {
display: flex;
position: relative;
align-items: center;
height: 1em;
height: 1.2em;
contain: strict;
}

View File

@@ -59,6 +59,9 @@ export class HuiThemeSelectEditor extends LitElement {
paper-dropdown-menu {
width: 100%;
}
paper-item {
cursor: pointer;
}
`;
}

View File

@@ -353,11 +353,9 @@ 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, 4px);
background: var(--primary-background-color, #fafafa);
cursor: pointer;
box-sizing: border-box;
position: relative;
}
@@ -375,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);
}
@@ -408,6 +405,10 @@ export class HuiCardPicker extends LitElement {
width: 100%;
height: 100%;
z-index: 1;
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 {

View File

@@ -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%;

View File

@@ -8,7 +8,7 @@ export interface CreateCardDialogParams {
entities?: string[]; // We can pass entity id's that will be added to the config when a card is picked
}
const importCreateCardDialog = () => import("./hui-dialog-create-card");
export const importCreateCardDialog = () => import("./hui-dialog-create-card");
export const showCreateCardDialog = (
element: HTMLElement,

View File

@@ -6,7 +6,7 @@ export interface DeleteCardDialogParams {
cardConfig?: LovelaceCardConfig;
}
const importDeleteCardDialog = () => import("./hui-dialog-delete-card");
export const importDeleteCardDialog = () => import("./hui-dialog-delete-card");
export const showDeleteCardDialog = (
element: HTMLElement,

View File

@@ -8,7 +8,7 @@ export interface EditCardDialogParams {
cardConfig?: LovelaceCardConfig;
}
const importEditCardDialog = () => import("./hui-dialog-edit-card");
export const importEditCardDialog = () => import("./hui-dialog-edit-card");
export const showEditCardDialog = (
element: HTMLElement,

View File

@@ -115,7 +115,7 @@ export class HuiButtonCardEditor extends LitElement
.label="${this.hass.localize(
"ui.panel.lovelace.editor.card.generic.entity"
)} (${this.hass.localize(
"ui.panel.lovelace.editor.card.config.required"
"ui.panel.lovelace.editor.card.config.optional"
)})"
.hass=${this.hass}
.value=${this._entity}

View File

@@ -173,8 +173,8 @@ class LovelaceFullConfigEditor extends LitElement {
text: this.hass.localize(
"ui.panel.lovelace.editor.raw_editor.confirm_unsaved_changes"
),
dismissText: this.hass!.localize("ui.common.leave"),
confirmText: this.hass!.localize("ui.common.stay"),
dismissText: this.hass!.localize("ui.common.stay"),
confirmText: this.hass!.localize("ui.common.leave"),
}))
) {
return;

View File

@@ -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)
);
}
`,
];
}

View File

@@ -1,3 +1,10 @@
// hui-view dependencies for when in edit mode.
import "../../../components/ha-fab";
import "../components/hui-card-options";
import { importCreateCardDialog } from "../editor/card-editor/show-create-card-dialog";
import { importDeleteCardDialog } from "../editor/card-editor/show-delete-card-dialog";
import { importEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
importCreateCardDialog();
importDeleteCardDialog();
importEditCardDialog();

View File

@@ -10,6 +10,7 @@ import {
TemplateResult,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeRTL } from "../../../common/util/compute_rtl";
import { nextRender } from "../../../common/util/render-status";
import "../../../components/entity/ha-state-label-badge";
@@ -21,7 +22,6 @@ import type {
import type { HomeAssistant } from "../../../types";
import type { HuiErrorCard } from "../cards/hui-error-card";
import { computeCardSize } from "../common/compute-card-size";
import { showCreateCardDialog } from "../editor/card-editor/show-create-card-dialog";
import type { Lovelace, LovelaceBadge, LovelaceCard } from "../types";
let editCodeLoaded = false;
@@ -148,11 +148,7 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
}
private _addCard(): void {
showCreateCardDialog(this, {
lovelaceConfig: this.lovelace!.config,
saveConfig: this.lovelace!.saveConfig,
path: [this.index!],
});
fireEvent(this, "ll-create-card");
}
private async _createColumns() {
@@ -293,7 +289,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 {

View File

@@ -20,11 +20,23 @@ import { processConfigEntities } from "../common/process-config-entities";
import { createBadgeElement } from "../create-element/create-badge-element";
import { createCardElement } from "../create-element/create-card-element";
import { createViewElement } from "../create-element/create-view-element";
import { showCreateCardDialog } from "../editor/card-editor/show-create-card-dialog";
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
import { confDeleteCard } from "../editor/delete-card";
import type { Lovelace, LovelaceBadge, LovelaceCard } from "../types";
const DEFAULT_VIEW_LAYOUT = "masonry";
const PANEL_VIEW_LAYOUT = "panel";
declare global {
// for fire event
interface HASSDomEvents {
"ll-create-card": undefined;
"ll-edit-card": { path: [number] | [number, number] };
"ll-delete-card": { path: [number] | [number, number] };
}
}
@customElement("hui-view")
export class HUIView extends UpdatingElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@@ -106,6 +118,23 @@ export class HUIView extends UpdatingElement {
if (configChanged && !this._layoutElement) {
this._layoutElement = createViewElement(viewConfig!);
this._layoutElement.addEventListener("ll-create-card", () => {
showCreateCardDialog(this, {
lovelaceConfig: this.lovelace!.config,
saveConfig: this.lovelace!.saveConfig,
path: [this.index!],
});
});
this._layoutElement.addEventListener("ll-edit-card", (ev) => {
showEditCardDialog(this, {
lovelaceConfig: this.lovelace!.config,
saveConfig: this.lovelace!.saveConfig,
path: ev.detail.path,
});
});
this._layoutElement.addEventListener("ll-delete-card", (ev) => {
confDeleteCard(this, this.hass!, this.lovelace!, ev.detail.path);
});
}
if (configChanged) {

View File

@@ -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`
<style include="ha-style">
.error {
color: red;
}
.status {
color: var(--primary-color);
}
.error,
.status {
position: absolute;
top: -4px;
}
.currentPassword {
margin-top: -4px;
}
</style>
<div>
<ha-card
header="[[localize('ui.panel.profile.change_password.header')]]"
>
<div class="card-content">
<template is="dom-if" if="[[_errorMsg]]">
<div class="error">[[_errorMsg]]</div>
</template>
<template is="dom-if" if="[[_statusMsg]]">
<div class="status">[[_statusMsg]]</div>
</template>
<paper-input
class="currentPassword"
label="[[localize('ui.panel.profile.change_password.current_password')]]"
type="password"
value="{{_currentPassword}}"
required
auto-validate
error-message="[[localize('ui.panel.profile.change_password.error_required')]]"
></paper-input>
<template is="dom-if" if="[[_currentPassword]]">
<paper-input
label="[[localize('ui.panel.profile.change_password.new_password')]]"
type="password"
value="{{_password1}}"
required
auto-validate
error-message="[[localize('ui.panel.profile.change_password.error_required')]]"
></paper-input>
<paper-input
label="[[localize('ui.panel.profile.change_password.confirm_new_password')]]"
type="password"
value="{{_password2}}"
required
auto-validate
error-message="[[localize('ui.panel.profile.change_password.error_required')]]"
></paper-input>
</template>
</div>
<div class="card-actions">
<template is="dom-if" if="[[_loading]]">
<div><ha-circular-progress active></ha-circular-progress></div>
</template>
<template is="dom-if" if="[[!_loading]]">
<mwc-button on-click="_changePassword"
>[[localize('ui.panel.profile.change_password.submit')]]</mwc-button
>
</template>
</div>
</ha-card>
</div>
`;
}
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);

View File

@@ -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`
<div>
<ha-card
.header=${this.hass.localize(
"ui.panel.profile.change_password.header"
)}
>
<div class="card-content">
${this._errorMsg
? html` <div class="error">${this._errorMsg}</div> `
: ""}
${this._statusMsg
? html` <div class="status">${this._statusMsg}</div> `
: ""}
<paper-input
id="currentPassword"
.label=${this.hass.localize(
"ui.panel.profile.change_password.current_password"
)}
type="password"
.value=${this._currentPassword}
@value-changed=${this._currentPasswordChanged}
required
></paper-input>
${this._currentPassword
? html` <paper-input
.label=${this.hass.localize(
"ui.panel.profile.change_password.new_password"
)}
name="password"
type="password"
.value=${this._password}
@value-changed=${this._newPasswordChanged}
required
auto-validate
></paper-input>
<paper-input
.label=${this.hass.localize(
"ui.panel.profile.change_password.confirm_new_password"
)}
name="passwordConfirm"
type="password"
.value=${this._passwordConfirm}
@value-changed=${this._newPasswordConfirmChanged}
required
auto-validate
></paper-input>`
: ""}
</div>
<div class="card-actions">
${this._loading
? html`<div>
<ha-circular-progress active></ha-circular-progress>
</div>`
: html`<mwc-button
@click=${this._changePassword}
.disabled=${!this._passwordConfirm}
>${this.hass.localize(
"ui.panel.profile.change_password.submit"
)}</mwc-button
>`}
</div>
</ha-card>
</div>
`;
}
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;
}
}

View File

@@ -25,7 +25,7 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
>[[localize('ui.panel.profile.push_notifications.header')]]</span
>
<span slot="description">
[[_description(_platformLoaded, _pushSupported)]]
[[localize(_descrLocalizeKey)]]
<a
href="[[_computeDocumentationUrl(hass)]]"
target="_blank"
@@ -45,6 +45,10 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
return {
hass: Object,
narrow: Boolean,
_descrLocalizeKey: {
type: String,
computed: "_descriptionKey(_platformLoaded, _pushSupported)",
},
_platformLoaded: {
type: Boolean,
computed: "_compPlatformLoaded(hass)",
@@ -72,7 +76,7 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
return !platformLoaded || !pushSupported_;
}
_description(platformLoaded, pushSupported_) {
_descriptionKey(platformLoaded, pushSupported_) {
let key;
if (!pushSupported_) {
key = "error_use_https";
@@ -81,7 +85,7 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
} else {
key = "description";
}
return this.localize(`ui.panel.profile.push_notifications.${key}`);
return `ui.panel.profile.push_notifications.${key}`;
}
}

View File

@@ -33,7 +33,8 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
duration: 0,
dismissable: false,
action: {
text: this.hass!.localize("ui.notification_toast.dismiss"),
text:
this.hass!.localize("ui.notification_toast.dismiss") || "Dismiss",
action: () => {},
},
});

View File

@@ -21,7 +21,8 @@ export const panelTitleMixin = <T extends Constructor<HassBaseEl>>(
if (
!oldHass ||
oldHass.panels !== this.hass.panels ||
oldHass.panelUrl !== this.hass.panelUrl
oldHass.panelUrl !== this.hass.panelUrl ||
oldHass.localize !== this.hass.localize
) {
setTitle(getPanelTitle(this.hass));
}

View File

@@ -36,6 +36,8 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
// eslint-disable-next-line: variable-name
private __coreProgress?: string;
private __loadedFragmetTranslations: Set<string> = new Set();
private __loadedTranslations: {
// track what things have been loaded
[category: string]: LoadedTranslationCategory;
@@ -101,6 +103,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
document.querySelector("html")!.setAttribute("lang", hass.language);
this.style.direction = computeRTL(hass) ? "rtl" : "ltr";
this._loadCoreTranslations(hass.language);
this.__loadedFragmetTranslations = new Set();
this._loadFragmentTranslations(hass.language, hass.panelUrl);
}
@@ -195,10 +198,31 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
language: string,
panelUrl: string
) {
if (translationMetadata.fragments.includes(panelUrl)) {
const result = await getTranslation(panelUrl, language);
this._updateResources(result.language, result.data);
if (!panelUrl) {
return;
}
const panelComponent = this.hass?.panels?.[panelUrl]?.component_name;
// If it's the first call we don't have panel info yet to check the component.
// If the url is not known it might be a custom lovelace dashboard, so we load lovelace translations
const fragment = translationMetadata.fragments.includes(
panelComponent || panelUrl
)
? panelComponent || panelUrl
: !panelComponent
? "lovelace"
: undefined;
if (!fragment) {
return;
}
if (this.__loadedFragmetTranslations.has(fragment)) {
return;
}
this.__loadedFragmetTranslations.add(fragment);
const result = await getTranslation(fragment, language);
this._updateResources(result.language, result.data);
}
private async _loadCoreTranslations(language: string) {
@@ -210,7 +234,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
this.__coreProgress = language;
try {
const result = await getTranslation(null, language);
this._updateResources(result.language, result.data);
await this._updateResources(result.language, result.data);
} finally {
this.__coreProgress = undefined;
}
@@ -226,18 +250,29 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
// before this.hass is even created. In this case our base state comes
// from this._pendingHass instead. Otherwise the first set of strings is
// overwritten when we call _updateHass the second time!
const baseHass = this.hass ?? this._pendingHass;
// Allow hass to be updated
await new Promise((resolve) => setTimeout(resolve, 0));
if (language !== (this.hass ?? this._pendingHass).language) {
// the language was changed, abort
return;
}
const resources = {
[language]: {
...baseHass?.resources?.[language],
...(this.hass ?? this._pendingHass)?.resources?.[language],
...data,
},
};
const changes: Partial<HomeAssistant> = { resources };
if (this.hass && language === this.hass.language) {
changes.localize = await computeLocalize(this, language, resources);
const changes: Partial<HomeAssistant> = {
resources,
localize: await computeLocalize(this, language, resources),
};
if (language === (this.hass ?? this._pendingHass).language) {
this._updateHass(changes);
}
this._updateHass(changes);
}
private _refetchCachedHassTranslations(

View File

@@ -98,7 +98,8 @@
"disabled_by": {
"user": "User",
"integration": "Integration",
"config_entry": "Config Entry"
"config_entry": "Config Entry",
"device": "Device"
}
},
"ui": {
@@ -327,6 +328,7 @@
"entity-picker": {
"entity": "Entity",
"clear": "Clear",
"no_match": "No matching entities found",
"show_entities": "Show entities"
},
"entity-attribute-picker": {
@@ -334,6 +336,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",
@@ -348,6 +360,8 @@
"clear": "Clear",
"toggle": "Toggle",
"show_devices": "Show devices",
"no_devices": "You don't have any devices",
"no_match": "No matching devices found",
"device": "Device",
"no_area": "No area"
},
@@ -356,6 +370,8 @@
"show_areas": "Show areas",
"area": "Area",
"add_new": "Add new area…",
"no_areas": "You don't have any areas",
"no_match": "No matching areas found",
"add_dialog": {
"title": "Add new area",
"text": "Enter the name of the new area.",
@@ -612,6 +628,8 @@
"unavailable": "This entity is not currently available.",
"enabled_label": "Enable entity",
"enabled_cause": "Disabled by {cause}.",
"device_disabled": "The device of this entity is disabled.",
"open_device_settings": "Open device settings",
"enabled_description": "Disabled entities will not be added to Home Assistant.",
"enabled_delay_confirm": "The enabled entities will be added to Home Assistant in {delay} seconds",
"enabled_restart_confirm": "Restart Home Assistant to finish enabling the entities",
@@ -787,7 +805,7 @@
},
"areas": {
"caption": "Areas",
"description": "Manage areas in your home",
"description": "Group devices and entities into areas",
"data_table": {
"area": "Area",
"devices": "Devices"
@@ -817,7 +835,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",
@@ -836,7 +854,7 @@
"new_tag": "New tag",
"name": "Name",
"description": "Description",
"tag_id": "Tag id",
"tag_id": "Tag ID",
"tag_id_placeholder": "Autogenerated when left empty",
"delete": "Delete",
"update": "Update",
@@ -848,7 +866,7 @@
},
"helpers": {
"caption": "Helpers",
"description": "Manage elements that help build automations",
"description": "Elements that help build automations",
"types": {
"input_text": "Text",
"input_number": "Number",
@@ -876,7 +894,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",
@@ -905,7 +923,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.",
@@ -940,7 +958,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",
@@ -1031,7 +1049,7 @@
"introduction": "Some parts of Home Assistant can reload without requiring a restart. Hitting reload will unload their current YAML configuration and load the new one.",
"reload": "Reload {domain}",
"core": "Reload location & customizations",
"group": "Reload groups, group entities, and notify services",
"group": "Reload groups, group entities, and group notify services",
"automation": "Reload automations",
"script": "Reload scripts",
"scene": "Reload scenes",
@@ -1044,7 +1062,7 @@
"input_select": "Reload input selects",
"template": "Reload template entities",
"universal": "Reload universal media player entities",
"rest": "Reload rest entities and notify services",
"rest": "Reload rest entities, and rest notify services",
"command_line": "Reload command line entities",
"filter": "Reload filter entities",
"statistics": "Reload statistics entities",
@@ -1095,7 +1113,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.",
@@ -1130,7 +1148,7 @@
},
"editor": {
"enable_disable": "Enable/Disable automation",
"introduction": "Use automations to bring your home to live.",
"introduction": "Use automations to bring your home to life.",
"default_name": "New Automation",
"load_error_not_editable": "Only automations in automations.yaml are editable.",
"load_error_unknown": "Error loading automation ({err_no}).",
@@ -1147,8 +1165,6 @@
"header": "Blueprint",
"blueprint_to_use": "Blueprint to use",
"no_blueprints": "You don't have any blueprints",
"manage_blueprints": "Manage Blueprints",
"inputs": "Inputs",
"no_inputs": "This blueprint doesn't have any inputs."
},
"modes": {
@@ -1445,8 +1461,8 @@
"description": "Manage blueprints",
"overview": {
"header": "Blueprint Editor",
"introduction": "The blueprint editor allows you to create and edit blueprints.",
"learn_more": "Learn more about blueprints",
"introduction": "The blueprint configuration allows you to import and manage your blueprints.",
"learn_more": "Learn more about using blueprints",
"headers": {
"name": "Name",
"domain": "Domain",
@@ -1456,26 +1472,28 @@
"confirm_delete_text": "Are you sure you want to delete this blueprint?",
"add_blueprint": "Import blueprint",
"use_blueprint": "Create automation",
"delete_blueprint": "Delete blueprint"
"delete_blueprint": "Delete blueprint",
"discover_more": "Discover more blueprints"
},
"add": {
"header": "Add new blueprint",
"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.",
"header": "Import a blueprint",
"import_header": "Blueprint \"{name}\"",
"import_introduction_link": "You can import blueprints of other users from Github and the {community_link}. Enter the URL of the blueprint below.",
"community_forums": "community forums",
"url": "URL of the blueprint",
"raw_blueprint": "Blueprint content",
"importing": "Importing blueprint...",
"import_btn": "Import blueprint",
"saving": "Saving blueprint...",
"save_btn": "Save blueprint",
"importing": "Loading blueprint...",
"import_btn": "Preview blueprint",
"saving": "Importing blueprint...",
"save_btn": "Import blueprint",
"error_no_url": "Please enter the URL of the blueprint.",
"unsupported_blueprint": "This blueprint is not supported",
"file_name": "Local blueprint file name"
"file_name": "Blueprint Path"
}
},
"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.",
@@ -1525,7 +1543,7 @@
},
"scene": {
"caption": "Scenes",
"description": "Manage scenes",
"description": "Capture device states and easily recall them later",
"activated": "Activated scene {name}.",
"picker": {
"header": "Scene Editor",
@@ -1544,7 +1562,7 @@
}
},
"editor": {
"introduction": "Use scenes to bring your home to live.",
"introduction": "Use scenes to bring your home to life.",
"default_name": "New Scene",
"load_error_not_editable": "Only scenes in scenes.yaml are editable.",
"load_error_unknown": "Error loading scene ({err_no}).",
@@ -1571,7 +1589,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.",
@@ -1738,18 +1756,27 @@
"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",
"name": "Name",
"update": "Update",
"no_devices": "No devices",
"enabled_label": "Enable device",
"enabled_cause": "The device is disabled by {cause}.",
"disabled_by": {
"user": "User",
"integration": "Integration",
"config_entry": "Config Entry"
},
"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",
@@ -1770,12 +1797,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.",
@@ -1790,6 +1819,7 @@
"scenes": "Scenes",
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
"disabled": "Disabled",
"data_table": {
"device": "Device",
"manufacturer": "Manufacturer",
@@ -1797,11 +1827,19 @@
"area": "Area",
"integration": "Integration",
"battery": "Battery",
"no_devices": "No devices",
"no_area": "No area"
"no_devices": "No devices"
},
"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",
@@ -1916,7 +1954,7 @@
},
"integrations": {
"caption": "Integrations",
"description": "Manage integrations",
"description": "Manage integrations with services, devices, ...",
"integration": "integration",
"discovered": "Discovered",
"attention": "Attention required",
@@ -1989,7 +2027,7 @@
},
"users": {
"caption": "Users",
"description": "Manage users",
"description": "Manage the Home Assistant user accounts",
"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": {
@@ -2022,7 +2060,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",
@@ -2871,7 +2910,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",

View File

@@ -437,6 +437,7 @@
"add_new": "إضافة منطقة جديدة ...",
"area": "المنطقة",
"clear": "مسح",
"no_match": "لم يتم العثور على مناطق مطابقة",
"show_areas": "إظهار المناطق"
},
"data-table": {
@@ -449,6 +450,7 @@
},
"device-picker": {
"no_area": "لا مجال",
"no_match": "لم يتم العثور على أجهزة مطابقة",
"toggle": "تبديل"
},
"entity": {

File diff suppressed because it is too large Load Diff

View File

@@ -2,11 +2,13 @@
"config_entry": {
"disabled_by": {
"config_entry": "Entrada de configuració",
"device": "Dispositiu",
"integration": "Integració",
"user": "Usuari"
}
},
"groups": {
"owner": "Propietari",
"system-admin": "Administradors",
"system-read-only": "Usuaris de només lectura",
"system-users": "Usuaris"
@@ -545,12 +547,14 @@
"add_new": "Afegir àrea nova...",
"area": "Àrea",
"clear": "Esborra",
"no_areas": "No tens cap àrea",
"no_match": "No s'han trobat àrees coincidents",
"show_areas": "Mostra àrees"
},
"blueprint-picker": {
"add_user": "Afegeix usuari",
"remove_user": "Elimina usuari",
"select_blueprint": "Selecciona un plànol"
"select_blueprint": "Selecciona un blueprint"
},
"data-table": {
"no-data": "No hi ha dades",
@@ -565,6 +569,8 @@
"clear": "Esborra",
"device": "Dispositiu",
"no_area": "Sense àrees",
"no_devices": "No tens cap dispositiu",
"no_match": "No s'han trobat dispositius coincidents",
"show_devices": "Mostra dispositius",
"toggle": "Commuta"
},
@@ -576,6 +582,7 @@
"entity-picker": {
"clear": "Esborra",
"entity": "Entitat",
"no_match": "No s'han trobat entitats coincidents",
"show_entities": "Mostra entitats"
}
},
@@ -709,6 +716,16 @@
"service-picker": {
"service": "Servei"
},
"target-picker": {
"add_area_id": "Selecciona àrea",
"add_device_id": "Selecciona dispositiu",
"add_entity_id": "Selecciona entitat",
"expand_area_id": "Expandeix aquesta àrea en els dispositius i entitats que conté. Després d'expandir-la, no s'actualitzaran els dispositius i les entitats quan l'àrea canviï.",
"expand_device_id": "Expandeix aquest dispositiu en entitats separades. Després d'expandir-lo, no s'actualitzaran les entitats quan el dispositiu canviï.",
"remove_area_id": "Elimina àrea",
"remove_device_id": "Elimina dispositiu",
"remove_entity_id": "Elimina entitat"
},
"user-picker": {
"add_user": "Afegeix usuari",
"no_user": "Cap usuari",
@@ -732,6 +749,7 @@
"editor": {
"confirm_delete": "Estàs segur que vols eliminar aquesta entrada?",
"delete": "Elimina",
"device_disabled": "El dispositiu d'aquesta entitat està desactivat.",
"enabled_cause": "Desactivada per {cause}.",
"enabled_delay_confirm": "Les entitats activades s'afegiran a Home Assistant d'aquí a {delay} segons",
"enabled_description": "Les entitats desactivades no s'afegiran a Home Assistant.",
@@ -742,6 +760,7 @@
"icon_error": "Els icones han de tenir el format 'prefix:nom_icona', per exemple: 'mdi:home'",
"name": "Nom",
"note": "Nota: podria no funcionar amb alguna de les integracions.",
"open_device_settings": "Obre la configuració del dispositiu",
"unavailable": "Aquesta entitat no està disponible actualment.",
"update": "Actualitza"
},
@@ -882,7 +901,7 @@
"navigation": {
"areas": "Àrees",
"automation": "Automatització",
"blueprint": "Plànols",
"blueprint": "Blueprints",
"core": "General",
"customize": "Personalització",
"devices": "Dispositius",
@@ -1029,7 +1048,7 @@
"confirmation_text": "Tots els dispositius d'aquesta àrea quedaran sense assignar.",
"confirmation_title": "Estàs segur que vols eliminar aquesta àrea?"
},
"description": "Gestiona les àrees de la casa",
"description": "Agrupa dispositius i entitats en àrees",
"editor": {
"area_id": "ID d'àrea",
"create": "Crea",
@@ -1051,10 +1070,10 @@
},
"automation": {
"caption": "Automatització",
"description": "Gestiona les automatitzacions",
"description": "Crea regles de comportament personalitzades per a casa teva",
"dialog_new": {
"blueprint": {
"use_blueprint": "Utilitza un plànol"
"use_blueprint": "Utilitza un blueprint"
},
"header": "Creació d'una nova automatització",
"how": "Com vols crear la nova automatització?",
@@ -1147,12 +1166,12 @@
},
"alias": "Nom",
"blueprint": {
"blueprint_to_use": "Plànol a utilitzar",
"header": "Plànol",
"blueprint_to_use": "Blueprint a utilitzar",
"header": "Blueprint",
"inputs": "Entrades",
"manage_blueprints": "Gestiona els plànols",
"no_blueprints": "No tens plànols",
"no_inputs": "Aquest plànol no té entrades."
"manage_blueprints": "Gestiona els blueprints",
"no_blueprints": "No tens blueprints",
"no_inputs": "Aquest blueprint no té entrades."
},
"conditions": {
"add": "Afegir condició",
@@ -1239,7 +1258,7 @@
"edit_ui": "Edita a través d'interfície",
"edit_yaml": "Edita com a YAML",
"enable_disable": "Activa/desactiva automatització",
"introduction": "Utilitza les automatitzacions per donar més vida a la teva casa",
"introduction": "Utilitza les automatitzacions per donar vida a casa teva.",
"load_error_not_editable": "Només es poden editar les automatitzacions de l'arxiu automations.yaml.",
"load_error_unknown": "Error en carregar l'automatització ({err_no}).",
"max": {
@@ -1398,29 +1417,38 @@
},
"blueprint": {
"add": {
"error_no_url": "Introdueix l'URL del plànol.",
"header": "Afegiu plànol nou",
"import_btn": "Importa plànol",
"import_header": "Importa {name} ({domain})",
"import_introduction": "Pots importar plànols d'altres usuaris des de Github i els fòrums de la comunitat. Introdueix, a sota, l'URL del plànol.",
"importing": "Important plànol",
"save_btn": "Desa plànol",
"saving": "Desant plànol...",
"unsupported_blueprint": "Aquest plànols no és compatible",
"url": "URL del plànol"
"community_forums": "fòrums de la comunitat",
"error_no_url": "Introdueix l'URL del blueprint.",
"file_name": "Directori del blueprint",
"header": "Importa un blueprint nou",
"import_btn": "Vista prèvia del blueprint",
"import_header": "Blueprint \"{name}\"",
"import_introduction": "Pots importar blueprints d'altres usuaris des de Github i els fòrums de la comunitat. Introdueix, a sota, l'URL del blueprint.",
"import_introduction_link": "Pots importar blueprints d'altres usuaris des de Github i des dels {community_link}. Introdueix, a sota, l'URL del blueprint.",
"importing": "Carregant blueprint...",
"raw_blueprint": "Contingut del blueprint",
"save_btn": "Importa blueprint",
"saving": "Important blueprint...",
"unsupported_blueprint": "Aquest blueprint no és compatible",
"url": "URL del blueprint"
},
"caption": "Plànols",
"description": "Gestiona els plànols",
"caption": "Blueprints",
"description": "Gestiona els blueprints",
"overview": {
"add_blueprint": "Afegiu plànol",
"confirm_delete_header": "Eliminar aquest plànol?",
"confirm_delete_text": "Segur que vols eliminar aquest plànol?",
"header": "Editor de plànols",
"add_blueprint": "Importa blueprint",
"confirm_delete_header": "Eliminar aquest blueprint?",
"confirm_delete_text": "Segur que vols eliminar aquest blueprint?",
"delete_blueprint": "Elimina blueprint",
"discover_more": "Descobreix més blueprints",
"header": "Editor de blueprints",
"headers": {
"domain": "Domini",
"file_name": "Nom de l'arxiu",
"name": "Nom"
},
"introduction": "L'editor de plànols et permet crear i editar plànols.",
"learn_more": "Més informació sobre els plànols"
"introduction": "La configuració dels blueprints et permet importar-ne i gestionar-los.",
"learn_more": "Més informació sobre l'ús dels blueprints",
"use_blueprint": "Crea automatització"
}
},
"cloud": {
@@ -1503,7 +1531,7 @@
"title": "Alexa"
},
"caption": "Home Assistant Cloud",
"description_features": "Controla la casa des de fora, pots integrar Alexa i Google Assistant.",
"description_features": "Controla la casa quan siguis fora i integra-hi Alexa i Google Assistant",
"description_login": "Sessió iniciada com a {email}",
"description_not_login": "No has iniciat sessió",
"dialog_certificate": {
@@ -1598,7 +1626,7 @@
},
"core": {
"caption": "General",
"description": "Canvia la configuració general de Home Assistant",
"description": "Sistema d'unitats, ubicació, zona horària i altres paràmetres generals",
"section": {
"core": {
"core_config": {
@@ -1660,6 +1688,7 @@
"unknown_condition": "Condició desconeguda"
},
"create": "Crea una automatització amb el dispositiu",
"create_disable": "No es pot crear una automatització amb dispositius desactivats",
"no_automations": "No hi ha automatitzacions",
"no_device_automations": "No hi ha automatitzacions disponibles per a aquest dispositiu.",
"triggers": {
@@ -1685,9 +1714,18 @@
"no_devices": "Sense dispositius"
},
"delete": "Elimina",
"description": "Gestiona els dispositius connectats",
"description": "Gestiona els dispositius configurats",
"device_info": "Informació del dispositiu",
"device_not_found": "Dispositiu no trobat.",
"disabled": "Desactivat",
"disabled_by": {
"config_entry": "Entrada de configuració",
"integration": "Integració",
"user": "Usuari"
},
"enabled_cause": "El dispositiu està desactivat per {cause}.",
"enabled_description": "Els dispositius desactivats no es mostraran i les entitats que hi pertanyin es desactivaran i no s'afegiran a Home Assistant.",
"enabled_label": "Activa dispositiu",
"entities": {
"add_entities_lovelace": "Afegeix a Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {entitat desabilitada}\n other {entitats desabilitades}\n}",
@@ -1697,14 +1735,25 @@
},
"name": "Nom",
"no_devices": "No hi ha dispositius",
"picker": {
"filter": {
"filter": "Filtre",
"hidden_devices": "{number} {number, plural,\n one {dispositiu amagat}\n other {dispositius amagats}\n}",
"show_all": "Mostra-ho tot",
"show_disabled": "Mostra dispositius desactivats"
},
"search": "Cerca dispositius"
},
"scene": {
"create": "Crea una escena amb el dispositiu",
"create_disable": "No es pot crear una escena amb dispositius desactivats",
"no_scenes": "No hi ha escenes",
"scenes": "Escenes"
},
"scenes": "Escenes",
"script": {
"create": "Crea un programa (script) amb el dispositiu",
"create_disable": "No es pot crear un script amb dispositius desactivats",
"no_scripts": "No hi ha scripts",
"scripts": "Scripts"
},
@@ -1737,6 +1786,7 @@
},
"header": "Entitats",
"headers": {
"area": "Àrea",
"entity_id": "ID de l'entitat",
"integration": "Integració",
"name": "Nom",
@@ -1769,7 +1819,7 @@
"header": "Configuració de Home Assistant",
"helpers": {
"caption": "Ajudants",
"description": "Gestiona elements útils per a construir automatitzacions",
"description": "Elements útils per a construir automatitzacions",
"dialog": {
"add_helper": "Afegeix ajudant",
"add_platform": "Afegeix {platform}",
@@ -1801,7 +1851,7 @@
"copy_github": "Per GitHub",
"copy_raw": "Text en brut",
"custom_uis": "Interfícies d'usuari personalitzades:",
"description": "Consulta informació de la teva instal·lació de Home Assistant",
"description": "Versió, estat del sistema i enllaços a la documentació",
"developed_by": "Desenvolupat per un munt de gent fantàstica.",
"documentation": "Documentació",
"frontend": "frontend-ui",
@@ -1907,7 +1957,7 @@
},
"configure": "Configurar",
"configured": "Configurades",
"description": "Gestiona les integracions",
"description": "Gestiona les integracions amb serveis, dispositius, ...",
"details": "Detalls de la integració",
"discovered": "Descobertes",
"home_assistant_website": "lloc web de Home Assistant",
@@ -1992,7 +2042,7 @@
"open": "Obrir"
}
},
"description": "Gestiona els teus panells Lovelace",
"description": "Crea conjunts de panells personalitzats per controlar la teva casa",
"resources": {
"cant_edit_yaml": "Estàs utilitzant Lovelace en mode YAML per tant no pots gestionar els recursos des de la interfície d'usuari. Els pots gestionar des del fitxer 'configuration.yaml'.",
"caption": "Recursos",
@@ -2135,7 +2185,7 @@
"refresh_node": {
"battery_note": "Si el node funciona amb bateria, assegura't de que estigui actiu abans de continuar",
"button": "Actualitza node",
"complete": "Actualització del node completa",
"complete": "Actualització del node completada",
"description": "Això farà que OpenZWave torni a consultar el node i n'actualitzi les classes de comandes, funcions i valors.",
"node_status": "Estat del node",
"refreshing_description": "Actualitzant la informació del node...",
@@ -2191,7 +2241,7 @@
"scene": {
"activated": "Escena {name} activada.",
"caption": "Escenes",
"description": "Gestiona les escenes",
"description": "Captura els estats dels dispositius i recorda'ls més tard",
"editor": {
"default_name": "Nova escena",
"devices": {
@@ -2209,7 +2259,7 @@
"without_device": "Entitats sense dispositiu"
},
"icon": "Icona",
"introduction": "Utilitza les escenes per donar més vida a la teva llar.",
"introduction": "Utilitza les escenes per donar més vida a la teva casa.",
"load_error_not_editable": "Només es poden editar les escenes de l'arxiu scenes.yaml.",
"load_error_unknown": "Error en carregar l'escena ({err_no}).",
"name": "Nom",
@@ -2235,7 +2285,7 @@
},
"script": {
"caption": "Programació (scripts)",
"description": "Gestiona els programes (scripts)",
"description": "Executa una seqüència d'accions",
"editor": {
"alias": "Nom",
"default_name": "Nou script",
@@ -2346,7 +2396,7 @@
"confirm_remove": "Estàs segur que vols eliminar l'etiqueta {tag}?",
"confirm_remove_title": "Elimina l'etiqueta?",
"create_automation": "Crea una automatització amb una etiqueta",
"description": "Gestiona les etiquetes",
"description": "Dispara automatitzacions quan una etiqueta NFC, un codi QR, etc; s'escanegi",
"detail": {
"companion_apps": "aplicacions de companion",
"create": "Crea",
@@ -2381,10 +2431,11 @@
"username": "Nom d'usuari"
},
"caption": "Usuaris",
"description": "Gestiona els usuaris",
"description": "Gestiona els comptes d'usuari de Home Assistant",
"editor": {
"activate_user": "Activar usuari",
"active": "Actiu",
"active_tooltip": "Controla si l'usuari pot iniciar sessió",
"admin": "Administrador",
"caption": "Mostra usuari",
"change_password": "Canviar contrasenya",
@@ -2393,7 +2444,7 @@
"delete_user": "Eliminar usuari",
"group": "Grup",
"id": "ID",
"name": "Nom",
"name": "Nom de visualització",
"new_password": "Nova contrasenya",
"owner": "Propietari",
"password_changed": "La contrasenya s'ha canviat correctament",
@@ -2401,19 +2452,24 @@
"system_generated_users_not_editable": "No es poden actualitzar usuaris generats pel sistema.",
"system_generated_users_not_removable": "No es poden eliminar usuaris generats pel sistema.",
"unnamed_user": "Usuari sense nom",
"update_user": "Actualitza"
"update_user": "Actualitza",
"username": "Nom d'usuari"
},
"picker": {
"add_user": "Afegeix usuari",
"headers": {
"group": "Grup",
"name": "Nom",
"system": "Sistema"
"is_active": "Actiu",
"is_owner": "Propietari",
"name": "Nom de visualització",
"system": "Generat pel sistema",
"username": "Nom d'usuari"
}
},
"users_privileges_note": "El grup d'usuaris encara no està del tot acabat. L'usuari no podrà administrar la instància a través de la interfície d'usuari. Encara estem verificant tots els punts de l'API de gestió per assegurar-nos que limiten correctament l'accés als administradors."
},
"zha": {
"add_device": "Afegeix dispositiu",
"add_device_page": {
"discovered_text": "Els dispositius apareixeran aquí un cop descoberts.",
"discovery_text": "Els dispositius descoberts apareixeran aquí. Segueix les instruccions del/s teu/s dispositiu/s i posa el dispositiu/s en mode d'emparellament.",
@@ -2459,6 +2515,16 @@
"value": "Valor"
},
"description": "Gestiona la xarxa domòtica Zigbee (ZHA)",
"device_pairing_card": {
"CONFIGURED": "Configuració completada",
"CONFIGURED_status_text": "Inicialitzant",
"INITIALIZED": "Inicialització completada",
"INITIALIZED_status_text": "El dispositiu està llest per a utilitzar-se",
"INTERVIEW_COMPLETE": "Consulta completada",
"INTERVIEW_COMPLETE_status_text": "Configurant",
"PAIRED": "Dispositiu trobat",
"PAIRED_status_text": "Iniciant consulta"
},
"devices": {
"header": "Domòtica Zigbee (ZHA) - Dispositiu"
},
@@ -2474,6 +2540,7 @@
"unbind_button_label": "Desvincula grup"
},
"groups": {
"add_group": "Afegeix grup",
"add_members": "Afegeix membres",
"adding_members": "Afegint membres",
"caption": "Grups",
@@ -2516,7 +2583,11 @@
"hint_wakeup": "Alguns dispositius com els sensors Xiaomi tenen un botó per despertar-los que pots prémer a intervals de 5 segons per mantenir-los desperts mentre hi interactues.",
"introduction": "Executa comandes ZHA que afecten un sol dispositiu. Tria un dispositiu per veure el seu llistat de comandes disponibles."
},
"title": "Domòtica Zigbee (ZHA)"
"title": "Domòtica Zigbee (ZHA)",
"visualization": {
"caption": "Visualització",
"header": "Visualització de xarxa"
}
},
"zone": {
"add_zone": "Afegeix zona",
@@ -3116,7 +3187,7 @@
"close": "Tanca",
"empty_config": "Comença amb un panell buit",
"header": "Pren el control de la interfície d'usuari Lovelace",
"para": "Aquest panell Lovelace s'està gestionant per Home Assistant. S'actualitza automàticament quan hi ha noves entitats o nous components de Lovelace disponibles. Si prens el control, aquest panell no s'actualitzarà automàticament. Sempre pots crear un nou panell a configuració i fer-hi proves.",
"para": "Aquest panell Lovelace està gestionat per Home Assistant. S'actualitza automàticament quan hi ha noves entitats o nous components de Lovelace disponibles. Si prens el control, aquest panell no s'actualitzarà automàticament. Sempre pots crear un nou panell a configuració i fer-hi proves.",
"para_sure": "Estàs segur que vols prendre el control de la interfície d'usuari?",
"save": "Prendre el control",
"yaml_config": "Per ajudar a familiaritzar-te, aquí tens la configuració actual del teu panell Lovelace:",
@@ -3383,10 +3454,13 @@
"change_password": {
"confirm_new_password": "Confirmar contrasenya nova",
"current_password": "Contrasenya actual",
"error_new_is_old": "La contrasenya nova ha de ser diferent de la contrasenya actual",
"error_new_mismatch": "Els valors introduïts de la nova contrasenya no coincideixen",
"error_required": "Obligatori",
"header": "Canvi de contrasenya",
"new_password": "Contrasenya nova",
"submit": "Envia"
"submit": "Envia",
"success": "La contrasenya s'ha canviat correctament"
},
"current_user": "Has iniciat la sessió com a {fullName}.",
"customize_sidebar": {

View File

@@ -2,6 +2,7 @@
"config_entry": {
"disabled_by": {
"config_entry": "Položka nastavení",
"device": "Zařízení",
"integration": "Integrace",
"user": "Uživatel"
}
@@ -546,11 +547,14 @@
"add_new": "Přidat novou oblast ...",
"area": "Oblast",
"clear": "Vymazat",
"no_areas": "Nemáte žádné oblasti",
"no_match": "Nebyly nalezeny žádné odpovídající oblasti",
"show_areas": "Zobrazit oblasti"
},
"blueprint-picker": {
"add_user": "Přidat uživatele",
"remove_user": "Odebrat uživatele"
"remove_user": "Odebrat uživatele",
"select_blueprint": "Vyberte šablonu"
},
"data-table": {
"no-data": "Žádná data",
@@ -565,6 +569,8 @@
"clear": "Zrušit",
"device": "Zařízení",
"no_area": "Žádná oblast",
"no_devices": "Nemáte žádná zařízení",
"no_match": "Nebyla nalezena žádná odpovídající zařízení",
"show_devices": "Zobrazit zařízení",
"toggle": "Přepnout"
},
@@ -576,6 +582,7 @@
"entity-picker": {
"clear": "Zrušit",
"entity": "Entita",
"no_match": "Nebyly nalezeny žádné odpovídající entity",
"show_entities": "Zobrazit entity"
}
},
@@ -709,6 +716,16 @@
"service-picker": {
"service": "Služba"
},
"target-picker": {
"add_area_id": "Vyberte oblast",
"add_device_id": "Vyberte zařízení",
"add_entity_id": "Vyberte entitu",
"expand_area_id": "Rozdělit tuto oblast na jednotlivá zařízení a entity, které obsahuje. Po rozdělení nebudou zařízení a entity aktualizovány, pokud dojde ke změnám oblasti.",
"expand_device_id": "Rozdělit toto zařízení na jednotlivé entity. Po rozdělení nebudou entity aktualizovány, pokud dojde ke změnám zařízení.",
"remove_area_id": "Odebrat oblast",
"remove_device_id": "Odebrat zařízení",
"remove_entity_id": "Odebrat entitu"
},
"user-picker": {
"add_user": "Přidat uživatele",
"no_user": "Žádný uživatel",
@@ -732,6 +749,7 @@
"editor": {
"confirm_delete": "Opravdu chcete tuto položku smazat?",
"delete": "Odstranit",
"device_disabled": "Zařízení této entity je zakázáno.",
"enabled_cause": "Zakázáno {cause}.",
"enabled_delay_confirm": "Povolené entity budou přidány do Home Assistant za {delay} sekund",
"enabled_description": "Zakázané entity nebudou přidány do Home Assistant.",
@@ -742,6 +760,7 @@
"icon_error": "Ikony by měly být ve formátu 'prefix:nazevikony', např. 'mdi:home'",
"name": "Jméno",
"note": "Poznámka: U všech integrací to ještě nemusí fungovat.",
"open_device_settings": "Otevřít nastavení zařízení",
"unavailable": "Tato entita není momentálně k dispozici.",
"update": "Aktualizovat"
},
@@ -882,6 +901,7 @@
"navigation": {
"areas": "Oblasti",
"automation": "Automatizace",
"blueprint": "Šablony",
"core": "Obecné",
"customize": "Přizpůsobení",
"devices": "Zařízení",
@@ -890,7 +910,7 @@
"info": "Informace",
"integrations": "Integrace",
"logs": "Logy",
"lovelace": "Lovelace Dashboardy",
"lovelace": "Ovládací panely Lovelace",
"navigate_to": "Přejít na {panel}",
"navigate_to_config": "Přejít na nastavení {panel}",
"person": "Osoby",
@@ -953,7 +973,7 @@
"zha_device_info": {
"buttons": {
"add": "Přidejte zařízení prostřednictvím tohoto zařízení",
"clusters": "Clustery",
"clusters": "Správa clusterů",
"reconfigure": "Přenastavit zařízení",
"remove": "Odebrat zařízení",
"zigbee_information": "Podpis zařízení Zigbee"
@@ -1028,7 +1048,7 @@
"confirmation_text": "Všechna zařízení v této oblasti budou nastavena jako nepřiřazena.",
"confirmation_title": "Opravdu chcete tuto oblast smazat?"
},
"description": "Správa oblastí ve vaší domácnosti",
"description": "Seskupte zařízení a entity do oblastí",
"editor": {
"area_id": "ID oblasti",
"create": "VYTVOŘIT",
@@ -1050,11 +1070,14 @@
},
"automation": {
"caption": "Automatizace",
"description": "Správa automatizací",
"description": "Vytvořte si pro svůj domov vlastní pravidla chování",
"dialog_new": {
"blueprint": {
"use_blueprint": "Použít šablonu"
},
"header": "Vytvoření automatizace",
"how": "Jak chcete vytvořit svou novou automatizaci?",
"start_empty": "Začněte s prázdnou automatizací",
"start_empty": "Začít s prázdnou automatizací",
"thingtalk": {
"create": "Vytvořit",
"header": "Popište automatizaci, kterou chcete vytvořit",
@@ -1087,8 +1110,8 @@
"label": "Stav"
},
"delay": {
"delay": "Zpoždění",
"label": "Zpoždění"
"delay": "Pozdržení",
"label": "Pozdržení"
},
"device_id": {
"action": "Akce",
@@ -1143,7 +1166,12 @@
},
"alias": "Název",
"blueprint": {
"inputs": "Vstupy"
"blueprint_to_use": "Šablona k použití",
"header": "Šablona",
"inputs": "Vstupy",
"manage_blueprints": "Správa šablon",
"no_blueprints": "Nemáme žádné šablony",
"no_inputs": "Šablona nemá žádné vstupy."
},
"conditions": {
"add": "Přidat podmínku",
@@ -1389,24 +1417,38 @@
},
"blueprint": {
"add": {
"error_no_url": "Zadejte adresu URL šablonky konfigurace",
"header": "Přidat novou šablonku konfigurace",
"import_btn": "Importovat šablonku konfigurace",
"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",
"saving": "Ukládání konfigurační šablonky",
"url": "URL šablonky konfigurace"
"community_forums": "komunitních fór",
"error_no_url": "Zadejte adresu URL adresu šablony",
"file_name": "Cesta k šabloně",
"header": "Import šablony",
"import_btn": "Náhled šablony",
"import_header": "Šablona \"{name}\"",
"import_introduction": "Můžete importovat šablony od ostatních uživatelů z GitHubu a komunitních fór. Níže zadejte URL adresu šablony.",
"import_introduction_link": "Můžete importovat šablony od ostatních uživatelů z GitHubu a {community_link}. Níže zadejte URL adresu šablony.",
"importing": "Načítám šablonu...",
"raw_blueprint": "Obsah šablony",
"save_btn": "Importovat šablonu",
"saving": "Importuji šablonu...",
"unsupported_blueprint": "Tato šablona není podporována.",
"url": "URL adresa šablony"
},
"caption": "Šablony",
"description": "Správa šablon",
"overview": {
"confirm_delete_header": "Odstranit tuto šablonku konfigurace?",
"add_blueprint": "Import šablony",
"confirm_delete_header": "Odstranit tuto šablonu?",
"confirm_delete_text": "Opravdu chcete smazat tuto šablonu?",
"delete_blueprint": "Smazat šablonu",
"discover_more": "Objevte další šablony",
"header": "Editor šablon",
"headers": {
"domain": "Doména",
"file_name": "Název souboru",
"name": "Jméno"
},
"learn_more": "Další informace o šablonkách konfigurace"
"introduction": "Nastavení šablon vám umožňuje importovat a spravovat vaše šablony.",
"learn_more": "Další informace o používání šablon",
"use_blueprint": "Vytvořit automatizaci"
}
},
"cloud": {
@@ -1419,7 +1461,7 @@
"enable_state_reporting": "Povolit hlášení stavu",
"info": "Díky integraci Alexa pro Home Assistant Cloud budete moci ovládat všechna zařízení v Home Assistant pomocí jakéhokoli zařízení podporujícího Alexa.",
"info_state_reporting": "Pokud povolíte hlášení stavu, Home Assistant bude posílat veškeré změny stavů všech exponovaných entit do Amazonu. Toto vám umožní sledovat aktuální stavy entity v aplikaci Alexa a použít tyto stavy k vytvoření rutin.",
"manage_entities": "Spravovat entity",
"manage_entities": "Správa entit",
"state_reporting_error": "Nelze {enable_disable} hlášení stavu.",
"sync_entities": "Synchronizovat entity",
"sync_entities_error": "Chyba při synchronizaci entit:",
@@ -1448,7 +1490,7 @@
"integrations_introduction": "Integrace pro Home Assistant Cloud vám umožní připojit se ke cloudovým službám, aniž byste museli veřejně zpřístupnit vaší instanci Home Assistant na internetu.",
"integrations_introduction2": "Na webových stránkách najdete ",
"integrations_link_all_features": " všechny dostupné funkce",
"manage_account": "Spravovat účet",
"manage_account": "Správa účtu",
"nabu_casa_account": "Účet Nabu Casa",
"not_connected": "Není připojeno",
"remote": {
@@ -1489,7 +1531,7 @@
"title": "Alexa"
},
"caption": "Home Assistant Cloud",
"description_features": "Ovládejte vzdáleně, integrace s Alexou a Google Assistant.",
"description_features": "Ovládejte, i když nejste doma, a propojte s Alexou a Google Assistantem",
"description_login": "Přihlášen jako {email}",
"description_not_login": "Nepřihlášen",
"dialog_certificate": {
@@ -1584,7 +1626,7 @@
},
"core": {
"caption": "Obecné",
"description": "Změny obecného nastavení Home Assistant",
"description": "Jednotkový systém, umístění, časové pásmo a další obecné parametry",
"section": {
"core": {
"core_config": {
@@ -1646,6 +1688,7 @@
"unknown_condition": "Neznámá podmínka"
},
"create": "Vytvořit automatizaci se zařízením",
"create_disable": "Nelze vytvořit automatizaci se zakázaným zařízením",
"no_automations": "Žádné automatizace",
"no_device_automations": "Pro toto zařízení nejsou k dispozici žádné automatizace.",
"triggers": {
@@ -1659,7 +1702,7 @@
"caption": "Zařízení",
"confirm_delete": "Opravdu chcete toto zařízení odstranit?",
"confirm_rename_entity_ids": "Chcete také přejmenovat ID entit?",
"confirm_rename_entity_ids_warning": "Žádná nastavení (např. automatizace, skripty, scény, dashboardy), která tyto entity aktuálně používá, nebudou změněna! Vše budete muset aktualizovat sami, aby se používaly nová ID entit!",
"confirm_rename_entity_ids_warning": "Žádná nastavení (např. automatizace, skripty, scény, ovládací panely), která tyto entity aktuálně používá, nebudou změněna! Vše budete muset aktualizovat sami, aby se používaly nová ID entit!",
"data_table": {
"area": "Oblast",
"battery": "Baterie",
@@ -1674,6 +1717,15 @@
"description": "Správa připojených zařízení",
"device_info": "Informace o zařízení",
"device_not_found": "Zařízení nebylo nalezeno.",
"disabled": "Zakázáno",
"disabled_by": {
"config_entry": "Položka nastavení",
"integration": "Integrace",
"user": "Uživatel"
},
"enabled_cause": "Zařízení je zakázáno přes {cause}.",
"enabled_description": "Zakázaná zařízení se nebudou zobrazovat a entity patřící k těmto zařízením budou zakázány a nebudou přidány do Home Assistant.",
"enabled_label": "Povolit zařízení",
"entities": {
"add_entities_lovelace": "Přidat do Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {zakázaná entita}\n other {zakázaných entit}\n}",
@@ -1683,14 +1735,25 @@
},
"name": "Jméno",
"no_devices": "Žádná zařízení",
"picker": {
"filter": {
"filter": "Filtrovat",
"hidden_devices": "{number} {number, plural,\n one {skryté zařízení}\n few {skrytá zařízení}\n other {skrytých zařízení}\n}",
"show_all": "Zobrazit vše",
"show_disabled": "Zobrazit zakázaná zařízení"
},
"search": "Hledat zařízení"
},
"scene": {
"create": "Vytvořit scénu se zařízením",
"create_disable": "Nelze vytvořit scénu se zakázaným zařízením",
"no_scenes": "Žádné scény",
"scenes": "Scény"
},
"scenes": "Scény",
"script": {
"create": "Vytvořit skript se zařízením",
"create_disable": "Nelze vytvořit skript se zakázaným zařízením",
"no_scripts": "Žádné skripty",
"scripts": "Skripty"
},
@@ -1756,7 +1819,7 @@
"header": "Nastavení Home Assistant",
"helpers": {
"caption": "Pomocníci",
"description": "Správa prvků, které mohou pomoci při vytváře automatizací",
"description": "Prvky, které pomáhají vytvářet automatizace",
"dialog": {
"add_helper": "Přidat pomocníka",
"add_platform": "Přidat {platform}",
@@ -1774,7 +1837,7 @@
},
"types": {
"counter": "Počítadlo",
"input_boolean": "Přepnout",
"input_boolean": "Přepínač",
"input_datetime": "Datum a/nebo čas",
"input_number": "Číslo",
"input_select": "Výběr",
@@ -1788,7 +1851,7 @@
"copy_github": "Pro GitHub",
"copy_raw": "Nezpracovaný text",
"custom_uis": "Vlastní uživatelská rozhraní:",
"description": "Informace o instalaci Home Assistant",
"description": "Verze, stav systému a odkazy na dokumentaci",
"developed_by": "Vyvinuto partou úžasných lidí.",
"documentation": "Dokumentace",
"frontend": "frontend-ui",
@@ -1830,7 +1893,7 @@
"virtualenv": "Virtuální prostředí"
},
"lovelace": {
"dashboards": "Dashboardy",
"dashboards": "Ovládací panely",
"mode": "Režim",
"resources": "Zdroje"
}
@@ -1894,7 +1957,7 @@
},
"configure": "Nastavit",
"configured": "Nastaveno",
"description": "Správa integrací",
"description": "Správa integrací a jejich služeb, zařízení, ...",
"details": "Podrobnosti o integraci",
"discovered": "Objeveno",
"home_assistant_website": "stránky Home Assistant",
@@ -1938,24 +2001,24 @@
"title": "Logy"
},
"lovelace": {
"caption": "Lovelace Dashboardy",
"caption": "Ovládací panely Lovelace",
"dashboards": {
"cant_edit_default": "Standardní Lovelace dashboard nelze upravovat z uživatelského rozhraní. Můžete jej skrýt nastavením jiného dashboardu jako výchozího.",
"cant_edit_yaml": "Dashboardy definované v YAML nelze upravovat z uživatelského rozhraní. Změňte je v configuration.yaml.",
"caption": "Dashboardy",
"cant_edit_default": "Standardní ovládací panel Lovelace nelze upravovat z uživatelského rozhraní. Můžete jej skrýt nastavením jiného ovládacího panelu jako výchozího.",
"cant_edit_yaml": "Ovládací panely definované v YAML nelze upravovat z uživatelského rozhraní. Změňte je v configuration.yaml.",
"caption": "Ovládací panely",
"conf_mode": {
"storage": "Řízeno uživatelským rozhraním",
"yaml": "Soubor YAML"
},
"confirm_delete": "Opravdu chcete odstranit tento dashboard?",
"default_dashboard": "Toto je výchozí dashboard",
"confirm_delete": "Opravdu chcete odstranit tento ovládací panel?",
"default_dashboard": "Toto je výchozí ovládací panel",
"detail": {
"create": "Vytvořit",
"delete": "Smazat",
"dismiss": "Zavřít",
"edit_dashboard": "Upravit dashboard",
"edit_dashboard": "Upravit ovládací panel",
"icon": "Ikona",
"new_dashboard": "Přidat nový dashboard",
"new_dashboard": "Přidat nový ovládací panel",
"remove_default": "Odebrat jako výchozí na tomto zařízení",
"require_admin": "Pouze správce",
"set_default": "Nastavit jako výchozí na tomto zařízení",
@@ -1967,7 +2030,7 @@
"url_error_msg": "Adresa URL by měla obsahovat - a nesmí obsahovat mezery ani speciální znaky, s výjimkou _ a -"
},
"picker": {
"add_dashboard": "Přidat dashboard",
"add_dashboard": "Přidat ovládací panel",
"headers": {
"conf_mode": "Metoda nastavení",
"default": "Výchozí",
@@ -1979,7 +2042,7 @@
"open": "Otevřít"
}
},
"description": "Správa Lovelace Dashboardů",
"description": "Vytvořte vlastní sady karet pro ovládání svého domova",
"resources": {
"cant_edit_yaml": "Používáte Lovelace v režimu YAML, proto nemůžete spravovat své zdroje prostřednictvím uživatelského rozhraní. Spravujte je v souboru configuration.yaml.",
"caption": "Zdroje",
@@ -2020,7 +2083,7 @@
"description_publish": "Publikovat paket",
"listening_to": "Naslouchám",
"message_received": "Zpráva {id} přijata na {topic} v {time} :",
"payload": "Obsah",
"payload": "Obsah (povolena šablona)",
"publish": "Publikovat",
"start_listening": "Začít naslouchat",
"stop_listening": "Přestat naslouchat",
@@ -2049,7 +2112,7 @@
"network": "Síť",
"node": {
"config": "Nastavení",
"dashboard": "Dashboard"
"dashboard": "Ovládací panel"
},
"nodes": "Uzly",
"select_instance": "Vyberte instanci"
@@ -2082,7 +2145,7 @@
"node_config": {
"header": "Nastavení uzlu",
"help_source": "Popisy parametrů nastavení a text nápovědy poskytuje projekt OpenZWave.",
"introduction": "Spravujte různé parametry nastavení uzlu Z-Wave.",
"introduction": "Správa různých parametrů nastavení uzlu Z-Wave.",
"wakeup_help": "Uzly napájené z baterie musí být vzhůru, aby mohly změnit své nastavení. Pokud uzel není vzhůru, OpenZWave se pokusí aktualizovat nastavení uzlu při příštím probuzení, což může být o několik hodin (nebo dní) později. Zařízení probudíte takto:"
},
"node_metadata": {
@@ -2178,7 +2241,7 @@
"scene": {
"activated": "Aktivovaná scéna {name}.",
"caption": "Scény",
"description": "Správa scén",
"description": "Zachyťte stavy zařízení a snadno je později vyvolejte",
"editor": {
"default_name": "Nová scéna",
"devices": {
@@ -2222,7 +2285,7 @@
},
"script": {
"caption": "Skripty",
"description": "Správa skriptů",
"description": "Provádějte posloupnosti akcí",
"editor": {
"alias": "Název",
"default_name": "Nový skript",
@@ -2283,7 +2346,7 @@
"generic": "Nově načíst entity integrace Generic IP camera",
"generic_thermostat": "Nově načíst entity integrace Generic thermostat",
"group": "Nově načíst skupiny, skupiny entit a notifikační služby",
"heading": "Nastavení z YAML se načítá",
"heading": "Nové načtení YAML konfigurace",
"history_stats": "Nově načíst entity integrace History stats",
"homekit": "Nově načíst entity integrace HomeKit",
"input_boolean": "Nově načíst pomocníky - přepínače",
@@ -2333,7 +2396,7 @@
"confirm_remove": "Opravdu chcete odebrat štítek {tag}?",
"confirm_remove_title": "Odebrat štítek?",
"create_automation": "Vytvořit automatizaci se štítkem",
"description": "Správa štítků",
"description": "Spusťte automatizaci skenováním NFC tagu, QR kódu atd.",
"detail": {
"companion_apps": "doprovodné aplikace",
"create": "Vytvořit",
@@ -2368,10 +2431,11 @@
"username": "Uživatelské jméno"
},
"caption": "Uživatelé",
"description": "Správa uživatelů",
"description": "Správa uživatelských účtů pro Home Assistant",
"editor": {
"activate_user": "Aktivovat uživatele",
"active": "Aktivní",
"active_tooltip": "Určuje, zda se uživatel může přihlásit",
"admin": "Administrátor",
"caption": "Zobrazit uživatele",
"change_password": "Změnit heslo",
@@ -2564,7 +2628,7 @@
"value": "Hodnota",
"wakeup_interval": "Interval probuzení"
},
"description": "Spravujte svou síť Z-Wave",
"description": "Správa síťě Z-Wave",
"learn_more": "Další informace o Z-Wave",
"network_management": {
"header": "Správa sítě Z-Wave",
@@ -2703,11 +2767,11 @@
},
"templates": {
"all_listeners": "Tato šablona naslouchá všem změnám stavu.",
"description": "Šablony jsou vykreslovány pomocí Jinja2 šablonového enginu s některými specifickými rozšířeními pro Home Assistant.",
"description": "Šablony jsou vykreslovány pomocí šablonovacího systému Jinja2 s některými specifickými rozšířeními pro Home Assistant.",
"domain": "Doména",
"editor": "Editor šablon",
"entity": "Entita",
"jinja_documentation": "Dokumentace šablony Jinja2",
"jinja_documentation": "Dokumentace šablon Jinja2",
"listeners": "Tato šablona naslouchá následujícím změnám stavu:",
"no_listeners": "Tato šablona nenaslouchá žádným událostem a nebude automaticky aktualizována.",
"reset": "Obnovit ukázkovou šablonu",
@@ -2715,7 +2779,7 @@
"template_extensions": "Rozšíření šablony Home Assistant",
"time": "Tato šablona se aktualizuje na začátku každé minuty.",
"title": "Šablony",
"unknown_error_template": "Šablona vykreslování neznámých chyb"
"unknown_error_template": "Neznámá chyba při vykreslení šablony"
}
}
},
@@ -2780,7 +2844,7 @@
}
},
"changed_toast": {
"message": "Nastavení Lovelace pro tento dashboard bylo aktualizováno. Chcete obnovit stránku?",
"message": "Nastavení Lovelace pro tento ovládací panel bylo aktualizováno. Chcete obnovit stránku?",
"refresh": "Obnovit"
},
"editor": {
@@ -3121,17 +3185,17 @@
"save_config": {
"cancel": "Zahodit změnu",
"close": "Zavřít",
"empty_config": "Začít s prázdným dashboardem",
"empty_config": "Začít s prázdným ovládacím panel",
"header": "Převzít kontrolu nad vaší Lovelace UI",
"para": "Tento dashboard momentálně spravuje Home Assistant. Je automaticky aktualizován při přidání nové entity nebo Lovelace komponenty. Pokud převezmete kontrolu, nebudeme již provádět změny automaticky za vás. Vždy si můžete vytvořit nový dashboard na hraní.",
"para": "Tento ovládací panel momentálně spravuje Home Assistant. Je automaticky aktualizován při přidání nové entity nebo Lovelace komponenty. Pokud převezmete kontrolu, nebudeme již provádět změny automaticky za vás. Vždy si můžete vytvořit nový ovládací panel na hraní.",
"para_sure": "Opravdu chcete převzít kontrolu nad uživalským rozhraním ?",
"save": "Převzít kontrolu",
"yaml_config": "Abyste mohli snadněji začít, zde je aktuální nastavení tohoto dashboardu:",
"yaml_control": "Chcete-li převzít kontrolu v režimu YAML, vytvořte soubor YAML s názvem, který jste uvedli ve svém nastavení pro tento dashboard, nebo výchozí \"ui-lovelace.yaml\".",
"yaml_config": "Abyste mohli snadněji začít, zde je aktuální nastavení tohoto ovládacího panelu:",
"yaml_control": "Chcete-li převzít kontrolu v režimu YAML, vytvořte soubor YAML s názvem, který jste uvedli ve svém nastavení pro tento ovládací panel, nebo výchozí \"ui-lovelace.yaml\".",
"yaml_mode": "Používáte režim YAML, což znamená, že nemůžete změnit nastavení Lovelace z uživatelského rozhraní. Pokud chcete měnit Lovelace z uživatelského rozhraní, odstraňte \"mode: yaml\" z vašeho nastavení Lovelace v \"configuration.yaml\"."
},
"select_view": {
"dashboard_label": "Dashboard",
"dashboard_label": "Ovládací panel",
"header": "Vyberte pohled"
},
"sub-element-editor": {
@@ -3156,7 +3220,7 @@
},
"menu": {
"close": "Zavřít",
"configure_ui": "Upravit Dashboard",
"configure_ui": "Upravit ovládací panel",
"exit_edit_mode": "Ukončit režim úprav uživatelského rozhraní",
"help": "Nápověda",
"refresh": "Obnovit",
@@ -3390,10 +3454,13 @@
"change_password": {
"confirm_new_password": "Potvrďte nové heslo",
"current_password": "Současné heslo",
"error_new_is_old": "Nové heslo se musí lišit od aktuálního hesla",
"error_new_mismatch": "Zadaná nová hesla se neshodují",
"error_required": "Povinný",
"header": "Změnit heslo",
"new_password": "Nové heslo",
"submit": "Odeslat"
"submit": "Odeslat",
"success": "Heslo bylo úspěšně změněno"
},
"current_user": "Nyní jste přihlášeni jako {fullName}.",
"customize_sidebar": {
@@ -3402,9 +3469,9 @@
"header": "Změna pořadí a skrytí položek postranního panelu"
},
"dashboard": {
"description": "Vyberte výchozí dashboard pro toto zařízení.",
"dropdown_label": "Dashboard",
"header": "Dashboard"
"description": "Vyberte výchozí ovládací panel pro toto zařízení.",
"dropdown_label": "Ovládací panel",
"header": "Ovládací panel"
},
"enable_shortcuts": {
"description": "Povolte nebo zakažte klávesové zkratky pro provádění různých akcí v uživatelském rozhraní.",

View File

@@ -2,11 +2,13 @@
"config_entry": {
"disabled_by": {
"config_entry": "Konfigurationstilstand",
"device": "Enhed",
"integration": "Integration",
"user": "Bruger"
}
},
"groups": {
"owner": "Ejer",
"system-admin": "Administratorer",
"system-read-only": "Skrivebeskyttede brugere",
"system-users": "Brugere"
@@ -501,6 +503,8 @@
"continue": "Fortsæt",
"copied": "Kopieret",
"delete": "Slet",
"disable": "Deaktiver",
"enable": "Aktiver",
"error_required": "Påkrævet",
"loading": "Indlæser",
"menu": "Menu",
@@ -509,6 +513,8 @@
"overflow_menu": "Overløbsmenu",
"previous": "Forrige",
"refresh": "Opdater",
"remove": "Fjern",
"rename": "Omdøb",
"save": "Gem",
"successfully_deleted": "Slettet",
"successfully_saved": "Gemt",
@@ -529,6 +535,10 @@
"clear": "Ryd",
"show_areas": "Vis områder"
},
"blueprint-picker": {
"add_user": "Tilføj bruger",
"remove_user": "Fjern bruger"
},
"data-table": {
"no-data": "Ingen data",
"search": "Søg"
@@ -542,6 +552,7 @@
"clear": "Ryd",
"device": "Enhed",
"no_area": "Intet område",
"no_devices": "Du har ingen enheder",
"show_devices": "Vis enheder",
"toggle": "Til/fra"
},
@@ -618,6 +629,10 @@
"service-picker": {
"service": "Tjeneste"
},
"target-picker": {
"add_device_id": "Vælg enhed",
"remove_device_id": "Fjern enhed"
},
"user-picker": {
"add_user": "Tilføj bruger",
"no_user": "Ingen bruger",
@@ -759,6 +774,15 @@
"description": "Indstillingerne blev gemt."
}
},
"quick-bar": {
"commands": {
"server_control": {
"perform_action": "{action} server",
"restart": "Genstart",
"stop": "Stop"
}
}
},
"voice_command": {
"did_not_hear": "Home Assistant hørte ikke noget",
"error": "Ups, der er opstået en fejl",
@@ -867,6 +891,14 @@
"automation": {
"caption": "Automatiseringer",
"description": "Administrer automatiseringer",
"dialog_new": {
"thingtalk": {
"create": "Opret",
"header": "Beskriv automationen du vil lave",
"input_label": "Hvad skal denne automation gøre?",
"intro": "Og vi vil forsøge at skabe den for dig. For eksempel: Sluk lyset, når jeg forlader hjemmet."
}
},
"editor": {
"actions": {
"add": "Tilføj handling",
@@ -1006,6 +1038,7 @@
},
"unsupported_condition": "Ikke-understøttet betingelse: {condition}"
},
"copy_to_clipboard": "Kopier til udklipsholder",
"default_name": "Ny automatisering",
"description": {
"label": "Beskrivelse",
@@ -1146,6 +1179,25 @@
"only_editable": "Kun automatiseringer, der er defineret i 'automations.yaml', er redigerbare.",
"pick_automation": "Vælg automatisering for at redigere",
"show_info_automation": "Vis info om automatisering"
},
"thingtalk": {
"create": "Opret automation",
"task_selection": {
"header": "Opret en ny automation",
"introduction": "Skriv nedenfor, hvad denne automation skal gøre, og vi vil forsøge at konvertere den til en Home Assistant automation."
}
}
},
"blueprint": {
"add": {
"import_introduction": "Du kan importere skabeloner af andre brugere fra Github og {community_link} . Indtast URL'en til skabelonen nedenfor.",
"import_introduction_link": "Du kan importere tegninger af andre brugere fra Github og {community_link} . Indtast webadressen til tegningen nedenfor."
},
"overview": {
"headers": {
"domain": "Domæne",
"file_name": "Filnavn"
}
}
},
"cloud": {
@@ -1360,13 +1412,16 @@
"devices": {
"automation": {
"actions": {
"caption": "Når noget udløses..."
"caption": "Når noget udløses...",
"no_actions": "Ingen handlinger",
"unknown_action": "Ukendt handling"
},
"automations": "Automatiseringer",
"conditions": {
"caption": "Gør kun noget, hvis..."
},
"create": "Opret automatisering med enhed",
"create_disable": "Kan ikke oprette automation med deaktiveret enhed",
"no_automations": "Ingen automatiseringer",
"no_device_automations": "Der er ingen automatiseringer til rådighed for denne enhed.",
"triggers": {
@@ -1391,6 +1446,12 @@
"description": "Administrer tilsluttede enheder",
"device_info": "Enhedsoplysninger",
"device_not_found": "Enhed blev ikke fundet.",
"disabled": "Deaktiveret",
"disabled_by": {
"integration": "Integration",
"user": "Bruger"
},
"enabled_label": "Aktiver enhed",
"entities": {
"add_entities_lovelace": "Tilføj til Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {deaktiveret entitet}\n other {deaktiverede entiteter}\n}",
@@ -1400,14 +1461,24 @@
},
"name": "Navn",
"no_devices": "Ingen enheder",
"picker": {
"filter": {
"filter": "Filtrer",
"show_all": "Vis alle",
"show_disabled": "Vis deaktiverede enheder"
},
"search": "Søg efter enheder"
},
"scene": {
"create": "Opret scene med enhed",
"create_disable": "Kan ikke oprette scene med deaktiveret enhed",
"no_scenes": "Ingen scener",
"scenes": "Scener"
},
"scenes": "Scener",
"script": {
"create": "Opret script med enhed",
"create_disable": "Kan ikke oprette script med deaktiveret enhed",
"no_scripts": "Ingen scripts",
"scripts": "Scripts"
},
@@ -1432,12 +1503,14 @@
},
"filter": {
"filter": "Filtrer",
"show_all": "Vis alle",
"show_disabled": "Vis deaktiverede entiteter",
"show_readonly": "Vis skrivebeskyttede entiteter",
"show_unavailable": "Vis utilgængelige entiteter"
},
"header": "Entiteter",
"headers": {
"area": "Område",
"entity_id": "Entitets-id",
"integration": "Integration",
"name": "Navn",
@@ -1497,6 +1570,7 @@
"info": {
"built_using": "Bygget ved hjælp af",
"caption": "Oplysninger",
"copy_raw": "Rå tekst",
"custom_uis": "Tilpassede brugergrænseflader:",
"description": "Se oplysninger om din Home Assistant-installation",
"developed_by": "Udviklet af en masse fantastiske mennesker.",
@@ -1512,6 +1586,21 @@
"server": "server",
"source": "Kilde:",
"system_health_error": "System Health-komponenten er ikke indlæst. Føj 'system_health:' til 'config.yaml'",
"system_health": {
"checks": {
"homeassistant": {
"dev": "Udvikling",
"docker": "Docker",
"hassio": "HassOS",
"installation_type": "Installationstype",
"os_version": "Styresystem version",
"python_version": "Python version",
"timezone": "Tidszone",
"version": "Version"
}
},
"manage": "Administrer"
},
"title": "Info"
},
"integration_panel_move": {
@@ -1914,18 +2003,23 @@
"system_generated_users_not_editable": "Systemoprettede brugere kan ikke opdateres.",
"system_generated_users_not_removable": "Kan ikke fjerne systemgenererede brugere.",
"unnamed_user": "Unavngiven bruger",
"update_user": "Opdater"
"update_user": "Opdater",
"username": "Brugernavn"
},
"picker": {
"headers": {
"group": "Gruppe",
"is_active": "Aktiv",
"is_owner": "Ejer",
"name": "Navn",
"system": "System"
"system": "System",
"username": "Brugernavn"
}
},
"users_privileges_note": "Bruger-gruppen stadig under udvikling. Brugeren vil ikke være i stand til at administrere instansen via brugerfladen. Vi kigger stadig alle administrations-API-slutpunkter igennem for at sikre, at de korrekt begrænser adgangen til administratorer."
},
"zha": {
"add_device": "Tilføj enhed",
"add_device_page": {
"discovered_text": "Enheder vil dukke op her, når de er fundet.",
"discovery_text": "Fundne enheder vil dukke op her. Følg instruktionerne for din enhed(er) og sæt enhed(erne) i parringstilstand.",
@@ -1971,6 +2065,9 @@
"value": "Værdi"
},
"description": "Zigbee Home Automation-opsætning",
"device_pairing_card": {
"INITIALIZED_status_text": "Enheden er klar til brug"
},
"devices": {
"header": "Zigbee Home Automation - Enhed"
},
@@ -1986,6 +2083,7 @@
"unbind_button_label": "Fjern sammenføjning af gruppe"
},
"groups": {
"add_group": "Tilføj gruppe",
"add_members": "Tilføj medlemmer",
"adding_members": "Tilføjer medlemmer",
"caption": "Grupper",

View File

@@ -2,6 +2,7 @@
"config_entry": {
"disabled_by": {
"config_entry": "Konfigurationseintrag",
"device": "Gerät",
"integration": "Integration",
"user": "Benutzer"
}
@@ -531,7 +532,7 @@
"stay": "Bleiben",
"successfully_deleted": "Erfolgreich gelöscht",
"successfully_saved": "Erfolgreich gespeichert",
"undo": "Rückgängig machen",
"undo": "Rückgängig",
"yes": "Ja"
},
"components": {
@@ -546,12 +547,14 @@
"add_new": "Neuen Bereich hinzufügen...",
"area": "Bereich",
"clear": "Löschen",
"no_areas": "Du hast keine Bereiche",
"no_match": "Keine übereinstimmende Bereiche gefunden",
"show_areas": "Bereiche anzeigen"
},
"blueprint-picker": {
"add_user": "Benutzer hinzufügen",
"remove_user": "Benutzer entfernen",
"select_blueprint": "Wähle einen Bauplan aus"
"select_blueprint": "Wähle eine Vorlage aus"
},
"data-table": {
"no-data": "Keine Daten",
@@ -566,6 +569,8 @@
"clear": "Löschen",
"device": "Gerät",
"no_area": "Kein Bereich",
"no_devices": "Du hast keine Geräte",
"no_match": "Keine übereinstimmende Geräte gefunden",
"show_devices": "Geräte anzeigen",
"toggle": "Umschalten"
},
@@ -577,6 +582,7 @@
"entity-picker": {
"clear": "Löschen",
"entity": "Entität",
"no_match": "Keine übereinstimmende Entitäten gefunden",
"show_entities": "Entitäten anzeigen"
}
},
@@ -593,7 +599,7 @@
"changed_to_state": "wechselte zu {state}",
"cleared_device_class": "gelöscht (keine {device_class} erkannt)",
"detected_device_class": "erkannt {device_class}",
"rose": "gestiegen",
"rose": "aufgegangen",
"set": "einstellen",
"turned_off": "ausgeschaltet",
"turned_on": "eingeschaltet",
@@ -656,7 +662,7 @@
"media-player-browser": "Medien-Browser",
"no_items": "Keine Einträge",
"no_local_media_found": "Keine lokalen Medien gefunden",
"no_media_folder": "Es sieht so aus, als hätten Sie noch kein Medienverzeichnis erstellt.",
"no_media_folder": "Es sieht so aus, als hättest du noch kein Medienverzeichnis erstellt.",
"pick": "Auswählen",
"pick-media": "Medien auswählen",
"play": "Abspielen",
@@ -710,6 +716,16 @@
"service-picker": {
"service": "Dienst"
},
"target-picker": {
"add_area_id": "Bereich auswählen",
"add_device_id": "Gerät auswählen",
"add_entity_id": "Entität auswählen",
"expand_area_id": "Erweitere diesen Bereich in einzelne Geräte und Entitäten. Nach der Erweiterung werden die Geräte und Entitäten nicht aktualisiert, wenn sich der Bereich ändert.",
"expand_device_id": "Erweitern Sie dieses Gerät in separate Entitäten. Nach dem Erweitern werden die Entitäten nicht aktualisiert, wenn sich das Gerät ändert.",
"remove_area_id": "Bereich entfernen",
"remove_device_id": "Gerät entfernen",
"remove_entity_id": "Entität entfernen"
},
"user-picker": {
"add_user": "Benutzer hinzufügen",
"no_user": "Kein Benutzer",
@@ -733,6 +749,7 @@
"editor": {
"confirm_delete": "Möchtest du diesen Eintrag wirklich löschen?",
"delete": "Löschen",
"device_disabled": "Das Gerät dieser Entität ist deaktiviert.",
"enabled_cause": "Deaktiviert durch {cause}.",
"enabled_delay_confirm": "Die aktivierten Entitäten werden in {delay} Sekunden zu Home Assistant hinzugefügt",
"enabled_description": "Deaktivierte Entitäten werden nicht zu Home Assistant hinzugefügt.",
@@ -743,6 +760,7 @@
"icon_error": "Symbole sollten das Format 'Präfix:iconname' haben, z. B. 'mdi:home'",
"name": "Namen",
"note": "Hinweis: Dies funktioniert möglicherweise noch nicht bei allen Integrationen.",
"open_device_settings": "Geräteeinstellungen öffnen",
"unavailable": "Diese Entität ist derzeit nicht verfügbar.",
"update": "Aktualisieren"
},
@@ -798,7 +816,7 @@
"pattern": "Regex-Muster für die clientseitige Validierung",
"text": "Text"
},
"platform_not_loaded": "Die {platform} -Komponente ist nicht geladen. Füge sie bitte deiner Konfiguration hinzu. Entweder durch Hinzufügen von 'default_config:' oder ''{platform}:''.",
"platform_not_loaded": "Die {platform}-Integration ist nicht geladen. Bitte füge sie deiner Konfiguration hinzu, indem du entweder 'default_config:' oder ''{platform}:'' einfügst.",
"required_error_msg": "Dieses Feld ist erforderlich",
"timer": {
"duration": "Dauer"
@@ -822,7 +840,7 @@
"edit": "Entität bearbeiten",
"history": "Verlauf",
"last_changed": "Zuletzt geändert",
"last_updated": "Letztes Update",
"last_updated": "Zuletzt aktualisiert",
"person": {
"create_zone": "Zone vom aktuellen Standort erstellen"
},
@@ -883,7 +901,7 @@
"navigation": {
"areas": "Bereiche",
"automation": "Automatisierungen",
"blueprint": "Baupläne",
"blueprint": "Vorlagen",
"core": "Allgemein",
"customize": "Anpassungen",
"devices": "Geräte",
@@ -905,13 +923,13 @@
},
"reload": {
"automation": "Automationen neu laden",
"command_line": "Komandozeilen Entätien neu laden",
"core": "Positionsdaten & Anpassungen neu laden",
"command_line": "Komandozeilenentätien neu laden",
"core": "Positionsdaten und Anpassungen neu laden",
"filesize": "Dateigröße-Entitäten neu laden",
"filter": "Filter Entitäten neu laden",
"generic": "Allgemeine IP Kamera Entitäten neu laden",
"generic_thermostat": "Allgemeine Thermostat Entitäte neu laden",
"group": "Gruppen, Gruppen Entitäten und Benachrichtigungsservices neu laden",
"filter": "Filterentitäten neu laden",
"generic": "Allgemeine IP-Kamera-Entitäten neu laden",
"generic_thermostat": "Allgemeine Thermostat-Entitäten neu laden",
"group": "Gruppen, Gruppenentitäten und Benachrichtigungsservices neu laden",
"history_stats": "Verlaufsstatistiken neu laden",
"homekit": "HomeKit neu laden",
"input_boolean": "Input-Booleans neu laden",
@@ -924,16 +942,16 @@
"person": "Personen neu laden",
"ping": "Binäre-Ping-Entitäten neu laden",
"reload": "{domain} neu laden",
"rest": "Rest Entitäten und Benachrichtigunsdienste neu laden",
"rest": "REST-Entitäten und Benachrichtigunsdienste neu laden",
"rpi_gpio": "Raspberry Pi GPIO Entitäten neu laden",
"scene": "Szenen neu laden",
"script": "Skripte neu laden",
"smtp": "SMTP-Benachrichtigungsdienst neu laden",
"statistics": "Statistik Entitäten neu laden",
"statistics": "Statistikentitäten neu laden",
"telegram": "Telegram-Benachrichtigungsdienst neu laden",
"template": "Templates neu laden",
"trend": "Trend Entitäten neu laden",
"universal": "Universelle Medien Player Entitäten neu laden",
"trend": "Trend-Entitäten neu laden",
"universal": "Universelle Medien-Player-Entitäten neu laden",
"zone": "Zonen neu laden"
},
"server_control": {
@@ -1021,16 +1039,16 @@
"link_profile_page": "deine Profilseite"
},
"areas": {
"caption": "Bereichsregister",
"caption": "Bereiche",
"data_table": {
"area": "Bereich",
"devices": "Geräte"
},
"delete": {
"confirmation_text": "Alle Geräte in diesem Bereich werden nicht mehr zugewiesen sein.",
"confirmation_text": "Die Zuordnung aller Geräte zu diesem Bereich wird aufgelöst.",
"confirmation_title": "Möchtest du diesen Bereich wirklich löschen?"
},
"description": "Bereiche in deinem Zuhause verwalten",
"description": "Geräte und Entitäten in Bereiche gruppieren",
"editor": {
"area_id": "Bereich-ID",
"create": "Erstellen",
@@ -1047,15 +1065,15 @@
"integrations_page": "Integrationsseite",
"introduction": "In Bereichen wird festgelegt, wo sich Geräte befinden. Diese Informationen werden in Home Assistant verwendet, um Sie bei der Organisation Ihrer Benutzeroberfläche, Berechtigungen und Integrationen mit anderen Systemen zu unterstützen.",
"introduction2": "Um Geräte in einem Bereich zu platzieren, navigiere mit dem Link unten zur Integrationsseite und klicke dann auf eine konfigurierte Integration, um zu den Gerätekarten zu gelangen.",
"no_areas": "Sieht aus, als hätten Sie noch keine Bereiche!"
"no_areas": "Sieht aus als hättest du noch keine Bereiche!"
}
},
"automation": {
"caption": "Automatisierung",
"description": "Automatisierungen verwalten",
"caption": "Automatisierungen",
"description": "Individuelle Regeln für dein Zuhause erstellen",
"dialog_new": {
"blueprint": {
"use_blueprint": "Einen Bauplan benutzen"
"use_blueprint": "Eine Vorlage verwenden"
},
"header": "Erstelle eine neue Automatisierung",
"how": "Wie möchtest du deine neue Automatisierung erstellen?",
@@ -1064,7 +1082,7 @@
"create": "Erstellen",
"header": "Beschreibe die Automatisierung, die du erstellen möchtest",
"input_label": "Was soll diese Automatisierung tun?",
"intro": "Und wir werden versuchen, es für dich zu erstellen. Zum Beispiel: Schalten das Licht aus, wenn ich gehe."
"intro": "Und wir werden versuchen, sie für dich zu erstellen. Zum Beispiel: Schalte das Licht aus, wenn ich gehe."
}
},
"editor": {
@@ -1116,11 +1134,11 @@
"label": "Anzahl"
},
"until": {
"conditions": "Bis Bedingungen",
"conditions": "Bis-Bedingungen",
"label": "Bis"
},
"while": {
"conditions": "Während Bedingungen",
"conditions": "Während-Bedingungen",
"label": "Während"
}
}
@@ -1148,12 +1166,12 @@
},
"alias": "Name",
"blueprint": {
"blueprint_to_use": "Zu verwendender Bauplan",
"header": "Bauplan",
"blueprint_to_use": "Zu verwendende Vorlage",
"header": "Vorlage",
"inputs": "Eingänge",
"manage_blueprints": "Baupläne verwalten",
"no_blueprints": "Du hast keine Baupläne",
"no_inputs": "Dieser Bauplan hat keine Eingänge."
"manage_blueprints": "Vorlagen verwalten",
"no_blueprints": "Du hast keine Vorlagen",
"no_inputs": "Diese Vorlage hat keine Eingänge."
},
"conditions": {
"add": "Bedingung hinzufügen",
@@ -1248,7 +1266,7 @@
"queued": "Länge der Warteschlange"
},
"modes": {
"description": "Der Modus steuert, was passiert, wenn ein Skript aufgerufen wird, während es noch von einem oder mehreren vorherigen Aufrufen ausgeführt wird. Überprüfen Sie den {documentation_link} für weitere Informationen.",
"description": "Der Modus steuert, was passiert, wenn ein Skript aufgerufen wird, während es noch von einem oder mehreren vorherigen Aufrufen ausgeführt wird. Lies {documentation_link} für weitere Informationen.",
"documentation": "Automatisierungs-Dokumentation",
"label": "Modus",
"parallel": "Parallel",
@@ -1342,7 +1360,7 @@
"time": {
"at": "Um",
"label": "Zeit",
"type_input": "Wert eines Datum/Zeit-Helfers",
"type_input": "Wert eines Datums-/Zeit-Helfers",
"type_value": "Feste Zeit"
},
"webhook": {
@@ -1399,31 +1417,37 @@
},
"blueprint": {
"add": {
"error_no_url": "Bitte gebe die URL des Bauplans ein.",
"header": "Neuen Bauplan hinzufügen",
"import_btn": "Bauplan importieren",
"import_header": "{name}({domain}) importieren",
"import_introduction": "Du kannst Baupläne anderer Benutzer aus GitHub und den Community-Foren importieren. Gib die URL des Bauplans unten ein.",
"importing": "Bauplan wird importiert...",
"save_btn": "Bauplan speichern",
"saving": "Bauplan wir gespeichert...",
"unsupported_blueprint": "Dieser Bauplan wird nicht unterstützt",
"url": "URL des Bauplans"
"community_forums": "Community-Foren",
"error_no_url": "Bitte gebe die URL der Vorlage ein.",
"file_name": "Vorlagenpfad",
"header": "Vorlage importieren",
"import_btn": "Vorschau Vorlage",
"import_header": "Vorlage \"{name}\"",
"import_introduction": "Du kannst Vorlagen anderer Benutzer aus GitHub und den Community-Foren importieren. Gib die URL der Vorlage unten ein.",
"import_introduction_link": "Du kannst Vorlagen anderer Benutzer aus GitHub und den {community_link} importieren. Gib unten die URL der Vorlage ein.",
"importing": "Vorlage wird geladen...",
"raw_blueprint": "Inhalt der Vorlage",
"save_btn": "Vorlage importieren",
"saving": "Vorlage wird importiert...",
"unsupported_blueprint": "Diese Vorlage wird nicht unterstützt",
"url": "URL der Vorlage"
},
"caption": "Baupläne",
"description": "Baupläne verwalten",
"caption": "Vorlagen",
"description": "Vorlagen verwalten",
"overview": {
"add_blueprint": "Bauplan hinzufügen",
"confirm_delete_header": "Diesen Bauplan löschen?",
"confirm_delete_text": "Bist du sicher, dass du diesen Bauplan löschen möchtest?",
"header": "Bauplan-Editor",
"add_blueprint": "Vorlage hinzufügen",
"confirm_delete_header": "Diese Vorlage löschen?",
"confirm_delete_text": "Bist du sicher, dass du diese Vorlage löschen möchtest?",
"delete_blueprint": "Vorlage löschen",
"discover_more": "Entdecke weitere Vorlagen",
"header": "Vorlagen-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",
"introduction": "Mit der Vorlagenkonfiguration kannst du deine Vorlagen importieren und verwalten.",
"learn_more": "Erfahre mehr über die Benutzung von Vorlagen",
"use_blueprint": "Automatisierung erstellen"
}
},
@@ -1507,7 +1531,7 @@
"title": "Alexa"
},
"caption": "Home Assistant Cloud",
"description_features": "Fernsteuerung und Integration mit Alexa und Google Assistant.",
"description_features": "Fernsteuerung und Integration mit Alexa und Google Assistant",
"description_login": "Angemeldet als {email}",
"description_not_login": "Nicht angemeldet",
"dialog_certificate": {
@@ -1602,7 +1626,7 @@
},
"core": {
"caption": "Allgemein",
"description": "Bearbeite die allgemeine Konfiguration von Home Assistant",
"description": "Mengeneinheiten, Standort, Zeitzone & andere allgemeine Parameter",
"section": {
"core": {
"core_config": {
@@ -1634,7 +1658,7 @@
"attributes_override": "Du kannst sie überschreiben, wenn du möchtest.",
"attributes_set": "Die folgenden Attribute der Entität sind programmatisch festgelegt.",
"caption": "Anpassung",
"description": "Elemente anpassen",
"description": "Entitäten individuell anpassen",
"different_include": "Möglich über eine Domain, einen Glob oder einen anderen Include.",
"pick_attribute": "Wähle ein Attribut zum Überschreiben aus.",
"picker": {
@@ -1664,6 +1688,7 @@
"unknown_condition": "Unbekannte Bedingung"
},
"create": "Automatisierung mit Gerät erstellen",
"create_disable": "Kann keine Automatisierung mit deaktiviertem Gerät erstellen",
"no_automations": "Keine Automatisierungen",
"no_device_automations": "Für dieses Gerät sind keine Automatisierungen verfügbar.",
"triggers": {
@@ -1677,7 +1702,7 @@
"caption": "Geräte",
"confirm_delete": "Möchtest du dieses Gerät wirklich löschen?",
"confirm_rename_entity_ids": "Möchten Sie auch die Entitäts-IDs Ihrer Entitäten umbenennen?",
"confirm_rename_entity_ids_warning": "Dies ändert keine Konfiguration (wie Automatisierungen, Skripte, Szenen, Dashboards), die derzeit diese Entitäten verwendet! Sie müssen sie selbst aktualisieren, um die neuen Entitäts-IDs zu verwenden!",
"confirm_rename_entity_ids_warning": "Dies ändert keine Konfiguration (wie Automatisierungen, Skripte, Szenen, Dashboards), die derzeit diese Entitäten verwendet! Du musst sie selbst aktualisieren, um die neuen Entitäts-IDs zu verwenden!",
"data_table": {
"area": "Bereich",
"battery": "Batterie",
@@ -1692,23 +1717,43 @@
"description": "Verbundene Geräte verwalten",
"device_info": "Geräteinformationen",
"device_not_found": "Gerät nicht gefunden.",
"disabled": "Deaktiviert",
"disabled_by": {
"config_entry": "Konfigurationseintrag",
"integration": "Integration",
"user": "Benutzer"
},
"enabled_cause": "Das Gerät ist durch {cause} deaktiviert.",
"enabled_description": "Deaktivierte Geräte werden nicht angezeigt und zum Gerät gehörende Entitäten werden deaktiviert und nicht zum Home Assistant hinzugefügt.",
"enabled_label": "Gerät aktivieren",
"entities": {
"add_entities_lovelace": "Zu Lovelace hinzufügen",
"disabled_entities": "+{count} {count, plural,\n one {deaktivierte Entität}\n other {deaktivierte Entitäten}\n}",
"entities": "Entitäten",
"hide_disabled": "Ausblenden deaktiviert",
"hide_disabled": "Deaktivierte ausblenden",
"none": "Dieses Gerät hat keine Entitäten"
},
"name": "Name",
"no_devices": "Keine Geräte",
"picker": {
"filter": {
"filter": "Filter",
"hidden_devices": "{number} {number, plural,\n one {verstecktes Gerät}\n other {versteckte Geräte}\n}",
"show_all": "Alle anzeigen",
"show_disabled": "Deaktivierte Geräte anzeigen"
},
"search": "Geräte suchen"
},
"scene": {
"create": "Szene mit Gerät erstellen",
"create_disable": "Kann keine Szene mit deaktiviertem Gerät erstellen",
"no_scenes": "Keine Szenen",
"scenes": "Szenen"
},
"scenes": "Szenen",
"script": {
"create": "Szene mit Gerät erstellen",
"create_disable": "Kann kein Skript mit deaktiviertem Gerät erstellen",
"no_scripts": "Keine Skripte",
"scripts": "Skripte"
},
@@ -1774,7 +1819,7 @@
"header": "Home Assistant konfigurieren",
"helpers": {
"caption": "Helfer",
"description": "Elemente verwalten, die beim Aufbau von Automatisierungen helfen können.",
"description": "Elemente verwalten, die beim Aufbau von Automatisierungen helfen",
"dialog": {
"add_helper": "Helfer hinzufügen",
"add_platform": "{platform} hinzufügen",
@@ -1806,7 +1851,7 @@
"copy_github": "Für GitHub",
"copy_raw": "Roher Text",
"custom_uis": "Benutzerdefinierte UIs:",
"description": "Informationen über deine Home Assistant Installation",
"description": "Version, Systemzustand und Links zur Dokumentation",
"developed_by": "Entwickelt von einem Haufen toller Leute.",
"documentation": "Dokumentation",
"frontend": "Frontend-UI",
@@ -1886,7 +1931,7 @@
"options": "Optionen",
"reload": "Neu laden",
"reload_confirm": "Die Integration wurde neu geladen",
"reload_restart_confirm": "Home Assistant neustarten, um das Neuladen dieser Integration abzuschließen",
"reload_restart_confirm": "Home Assistant neu starten, um das Neuladen dieser Integration abzuschließen",
"rename": "Umbenennen",
"restart_confirm": "Starte Home Assistant neu, um das Entfernen dieser Integration abzuschließen",
"services": "{count} {count, plural,\n one {Dienst}\n other {Dienste}\n}",
@@ -1912,7 +1957,7 @@
},
"configure": "Konfigurieren",
"configured": "Konfiguriert",
"description": "Verbundene Integrationen verwalten",
"description": "Integrationen zu Diensten, Geräten, usw. verwalten",
"details": "Details zur Integration",
"discovered": "Entdeckt",
"home_assistant_website": "Home Assistant Website",
@@ -1930,7 +1975,7 @@
"integration": "Integration",
"integration_not_found": "Integration nicht gefunden.",
"new": "Richte eine neue Integration ein",
"no_integrations": "Du hast anscheinend noch keine Integrationen konfiguriert. Klicke auf die Schaltfläche unten, um Deine erste Integration hinzuzufügen!",
"no_integrations": "Du hast anscheinend noch keine Integrationen konfiguriert. Klicke auf die Schaltfläche unten, um eine erste Integration hinzuzufügen!",
"none": "Noch nichts konfiguriert",
"none_found": "Keine Integrationen gefunden",
"none_found_detail": "Passe deine Suchkriterien an.",
@@ -1945,7 +1990,7 @@
"logs": {
"caption": "Logs",
"clear": "Leeren",
"description": "Die Home Assistant Logs anschauen",
"description": "Home Assistant Logs einsehen",
"details": "Protokolldetails ( {level} )",
"load_full_log": "Vollständiges Home Assistant-Protokoll laden",
"loading_log": "Fehlerprotokoll wird geladen...",
@@ -1962,7 +2007,7 @@
"cant_edit_yaml": "In YAML definierte Dashboards können nicht über die Benutzeroberfläche bearbeitet werden. Du kannst sie aber in der configuration.yaml ändern.",
"caption": "Dashboards",
"conf_mode": {
"storage": "UI gesteuert",
"storage": "Grafischer Editor",
"yaml": "YAML-Datei"
},
"confirm_delete": "Bist du sicher, dass du dieses Dashboard löschen möchtest?",
@@ -1990,14 +2035,14 @@
"conf_mode": "Konfigurationsmethode",
"default": "Standard",
"filename": "Dateiname",
"require_admin": "Nur für Administratoren",
"require_admin": "Nur Admin",
"sidebar": "In der Seitenleiste anzeigen",
"title": "Titel"
},
"open": "Öffnen"
}
},
"description": "Konfiguriere deine Lovelace-Dashboards",
"description": "Erstelle individuelle Oberflächen, um dein Zuhause zu steuern",
"resources": {
"cant_edit_yaml": "Du verwendest Lovelace im YAML-Modus. Daher kannst du deine Ressourcen nicht über die Benutzeroberfläche verwalten. Verwalte sie in der configuration.yaml.",
"caption": "Ressourcen",
@@ -2012,7 +2057,7 @@
"url": "URL",
"url_error_msg": "URL ist ein Pflichtfeld",
"warning_header": "Sei vorsichtig!",
"warning_text": "Das Hinzufügen von Ressourcen kann gefährlich sein. Stelle sicher, dass du die Quelle der Ressource kennst und ihr vertraust. Schlechte Ressourcen können dein System ernsthaft beschädigen."
"warning_text": "Das Hinzufügen von Ressourcen kann gefährlich sein. Stelle sicher, dass du die Quelle der Ressource kennst und ihr vertraust. Ressourcen aus bösartigen Quellen können dein System ernsthaft beschädigen."
},
"picker": {
"add_resource": "Ressource hinzufügen",
@@ -2055,7 +2100,7 @@
"node_id": "Knoten-ID",
"ozw_instance": "OpenZWave-Instanz",
"query_stage": "Abfragephase",
"wakeup_instructions": "Weckanleitung",
"wakeup_instructions": "Aufweckanleitung",
"zwave": "Z-Wave"
},
"device_info": {
@@ -2094,12 +2139,12 @@
},
"network": {
"header": "Netzwerkverwaltung",
"introduction": "Verwalten Sie netzwerkweite Funktionen.",
"introduction": "Verwalten netzwerkweiter Funktionen.",
"node_count": "{count} Knoten"
},
"node_config": {
"header": "Knotenkonfiguration",
"help_source": "Konfigurationsparameterbeschreibungen und Hilfetexte werden vom OpenZWave-Projekt bereitgestellt.",
"help_source": "Hilfetexte und Beschreibungen der Konfigurationsparameter stellt das OpenZWave-Projekt zur Verfügung.",
"introduction": "Verwalten Sie die verschiedenen Konfigurationsparameter für einen Z-Wave Knoten.",
"wakeup_help": "Batteriebetriebene Knoten müssen wach sein, um ihre Konfiguration zu ändern. Wenn der Knoten nicht aktiv ist, versucht OpenZWave beim nächsten Aufwachen, die Konfiguration des Knotens zu aktualisieren. Dies kann mehrere Stunden (oder Tage) später sein. Führen Sie die folgenden Schritte aus, um Ihr Gerät zu aktivieren:"
},
@@ -2152,8 +2197,8 @@
},
"select_instance": {
"header": "OpenZWave Instanz auswählen",
"introduction": "Sie haben mehr als eine OpenZWave-Instanz ausgeführt. Welche Instanz möchten Sie verwalten?",
"none_found": "Wir haben keine OpenZWave-Instanz gefunden. Wenn Sie der Meinung sind, dass dies nicht korrekt ist, überprüfen Sie Ihre OpenZWave- und MQTT-Setups und stellen Sie sicher, dass der Home Assistant mit Ihrem MQTT-Broker kommunizieren kann."
"introduction": "Du hast mehr als eine aktive OpenZWave-Instanz. Welche möchtest du verwalten?",
"none_found": "Wir haben keine OpenZWave-Instanz gefunden. Wenn du der Meinung bist, dass dies nicht korrekt ist, überprüfe deine OpenZWave- und MQTT-Setups und stelle sicher, dass der Home Assistant mit dem MQTT-Broker kommunizieren kann."
},
"services": {
"add_node": "Knoten hinzufügen",
@@ -2167,11 +2212,11 @@
"confirm_delete": "Möchtest du diese Person wirklich löschen?",
"confirm_delete2": "Alle Geräte, die zu dieser Person gehören, werden nicht mehr zugeordnet.",
"create_person": "Person erstellen",
"description": "Personen verwalten, denen Home Assistant folgt.",
"description": "Personen verwalten, denen Home Assistant folgt",
"detail": {
"admin": "Administrator",
"allow_login": "Erlauben Sie dieser Person, sich einzuloggen.",
"confirm_delete_user": "Bist Du sicher, dass Du das Benutzerkonto von {name} löschen möchtest? Du kannst der Person immer noch folgen, aber sie kann sich nicht mehr anmelden.",
"allow_login": "Erlaube dieser Person, sich einzuloggen.",
"confirm_delete_user": "Bist Du sicher, dass Du das Benutzerkonto für {name} löschen möchtest? Du kannst der Person immer noch folgen, aber sie kann sich nicht mehr anmelden.",
"create": "Erstellen",
"delete": "Löschen",
"device_tracker_intro": "Wähle die Geräte, die dieser Person gehören.",
@@ -2196,7 +2241,7 @@
"scene": {
"activated": "Aktivierte Szene {name}.",
"caption": "Szenen",
"description": "Szenen verwalten",
"description": "Gerätezustände erfassen und später einfach wieder abrufen",
"editor": {
"default_name": "Neue Szene",
"devices": {
@@ -2214,7 +2259,7 @@
"without_device": "Entitäten ohne Gerät"
},
"icon": "Symbol",
"introduction": "Benutze Szenen um deinem Zuhause Leben einzuhauchen.",
"introduction": "Benutze Szenen, um deinem Zuhause Leben einzuhauchen.",
"load_error_not_editable": "Nur Szenen in der scenes.yaml sind editierbar.",
"load_error_unknown": "Fehler beim Laden der Szene ({err_no}).",
"name": "Name",
@@ -2239,8 +2284,8 @@
}
},
"script": {
"caption": "Skript",
"description": "Skripte verwalten",
"caption": "Skripte",
"description": "Eine Sequenz aus Aktionen ausführen",
"editor": {
"alias": "Name",
"default_name": "Neues Skript",
@@ -2259,7 +2304,7 @@
"queued": "Länge der Warteschlange"
},
"modes": {
"description": "Der Modus steuert, was passiert, wenn ein Skript aufgerufen wird, während es noch von einem oder mehreren vorherigen Aufrufen ausgeführt wird. Überprüfen Sie den {documentation_link} für weitere Informationen.",
"description": "Der Modus steuert, was passiert, wenn ein Skript aufgerufen wird, während es noch von einem oder mehreren vorherigen Aufrufen ausgeführt wird. Lies {documentation_link} für weitere Informationen.",
"documentation": "Skript-Dokumentation",
"label": "Modus",
"parallel": "Parallel",
@@ -2313,7 +2358,7 @@
"min_max": "Min/Max-Entitäten neu laden",
"mqtt": "Lade manuell konfigurierte MQTT-Entitäten neu",
"person": "Personen neu laden",
"ping": "Binäre Ping-Sensorentitäten neu laden",
"ping": "Binäre Ping Sensorentitäten neu laden",
"reload": "{domain} neu laden",
"rest": "Rest Entitäten und Benachrichtigungsdienste neu laden",
"rpi_gpio": "Raspberry Pi GPIO Entitäten neu laden",
@@ -2323,7 +2368,7 @@
"statistics": "Statistik-Entitäten neu laden",
"telegram": "Telegram-Benachrichtigungsdienste neu laden",
"template": "Vorlagenentitäten neu laden",
"trend": "Trendentitäten neu laden",
"trend": "Trend-Entitäten neu laden",
"universal": "Universelle Media Player-Entitäten neu laden",
"zone": "Zonen neu laden"
},
@@ -2339,7 +2384,7 @@
"check_config": "Konfiguration prüfen",
"heading": "Konfiguration überprüfen",
"introduction": "Überprüfen Sie Ihre Konfiguration, wenn Sie kürzlich Änderungen vorgenommen haben und sicherstellen möchten, dass alle Änderungen gültig sind",
"invalid": "Konfiguration ungültig",
"invalid": "Konfiguration fehlerhaft",
"valid": "Konfiguration in Ordnung"
}
}
@@ -2351,7 +2396,7 @@
"confirm_remove": "Möchtest du den Tag {tag} wirklich entfernen?",
"confirm_remove_title": "Tag entfernen?",
"create_automation": "Automatisierung mit NFC Tag erstellen",
"description": "NFC Tags verwalten",
"description": "Automatisierungen auslösen wenn NFC Tag, QR Code, usw. gescannt wird",
"detail": {
"companion_apps": "Mobile Apps",
"create": "Erstellen",
@@ -2363,7 +2408,7 @@
"tag_id": "NFC Tag ID",
"tag_id_placeholder": "Automatisch generiert, wenn leer gelassen",
"update": "Aktualisieren",
"usage": "Ein Tag kann eine Automatisierung auslösen, wenn er gescannt wird. Sie können NFC-Tags, QR-Codes oder jede andere Art von Tags verwenden. Verwenden Sie unsere {companion_link}, um diesen Tag in ein programmierbares NFC-Tag zu schreiben oder einen QR-Code zu erstellen."
"usage": "Ein Tag kann eine Automatisierung auslösen, wenn er gescannt wird. Du kannst NFC-Tags, QR-Codes oder jede andere Art von Tags verwenden. Verwende unsere {companion_link}, um diesen Tag in ein programmierbares NFC-Tag zu schreiben oder einen QR-Code zu erstellen."
},
"edit": "Bearbeiten",
"headers": {
@@ -2386,10 +2431,11 @@
"username": "Benutzername"
},
"caption": "Benutzer",
"description": "Benutzer verwalten",
"description": "Home Assistant Benutzerkonten verwalten",
"editor": {
"activate_user": "Benutzer aktivieren",
"active": "Aktiv",
"active_tooltip": "Steuert, ob sich der Benutzer anmelden kann",
"admin": "Administrator",
"caption": "Benutzer anzeigen",
"change_password": "Passwort ändern",
@@ -2398,14 +2444,14 @@
"delete_user": "Benutzer löschen",
"group": "Gruppe",
"id": "ID",
"name": "Name",
"name": "Anzeigename",
"new_password": "Neues Passwort",
"owner": "Besitzer",
"password_changed": "Das Passwort wurde erfolgreich geändert",
"system_generated": "System generiert",
"system_generated": "Systemgeneriert",
"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",
"system_generated_users_not_removable": "Systemgenerierte Benutzer können nicht entfernt werden.",
"unnamed_user": "Namenloser Benutzer",
"update_user": "Aktualisieren",
"username": "Benutzername"
},
@@ -2415,12 +2461,12 @@
"group": "Gruppe",
"is_active": "Aktiv",
"is_owner": "Besitzer",
"name": "Name",
"system": "System",
"name": "Anzeigename",
"system": "System generiert",
"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."
"users_privileges_note": "Benutzergruppen befinden sich derzeit noch in Entwicklung. Der Benutzer wird nicht in der Lage sein, Änderungen an der Instanz über die Benutzeroberfläche vorzunehmen. Derzeit überprüfen wir noch alle API Endpunkte und stellen sicher, dass diese nur von Administratoren genutzt werden können."
},
"zha": {
"add_device": "Gerät hinzufügen",
@@ -2474,8 +2520,10 @@
"CONFIGURED_status_text": "Initialisieren",
"INITIALIZED": "Initialisierung abgeschlossen",
"INITIALIZED_status_text": "Das Gerät ist einsatzbereit",
"INTERVIEW_COMPLETE": "Interview abgeschlossen",
"INTERVIEW_COMPLETE_status_text": "Konfigurieren",
"PAIRED": "Gerät gefunden"
"PAIRED": "Gerät gefunden",
"PAIRED_status_text": "Interview starten"
},
"devices": {
"header": "Zigbee Home Automation - Gerät"
@@ -2547,7 +2595,7 @@
"configured_in_yaml": "Zonen, die über configuration.yaml konfiguriert wurden, können nicht über die Benutzeroberfläche bearbeitet werden.",
"confirm_delete": "Möchtest du diesen Bereich wirklich löschen?",
"create_zone": "Zone erstellen",
"description": "Verwalte die Zonen, in denen du Personen folgen möchtest.",
"description": "Verwalte die Zonen, in denen du Personen folgen möchtest",
"detail": {
"create": "Erstellen",
"delete": "Löschen",
@@ -2608,12 +2656,12 @@
"add_to_group": "Zur Gruppe hinzufügen",
"entities": "Entitäten dieses Knotens",
"entity_info": "Entitätsinformationen",
"exclude_entity": "Schließe diese Entität vom Home Assistant aus",
"exclude_entity": "Entität von Home Assistant ausschließen",
"group": "Gruppe",
"header": "Z-Wave-Knotenverwaltung",
"introduction": "Führe Z-Wave-Befehle aus, die einen einzelnen Knoten betreffen. Wähle einen Knoten aus, um eine Liste der verfügbaren Befehle anzuzeigen.",
"max_associations": "Max Assoziationen:",
"node_group_associations": "Knotengruppenzuordnungen",
"max_associations": "Maximale Zuordnungen:",
"node_group_associations": "Zuordnungen zu Kontengruppen",
"node_protection": "Knotenschutz",
"node_to_control": "Zu steuernder Knoten",
"nodes": "Knoten",
@@ -2708,8 +2756,8 @@
"filter_attributes": "Attribute filtern",
"filter_entities": "Entitäten filtern",
"filter_states": "Zustände filtern",
"last_changed": "Letzte Änderung",
"last_updated": "Letzte Aktualisierung",
"last_changed": "Zuletzt geändert",
"last_updated": "Zuletzt aktualisiert",
"more_info": "Mehr Info",
"no_entities": "Keine Entitäten",
"set_state": "Status setzen",
@@ -2802,7 +2850,7 @@
"editor": {
"action-editor": {
"actions": {
"call-service": "Dienst ausführen",
"call-service": "Dienst aufrufen",
"default_action": "Standardaktion",
"more-info": "Mehr Info",
"navigate": "Navigieren",
@@ -2817,11 +2865,11 @@
"card": {
"alarm-panel": {
"available_states": "Verfügbare Zustände",
"description": "Mit der Alarmzentralen-Karte kannst du die Integrationen Ihrer Alarmzentrale aktivieren und deaktivieren.",
"description": "Mit der Alarmzentralen-Karte kannst du integrierte Alarmzentralen scharfschalten oder deaktivieren.",
"name": "Alarmpanel"
},
"button": {
"default_action_help": "Die Standardaktion hängt von den Funktionen der Entität ab, sie wird entweder umgeschaltet oder die weiteren Informationen werden angezeigt.",
"default_action_help": "Die Standardaktion hängt von den Funktionen der Entität ab: sie wird entweder umgeschaltet oder die weiteren Informationen werden angezeigt.",
"description": "Mit der Schaltflächen-Karte kannst du Schaltflächen hinzufügen, um Aufgaben auszuführen.",
"name": "Schaltfläche"
},
@@ -2873,9 +2921,9 @@
"last-changed": "Zuletzt geändert",
"last-triggered": "Zuletzt ausgelöst",
"last-updated": "Zuletzt aktualisiert",
"none": "Keine Sekundärinformatrionen",
"none": "Keine Sekundärinformation",
"position": "Position",
"tilt-position": "Neigungsposition"
"tilt-position": "Neigung"
},
"show_header_toggle": "Schalter anzeigen?",
"special_row": "spezielle Reihe",
@@ -2886,7 +2934,7 @@
"name": "Entität Filter"
},
"entity": {
"description": "Mit der Entitätskarte erhältst du einen schnellen Überblick über den Status Ihrer Entität.",
"description": "Mit der Entitätskarte erhältst du einen schnellen Überblick über den Status einer Entität.",
"name": "Entität"
},
"gauge": {
@@ -2968,7 +3016,7 @@
"map": {
"dark_mode": "Dunkler Modus?",
"default_zoom": "Standard-Zoom",
"description": "Mit der Map-Karte kannst du Objekte auf einer Karte anzeigen lassen.",
"description": "Mit der Map-Karte kannst du Objekte auf einer Landkarte anzeigen lassen.",
"geo_location_sources": "Geolocation-Quellen",
"hours_to_show": "Zu zeigende Stunden",
"name": "Karte",
@@ -2984,7 +3032,7 @@
"name": "Mediensteuerung"
},
"picture-elements": {
"description": "Die Bilder-Karte ist eine der vielseitigsten Arten von Karten. Mit den Karten kannst du Symbole, Text und sogar Dienste positionieren! Auf einem Bild basierend auf Koordinaten.",
"description": "Die Bilder-Karte ist eine der vielseitigsten Karten. Hier kannst du Symbole, Texte und sogar Dienste basierend auf Bildkoordinaten positionieren.",
"name": "Picture Elements"
},
"picture-entity": {
@@ -3082,7 +3130,7 @@
"header_name": "{name} Konfiguration anzeigen",
"move_left": "Ansicht nach links verschieben",
"move_right": "Ansicht nach rechts verschieben",
"tab_badges": "Abzeichen",
"tab_badges": "Plaketten",
"tab_settings": "Einstellungen",
"tab_visibility": "Sichtbarkeit",
"visibility": {
@@ -3143,8 +3191,8 @@
"para_sure": "Bist du dir sicher, dass du die Benutzeroberfläche selbst verwalten möchtest?",
"save": "Kontrolle übernehmen",
"yaml_config": "Um dir den Einstieg zu erleichtern, findest du hier die aktuelle Konfiguration dieses Dashboards:",
"yaml_control": "Um die Kontrolle im YAML-Modus zu übernehmen, erstelle eine YAML-Datei mit dem Namen, den du in Deiner Konfiguration für dieses Dashboard angegeben hast, oder mit der Standardeinstellung 'ui-lovelace.yaml'.",
"yaml_mode": "Du verwendest den YAML-Modus für dieses Dashboard. Dies bedeutet, dass Du Deine Lovelace-Konfiguration nicht über die Benutzeroberfläche ändern kannst. Wenn du dieses Dashboard über die Benutzeroberfläche verwalten möchtest, entferne \"mode: yaml\" aus Deiner Lovelace-Konfiguration in \"configuration.yaml\"."
"yaml_control": "Um die Kontrolle im YAML-Modus zu übernehmen, erstelle eine YAML-Datei mit dem Namen, den du in deiner Konfiguration für dieses Dashboard angegeben hast, oder mit der Standardeinstellung 'ui-lovelace.yaml'.",
"yaml_mode": "Du verwendest den YAML-Modus für dieses Dashboard. Dies bedeutet, dass du deine Lovelace-Konfiguration nicht über die Benutzeroberfläche ändern kannst. Wenn du dieses Dashboard über die Benutzeroberfläche verwalten möchtest, entferne \"mode: yaml\" aus Deiner Lovelace-Konfiguration in \"configuration.yaml\"."
},
"select_view": {
"dashboard_label": "Dashboard",
@@ -3164,7 +3212,7 @@
},
"view": {
"panel_mode": {
"description": "Dadurch wird die erste Karte in voller Breite angezeigt. Andere Karten und Marker in dieser Ansicht werden nicht angezeigt.",
"description": "Hiermit wird die erste Karte in voller Breite angezeigt. Andere Karten und Marker in dieser Ansicht werden nicht angezeigt.",
"title": "Panel-Modus?",
"warning_multiple_cards": "Diese Ansicht enthält mehr als eine Karte, in einer Bedienfeldansicht kann jedoch nur eine Karte angezeigt werden."
}
@@ -3377,8 +3425,8 @@
"intro": "Sind Sie bereit, dein Zuhause zu wecken, Ihre Privatsphäre zurückzugewinnen und einer weltweiten Gemeinschaft von Tüftlern beizutreten?",
"restore": {
"description": "Alternativ kannst du von einem vorherigen Snapshot wiederherstellen.",
"hide_log": "Vollständiges Log verstecken",
"in_progress": "Wiederherstellung im Prozess",
"hide_log": "Vollständiges Protokoll ausblenden",
"in_progress": "Wiederherstellung im Gange",
"show_log": "Vollständiges Protokoll anzeigen"
},
"user": {
@@ -3399,17 +3447,20 @@
},
"profile": {
"advanced_mode": {
"description": "Home Assistent verbirgt standardmäßig erweiterte Funktionen und Optionen. Mache diese Funktionen zugänglich, indem diese Option aktiviert wird. Dies ist eine benutzerspezifische Einstellung, die sich nicht auf andere Benutzer auswirkt, die Home Assistant verwenden.",
"description": "Home Assistant verbirgt standardmäßig erweiterte Funktionen und Optionen. Mache diese Funktionen zugänglich, indem diese Option aktiviert wird. Dies ist eine benutzerspezifische Einstellung, die sich nicht auf andere Benutzer auswirkt, die Home Assistant verwenden.",
"link_promo": "Mehr erfahren",
"title": "Erweiterter Modus"
},
"change_password": {
"confirm_new_password": "Neues Passwort Bestätigen",
"current_password": "Aktuelles Passwort",
"error_new_is_old": "Das neue Passwort muss sich von dem aktuellen Passwort unterscheiden.",
"error_new_mismatch": "Eingegebene neue Passwörter stimmen nicht überein",
"error_required": "Erforderlich",
"header": "Passwort ändern",
"new_password": "Neues Passwort",
"submit": "Absenden"
"submit": "Absenden",
"success": "Passwort wurde erfolgreich geändert"
},
"current_user": "Du bist derzeit als {fullName} angemeldet.",
"customize_sidebar": {
@@ -3449,7 +3500,7 @@
"description": "Erstelle langlebige Zugriffstoken, damit deine Skripte mit deiner Home Assistant-Instanz interagieren können. Jedes Token ist ab der Erstellung für 10 Jahre gültig. Die folgenden langlebigen Zugriffstoken sind derzeit aktiv.",
"empty_state": "Sie haben noch keine langlebigen Zugangs-Token.",
"header": "Langlebige Zugangs-Token",
"last_used": "Zuletzt verwendet am {date} in {location}",
"last_used": "Zuletzt verwendet {date} von {location}",
"learn_auth_requests": "Erfahre, wie du authentifizierte Anfragen stellen kannst.",
"name": "Name",
"not_used": "Wurde noch nie benutzt",
@@ -3472,7 +3523,7 @@
"push_notifications": {
"add_device_prompt": {
"input_label": "Gerätename",
"title": "Wie sollte dieses Gerät genannt werden?"
"title": "Wie soll dieses Gerät genannt werden?"
},
"description": "Sende Benachrichtigungen an dieses Gerät.",
"error_load_platform": "Konfiguriere notify.html5.",
@@ -3488,7 +3539,7 @@
"delete_failed": "Fehler beim Löschen das Aktualisierungs-Token.",
"description": "Jedes Aktualisierungs-Token stellt eine Anmeldesitzung dar. Aktualisierungs-Token werden automatisch entfernt, wenn Sie Abmelden klicken. Die folgenden Aktualisierungs-Token sind derzeit für Ihr Konto aktiv.",
"header": "Aktualisierungs-Tokens",
"last_used": "Zuletzt verwendet am {date} in {location}",
"last_used": "Zuletzt verwendet {date} von {location}",
"not_used": "Wurde noch nie benutzt",
"token_title": "Aktualisierungs-Token für {clientId}"
},

View File

@@ -2,11 +2,13 @@
"config_entry": {
"disabled_by": {
"config_entry": "Παράμετρος διαμόρφωσης",
"device": "Συσκευή",
"integration": "Ενσωμάτωση",
"user": "Χρήστης"
}
},
"groups": {
"owner": "Ιδιοκτήτης",
"system-admin": "Διαχειριστές",
"system-read-only": "Χρήστες μόνο για ανάγνωση",
"system-users": "Χρήστες"
@@ -545,8 +547,15 @@
"add_new": "Προσθήκη νέας περιοχής...",
"area": "Περιοχή",
"clear": "Εκκαθάριση",
"no_areas": "Δεν έχετε περιοχές",
"no_match": "Δεν βρέθηκαν περιοχές που να ταιριάζουν",
"show_areas": "Εμφάνιση περιοχών"
},
"blueprint-picker": {
"add_user": "Προσθήκη χρήστη",
"remove_user": "Κατάργηση χρήστη",
"select_blueprint": "Επιλέξτε ένα σχεδιάγραμμα"
},
"data-table": {
"no-data": "Δεν υπάρχουν δεδομένα",
"search": "Αναζήτηση"
@@ -560,6 +569,8 @@
"clear": "Καθαρός",
"device": "Συσκευή",
"no_area": "Καμία περιοχή",
"no_devices": "Δεν έχετε συσκευές",
"no_match": "Δεν βρέθηκαν συσκευές που να ταιριάζουν",
"show_devices": "Εμφάνιση συσκευών",
"toggle": "Εναλλαγή"
},
@@ -571,6 +582,7 @@
"entity-picker": {
"clear": "Καθαρισμός",
"entity": "Οντότητα",
"no_match": "Δεν βρέθηκαν οντότητες που να ταιριάζουν",
"show_entities": "Εμφάνιση οντοτήτων"
}
},
@@ -587,8 +599,8 @@
"changed_to_state": "άλλαξε σε {state}",
"cleared_device_class": "παραγράφηκε (δεν εντοπίστηκε {device_class} )",
"detected_device_class": "εντόπισε {device_class}",
"rose": "αυξήθηκε",
"set": "ορίστηκε",
"rose": "ανέτειλε",
"set": "έδυσε",
"turned_off": "απενεργοποιήθηκε",
"turned_on": "ενεργοποιήθηκε",
"was_at_home": "ήταν στο σπίτι",
@@ -704,6 +716,16 @@
"service-picker": {
"service": "Υπηρεσία"
},
"target-picker": {
"add_area_id": "Επιλέξτε περιοχή",
"add_device_id": "Επιλέξτε συσκευή",
"add_entity_id": "Διαλέξτε οντότητα",
"expand_area_id": "Αναπτύξτε αυτήν την περιοχή στις ξεχωριστές συσκευές και οντότητες που περιέχει. Μετά την επέκταση δεν θα ενημερώσει τις συσκευές και τις οντότητες όταν αλλάζει η περιοχή.",
"expand_device_id": "Αναπτύξτε αυτήν τη συσκευή σε ξεχωριστές οντότητες. Μετά την επέκταση, δεν θα ενημερώσει τις οντότητες όταν αλλάξει η συσκευή.",
"remove_area_id": "Κατάργηση περιοχής",
"remove_device_id": "Αφαίρεση συσκευής",
"remove_entity_id": "Αφαίρεση οντότητας"
},
"user-picker": {
"add_user": "Προσθήκη χρήστη",
"no_user": "Κανένας χρήστης",
@@ -727,6 +749,7 @@
"editor": {
"confirm_delete": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την καταχώριση;",
"delete": "Διαγραφή",
"device_disabled": "Η συσκευή αυτής της οντότητας είναι απενεργοποιημένη.",
"enabled_cause": "Απενεργοποιήθηκε από {cause}.",
"enabled_delay_confirm": "Τα ενεργοποιημένα στοιχεία θα προστεθούν στο Home Assistant σε {delay} δευτερόλεπτα",
"enabled_description": "Οι απενεργοποιημένες οντότητες δεν θα προστεθούν στον Home Assistant.",
@@ -737,6 +760,7 @@
"icon_error": "Το εικονίδιο πρέπει να είναι στη μορφή 'πρόθεμα:όνομαικόνας', για παράδειγμα: 'mdi:home'",
"name": "Όνομα",
"note": "Σημείωση: Αυτό μπορεί να μην λειτουργεί ακόμη με όλες τις ενσωματώσεις.",
"open_device_settings": "Άνοιγμα ρυθμίσεων συσκευής",
"unavailable": "Αυτή η οντότητα δεν είναι προς το παρόν διαθέσιμη.",
"update": "Ενημέρωση"
},
@@ -877,6 +901,7 @@
"navigation": {
"areas": "Περιοχές",
"automation": "Αυτοματισμοί",
"blueprint": "Σχεδιαγράμματα",
"core": "Γενικά",
"customize": "Μορφοποιήσεις",
"devices": "Συσκευές",
@@ -1046,6 +1071,20 @@
"automation": {
"caption": "Αυτοματισμοί",
"description": "Διαχείριση αυτοματισμών",
"dialog_new": {
"blueprint": {
"use_blueprint": "Χρησιμοποιήστε ένα σχεδιάγραμμα"
},
"header": "Δημιουργία νέου αυτοματισμού",
"how": "Πώς θέλετε να δημιουργήσετε τον νέο σας αυτοματισμό;",
"start_empty": "Ξεκινήστε με έναν κενό αυτοματισμό",
"thingtalk": {
"create": "Δημιουργία",
"header": "Περιγράψτε τον αυτοματισμό που θέλετε να δημιουργήσετε",
"input_label": "Τι πρέπει να κάνει αυτός ο αυτοματισμός;",
"intro": "Και θα προσπαθήσουμε να το δημιουργήσουμε για εσάς. Για παράδειγμα: Σβήσε τα φώτα όταν φεύγω."
}
},
"editor": {
"actions": {
"add": "Προσθήκη ενέργειας",
@@ -1126,6 +1165,14 @@
"unsupported_action": "Χωρίς υποστήριξη διεπαφής χρήστη για ενέργεια: {action}"
},
"alias": "Όνομα",
"blueprint": {
"blueprint_to_use": "Σχεδιάγραμμα για χρήση",
"header": "Σχεδιάγραμμα",
"inputs": "Είσοδοι",
"manage_blueprints": "Διαχείριση σχεδιαγραμμάτων",
"no_blueprints": "Δεν έχετε σχεδιαγράμματα",
"no_inputs": "Αυτό το σχεδιάγραμμα δεν έχει καμία εισαγωγή."
},
"conditions": {
"add": "Προσθήκη όρου",
"delete": "Διαγραφή",
@@ -1368,6 +1415,42 @@
}
}
},
"blueprint": {
"add": {
"community_forums": "κοινοτικά φόρουμ",
"error_no_url": "Εισαγάγετε τη διεύθυνση URL του σχεδιαγράμματος.",
"file_name": "Διαδρομή σχεδιαγράμματος",
"header": "Εισαγωγή σχεδιαγράμματος",
"import_btn": "Προεπισκόπηση σχεδιαγράμματος",
"import_header": "Σχεδιάγραμμα \"{name}\"",
"import_introduction": "Μπορείτε να εισαγάγετε σχεδιαγράμματα άλλων χρηστών από το Github και τα φόρουμ της κοινότητας. Εισαγάγετε τη διεύθυνση URL του σχεδιαγράμματος παρακάτω.",
"import_introduction_link": "Μπορείτε να εισαγάγετε σχεδιαγράμματα άλλων χρηστών από το Github και το {community_link} . Εισαγάγετε τη διεύθυνση URL του σχεδιαγράμματος παρακάτω.",
"importing": "Φόρτωση σχεδιαγράμματος...",
"raw_blueprint": "Περιεχόμενο σχεδιαγράμματος",
"save_btn": "Εισαγωγή σχεδιαγράμματος",
"saving": "Εισαγωγή σχεδιαγράμματος...",
"unsupported_blueprint": "Αυτό το σχεδιάγραμμα δεν υποστηρίζεται",
"url": "Διεύθυνση URL του σχεδιαγράμματος"
},
"caption": "Σχεδιαγράμματα",
"description": "Διαχείριση σχεδιαγραμμάτων",
"overview": {
"add_blueprint": "Εισαγωγή σχεδιαγράμματος",
"confirm_delete_header": "Διαγραφή αυτού του σχεδιαγράμματος;",
"confirm_delete_text": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το σχεδιάγραμμα;",
"delete_blueprint": "Διαγραφή σχεδιαγράμματος",
"discover_more": "Ανακαλύψτε περισσότερα σχεδιαγράμματα",
"header": "Πρόγραμμα επεξεργασίας σχεδιαγραμμάτων",
"headers": {
"domain": "Τομέας",
"file_name": "Ονομα αρχείου",
"name": "Όνομα"
},
"introduction": "Η διαμόρφωση του σχεδιαγράμματος σας επιτρέπει να εισάγετε και να διαχειρίζεστε τα σχεδιαγράμματά σας.",
"learn_more": "Μάθετε περισσότερα σχετικά με τη χρήση σχεδιαγραμμάτων",
"use_blueprint": "Δημιουργία αυτοματισμού"
}
},
"cloud": {
"account": {
"alexa": {
@@ -1605,6 +1688,7 @@
"unknown_condition": "Άγνωστη κατάσταση"
},
"create": "Δημιουργία αυτοματισμού με τη συσκευή",
"create_disable": "Δεν είναι δυνατή η δημιουργία αυτοματισμού με απενεργοποιημένη συσκευή",
"no_automations": "Δεν υπάρχουν αυτοματισμοί",
"no_device_automations": "Δεν υπάρχουν διαθέσιμοι αυτοματισμοί για αυτήν τη συσκευή.",
"triggers": {
@@ -1633,6 +1717,15 @@
"description": "Διαχείριση συνδεδεμένων συσκευών",
"device_info": "Πληροφορίες συσκευής",
"device_not_found": "Η συσκευή δε βρέθηκε.",
"disabled": "Απενεργοποιημένο",
"disabled_by": {
"config_entry": "Παράμετρος διαμόρφωσης",
"integration": "Ενσωμάτωση",
"user": "Χρήστης"
},
"enabled_cause": "Η συσκευή απενεργοποιείται από το {cause}.",
"enabled_description": "Οι απενεργοποιημένες συσκευές δεν θα εμφανίζονται και οι οντότητες που ανήκουν στη συσκευή θα απενεργοποιούνται και δεν θα προστίθενται στο Home Assistant.",
"enabled_label": "Ενεργοποίηση συσκευής",
"entities": {
"add_entities_lovelace": "Προσθήκη στο Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {απενεργοποιημένη οντότηταy}\n other {απενεργοποιημένες οντότητες}\n}",
@@ -1642,14 +1735,25 @@
},
"name": "Όνομα",
"no_devices": "Δεν υπάρχουν συσκευές",
"picker": {
"filter": {
"filter": "Φίλτρο",
"hidden_devices": "{number} κρυφή {number, plural,\n one {συσκευή}\n other {συσκευές}\n}",
"show_all": "Εμφάνιση όλων",
"show_disabled": "Εμφάνιση απενεργοποιημένων συσκευών"
},
"search": "Αναζήτηση συσκευών"
},
"scene": {
"create": "Δημιουργία σκηνής με τη συσκευή",
"create_disable": "Δεν είναι δυνατή η δημιουργία σκηνής με απενεργοποιημένη συσκευή",
"no_scenes": "Καμία σκηνή",
"scenes": "Σκηνές"
},
"scenes": "Σκηνές",
"script": {
"create": "Δημιουργία σεναρίου με συσκευή",
"create_disable": "Δεν είναι δυνατή η δημιουργία σεναρίου με απενεργοποιημένη συσκευή",
"no_scripts": "Χωρίς δέσμες ενεργειών",
"scripts": "Δέσμες ενεργειών"
},
@@ -1682,6 +1786,7 @@
},
"header": "Μητρώο οντοτήτων",
"headers": {
"area": "Περιοχή",
"entity_id": "Αναγνωριστικό οντότητας",
"integration": "Ενσωμάτωση",
"name": "Όνομα",
@@ -2330,6 +2435,7 @@
"editor": {
"activate_user": "Ενεργοποίηση χρήστη",
"active": "Ενεργό",
"active_tooltip": "Ελέγχει εάν ο χρήστης μπορεί να συνδεθεί",
"admin": "Διαχειριστής",
"caption": "Προβολή χρήστη",
"change_password": "Αλλαγή Κωδικού",
@@ -2346,19 +2452,24 @@
"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 διαχείρισης για να διασφαλίσουμε ότι περιορίζουν σωστά την πρόσβαση στους διαχειριστές."
},
"zha": {
"add_device": "Προσθήκη συσκευής",
"add_device_page": {
"discovered_text": "Οι συσκευές θα εμφανιστούν εδώ μόλις ανακαλυφθούν.",
"discovery_text": "Οι ανακαλυφθείσες συσκευές θα εμφανιστούν εδώ. Ακολουθήστε τις οδηγίες για τις συσκευές σας και τοποθετήστε τις συσκευές στη λειτουργία αντιστοίχισης.",
@@ -2404,6 +2515,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 - Συσκευή"
},
@@ -2419,6 +2540,7 @@
"unbind_button_label": "Αποσύνδεση ομάδας"
},
"groups": {
"add_group": "Προσθήκη ομάδας",
"add_members": "Προσθήκη Μελών",
"adding_members": "Προσθήκη Μελών",
"caption": "Ομάδες",
@@ -2461,7 +2583,11 @@
"hint_wakeup": "Μερικές συσκευές όπως οι αισθητήρες Xiaomi έχουν ένα κουμπί αφύπνισης το οποίο μπορείτε να πιέσετε για διαστήματα των ~5 δευτερολέπτων ώστε να κρατήσετε τις συσκευές αφυπνισμένες ενώ αλληλεπιδράτε μαζί τους.",
"introduction": "Εκτελέστε εντολές ZHA που επηρεάζουν μια μόνο συσκευή. Επιλέξτε μια συσκευή για να δείτε μια λίστα διαθέσιμων εντολών."
},
"title": "Οικιακός Αυτοματισμός Zigbee"
"title": "Οικιακός Αυτοματισμός Zigbee",
"visualization": {
"caption": "Απεικόνιση",
"header": "Απεικόνιση δικτύου"
}
},
"zone": {
"add_zone": "Προσθήκη ζώνης",
@@ -2915,7 +3041,8 @@
},
"picture-glance": {
"description": "Η κάρτα \"Ματιά εικόνας\" εμφανίζει μια εικόνα και τις αντίστοιχες καταστάσεις οντότητας ως εικονίδιο. Οι οντότητες στη δεξιά πλευρά επιτρέπουν ενέργειες εναλλαγής, ενώ άλλες εμφανίζουν το παράθυρο διαλόγου περισσότερων πληροφοριών.",
"name": "Στιγμιότυπο εικόνας"
"name": "Στιγμιότυπο εικόνας",
"state_entity": "Κρατική οντότητα"
},
"picture": {
"description": "Η κάρτα Εικόνας σάς επιτρέπει να ορίσετε μια εικόνα που θα χρησιμοποιείται για πλοήγηση σε διάφορες διαδρομές στη διεπαφή σας ή να καλείτε μια υπηρεσία.",
@@ -3327,10 +3454,13 @@
"change_password": {
"confirm_new_password": "Επιβεβαιώστε τον καινούριο κωδικό",
"current_password": "Τρέχων κωδικός",
"error_new_is_old": "Ο νέος κωδικός πρόσβασης πρέπει να είναι διαφορετικός από τον τρέχοντα κωδικό πρόσβασης",
"error_new_mismatch": "Οι νέες τιμές κωδικού πρόσβασης που έχουν εισαχθεί δεν ταιριάζουν",
"error_required": "Απαιτείται",
"header": "Αλλαγή Κωδικού",
"new_password": "Νέος κωδικός",
"submit": "Υποβολή"
"submit": "Υποβολή",
"success": "Ο κωδικός άλλαξε επιτυχώς"
},
"current_user": "Αυτήν τη στιγμή είστε συνδεδεμένος ως {fullName}.",
"customize_sidebar": {

View File

@@ -2,6 +2,7 @@
"config_entry": {
"disabled_by": {
"config_entry": "Config Entry",
"device": "Device",
"integration": "Integration",
"user": "User"
}
@@ -546,6 +547,8 @@
"add_new": "Add new area…",
"area": "Area",
"clear": "Clear",
"no_areas": "You don't have any areas",
"no_match": "No matching areas found",
"show_areas": "Show areas"
},
"blueprint-picker": {
@@ -566,6 +569,8 @@
"clear": "Clear",
"device": "Device",
"no_area": "No area",
"no_devices": "You don't have any devices",
"no_match": "No matching devices found",
"show_devices": "Show devices",
"toggle": "Toggle"
},
@@ -577,6 +582,7 @@
"entity-picker": {
"clear": "Clear",
"entity": "Entity",
"no_match": "No matching entities found",
"show_entities": "Show entities"
}
},
@@ -710,6 +716,16 @@
"service-picker": {
"service": "Service"
},
"target-picker": {
"add_area_id": "Pick area",
"add_device_id": "Pick device",
"add_entity_id": "Pick entity",
"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"
},
"user-picker": {
"add_user": "Add user",
"no_user": "No user",
@@ -733,6 +749,7 @@
"editor": {
"confirm_delete": "Are you sure you want to delete this entry?",
"delete": "Delete",
"device_disabled": "The device of this entity is disabled.",
"enabled_cause": "Disabled by {cause}.",
"enabled_delay_confirm": "The enabled entities will be added to Home Assistant in {delay} seconds",
"enabled_description": "Disabled entities will not be added to Home Assistant.",
@@ -743,6 +760,7 @@
"icon_error": "Icons should be in the format 'prefix:iconname', e.g. 'mdi:home'",
"name": "Name",
"note": "Note: This might not work yet with all integrations.",
"open_device_settings": "Open device settings",
"unavailable": "This entity is not currently available.",
"update": "Update"
},
@@ -1030,7 +1048,7 @@
"confirmation_text": "All devices in this area will become unassigned.",
"confirmation_title": "Are you sure you want to delete this area?"
},
"description": "Manage areas in your home",
"description": "Group devices and entities into areas",
"editor": {
"area_id": "Area ID",
"create": "Create",
@@ -1052,7 +1070,7 @@
},
"automation": {
"caption": "Automations",
"description": "Manage automations",
"description": "Create custom behavior rules for your home",
"dialog_new": {
"blueprint": {
"use_blueprint": "Use a blueprint"
@@ -1240,7 +1258,7 @@
"edit_ui": "Edit with UI",
"edit_yaml": "Edit as YAML",
"enable_disable": "Enable/Disable automation",
"introduction": "Use automations to bring your home to live.",
"introduction": "Use automations to bring your home to life.",
"load_error_not_editable": "Only automations in automations.yaml are editable.",
"load_error_unknown": "Error loading automation ({err_no}).",
"max": {
@@ -1399,16 +1417,18 @@
},
"blueprint": {
"add": {
"community_forums": "community forums",
"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}\" (type: {domain})",
"file_name": "Blueprint Path",
"header": "Import a blueprint",
"import_btn": "Preview blueprint",
"import_header": "Blueprint \"{name}\"",
"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...",
"import_introduction_link": "You can import blueprints of other users from Github and the {community_link}. Enter the URL of the blueprint below.",
"importing": "Loading blueprint...",
"raw_blueprint": "Blueprint content",
"save_btn": "Save blueprint",
"saving": "Saving blueprint...",
"save_btn": "Import blueprint",
"saving": "Importing blueprint...",
"unsupported_blueprint": "This blueprint is not supported",
"url": "URL of the blueprint"
},
@@ -1419,14 +1439,15 @@
"confirm_delete_header": "Delete this blueprint?",
"confirm_delete_text": "Are you sure you want to delete this blueprint?",
"delete_blueprint": "Delete blueprint",
"discover_more": "Discover more Blueprints",
"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",
"introduction": "The blueprint configuration allows you to import and manage your blueprints.",
"learn_more": "Learn more about using blueprints",
"use_blueprint": "Create automation"
}
},
@@ -1510,7 +1531,7 @@
"title": "Alexa"
},
"caption": "Home Assistant Cloud",
"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",
"description_login": "Logged in as {email}",
"description_not_login": "Not logged in",
"dialog_certificate": {
@@ -1605,7 +1626,7 @@
},
"core": {
"caption": "General",
"description": "Change your general Home Assistant configuration",
"description": "Unit system, location, time zone & other general parameters",
"section": {
"core": {
"core_config": {
@@ -1667,6 +1688,7 @@
"unknown_condition": "Unknown condition"
},
"create": "Create automation with device",
"create_disable": "Can't create automation with disabled device",
"no_automations": "No automations",
"no_device_automations": "There are no automations available for this device.",
"triggers": {
@@ -1692,9 +1714,18 @@
"no_devices": "No devices"
},
"delete": "Delete",
"description": "Manage connected devices",
"description": "Manage configured devices",
"device_info": "Device info",
"device_not_found": "Device not found.",
"disabled": "Disabled",
"disabled_by": {
"config_entry": "Config Entry",
"integration": "Integration",
"user": "User"
},
"enabled_cause": "The device is 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.",
"enabled_label": "Enable device",
"entities": {
"add_entities_lovelace": "Add to Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {disabled entity}\n other {disabled entities}\n}",
@@ -1704,14 +1735,25 @@
},
"name": "Name",
"no_devices": "No devices",
"picker": {
"filter": {
"filter": "Filter",
"hidden_devices": "{number} hidden {number, plural,\n one {device}\n other {devices}\n}",
"show_all": "Show all",
"show_disabled": "Show disabled devices"
},
"search": "Search devices"
},
"scene": {
"create": "Create scene with device",
"create_disable": "Can't create scene with disabled device",
"no_scenes": "No scenes",
"scenes": "Scenes"
},
"scenes": "Scenes",
"script": {
"create": "Create script with device",
"create_disable": "Can't create script with disabled device",
"no_scripts": "No scripts",
"scripts": "Scripts"
},
@@ -1777,7 +1819,7 @@
"header": "Configure Home Assistant",
"helpers": {
"caption": "Helpers",
"description": "Manage elements that help build automations",
"description": "Elements that help build automations",
"dialog": {
"add_helper": "Add helper",
"add_platform": "Add {platform}",
@@ -1809,7 +1851,7 @@
"copy_github": "For GitHub",
"copy_raw": "Raw Text",
"custom_uis": "Custom UIs:",
"description": "View info about your Home Assistant installation",
"description": "Version, system health and links to documentation",
"developed_by": "Developed by a bunch of awesome people.",
"documentation": "Documentation",
"frontend": "frontend-ui",
@@ -1915,7 +1957,7 @@
},
"configure": "Configure",
"configured": "Configured",
"description": "Manage integrations",
"description": "Manage integrations with services, devices, ...",
"details": "Integration details",
"discovered": "Discovered",
"home_assistant_website": "Home Assistant website",
@@ -2000,7 +2042,7 @@
"open": "Open"
}
},
"description": "Manage your Lovelace Dashboards",
"description": "Create customized sets of cards to control your home",
"resources": {
"cant_edit_yaml": "You are using Lovelace in YAML mode, therefore you cannot manage your resources through the UI. Manage them in configuration.yaml.",
"caption": "Resources",
@@ -2199,7 +2241,7 @@
"scene": {
"activated": "Activated scene {name}.",
"caption": "Scenes",
"description": "Manage scenes",
"description": "Capture device states and easily recall them later",
"editor": {
"default_name": "New Scene",
"devices": {
@@ -2243,7 +2285,7 @@
},
"script": {
"caption": "Scripts",
"description": "Manage scripts",
"description": "Execute a sequence of actions",
"editor": {
"alias": "Name",
"default_name": "New Script",
@@ -2354,7 +2396,7 @@
"confirm_remove": "Are you sure you want to remove tag {tag}?",
"confirm_remove_title": "Remove tag?",
"create_automation": "Create automation with tag",
"description": "Manage tags",
"description": "Trigger automations when a NFC tag, QR code, etc. is scanned",
"detail": {
"companion_apps": "companion apps",
"create": "Create",
@@ -2389,10 +2431,11 @@
"username": "Username"
},
"caption": "Users",
"description": "Manage users",
"description": "Manage the Home Assistant user accounts",
"editor": {
"activate_user": "Activate user",
"active": "Active",
"active_tooltip": "Controls if user can login",
"admin": "Administrator",
"caption": "View user",
"change_password": "Change password",
@@ -3411,10 +3454,13 @@
"change_password": {
"confirm_new_password": "Confirm New Password",
"current_password": "Current Password",
"error_new_is_old": "New password must be different than current password",
"error_new_mismatch": "Entered new password values do not match",
"error_required": "Required",
"header": "Change Password",
"new_password": "New Password",
"submit": "Submit"
"submit": "Submit",
"success": "Password changed successfully"
},
"current_user": "You are currently logged in as {fullName}.",
"customize_sidebar": {

View File

@@ -666,6 +666,16 @@
"service-picker": {
"service": "Servicio"
},
"target-picker": {
"add_area_id": "Seleccionar área",
"add_device_id": "Seleccionar dispositivo",
"add_entity_id": "Seleccionar entidad",
"expand_area_id": "Expanda esta área en los dispositivos y entidades independientes que contiene. Después de expandirlo no actualizará los dispositivos y entidades cuando cambie el área.",
"expand_device_id": "Expanda este dispositivo en entidades independientes. Después de expandirlo no actualizará las entidades cuando cambie el dispositivo.",
"remove_area_id": "Eliminar área",
"remove_device_id": "Eliminar dispositivo",
"remove_entity_id": "Eliminar entidad"
},
"user-picker": {
"add_user": "Agregar usuario",
"no_user": "Sin usuario",
@@ -689,6 +699,7 @@
"editor": {
"confirm_delete": "¿Está seguro de que desea eliminar esta entrada?",
"delete": "Eliminar",
"device_disabled": "El dispositivo de esta entidad está deshabilitado.",
"enabled_cause": "Deshabilitado por {cause}.",
"enabled_delay_confirm": "Las entidades habilitadas se agregarán a Home Assistant en {delay} segundos",
"enabled_description": "Las entidades deshabilitadas no serán agregadas a Home Assistant.",
@@ -699,6 +710,7 @@
"icon_error": "Los iconos deben estar en el formato 'prefijo:nombre del icono', por ejemplo, 'mdi: home'",
"name": "Sustituir nombre",
"note": "Nota: esto podría no funcionar todavía con todas las integraciones.",
"open_device_settings": "Abrir la configuración del dispositivo",
"unavailable": "Esta entidad no está disponible actualmente.",
"update": "Actualizar"
},
@@ -1489,6 +1501,7 @@
"unknown_condition": "Condición desconocida"
},
"create": "Crear automatización con dispositivo",
"create_disable": "No se puede crear automatización con un dispositivo deshabilitado",
"no_automations": "Sin automatizaciones",
"no_device_automations": "No hay automatizaciones disponibles para este dispositivo.",
"triggers": {
@@ -1515,6 +1528,14 @@
"description": "Administrar dispositivos conectados",
"device_info": "Información del dispositivo",
"device_not_found": "Dispositivo no encontrado.",
"disabled": "Deshabilitado",
"disabled_by": {
"config_entry": "Entrada de configuración",
"integration": "Integración",
"user": "Usuario"
},
"enabled_description": "Los dispositivos deshabilitados no se mostrarán y las entidades que pertenecen al dispositivo se deshabilitarán y no se agregarán a Home Assistant.",
"enabled_label": "Habilitar dispositivo",
"entities": {
"add_entities_lovelace": "Agregar a Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {entidad deshabilitada}\n other {entidades deshabilitadas}\n}",
@@ -1524,14 +1545,24 @@
},
"name": "Nombre",
"no_devices": "Sin dispositivos",
"picker": {
"filter": {
"filter": "Filtrar",
"show_all": "Mostrar todo",
"show_disabled": "Mostrar los dispositivos deshabilitadas"
},
"search": "Mostrar dispositivos"
},
"scene": {
"create": "Crear escena con dispositivo",
"create_disable": "No se puede crear una escena con un dispositivo deshabilitado",
"no_scenes": "Sin escenas",
"scenes": "Escenas"
},
"scenes": "Escenas",
"script": {
"create": "Crear script con dispositivo",
"create_disable": "No se puede crear un script con un dispositivo deshabilitado",
"no_scripts": "Sin scripts",
"scripts": "Scripts"
},
@@ -2168,6 +2199,7 @@
"editor": {
"activate_user": "Activar usuario",
"active": "Activo",
"active_tooltip": "Controla si el usuario puede iniciar sesión",
"admin": "Administrador",
"caption": "Ver usuario",
"change_password": "Cambiar contraseña",
@@ -3136,10 +3168,13 @@
"change_password": {
"confirm_new_password": "Confirmar nueva contraseña",
"current_password": "Contraseña actual",
"error_new_is_old": "La nueva contraseña debe ser diferente a la contraseña actual",
"error_new_mismatch": "Las contraseñas no coinciden",
"error_required": "Necesario",
"header": "Cambiar contraseña",
"new_password": "Nueva contraseña",
"submit": "Enviar"
"submit": "Enviar",
"success": "La contraseña se cambió con éxito"
},
"current_user": "Actualmente estás conectado como {fullName} .",
"customize_sidebar": {

View File

@@ -2,6 +2,7 @@
"config_entry": {
"disabled_by": {
"config_entry": "Entrada de configuración",
"device": "Dispositivo",
"integration": "Integración",
"user": "Usuario"
}
@@ -546,6 +547,8 @@
"add_new": "Añade una nueva área ...",
"area": "Área",
"clear": "Limpiar",
"no_areas": "No tienes áreas",
"no_match": "No se han encontrado áreas coincidentes",
"show_areas": "Mostrar áreas"
},
"blueprint-picker": {
@@ -566,6 +569,8 @@
"clear": "Limpiar",
"device": "Dispositivo",
"no_area": "Ningún área",
"no_devices": "No tienes ningún dispositivo",
"no_match": "No se han encontrado dispositivos coincidentes",
"show_devices": "Mostrar dispositivos",
"toggle": "Interruptor"
},
@@ -577,6 +582,7 @@
"entity-picker": {
"clear": "Limpiar",
"entity": "Entidad",
"no_match": "No se han encontrado entidades coincidentes",
"show_entities": "Mostrar entidades"
}
},
@@ -700,16 +706,26 @@
"never": "Nunca",
"past": "Hace {time}",
"past_duration": {
"day": "hace {count} {count, plural,\none {día}\nother {días}\n}",
"hour": "hace {count} {count, plural,\none {hora}\nother {horas}\n}",
"minute": "hace {count} {count, plural,\none {minuto}\nother {minutos}\n}",
"second": "hace {count} {count, plural,\none {segundo}\nother {segundos}\n}",
"day": "Hace {count} {count, plural,\none {día}\nother {días}\n}",
"hour": "Hace {count} {count, plural,\none {hora}\nother {horas}\n}",
"minute": "Hace {count} {count, plural,\none {minuto}\nother {minutos}\n}",
"second": "Hace {count} {count, plural,\none {segundo}\nother {segundos}\n}",
"week": "hace {count} {count, plural,\none {semana}\nother {semanas}\n}"
}
},
"service-picker": {
"service": "Servicio"
},
"target-picker": {
"add_area_id": "Seleccionar área",
"add_device_id": "Seleccionar dispositivo",
"add_entity_id": "Seleccionar entidad",
"expand_area_id": "Expande este área en los dispositivos y entidades independientes que contiene. Después de expandirse, no actualizará los dispositivos y entidades cuando cambie el área.",
"expand_device_id": "Expande este dispositivo en entidades separadas. Después de expandirse, no actualizará las entidades cuando cambie el dispositivo.",
"remove_area_id": "Eliminar área",
"remove_device_id": "Eliminar dispositivo",
"remove_entity_id": "Eliminar entidad"
},
"user-picker": {
"add_user": "Añadir usuario",
"no_user": "Sin usuario",
@@ -733,6 +749,7 @@
"editor": {
"confirm_delete": "¿Estás seguro de que quieres eliminar este elemento?",
"delete": "Eliminar",
"device_disabled": "El dispositivo de esta entidad está deshabilitado.",
"enabled_cause": "Desactivado por {cause}.",
"enabled_delay_confirm": "Las entidades habilitadas se agregarán a Home Assistant en {delay} segundos",
"enabled_description": "Las entidades deshabilitadas no se agregarán a Home Assistant.",
@@ -743,6 +760,7 @@
"icon_error": "Los iconos deben tener el formato 'prefijo:nombreicono', por ejemplo, 'mdi:home'",
"name": "Nombre",
"note": "Nota: puede que esto no funcione todavía con todas las integraciones",
"open_device_settings": "Abrir la configuración del dispositivo",
"unavailable": "Esta entidad no está disponible actualmente.",
"update": "Actualizar"
},
@@ -1030,7 +1048,7 @@
"confirmation_text": "Todos los dispositivos en esta área quedarán sin asignar.",
"confirmation_title": "¿Estás seguro de que deseas eliminar esta área?"
},
"description": "Administra áreas en tu hogar",
"description": "Agrupa dispositivos y entidades en áreas",
"editor": {
"area_id": "ID de área",
"create": "Crear",
@@ -1052,7 +1070,7 @@
},
"automation": {
"caption": "Automatizaciones",
"description": "Administra las automatizaciones",
"description": "Crea reglas de comportamiento personalizadas para tu hogar",
"dialog_new": {
"blueprint": {
"use_blueprint": "Usa un plano"
@@ -1075,7 +1093,7 @@
"duplicate": "Duplicar",
"header": "Acciones",
"introduction": "Las acciones son lo que hará Home Assistant cuando se desencadene la automatización.",
"learn_more": "Saber más sobre las acciones.",
"learn_more": "Aprende más sobre las acciones.",
"name": "Acción",
"type_select": "Tipo de acción",
"type": {
@@ -1151,7 +1169,7 @@
"blueprint_to_use": "Plano a usar",
"header": "Plano",
"inputs": "Entradas",
"manage_blueprints": "Administrar planos",
"manage_blueprints": "Administra los planos",
"no_blueprints": "No tienes ningún plano",
"no_inputs": "Este plano no tiene ninguna entrada."
},
@@ -1162,7 +1180,7 @@
"duplicate": "Duplicar",
"header": "Condiciones",
"introduction": "Las condiciones son opcionales e impedirán cualquier\nejecución posterior a menos que se cumplan todas las condiciones.",
"learn_more": "Saber más sobre las condiciones",
"learn_more": "Aprende más sobre las condiciones",
"name": "Condición",
"type_select": "Tipo de condición",
"type": {
@@ -1266,7 +1284,7 @@
"duplicate": "Duplicar",
"header": "Desencadenantes",
"introduction": "Los desencadenantes son los que inician el funcionamiento de una regla de automatización. Es posible especificar varios desencadenantes para la misma regla. Una vez que se inicia un desencadenante, Home Assistant comprobará las condiciones, si las hubiere, y ejecutará la acción.",
"learn_more": "Saber más sobre los desencadenantes",
"learn_more": "Aprende más sobre los desencadenantes",
"name": "Desencadenante",
"type_select": "Tipo de desencadenante",
"type": {
@@ -1374,7 +1392,7 @@
"name": "Nombre"
},
"introduction": "El editor de automatización te permite crear y editar automatizaciones. En el enlace siguiente puedes leer las instrucciones para asegurarte de que has configurado correctamente Home Assistant.",
"learn_more": "Saber más sobre las automatizaciones",
"learn_more": "Aprende más sobre las automatizaciones",
"no_automations": "No pudimos encontrar ninguna automatización editable",
"only_editable": "Solo las automatizaciones definidas en automations.yaml son editables.",
"pick_automation": "Elije la automatización para editar",
@@ -1399,34 +1417,37 @@
},
"blueprint": {
"add": {
"community_forums": "foros de la comunidad",
"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} (tipo: {domain})",
"file_name": "Ruta del plano",
"header": "Importar un plano",
"import_btn": "Vista previa del plano",
"import_header": "Plano \"{name}\"",
"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...",
"import_introduction_link": "Puedes importar planos de otros usuarios desde Github y {community_link}. Introduce la URL del plano a continuación.",
"importing": "Cargando plano...",
"raw_blueprint": "Contenido del plano",
"save_btn": "Guardar plano",
"saving": "Guardando plano...",
"save_btn": "Importar plano",
"saving": "Importando plano...",
"unsupported_blueprint": "Este plano no es compatible",
"url": "URL del plano"
},
"caption": "Planos",
"description": "Administrar planos",
"description": "Administra los planos",
"overview": {
"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",
"discover_more": "Descubre más planos",
"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",
"introduction": "La configuración de planos te permite importar y administrar tus planos.",
"learn_more": "Aprende más sobre el uso de planos",
"use_blueprint": "Crear automatización"
}
},
@@ -1486,7 +1507,7 @@
"webhooks": {
"disable_hook_error_msg": "No se pudo deshabilitar el webhook:",
"info": "Cualquier cosa que esté configurada para ser activada por un webhook puede recibir una URL de acceso público para permitirte enviar datos a Home Assistant desde cualquier lugar, sin exponer tu instancia a Internet.",
"link_learn_more": "Saber más sobre la creación de automatizaciones basadas en webhook.",
"link_learn_more": "Aprende más sobre la creación de automatizaciones basadas en webhook.",
"loading": "Cargando ...",
"manage": "Administrar",
"no_hooks_yet": "Parece que aún no tienes webhooks. Comienza configurando un",
@@ -1510,7 +1531,7 @@
"title": "Alexa"
},
"caption": "Nube Home Assistant",
"description_features": "Control fuera de casa, integración con Alexa y Google Assistant.",
"description_features": "Controla tu hogar cuando estés fuera e intégralo con Alexa y Google Assistant",
"description_login": "Has iniciado sesión como {email}",
"description_not_login": "No has iniciado sesión",
"dialog_certificate": {
@@ -1566,7 +1587,7 @@
"introduction2": "Este servicio está a cargo de nuestro socio.",
"introduction2a": ", una compañía fundada por los fundadores de Home Assistant y Hass.io.",
"introduction3": "Home Assistant Cloud es un servicio de suscripción con una prueba gratuita de un mes. No se necesita información de pago.",
"learn_more_link": "Saber más sobre Home Assistant Cloud",
"learn_more_link": "Aprende más sobre Home Assistant Cloud",
"password": "Contraseña",
"password_error_msg": "Las contraseñas tienen al menos 8 caracteres.",
"sign_in": "Inicia sesión",
@@ -1605,7 +1626,7 @@
},
"core": {
"caption": "Configuración general",
"description": "Cambia la configuración general de Home Assistant",
"description": "Sistema de unidades, ubicación, zona horaria y otros parámetros generales",
"section": {
"core": {
"core_config": {
@@ -1667,6 +1688,7 @@
"unknown_condition": "Condición desconocida"
},
"create": "Crear automatización con el dispositivo",
"create_disable": "No se puede crear una automatización con un dispositivo deshabilitado",
"no_automations": "Sin automatizaciones",
"no_device_automations": "No hay automatizaciones disponibles para este dispositivo.",
"triggers": {
@@ -1692,9 +1714,18 @@
"no_devices": "Sin dispositivos"
},
"delete": "Eliminar",
"description": "Administrar dispositivos conectados",
"description": "Administra dispositivos configurados",
"device_info": "Información del dispositivo",
"device_not_found": "Dispositivo no encontrado.",
"disabled": "Deshabilitado",
"disabled_by": {
"config_entry": "Entrada de configuración",
"integration": "Integración",
"user": "Usuario"
},
"enabled_cause": "El dispositivo está deshabilitado por {cause} .",
"enabled_description": "Los dispositivos deshabilitados no se mostrarán y las entidades que pertenecen al dispositivo se deshabilitarán y no se añadirán a Home Assistant.",
"enabled_label": "Habilitar dispositivo",
"entities": {
"add_entities_lovelace": "Añadir a Lovelace",
"disabled_entities": "+{count} {count, plural,\n one {entidad deshabilitada}\n other {entidades deshabilitadas}\n}",
@@ -1704,14 +1735,25 @@
},
"name": "Nombre",
"no_devices": "Sin dispositivos",
"picker": {
"filter": {
"filter": "Filtrar",
"hidden_devices": "{number} {number, plural,\n one {dispositivo oculto}\n other {dispositivos ocultos}\n}",
"show_all": "Mostrar todo",
"show_disabled": "Mostrar dispositivos deshabilitados"
},
"search": "Buscar dispositivos"
},
"scene": {
"create": "Crear escena con el dispositivo",
"create_disable": "No se puede crear una escena con un dispositivo deshabilitado",
"no_scenes": "Sin escenas",
"scenes": "Escenas"
},
"scenes": "Escenas",
"script": {
"create": "Crear script con el dispositivo",
"create_disable": "No se puede crear un script con un dispositivo deshabilitado",
"no_scripts": "Sin scripts",
"scripts": "Scripts"
},
@@ -1777,7 +1819,7 @@
"header": "Configurar Home Assistant",
"helpers": {
"caption": "Ayudantes",
"description": "Administra los elementos que pueden ayudar a construir automatizaciones.",
"description": "Elementos que ayudan a construir automatizaciones",
"dialog": {
"add_helper": "Añadir ayudante",
"add_platform": "Añadir {platform}",
@@ -1809,7 +1851,7 @@
"copy_github": "Para GitHub",
"copy_raw": "Texto sin procesar",
"custom_uis": "IU personalizadas:",
"description": "Ver información sobre tu instalación de Home Assistant",
"description": "Versión, estado del sistema y enlaces a la documentación",
"developed_by": "Desarrollado por un montón de gente impresionante.",
"documentation": "Documentación",
"frontend": "interfaz de usuario",
@@ -1915,7 +1957,7 @@
},
"configure": "Configurar",
"configured": "Configurado",
"description": "Administra las integraciones",
"description": "Gestiona integraciones con servicios, dispositivos, ...",
"details": "Detalles de la integración",
"discovered": "Descubierto",
"home_assistant_website": "Sitio web de Home Assistant",
@@ -1948,7 +1990,7 @@
"logs": {
"caption": "Registros",
"clear": "Limpiar",
"description": "Ver los registros de Home Assistant",
"description": "Ve los registros de Home Assistant",
"details": "Detalles de registro ({level})",
"load_full_log": "Cargar registro completo de Home Assistant",
"loading_log": "Cargando registro de errores...",
@@ -2000,7 +2042,7 @@
"open": "Abrir"
}
},
"description": "Administra tus Paneles de Control Lovelace",
"description": "Crea conjuntos personalizados de tarjetas para controlar tu hogar",
"resources": {
"cant_edit_yaml": "Estás utilizando Lovelace en modo YAML, por tanto no puedes administrar tus recursos a través de la IU. Adminístralos en configuration.yaml.",
"caption": "Recursos",
@@ -2190,7 +2232,7 @@
"update": "Actualizar"
},
"introduction": "Aquí puedes definir a cada persona de interés en Home Assistant.",
"learn_more": "Saber más sobre las personas",
"learn_more": "Aprende más sobre las personas",
"no_persons_created_yet": "Parece que aún no has creado ninguna persona.",
"note_about_persons_configured_in_yaml": "Nota: las personas configuradas a través de configuration.yaml no se pueden editar a través de la IU.",
"person_not_found": "No pudimos encontrar a la persona que intentabas editar.",
@@ -2199,7 +2241,7 @@
"scene": {
"activated": "Activada escena {name}.",
"caption": "Escenas",
"description": "Administra las escenas",
"description": "Captura los estados de los dispositivos y recupéralos fácilmente más tarde",
"editor": {
"default_name": "Nueva Escena",
"devices": {
@@ -2234,7 +2276,7 @@
"name": "Nombre"
},
"introduction": "El editor de escenas te permite crear y editar escenas. Por favor, sigue el siguiente enlace para leer las instrucciones para asegurarte de que has configurado Home Assistant correctamente.",
"learn_more": "Saber más sobre las escenas",
"learn_more": "Aprende más sobre las escenas",
"no_scenes": "No pudimos encontrar ninguna escena editable",
"only_editable": "Solo las escenas definidas en scenes.yaml son editables.",
"pick_scene": "Elige una escena para editar",
@@ -2243,7 +2285,7 @@
},
"script": {
"caption": "Scripts",
"description": "Administra los scripts",
"description": "Ejecuta una secuencia de acciones",
"editor": {
"alias": "Nombre",
"default_name": "Nuevo script",
@@ -2255,7 +2297,7 @@
"id_already_exists": "Este ID ya existe",
"id_already_exists_save_error": "No puedes guardar este script porque el ID no es único, elije otro ID o déjalo en blanco para generar uno automáticamente.",
"introduction": "Utiliza scripts para ejecutar una secuencia de acciones.",
"link_available_actions": "Saber más sobre las acciones disponibles.",
"link_available_actions": "Aprende más sobre las acciones disponibles.",
"load_error_not_editable": "Solo los scripts dentro de scripts.yaml son editables.",
"max": {
"parallel": "Número máximo de ejecuciones paralelas",
@@ -2284,7 +2326,7 @@
"name": "Nombre"
},
"introduction": "El editor de scripts te permite crear y editar scripts. Por favor, sigue el siguiente enlace para leer las instrucciones para asegurarte de que has configurado Home Assistant correctamente.",
"learn_more": "Saber más sobre los scripts",
"learn_more": "Aprende más sobre los scripts",
"no_scripts": "No hemos encontrado ningún script editable",
"run_script": "Ejecutar script",
"show_info": "Mostrar información sobre el script",
@@ -2354,7 +2396,7 @@
"confirm_remove": "¿Estás seguro de que quieres eliminar la etiqueta {tag} ?",
"confirm_remove_title": "¿Eliminar etiqueta?",
"create_automation": "Crear automatización con etiqueta",
"description": "Administrar etiquetas",
"description": "Activa automatizaciones cuando se escanea una etiqueta NFC, un código QR, etc.",
"detail": {
"companion_apps": "aplicaciones complementarias",
"create": "Crear",
@@ -2373,7 +2415,7 @@
"last_scanned": "Última vez escaneada",
"name": "Nombre"
},
"learn_more": "Más información sobre las etiquetas",
"learn_more": "Aprende más sobre las etiquetas",
"never_scanned": "Nunca escaneado",
"no_tags": "Sin etiquetas",
"write": "Escribir"
@@ -2389,10 +2431,11 @@
"username": "Nombre de usuario"
},
"caption": "Usuarios",
"description": "Administra usuarios",
"description": "Administra las cuentas de usuario de Home Assistant",
"editor": {
"activate_user": "Activar usuario",
"active": "Activo",
"active_tooltip": "Controla si el usuario puede iniciar sesión",
"admin": "Administrador",
"caption": "Ver usuario",
"change_password": "Cambiar la contraseña",
@@ -2586,7 +2629,7 @@
"wakeup_interval": "Intervalo de activación"
},
"description": "Administra tu red Z-Wave",
"learn_more": "Saber más sobre Z-Wave",
"learn_more": "Aprende más sobre Z-Wave",
"network_management": {
"header": "Administración de red Z-Wave",
"introduction": "Ejecutar comandos que afectan a la red Z-Wave. No recibirás comentarios sobre si la mayoría de los comandos tuvieron éxito, pero puedes consultar el Registro OZW para intentar averiguarlo."
@@ -3325,7 +3368,7 @@
"demo": {
"demo_by": "por {name}",
"introduction": "¡Bienvenido a casa! Has llegado a la demostración de Home Assistant donde mostramos las mejores interfaces de usuario creadas por nuestra comunidad.",
"learn_more": "Saber más sobre Home Assistant",
"learn_more": "Aprende más sobre Home Assistant",
"next_demo": "Siguiente demostración"
}
},
@@ -3405,16 +3448,19 @@
"profile": {
"advanced_mode": {
"description": "Desbloquea las funciones avanzadas.",
"link_promo": "Saber más",
"link_promo": "Aprende más",
"title": "Modo avanzado"
},
"change_password": {
"confirm_new_password": "Confirmar nueva contraseña",
"current_password": "Contraseña actual",
"error_new_is_old": "La nueva contraseña debe ser diferente a la contraseña actual",
"error_new_mismatch": "Los nuevos valores de contraseña introducidos no coinciden",
"error_required": "Obligatorio",
"header": "Cambiar contraseña",
"new_password": "Nueva contraseña",
"submit": "Enviar"
"submit": "Enviar",
"success": "Contraseña cambiada con éxito"
},
"current_user": "Has iniciado sesión como {fullName}.",
"customize_sidebar": {
@@ -3483,7 +3529,7 @@
"error_load_platform": "Configurar notify.html5.",
"error_use_https": "Requiere SSL activado para frontend.",
"header": "Notificaciones push",
"link_promo": "Saber más",
"link_promo": "Aprende más",
"push_notifications": "Notificaciones push"
},
"refresh_tokens": {

Some files were not shown because too many files have changed in this diff Show More