Merge pull request #9310 from home-assistant/dev

This commit is contained in:
Paulus Schoutsen 2021-05-30 20:30:44 -07:00 committed by GitHub
commit 1533c22d5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 794 additions and 534 deletions

View File

@ -3,6 +3,7 @@ import { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea";
import { DEFAULT_SCHEMA, Type } from "js-yaml";
import {
css,
CSSResultGroup,
@ -11,7 +12,7 @@ import {
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state, query } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/buttons/ha-progress-button";
@ -27,6 +28,7 @@ import {
HassioAddonDetails,
HassioAddonSetOptionParams,
setHassioAddonOption,
validateHassioAddonOption,
} from "../../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
@ -38,6 +40,13 @@ import { hassioStyle } from "../../resources/hassio-style";
const SUPPORTED_UI_TYPES = ["string", "select", "boolean", "integer", "float"];
const ADDON_YAML_SCHEMA = DEFAULT_SCHEMA.extend([
new Type("!secret", {
kind: "scalar",
construct: (data) => `!secret ${data}`,
}),
]);
@customElement("hassio-addon-config")
class HassioAddonConfig extends LitElement {
@property({ attribute: false }) public addon!: HassioAddonDetails;
@ -125,6 +134,7 @@ class HassioAddonConfig extends LitElement {
></ha-form>`
: html` <ha-yaml-editor
@value-changed=${this._configChanged}
.schema=${ADDON_YAML_SCHEMA}
></ha-yaml-editor>`}
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
${!this._yamlMode ||
@ -269,6 +279,14 @@ class HassioAddonConfig extends LitElement {
this._error = undefined;
try {
const validation = await validateHassioAddonOption(
this.hass,
this.addon.slug,
this._editor?.value
);
if (!validation.valid) {
throw Error(validation.message);
}
await setHassioAddonOption(this.hass, this.addon.slug, {
options: this._yamlMode ? this._editor?.value : this._options,
});

View File

@ -244,9 +244,6 @@ class HassioRegistriesDialog extends LitElement {
mwc-list-item span[slot="secondary"] {
color: var(--secondary-text-color);
}
ha-paper-dropdown-menu {
display: block;
}
`,
];
}

View File

@ -150,9 +150,6 @@ class HassioRepositoriesDialog extends LitElement {
mwc-button {
margin-left: 8px;
}
ha-paper-dropdown-menu {
display: block;
}
ha-circular-progress {
display: block;
margin: 32px;

View File

@ -1,15 +1,17 @@
import "@material/mwc-button";
import { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical, mdiPlus } from "@mdi/js";
import { mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import memoizeOne from "memoize-one";
import { atLeastVersion } from "../../../src/common/config/version";
import relativeTime from "../../../src/common/datetime/relative_time";
@ -17,18 +19,25 @@ import { HASSDomEvent } from "../../../src/common/dom/fire_event";
import {
DataTableColumnContainer,
RowClickedEvent,
SelectionChangedEvent,
} from "../../../src/components/data-table/ha-data-table";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-fab";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import {
fetchHassioSnapshots,
friendlyFolderName,
HassioSnapshot,
reloadHassioSnapshots,
removeSnapshot,
} from "../../../src/data/hassio/snapshot";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../src/dialogs/generic/show-dialog-box";
import "../../../src/layouts/hass-tabs-subpage-data-table";
import type { HaTabsSubpageDataTable } from "../../../src/layouts/hass-tabs-subpage-data-table";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant, Route } from "../../../src/types";
import { showHassioCreateSnapshotDialog } from "../dialogs/snapshot/show-dialog-hassio-create-snapshot";
@ -49,10 +58,15 @@ export class HassioSnapshots extends LitElement {
@property({ type: Boolean }) public isWide!: boolean;
private _firstUpdatedCalled = false;
@state() private _selectedSnapshots: string[] = [];
@state() private _snapshots?: HassioSnapshot[] = [];
@query("hass-tabs-subpage-data-table", true)
private _dataTable!: HaTabsSubpageDataTable;
private _firstUpdatedCalled = false;
public connectedCallback(): void {
super.connectedCallback();
if (this.hass && this._firstUpdatedCalled) {
@ -153,7 +167,9 @@ export class HassioSnapshots extends LitElement {
.data=${this._snapshotData(this._snapshots || [])}
id="slug"
@row-click=${this._handleRowClicked}
@selection-changed=${this._handleSelectionChanged}
clickable
selectable
hasFab
main-page
supervisor
@ -176,6 +192,45 @@ export class HassioSnapshots extends LitElement {
: ""}
</ha-button-menu>
${this._selectedSnapshots.length
? html`<div
class=${classMap({
"header-toolbar": this.narrow,
"table-header": !this.narrow,
})}
slot="header"
>
<p class="selected-txt">
${this.supervisor.localize("snapshot.selected", {
number: this._selectedSnapshots.length,
})}
</p>
<div class="header-btns">
${!this.narrow
? html`
<mwc-button
@click=${this._deleteSelected}
class="warning"
>
${this.supervisor.localize("snapshot.delete_selected")}
</mwc-button>
`
: html`
<mwc-icon-button
id="delete-btn"
class="warning"
@click=${this._deleteSelected}
>
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
</mwc-icon-button>
<paper-tooltip animation-delay="0" for="delete-btn">
${this.supervisor.localize("snapshot.delete_selected")}
</paper-tooltip>
`}
</div>
</div> `
: ""}
<ha-fab
slot="fab"
@click=${this._createSnapshot}
@ -199,6 +254,12 @@ export class HassioSnapshots extends LitElement {
}
}
private _handleSelectionChanged(
ev: HASSDomEvent<SelectionChangedEvent>
): void {
this._selectedSnapshots = ev.detail.value;
}
private _showUploadSnapshotDialog() {
showSnapshotUploadDialog(this, {
showSnapshot: (slug: string) =>
@ -216,6 +277,35 @@ export class HassioSnapshots extends LitElement {
this._snapshots = await fetchHassioSnapshots(this.hass);
}
private async _deleteSelected() {
const confirm = await showConfirmationDialog(this, {
title: this.supervisor.localize("snapshot.delete_snapshot_title"),
text: this.supervisor.localize("snapshot.delete_snapshot_text", {
number: this._selectedSnapshots.length,
}),
confirmText: this.supervisor.localize("snapshot.delete_snapshot_confirm"),
});
if (!confirm) {
return;
}
try {
await Promise.all(
this._selectedSnapshots.map((slug) => removeSnapshot(this.hass, slug))
);
} catch (err) {
showAlertDialog(this, {
title: this.supervisor.localize("snapshot.failed_to_delete"),
text: extractApiErrorMessage(err),
});
return;
}
await reloadHassioSnapshots(this.hass);
this._snapshots = await fetchHassioSnapshots(this.hass);
this._dataTable.clearSelection();
}
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
const slug = ev.detail.id;
showHassioSnapshotDialog(this, {
@ -244,7 +334,45 @@ export class HassioSnapshots extends LitElement {
}
static get styles(): CSSResultGroup {
return [haStyle, hassioStyle];
return [
haStyle,
hassioStyle,
css`
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 58px;
border-bottom: 1px solid rgba(var(--rgb-primary-text-color), 0.12);
}
.header-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
color: var(--secondary-text-color);
position: relative;
top: -4px;
}
.selected-txt {
font-weight: bold;
padding-left: 16px;
color: var(--primary-text-color);
}
.table-header .selected-txt {
margin-top: 20px;
}
.header-toolbar .selected-txt {
font-size: 16px;
}
.header-toolbar .header-btns {
margin-right: -12px;
}
.header-btns > mwc-button,
.header-btns > mwc-icon-button {
margin: 8px;
}
`,
];
}
}

View File

@ -71,7 +71,6 @@
"@polymer/iron-label": "^3.0.1",
"@polymer/iron-overlay-behavior": "^3.0.2",
"@polymer/iron-resizable-behavior": "^3.0.1",
"@polymer/paper-card": "^3.0.1",
"@polymer/paper-checkbox": "^3.1.0",
"@polymer/paper-dialog": "^3.0.1",
"@polymer/paper-dialog-behavior": "^3.0.1",

View File

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

View File

@ -0,0 +1,2 @@
export const escapeRegExp = (text: string): string =>
text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");

View File

@ -0,0 +1,6 @@
import { refine, string } from "superstruct";
const isCustomType = (value: string) => value.startsWith("custom:");
export const customType = () =>
refine(string(), "custom element type", isCustomType);

View File

@ -1,11 +1,6 @@
import { refine, string } from "superstruct";
const isEntityId = (value: string): boolean => {
if (!value.includes(".")) {
return false;
}
return true;
};
const isEntityId = (value: string): boolean => value.includes(".");
export const entityId = () =>
refine(string(), "entity ID (domain.entity)", isEntityId);

View File

@ -1,10 +1,5 @@
import { refine, string } from "superstruct";
const isIcon = (value: string) => {
if (!value.includes(":")) {
return false;
}
return true;
};
const isIcon = (value: string) => value.includes(":");
export const icon = () => refine(string(), "icon (mdi:icon-name)", isIcon);

View File

@ -86,11 +86,15 @@ export const computeLocalize = async (
| undefined;
if (!translatedMessage) {
translatedMessage = new IntlMessageFormat(
translatedValue,
language,
formats
);
try {
translatedMessage = new IntlMessageFormat(
translatedValue,
language,
formats
);
} catch (err) {
return "Translation error: " + err.message;
}
cache._localizationCache[messageKey] = translatedMessage;
}

View File

@ -4,7 +4,6 @@ import {
fetchDeviceActions,
localizeDeviceAutomationAction,
} from "../../data/device_automation";
import "../ha-paper-dropdown-menu";
import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
@customElement("ha-device-action-picker")

View File

@ -4,7 +4,6 @@ import {
fetchDeviceConditions,
localizeDeviceAutomationCondition,
} from "../../data/device_automation";
import "../ha-paper-dropdown-menu";
import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
@customElement("ha-device-condition-picker")

View File

@ -4,7 +4,6 @@ import {
fetchDeviceTriggers,
localizeDeviceAutomationTrigger,
} from "../../data/device_automation";
import "../ha-paper-dropdown-menu";
import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
@customElement("ha-device-trigger-picker")

View File

@ -54,17 +54,17 @@ class HaAttributes extends LitElement {
</div>
`
)}
${this.stateObj.attributes.attribution
? html`
<div class="attribution">
${this.stateObj.attributes.attribution}
</div>
`
: ""}
`
: ""}
</div>
</ha-expansion-panel>
${this.stateObj.attributes.attribution
? html`
<div class="attribution">
${this.stateObj.attributes.attribution}
</div>
`
: ""}
`;
}
@ -91,6 +91,7 @@ class HaAttributes extends LitElement {
.attribution {
color: var(--secondary-text-color);
text-align: center;
margin-top: 16px;
}
pre {
font-family: inherit;

View File

@ -1,4 +1,4 @@
import { dump, load } from "js-yaml";
import { DEFAULT_SCHEMA, dump, load, Schema } from "js-yaml";
import { html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
@ -20,6 +20,8 @@ const isEmpty = (obj: Record<string, unknown>): boolean => {
export class HaYamlEditor extends LitElement {
@property() public value?: any;
@property({ attribute: false }) public yamlSchema: Schema = DEFAULT_SCHEMA;
@property() public defaultValue?: any;
@property() public isValid = true;
@ -30,7 +32,10 @@ export class HaYamlEditor extends LitElement {
public setValue(value): void {
try {
this._yaml = value && !isEmpty(value) ? dump(value) : "";
this._yaml =
value && !isEmpty(value)
? dump(value, { schema: this.yamlSchema })
: "";
} catch (err) {
// eslint-disable-next-line no-console
console.error(err, value);
@ -67,7 +72,7 @@ export class HaYamlEditor extends LitElement {
if (this._yaml) {
try {
parsed = load(this._yaml);
parsed = load(this._yaml, { schema: this.yamlSchema });
} catch (err) {
// Invalid YAML
isValid = false;

View File

@ -45,7 +45,6 @@ import "../ha-button-menu";
import "../ha-card";
import "../ha-circular-progress";
import "../ha-fab";
import "../ha-paper-dropdown-menu";
import "../ha-svg-icon";
declare global {

View File

@ -212,13 +212,15 @@ export const setHassioAddonOption = async (
export const validateHassioAddonOption = async (
hass: HomeAssistant,
slug: string
slug: string,
data?: any
): Promise<{ message: string; valid: boolean }> => {
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
return hass.callWS({
type: "supervisor/api",
endpoint: `/addons/${slug}/options/validate`,
method: "post",
data,
});
}

View File

@ -130,6 +130,21 @@ export const createHassioFullSnapshot = async (
);
};
export const removeSnapshot = async (hass: HomeAssistant, slug: string) => {
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
await hass.callWS({
type: "supervisor/api",
endpoint: `/snapshots/${slug}/remove`,
method: "post",
});
return;
}
await hass.callApi<HassioResponse<void>>(
"POST",
`hassio/snapshots/${slug}/remove`
);
};
export const createHassioPartialSnapshot = async (
hass: HomeAssistant,
data: HassioPartialSnapshotCreateParams

View File

@ -36,18 +36,16 @@ export const getIcon = (iconName: string) =>
.then((icon) => resolve_(icon))
.catch((e) => reject_(e));
}
})
)
.catch((e) => {
// Firefox in private mode doesn't support IDB
// Safari sometime doesn't open the DB so we time out
for (const [, , reject_] of toRead) {
reject_(e);
}
})
.finally(() => {
toRead = [];
});
})
).catch((e) => {
// Firefox in private mode doesn't support IDB
// Safari sometime doesn't open the DB so we time out
for (const [, , reject_] of toRead) {
reject_(e);
}
toRead = [];
});
});
export const findIconChunk = (icon: string): string => {

View File

@ -1,74 +0,0 @@
import "@polymer/paper-card/paper-card";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { enableWrite } from "../common/auth/token_storage";
import LocalizeMixin from "../mixins/localize-mixin";
import "../styles/polymer-ha-style";
class HaStoreAuth extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="ha-style">
paper-card {
position: fixed;
padding: 8px 0;
bottom: 16px;
right: 16px;
}
.card-content {
color: var(--primary-text-color);
}
.card-actions {
text-align: right;
border-top: 0;
margin-right: -4px;
}
:host(.small) paper-card {
bottom: 0;
left: 0;
right: 0;
}
</style>
<paper-card elevation="4">
<div class="card-content">[[localize('ui.auth_store.ask')]]</div>
<div class="card-actions">
<mwc-button on-click="_done"
>[[localize('ui.auth_store.decline')]]</mwc-button
>
<mwc-button raised on-click="_save"
>[[localize('ui.auth_store.confirm')]]</mwc-button
>
</div>
</paper-card>
`;
}
static get properties() {
return {
hass: Object,
};
}
ready() {
super.ready();
this.classList.toggle("small", window.innerWidth < 600);
}
_save() {
enableWrite();
this._done();
}
_done() {
const card = this.shadowRoot.querySelector("paper-card");
card.style.transition = "bottom .25s";
card.style.bottom = `-${card.offsetHeight + 8}px`;
setTimeout(() => this.parentNode.removeChild(this), 300);
}
}
customElements.define("ha-store-auth-card", HaStoreAuth);

View File

@ -0,0 +1,75 @@
import { LitElement, TemplateResult, html, css } from "lit";
import { property } from "lit/decorators";
import { enableWrite } from "../common/auth/token_storage";
import { HomeAssistant } from "../types";
import "../components/ha-card";
import type { HaCard } from "../components/ha-card";
import "@material/mwc-button/mwc-button";
class HaStoreAuth extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
protected render(): TemplateResult {
return html`
<ha-card>
<div class="card-content">
${this.hass.localize("ui.auth_store.ask")}
</div>
<div class="card-actions">
<mwc-button @click=${this._dismiss}>
${this.hass.localize("ui.auth_store.decline")}
</mwc-button>
<mwc-button raised @click=${this._save}>
${this.hass.localize("ui.auth_store.confirm")}
</mwc-button>
</div>
</ha-card>
`;
}
firstUpdated() {
this.classList.toggle("small", window.innerWidth < 600);
}
private _save(): void {
enableWrite();
this._dismiss();
}
private _dismiss(): void {
const card = this.shadowRoot!.querySelector("ha-card") as HaCard;
card.style.bottom = `-${card.offsetHeight + 8}px`;
setTimeout(() => this.parentNode!.removeChild(this), 300);
}
static get styles() {
return css`
ha-card {
position: fixed;
padding: 8px 0;
bottom: 16px;
right: 16px;
transition: bottom 0.25s;
}
.card-actions {
text-align: right;
border-top: 0;
}
:host(.small) ha-card {
bottom: 0;
left: 0;
right: 0;
}
`;
}
}
customElements.define("ha-store-auth-card", HaStoreAuth);
declare global {
interface HTMLElementTagNameMap {
"ha-store-auth-card": HaStoreAuth;
}
}

View File

@ -6,7 +6,7 @@ import { TagTrigger } from "../../../../../data/automation";
import { fetchTags, Tag } from "../../../../../data/tag";
import { HomeAssistant } from "../../../../../types";
import { TriggerElement } from "../ha-automation-trigger-row";
import "../../../../../components/ha-paper-dropdown-menu";
@customElement("ha-automation-trigger-tag")
export class HaTagTrigger extends LitElement implements TriggerElement {
@property({ attribute: false }) public hass!: HomeAssistant;

View File

@ -193,9 +193,6 @@ class HaInputNumberForm extends LitElement {
.form {
color: var(--primary-text-color);
}
ha-paper-dropdown-menu {
display: block;
}
`,
];
}

View File

@ -196,9 +196,6 @@ class HaInputSelectForm extends LitElement {
mwc-button {
margin-left: 8px;
}
ha-paper-dropdown-menu {
display: block;
}
`,
];
}

View File

@ -179,9 +179,6 @@ class HaInputTextForm extends LitElement {
.row {
padding: 16px 0;
}
ha-paper-dropdown-menu {
display: block;
}
`,
];
}

View File

@ -11,8 +11,8 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { dump, load } from "js-yaml";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import { isPatternInWord } from "../../../common/string/filter/filter";
import { computeRTL } from "../../../common/util/compute_rtl";
import { escapeRegExp } from "../../../common/string/escape_regexp";
import { copyToClipboard } from "../../../common/util/copy-clipboard";
import "../../../components/entity/ha-entity-picker";
import "../../../components/ha-code-editor";
@ -412,72 +412,68 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
}
computeEntities(hass, _entityFilter, _stateFilter, _attributeFilter) {
const _entityFilterLength = _entityFilter && _entityFilter.length;
const _entityFilterLow = _entityFilter && _entityFilter.toLowerCase();
const entityFilterRegExp =
_entityFilter &&
RegExp(escapeRegExp(_entityFilter).replace(/\\\*/g, ".*"), "i");
return Object.keys(hass.states)
.map((key) => hass.states[key])
const stateFilterRegExp =
_stateFilter &&
RegExp(escapeRegExp(_stateFilter).replace(/\\\*/g, ".*"), "i");
let keyFilterRegExp;
let valueFilterRegExp;
let multiMode = false;
if (_attributeFilter) {
const colonIndex = _attributeFilter.indexOf(":");
multiMode = colonIndex !== -1;
const keyFilter = multiMode
? _attributeFilter.substring(0, colonIndex).trim()
: _attributeFilter;
const valueFilter = multiMode
? _attributeFilter.substring(colonIndex + 1).trim()
: _attributeFilter;
keyFilterRegExp = RegExp(
escapeRegExp(keyFilter).replace(/\\\*/g, ".*"),
"i"
);
valueFilterRegExp = multiMode
? RegExp(escapeRegExp(valueFilter).replace(/\\\*/g, ".*"), "i")
: keyFilterRegExp;
}
return Object.values(hass.states)
.filter((value) => {
if (
_entityFilter &&
!isPatternInWord(
_entityFilterLow,
0,
_entityFilterLength,
value.entity_id.toLowerCase(),
0,
value.entity_id.length,
true
) &&
entityFilterRegExp &&
!entityFilterRegExp.test(value.entity_id) &&
(value.attributes.friendly_name === undefined ||
!isPatternInWord(
_entityFilterLow,
0,
_entityFilterLength,
value.attributes.friendly_name.toLowerCase(),
0,
value.attributes.friendly_name.length,
true
))
!entityFilterRegExp.test(value.attributes.friendly_name))
) {
return false;
}
if (!value.state.toLowerCase().includes(_stateFilter.toLowerCase())) {
if (stateFilterRegExp && !stateFilterRegExp.test(value.state)) {
return false;
}
if (_attributeFilter !== "") {
const attributeFilter = _attributeFilter.toLowerCase();
const colonIndex = attributeFilter.indexOf(":");
const multiMode = colonIndex !== -1;
let keyFilter = attributeFilter;
let valueFilter = attributeFilter;
if (multiMode) {
// we need to filter keys and values separately
keyFilter = attributeFilter.substring(0, colonIndex).trim();
valueFilter = attributeFilter.substring(colonIndex + 1).trim();
}
const attributeKeys = Object.keys(value.attributes);
for (let i = 0; i < attributeKeys.length; i++) {
const key = attributeKeys[i];
if (key.includes(keyFilter) && !multiMode) {
if (keyFilterRegExp && valueFilterRegExp) {
for (const [key, attributeValue] of Object.entries(
value.attributes
)) {
const match = keyFilterRegExp.test(key);
if (match && !multiMode) {
return true; // in single mode we're already satisfied with this match
}
if (!key.includes(keyFilter) && multiMode) {
if (!match && multiMode) {
continue;
}
const attributeValue = value.attributes[key];
if (
attributeValue !== undefined &&
JSON.stringify(attributeValue).toLowerCase().includes(valueFilter)
valueFilterRegExp.test(JSON.stringify(attributeValue))
) {
return true;
}

View File

@ -15,7 +15,8 @@ import "../../components/hui-action-editor";
import "../../components/hui-entity-editor";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import { actionConfigStruct, EditorTarget } from "../types";
import { actionConfigStruct } from "../structs/action-struct";
import { EditorTarget } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -5,15 +5,20 @@ import "@polymer/paper-listbox/paper-listbox";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import {
any,
array,
assert,
boolean,
literal,
number,
object,
optional,
string,
type,
union,
} from "superstruct";
import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event";
import { customType } from "../../../../common/structs/is-custom-type";
import { entityId } from "../../../../common/structs/is-entity-id";
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
import "../../../../components/entity/state-badge";
@ -25,20 +30,127 @@ import type { HomeAssistant } from "../../../../types";
import type { EntitiesCardConfig } from "../../cards/types";
import "../../components/hui-theme-select-editor";
import type { LovelaceRowConfig } from "../../entity-rows/types";
import { headerFooterConfigStructs } from "../../header-footer/types";
import { headerFooterConfigStructs } from "../../header-footer/structs";
import type { LovelaceCardEditor } from "../../types";
import "../header-footer-editor/hui-header-footer-editor";
import "../hui-entities-card-row-editor";
import "../hui-sub-element-editor";
import { processEditorEntities } from "../process-editor-entities";
import { actionConfigStruct } from "../structs/action-struct";
import { entitiesConfigStruct } from "../structs/entities-struct";
import {
EditorTarget,
EditSubElementEvent,
entitiesConfigStruct,
SubElementEditorConfig,
} from "../types";
import { configElementStyle } from "./config-elements-style";
const buttonEntitiesRowConfigStruct = object({
type: literal("button"),
name: string(),
action_name: optional(string()),
tap_action: actionConfigStruct,
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
});
const castEntitiesRowConfigStruct = object({
type: literal("cast"),
view: union([string(), number()]),
dashboard: optional(string()),
name: optional(string()),
icon: optional(string()),
hide_if_unavailable: optional(boolean()),
});
const callServiceEntitiesRowConfigStruct = object({
type: literal("call-service"),
name: string(),
service: string(),
icon: optional(string()),
action_name: optional(string()),
service_data: optional(any()),
});
const conditionalEntitiesRowConfigStruct = object({
type: literal("conditional"),
row: any(),
conditions: array(
object({
entity: string(),
state: optional(string()),
state_not: optional(string()),
})
),
});
const dividerEntitiesRowConfigStruct = object({
type: literal("divider"),
style: optional(any()),
});
const sectionEntitiesRowConfigStruct = object({
type: literal("section"),
label: optional(string()),
});
const webLinkEntitiesRowConfigStruct = object({
type: literal("weblink"),
url: string(),
name: optional(string()),
icon: optional(string()),
});
const buttonsEntitiesRowConfigStruct = object({
type: literal("buttons"),
entities: array(
union([
object({
entity: string(),
icon: optional(string()),
image: optional(string()),
name: optional(string()),
}),
string(),
])
),
});
const attributeEntitiesRowConfigStruct = object({
type: literal("attribute"),
entity: string(),
attribute: string(),
prefix: optional(string()),
suffix: optional(string()),
name: optional(string()),
});
const textEntitiesRowConfigStruct = object({
type: literal("text"),
name: string(),
text: string(),
icon: optional(string()),
});
const customRowConfigStruct = type({
type: customType(),
});
const entitiesRowConfigStruct = union([
entitiesConfigStruct,
buttonEntitiesRowConfigStruct,
castEntitiesRowConfigStruct,
conditionalEntitiesRowConfigStruct,
dividerEntitiesRowConfigStruct,
sectionEntitiesRowConfigStruct,
webLinkEntitiesRowConfigStruct,
buttonsEntitiesRowConfigStruct,
attributeEntitiesRowConfigStruct,
callServiceEntitiesRowConfigStruct,
textEntitiesRowConfigStruct,
customRowConfigStruct,
]);
const cardConfigStruct = object({
type: string(),
title: optional(union([string(), boolean()])),
@ -47,7 +159,7 @@ const cardConfigStruct = object({
icon: optional(string()),
show_header_toggle: optional(boolean()),
state_color: optional(boolean()),
entities: array(entitiesConfigStruct),
entities: array(entitiesRowConfigStruct),
header: optional(headerFooterConfigStructs),
footer: optional(headerFooterConfigStructs),
});

View File

@ -11,7 +11,7 @@ import { EntityCardConfig } from "../../cards/types";
import "../../components/hui-action-editor";
import "../../components/hui-entity-editor";
import "../../components/hui-theme-select-editor";
import { headerFooterConfigStructs } from "../../header-footer/types";
import { headerFooterConfigStructs } from "../../header-footer/structs";
import { LovelaceCardEditor } from "../../types";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";

View File

@ -14,11 +14,8 @@ import "../../components/hui-action-editor";
import "../../components/hui-entity-editor";
import "../../components/hui-theme-select-editor";
import { LovelaceRowEditor } from "../../types";
import {
EditorTarget,
entitiesConfigStruct,
EntitiesEditorEvent,
} from "../types";
import { entitiesConfigStruct } from "../structs/entities-struct";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = {

View File

@ -26,11 +26,8 @@ import "../../components/hui-entity-editor";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import { processEditorEntities } from "../process-editor-entities";
import {
EditorTarget,
entitiesConfigStruct,
EntitiesEditorEvent,
} from "../types";
import { entitiesConfigStruct } from "../structs/entities-struct";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -8,10 +8,8 @@ import "../../../../components/entity/ha-entity-picker";
import "../../../../components/ha-formfield";
import "../../../../components/ha-switch";
import type { HomeAssistant } from "../../../../types";
import {
GraphHeaderFooterConfig,
graphHeaderFooterConfigStruct,
} from "../../header-footer/types";
import { graphHeaderFooterConfigStruct } from "../../header-footer/structs";
import { GraphHeaderFooterConfig } from "../../header-footer/types";
import type { LovelaceCardEditor } from "../../types";
import type { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";

View File

@ -1,34 +1,18 @@
import "@polymer/paper-input/paper-input";
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import {
array,
assert,
number,
object,
optional,
string,
union,
} from "superstruct";
import { array, assert, number, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import { entityId } from "../../../../common/structs/is-entity-id";
import { HomeAssistant } from "../../../../types";
import { HistoryGraphCardConfig } from "../../cards/types";
import "../../components/hui-entity-editor";
import { EntityConfig } from "../../entity-rows/types";
import { LovelaceCardEditor } from "../../types";
import { processEditorEntities } from "../process-editor-entities";
import { entitiesConfigStruct } from "../structs/entities-struct";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const entitiesConfigStruct = union([
object({
entity: entityId(),
name: optional(string()),
}),
entityId(),
]);
const cardConfigStruct = object({
type: string(),
entities: array(entitiesConfigStruct),

View File

@ -12,7 +12,8 @@ import "../../components/hui-action-editor";
import "../../components/hui-entity-editor";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import { actionConfigStruct, EditorTarget } from "../types";
import { actionConfigStruct } from "../structs/action-struct";
import { EditorTarget } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -22,11 +22,8 @@ import "../../components/hui-input-list-editor";
import { EntityConfig } from "../../entity-rows/types";
import { LovelaceCardEditor } from "../../types";
import { processEditorEntities } from "../process-editor-entities";
import {
EditorTarget,
entitiesConfigStruct,
EntitiesEditorEvent,
} from "../types";
import { entitiesConfigStruct } from "../structs/entities-struct";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -9,7 +9,8 @@ import { PictureCardConfig } from "../../cards/types";
import "../../components/hui-action-editor";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import { actionConfigStruct, EditorTarget } from "../types";
import { actionConfigStruct } from "../structs/action-struct";
import { EditorTarget } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -16,7 +16,8 @@ import "../../components/hui-action-editor";
import "../../components/hui-entity-editor";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import { actionConfigStruct, EditorTarget } from "../types";
import { actionConfigStruct } from "../structs/action-struct";
import { EditorTarget } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -16,11 +16,9 @@ import "../../components/hui-theme-select-editor";
import { EntityConfig } from "../../entity-rows/types";
import { LovelaceCardEditor } from "../../types";
import { processEditorEntities } from "../process-editor-entities";
import {
actionConfigStruct,
EditorTarget,
entitiesConfigStruct,
} from "../types";
import { actionConfigStruct } from "../structs/action-struct";
import { entitiesConfigStruct } from "../structs/entities-struct";
import { EditorTarget } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -11,11 +11,8 @@ import { HomeAssistant } from "../../../../types";
import { WeatherForecastCardConfig } from "../../cards/types";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
import {
actionConfigStruct,
EditorTarget,
EntitiesEditorEvent,
} from "../types";
import { actionConfigStruct } from "../structs/action-struct";
import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = object({

View File

@ -5,7 +5,6 @@ import "@polymer/paper-listbox/paper-listbox";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-paper-dropdown-menu";
import "../../../../components/ha-svg-icon";
import type { LovelaceConfig } from "../../../../data/lovelace";
import type { HomeAssistant } from "../../../../types";

View File

@ -0,0 +1,67 @@
import {
object,
string,
union,
boolean,
optional,
array,
literal,
enums,
} from "superstruct";
const actionConfigStructUser = object({
user: string(),
});
const actionConfigStructConfirmation = union([
boolean(),
object({
text: optional(string()),
excemptions: optional(array(actionConfigStructUser)),
}),
]);
const actionConfigStructUrl = object({
action: literal("url"),
url_path: string(),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructService = object({
action: literal("call-service"),
service: string(),
service_data: optional(object()),
target: optional(
object({
entity_id: optional(union([string(), array(string())])),
device_id: optional(union([string(), array(string())])),
area_id: optional(union([string(), array(string())])),
})
),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructNavigate = object({
action: literal("navigate"),
navigation_path: string(),
confirmation: optional(actionConfigStructConfirmation),
});
export const actionConfigStructType = object({
action: enums([
"none",
"toggle",
"more-info",
"call-service",
"url",
"navigate",
]),
confirmation: optional(actionConfigStructConfirmation),
});
export const actionConfigStruct = union([
actionConfigStructType,
actionConfigStructUrl,
actionConfigStructNavigate,
actionConfigStructService,
]);

View File

@ -0,0 +1,18 @@
import { union, object, string, optional, boolean } from "superstruct";
import { actionConfigStruct } from "./action-struct";
export const entitiesConfigStruct = union([
object({
entity: string(),
name: optional(string()),
icon: optional(string()),
image: optional(string()),
secondary_info: optional(string()),
format: optional(string()),
state_color: optional(boolean()),
tap_action: optional(actionConfigStruct),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
}),
string(),
]);

View File

@ -1,16 +1,3 @@
import {
any,
array,
boolean,
dynamic,
enums,
literal,
number,
object,
optional,
string,
union,
} from "superstruct";
import {
ActionConfig,
LovelaceCardConfig,
@ -94,175 +81,3 @@ export interface SubElementEditorConfig {
export interface EditSubElementEvent {
subElementConfig: SubElementEditorConfig;
}
export const actionConfigStruct = dynamic((_value, ctx) => {
if (ctx.branch[0][ctx.path[0]]) {
return (
actionConfigMap[ctx.branch[0][ctx.path[0]].action] ||
actionConfigStructType
);
}
return actionConfigStructType;
});
const actionConfigStructUser = object({
user: string(),
});
const actionConfigStructConfirmation = union([
boolean(),
object({
text: optional(string()),
excemptions: optional(array(actionConfigStructUser)),
}),
]);
const actionConfigStructUrl = object({
action: literal("url"),
url_path: string(),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructService = object({
action: literal("call-service"),
service: string(),
service_data: optional(object()),
target: optional(
object({
entity_id: optional(union([string(), array(string())])),
device_id: optional(union([string(), array(string())])),
area_id: optional(union([string(), array(string())])),
})
),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructNavigate = object({
action: literal("navigate"),
navigation_path: string(),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigMap = {
url: actionConfigStructUrl,
navigate: actionConfigStructNavigate,
"call-service": actionConfigStructService,
};
export const actionConfigStructType = object({
action: enums([
"none",
"toggle",
"more-info",
"call-service",
"url",
"navigate",
]),
confirmation: optional(actionConfigStructConfirmation),
});
const buttonEntitiesRowConfigStruct = object({
type: string(),
name: string(),
action_name: optional(string()),
tap_action: actionConfigStruct,
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
});
const castEntitiesRowConfigStruct = object({
type: string(),
view: union([string(), number()]),
dashboard: optional(string()),
name: optional(string()),
icon: optional(string()),
hide_if_unavailable: optional(boolean()),
});
const callServiceEntitiesRowConfigStruct = object({
type: string(),
name: string(),
service: string(),
icon: optional(string()),
action_name: optional(string()),
service_data: optional(any()),
});
const conditionalEntitiesRowConfigStruct = object({
type: string(),
row: any(),
conditions: array(
object({
entity: string(),
state: optional(string()),
state_not: optional(string()),
})
),
});
const dividerEntitiesRowConfigStruct = object({
type: string(),
style: optional(any()),
});
const sectionEntitiesRowConfigStruct = object({
type: string(),
label: optional(string()),
});
const webLinkEntitiesRowConfigStruct = object({
type: string(),
url: string(),
name: optional(string()),
icon: optional(string()),
});
const buttonsEntitiesRowConfigStruct = object({
type: string(),
entities: array(
union([
object({
entity: string(),
icon: optional(string()),
image: optional(string()),
name: optional(string()),
}),
string(),
])
),
});
const attributeEntitiesRowConfigStruct = object({
type: string(),
entity: string(),
attribute: string(),
prefix: optional(string()),
suffix: optional(string()),
name: optional(string()),
});
export const entitiesConfigStruct = union([
object({
entity: string(),
name: optional(string()),
icon: optional(string()),
image: optional(string()),
secondary_info: optional(string()),
format: optional(string()),
state_color: optional(boolean()),
tap_action: optional(actionConfigStruct),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
}),
string(),
buttonEntitiesRowConfigStruct,
castEntitiesRowConfigStruct,
conditionalEntitiesRowConfigStruct,
dividerEntitiesRowConfigStruct,
sectionEntitiesRowConfigStruct,
webLinkEntitiesRowConfigStruct,
buttonsEntitiesRowConfigStruct,
attributeEntitiesRowConfigStruct,
callServiceEntitiesRowConfigStruct,
]);

View File

@ -0,0 +1,29 @@
import { object, string, optional, array, number, union } from "superstruct";
import { actionConfigStruct } from "../editor/structs/action-struct";
import { entitiesConfigStruct } from "../editor/structs/entities-struct";
export const pictureHeaderFooterConfigStruct = object({
type: string(),
image: string(),
tap_action: optional(actionConfigStruct),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
});
export const buttonsHeaderFooterConfigStruct = object({
type: string(),
entities: array(entitiesConfigStruct),
});
export const graphHeaderFooterConfigStruct = object({
type: string(),
entity: string(),
detail: optional(number()),
hours_to_show: optional(number()),
});
export const headerFooterConfigStructs = union([
pictureHeaderFooterConfigStruct,
buttonsHeaderFooterConfigStruct,
graphHeaderFooterConfigStruct,
]);

View File

@ -1,6 +1,4 @@
import { array, number, object, optional, string, union } from "superstruct";
import { ActionConfig } from "../../../data/lovelace";
import { actionConfigStruct, entitiesConfigStruct } from "../editor/types";
import { EntityConfig } from "../entity-rows/types";
export interface LovelaceHeaderFooterConfig {
@ -27,29 +25,3 @@ export interface PictureHeaderFooterConfig extends LovelaceHeaderFooterConfig {
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
}
export const pictureHeaderFooterConfigStruct = object({
type: string(),
image: string(),
tap_action: optional(actionConfigStruct),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
});
export const buttonsHeaderFooterConfigStruct = object({
type: string(),
entities: array(entitiesConfigStruct),
});
export const graphHeaderFooterConfigStruct = object({
type: string(),
entity: string(),
detail: optional(number()),
hours_to_show: optional(number()),
});
export const headerFooterConfigStructs = union([
pictureHeaderFooterConfigStruct,
buttonsHeaderFooterConfigStruct,
graphHeaderFooterConfigStruct,
]);

View File

@ -17,7 +17,6 @@ import "../../components/ha-paper-dropdown-menu";
import "../../components/ha-radio";
import type { HaRadio } from "../../components/ha-radio";
import "../../components/ha-settings-row";
import { Theme } from "../../data/ws-themes";
import {
DEFAULT_PRIMARY_COLOR,
DEFAULT_ACCENT_COLOR,
@ -33,10 +32,6 @@ export class HaPickThemeRow extends LitElement {
@state() _themeNames: string[] = [];
@state() _selectedThemeIndex = 0;
@state() _selectedTheme?: Theme;
protected render(): TemplateResult {
const hasThemes =
this.hass.themes.themes && Object.keys(this.hass.themes.themes).length;
@ -72,7 +67,8 @@ export class HaPickThemeRow extends LitElement {
>
<paper-listbox
slot="dropdown-content"
.selected=${this._selectedThemeIndex}
.selected=${this.hass.selectedTheme?.theme || "Backend-selected"}
attr-for-selected="theme"
@iron-select=${this._handleThemeSelection}
>
${this._themeNames.map(
@ -81,8 +77,7 @@ export class HaPickThemeRow extends LitElement {
</paper-listbox>
</ha-paper-dropdown-menu>
</ha-settings-row>
${curTheme === "default" ||
(this._selectedTheme && this._supportsModeSelection(this._selectedTheme))
${curTheme === "default" || this._supportsModeSelection(curTheme)
? html` <div class="inputs">
<ha-formfield
.label=${this.hass.localize(
@ -155,36 +150,17 @@ export class HaPickThemeRow extends LitElement {
`;
}
protected updated(changedProperties: PropertyValues) {
public willUpdate(changedProperties: PropertyValues) {
const oldHass = changedProperties.get("hass") as undefined | HomeAssistant;
const themesChanged =
changedProperties.has("hass") &&
(!oldHass || oldHass.themes.themes !== this.hass.themes.themes);
const selectedThemeChanged =
changedProperties.has("hass") &&
(!oldHass || oldHass.selectedTheme !== this.hass.selectedTheme);
if (themesChanged) {
this._themeNames = ["Backend-selected", "default"].concat(
Object.keys(this.hass.themes.themes).sort()
);
}
if (selectedThemeChanged) {
if (
this.hass.selectedTheme &&
this._themeNames.indexOf(this.hass.selectedTheme.theme) > 0
) {
this._selectedThemeIndex = this._themeNames.indexOf(
this.hass.selectedTheme.theme
);
this._selectedTheme = this.hass.themes.themes[
this.hass.selectedTheme.theme
];
} else if (!this.hass.selectedTheme) {
this._selectedThemeIndex = 0;
}
}
}
private _handleColorChange(ev: CustomEvent) {
@ -199,8 +175,8 @@ export class HaPickThemeRow extends LitElement {
});
}
private _supportsModeSelection(theme: Theme): boolean {
return theme.modes?.light !== undefined && theme.modes?.dark !== undefined;
private _supportsModeSelection(themeName: string): boolean {
return "modes" in this.hass.themes.themes[themeName];
}
private _handleDarkMode(ev: CustomEvent) {

View File

@ -32,8 +32,8 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
.then(() => import("../dialogs/ha-store-auth-card"))
.then(() => {
const el = document.createElement("ha-store-auth-card");
this.shadowRoot!.appendChild(el);
this.provideHass(el);
this.shadowRoot!.appendChild(el);
});
}
}

View File

@ -74,16 +74,15 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
const themeName =
themeSettings?.theme ||
(darkPreferred && this.hass.themes.default_dark_theme
? this.hass.themes.default_dark_theme!
? this.hass.themes.default_dark_theme
: this.hass.themes.default_theme);
let darkMode =
themeSettings?.dark === undefined ? darkPreferred : themeSettings?.dark;
const selectedTheme =
themeSettings?.theme !== undefined
? this.hass.themes.themes[themeSettings.theme]
: undefined;
const selectedTheme = themeName
? this.hass.themes.themes[themeName]
: undefined;
if (selectedTheme && darkMode && !selectedTheme.modes) {
darkMode = false;

View File

@ -3896,6 +3896,12 @@
"available_snapshots": "Available Snapshots",
"no_snapshots": "You don't have any snapshots yet.",
"create_blocked_not_running": "Creating a snapshot is not possible right now because the system is in {state} state.",
"delete_selected": "Delete selected snapshots",
"delete_snapshot_title": "Delete snapshot",
"delete_snapshot_text": "Do you want to delete {number} {number, plural,\n one {snapshot}\n other {snapshots}\n}?",
"delete_snapshot_confirm": "delete",
"selected": "{number} selected",
"failed_to_delete": "Failed to delete",
"could_not_create": "Could not create snapshot",
"upload_snapshot": "Upload snapshot",
"create_snapshot": "Create snapshot",

View File

@ -530,8 +530,11 @@
},
"light": {
"brightness": "Яркост",
"cold_white_value": "Студено бяла яркост",
"color_brightness": "Яркост на цвета",
"color_temperature": "Цветова температура",
"effect": "Ефект",
"warm_white_value": "Топло бяла яркост",
"white_value": "Стойност на бялото"
},
"lock": {
@ -679,6 +682,9 @@
"no_match": "Не са намерени съответстващи области",
"show_areas": "Показване на области"
},
"attributes": {
"expansion_header": "Атрибути"
},
"blueprint-picker": {
"add_user": "Добавяне на потребител",
"remove_user": "Премахване на потребител",
@ -1052,6 +1058,7 @@
"person": "Презареждане на хората",
"reload": "Презареждане на {domain}",
"rest": "Презареждане на REST обекти и услуги за нотификация",
"rpi_gpio": "Raspberry Pi GPIO обекти",
"scene": "Презареждане на сцените",
"script": "Презареждане на скриптовете",
"telegram": "Презареждане на Telegram услугите за нотификация",
@ -2215,6 +2222,8 @@
},
"network_status": {
"details": {
"driverfailed": "Неуспешно свързване с Z-Wave контролера",
"driverready": "Инициализиране на Z-Wave контролера",
"ready": "Готов за свързване",
"started": "Свързан към MQTT",
"starting": "Свързване към MQTT"
@ -2613,6 +2622,7 @@
"header": "Z-Wave конфигурация на устройството",
"introduction": "Управление и настройване на специфични конфигурационни параметри на подбраното устройството (възел, node)",
"parameter_is_read_only": "Този параметър е само за четене.",
"set_param_error": "Възникна грешка.",
"zwave_js_device_database": "Z-Wave JS база данни с устройства"
},
"node_status": {
@ -3483,12 +3493,15 @@
"reset": "Нулиране"
},
"time_format": {
"description": "Изберете как да се форматира времето.",
"dropdown_label": "Формат на времето",
"formats": {
"12": "12 часа (AM/PM)",
"24": "24 часа",
"language": "Авто (езикова настройка)",
"system": "Системна настройка"
}
},
"header": "Формат на времето"
},
"vibrate": {
"description": "Разрешаване или забраняване на вибрациите на това устройство при управление на устройства.",

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "Ara mateix no és possible crear una instantània perquè el sistema es troba en estat {state}.",
"create_snapshot": "Crea instantània",
"created": "Creada",
"delete_selected": "Suprimeix les instantànies seleccionades",
"delete_snapshot_confirm": "suprimeix",
"delete_snapshot_text": "Vols suprimir {number} {number, plural,\n one {instantània}\n other {instantànies}\n}?",
"delete_snapshot_title": "Suprimeix instantània",
"description": "Les instantànies et permeten fer una còpia de seguretat i recuperar les dades de la teva instància de Home Assistant.",
"enter_password": "Introdueix una contrasenya.",
"failed_to_delete": "No s'ha pogut suprimir",
"folder": {
"addons/local": "Complements locals",
"homeassistant": "Configuració de Home Assistant",
@ -404,6 +409,7 @@
"password_protection": "Protecció amb contrasenya",
"security": "Seguretat",
"select_type": "Selecciona què vols restaurar",
"selected": "{number} seleccionada/es",
"type": "Tipus d'instantània",
"upload_snapshot": "Puja instantània"
},

View File

@ -3786,7 +3786,7 @@
"working": "Vent venligst"
},
"initializing": "Initialiserer",
"logging_in_to_with": "Logger ind på ** {locationName} ** med ** {authProviderName} **.",
"logging_in_to_with": "Logger ind på **{locationName}** med **{authProviderName}**.",
"logging_in_with": "Log ind med **{authProviderName}**.",
"pick_auth_provider": "Eller log ind med"
},

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "Creating a snapshot is not possible right now because the system is in {state} state.",
"create_snapshot": "Create snapshot",
"created": "Created",
"delete_selected": "Delete selected snapshots",
"delete_snapshot_confirm": "delete",
"delete_snapshot_text": "Do you want to delete {number} {number, plural,\n one {snapshot}\n other {snapshots}\n}?",
"delete_snapshot_title": "Delete snapshot",
"description": "Snapshots allow you to easily backup and restore all data of your Home Assistant instance.",
"enter_password": "Please enter a password.",
"failed_to_delete": "Failed to delete",
"folder": {
"addons/local": "Local add-ons",
"homeassistant": "Home Assistant configuration",
@ -404,6 +409,7 @@
"password_protection": "Password protection",
"security": "Security",
"select_type": "Select what to restore",
"selected": "{number} selected",
"type": "Snapshot type",
"upload_snapshot": "Upload snapshot"
},

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "No es posible crear una instantánea en este momento porque el sistema está en el estado {state}.",
"create_snapshot": "Crear instantánea",
"created": "Creada",
"delete_selected": "Eliminar instantáneas seleccionadas",
"delete_snapshot_confirm": "Eliminar",
"delete_snapshot_text": "¿Deseas eliminar {number} {number, plural,\n one {instantánea}\n other {instantáneas}\n}?",
"delete_snapshot_title": "Eliminar instantánea",
"description": "Las instantáneas te permiten realizar copias de seguridad y restaurar fácilmente todos los datos de tu instancia de Home Assistant.",
"enter_password": "Por favor, introduce una contraseña.",
"failed_to_delete": "No se pudo eliminar",
"folder": {
"addons/local": "Complementos locales",
"homeassistant": "Configuración de Home Assistant",
@ -404,6 +409,7 @@
"password_protection": "Protección con contraseña",
"security": "Seguridad",
"select_type": "Selecciona qué restaurar",
"selected": "{number} {number, plural,\n one {seleccionada}\n other {seleccionadas}\n}",
"type": "Tipo de instantánea",
"upload_snapshot": "Subir instantánea"
},

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "Hetktõmmise loomine pole praegu võimalik kuna süsteem on olekus {state}.",
"create_snapshot": "Loo hetktõmmis",
"created": "Loodud",
"delete_selected": "Kustuta valitud hetktõmmised",
"delete_snapshot_confirm": "kustuta",
"delete_snapshot_text": "Kas kustutada {number} {number, plural,\n one {hetktõmmis}\n other {hetktõmmist}\n}?",
"delete_snapshot_title": "Kustuta hetktõmmis",
"description": "Hetktõmmised võimaldavad hõlpsalt varundada ja taastada kõik Home Assistanti andmed.",
"enter_password": "Sisesta salasõna.",
"failed_to_delete": "Kustutamine nurjus",
"folder": {
"addons/local": "Kohalikud lisandmoodulid",
"homeassistant": "Home Assistanti sätted",
@ -404,6 +409,7 @@
"password_protection": "Salasõnaga kaitstud",
"security": "Turvalisus",
"select_type": "Vali mida taastada",
"selected": "{number} valitud",
"type": "Hetktõmmise tüüp",
"upload_snapshot": "Hetktõmmise üleslaadimine"
},

View File

@ -58,6 +58,17 @@
},
"my": {
"error_addon_not_found": "Add-on net fûn"
},
"snapshot": {
"created": "Makke",
"delete_snapshot_confirm": "ferwiderje",
"failed_to_delete": "Ferwiderje is mislearre",
"selected": "{number} selekteare"
},
"system": {
"supervisor": {
"search": "Sykje"
}
}
},
"ui": {
@ -110,6 +121,9 @@
"name": "Namme"
}
},
"data-table": {
"clear": "Opklearje"
},
"device-picker": {
"device": "Apparaat",
"toggle": "Skeakelje"
@ -119,6 +133,14 @@
"generic": {
"cancel": "Annulearje"
},
"quick-bar": {
"commands": {
"types": {
"navigation": "Navigearje",
"server_control": "Server"
}
}
},
"zha_device_info": {
"zha_device_card": {
"device_name_placeholder": "Feroarje apparaatnamme"
@ -142,6 +164,12 @@
"type": {
"choose": {
"add_option": "Opsje tafoegje"
},
"device_id": {
"extra_fields": {
"mode": "Wize",
"value": "Wearde"
}
}
}
},
@ -199,6 +227,9 @@
}
},
"cloud": {
"account": {
"connecting": "Ferbine ..."
},
"alexa": {
"title": "Alexa"
},
@ -221,6 +252,21 @@
"info": {
"description": "Ynformaasje oer dyn Home Assistant ynstallaasje"
},
"integrations": {
"config_entry": {
"configure": "Ynstelle"
},
"disable": {
"show": "Toan"
}
},
"logs": {
"level": {
"critical": "KRITYSK",
"info": "YNFO",
"warning": "WARSKÔGING"
}
},
"lovelace": {
"description": "Konfigurearje dyn Lovelace-dashboards",
"resources": {
@ -241,6 +287,8 @@
"name": "Namme"
},
"picker": {
"duplicate": "Duplisearje",
"duplicate_scene": "Duplisearje sêne",
"headers": {
"name": "Namme"
}
@ -338,6 +386,13 @@
}
}
},
"page-onboarding": {
"analytics": {
"finish": "Folgjende"
},
"finish": "Ein",
"next": "Folgjende"
},
"profile": {
"advanced_mode": {
"link_promo": "Lear mear"
@ -349,6 +404,11 @@
"mfa_setup": {
"close": "Slute"
},
"number_format": {
"formats": {
"none": "Gjin"
}
},
"themes": {
"dark_mode": {
"dark": "Tsjuster",

View File

@ -314,7 +314,7 @@
"addon_new_version": "Nuova versione disponibile",
"addon_running": "Il componente aggiuntivo è in esecuzione",
"addon_stopped": "Il componente aggiuntivo viene arrestato",
"addons": "Componenti aggiuntivi",
"addons": "Componenti aggiuntivi installati",
"no_addons": "Non hai ancora installato alcun componente aggiuntivo. Vai al negozio di componenti aggiuntivi per iniziare!"
},
"dialog": {
@ -385,8 +385,13 @@
"create_blocked_not_running": "La creazione di un'istantanea non è al momento possibile perché il sistema è nello stato {state}.",
"create_snapshot": "Crea istantanea",
"created": "Creato",
"delete_selected": "Elimina le istantanee selezionate",
"delete_snapshot_confirm": "Elimina",
"delete_snapshot_text": "Vuoi eliminare {number} {number, plural,\n one {istantanea}\n other {istantanee}\n}?",
"delete_snapshot_title": "Elimina istantanea",
"description": "Le istantanee ti consentono di eseguire facilmente il backup e il ripristino di tutti i dati dell'istanza di Home Assistant.",
"enter_password": "Immettere una password.",
"failed_to_delete": "Impossibile eliminare",
"folder": {
"addons/local": "Componenti aggiuntivi locali",
"homeassistant": "Configurazione di Home Assistant",
@ -396,14 +401,16 @@
},
"folders": "Cartelle",
"full_snapshot": "Istantanea completa",
"name": "Nome",
"name": "Nome dell'istantanea",
"no_snapshots": "Non hai ancora nessuna istantanea.",
"partial_snapshot": "Istantanea parziale",
"password": "Password",
"password": "Password dell'istantanea",
"password_protected": "protetto da password",
"password_protection": "Protezione con password",
"security": "Sicurezza",
"type": "Tipo",
"select_type": "Seleziona cosa ripristinare",
"selected": "{number} selezionato/i",
"type": "Tipo di istantanea",
"upload_snapshot": "Invia istantanea"
},
"store": {
@ -720,6 +727,9 @@
"no_match": "Non sono state trovate aree corrispondenti",
"show_areas": "Mostra le aree"
},
"attributes": {
"expansion_header": "Attributi"
},
"blueprint-picker": {
"add_user": "Aggiungi utente",
"remove_user": "Rimuovi utente",
@ -1719,6 +1729,7 @@
"title": "Alexa"
},
"connected": "Connesso",
"connecting": "In collegamento...",
"connection_status": "Stato della connessione cloud",
"fetching_subscription": "Recupero iscrizione in corso...",
"google": {
@ -2959,6 +2970,7 @@
},
"logs": {
"log_level": "Livello di registro",
"log_level_changed": "Livello di registro modificato in: {level}",
"subscribed_to_logs": "Sottoscrizione al registro dei messaggi di Z-Wave JS ...",
"title": "Registri Z-Wave JS"
},

View File

@ -292,7 +292,7 @@
"save": "Opslaan",
"show_more": "Toon meer informatie hierover",
"update": "Update",
"update_available": "Er {count, plural, one {staat een update} other {{count} staan updates}} klaar",
"update_available": "{count, plural, one {Een update staat} other {{count} updates staan}} klaar",
"version": "Versie",
"yes": "Ja"
},
@ -385,8 +385,13 @@
"create_blocked_not_running": "Het maken van een snapshot is nu niet mogelijk omdat het systeem in {state} staat.",
"create_snapshot": "Maak snapshot",
"created": "Gemaakt",
"delete_selected": "Verwijder geselecteerde snapshots",
"delete_snapshot_confirm": "verwijder",
"delete_snapshot_text": "Wilt u {number} {number, plural,\n one {snapshot}\n other {snapshots}\n} verwijderen?",
"delete_snapshot_title": "Verwijder snapshot",
"description": "Met snapshots kunt u gemakkelijk een back-up maken van alle gegevens van uw Home Assistant en ze herstellen.",
"enter_password": "Voer een wachtwoord in.",
"failed_to_delete": "Verwijderen mislukt",
"folder": {
"addons/local": "Lokale invoegtoepassingen",
"homeassistant": "Home Assistant configuratie",
@ -404,6 +409,7 @@
"password_protection": "Wachtwoord bescherming",
"security": "Beveiliging",
"select_type": "Selecteer wat u wilt herstellen",
"selected": "{number} geselecteerd",
"type": "Snapshot type",
"upload_snapshot": "Upload snapshot"
},
@ -4021,7 +4027,7 @@
"12": "12 uur (AM/PM)",
"24": "24 uur",
"language": "Automatisch (taalinstelling gebruiken)",
"system": "Systeemlokalen gebruiken"
"system": "Gebruik systeemlandinstelling"
},
"header": "Tijdformaat"
},

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "Tworzenie snapshota nie jest teraz możliwe, ponieważ system jest w {state}.",
"create_snapshot": "Utwórz snapshot",
"created": "Utworzony",
"delete_selected": "Usuń wybrane snapshoty",
"delete_snapshot_confirm": "usuń",
"delete_snapshot_text": "Czy chcesz usunąć {number} {number, plural,\n one {snapshota}\n few {snapshoty}\n many {snapshotów}\n other {snapshoty}\n}?",
"delete_snapshot_title": "Usuń snapshota",
"description": "Snapshoty umożliwiają łatwe tworzenie kopii zapasowych i przywracanie wszystkich danych instancji Home Assistant.",
"enter_password": "Proszę wprowadzić hasło",
"failed_to_delete": "Nie udało się usunąć",
"folder": {
"addons/local": "Folder Local add-ons",
"homeassistant": "Folder konfiguracji Home Assistant",
@ -404,6 +409,7 @@
"password_protection": "Ochrona hasłem",
"security": "Bezpieczeństwo",
"select_type": "Wybierz, co przywrócić",
"selected": "wybrano {number}",
"type": "Typ snapshota",
"upload_snapshot": "Prześlij snapshota"
},

View File

@ -121,9 +121,16 @@
},
"snapshot": {
"created": "Criado",
"delete_selected": "Excluir snapshots selecionados",
"delete_snapshot_confirm": "Excluir",
"delete_snapshot_text": "Deseja excluir {number} {number, plural,\n one {snapshot}\n other {snapshots}\n}?",
"delete_snapshot_title": "Excluir snapshot",
"failed_to_delete": "Falha ao excluir",
"folder": {
"homeassistant": "Configuração do Home Assistant"
}
},
"select_type": "Selecione o que restaurar",
"selected": "{number} selecionado"
},
"system": {
"supervisor": {
@ -338,6 +345,9 @@
"no_match": "Não foram encontradas áreas com esta configuração",
"show_areas": "Mostrar áreas"
},
"attributes": {
"expansion_header": "Atributos"
},
"blueprint-picker": {
"add_user": "Adicionar Usuário",
"remove_user": "Remover usuário"
@ -1117,6 +1127,7 @@
"title": "Alexa"
},
"connected": "Conectado",
"connecting": "Conectando ...",
"connection_status": "Status de conexão com a Cloud",
"fetching_subscription": "Buscando assinatura…",
"google": {
@ -1152,7 +1163,8 @@
"link_learn_how_it_works": "Aprenda como funciona",
"not_connected": "Não Conectado",
"remote_enabled": {
"caption": "Conectar automaticamente"
"caption": "Conectar automaticamente",
"description": "Ative esta opção para garantir que a instância do Home Assistant esteja sempre acessível remotamente."
},
"title": "Controle Remoto"
},
@ -1806,8 +1818,8 @@
"add_scene": "Adicionar cena",
"delete_confirm": "Tem certeza de que deseja excluir esta cena?",
"delete_scene": "Excluir cena",
"duplicate": "Duplicado",
"duplicate_scene": "Cena duplicada",
"duplicate": "Duplicar",
"duplicate_scene": "Duplicar cena",
"edit_scene": "Editar cena",
"header": "Editor de cena",
"headers": {
@ -2107,7 +2119,9 @@
},
"zwave_js": {
"logs": {
"log_level": "Nível de Log"
"log_level": "Nível de Log",
"subscribed_to_logs": "Inscrito em mensagens de log JS do Z-Wave ...",
"title": "Logs Z-Wave JS"
},
"navigation": {
"logs": "Logs"
@ -3006,9 +3020,9 @@
"description": "Escolha como os horários são formatados.",
"dropdown_label": "Formato de hora",
"formats": {
"12": "Horas",
"24": "Horas",
"language": "Auto (usar configuração de idioma)",
"12": "12 horas (AM/PM)",
"24": "24 horas",
"language": "Automático (usar configuração de idioma)",
"system": "Use a localidade do sistema"
},
"header": "Formato de hora"

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "Создание снимка сейчас невозможно, потому что система находится в состоянии {state}.",
"create_snapshot": "Создать снимок",
"created": "Создан",
"delete_selected": "Удалить выбранные снимки",
"delete_snapshot_confirm": "удалить",
"delete_snapshot_text": "Вы уверены, что хотите удалить {number} {number, plural,\n one {снимок}\n few {снимка}\n many {снимков}\n other {снимков}\n}?",
"delete_snapshot_title": "Удалить снимок",
"description": "Снимок файловой системы (snapshot) позволяет легко создавать и восстанавливать резервную копию всех данных Вашего Home Assistant.",
"enter_password": "Пожалуйста, введите пароль.",
"failed_to_delete": "Не удалось удалить",
"folder": {
"addons/local": "Локальные дополнения",
"homeassistant": "Home Assistant",
@ -403,7 +408,8 @@
"password_protected": "защищено паролем",
"password_protection": "Защита паролем",
"security": "Безопасность",
"select_type": "Выберите, что нужно восстановить",
"select_type": "Выберите что нужно восстановить",
"selected": "Выбрано: {number}",
"type": "Тип снимка",
"upload_snapshot": "Загрузить снимок"
},

View File

@ -1490,7 +1490,7 @@
"picker": {
"filter": {
"filter": "Filter",
"hidden_devices": "{number} {number, plural,\n one {skrita naprava}\n two {skriti napravi}\n few {skrite naprave}\n many {skritih naprav}\n}",
"hidden_devices": "{number} {number, plural,\n one {skrita naprava}\n two {skriti napravi}\n few {skrite naprave}\n other {skritih naprav}\n}",
"show_all": "Prikaži vse",
"show_disabled": "Prikaži onemogočene naprave"
},
@ -1530,7 +1530,7 @@
},
"filter": {
"filter": "Filter",
"hidden_entities": "{number} {number, plural,\n one {skrita entiteta}\n two {skriti entiteti}\n few {skrite entitete}\n many {skritih entitet}\n}",
"hidden_entities": "{number} {number, plural,\n one {skrita entiteta}\n two {skriti entiteti}\n few {skrite entitete}\n other {skritih entitet}\n}",
"show_all": "Pokaži vse",
"show_disabled": "Pokaži onemogočene entitete",
"show_readonly": "Prikaži entitete \"samo za branje\"",

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "现在无法创建快照,因为系统处于{state}状态。",
"create_snapshot": "创建快照",
"created": "创建于",
"delete_selected": "删除选定的快照",
"delete_snapshot_confirm": "删除",
"delete_snapshot_text": "您是否要删除{number}个快照?",
"delete_snapshot_title": "删除快照",
"description": "“快照”使您可以轻松地备份和还原 Home Assistant 实例的所有数据。",
"enter_password": "请输入密码。",
"failed_to_delete": "删除失败",
"folder": {
"addons/local": "本地加载项",
"homeassistant": "Home Assistant 配置",
@ -403,6 +408,8 @@
"password_protected": "密码保护",
"password_protection": "密码保护",
"security": "安全性",
"select_type": "选择要还原的内容",
"selected": "选择了 {number} 项",
"type": "类型",
"upload_snapshot": "上传快照"
},
@ -573,8 +580,8 @@
},
"lock": {
"code": "密码",
"lock": "",
"unlock": "锁"
"lock": "锁",
"unlock": "锁"
},
"media_player": {
"browse_media": "浏览媒体",
@ -720,6 +727,9 @@
"no_match": "未找到相关区域",
"show_areas": "显示区域"
},
"attributes": {
"expansion_header": "属性"
},
"blueprint-picker": {
"add_user": "添加用户",
"remove_user": "删除用户",
@ -788,13 +798,13 @@
"was_closed": "已关闭",
"was_connected": "已连接",
"was_disconnected": "已断开",
"was_locked": "已",
"was_locked": "已锁",
"was_low": "较低",
"was_normal": "正常",
"was_opened": "已打开",
"was_plugged_in": "已插入",
"was_safe": "[%key_id:6884522%]",
"was_unlocked": "已解锁",
"was_unlocked": "已打开",
"was_unplugged": "已拔出",
"was_unsafe": "[%key_id:6884523%]"
},
@ -1119,7 +1129,7 @@
"command_line": "命令行实体",
"core": "位置和自定义",
"filesize": "文件大小实体",
"filter": "filter 实体",
"filter": "筛选实体",
"generic": "通用 IP 摄像机实体",
"generic_thermostat": "通用恒温器实体",
"group": "分组、分组实体及其通知服务",
@ -1719,6 +1729,7 @@
"title": "Alexa"
},
"connected": "已连接",
"connecting": "正在连接...",
"connection_status": "云连接状态",
"fetching_subscription": "正在获取订阅...",
"google": {
@ -1792,7 +1803,7 @@
}
},
"alexa": {
"banner": "由于已在configuration.yaml中配置了实体过滤器因此无法编辑通过此UI公开哪些实体。",
"banner": "您在configuration.yaml中配置了实体过滤器因此无法用此UI修改被公开的实体名单。",
"dont_expose_entity": "使实体不可发现",
"expose": "向Alexa发送你的位置",
"expose_entity": "使实体可发现",
@ -2041,7 +2052,7 @@
"filter": {
"filter": "筛选",
"hidden_devices": "{number} 个隐藏设备",
"show_all": "显示全部",
"show_all": "全部显示",
"show_disabled": "显示已禁用的设备"
},
"search": "搜索设备"
@ -2081,7 +2092,7 @@
"filter": {
"filter": "筛选",
"hidden_entities": "{number} 个隐藏{number, plural,\n one {实体}\n other {实体}\n}",
"show_all": "显示全部",
"show_all": "全部显示",
"show_disabled": "显示已禁用的实体",
"show_readonly": "显示只读实体",
"show_unavailable": "显示不可用的实体"
@ -2661,7 +2672,7 @@
"command_line": "命令行实体",
"core": "位置和自定义",
"filesize": "文件大小实体",
"filter": "filter 实体",
"filter": "筛选实体",
"generic": "通用 IP 摄像机实体",
"generic_thermostat": "通用恒温器实体",
"group": "分组、分组实体及其通知服务",
@ -2959,6 +2970,7 @@
},
"logs": {
"log_level": "日志级别",
"log_level_changed": "日志级别更改为: {level}",
"subscribed_to_logs": "已订阅 Z-Wave JS 日志消息...",
"title": "Z-Wave JS 日志"
},

View File

@ -385,8 +385,13 @@
"create_blocked_not_running": "由於系統為 {state} 狀態,無法製作系統備份。",
"create_snapshot": "製作系統備份",
"created": "建立",
"delete_selected": "刪除已選擇系統備份",
"delete_snapshot_confirm": "刪除",
"delete_snapshot_text": "是否要刪除 {number} {number, plural,\n one {個系統備份}\n other {個系統備份}\n}",
"delete_snapshot_title": "刪除系統備份",
"description": "系統備份可供您快速的備份與還原 Home Assistant 所有資料。",
"enter_password": "請輸入密碼。",
"failed_to_delete": "刪除失敗",
"folder": {
"addons/local": "本地附加元件",
"homeassistant": "Home Assistant 設定",
@ -404,6 +409,7 @@
"password_protection": "密碼保護",
"security": "加密",
"select_type": "選擇所要回復內容",
"selected": "已選擇 {number} 個",
"type": "系統備份類型",
"upload_snapshot": "上傳系統備份"
},

View File

@ -2104,7 +2104,7 @@
"@polymer/iron-meta" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
"@polymer/iron-image@^3.0.0-pre.26", "@polymer/iron-image@^3.0.1":
"@polymer/iron-image@^3.0.1":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@polymer/iron-image/-/iron-image-3.0.2.tgz#425ee6269634e024dbea726a91a61724ae4402b6"
integrity sha512-VyYtnewGozDb5sUeoLR1OvKzlt5WAL6b8Od7fPpio5oYL+9t061/nTV8+ZMrpMgF2WgB0zqM/3K53o3pbK5v8Q==
@ -2226,16 +2226,6 @@
"@polymer/paper-ripple" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
"@polymer/paper-card@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@polymer/paper-card/-/paper-card-3.0.1.tgz#fb5960b3e55fab56d20b7c1c3dee08f0d052ff2a"
integrity sha512-ZYzfA4kzP9niRO22wSOBL2RS+URZNUP5XmUCwN91fYPIGO0Qbimh7d1O2HpJD4cRCZhvGYn2CJMDMVmDm35vIg==
dependencies:
"@polymer/iron-flex-layout" "^3.0.0-pre.26"
"@polymer/iron-image" "^3.0.0-pre.26"
"@polymer/paper-styles" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
"@polymer/paper-checkbox@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@polymer/paper-checkbox/-/paper-checkbox-3.1.0.tgz#66b903ae5814db237d027deb4a3f3430f48d905b"