mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-13 20:36:35 +00:00
Merge pull request #9310 from home-assistant/dev
This commit is contained in:
commit
1533c22d5c
@ -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,
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
2
setup.py
2
setup.py
@ -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",
|
||||
|
2
src/common/string/escape_regexp.ts
Normal file
2
src/common/string/escape_regexp.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const escapeRegExp = (text: string): string =>
|
||||
text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
6
src/common/structs/is-custom-type.ts
Normal file
6
src/common/structs/is-custom-type.ts
Normal 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);
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 => {
|
||||
|
@ -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);
|
75
src/dialogs/ha-store-auth-card.ts
Normal file
75
src/dialogs/ha-store-auth-card.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -193,9 +193,6 @@ class HaInputNumberForm extends LitElement {
|
||||
.form {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
ha-paper-dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -196,9 +196,6 @@ class HaInputSelectForm extends LitElement {
|
||||
mwc-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
ha-paper-dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -179,9 +179,6 @@ class HaInputTextForm extends LitElement {
|
||||
.row {
|
||||
padding: 16px 0;
|
||||
}
|
||||
ha-paper-dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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({
|
||||
|
@ -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),
|
||||
});
|
||||
|
@ -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";
|
||||
|
@ -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[] } } = {
|
||||
|
@ -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({
|
||||
|
@ -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";
|
||||
|
@ -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),
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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({
|
||||
|
@ -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";
|
||||
|
67
src/panels/lovelace/editor/structs/action-struct.ts
Normal file
67
src/panels/lovelace/editor/structs/action-struct.ts
Normal 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,
|
||||
]);
|
18
src/panels/lovelace/editor/structs/entities-struct.ts
Normal file
18
src/panels/lovelace/editor/structs/entities-struct.ts
Normal 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(),
|
||||
]);
|
@ -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,
|
||||
]);
|
||||
|
29
src/panels/lovelace/header-footer/structs.ts
Normal file
29
src/panels/lovelace/header-footer/structs.ts
Normal 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,
|
||||
]);
|
@ -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,
|
||||
]);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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": "Разрешаване или забраняване на вибрациите на това устройство при управление на устройства.",
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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",
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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"
|
||||
|
@ -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": "Загрузить снимок"
|
||||
},
|
||||
|
@ -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\"",
|
||||
|
@ -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 日志"
|
||||
},
|
||||
|
@ -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": "上傳系統備份"
|
||||
},
|
||||
|
12
yarn.lock
12
yarn.lock
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user