mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-28 07:17:21 +00:00
Merge pull request #8448 from home-assistant/dev
Co-authored-by: Bram Kragten <mail@bramkragten.nl> Co-authored-by: Philip Allgaier <mail@spacegaier.de> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: GitHub Action <github-action@users.noreply.github.com> Co-authored-by: Joakim Sørensen <joasoe@gmail.com> Co-authored-by: Álvaro Fernández Rojas <noltari@gmail.com> Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Co-authored-by: Kendell R <KTibow@users.noreply.github.com> Co-authored-by: larena1 <60823161+larena1@users.noreply.github.com>
This commit is contained in:
commit
c85f69c9ee
@ -23,7 +23,7 @@ class HassioRouter extends HassRouterPage {
|
|||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
// Hass.io has a page with tabs, so we route all non-matching routes to it.
|
// Hass.io has a page with tabs, so we route all non-matching routes to it.
|
||||||
defaultPage: "dashboard",
|
defaultPage: "dashboard",
|
||||||
initialLoad: () => this._fetchData(),
|
initialLoad: () => this._redirectIngress(),
|
||||||
showLoading: true,
|
showLoading: true,
|
||||||
routes: {
|
routes: {
|
||||||
dashboard: {
|
dashboard: {
|
||||||
@ -50,7 +50,13 @@ class HassioRouter extends HassRouterPage {
|
|||||||
|
|
||||||
protected updatePageEl(el) {
|
protected updatePageEl(el) {
|
||||||
// the tabs page does its own routing so needs full route.
|
// the tabs page does its own routing so needs full route.
|
||||||
const route = el.nodeName === "HASSIO-PANEL" ? this.route : this.routeTail;
|
const hassioPanel = el.nodeName === "HASSIO-PANEL";
|
||||||
|
const route = hassioPanel ? this.route : this.routeTail;
|
||||||
|
|
||||||
|
if (hassioPanel && this.panel.config?.ingress) {
|
||||||
|
this._redirectIngress();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
el.hass = this.hass;
|
el.hass = this.hass;
|
||||||
el.narrow = this.narrow;
|
el.narrow = this.narrow;
|
||||||
@ -63,15 +69,14 @@ class HassioRouter extends HassRouterPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchData() {
|
private async _redirectIngress() {
|
||||||
if (this.panel.config && this.panel.config.ingress) {
|
if (this.panel.config && this.panel.config.ingress) {
|
||||||
this._redirectIngress(this.panel.config.ingress);
|
this.route = {
|
||||||
|
prefix: "/hassio",
|
||||||
|
path: `/ingress/${this.panel.config.ingress}`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _redirectIngress(addonSlug: string) {
|
|
||||||
this.route = { prefix: "/hassio", path: `/ingress/${addonSlug}` };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
20
package.json
20
package.json
@ -23,6 +23,14 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "^5.0.0",
|
"@braintree/sanitize-url": "^5.0.0",
|
||||||
|
"@codemirror/commands": "^0.17.2",
|
||||||
|
"@codemirror/gutter": "^0.17.2",
|
||||||
|
"@codemirror/highlight": "^0.17.2",
|
||||||
|
"@codemirror/legacy-modes": "^0.17.1",
|
||||||
|
"@codemirror/state": "^0.17.1",
|
||||||
|
"@codemirror/stream-parser": "^0.17.1",
|
||||||
|
"@codemirror/text": "^0.17.2",
|
||||||
|
"@codemirror/view": "^0.17.7",
|
||||||
"@formatjs/intl-getcanonicallocales": "^1.4.6",
|
"@formatjs/intl-getcanonicallocales": "^1.4.6",
|
||||||
"@formatjs/intl-pluralrules": "^3.4.10",
|
"@formatjs/intl-pluralrules": "^3.4.10",
|
||||||
"@fullcalendar/common": "5.1.0",
|
"@fullcalendar/common": "5.1.0",
|
||||||
@ -177,7 +185,7 @@
|
|||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-airbnb-typescript": "^7.2.1",
|
"eslint-config-airbnb-typescript": "^7.2.1",
|
||||||
"eslint-config-prettier": "^6.10.1",
|
"eslint-config-prettier": "^6.10.1",
|
||||||
"eslint-import-resolver-webpack": "^0.12.2",
|
"eslint-import-resolver-webpack": "^0.13.0",
|
||||||
"eslint-plugin-disable": "^2.0.1",
|
"eslint-plugin-disable": "^2.0.1",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-plugin-import": "^2.20.2",
|
||||||
"eslint-plugin-lit": "^1.2.0",
|
"eslint-plugin-lit": "^1.2.0",
|
||||||
@ -213,16 +221,16 @@
|
|||||||
"sinon": "^7.3.1",
|
"sinon": "^7.3.1",
|
||||||
"source-map-url": "^0.4.0",
|
"source-map-url": "^0.4.0",
|
||||||
"systemjs": "^6.3.2",
|
"systemjs": "^6.3.2",
|
||||||
"terser-webpack-plugin": "^5.0.0",
|
"terser-webpack-plugin": "^5.1.1",
|
||||||
"ts-lit-plugin": "^1.2.1",
|
"ts-lit-plugin": "^1.2.1",
|
||||||
"ts-mocha": "^7.0.0",
|
"ts-mocha": "^7.0.0",
|
||||||
"typescript": "^4.0.3",
|
"typescript": "^4.0.3",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"webpack": "5.1.3",
|
"webpack": "^5.24.1",
|
||||||
"webpack-cli": "4.1.0",
|
"webpack-cli": "^4.5.0",
|
||||||
"webpack-dev-server": "^3.11.0",
|
"webpack-dev-server": "^3.11.2",
|
||||||
"webpack-manifest-plugin": "~3.0.0",
|
"webpack-manifest-plugin": "^3.0.0",
|
||||||
"workbox-build": "^5.1.3"
|
"workbox-build": "^5.1.3"
|
||||||
},
|
},
|
||||||
"_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page",
|
"_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page",
|
||||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20210222.0",
|
version="20210224.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -5,11 +5,15 @@ export const atLeastVersion = (
|
|||||||
patch?: number
|
patch?: number
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const [haMajor, haMinor, haPatch] = version.split(".", 3);
|
const [haMajor, haMinor, haPatch] = version.split(".", 3);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Number(haMajor) > major ||
|
Number(haMajor) > major ||
|
||||||
(Number(haMajor) === major && Number(haMinor) >= minor) ||
|
(Number(haMajor) === major && (patch === undefined
|
||||||
|
? Number(haMinor) >= minor
|
||||||
|
: Number(haMinor) > minor)) ||
|
||||||
(patch !== undefined &&
|
(patch !== undefined &&
|
||||||
Number(haMajor) === major && Number(haMinor) === minor &&
|
Number(haMajor) === major &&
|
||||||
|
Number(haMinor) === minor &&
|
||||||
Number(haPatch) >= patch)
|
Number(haPatch) >= patch)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -8,12 +8,19 @@ export const batteryIcon = (
|
|||||||
const battery = Number(batteryState.state);
|
const battery = Number(batteryState.state);
|
||||||
const battery_charging =
|
const battery_charging =
|
||||||
batteryChargingState && batteryChargingState.state === "on";
|
batteryChargingState && batteryChargingState.state === "on";
|
||||||
|
let icon = "hass:battery";
|
||||||
|
|
||||||
if (isNaN(battery)) {
|
if (isNaN(battery)) {
|
||||||
return "hass:battery-unknown";
|
if (batteryState.state === "off") {
|
||||||
|
icon += "-full";
|
||||||
|
} else if (batteryState.state === "on") {
|
||||||
|
icon += "-alert";
|
||||||
|
} else {
|
||||||
|
icon += "-unknown";
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon = "hass:battery";
|
|
||||||
const batteryRound = Math.round(battery / 10) * 10;
|
const batteryRound = Math.round(battery / 10) * 10;
|
||||||
if (battery_charging && battery > 10) {
|
if (battery_charging && battery > 10) {
|
||||||
icon += `-charging-${batteryRound}`;
|
icon += `-charging-${batteryRound}`;
|
||||||
|
@ -15,7 +15,7 @@ export const iconColorCSS = css`
|
|||||||
ha-icon[data-domain="media_player"][data-state="on"],
|
ha-icon[data-domain="media_player"][data-state="on"],
|
||||||
ha-icon[data-domain="media_player"][data-state="paused"],
|
ha-icon[data-domain="media_player"][data-state="paused"],
|
||||||
ha-icon[data-domain="media_player"][data-state="playing"],
|
ha-icon[data-domain="media_player"][data-state="playing"],
|
||||||
ha-icon[data-domain="script"][data-state="running"],
|
ha-icon[data-domain="script"][data-state="on"],
|
||||||
ha-icon[data-domain="sun"][data-state="above_horizon"],
|
ha-icon[data-domain="sun"][data-state="above_horizon"],
|
||||||
ha-icon[data-domain="switch"][data-state="on"],
|
ha-icon[data-domain="switch"][data-state="on"],
|
||||||
ha-icon[data-domain="timer"][data-state="active"],
|
ha-icon[data-domain="timer"][data-state="active"],
|
||||||
|
@ -115,7 +115,7 @@ export class StateBadge extends LitElement {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
console.warn(errorMessage);
|
console.warn(errorMessage);
|
||||||
}
|
}
|
||||||
// lowest brighntess will be around 50% (that's pretty dark)
|
// lowest brightness will be around 50% (that's pretty dark)
|
||||||
iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`;
|
iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
148
src/components/ha-addon-picker.ts
Normal file
148
src/components/ha-addon-picker.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { compare } from "../common/string/compare";
|
||||||
|
import { HassioAddonInfo } from "../data/hassio/addon";
|
||||||
|
import { fetchHassioSupervisorInfo } from "../data/hassio/supervisor";
|
||||||
|
import { showAlertDialog } from "../dialogs/generic/show-dialog-box";
|
||||||
|
import { PolymerChangedEvent } from "../polymer-types";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
import { HaComboBox } from "./ha-combo-box";
|
||||||
|
|
||||||
|
const rowRenderer = (
|
||||||
|
root: HTMLElement,
|
||||||
|
_owner,
|
||||||
|
model: { item: HassioAddonInfo }
|
||||||
|
) => {
|
||||||
|
if (!root.firstElementChild) {
|
||||||
|
root.innerHTML = `
|
||||||
|
<style>
|
||||||
|
paper-item {
|
||||||
|
margin: -10px 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body two-line="">
|
||||||
|
<div class='name'>[[item.name]]</div>
|
||||||
|
<div secondary>[[item.slug]]</div>
|
||||||
|
</paper-item-body>
|
||||||
|
</paper-item>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.querySelector(".name")!.textContent = model.item.name;
|
||||||
|
root.querySelector("[secondary]")!.textContent = model.item.slug;
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("ha-addon-picker")
|
||||||
|
class HaAddonPicker extends LitElement {
|
||||||
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
@property() public value = "";
|
||||||
|
|
||||||
|
@internalProperty() private _addons?: HassioAddonInfo[];
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
@query("ha-combo-box") private _comboBox!: HaComboBox;
|
||||||
|
|
||||||
|
public open() {
|
||||||
|
this._comboBox?.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus() {
|
||||||
|
this._comboBox?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated() {
|
||||||
|
this._getAddons();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._addons) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-combo-box
|
||||||
|
.hass=${this.hass}
|
||||||
|
.label=${this.label === undefined && this.hass
|
||||||
|
? this.hass.localize("ui.components.addon-picker.addon")
|
||||||
|
: this.label}
|
||||||
|
.value=${this._value}
|
||||||
|
.renderer=${rowRenderer}
|
||||||
|
.items=${this._addons}
|
||||||
|
item-value-path="slug"
|
||||||
|
item-id-path="slug"
|
||||||
|
item-label-path="name"
|
||||||
|
@value-changed=${this._addonChanged}
|
||||||
|
></ha-combo-box>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _getAddons() {
|
||||||
|
try {
|
||||||
|
if (isComponentLoaded(this.hass, "hassio")) {
|
||||||
|
const supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||||
|
this._addons = supervisorInfo.addons.sort((a, b) =>
|
||||||
|
compare(a.name, b.name)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.componencts.addon-picker.error.no_supervisor.title"
|
||||||
|
),
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.componencts.addon-picker.error.no_supervisor.description"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.componencts.addon-picker.error.fetch_addons.title"
|
||||||
|
),
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.componencts.addon-picker.error.fetch_addons.description"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _value() {
|
||||||
|
return this.value || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addonChanged(ev: PolymerChangedEvent<string>) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const newValue = ev.detail.value;
|
||||||
|
|
||||||
|
if (newValue !== this._value) {
|
||||||
|
this._setValue(newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _setValue(value: string) {
|
||||||
|
this.value = value;
|
||||||
|
setTimeout(() => {
|
||||||
|
fireEvent(this, "value-changed", { value });
|
||||||
|
fireEvent(this, "change");
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-addon-picker": HaAddonPicker;
|
||||||
|
}
|
||||||
|
}
|
@ -140,7 +140,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
|
|||||||
this._devices = devices;
|
this._devices = devices;
|
||||||
}),
|
}),
|
||||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
this._entities = entities;
|
this._entities = entities.filter((entity) => entity.area_id);
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -193,11 +193,14 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
|
|||||||
deviceEntityLookup[entity.device_id].push(entity);
|
deviceEntityLookup[entity.device_id].push(entity);
|
||||||
}
|
}
|
||||||
inputDevices = devices;
|
inputDevices = devices;
|
||||||
inputEntities = entities.filter((entity) => entity.area_id);
|
inputEntities = entities;
|
||||||
} else if (deviceFilter) {
|
} else {
|
||||||
|
if (deviceFilter) {
|
||||||
inputDevices = devices;
|
inputDevices = devices;
|
||||||
} else if (entityFilter) {
|
}
|
||||||
inputEntities = entities.filter((entity) => entity.area_id);
|
if (entityFilter) {
|
||||||
|
inputEntities = entities;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDomains) {
|
if (includeDomains) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Editor } from "codemirror";
|
import type { StreamLanguage } from "@codemirror/stream-parser";
|
||||||
|
import type { EditorView, KeyBinding, ViewUpdate } from "@codemirror/view";
|
||||||
import {
|
import {
|
||||||
customElement,
|
customElement,
|
||||||
internalProperty,
|
internalProperty,
|
||||||
@ -15,32 +16,40 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modeTag = Symbol("mode");
|
||||||
|
|
||||||
|
const readOnlyTag = Symbol("readOnly");
|
||||||
|
|
||||||
|
const saveKeyBinding: KeyBinding = {
|
||||||
|
key: "Mod-s",
|
||||||
|
run: (view: EditorView) => {
|
||||||
|
fireEvent(view.dom, "editor-save");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("ha-code-editor")
|
@customElement("ha-code-editor")
|
||||||
export class HaCodeEditor extends UpdatingElement {
|
export class HaCodeEditor extends UpdatingElement {
|
||||||
public codemirror?: Editor;
|
public codemirror?: EditorView;
|
||||||
|
|
||||||
@property() public mode?: string;
|
@property() public mode = "yaml";
|
||||||
|
|
||||||
@property({ type: Boolean }) public autofocus = false;
|
@property({ type: Boolean }) public autofocus = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public readOnly = false;
|
@property({ type: Boolean }) public readOnly = false;
|
||||||
|
|
||||||
@property() public rtl = false;
|
|
||||||
|
|
||||||
@property() public error = false;
|
@property() public error = false;
|
||||||
|
|
||||||
@internalProperty() private _value = "";
|
@internalProperty() private _value = "";
|
||||||
|
|
||||||
|
@internalProperty() private _langs?: Record<string, StreamLanguage<unknown>>;
|
||||||
|
|
||||||
public set value(value: string) {
|
public set value(value: string) {
|
||||||
this._value = value;
|
this._value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get value(): string {
|
public get value(): string {
|
||||||
return this.codemirror ? this.codemirror.getValue() : this._value;
|
return this.codemirror ? this.codemirror.state.doc.toString() : this._value;
|
||||||
}
|
|
||||||
|
|
||||||
public get hasComments(): boolean {
|
|
||||||
return !!this.shadowRoot!.querySelector("span.cm-comment");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectedCallback() {
|
public connectedCallback() {
|
||||||
@ -48,7 +57,6 @@ export class HaCodeEditor extends UpdatingElement {
|
|||||||
if (!this.codemirror) {
|
if (!this.codemirror) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.codemirror.refresh();
|
|
||||||
if (this.autofocus !== false) {
|
if (this.autofocus !== false) {
|
||||||
this.codemirror.focus();
|
this.codemirror.focus();
|
||||||
}
|
}
|
||||||
@ -62,17 +70,27 @@ export class HaCodeEditor extends UpdatingElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changedProps.has("mode")) {
|
if (changedProps.has("mode")) {
|
||||||
this.codemirror.setOption("mode", this.mode);
|
this.codemirror.dispatch({
|
||||||
|
reconfigure: {
|
||||||
|
[modeTag]: this._mode,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (changedProps.has("autofocus")) {
|
if (changedProps.has("readOnly")) {
|
||||||
this.codemirror.setOption("autofocus", this.autofocus !== false);
|
this.codemirror.dispatch({
|
||||||
|
reconfigure: {
|
||||||
|
[readOnlyTag]: !this.readOnly,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (changedProps.has("_value") && this._value !== this.value) {
|
if (changedProps.has("_value") && this._value !== this.value) {
|
||||||
this.codemirror.setValue(this._value);
|
this.codemirror.dispatch({
|
||||||
}
|
changes: {
|
||||||
if (changedProps.has("rtl")) {
|
from: 0,
|
||||||
this.codemirror.setOption("gutters", this._calcGutters());
|
to: this.codemirror.state.doc.length,
|
||||||
this._setScrollBarDirection();
|
insert: this._value,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (changedProps.has("error")) {
|
if (changedProps.has("error")) {
|
||||||
this.classList.toggle("error-state", this.error);
|
this.classList.toggle("error-state", this.error);
|
||||||
@ -85,159 +103,62 @@ export class HaCodeEditor extends UpdatingElement {
|
|||||||
this._load();
|
this._load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get _mode() {
|
||||||
|
return this._langs![this.mode];
|
||||||
|
}
|
||||||
|
|
||||||
private async _load(): Promise<void> {
|
private async _load(): Promise<void> {
|
||||||
const loaded = await loadCodeMirror();
|
const loaded = await loadCodeMirror();
|
||||||
|
|
||||||
const codeMirror = loaded.codeMirror;
|
this._langs = loaded.langs;
|
||||||
|
|
||||||
const shadowRoot = this.attachShadow({ mode: "open" });
|
const shadowRoot = this.attachShadow({ mode: "open" });
|
||||||
|
|
||||||
shadowRoot!.innerHTML = `
|
shadowRoot!.innerHTML = `<style>
|
||||||
<style>
|
:host(.error-state) div.cm-wrap .cm-gutters {
|
||||||
${loaded.codeMirrorCss}
|
|
||||||
.CodeMirror {
|
|
||||||
height: var(--code-mirror-height, auto);
|
|
||||||
direction: var(--code-mirror-direction, ltr);
|
|
||||||
font-family: var(--code-font-family, monospace);
|
|
||||||
}
|
|
||||||
.CodeMirror-scroll {
|
|
||||||
max-height: var(--code-mirror-max-height, --code-mirror-height);
|
|
||||||
}
|
|
||||||
:host(.error-state) .CodeMirror-gutters {
|
|
||||||
border-color: var(--error-state-color, red);
|
border-color: var(--error-state-color, red);
|
||||||
}
|
}
|
||||||
.CodeMirror-focused .CodeMirror-gutters {
|
|
||||||
border-right: 2px solid var(--paper-input-container-focus-color, var(--primary-color));
|
|
||||||
}
|
|
||||||
.CodeMirror-linenumber {
|
|
||||||
color: var(--paper-dialog-color, var(--secondary-text-color));
|
|
||||||
}
|
|
||||||
.rtl .CodeMirror-vscrollbar {
|
|
||||||
right: auto;
|
|
||||||
left: 0px;
|
|
||||||
}
|
|
||||||
.rtl-gutter {
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
||||||
.CodeMirror-gutters {
|
|
||||||
border-right: 1px solid var(--paper-input-container-color, var(--secondary-text-color));
|
|
||||||
background-color: var(--paper-dialog-background-color, var(--primary-background-color));
|
|
||||||
transition: 0.2s ease border-right;
|
|
||||||
}
|
|
||||||
.cm-s-default.CodeMirror {
|
|
||||||
background-color: var(--code-editor-background-color, var(--card-background-color));
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
.cm-s-default .CodeMirror-cursor {
|
|
||||||
border-left: 1px solid var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default div.CodeMirror-selected, .cm-s-default.CodeMirror-focused div.CodeMirror-selected {
|
|
||||||
background: rgba(var(--rgb-primary-color), 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .CodeMirror-line::selection,
|
|
||||||
.cm-s-default .CodeMirror-line>span::selection,
|
|
||||||
.cm-s-default .CodeMirror-line>span>span::selection {
|
|
||||||
background: rgba(var(--rgb-primary-color), 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-keyword {
|
|
||||||
color: var(--codemirror-keyword, #6262FF);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-operator {
|
|
||||||
color: var(--codemirror-operator, #cda869);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-variable-2 {
|
|
||||||
color: var(--codemirror-variable-2, #690);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-builtin {
|
|
||||||
color: var(--codemirror-builtin, #9B7536);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-atom {
|
|
||||||
color: var(--codemirror-atom, #F90);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-number {
|
|
||||||
color: var(--codemirror-number, #ca7841);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-def {
|
|
||||||
color: var(--codemirror-def, #8DA6CE);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-string {
|
|
||||||
color: var(--codemirror-string, #07a);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-string-2 {
|
|
||||||
color: var(--codemirror-string-2, #bd6b18);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-comment {
|
|
||||||
color: var(--codemirror-comment, #777);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-variable {
|
|
||||||
color: var(--codemirror-variable, #07a);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-tag {
|
|
||||||
color: var(--codemirror-tag, #997643);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-meta {
|
|
||||||
color: var(--codemirror-meta, var(--primary-text-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-attribute {
|
|
||||||
color: var(--codemirror-attribute, #d6bb6d);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-property {
|
|
||||||
color: var(--codemirror-property, #905);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-qualifier {
|
|
||||||
color: var(--codemirror-qualifier, #690);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-variable-3 {
|
|
||||||
color: var(--codemirror-variable-3, #07a);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-default .cm-type {
|
|
||||||
color: var(--codemirror-type, #07a);
|
|
||||||
}
|
|
||||||
</style>`;
|
</style>`;
|
||||||
|
|
||||||
this.codemirror = codeMirror(shadowRoot, {
|
const container = document.createElement("span");
|
||||||
value: this._value,
|
|
||||||
lineNumbers: true,
|
shadowRoot.appendChild(container);
|
||||||
tabSize: 2,
|
|
||||||
mode: this.mode,
|
this.codemirror = new loaded.EditorView({
|
||||||
autofocus: this.autofocus !== false,
|
state: loaded.EditorState.create({
|
||||||
viewportMargin: Infinity,
|
doc: this._value,
|
||||||
readOnly: this.readOnly,
|
extensions: [
|
||||||
extraKeys: {
|
loaded.lineNumbers(),
|
||||||
Tab: "indentMore",
|
loaded.keymap.of([
|
||||||
"Shift-Tab": "indentLess",
|
...loaded.defaultKeymap,
|
||||||
},
|
loaded.defaultTabBinding,
|
||||||
gutters: this._calcGutters(),
|
saveKeyBinding,
|
||||||
|
]),
|
||||||
|
loaded.tagExtension(modeTag, this._mode),
|
||||||
|
loaded.theme,
|
||||||
|
loaded.Prec.fallback(loaded.highlightStyle),
|
||||||
|
loaded.EditorView.updateListener.of((update) =>
|
||||||
|
this._onUpdate(update)
|
||||||
|
),
|
||||||
|
loaded.tagExtension(
|
||||||
|
readOnlyTag,
|
||||||
|
loaded.EditorView.editable.of(!this.readOnly)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
root: shadowRoot,
|
||||||
|
parent: container,
|
||||||
});
|
});
|
||||||
this._setScrollBarDirection();
|
|
||||||
this.codemirror!.on("changes", () => this._onChange());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _blockKeyboardShortcuts() {
|
private _blockKeyboardShortcuts() {
|
||||||
this.addEventListener("keydown", (ev) => ev.stopPropagation());
|
this.addEventListener("keydown", (ev) => ev.stopPropagation());
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onChange(): void {
|
private _onUpdate(update: ViewUpdate): void {
|
||||||
|
if (!update.docChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const newValue = this.value;
|
const newValue = this.value;
|
||||||
if (newValue === this._value) {
|
if (newValue === this._value) {
|
||||||
return;
|
return;
|
||||||
@ -245,16 +166,6 @@ export class HaCodeEditor extends UpdatingElement {
|
|||||||
this._value = newValue;
|
this._value = newValue;
|
||||||
fireEvent(this, "value-changed", { value: this._value });
|
fireEvent(this, "value-changed", { value: this._value });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _calcGutters(): string[] {
|
|
||||||
return this.rtl ? ["rtl-gutter", "CodeMirror-linenumbers"] : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setScrollBarDirection(): void {
|
|
||||||
if (this.codemirror) {
|
|
||||||
this.codemirror.getWrapperElement().classList.toggle("rtl", this.rtl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
30
src/components/ha-selector/ha-selector-addon.ts
Normal file
30
src/components/ha-selector/ha-selector-addon.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { customElement, html, LitElement, property } from "lit-element";
|
||||||
|
import { AddonSelector } from "../../data/selector";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
import "../ha-addon-picker";
|
||||||
|
|
||||||
|
@customElement("ha-selector-addon")
|
||||||
|
export class HaAddonSelector extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public selector!: AddonSelector;
|
||||||
|
|
||||||
|
@property() public value?: any;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`<ha-addon-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this.value}
|
||||||
|
.label=${this.label}
|
||||||
|
allow-custom-entity
|
||||||
|
></ha-addon-picker>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-selector-addon": HaAddonSelector;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
|||||||
import { Selector } from "../../data/selector";
|
import { Selector } from "../../data/selector";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "./ha-selector-action";
|
import "./ha-selector-action";
|
||||||
|
import "./ha-selector-addon";
|
||||||
import "./ha-selector-area";
|
import "./ha-selector-area";
|
||||||
import "./ha-selector-boolean";
|
import "./ha-selector-boolean";
|
||||||
import "./ha-selector-device";
|
import "./ha-selector-device";
|
||||||
|
@ -79,6 +79,10 @@ class HaSlider extends PaperSliderClass {
|
|||||||
return subTemplate;
|
return subTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setImmediateValue(newImmediateValue) {
|
||||||
|
super._setImmediateValue(Math.round(newImmediateValue));
|
||||||
|
}
|
||||||
|
|
||||||
_calcStep(value) {
|
_calcStep(value) {
|
||||||
if (!this.step) {
|
if (!this.step) {
|
||||||
return parseFloat(value);
|
return parseFloat(value);
|
||||||
|
@ -5,20 +5,10 @@ import {
|
|||||||
internalProperty,
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
query,
|
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { afterNextRender } from "../common/util/render-status";
|
|
||||||
import "./ha-code-editor";
|
import "./ha-code-editor";
|
||||||
import type { HaCodeEditor } from "./ha-code-editor";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// for fire event
|
|
||||||
interface HASSDomEvents {
|
|
||||||
"editor-refreshed": undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isEmpty = (obj: Record<string, unknown>): boolean => {
|
const isEmpty = (obj: Record<string, unknown>): boolean => {
|
||||||
if (typeof obj !== "object") {
|
if (typeof obj !== "object") {
|
||||||
@ -44,8 +34,6 @@ export class HaYamlEditor extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _yaml = "";
|
@internalProperty() private _yaml = "";
|
||||||
|
|
||||||
@query("ha-code-editor") private _editor?: HaCodeEditor;
|
|
||||||
|
|
||||||
public setValue(value): void {
|
public setValue(value): void {
|
||||||
try {
|
try {
|
||||||
this._yaml = value && !isEmpty(value) ? safeDump(value) : "";
|
this._yaml = value && !isEmpty(value) ? safeDump(value) : "";
|
||||||
@ -54,12 +42,6 @@ export class HaYamlEditor extends LitElement {
|
|||||||
console.error(err, value);
|
console.error(err, value);
|
||||||
alert(`There was an error converting to YAML: ${err}`);
|
alert(`There was an error converting to YAML: ${err}`);
|
||||||
}
|
}
|
||||||
afterNextRender(() => {
|
|
||||||
if (this._editor?.codemirror) {
|
|
||||||
this._editor.codemirror.refresh();
|
|
||||||
}
|
|
||||||
afterNextRender(() => fireEvent(this, "editor-refreshed"));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(): void {
|
protected firstUpdated(): void {
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
html,
|
html,
|
||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import "./state-history-chart-line";
|
import "./state-history-chart-line";
|
||||||
@ -83,6 +84,10 @@ class StateHistoryCharts extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
|
return !(changedProps.size === 1 && changedProps.has("hass"));
|
||||||
|
}
|
||||||
|
|
||||||
private _isHistoryEmpty(): boolean {
|
private _isHistoryEmpty(): boolean {
|
||||||
const historyDataEmpty =
|
const historyDataEmpty =
|
||||||
!this.historyData ||
|
!this.historyData ||
|
||||||
|
@ -9,6 +9,7 @@ export interface ConfigEntry {
|
|||||||
connection_class: string;
|
connection_class: string;
|
||||||
supports_options: boolean;
|
supports_options: boolean;
|
||||||
supports_unload: boolean;
|
supports_unload: boolean;
|
||||||
|
disabled_by: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigEntryMutableParams {
|
export interface ConfigEntryMutableParams {
|
||||||
@ -43,6 +44,27 @@ export const reloadConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
|
|||||||
require_restart: boolean;
|
require_restart: boolean;
|
||||||
}>("POST", `config/config_entries/entry/${configEntryId}/reload`);
|
}>("POST", `config/config_entries/entry/${configEntryId}/reload`);
|
||||||
|
|
||||||
|
export const disableConfigEntry = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
configEntryId: string
|
||||||
|
) =>
|
||||||
|
hass.callWS<{
|
||||||
|
require_restart: boolean;
|
||||||
|
}>({
|
||||||
|
type: "config_entries/disable",
|
||||||
|
entry_id: configEntryId,
|
||||||
|
disabled_by: "user",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const enableConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
|
||||||
|
hass.callWS<{
|
||||||
|
require_restart: boolean;
|
||||||
|
}>({
|
||||||
|
type: "config_entries/disable",
|
||||||
|
entry_id: configEntryId,
|
||||||
|
disabled_by: null,
|
||||||
|
});
|
||||||
|
|
||||||
export const getConfigEntrySystemOptions = (
|
export const getConfigEntrySystemOptions = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
configEntryId: string
|
configEntryId: string
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export type Selector =
|
export type Selector =
|
||||||
|
| AddonSelector
|
||||||
| EntitySelector
|
| EntitySelector
|
||||||
| DeviceSelector
|
| DeviceSelector
|
||||||
| AreaSelector
|
| AreaSelector
|
||||||
@ -30,6 +31,13 @@ export interface DeviceSelector {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AddonSelector {
|
||||||
|
addon: {
|
||||||
|
name?: string;
|
||||||
|
slug?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface AreaSelector {
|
export interface AreaSelector {
|
||||||
area: {
|
area: {
|
||||||
entity?: {
|
entity?: {
|
||||||
|
@ -52,6 +52,7 @@ class MoreInfoFan extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
caption="[[localize('ui.card.fan.speed')]]"
|
caption="[[localize('ui.card.fan.speed')]]"
|
||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
|
step="[[computePercentageStepSize(stateObj)]]"
|
||||||
value="{{percentageSliderValue}}"
|
value="{{percentageSliderValue}}"
|
||||||
on-change="percentageChanged"
|
on-change="percentageChanged"
|
||||||
pin=""
|
pin=""
|
||||||
@ -113,7 +114,7 @@ class MoreInfoFan extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
|
|
||||||
<ha-attributes
|
<ha-attributes
|
||||||
state-obj="[[stateObj]]"
|
state-obj="[[stateObj]]"
|
||||||
extra-filters="speed,preset_mode,preset_modes,speed_list,percentage,oscillating,direction"
|
extra-filters="percentage_step,speed,preset_mode,preset_modes,speed_list,percentage,oscillating,direction"
|
||||||
></ha-attributes>
|
></ha-attributes>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -154,6 +155,13 @@ class MoreInfoFan extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computePercentageStepSize(stateObj) {
|
||||||
|
if (stateObj.attributes.percentage_step) {
|
||||||
|
return stateObj.attributes.percentage_step;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
computeClassNames(stateObj) {
|
computeClassNames(stateObj) {
|
||||||
return (
|
return (
|
||||||
"more-info-fan " +
|
"more-info-fan " +
|
||||||
|
@ -12,13 +12,14 @@ import {
|
|||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { compare } from "../../../common/string/compare";
|
import { compare } from "../../../common/string/compare";
|
||||||
import { slugify } from "../../../common/string/slugify";
|
import { slugify } from "../../../common/string/slugify";
|
||||||
import "../../../components/entity/ha-battery-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import { AreaRegistryEntry } from "../../../data/area_registry";
|
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import { ConfigEntry } from "../../../data/config_entries";
|
import { ConfigEntry, disableConfigEntry } from "../../../data/config_entries";
|
||||||
import {
|
import {
|
||||||
computeDeviceName,
|
computeDeviceName,
|
||||||
DeviceRegistryEntry,
|
DeviceRegistryEntry,
|
||||||
@ -160,6 +161,8 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
const batteryState = batteryEntity
|
const batteryState = batteryEntity
|
||||||
? this.hass.states[batteryEntity.entity_id]
|
? this.hass.states[batteryEntity.entity_id]
|
||||||
: undefined;
|
: undefined;
|
||||||
|
const batteryIsBinary = batteryState
|
||||||
|
&& computeStateDomain(batteryState) === "binary_sensor";
|
||||||
const batteryChargingState = batteryChargingEntity
|
const batteryChargingState = batteryChargingEntity
|
||||||
? this.hass.states[batteryChargingEntity.entity_id]
|
? this.hass.states[batteryChargingEntity.entity_id]
|
||||||
: undefined;
|
: undefined;
|
||||||
@ -215,7 +218,7 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
batteryState
|
batteryState
|
||||||
? html`
|
? html`
|
||||||
<div class="battery">
|
<div class="battery">
|
||||||
${batteryState.state}%
|
${batteryIsBinary ? "" : batteryState.state + "%"}
|
||||||
<ha-battery-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.batteryStateObj=${batteryState}
|
.batteryStateObj=${batteryState}
|
||||||
@ -261,11 +264,13 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions" slot="actions">
|
${device.disabled_by === "user"
|
||||||
|
? html` <div class="card-actions" slot="actions">
|
||||||
<mwc-button unelevated @click=${this._enableDevice}>
|
<mwc-button unelevated @click=${this._enableDevice}>
|
||||||
${this.hass.localize("ui.common.enable")}
|
${this.hass.localize("ui.common.enable")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</div>`
|
||||||
|
: ""}
|
||||||
`
|
`
|
||||||
: html``
|
: html``
|
||||||
}
|
}
|
||||||
@ -626,6 +631,41 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
updateEntry: async (updates) => {
|
updateEntry: async (updates) => {
|
||||||
const oldDeviceName = device.name_by_user || device.name;
|
const oldDeviceName = device.name_by_user || device.name;
|
||||||
const newDeviceName = updates.name_by_user;
|
const newDeviceName = updates.name_by_user;
|
||||||
|
const disabled =
|
||||||
|
updates.disabled_by === "user" && device.disabled_by !== "user";
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
for (const cnfg_entry of device.config_entries) {
|
||||||
|
if (
|
||||||
|
!this.devices.some(
|
||||||
|
(dvc) =>
|
||||||
|
dvc.id !== device.id &&
|
||||||
|
dvc.config_entries.includes(cnfg_entry)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const config_entry = this.entries.find(
|
||||||
|
(entry) => entry.entry_id === cnfg_entry
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
config_entry &&
|
||||||
|
!config_entry.disabled_by &&
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
(await showConfirmationDialog(this, {
|
||||||
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.devices.confirm_disable_config_entry",
|
||||||
|
"entry_name",
|
||||||
|
config_entry.title
|
||||||
|
),
|
||||||
|
confirmText: this.hass.localize("ui.common.yes"),
|
||||||
|
dismissText: this.hass.localize("ui.common.no"),
|
||||||
|
}))
|
||||||
|
) {
|
||||||
|
disableConfigEntry(this.hass, cnfg_entry);
|
||||||
|
delete updates.disabled_by;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
await updateDeviceRegistryEntry(this.hass, this.deviceId, updates);
|
await updateDeviceRegistryEntry(this.hass, this.deviceId, updates);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
import { classMap } from "lit-html/directives/class-map";
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
@ -293,9 +294,11 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
batteryEntityPair && batteryEntityPair[1]
|
batteryEntityPair && batteryEntityPair[1]
|
||||||
? this.hass.states[batteryEntityPair[1]]
|
? this.hass.states[batteryEntityPair[1]]
|
||||||
: undefined;
|
: undefined;
|
||||||
return battery && !isNaN(battery.state as any)
|
const batteryIsBinary =
|
||||||
|
battery && computeStateDomain(battery) === "binary_sensor";
|
||||||
|
return battery && (batteryIsBinary || !isNaN(battery.state as any))
|
||||||
? html`
|
? html`
|
||||||
${battery.state}%
|
${batteryIsBinary ? "" : battery.state + "%"}
|
||||||
<ha-battery-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.batteryStateObj=${battery}
|
.batteryStateObj=${battery}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import "@material/mwc-icon-button";
|
import "@material/mwc-icon-button";
|
||||||
|
import { ActionDetail } from "@material/mwc-list";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical, mdiPlus } from "@mdi/js";
|
import { mdiDotsVertical, mdiPlus } from "@mdi/js";
|
||||||
import "@polymer/app-route/app-route";
|
import "@polymer/app-route/app-route";
|
||||||
@ -122,6 +123,8 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
@internalProperty() private _showIgnored = false;
|
@internalProperty() private _showIgnored = false;
|
||||||
|
|
||||||
|
@internalProperty() private _showDisabled = false;
|
||||||
|
|
||||||
@internalProperty() private _searchParms = new URLSearchParams(
|
@internalProperty() private _searchParms = new URLSearchParams(
|
||||||
window.location.hash.substring(1)
|
window.location.hash.substring(1)
|
||||||
);
|
);
|
||||||
@ -181,18 +184,30 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
(
|
(
|
||||||
configEntries: ConfigEntryExtended[],
|
configEntries: ConfigEntryExtended[],
|
||||||
filter?: string
|
filter?: string
|
||||||
): [Map<string, ConfigEntryExtended[]>, ConfigEntryExtended[]] => {
|
): [
|
||||||
|
Map<string, ConfigEntryExtended[]>,
|
||||||
|
ConfigEntryExtended[],
|
||||||
|
Map<string, ConfigEntryExtended[]>
|
||||||
|
] => {
|
||||||
const filteredConfigEnties = this._filterConfigEntries(
|
const filteredConfigEnties = this._filterConfigEntries(
|
||||||
configEntries,
|
configEntries,
|
||||||
filter
|
filter
|
||||||
);
|
);
|
||||||
const ignored: ConfigEntryExtended[] = [];
|
const ignored: ConfigEntryExtended[] = [];
|
||||||
|
const disabled: ConfigEntryExtended[] = [];
|
||||||
for (let i = filteredConfigEnties.length - 1; i >= 0; i--) {
|
for (let i = filteredConfigEnties.length - 1; i >= 0; i--) {
|
||||||
if (filteredConfigEnties[i].source === "ignore") {
|
if (filteredConfigEnties[i].source === "ignore") {
|
||||||
ignored.push(filteredConfigEnties.splice(i, 1)[0]);
|
ignored.push(filteredConfigEnties.splice(i, 1)[0]);
|
||||||
}
|
}
|
||||||
|
if (filteredConfigEnties[i].disabled_by !== null) {
|
||||||
|
disabled.push(filteredConfigEnties.splice(i, 1)[0]);
|
||||||
}
|
}
|
||||||
return [groupByIntegration(filteredConfigEnties), ignored];
|
}
|
||||||
|
return [
|
||||||
|
groupByIntegration(filteredConfigEnties),
|
||||||
|
ignored,
|
||||||
|
groupByIntegration(disabled),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -254,6 +269,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
const [
|
const [
|
||||||
groupedConfigEntries,
|
groupedConfigEntries,
|
||||||
ignoredConfigEntries,
|
ignoredConfigEntries,
|
||||||
|
disabledConfigEntries,
|
||||||
] = this._filterGroupConfigEntries(this._configEntries, this._filter);
|
] = this._filterGroupConfigEntries(this._configEntries, this._filter);
|
||||||
const configEntriesInProgress = this._filterConfigEntriesInProgress(
|
const configEntriesInProgress = this._filterConfigEntriesInProgress(
|
||||||
this._configEntriesInProgress,
|
this._configEntriesInProgress,
|
||||||
@ -289,7 +305,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
<ha-button-menu
|
<ha-button-menu
|
||||||
corner="BOTTOM_START"
|
corner="BOTTOM_START"
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
@action=${this._toggleShowIgnored}
|
@action=${this._handleMenuAction}
|
||||||
>
|
>
|
||||||
<mwc-icon-button
|
<mwc-icon-button
|
||||||
.title=${this.hass.localize("ui.common.menu")}
|
.title=${this.hass.localize("ui.common.menu")}
|
||||||
@ -305,6 +321,13 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
: "ui.panel.config.integrations.ignore.show_ignored"
|
: "ui.panel.config.integrations.ignore.show_ignored"
|
||||||
)}
|
)}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
|
<mwc-list-item>
|
||||||
|
${this.hass.localize(
|
||||||
|
this._showDisabled
|
||||||
|
? "ui.panel.config.integrations.disable.hide_disabled"
|
||||||
|
: "ui.panel.config.integrations.disable.show_disabled"
|
||||||
|
)}
|
||||||
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
|
|
||||||
${!this.narrow
|
${!this.narrow
|
||||||
@ -319,6 +342,20 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
"ui.panel.config.integrations.search"
|
"ui.panel.config.integrations.search"
|
||||||
)}
|
)}
|
||||||
></search-input>
|
></search-input>
|
||||||
|
${!this._showDisabled && disabledConfigEntries.size
|
||||||
|
? html`<div class="active-filters">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.disable.disabled_integrations",
|
||||||
|
"number",
|
||||||
|
disabledConfigEntries.size
|
||||||
|
)}
|
||||||
|
<mwc-button @click=${this._toggleShowDisabled}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.filtering.show"
|
||||||
|
)}</mwc-button
|
||||||
|
>
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@ -433,6 +470,21 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
: ""}
|
: ""}
|
||||||
|
${this._showDisabled
|
||||||
|
? Array.from(disabledConfigEntries.entries()).map(
|
||||||
|
([domain, items]) =>
|
||||||
|
html`<ha-integration-card
|
||||||
|
data-domain=${domain}
|
||||||
|
disabled
|
||||||
|
.hass=${this.hass}
|
||||||
|
.domain=${domain}
|
||||||
|
.items=${items}
|
||||||
|
.manifest=${this._manifests[domain]}
|
||||||
|
.entityRegistryEntries=${this._entityRegistryEntries}
|
||||||
|
.deviceRegistryEntries=${this._deviceRegistryEntries}
|
||||||
|
></ha-integration-card> `
|
||||||
|
)
|
||||||
|
: ""}
|
||||||
${groupedConfigEntries.size
|
${groupedConfigEntries.size
|
||||||
? Array.from(groupedConfigEntries.entries()).map(
|
? Array.from(groupedConfigEntries.entries()).map(
|
||||||
([domain, items]) =>
|
([domain, items]) =>
|
||||||
@ -596,10 +648,25 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
getConfigFlowInProgressCollection(this.hass.connection).refresh();
|
getConfigFlowInProgressCollection(this.hass.connection).refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
||||||
|
switch (ev.detail.index) {
|
||||||
|
case 0:
|
||||||
|
this._toggleShowIgnored();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this._toggleShowDisabled();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _toggleShowIgnored() {
|
private _toggleShowIgnored() {
|
||||||
this._showIgnored = !this._showIgnored;
|
this._showIgnored = !this._showIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _toggleShowDisabled() {
|
||||||
|
this._showDisabled = !this._showDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
private async _removeIgnoredIntegration(ev: Event) {
|
private async _removeIgnoredIntegration(ev: Event) {
|
||||||
const entry = (ev.target! as any).entry;
|
const entry = (ev.target! as any).entry;
|
||||||
showConfirmationDialog(this, {
|
showConfirmationDialog(this, {
|
||||||
@ -767,11 +834,14 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
}
|
}
|
||||||
.search {
|
.search {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
background: var(--sidebar-background-color);
|
background: var(--sidebar-background-color);
|
||||||
border-bottom: 1px solid var(--divider-color);
|
border-bottom: 1px solid var(--divider-color);
|
||||||
}
|
}
|
||||||
.search search-input {
|
.search search-input {
|
||||||
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
}
|
}
|
||||||
@ -796,6 +866,32 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
.active-filters {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 2px 2px 8px;
|
||||||
|
margin-left: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.active-filters ha-icon {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
.active-filters mwc-button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.active-filters::before {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
opacity: 0.12;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,15 @@ import {
|
|||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import {
|
import {
|
||||||
ConfigEntry,
|
ConfigEntry,
|
||||||
deleteConfigEntry,
|
deleteConfigEntry,
|
||||||
|
disableConfigEntry,
|
||||||
|
enableConfigEntry,
|
||||||
reloadConfigEntry,
|
reloadConfigEntry,
|
||||||
updateConfigEntry,
|
updateConfigEntry,
|
||||||
} from "../../../data/config_entries";
|
} from "../../../data/config_entries";
|
||||||
@ -88,6 +91,8 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
|
|
||||||
@property() public selectedConfigEntryId?: string;
|
@property() public selectedConfigEntryId?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
firstUpdated(changedProps) {
|
firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
}
|
}
|
||||||
@ -109,7 +114,14 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
|
|
||||||
private _renderGroupedIntegration(): TemplateResult {
|
private _renderGroupedIntegration(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-card outlined class="group">
|
<ha-card outlined class="group ${classMap({ disabled: this.disabled })}">
|
||||||
|
${this.disabled
|
||||||
|
? html`<div class="header">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_entry.disable.disabled"
|
||||||
|
)}
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
<div class="group-header">
|
<div class="group-header">
|
||||||
<img
|
<img
|
||||||
src=${brandsUrl(this.domain, "icon")}
|
src=${brandsUrl(this.domain, "icon")}
|
||||||
@ -148,7 +160,9 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
outlined
|
outlined
|
||||||
class="single integration"
|
class="single integration ${classMap({
|
||||||
|
disabled: Boolean(item.disabled_by),
|
||||||
|
})}"
|
||||||
.configEntry=${item}
|
.configEntry=${item}
|
||||||
.id=${item.entry_id}
|
.id=${item.entry_id}
|
||||||
>
|
>
|
||||||
@ -159,6 +173,17 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
@click=${this._back}
|
@click=${this._back}
|
||||||
></ha-icon-button>`
|
></ha-icon-button>`
|
||||||
: ""}
|
: ""}
|
||||||
|
${item.disabled_by
|
||||||
|
? html`<div class="header">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_entry.disable.disabled_cause",
|
||||||
|
"cause",
|
||||||
|
this.hass.localize(
|
||||||
|
`ui.panel.config.integrations.config_entry.disable.disabled_by.${item.disabled_by}`
|
||||||
|
) || item.disabled_by
|
||||||
|
)}
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="image">
|
<div class="image">
|
||||||
<img
|
<img
|
||||||
@ -222,11 +247,16 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<div>
|
<div>
|
||||||
<mwc-button @click=${this._editEntryName}
|
${item.disabled_by === "user"
|
||||||
>${this.hass.localize(
|
? html`<mwc-button unelevated @click=${this._handleEnable}>
|
||||||
|
${this.hass.localize("ui.common.enable")}
|
||||||
|
</mwc-button>`
|
||||||
|
: ""}
|
||||||
|
<mwc-button @click=${this._editEntryName}>
|
||||||
|
${this.hass.localize(
|
||||||
"ui.panel.config.integrations.config_entry.rename"
|
"ui.panel.config.integrations.config_entry.rename"
|
||||||
)}</mwc-button
|
)}
|
||||||
>
|
</mwc-button>
|
||||||
${item.domain in integrationsWithPanel
|
${item.domain in integrationsWithPanel
|
||||||
? html`<a
|
? html`<a
|
||||||
href=${`${
|
href=${`${
|
||||||
@ -279,13 +309,25 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</a>
|
</a>
|
||||||
`}
|
`}
|
||||||
${item.state === "loaded" && item.supports_unload
|
${!item.disabled_by &&
|
||||||
|
item.state === "loaded" &&
|
||||||
|
item.supports_unload
|
||||||
? html`<mwc-list-item @request-selected="${this._handleReload}">
|
? html`<mwc-list-item @request-selected="${this._handleReload}">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.integrations.config_entry.reload"
|
"ui.panel.config.integrations.config_entry.reload"
|
||||||
)}
|
)}
|
||||||
</mwc-list-item>`
|
</mwc-list-item>`
|
||||||
: ""}
|
: ""}
|
||||||
|
${item.disabled_by === "user"
|
||||||
|
? html`<mwc-list-item @request-selected="${this._handleEnable}">
|
||||||
|
${this.hass.localize("ui.common.enable")}
|
||||||
|
</mwc-list-item>`
|
||||||
|
: html`<mwc-list-item
|
||||||
|
class="warning"
|
||||||
|
@request-selected="${this._handleDisable}"
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.common.disable")}
|
||||||
|
</mwc-list-item>`}
|
||||||
<mwc-list-item
|
<mwc-list-item
|
||||||
class="warning"
|
class="warning"
|
||||||
@request-selected="${this._handleDelete}"
|
@request-selected="${this._handleDelete}"
|
||||||
@ -370,6 +412,24 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleDisable(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||||
|
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._disableIntegration(
|
||||||
|
((ev.target as HTMLElement).closest("ha-card") as any).configEntry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleEnable(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||||
|
if (ev.detail.source && !shouldHandleRequestSelectedEvent(ev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._enableIntegration(
|
||||||
|
((ev.target as HTMLElement).closest("ha-card") as any).configEntry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private _handleSystemOptions(ev: CustomEvent<RequestSelectedDetail>): void {
|
private _handleSystemOptions(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||||
return;
|
return;
|
||||||
@ -385,6 +445,48 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _disableIntegration(configEntry: ConfigEntry) {
|
||||||
|
const entryId = configEntry.entry_id;
|
||||||
|
|
||||||
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_entry.disable.disable_confirm"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = await disableConfigEntry(this.hass, entryId);
|
||||||
|
if (result.require_restart) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_entry.disable_restart_confirm"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fireEvent(this, "entry-updated", {
|
||||||
|
entry: { ...configEntry, disabled_by: "user" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _enableIntegration(configEntry: ConfigEntry) {
|
||||||
|
const entryId = configEntry.entry_id;
|
||||||
|
|
||||||
|
const result = await enableConfigEntry(this.hass, entryId);
|
||||||
|
|
||||||
|
if (result.require_restart) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_entry.enable_restart_confirm"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fireEvent(this, "entry-updated", {
|
||||||
|
entry: { ...configEntry, disabled_by: null },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async _removeIntegration(configEntry: ConfigEntry) {
|
private async _removeIntegration(configEntry: ConfigEntry) {
|
||||||
const entryId = configEntry.entry_id;
|
const entryId = configEntry.entry_id;
|
||||||
|
|
||||||
@ -397,7 +499,7 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
deleteConfigEntry(this.hass, entryId).then((result) => {
|
const result = await deleteConfigEntry(this.hass, entryId);
|
||||||
fireEvent(this, "entry-removed", { entryId });
|
fireEvent(this, "entry-removed", { entryId });
|
||||||
|
|
||||||
if (result.require_restart) {
|
if (result.require_restart) {
|
||||||
@ -407,13 +509,12 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _reloadIntegration(configEntry: ConfigEntry) {
|
private async _reloadIntegration(configEntry: ConfigEntry) {
|
||||||
const entryId = configEntry.entry_id;
|
const entryId = configEntry.entry_id;
|
||||||
|
|
||||||
reloadConfigEntry(this.hass, entryId).then((result) => {
|
const result = await reloadConfigEntry(this.hass, entryId);
|
||||||
const locale_key = result.require_restart
|
const locale_key = result.require_restart
|
||||||
? "reload_restart_confirm"
|
? "reload_restart_confirm"
|
||||||
: "reload_confirm";
|
: "reload_confirm";
|
||||||
@ -422,7 +523,6 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
`ui.panel.config.integrations.config_entry.${locale_key}`
|
`ui.panel.config.integrations.config_entry.${locale_key}`
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _editEntryName(ev) {
|
private async _editEntryName(ev) {
|
||||||
@ -461,6 +561,15 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
:host(.highlight) ha-card {
|
:host(.highlight) ha-card {
|
||||||
border: 1px solid var(--accent-color);
|
border: 1px solid var(--accent-color);
|
||||||
}
|
}
|
||||||
|
.disabled {
|
||||||
|
--ha-card-border-color: var(--warning-color);
|
||||||
|
}
|
||||||
|
.disabled .header {
|
||||||
|
background: var(--warning-color);
|
||||||
|
color: var(--text-primary-color);
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
.card-content {
|
.card-content {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -11,6 +11,7 @@ import memoizeOne from "memoize-one";
|
|||||||
import { LocalStorage } from "../../../common/decorators/local-storage";
|
import { LocalStorage } from "../../../common/decorators/local-storage";
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { computeObjectId } from "../../../common/entity/compute_object_id";
|
import { computeObjectId } from "../../../common/entity/compute_object_id";
|
||||||
|
import { extractSearchParam } from "../../../common/url/search-params";
|
||||||
import "../../../components/buttons/ha-progress-button";
|
import "../../../components/buttons/ha-progress-button";
|
||||||
import "../../../components/entity/ha-entity-picker";
|
import "../../../components/entity/ha-entity-picker";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
@ -40,7 +41,19 @@ class HaPanelDevService extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(params) {
|
protected firstUpdated(params) {
|
||||||
super.firstUpdated(params);
|
super.firstUpdated(params);
|
||||||
if (!this._serviceData?.service) {
|
const serviceParam = extractSearchParam("service");
|
||||||
|
if (serviceParam) {
|
||||||
|
this._serviceData = {
|
||||||
|
service: serviceParam,
|
||||||
|
target: {},
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
if (this._yamlMode) {
|
||||||
|
this.updateComplete.then(() =>
|
||||||
|
this._yamlEditor?.setValue(this._serviceData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (!this._serviceData?.service) {
|
||||||
const domain = Object.keys(this.hass.services).sort()[0];
|
const domain = Object.keys(this.hass.services).sort()[0];
|
||||||
const service = Object.keys(this.hass.services[domain]).sort()[0];
|
const service = Object.keys(this.hass.services[domain]).sort()[0];
|
||||||
this._serviceData = {
|
this._serviceData = {
|
||||||
@ -48,6 +61,11 @@ class HaPanelDevService extends LitElement {
|
|||||||
target: {},
|
target: {},
|
||||||
data: {},
|
data: {},
|
||||||
};
|
};
|
||||||
|
if (this._yamlMode) {
|
||||||
|
this.updateComplete.then(() =>
|
||||||
|
this._yamlEditor?.setValue(this._serviceData)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +158,10 @@ class HaPanelDevService extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
${fields.map(
|
${(this._yamlMode
|
||||||
|
? fields
|
||||||
|
: this._filterSelectorFields(fields)
|
||||||
|
).map(
|
||||||
(field) => html` <tr>
|
(field) => html` <tr>
|
||||||
<td><pre>${field.key}</pre></td>
|
<td><pre>${field.key}</pre></td>
|
||||||
<td>${field.description}</td>
|
<td>${field.description}</td>
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { mdiInformationOutline } from "@mdi/js";
|
import {
|
||||||
|
mdiInformationOutline,
|
||||||
|
mdiClipboardTextMultipleOutline
|
||||||
|
} from "@mdi/js";
|
||||||
import "@polymer/paper-checkbox/paper-checkbox";
|
import "@polymer/paper-checkbox/paper-checkbox";
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
@ -15,6 +18,7 @@ import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
|||||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../styles/polymer-ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
|
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||||
|
|
||||||
const ERROR_SENTINEL = {};
|
const ERROR_SENTINEL = {};
|
||||||
/*
|
/*
|
||||||
@ -165,7 +169,7 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
<th>[[localize('ui.panel.developer-tools.tabs.states.state')]]</th>
|
<th>[[localize('ui.panel.developer-tools.tabs.states.state')]]</th>
|
||||||
<th hidden$="[[narrow]]">
|
<th hidden$="[[narrow]]">
|
||||||
[[localize('ui.panel.developer-tools.tabs.states.attributes')]]
|
[[localize('ui.panel.developer-tools.tabs.states.attributes')]]
|
||||||
<paper-checkbox checked="{{_showAttributes}}"></paper-checkbox>
|
<paper-checkbox checked="{{_showAttributes}}" on-change="{{saveAttributeCheckboxState}}"></paper-checkbox>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -205,6 +209,12 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
title="[[localize('ui.panel.developer-tools.tabs.states.more_info')]]"
|
title="[[localize('ui.panel.developer-tools.tabs.states.more_info')]]"
|
||||||
path="[[informationOutlineIcon()]]"
|
path="[[informationOutlineIcon()]]"
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
|
<ha-svg-icon
|
||||||
|
on-click="copyEntity"
|
||||||
|
alt="[[localize('ui.panel.developer-tools.tabs.states.copy_id')]]"
|
||||||
|
title="[[localize('ui.panel.developer-tools.tabs.states.copy_id')]]"
|
||||||
|
path="[[clipboardOutlineIcon()]]"
|
||||||
|
></ha-svg-icon>
|
||||||
<a href="#" on-click="entitySelected">[[entity.entity_id]]</a>
|
<a href="#" on-click="entitySelected">[[entity.entity_id]]</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -275,7 +285,7 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
|
|
||||||
_showAttributes: {
|
_showAttributes: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
value: true,
|
value: JSON.parse(localStorage.getItem("devToolsShowAttributes") || true),
|
||||||
},
|
},
|
||||||
|
|
||||||
_entities: {
|
_entities: {
|
||||||
@ -296,6 +306,11 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyEntity(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
copyToClipboard(ev.model.entity.entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
entitySelected(ev) {
|
entitySelected(ev) {
|
||||||
const state = ev.model.entity;
|
const state = ev.model.entity;
|
||||||
this._entityId = state.entity_id;
|
this._entityId = state.entity_id;
|
||||||
@ -345,6 +360,10 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
return mdiInformationOutline;
|
return mdiInformationOutline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clipboardOutlineIcon() {
|
||||||
|
return mdiClipboardTextMultipleOutline;
|
||||||
|
}
|
||||||
|
|
||||||
computeEntities(hass, _entityFilter, _stateFilter, _attributeFilter) {
|
computeEntities(hass, _entityFilter, _stateFilter, _attributeFilter) {
|
||||||
return Object.keys(hass.states)
|
return Object.keys(hass.states)
|
||||||
.map(function (key) {
|
.map(function (key) {
|
||||||
@ -459,6 +478,14 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
|||||||
return Array.isArray(value) ? value.join(", ") : value;
|
return Array.isArray(value) ? value.join(", ") : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveAttributeCheckboxState(ev) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem("devToolsShowAttributes", ev.target.checked);
|
||||||
|
} catch (e) {
|
||||||
|
// Catch for Safari private mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_computeParsedStateAttributes(stateAttributes) {
|
_computeParsedStateAttributes(stateAttributes) {
|
||||||
try {
|
try {
|
||||||
return stateAttributes.trim() ? safeLoad(stateAttributes) : {};
|
return stateAttributes.trim() ? safeLoad(stateAttributes) : {};
|
||||||
|
@ -49,10 +49,15 @@ export class HuiActionEditor extends LitElement {
|
|||||||
return config.url_path || "";
|
return config.url_path || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _service(): string {
|
||||||
|
const config = this.config as CallServiceActionConfig;
|
||||||
|
return config.service || "";
|
||||||
|
}
|
||||||
|
|
||||||
private _serviceAction = memoizeOne(
|
private _serviceAction = memoizeOne(
|
||||||
(config: CallServiceActionConfig): ServiceAction => {
|
(config: CallServiceActionConfig): ServiceAction => {
|
||||||
return {
|
return {
|
||||||
service: config.service || "",
|
service: this._service,
|
||||||
data: config.service_data,
|
data: config.service_data,
|
||||||
target: config.target,
|
target: config.target,
|
||||||
};
|
};
|
||||||
@ -155,8 +160,25 @@ export class HuiActionEditor extends LitElement {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let data;
|
||||||
|
switch (value) {
|
||||||
|
case "url": {
|
||||||
|
data = { url_path: this._url_path };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "call-service": {
|
||||||
|
data = { service: this._service };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "navigate": {
|
||||||
|
data = { navigation_path: this._navigation_path };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fireEvent(this, "value-changed", {
|
fireEvent(this, "value-changed", {
|
||||||
value: { action: value },
|
value: { action: value, ...data },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ export class HuiDialogEditCard extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _opened() {
|
private _opened() {
|
||||||
this._cardEditorEl?.refreshYamlEditor();
|
this._cardEditorEl?.focusYamlEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _canSave(): boolean {
|
private get _canSave(): boolean {
|
||||||
|
@ -61,8 +61,8 @@ export class HuiConditionalCardEditor extends LitElement
|
|||||||
this._config = config;
|
this._config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public refreshYamlEditor(focus) {
|
public focusYamlEditor() {
|
||||||
this._cardEditorEl?.refreshYamlEditor(focus);
|
this._cardEditorEl?.focusYamlEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
@ -54,8 +54,8 @@ export class HuiStackCardEditor extends LitElement
|
|||||||
this._config = config;
|
this._config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public refreshYamlEditor(focus) {
|
public focusYamlEditor() {
|
||||||
this._cardEditorEl?.refreshYamlEditor(focus);
|
this._cardEditorEl?.focusYamlEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
@ -157,18 +157,15 @@ export abstract class HuiElementEditor<T> extends LitElement {
|
|||||||
this.GUImode = !this.GUImode;
|
this.GUImode = !this.GUImode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public refreshYamlEditor(focus = false) {
|
public focusYamlEditor() {
|
||||||
if (this._configElement?.refreshYamlEditor) {
|
if (this._configElement?.focusYamlEditor) {
|
||||||
this._configElement.refreshYamlEditor(focus);
|
this._configElement.focusYamlEditor();
|
||||||
}
|
}
|
||||||
if (!this._yamlEditor?.codemirror) {
|
if (!this._yamlEditor?.codemirror) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._yamlEditor.codemirror.refresh();
|
|
||||||
if (focus) {
|
|
||||||
this._yamlEditor.codemirror.focus();
|
this._yamlEditor.codemirror.focus();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected async getConfigElement(): Promise<
|
protected async getConfigElement(): Promise<
|
||||||
LovelaceGenericElementEditor | undefined
|
LovelaceGenericElementEditor | undefined
|
||||||
@ -290,7 +287,7 @@ export abstract class HuiElementEditor<T> extends LitElement {
|
|||||||
|
|
||||||
if (this._configElementType !== this.configElementType) {
|
if (this._configElementType !== this.configElementType) {
|
||||||
// If the type has changed, we need to load a new GUI editor
|
// If the type has changed, we need to load a new GUI editor
|
||||||
this._guiSupported = false;
|
this._guiSupported = undefined;
|
||||||
this._configElement = undefined;
|
this._configElement = undefined;
|
||||||
|
|
||||||
if (!this.configElementType) {
|
if (!this.configElementType) {
|
||||||
|
@ -120,13 +120,13 @@ const actionConfigStructConfirmation = union([
|
|||||||
|
|
||||||
const actionConfigStructUrl = object({
|
const actionConfigStructUrl = object({
|
||||||
action: literal("url"),
|
action: literal("url"),
|
||||||
url_path: optional(string()),
|
url_path: string(),
|
||||||
confirmation: optional(actionConfigStructConfirmation),
|
confirmation: optional(actionConfigStructConfirmation),
|
||||||
});
|
});
|
||||||
|
|
||||||
const actionConfigStructService = object({
|
const actionConfigStructService = object({
|
||||||
action: literal("call-service"),
|
action: literal("call-service"),
|
||||||
service: optional(string()),
|
service: string(),
|
||||||
service_data: optional(object()),
|
service_data: optional(object()),
|
||||||
target: optional(
|
target: optional(
|
||||||
object({
|
object({
|
||||||
@ -140,7 +140,7 @@ const actionConfigStructService = object({
|
|||||||
|
|
||||||
const actionConfigStructNavigate = object({
|
const actionConfigStructNavigate = object({
|
||||||
action: literal("navigate"),
|
action: literal("navigate"),
|
||||||
navigation_path: optional(string()),
|
navigation_path: string(),
|
||||||
confirmation: optional(actionConfigStructConfirmation),
|
confirmation: optional(actionConfigStructConfirmation),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,7 +54,8 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
|
|||||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||||
${stateObj.state === "on"
|
${stateObj.state === "on"
|
||||||
? html`<mwc-button @click=${this._cancelScript}>
|
? html`<mwc-button @click=${this._cancelScript}>
|
||||||
${(stateObj.attributes.current || 0) > 0
|
${stateObj.attributes.mode !== "single" &&
|
||||||
|
(stateObj.attributes.current || 0) > 0
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.card.script.cancel_multiple",
|
"ui.card.script.cancel_multiple",
|
||||||
"number",
|
"number",
|
||||||
|
@ -29,6 +29,8 @@ export interface WeblinkConfig {
|
|||||||
name?: string;
|
name?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
new_tab?: boolean;
|
||||||
|
download?: boolean;
|
||||||
}
|
}
|
||||||
export interface TextConfig {
|
export interface TextConfig {
|
||||||
type: "text";
|
type: "text";
|
||||||
|
@ -47,8 +47,6 @@ class LovelaceFullConfigEditor extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _changed?: boolean;
|
@internalProperty() private _changed?: boolean;
|
||||||
|
|
||||||
private _generation = 1;
|
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<ha-app-layout>
|
<ha-app-layout>
|
||||||
@ -133,11 +131,7 @@ class LovelaceFullConfigEditor extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
height: calc(100vh - 68px);
|
height: calc(100vh - var(--header-height));
|
||||||
}
|
|
||||||
|
|
||||||
hui-code-editor {
|
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.save-button {
|
.save-button {
|
||||||
@ -154,15 +148,11 @@ class LovelaceFullConfigEditor extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _yamlChanged() {
|
private _yamlChanged() {
|
||||||
this._changed = !this.yamlEditor
|
this._changed = true;
|
||||||
.codemirror!.getDoc()
|
if (!window.onbeforeunload) {
|
||||||
.isClean(this._generation);
|
|
||||||
if (this._changed && !window.onbeforeunload) {
|
|
||||||
window.onbeforeunload = () => {
|
window.onbeforeunload = () => {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
} else if (!this._changed && window.onbeforeunload) {
|
|
||||||
window.onbeforeunload = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +214,7 @@ class LovelaceFullConfigEditor extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.yamlEditor.hasComments) {
|
if (/^#|\s#/gm.test(value)) {
|
||||||
if (
|
if (
|
||||||
!confirm(
|
!confirm(
|
||||||
this.hass.localize(
|
this.hass.localize(
|
||||||
@ -281,9 +271,6 @@ class LovelaceFullConfigEditor extends LitElement {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this._generation = this.yamlEditor
|
|
||||||
.codemirror!.getDoc()
|
|
||||||
.changeGeneration(true);
|
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
this._saving = false;
|
this._saving = false;
|
||||||
this._changed = false;
|
this._changed = false;
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
LitElement,
|
LitElement,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceRow, WeblinkConfig } from "../entity-rows/types";
|
import { LovelaceRow, WeblinkConfig } from "../entity-rows/types";
|
||||||
@ -37,8 +38,9 @@ class HuiWeblinkRow extends LitElement implements LovelaceRow {
|
|||||||
return html`
|
return html`
|
||||||
<a
|
<a
|
||||||
href=${this._config.url}
|
href=${this._config.url}
|
||||||
target=${this._config.url.indexOf("://") !== -1 ? "_blank" : ""}
|
target=${ifDefined(this._computeTargetValue())}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
|
?download=${this._config.download}
|
||||||
>
|
>
|
||||||
<ha-icon .icon="${this._config.icon}"></ha-icon>
|
<ha-icon .icon="${this._config.icon}"></ha-icon>
|
||||||
<div>${this._config.name}</div>
|
<div>${this._config.name}</div>
|
||||||
@ -66,6 +68,15 @@ class HuiWeblinkRow extends LitElement implements LovelaceRow {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected _computeTargetValue(): string | undefined {
|
||||||
|
return this._config &&
|
||||||
|
(this._config.url.indexOf("://") !== -1 ||
|
||||||
|
this._config.new_tab === true ||
|
||||||
|
this._config.download === true)
|
||||||
|
? "_blank"
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -86,5 +86,5 @@ export interface LovelaceGenericElementEditor extends HTMLElement {
|
|||||||
hass?: HomeAssistant;
|
hass?: HomeAssistant;
|
||||||
lovelace?: LovelaceConfig;
|
lovelace?: LovelaceConfig;
|
||||||
setConfig(config: any): void;
|
setConfig(config: any): void;
|
||||||
refreshYamlEditor?: (focus: boolean) => void;
|
focusYamlEditor?: () => void;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
import "../../layouts/hass-error-screen";
|
import "../../layouts/hass-error-screen";
|
||||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
import { domainToName } from "../../data/integration";
|
import { domainToName } from "../../data/integration";
|
||||||
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
|
|
||||||
const REDIRECTS: Redirects = {
|
const REDIRECTS: Redirects = {
|
||||||
developer_states: {
|
developer_states: {
|
||||||
@ -23,12 +24,21 @@ const REDIRECTS: Redirects = {
|
|||||||
developer_services: {
|
developer_services: {
|
||||||
redirect: "/developer-tools/service",
|
redirect: "/developer-tools/service",
|
||||||
},
|
},
|
||||||
|
developer_call_service: {
|
||||||
|
redirect: "/developer-tools/service",
|
||||||
|
params: {
|
||||||
|
service: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
developer_template: {
|
developer_template: {
|
||||||
redirect: "/developer-tools/template",
|
redirect: "/developer-tools/template",
|
||||||
},
|
},
|
||||||
developer_events: {
|
developer_events: {
|
||||||
redirect: "/developer-tools/event",
|
redirect: "/developer-tools/event",
|
||||||
},
|
},
|
||||||
|
config: {
|
||||||
|
redirect: "/config",
|
||||||
|
},
|
||||||
cloud: {
|
cloud: {
|
||||||
component: "cloud",
|
component: "cloud",
|
||||||
redirect: "/config/cloud",
|
redirect: "/config/cloud",
|
||||||
@ -42,6 +52,18 @@ const REDIRECTS: Redirects = {
|
|||||||
domain: "string",
|
domain: "string",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
config_mqtt: {
|
||||||
|
component: "mqtt",
|
||||||
|
redirect: "/config/mqtt",
|
||||||
|
},
|
||||||
|
config_zha: {
|
||||||
|
component: "zha",
|
||||||
|
redirect: "/config/zha/dashboard",
|
||||||
|
},
|
||||||
|
config_zwave_js: {
|
||||||
|
component: "zwave_js",
|
||||||
|
redirect: "/config/zwave_js/dashboard",
|
||||||
|
},
|
||||||
devices: {
|
devices: {
|
||||||
redirect: "/config/devices/dashboard",
|
redirect: "/config/devices/dashboard",
|
||||||
},
|
},
|
||||||
@ -52,39 +74,49 @@ const REDIRECTS: Redirects = {
|
|||||||
redirect: "/config/areas/dashboard",
|
redirect: "/config/areas/dashboard",
|
||||||
},
|
},
|
||||||
blueprints: {
|
blueprints: {
|
||||||
|
component: "blueprint",
|
||||||
redirect: "/config/blueprint/dashboard",
|
redirect: "/config/blueprint/dashboard",
|
||||||
},
|
},
|
||||||
blueprint_import: {
|
blueprint_import: {
|
||||||
|
component: "blueprint",
|
||||||
redirect: "/config/blueprint/dashboard/import",
|
redirect: "/config/blueprint/dashboard/import",
|
||||||
params: {
|
params: {
|
||||||
blueprint_url: "url",
|
blueprint_url: "url",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
automations: {
|
automations: {
|
||||||
|
component: "automation",
|
||||||
redirect: "/config/automation/dashboard",
|
redirect: "/config/automation/dashboard",
|
||||||
},
|
},
|
||||||
scenes: {
|
scenes: {
|
||||||
|
component: "scene",
|
||||||
redirect: "/config/scene/dashboard",
|
redirect: "/config/scene/dashboard",
|
||||||
},
|
},
|
||||||
scripts: {
|
scripts: {
|
||||||
|
component: "script",
|
||||||
redirect: "/config/script/dashboard",
|
redirect: "/config/script/dashboard",
|
||||||
},
|
},
|
||||||
helpers: {
|
helpers: {
|
||||||
redirect: "/config/helpers",
|
redirect: "/config/helpers",
|
||||||
},
|
},
|
||||||
tags: {
|
tags: {
|
||||||
|
component: "tags",
|
||||||
redirect: "/config/tags",
|
redirect: "/config/tags",
|
||||||
},
|
},
|
||||||
lovelace_dashboards: {
|
lovelace_dashboards: {
|
||||||
|
component: "lovelace",
|
||||||
redirect: "/config/lovelace/dashboards",
|
redirect: "/config/lovelace/dashboards",
|
||||||
},
|
},
|
||||||
lovelace_resources: {
|
lovelace_resources: {
|
||||||
|
component: "lovelace",
|
||||||
redirect: "/config/lovelace/resources",
|
redirect: "/config/lovelace/resources",
|
||||||
},
|
},
|
||||||
people: {
|
people: {
|
||||||
|
component: "person",
|
||||||
redirect: "/config/person",
|
redirect: "/config/person",
|
||||||
},
|
},
|
||||||
zones: {
|
zones: {
|
||||||
|
component: "zone",
|
||||||
redirect: "/config/zone",
|
redirect: "/config/zone",
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
@ -108,6 +140,14 @@ const REDIRECTS: Redirects = {
|
|||||||
profile: {
|
profile: {
|
||||||
redirect: "/profile/dashboard",
|
redirect: "/profile/dashboard",
|
||||||
},
|
},
|
||||||
|
logbook: {
|
||||||
|
component: "logbook",
|
||||||
|
redirect: "/logbook",
|
||||||
|
},
|
||||||
|
history: {
|
||||||
|
component: "history",
|
||||||
|
redirect: "/history",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ParamType = "url" | "string";
|
export type ParamType = "url" | "string";
|
||||||
@ -201,12 +241,16 @@ class HaPanelMy extends LitElement {
|
|||||||
) || "This redirect is not supported.";
|
) || "This redirect is not supported.";
|
||||||
break;
|
break;
|
||||||
case "no_supervisor":
|
case "no_supervisor":
|
||||||
error =
|
error = this.hass.localize(
|
||||||
this.hass.localize(
|
"ui.panel.my.no_supervisor",
|
||||||
"ui.panel.my.component_not_loaded",
|
"docs_link",
|
||||||
"integration",
|
html`<a
|
||||||
"Home Assistant Supervisor"
|
target="_blank"
|
||||||
) || "This redirect requires Home Assistant Supervisor.";
|
rel="noreferrer noopener"
|
||||||
|
href="${documentationUrl(this.hass, "/installation")}"
|
||||||
|
>${this.hass.localize("ui.panel.my.documentation")}</a
|
||||||
|
>`
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error = this.hass.localize("ui.panel.my.error") || "Unknown error";
|
error = this.hass.localize("ui.panel.my.error") || "Unknown error";
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
interface LoadedCodeMirror {
|
let loaded: Promise<typeof import("./codemirror")>;
|
||||||
codeMirror: any;
|
|
||||||
codeMirrorCss: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
let loaded: Promise<LoadedCodeMirror>;
|
export const loadCodeMirror = async (): Promise<
|
||||||
|
typeof import("./codemirror")
|
||||||
export const loadCodeMirror = async (): Promise<LoadedCodeMirror> => {
|
> => {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
loaded = import("./codemirror");
|
loaded = import("./codemirror");
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,122 @@
|
|||||||
// @ts-ignore
|
import { HighlightStyle, tags } from "@codemirror/highlight";
|
||||||
import _CodeMirror, { Editor } from "codemirror";
|
import { EditorView as CMEditorView } from "@codemirror/view";
|
||||||
// @ts-ignore
|
import { StreamLanguage } from "@codemirror/stream-parser";
|
||||||
import _codeMirrorCss from "codemirror/lib/codemirror.css";
|
import { jinja2 } from "@codemirror/legacy-modes/mode/jinja2";
|
||||||
import "codemirror/mode/jinja2/jinja2";
|
import { yaml } from "@codemirror/legacy-modes/mode/yaml";
|
||||||
import "codemirror/mode/yaml/yaml";
|
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
|
||||||
|
|
||||||
// @ts-ignore
|
export { keymap } from "@codemirror/view";
|
||||||
_CodeMirror.commands.save = (cm: Editor) => {
|
export { CMEditorView as EditorView };
|
||||||
fireEvent(cm.getWrapperElement(), "editor-save");
|
export { EditorState, Prec, tagExtension } from "@codemirror/state";
|
||||||
|
export { defaultKeymap, defaultTabBinding } from "@codemirror/commands";
|
||||||
|
export { lineNumbers } from "@codemirror/gutter";
|
||||||
|
|
||||||
|
export const langs = {
|
||||||
|
jinja2: StreamLanguage.define(jinja2),
|
||||||
|
yaml: StreamLanguage.define(yaml),
|
||||||
};
|
};
|
||||||
export const codeMirror: any = _CodeMirror;
|
|
||||||
export const codeMirrorCss: any = _codeMirrorCss;
|
export const theme = CMEditorView.theme({
|
||||||
|
$: {
|
||||||
|
color: "var(--primary-text-color)",
|
||||||
|
backgroundColor:
|
||||||
|
"var(--code-editor-background-color, var(--card-background-color))",
|
||||||
|
"& ::selection": { backgroundColor: "rgba(var(--rgb-primary-color), 0.2)" },
|
||||||
|
caretColor: "var(--secondary-text-color)",
|
||||||
|
height: "var(--code-mirror-height, auto)",
|
||||||
|
},
|
||||||
|
|
||||||
|
$$focused: { outline: "none" },
|
||||||
|
|
||||||
|
"$$focused $cursor": { borderLeftColor: "#var(--secondary-text-color)" },
|
||||||
|
"$$focused $selectionBackground, $selectionBackground": {
|
||||||
|
backgroundColor: "rgba(var(--rgb-primary-color), 0.2)",
|
||||||
|
},
|
||||||
|
|
||||||
|
$gutters: {
|
||||||
|
backgroundColor:
|
||||||
|
"var(--paper-dialog-background-color, var(--primary-background-color))",
|
||||||
|
color: "var(--paper-dialog-color, var(--secondary-text-color))",
|
||||||
|
border: "none",
|
||||||
|
borderRight:
|
||||||
|
"1px solid var(--paper-input-container-color, var(--secondary-text-color))",
|
||||||
|
},
|
||||||
|
"$$focused $gutters": {
|
||||||
|
borderRight:
|
||||||
|
"2px solid var(--paper-input-container-focus-color, var(--primary-color))",
|
||||||
|
},
|
||||||
|
"$gutterElementags.lineNumber": { color: "inherit" },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const highlightStyle = HighlightStyle.define(
|
||||||
|
{ tag: tags.keyword, color: "var(--codemirror-keyword, #6262FF)" },
|
||||||
|
{
|
||||||
|
tag: [
|
||||||
|
tags.name,
|
||||||
|
tags.deleted,
|
||||||
|
tags.character,
|
||||||
|
tags.propertyName,
|
||||||
|
tags.macroName,
|
||||||
|
],
|
||||||
|
color: "var(--codemirror-property, #905)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: [tags.function(tags.variableName), tags.labelName],
|
||||||
|
color: "var(--codemirror-variable, #07a)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)],
|
||||||
|
color: "var(--codemirror-qualifier, #690)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: [tags.definition(tags.name), tags.separator],
|
||||||
|
color: "var(--codemirror-def, #8DA6CE)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: [
|
||||||
|
tags.typeName,
|
||||||
|
tags.className,
|
||||||
|
tags.number,
|
||||||
|
tags.changed,
|
||||||
|
tags.annotation,
|
||||||
|
tags.modifier,
|
||||||
|
tags.self,
|
||||||
|
tags.namespace,
|
||||||
|
],
|
||||||
|
color: "var(--codemirror-number, #ca7841)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: [
|
||||||
|
tags.operator,
|
||||||
|
tags.operatorKeyword,
|
||||||
|
tags.url,
|
||||||
|
tags.escape,
|
||||||
|
tags.regexp,
|
||||||
|
tags.link,
|
||||||
|
tags.special(tags.string),
|
||||||
|
],
|
||||||
|
color: "var(--codemirror-operator, #cda869)",
|
||||||
|
},
|
||||||
|
{ tag: tags.comment, color: "var(--codemirror-comment, #777)" },
|
||||||
|
{
|
||||||
|
tag: tags.meta,
|
||||||
|
color: "var(--codemirror-meta, var(--primary-text-color))",
|
||||||
|
},
|
||||||
|
{ tag: tags.strong, fontWeight: "bold" },
|
||||||
|
{ tag: tags.emphasis, fontStyle: "italic" },
|
||||||
|
{
|
||||||
|
tag: tags.link,
|
||||||
|
color: "var(--primary-color)",
|
||||||
|
textDecoration: "underline",
|
||||||
|
},
|
||||||
|
{ tag: tags.heading, fontWeight: "bold" },
|
||||||
|
{ tag: tags.atom, color: "var(--codemirror-atom, #F90)" },
|
||||||
|
{ tag: tags.bool, color: "var(--codemirror-atom, #F90)" },
|
||||||
|
{
|
||||||
|
tag: tags.special(tags.variableName),
|
||||||
|
color: "var(--codemirror-variable-2, #690)",
|
||||||
|
},
|
||||||
|
{ tag: tags.processingInstruction, color: "var(--secondary-text-color)" },
|
||||||
|
{ tag: tags.string, color: "var(--codemirror-string, #07a)" },
|
||||||
|
{ tag: tags.inserted, color: "var(--codemirror-string2, #07a)" },
|
||||||
|
{ tag: tags.invalid, color: "var(--error-color)" }
|
||||||
|
);
|
||||||
|
@ -33,7 +33,8 @@ export class StateCardScript extends LitElement {
|
|||||||
></state-info>
|
></state-info>
|
||||||
${stateObj.state === "on"
|
${stateObj.state === "on"
|
||||||
? html`<mwc-button @click=${this._cancelScript}>
|
? html`<mwc-button @click=${this._cancelScript}>
|
||||||
${(stateObj.attributes.current || 0) > 0
|
${stateObj.attributes.mode !== "single" &&
|
||||||
|
(stateObj.attributes.current || 0) > 0
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.card.script.cancel_multiple",
|
"ui.card.script.cancel_multiple",
|
||||||
"number",
|
"number",
|
||||||
|
@ -98,7 +98,7 @@
|
|||||||
"disabled_by": {
|
"disabled_by": {
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"integration": "Integration",
|
"integration": "Integration",
|
||||||
"config_entry": "Config Entry",
|
"config_entry": "Config entry",
|
||||||
"device": "Device"
|
"device": "Device"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -339,8 +339,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"target-picker": {
|
"target-picker": {
|
||||||
"expand_area_id": "Expand this area in the seperate devices and entities that it contains. After expanding it will not update the devices and entities when the area changes.",
|
"expand_area_id": "Expand this area into the separate devices and entities that it contains. After expanding, it will not update the devices and entities when the area changes.",
|
||||||
"expand_device_id": "Expand this device in seperate entities. After expanding it will not update the entities when the device changes.",
|
"expand_device_id": "Expand this device into the separate entities that it contains. After expanding, it will not update the entities when the device changes.",
|
||||||
"remove_area_id": "Remove area",
|
"remove_area_id": "Remove area",
|
||||||
"remove_device_id": "Remove device",
|
"remove_device_id": "Remove device",
|
||||||
"remove_entity_id": "Remove entity",
|
"remove_entity_id": "Remove entity",
|
||||||
@ -382,6 +382,19 @@
|
|||||||
"failed_create_area": "Failed to create area."
|
"failed_create_area": "Failed to create area."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"addon-picker": {
|
||||||
|
"addon": "Add-on",
|
||||||
|
"error": {
|
||||||
|
"no_supervisor": {
|
||||||
|
"title": "No Supervisor",
|
||||||
|
"description": "No Supervisor found, so add-ons could not be loaded."
|
||||||
|
},
|
||||||
|
"fetch_addons": {
|
||||||
|
"title": "Error fetching add-ons",
|
||||||
|
"description": "Fetching add-ons returned an error."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"picture-upload": {
|
"picture-upload": {
|
||||||
"label": "Picture",
|
"label": "Picture",
|
||||||
"unsupported_format": "Unsupported format, please choose a JPEG, PNG or GIF image."
|
"unsupported_format": "Unsupported format, please choose a JPEG, PNG or GIF image."
|
||||||
@ -426,8 +439,8 @@
|
|||||||
},
|
},
|
||||||
"service-control": {
|
"service-control": {
|
||||||
"required": "This field is required",
|
"required": "This field is required",
|
||||||
"target": "Target",
|
"target": "Targets",
|
||||||
"target_description": "What should this service call target",
|
"target_description": "What should this service use as targeted areas, devices or entities.",
|
||||||
"service_data": "Service data"
|
"service_data": "Service data"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
@ -813,6 +826,8 @@
|
|||||||
"my": {
|
"my": {
|
||||||
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
|
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
|
||||||
"component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.",
|
"component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.",
|
||||||
|
"no_supervisor": "This redirect is not supported by your Home Assistant installation. It needs either the Home Assistant Operating System or Home Assistant Supervised installation method. For more information, see the {docs_link}.",
|
||||||
|
"documentation": "documentation",
|
||||||
"faq_link": "My Home Assistant FAQ",
|
"faq_link": "My Home Assistant FAQ",
|
||||||
"error": "An unknown error occured"
|
"error": "An unknown error occured"
|
||||||
},
|
},
|
||||||
@ -821,7 +836,8 @@
|
|||||||
"introduction": "In this view it is possible to configure your components and Home Assistant. Not everything is possible to configure from the UI yet, but we're working on it.",
|
"introduction": "In this view it is possible to configure your components and Home Assistant. Not everything is possible to configure from the UI yet, but we're working on it.",
|
||||||
"filtering": {
|
"filtering": {
|
||||||
"filtering_by": "Filtering by",
|
"filtering_by": "Filtering by",
|
||||||
"clear": "Clear"
|
"clear": "Clear",
|
||||||
|
"show": "Show"
|
||||||
},
|
},
|
||||||
"advanced_mode": {
|
"advanced_mode": {
|
||||||
"hint_enable": "Missing config options? Enable advanced mode on",
|
"hint_enable": "Missing config options? Enable advanced mode on",
|
||||||
@ -1819,7 +1835,7 @@
|
|||||||
"disabled_by": {
|
"disabled_by": {
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"integration": "Integration",
|
"integration": "Integration",
|
||||||
"config_entry": "Config Entry"
|
"config_entry": "Config entry"
|
||||||
},
|
},
|
||||||
"enabled_description": "Disabled devices will not be shown and entities belonging to the device will be disabled and not added to Home Assistant.",
|
"enabled_description": "Disabled devices will not be shown and entities belonging to the device will be disabled and not added to Home Assistant.",
|
||||||
"automation": {
|
"automation": {
|
||||||
@ -1870,6 +1886,7 @@
|
|||||||
"scenes": "Scenes",
|
"scenes": "Scenes",
|
||||||
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
|
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
|
||||||
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
|
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
|
||||||
|
"confirm_disable_config_entry": "There are no more devices for the config entry {entry_name}, do you want to instead disable the config entry?",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"data_table": {
|
"data_table": {
|
||||||
"device": "Device",
|
"device": "Device",
|
||||||
@ -2027,6 +2044,11 @@
|
|||||||
"rename_dialog": "Edit the name of this config entry",
|
"rename_dialog": "Edit the name of this config entry",
|
||||||
"rename_input_label": "Entry name",
|
"rename_input_label": "Entry name",
|
||||||
"search": "Search integrations",
|
"search": "Search integrations",
|
||||||
|
"disable": {
|
||||||
|
"show_disabled": "Show disabled integrations",
|
||||||
|
"hide_disabled": "Hide disabled integrations",
|
||||||
|
"disabled_integrations": "{number} disabled"
|
||||||
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"ignore": "Ignore",
|
"ignore": "Ignore",
|
||||||
"confirm_ignore_title": "Ignore discovery of {name}?",
|
"confirm_ignore_title": "Ignore discovery of {name}?",
|
||||||
@ -2052,6 +2074,8 @@
|
|||||||
"restart_confirm": "Restart Home Assistant to finish removing this integration",
|
"restart_confirm": "Restart Home Assistant to finish removing this integration",
|
||||||
"reload_confirm": "The integration was reloaded",
|
"reload_confirm": "The integration was reloaded",
|
||||||
"reload_restart_confirm": "Restart Home Assistant to finish reloading this integration",
|
"reload_restart_confirm": "Restart Home Assistant to finish reloading this integration",
|
||||||
|
"disable_restart_confirm": "Restart Home Assistant to finish disabling this integration",
|
||||||
|
"enable_restart_confirm": "Restart Home Assistant to finish enabling this integration",
|
||||||
"manuf": "by {manufacturer}",
|
"manuf": "by {manufacturer}",
|
||||||
"hub": "Connected via",
|
"hub": "Connected via",
|
||||||
"firmware": "Firmware: {version}",
|
"firmware": "Firmware: {version}",
|
||||||
@ -2059,7 +2083,17 @@
|
|||||||
"device_unavailable": "Device unavailable",
|
"device_unavailable": "Device unavailable",
|
||||||
"entity_unavailable": "Entity unavailable",
|
"entity_unavailable": "Entity unavailable",
|
||||||
"area": "In {area}",
|
"area": "In {area}",
|
||||||
"no_area": "No Area"
|
"no_area": "No Area",
|
||||||
|
"disable": {
|
||||||
|
"disabled": "Disabled",
|
||||||
|
"disabled_cause": "Disabled by {cause}",
|
||||||
|
"disabled_by": {
|
||||||
|
"user": "user",
|
||||||
|
"integration": "integration",
|
||||||
|
"device": "device"
|
||||||
|
},
|
||||||
|
"disable_confirm": "Are you sure you want to disable this config entry? It's devices and entities will be disabled."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Aborted",
|
"aborted": "Aborted",
|
||||||
@ -2620,7 +2654,7 @@
|
|||||||
"confirm_remove_config_title": "Are you sure you want to remove your Lovelace UI configuration?",
|
"confirm_remove_config_title": "Are you sure you want to remove your Lovelace UI configuration?",
|
||||||
"confirm_remove_config_text": "We will automatically generate your Lovelace UI views with your areas and devices if you remove your Lovelace UI configuration.",
|
"confirm_remove_config_text": "We will automatically generate your Lovelace UI views with your areas and devices if you remove your Lovelace UI configuration.",
|
||||||
"confirm_unsaved_changes": "You have unsaved changes, are you sure you want to exit?",
|
"confirm_unsaved_changes": "You have unsaved changes, are you sure you want to exit?",
|
||||||
"confirm_unsaved_comments": "Your configuration contains comment(s), these will not be saved. Do you want to continue?",
|
"confirm_unsaved_comments": "Your configuration might contains comment(s), these will not be saved. Do you want to continue?",
|
||||||
"error_parse_yaml": "Unable to parse YAML: {error}",
|
"error_parse_yaml": "Unable to parse YAML: {error}",
|
||||||
"error_invalid_config": "Your configuration is not valid: {error}",
|
"error_invalid_config": "Your configuration is not valid: {error}",
|
||||||
"error_save_yaml": "Unable to save YAML: {error}",
|
"error_save_yaml": "Unable to save YAML: {error}",
|
||||||
@ -3311,7 +3345,8 @@
|
|||||||
"more_info": "More Info",
|
"more_info": "More Info",
|
||||||
"alert_entity_field": "Entity is a mandatory field",
|
"alert_entity_field": "Entity is a mandatory field",
|
||||||
"last_updated": "[%key:ui::dialogs::more_info_control::last_updated%]",
|
"last_updated": "[%key:ui::dialogs::more_info_control::last_updated%]",
|
||||||
"last_changed": "[%key:ui::dialogs::more_info_control::last_changed%]"
|
"last_changed": "[%key:ui::dialogs::more_info_control::last_changed%]",
|
||||||
|
"copy_id": "Copy ID to clipboard"
|
||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
"title": "Template",
|
"title": "Template",
|
||||||
|
41
test-mocha/common/config/version.ts
Normal file
41
test-mocha/common/config/version.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { assert } from "chai";
|
||||||
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
|
|
||||||
|
const testTruthyData = [
|
||||||
|
{ version: "2021.1.1", major: 2021, minor: 1, patch: 1 },
|
||||||
|
{ version: "2021.1.1", major: 2021, minor: 1 },
|
||||||
|
{ version: "2021.1.1", major: 2020, minor: 12, patch: 1 },
|
||||||
|
{ version: "2021.1.1", major: 2020, minor: 12 },
|
||||||
|
{ version: "2021.1.1", major: 2021, minor: 2, patch: 0 },
|
||||||
|
{ version: "2021.1.1", major: 2021, minor: 2 },
|
||||||
|
|
||||||
|
{ version: "2021.2.4", major: 0, minor: 113, patch: 0 },
|
||||||
|
{ version: "2021.2.4", major: 0, minor: 113 },
|
||||||
|
|
||||||
|
{ version: "0.114.0", major: 0, minor: 113, patch: 0 },
|
||||||
|
{ version: "0.114.0", major: 0, minor: 113 },
|
||||||
|
|
||||||
|
{ version: "2021.2.0dev.2323", major: 2021, minor: 2, patch: 0 },
|
||||||
|
{ version: "2021.2.0dev.2323", major: 2021, minor: 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const testFalsyData = [
|
||||||
|
{ version: "0.114.0", major: 0, minor: 113 },
|
||||||
|
{ version: "2021.2.0dev.2323", major: 2021, minor: 2, patch: 0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe("atLeastVersion - Truthy", () => {
|
||||||
|
testTruthyData.forEach((test) =>
|
||||||
|
it(`'${test.version}' >= ${test.major},${test.minor},${test.patch}`, () => {
|
||||||
|
assert.isTrue(atLeastVersion("2021.1.1", 2021, 1));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("atLeastVersion - Falsy", () => {
|
||||||
|
testFalsyData.forEach((test) =>
|
||||||
|
it(`'${test.version}' >= ${test.major},${test.minor},${test.patch}`, () => {
|
||||||
|
assert.isTrue(atLeastVersion("2021.1.1", 2021, 1));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
@ -754,7 +754,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Na",
|
"after": "Na",
|
||||||
"before": "Voor",
|
"before": "Voor",
|
||||||
"label": "Tyd"
|
"label": "Tyd",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Maandag"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "Entiteit met plek",
|
"entity": "Entiteit met plek",
|
||||||
|
@ -717,7 +717,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "بعد",
|
"after": "بعد",
|
||||||
"before": "قبل",
|
"before": "قبل",
|
||||||
"label": "وقت"
|
"label": "وقت",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "الاثنين"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "كيان مع موقع",
|
"entity": "كيان مع موقع",
|
||||||
|
@ -186,6 +186,15 @@
|
|||||||
"no_blueprints": "আপনার কোনও ব্লুপ্রিন্ট নেই",
|
"no_blueprints": "আপনার কোনও ব্লুপ্রিন্ট নেই",
|
||||||
"no_inputs": "এই ব্লুপ্রিন্টের কোনও ইনপুট নেই।"
|
"no_inputs": "এই ব্লুপ্রিন্টের কোনও ইনপুট নেই।"
|
||||||
},
|
},
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "সোমবার"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"introduction": "ট্রিগারগুলি যা অটোমেশন নিয়মের প্রক্রিয়া শুরু করে। একই নিয়মের জন্য একাধিক ট্রিগার নির্দিষ্ট করা সম্ভব। ট্রিগার শুরু হয়ে গেলে, Home Assistant এর শর্তগুলি যথাযথভাবে প্রযোজ্য হবে, যদি থাকে তবে এবং অ্যাকশন কল করবে।",
|
"introduction": "ট্রিগারগুলি যা অটোমেশন নিয়মের প্রক্রিয়া শুরু করে। একই নিয়মের জন্য একাধিক ট্রিগার নির্দিষ্ট করা সম্ভব। ট্রিগার শুরু হয়ে গেলে, Home Assistant এর শর্তগুলি যথাযথভাবে প্রযোজ্য হবে, যদি থাকে তবে এবং অ্যাকশন কল করবে।",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -242,6 +242,15 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"automation": {
|
"automation": {
|
||||||
"editor": {
|
"editor": {
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Ponedeljak"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"type": {
|
"type": {
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "fa {count} {count, plural,\n one {setmana}\n other {setmanes}\n}"
|
"week": "fa {count} {count, plural,\n one {setmana}\n other {setmanes}\n}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "Aquest camp és obligatori",
|
||||||
|
"service_data": "Dades del servei",
|
||||||
|
"target": "Objectiu",
|
||||||
|
"target_description": "Objectiu d'aquesta crida de servei"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Servei"
|
"service": "Servei"
|
||||||
},
|
},
|
||||||
@ -1152,7 +1158,7 @@
|
|||||||
"event": {
|
"event": {
|
||||||
"event": "Esdeveniment:",
|
"event": "Esdeveniment:",
|
||||||
"label": "Disparar esdeveniment",
|
"label": "Disparar esdeveniment",
|
||||||
"service_data": "Dades de servei"
|
"service_data": "Dades del servei"
|
||||||
},
|
},
|
||||||
"repeat": {
|
"repeat": {
|
||||||
"label": "Repeteix",
|
"label": "Repeteix",
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Avortat",
|
"aborted": "Avortat",
|
||||||
"close": "Tanca",
|
"close": "Tanca",
|
||||||
|
"could_not_load": "El flux de dades de configuració no s'ha pogut carregar",
|
||||||
"created_config": "S'ha creat configuració per a {name}.",
|
"created_config": "S'ha creat configuració per a {name}.",
|
||||||
"dismiss": "Omet el diàleg",
|
"dismiss": "Omet el diàleg",
|
||||||
|
"error": "Error",
|
||||||
"error_saving_area": "Error desant àrea: {error}",
|
"error_saving_area": "Error desant àrea: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Aquest pas requereix que visitis un lloc web extern per completar-lo.",
|
"description": "Aquest pas requereix que visitis un lloc web extern per completar-lo.",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "Finalitza",
|
"finish": "Finalitza",
|
||||||
"loading_first_time": "Espera mentre s'instal·la la integració",
|
"loading_first_time": "Espera mentre s'instal·la la integració",
|
||||||
"not_all_required_fields": "No s'han omplert tots els camps obligatoris.",
|
"not_all_required_fields": "No s'han omplert tots els camps obligatoris.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "No, configura una altra instància de {integration}",
|
||||||
|
"title": "N'hem descobert aquests, vols configurar-los?"
|
||||||
|
},
|
||||||
"submit": "Envia"
|
"submit": "Envia"
|
||||||
},
|
},
|
||||||
"configure": "Configurar",
|
"configure": "Configurar",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "Tipus d'esdeveniment"
|
"type": "Tipus d'esdeveniment"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "Aquest servei accepta un objectiu, per exemple: `entity_id: light.bed_light`",
|
||||||
"alert_parsing_yaml": "S'ha produït un error analitzant el codi YAML: {data}",
|
"alert_parsing_yaml": "S'ha produït un error analitzant el codi YAML: {data}",
|
||||||
|
"all_parameters": "Tots els paràmetres disponibles",
|
||||||
"call_service": "Crida servei",
|
"call_service": "Crida servei",
|
||||||
"column_description": "Descripció",
|
"column_description": "Descripció",
|
||||||
"column_example": "Exemple",
|
"column_example": "Exemple",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "No hi ha cap descripció disponible",
|
"no_description": "No hi ha cap descripció disponible",
|
||||||
"no_parameters": "Aquest servei no té paràmetres.",
|
"no_parameters": "Aquest servei no té paràmetres.",
|
||||||
"select_service": "Selecciona un servei per veure'n la descripció",
|
"select_service": "Selecciona un servei per veure'n la descripció",
|
||||||
"title": "Serveis"
|
"title": "Serveis",
|
||||||
|
"ui_mode": "Vés al mode d'interfície d'usuari",
|
||||||
|
"yaml_mode": "Vés al mode YAML",
|
||||||
|
"yaml_parameters": "Paràmetres només disponibles en mode YAML"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "L'entitat és un camp obligatori",
|
"alert_entity_field": "L'entitat és un camp obligatori",
|
||||||
|
@ -611,7 +611,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Ar ôl",
|
"after": "Ar ôl",
|
||||||
"before": "Cyn",
|
"before": "Cyn",
|
||||||
"label": "Amser"
|
"label": "Amser",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Dydd Llun"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "Endid gyda lleoliad",
|
"entity": "Endid gyda lleoliad",
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "{count} {count, plural,\n one {week}\n other {weeks}\n} ago"
|
"week": "{count} {count, plural,\n one {week}\n other {weeks}\n} ago"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "This field is required",
|
||||||
|
"service_data": "Service data",
|
||||||
|
"target": "Targets",
|
||||||
|
"target_description": "What should this service use as targeted areas, devices or entities."
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Service"
|
"service": "Service"
|
||||||
},
|
},
|
||||||
@ -727,8 +733,8 @@
|
|||||||
"add_area_id": "Pick area",
|
"add_area_id": "Pick area",
|
||||||
"add_device_id": "Pick device",
|
"add_device_id": "Pick device",
|
||||||
"add_entity_id": "Pick entity",
|
"add_entity_id": "Pick entity",
|
||||||
"expand_area_id": "Expand this area in the seperate devices and entities that it contains. After expanding it will not update the devices and entities when the area changes.",
|
"expand_area_id": "Expand this area into the separate devices and entities that it contains. After expanding, it will not update the devices and entities when the area changes.",
|
||||||
"expand_device_id": "Expand this device in seperate entities. After expanding it will not update the entities when the device changes.",
|
"expand_device_id": "Expand this device into the separate entities that it contains. After expanding, it will not update the entities when the device changes.",
|
||||||
"remove_area_id": "Remove area",
|
"remove_area_id": "Remove area",
|
||||||
"remove_device_id": "Remove device",
|
"remove_device_id": "Remove device",
|
||||||
"remove_entity_id": "Remove entity"
|
"remove_entity_id": "Remove entity"
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Aborted",
|
"aborted": "Aborted",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"could_not_load": "Config flow could not be loaded",
|
||||||
"created_config": "Created configuration for {name}.",
|
"created_config": "Created configuration for {name}.",
|
||||||
"dismiss": "Dismiss dialog",
|
"dismiss": "Dismiss dialog",
|
||||||
|
"error": "Error",
|
||||||
"error_saving_area": "Error saving area: {error}",
|
"error_saving_area": "Error saving area: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "This step requires you to visit an external website to be completed.",
|
"description": "This step requires you to visit an external website to be completed.",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "Finish",
|
"finish": "Finish",
|
||||||
"loading_first_time": "Please wait while the integration is being installed",
|
"loading_first_time": "Please wait while the integration is being installed",
|
||||||
"not_all_required_fields": "Not all required fields are filled in.",
|
"not_all_required_fields": "Not all required fields are filled in.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "No, set up an other instance of {integration}",
|
||||||
|
"title": "We discovered these, want to set them up?"
|
||||||
|
},
|
||||||
"submit": "Submit"
|
"submit": "Submit"
|
||||||
},
|
},
|
||||||
"configure": "Configure",
|
"configure": "Configure",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "Event Type"
|
"type": "Event Type"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "This service accepts a target, for example: `entity_id: light.bed_light`",
|
||||||
"alert_parsing_yaml": "Error parsing YAML: {data}",
|
"alert_parsing_yaml": "Error parsing YAML: {data}",
|
||||||
|
"all_parameters": "All available parameters",
|
||||||
"call_service": "Call Service",
|
"call_service": "Call Service",
|
||||||
"column_description": "Description",
|
"column_description": "Description",
|
||||||
"column_example": "Example",
|
"column_example": "Example",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "No description is available",
|
"no_description": "No description is available",
|
||||||
"no_parameters": "This service takes no parameters.",
|
"no_parameters": "This service takes no parameters.",
|
||||||
"select_service": "Select a service to see the description",
|
"select_service": "Select a service to see the description",
|
||||||
"title": "Services"
|
"title": "Services",
|
||||||
|
"ui_mode": "Go to UI mode",
|
||||||
|
"yaml_mode": "Go to YAML mode",
|
||||||
|
"yaml_parameters": "Parameters only available in YAML mode"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "Entity is a mandatory field",
|
"alert_entity_field": "Entity is a mandatory field",
|
||||||
|
@ -7,6 +7,19 @@
|
|||||||
},
|
},
|
||||||
"panel": {
|
"panel": {
|
||||||
"config": {
|
"config": {
|
||||||
|
"automation": {
|
||||||
|
"editor": {
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Monday"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"integrations": {
|
"integrations": {
|
||||||
"caption": "Integrations",
|
"caption": "Integrations",
|
||||||
"configure": "Configure",
|
"configure": "Configure",
|
||||||
|
@ -74,7 +74,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"conditions": {
|
"conditions": {
|
||||||
"name": "Kondiĉo"
|
"name": "Kondiĉo",
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Lundo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"edit_ui": "Redakti kun UI",
|
"edit_ui": "Redakti kun UI",
|
||||||
"edit_yaml": "Redakti kiel YAML",
|
"edit_yaml": "Redakti kiel YAML",
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "hace {count} {count, plural,\none {semana}\nother {semanas}\n}"
|
"week": "hace {count} {count, plural,\none {semana}\nother {semanas}\n}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "Este campo es obligatorio",
|
||||||
|
"service_data": "Datos de servicio",
|
||||||
|
"target": "Objetivo",
|
||||||
|
"target_description": "¿A qué debería dirigirse esta llamada de servicio?"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Servicio"
|
"service": "Servicio"
|
||||||
},
|
},
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Abortado",
|
"aborted": "Abortado",
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
|
"could_not_load": "No se pudo cargar el flujo de configuración",
|
||||||
"created_config": "Configuración creada para {name}.",
|
"created_config": "Configuración creada para {name}.",
|
||||||
"dismiss": "Descartar diálogo",
|
"dismiss": "Descartar diálogo",
|
||||||
|
"error": "Error",
|
||||||
"error_saving_area": "Error al guardar el área: {error}",
|
"error_saving_area": "Error al guardar el área: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Este paso requiere que visites una web externa para ser completado.",
|
"description": "Este paso requiere que visites una web externa para ser completado.",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "Terminar",
|
"finish": "Terminar",
|
||||||
"loading_first_time": "Por favor, espera mientras la integración está siendo instalada",
|
"loading_first_time": "Por favor, espera mientras la integración está siendo instalada",
|
||||||
"not_all_required_fields": "No se han completado todos los campos requeridos.",
|
"not_all_required_fields": "No se han completado todos los campos requeridos.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "No, configura otra instancia de {integration}",
|
||||||
|
"title": "Hemos descubierto éstas, ¿quieres configurarlas?"
|
||||||
|
},
|
||||||
"submit": "Enviar"
|
"submit": "Enviar"
|
||||||
},
|
},
|
||||||
"configure": "Configurar",
|
"configure": "Configurar",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "Tipo de evento"
|
"type": "Tipo de evento"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "Este servicio acepta un objetivo, por ejemplo: `entity_id: light.luz_dormitorio`",
|
||||||
"alert_parsing_yaml": "Error al analizar YAML: {data}",
|
"alert_parsing_yaml": "Error al analizar YAML: {data}",
|
||||||
|
"all_parameters": "Todos los parámetros disponibles",
|
||||||
"call_service": "Llamar servicio",
|
"call_service": "Llamar servicio",
|
||||||
"column_description": "Descripción",
|
"column_description": "Descripción",
|
||||||
"column_example": "Ejemplo",
|
"column_example": "Ejemplo",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "No hay descripción disponible.",
|
"no_description": "No hay descripción disponible.",
|
||||||
"no_parameters": "Este servicio no toma parámetros.",
|
"no_parameters": "Este servicio no toma parámetros.",
|
||||||
"select_service": "Seleccione un servicio para ver la descripción.",
|
"select_service": "Seleccione un servicio para ver la descripción.",
|
||||||
"title": "Servicios"
|
"title": "Servicios",
|
||||||
|
"ui_mode": "Ir al modo IU",
|
||||||
|
"yaml_mode": "Ir al modo YAML",
|
||||||
|
"yaml_parameters": "Parámetros solo disponibles en modo YAML"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "Entidad es un campo obligatorio",
|
"alert_entity_field": "Entidad es un campo obligatorio",
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "{count} {count, plural,\n one {nädala}\n other {nädala}\n} eest"
|
"week": "{count} {count, plural,\n one {nädala}\n other {nädala}\n} eest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "See väli on nõutav",
|
||||||
|
"service_data": "Teenuse andmed",
|
||||||
|
"target": "Sihtmärk",
|
||||||
|
"target_description": "Mida peaks see teenus välja kutsuma"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Teenus"
|
"service": "Teenus"
|
||||||
},
|
},
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Katkestatud",
|
"aborted": "Katkestatud",
|
||||||
"close": "Sulge",
|
"close": "Sulge",
|
||||||
|
"could_not_load": "Konfiguratsioonivoogu ei saanud laadida",
|
||||||
"created_config": "Üksuse {name} jaoks on loodud konfiguratsioon.",
|
"created_config": "Üksuse {name} jaoks on loodud konfiguratsioon.",
|
||||||
"dismiss": "Loobumisdialoog",
|
"dismiss": "Loobumisdialoog",
|
||||||
|
"error": "Viga",
|
||||||
"error_saving_area": "Viga ala salvestamisel: {error}",
|
"error_saving_area": "Viga ala salvestamisel: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Selle etapi lõpetamine nõuab välise veebisaidi külastamist.",
|
"description": "Selle etapi lõpetamine nõuab välise veebisaidi külastamist.",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "Lõpeta",
|
"finish": "Lõpeta",
|
||||||
"loading_first_time": "Palun oodake kuni sidumist paigaldatakse",
|
"loading_first_time": "Palun oodake kuni sidumist paigaldatakse",
|
||||||
"not_all_required_fields": "Kõik nõutavad väljad pole täidetud.",
|
"not_all_required_fields": "Kõik nõutavad väljad pole täidetud.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "Ei, seadista teine {integration} eksemplar",
|
||||||
|
"title": "Avastasime need, kas soovid neid seadistada?"
|
||||||
|
},
|
||||||
"submit": "Esita"
|
"submit": "Esita"
|
||||||
},
|
},
|
||||||
"configure": "Seadista",
|
"configure": "Seadista",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "Sündmuse tüüp"
|
"type": "Sündmuse tüüp"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "See teenus aktsepteerib sihtmärki, näiteks: \"entity_id: light.elutuba\"",
|
||||||
"alert_parsing_yaml": "Viga YAML'i parsimisel: {data}",
|
"alert_parsing_yaml": "Viga YAML'i parsimisel: {data}",
|
||||||
|
"all_parameters": "Kõik saadaolevad parameetrid",
|
||||||
"call_service": "Kutsu teenus",
|
"call_service": "Kutsu teenus",
|
||||||
"column_description": "Kirjeldus",
|
"column_description": "Kirjeldus",
|
||||||
"column_example": "Näide",
|
"column_example": "Näide",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "Kirjeldus pole saadaval",
|
"no_description": "Kirjeldus pole saadaval",
|
||||||
"no_parameters": "Sellel teenusel pole parameetreid.",
|
"no_parameters": "Sellel teenusel pole parameetreid.",
|
||||||
"select_service": "Kirjelduse kuvamiseks vali teenus",
|
"select_service": "Kirjelduse kuvamiseks vali teenus",
|
||||||
"title": "Teenused"
|
"title": "Teenused",
|
||||||
|
"ui_mode": "Ava kasutajaliidese režiim",
|
||||||
|
"yaml_mode": "Redigeeri YAML-is",
|
||||||
|
"yaml_parameters": "Parameetrid on saadaval ainult YAML režiimis"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "Olem on kohustuslik väli",
|
"alert_entity_field": "Olem on kohustuslik väli",
|
||||||
|
@ -442,7 +442,10 @@
|
|||||||
"value_template": "Valio txantiloia"
|
"value_template": "Valio txantiloia"
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"label": "Denbora"
|
"label": "Denbora",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Astelehena"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -895,7 +895,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "بعد از",
|
"after": "بعد از",
|
||||||
"before": "قبل از",
|
"before": "قبل از",
|
||||||
"label": "زمان"
|
"label": "زمان",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "دوشنبه"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "نهاد به همراخ موقعیت",
|
"entity": "نهاد به همراخ موقعیت",
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"automation": {
|
"automation": {
|
||||||
"editor": {
|
"editor": {
|
||||||
"triggers": {
|
"conditions": {
|
||||||
"type": {
|
"type": {
|
||||||
"mqtt": {
|
"time": {
|
||||||
"label": ""
|
"weekdays": {
|
||||||
|
"mon": "Luns"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,10 @@
|
|||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"after": "बाद",
|
"after": "बाद",
|
||||||
"before": "पहले"
|
"before": "पहले",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "सोमवार"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -731,7 +731,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Nakon",
|
"after": "Nakon",
|
||||||
"before": "Prije",
|
"before": "Prije",
|
||||||
"label": "Vrijeme"
|
"label": "Vrijeme",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "ponedjeljak"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "Entitet sa lokacijom",
|
"entity": "Entitet sa lokacijom",
|
||||||
|
@ -654,7 +654,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Հետո",
|
"after": "Հետո",
|
||||||
"before": "Նախքան",
|
"before": "Նախքան",
|
||||||
"label": "ժամանակը"
|
"label": "ժամանակը",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Երկուշաբթի"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "կազմակերպության գտնվելու վայրը",
|
"entity": "կազմակերպության գտնվելու վայրը",
|
||||||
|
@ -5,6 +5,19 @@
|
|||||||
"ui": {
|
"ui": {
|
||||||
"panel": {
|
"panel": {
|
||||||
"config": {
|
"config": {
|
||||||
|
"automation": {
|
||||||
|
"editor": {
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "ორშაბათს"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"blueprint": {
|
"blueprint": {
|
||||||
"add": {
|
"add": {
|
||||||
"file_name": "ლოკალური გეგმა-ფაილის სახელი",
|
"file_name": "ლოკალური გეგმა-ფაილის სახელი",
|
||||||
|
@ -544,7 +544,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Po",
|
"after": "Po",
|
||||||
"before": "Prieš",
|
"before": "Prieš",
|
||||||
"label": "Laikas"
|
"label": "Laikas",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Pirmadienis"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"label": "Vieta",
|
"label": "Vieta",
|
||||||
|
@ -874,7 +874,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Pēc",
|
"after": "Pēc",
|
||||||
"before": "Pirms",
|
"before": "Pirms",
|
||||||
"label": "Laiks"
|
"label": "Laiks",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Pirmdiena"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "Vienība ar atrašanos vietu",
|
"entity": "Vienība ar atrašanos vietu",
|
||||||
|
@ -3409,6 +3409,7 @@
|
|||||||
"playback_title": "Meldingsavspilling"
|
"playback_title": "Meldingsavspilling"
|
||||||
},
|
},
|
||||||
"my": {
|
"my": {
|
||||||
|
"component_not_loaded": "Denne viderekoblingen støttes ikke av Home Assistant-forekomsten. Du trenger integrasjonen {integration} å bruke denne viderekoblingen.",
|
||||||
"error": "Det oppstod en ukjent feil",
|
"error": "Det oppstod en ukjent feil",
|
||||||
"faq_link": "Vanlige spørsmål om Min Home Assistant",
|
"faq_link": "Vanlige spørsmål om Min Home Assistant",
|
||||||
"not_supported": "Denne viderekoblingen støttes ikke av Home Assistant-forekomsten. Se på {link} for viderekoblinger som støttes, og hvilken versjon de ble introdusert."
|
"not_supported": "Denne viderekoblingen støttes ikke av Home Assistant-forekomsten. Se på {link} for viderekoblinger som støttes, og hvilken versjon de ble introdusert."
|
||||||
|
@ -2002,7 +2002,7 @@
|
|||||||
},
|
},
|
||||||
"configure": "Configureer",
|
"configure": "Configureer",
|
||||||
"configured": "Geconfigureerd",
|
"configured": "Geconfigureerd",
|
||||||
"confirm_new": "Wil je {integratie} instellen?",
|
"confirm_new": "Wil je {integration} instellen?",
|
||||||
"description": "Beheer integraties met services, apparaten, ...",
|
"description": "Beheer integraties met services, apparaten, ...",
|
||||||
"details": "Integratiedetails",
|
"details": "Integratiedetails",
|
||||||
"discovered": "Ontdekt",
|
"discovered": "Ontdekt",
|
||||||
|
@ -766,7 +766,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "Etter",
|
"after": "Etter",
|
||||||
"before": "Før",
|
"before": "Før",
|
||||||
"label": "Tid"
|
"label": "Tid",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "mandag"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "Eining med posisjon",
|
"entity": "Eining med posisjon",
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "{count} {count, plural,\n one {tydzień}\n few {tygodnie}\n many {tygodni}\n other {tygodni}\n} temu"
|
"week": "{count} {count, plural,\n one {tydzień}\n few {tygodnie}\n many {tygodni}\n other {tygodni}\n} temu"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "To pole jest wymagane",
|
||||||
|
"service_data": "Dane usługi",
|
||||||
|
"target": "Cel",
|
||||||
|
"target_description": "Jaki powinien być cel wywołania tej usługi"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Usługa"
|
"service": "Usługa"
|
||||||
},
|
},
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Przerwano",
|
"aborted": "Przerwano",
|
||||||
"close": "Zamknij",
|
"close": "Zamknij",
|
||||||
|
"could_not_load": "Nie można wczytać interfejsu konfiguracji",
|
||||||
"created_config": "Utworzono konfigurację dla {name}.",
|
"created_config": "Utworzono konfigurację dla {name}.",
|
||||||
"dismiss": "Okno dialogowe odrzucenia",
|
"dismiss": "Okno dialogowe odrzucenia",
|
||||||
|
"error": "Błąd",
|
||||||
"error_saving_area": "Błąd podczas zapisywania obszaru: {error}",
|
"error_saving_area": "Błąd podczas zapisywania obszaru: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Ten krok wymaga od Ciebie odwiedzenia zewnętrznej strony.",
|
"description": "Ten krok wymaga od Ciebie odwiedzenia zewnętrznej strony.",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "Zakończ",
|
"finish": "Zakończ",
|
||||||
"loading_first_time": "Proszę czekać, trwa instalowanie integracji...",
|
"loading_first_time": "Proszę czekać, trwa instalowanie integracji...",
|
||||||
"not_all_required_fields": "Nie wszystkie wymagane pola są wypełnione.",
|
"not_all_required_fields": "Nie wszystkie wymagane pola są wypełnione.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "Nie, skonfiguruj inną instancję integracji {integration}",
|
||||||
|
"title": "Odkryliśmy je, chcesz je skonfigurować?"
|
||||||
|
},
|
||||||
"submit": "Zatwierdź"
|
"submit": "Zatwierdź"
|
||||||
},
|
},
|
||||||
"configure": "Konfiguruj",
|
"configure": "Konfiguruj",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "Typ zdarzenia"
|
"type": "Typ zdarzenia"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "Ta usługa akceptuje cel, na przykład: `entity_id: light.bed_light`",
|
||||||
"alert_parsing_yaml": "Błąd parsowania YAML: {data}",
|
"alert_parsing_yaml": "Błąd parsowania YAML: {data}",
|
||||||
|
"all_parameters": "Wszystkie dostępne parametry",
|
||||||
"call_service": "Wywołaj usługę",
|
"call_service": "Wywołaj usługę",
|
||||||
"column_description": "Opis",
|
"column_description": "Opis",
|
||||||
"column_example": "Przykład",
|
"column_example": "Przykład",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "Opis nie jest dostępny",
|
"no_description": "Opis nie jest dostępny",
|
||||||
"no_parameters": "Ta usługa nie przyjmuje parametrów.",
|
"no_parameters": "Ta usługa nie przyjmuje parametrów.",
|
||||||
"select_service": "Wybierz usługę, aby zobaczyć opis",
|
"select_service": "Wybierz usługę, aby zobaczyć opis",
|
||||||
"title": "Usługi"
|
"title": "Usługi",
|
||||||
|
"ui_mode": "Przejdź do trybu interfejsu użytkownika",
|
||||||
|
"yaml_mode": "Przejdź do trybu YAML",
|
||||||
|
"yaml_parameters": "Parametry dostępne tylko w trybie YAML"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "Encja jest polem obowiązkowym",
|
"alert_entity_field": "Encja jest polem obowiązkowym",
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "{count} {count, plural,\n one {нед.}\n other {нед.}\n} назад"
|
"week": "{count} {count, plural,\n one {нед.}\n other {нед.}\n} назад"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "Обязательное поле",
|
||||||
|
"service_data": "Данные службы",
|
||||||
|
"target": "Цель",
|
||||||
|
"target_description": "Что эта служба должна использовать в качестве цели"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Служба"
|
"service": "Служба"
|
||||||
},
|
},
|
||||||
@ -1152,7 +1158,7 @@
|
|||||||
"event": {
|
"event": {
|
||||||
"event": "Событие:",
|
"event": "Событие:",
|
||||||
"label": "Создание события",
|
"label": "Создание события",
|
||||||
"service_data": "Данные"
|
"service_data": "Данные службы"
|
||||||
},
|
},
|
||||||
"repeat": {
|
"repeat": {
|
||||||
"label": "Повтор",
|
"label": "Повтор",
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "Отменено",
|
"aborted": "Отменено",
|
||||||
"close": "Закрыть",
|
"close": "Закрыть",
|
||||||
|
"could_not_load": "Не удалось загрузить мастер настройки",
|
||||||
"created_config": "Создана конфигурация для {name}.",
|
"created_config": "Создана конфигурация для {name}.",
|
||||||
"dismiss": "Закрыть",
|
"dismiss": "Закрыть",
|
||||||
|
"error": "Ошибка",
|
||||||
"error_saving_area": "Ошибка сохранения помещения: {error}",
|
"error_saving_area": "Ошибка сохранения помещения: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Для завершения этого шага требуется посетить внешний веб-сайт.",
|
"description": "Для завершения этого шага требуется посетить внешний веб-сайт.",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "Готово",
|
"finish": "Готово",
|
||||||
"loading_first_time": "Идет установка интеграции, пожалуйста, подождите",
|
"loading_first_time": "Идет установка интеграции, пожалуйста, подождите",
|
||||||
"not_all_required_fields": "Не все обязательные поля заполнены.",
|
"not_all_required_fields": "Не все обязательные поля заполнены.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "Нет, настроить другой экземпляр {integration}",
|
||||||
|
"title": "Это обнаружено автоматически, начать настройку?"
|
||||||
|
},
|
||||||
"submit": "Подтвердить"
|
"submit": "Подтвердить"
|
||||||
},
|
},
|
||||||
"configure": "Настроить",
|
"configure": "Настроить",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "Событие"
|
"type": "Событие"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "Эта служба принимает целевой объект, например: `entity_id: light.bed_light`",
|
||||||
"alert_parsing_yaml": "Ошибка при разборе синтаксиса YAML: {data}",
|
"alert_parsing_yaml": "Ошибка при разборе синтаксиса YAML: {data}",
|
||||||
|
"all_parameters": "Все доступные параметры",
|
||||||
"call_service": "Вызвать службу",
|
"call_service": "Вызвать службу",
|
||||||
"column_description": "Описание",
|
"column_description": "Описание",
|
||||||
"column_example": "Пример",
|
"column_example": "Пример",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "Описание недоступно",
|
"no_description": "Описание недоступно",
|
||||||
"no_parameters": "Нет параметров для этой службы.",
|
"no_parameters": "Нет параметров для этой службы.",
|
||||||
"select_service": "Выберите службу, чтобы увидеть описание.",
|
"select_service": "Выберите службу, чтобы увидеть описание.",
|
||||||
"title": "Службы"
|
"title": "Службы",
|
||||||
|
"ui_mode": "Перейти в режим формы ввода",
|
||||||
|
"yaml_mode": "Перейти в режим YAML",
|
||||||
|
"yaml_parameters": "Параметры доступны только в режиме YAML"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "Укажите объект.",
|
"alert_entity_field": "Укажите объект.",
|
||||||
|
@ -666,6 +666,9 @@
|
|||||||
"week": "Pred {count} {count, plural,\none {týždňom}\nother {týždňami}\n}"
|
"week": "Pred {count} {count, plural,\none {týždňom}\nother {týždňami}\n}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"service_data": "Dáta služby"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "Služba"
|
"service": "Služba"
|
||||||
},
|
},
|
||||||
@ -1643,6 +1646,7 @@
|
|||||||
"close": "Zavrieť",
|
"close": "Zavrieť",
|
||||||
"created_config": "Vytvorená konfigurácia pre {name}.",
|
"created_config": "Vytvorená konfigurácia pre {name}.",
|
||||||
"dismiss": "Zrušiť dialógové okno",
|
"dismiss": "Zrušiť dialógové okno",
|
||||||
|
"error": "Chyba",
|
||||||
"error_saving_area": "Chyba pri ukladaní oblasti: {error}",
|
"error_saving_area": "Chyba pri ukladaní oblasti: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Tento krok vyžaduje, aby ste navštívili externú webovú stránku, ktorá dokončí proces.",
|
"description": "Tento krok vyžaduje, aby ste navštívili externú webovú stránku, ktorá dokončí proces.",
|
||||||
|
@ -73,6 +73,15 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"automation": {
|
"automation": {
|
||||||
"editor": {
|
"editor": {
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Понедељак"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"type": {
|
"type": {
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
|
@ -56,6 +56,15 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"automation": {
|
"automation": {
|
||||||
"editor": {
|
"editor": {
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "Понедељак"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"learn_more": "Сазнајте више о окидачима",
|
"learn_more": "Сазнајте више о окидачима",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -239,6 +239,15 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"automation": {
|
"automation": {
|
||||||
"editor": {
|
"editor": {
|
||||||
|
"conditions": {
|
||||||
|
"type": {
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "திங்கட்கிழமை"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"type": {
|
"type": {
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
|
@ -409,7 +409,10 @@
|
|||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"after": "తరువాత",
|
"after": "తరువాత",
|
||||||
"before": "ముందు"
|
"before": "ముందు",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "సోమవారం"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -670,7 +670,10 @@
|
|||||||
"time": {
|
"time": {
|
||||||
"after": "หลังจาก",
|
"after": "หลังจาก",
|
||||||
"before": "ก่อนที่จะ",
|
"before": "ก่อนที่จะ",
|
||||||
"label": "เวลา"
|
"label": "เวลา",
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "วันจันทร์"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"zone": {
|
"zone": {
|
||||||
"entity": "Entity พร้อมตำแหน่ง",
|
"entity": "Entity พร้อมตำแหน่ง",
|
||||||
|
@ -37,6 +37,11 @@
|
|||||||
"type": {
|
"type": {
|
||||||
"device": {
|
"device": {
|
||||||
"label": "آلہ"
|
"label": "آلہ"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"weekdays": {
|
||||||
|
"mon": "پیر"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -720,6 +720,12 @@
|
|||||||
"week": "{count} {count, plural,\n one {週}\n other {週}\n}以前"
|
"week": "{count} {count, plural,\n one {週}\n other {週}\n}以前"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "必填欄位",
|
||||||
|
"service_data": "服務資料",
|
||||||
|
"target": "目標",
|
||||||
|
"target_description": "此服務呼叫的目標"
|
||||||
|
},
|
||||||
"service-picker": {
|
"service-picker": {
|
||||||
"service": "服務"
|
"service": "服務"
|
||||||
},
|
},
|
||||||
@ -1152,7 +1158,7 @@
|
|||||||
"event": {
|
"event": {
|
||||||
"event": "事件:",
|
"event": "事件:",
|
||||||
"label": "執行事件",
|
"label": "執行事件",
|
||||||
"service_data": "資料"
|
"service_data": "服務資料"
|
||||||
},
|
},
|
||||||
"repeat": {
|
"repeat": {
|
||||||
"label": "重複",
|
"label": "重複",
|
||||||
@ -1988,8 +1994,10 @@
|
|||||||
"config_flow": {
|
"config_flow": {
|
||||||
"aborted": "已中止",
|
"aborted": "已中止",
|
||||||
"close": "關閉",
|
"close": "關閉",
|
||||||
|
"could_not_load": "設定流程無法載入",
|
||||||
"created_config": "新增 {name} 設定。",
|
"created_config": "新增 {name} 設定。",
|
||||||
"dismiss": "關閉對話",
|
"dismiss": "關閉對話",
|
||||||
|
"error": "錯誤",
|
||||||
"error_saving_area": "儲存分區錯誤:{error}",
|
"error_saving_area": "儲存分區錯誤:{error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "此步驟將需要開啟外部網站方能完成。",
|
"description": "此步驟將需要開啟外部網站方能完成。",
|
||||||
@ -1998,6 +2006,10 @@
|
|||||||
"finish": "完成",
|
"finish": "完成",
|
||||||
"loading_first_time": "請稍候、正在安裝整合",
|
"loading_first_time": "請稍候、正在安裝整合",
|
||||||
"not_all_required_fields": "所有所需欄位都需要填寫。",
|
"not_all_required_fields": "所有所需欄位都需要填寫。",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "不,設定另一組 {integration} 實例",
|
||||||
|
"title": "發現以下裝置,是否進行設定?"
|
||||||
|
},
|
||||||
"submit": "傳送"
|
"submit": "傳送"
|
||||||
},
|
},
|
||||||
"configure": "設定",
|
"configure": "設定",
|
||||||
@ -2857,7 +2869,9 @@
|
|||||||
"type": "事件類別"
|
"type": "事件類別"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"accepts_target": "服務接受目標,例如:`entity_id: light.bed_light`",
|
||||||
"alert_parsing_yaml": "解析 YAML 錯誤:{data}",
|
"alert_parsing_yaml": "解析 YAML 錯誤:{data}",
|
||||||
|
"all_parameters": "所有可用參數",
|
||||||
"call_service": "執行服務",
|
"call_service": "執行服務",
|
||||||
"column_description": "說明",
|
"column_description": "說明",
|
||||||
"column_example": "範例",
|
"column_example": "範例",
|
||||||
@ -2868,7 +2882,10 @@
|
|||||||
"no_description": "無描述可使用",
|
"no_description": "無描述可使用",
|
||||||
"no_parameters": "此服務未含任何參數。",
|
"no_parameters": "此服務未含任何參數。",
|
||||||
"select_service": "選擇服務以檢視其說明",
|
"select_service": "選擇服務以檢視其說明",
|
||||||
"title": "服務"
|
"title": "服務",
|
||||||
|
"ui_mode": "進入 UI 模式",
|
||||||
|
"yaml_mode": "進入 YAML 模式",
|
||||||
|
"yaml_parameters": "參數僅限於 YAML 模式"
|
||||||
},
|
},
|
||||||
"states": {
|
"states": {
|
||||||
"alert_entity_field": "實體為必填欄位",
|
"alert_entity_field": "實體為必填欄位",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user