mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 05:27:46 +00:00
commit
7a16ed5400
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20181207.0",
|
||||
version="20181210.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -7,6 +7,9 @@
|
||||
/** Icon to use when no icon specified for domain. */
|
||||
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
|
||||
|
||||
/** Panel to show when no panel is picked. */
|
||||
export const DEFAULT_PANEL = "states";
|
||||
|
||||
/** Domains that have a state card. */
|
||||
export const DOMAINS_WITH_CARD = [
|
||||
"climate",
|
||||
|
@ -1,22 +1,23 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export interface LovelaceConfig {
|
||||
_frontendAuto: boolean;
|
||||
title?: string;
|
||||
views: LovelaceViewConfig[];
|
||||
}
|
||||
|
||||
export interface LovelaceViewConfig {
|
||||
index?: number;
|
||||
title?: string;
|
||||
badges?: string[];
|
||||
cards?: LovelaceCardConfig[];
|
||||
id?: string;
|
||||
path?: string;
|
||||
icon?: string;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface LovelaceCardConfig {
|
||||
id?: string;
|
||||
index?: number;
|
||||
view_index?: number;
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
@ -60,95 +61,11 @@ export const fetchConfig = (
|
||||
force,
|
||||
});
|
||||
|
||||
export const migrateConfig = (hass: HomeAssistant): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/migrate",
|
||||
});
|
||||
|
||||
export const saveConfig = (
|
||||
hass: HomeAssistant,
|
||||
config: LovelaceConfig | string,
|
||||
format: "json" | "yaml"
|
||||
config: LovelaceConfig
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/save",
|
||||
config,
|
||||
format,
|
||||
});
|
||||
|
||||
export const getCardConfig = (
|
||||
hass: HomeAssistant,
|
||||
cardId: string
|
||||
): Promise<string> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/card/get",
|
||||
card_id: cardId,
|
||||
});
|
||||
|
||||
export const updateCardConfig = (
|
||||
hass: HomeAssistant,
|
||||
cardId: string,
|
||||
config: LovelaceCardConfig | string,
|
||||
format: "json" | "yaml"
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/card/update",
|
||||
card_id: cardId,
|
||||
card_config: config,
|
||||
format,
|
||||
});
|
||||
|
||||
export const deleteCard = (
|
||||
hass: HomeAssistant,
|
||||
cardId: string
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/card/delete",
|
||||
card_id: cardId,
|
||||
});
|
||||
|
||||
export const addCard = (
|
||||
hass: HomeAssistant,
|
||||
viewId: string,
|
||||
config: LovelaceCardConfig | string,
|
||||
format: "json" | "yaml"
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/card/add",
|
||||
view_id: viewId,
|
||||
card_config: config,
|
||||
format,
|
||||
});
|
||||
|
||||
export const updateViewConfig = (
|
||||
hass: HomeAssistant,
|
||||
viewId: string,
|
||||
config: LovelaceViewConfig | string,
|
||||
format: "json" | "yaml"
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/view/update",
|
||||
view_id: viewId,
|
||||
view_config: config,
|
||||
format,
|
||||
});
|
||||
|
||||
export const deleteView = (
|
||||
hass: HomeAssistant,
|
||||
viewId: string
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/view/delete",
|
||||
view_id: viewId,
|
||||
});
|
||||
|
||||
export const addView = (
|
||||
hass: HomeAssistant,
|
||||
config: LovelaceViewConfig | string,
|
||||
format: "json" | "yaml"
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config/view/add",
|
||||
view_config: config,
|
||||
format,
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ import "../home-assistant-main";
|
||||
import "../ha-init-page";
|
||||
import "../../resources/ha-style";
|
||||
import registerServiceWorker from "../../util/register-service-worker";
|
||||
import { DEFAULT_PANEL } from "../../common/const";
|
||||
|
||||
import HassBaseMixin from "./hass-base-mixin";
|
||||
import AuthMixin from "./auth-mixin";
|
||||
@ -94,7 +95,7 @@ class HomeAssistant extends ext(PolymerElement, [
|
||||
}
|
||||
|
||||
computePanelUrl(routeData) {
|
||||
return (routeData && routeData.panel) || "lovelace";
|
||||
return (routeData && routeData.panel) || DEFAULT_PANEL;
|
||||
}
|
||||
|
||||
panelUrlChanged(newPanelUrl) {
|
||||
|
@ -11,6 +11,7 @@ import "./partial-panel-resolver";
|
||||
import EventsMixin from "../mixins/events-mixin";
|
||||
import NavigateMixin from "../mixins/navigate-mixin";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import { DEFAULT_PANEL } from "../common/const";
|
||||
|
||||
import(/* webpackChunkName: "ha-sidebar" */ "../components/ha-sidebar");
|
||||
import(/* webpackChunkName: "voice-command-dialog" */ "../dialogs/ha-voice-command-dialog");
|
||||
@ -98,7 +99,7 @@ class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) {
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this._defaultPage = localStorage.defaultPage || "lovelace";
|
||||
this._defaultPage = localStorage.defaultPage || DEFAULT_PANEL;
|
||||
this.addEventListener("hass-open-menu", () => this.handleOpenMenu());
|
||||
this.addEventListener("hass-close-menu", () => this.handleCloseMenu());
|
||||
this.addEventListener("hass-start-voice", (ev) =>
|
||||
@ -135,7 +136,7 @@ class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) {
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (document.location.pathname === "/") {
|
||||
this.navigate(`/${localStorage.defaultPage || "lovelace"}`, true);
|
||||
this.navigate(`/${localStorage.defaultPage || DEFAULT_PANEL}`, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import formatTime from "../../common/datetime/format_time";
|
||||
import EventsMixin from "../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
||||
|
||||
const OPT_IN_PANEL = "lovelace";
|
||||
let registeredDialog = false;
|
||||
|
||||
class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
@ -164,7 +165,7 @@ class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
</template>
|
||||
</p>
|
||||
<p>
|
||||
<a href='/states'>Go back to the old states page</a>
|
||||
<a href='/lovelace'>Try out the new Lovelace UI</a>
|
||||
<div id="love" style="cursor:pointer;" on-click="_toggleDefaultPage">[[_defaultPageText()]]</div
|
||||
</p>
|
||||
</div>
|
||||
@ -364,15 +365,15 @@ class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
|
||||
_defaultPageText() {
|
||||
return `>> ${
|
||||
localStorage.defaultPage === "states" ? "Remove" : "Set"
|
||||
} the old states as default page on this device <<`;
|
||||
localStorage.defaultPage === OPT_IN_PANEL ? "Remove" : "Set"
|
||||
} ${OPT_IN_PANEL} as default page on this device <<`;
|
||||
}
|
||||
|
||||
_toggleDefaultPage() {
|
||||
if (localStorage.defaultPage === "states") {
|
||||
if (localStorage.defaultPage === OPT_IN_PANEL) {
|
||||
delete localStorage.defaultPage;
|
||||
} else {
|
||||
localStorage.defaultPage = "states";
|
||||
localStorage.defaultPage = OPT_IN_PANEL;
|
||||
}
|
||||
this.$.love.innerText = this._defaultPageText();
|
||||
}
|
||||
|
@ -134,8 +134,14 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
this._roundSliderStyle = loaded.roundSliderStyle;
|
||||
this._jQuery = loaded.jQuery;
|
||||
|
||||
const brightness = this.hass!.states[this._config!.entity].attributes
|
||||
.brightness;
|
||||
const stateObj = this.hass!.states[this._config!.entity] as LightEntity;
|
||||
|
||||
if (!stateObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
const brightness = stateObj.attributes.brightness || 0;
|
||||
|
||||
this._jQuery("#light", this.shadowRoot).roundSlider({
|
||||
...lightConfig,
|
||||
change: (value) => this._setBrightness(value),
|
||||
@ -152,7 +158,13 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
return;
|
||||
}
|
||||
|
||||
const attrs = this.hass!.states[this._config!.entity].attributes;
|
||||
const stateObj = this.hass!.states[this._config!.entity];
|
||||
|
||||
if (!stateObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attrs = stateObj.attributes;
|
||||
|
||||
this._jQuery("#light", this.shadowRoot).roundSlider({
|
||||
value: Math.round((attrs.brightness / 254) * 100) || 0,
|
||||
|
@ -110,7 +110,8 @@ class LongPress extends HTMLElement implements LongPress {
|
||||
const clickEnd = (ev: Event) => {
|
||||
if (
|
||||
this.cooldownEnd ||
|
||||
(ev instanceof TouchEvent && this.timer === undefined)
|
||||
(["touchend", "touchcancel"].includes(ev.type) &&
|
||||
this.timer === undefined)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ const computeDefaultViewStates = (hass: HomeAssistant): HassEntities => {
|
||||
|
||||
const generateViewConfig = (
|
||||
localize: LocalizeFunc,
|
||||
id: string,
|
||||
path: string,
|
||||
title: string | undefined,
|
||||
icon: string | undefined,
|
||||
entities: HassEntities,
|
||||
@ -158,7 +158,7 @@ const generateViewConfig = (
|
||||
});
|
||||
|
||||
return {
|
||||
id,
|
||||
path,
|
||||
title,
|
||||
icon,
|
||||
badges,
|
||||
@ -228,7 +228,6 @@ export const generateLovelaceConfig = (
|
||||
}
|
||||
|
||||
return {
|
||||
_frontendAuto: true,
|
||||
title,
|
||||
views,
|
||||
};
|
||||
|
@ -1,31 +1,23 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { showEditCardDialog } from "../editor/show-edit-card-dialog";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
|
||||
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { confDeleteCard } from "../editor/delete-card";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"show-edit-card": {
|
||||
cardConfig?: LovelaceCardConfig;
|
||||
viewId?: string | number;
|
||||
add: boolean;
|
||||
reloadLovelace: () => void;
|
||||
};
|
||||
}
|
||||
}
|
||||
import { Lovelace } from "../types";
|
||||
import { swapCard } from "../editor/config-util";
|
||||
|
||||
export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
|
||||
public cardConfig?: LovelaceCardConfig;
|
||||
protected hass?: HomeAssistant;
|
||||
protected lovelace?: Lovelace;
|
||||
protected path?: [number, number];
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return { hass: {} };
|
||||
return { hass: {}, lovelace: {}, path: {} };
|
||||
}
|
||||
|
||||
protected render() {
|
||||
@ -38,14 +30,14 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
|
||||
box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 2px 0px,
|
||||
rgba(0, 0, 0, 0.12) 0px 1px 5px 0px,
|
||||
rgba(0, 0, 0, 0.2) 0px 3px 1px -2px;
|
||||
text-align: right;
|
||||
}
|
||||
paper-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
paper-button.warning:not([disabled]) {
|
||||
color: var(--google-red-500);
|
||||
paper-icon-button.delete {
|
||||
color: var(--secondary-text-color);
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
<slot></slot>
|
||||
@ -55,36 +47,55 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
|
||||
this.localize("ui.panel.lovelace.editor.edit_card.edit")
|
||||
}</paper-button
|
||||
>
|
||||
<paper-button class="warning" @click="${this._deleteCard}"
|
||||
>${
|
||||
this.localize("ui.panel.lovelace.editor.edit_card.delete")
|
||||
}</paper-button
|
||||
>
|
||||
<paper-icon-button
|
||||
icon="hass:arrow-up"
|
||||
@click="${this._cardUp}"
|
||||
?disabled="${this.path![1] === 0}"
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon="hass:arrow-down"
|
||||
@click="${this._cardDown}"
|
||||
?disabled="${
|
||||
this.lovelace!.config.views[this.path![0]].cards!.length ===
|
||||
this.path![1] + 1
|
||||
}"
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
class="delete"
|
||||
icon="hass:delete"
|
||||
@click="${this._deleteCard}"
|
||||
title="${this.localize("ui.panel.lovelace.editor.edit_card.delete")}"
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _editCard(): void {
|
||||
if (!this.cardConfig) {
|
||||
return;
|
||||
}
|
||||
showEditCardDialog(this, {
|
||||
cardConfig: this.cardConfig,
|
||||
add: false,
|
||||
reloadLovelace: () => fireEvent(this, "config-refresh"),
|
||||
lovelace: this.lovelace!,
|
||||
path: this.path!,
|
||||
});
|
||||
}
|
||||
private _deleteCard(): void {
|
||||
if (!this.cardConfig) {
|
||||
return;
|
||||
}
|
||||
if (!this.cardConfig.id) {
|
||||
this._editCard();
|
||||
return;
|
||||
}
|
||||
confDeleteCard(this.hass!, this.cardConfig.id, () =>
|
||||
fireEvent(this, "config-refresh")
|
||||
|
||||
private _cardUp(): void {
|
||||
const lovelace = this.lovelace!;
|
||||
const path = this.path!;
|
||||
lovelace.saveConfig(
|
||||
swapCard(lovelace.config, path, [path[0], path[1] - 1])
|
||||
);
|
||||
}
|
||||
|
||||
private _cardDown(): void {
|
||||
const lovelace = this.lovelace!;
|
||||
const path = this.path!;
|
||||
lovelace.saveConfig(
|
||||
swapCard(lovelace.config, path, [path[0], path[1] + 1])
|
||||
);
|
||||
}
|
||||
|
||||
private _deleteCard(): void {
|
||||
confDeleteCard(this.lovelace!, this.path!);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -2,22 +2,11 @@ import { html, LitElement } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { getCardElementTag } from "../common/get-card-element-tag";
|
||||
import { CardPickTarget } from "./types";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
|
||||
import { uid } from "../../../common/util/uid";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"card-picked": {
|
||||
config: LovelaceCardConfig;
|
||||
};
|
||||
}
|
||||
}
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
import { CardPickTarget } from "../types";
|
||||
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
|
||||
|
||||
const cards = [
|
||||
{ name: "Alarm panel", type: "alarm-panel" },
|
||||
@ -28,7 +17,7 @@ const cards = [
|
||||
{ name: "Gauge", type: "gauge" },
|
||||
{ name: "Glance", type: "glance" },
|
||||
{ name: "History Graph", type: "history-graph" },
|
||||
{ name: "Horizontal Stack", type: "horizontal-graph" },
|
||||
{ name: "Horizontal Stack", type: "horizontal-stack" },
|
||||
{ name: "iFrame", type: "iframe" },
|
||||
{ name: "Light", type: "light" },
|
||||
{ name: "Map", type: "map" },
|
||||
@ -47,7 +36,8 @@ const cards = [
|
||||
];
|
||||
|
||||
export class HuiCardPicker extends hassLocalizeLitMixin(LitElement) {
|
||||
protected hass?: HomeAssistant;
|
||||
public hass?: HomeAssistant;
|
||||
public cardPicked?: (cardConf: LovelaceCardConfig) => void;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
@ -90,16 +80,14 @@ export class HuiCardPicker extends hassLocalizeLitMixin(LitElement) {
|
||||
const tag = getCardElementTag(type);
|
||||
|
||||
const elClass = customElements.get(tag);
|
||||
let config: LovelaceCardConfig = { type, id: uid() };
|
||||
let config: LovelaceCardConfig = { type };
|
||||
|
||||
if (elClass && elClass.getStubConfig) {
|
||||
const cardConfig = elClass.getStubConfig(this.hass);
|
||||
config = { ...config, ...cardConfig };
|
||||
}
|
||||
|
||||
fireEvent(this, "card-picked", {
|
||||
config,
|
||||
});
|
||||
this.cardPicked!(config);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
|
||||
import createCardElement from "../common/create-card-element";
|
||||
import createErrorCardConfig from "../common/create-error-card-config";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { ConfigError } from "./types";
|
||||
import { getCardElementTag } from "../common/get-card-element-tag";
|
||||
import createCardElement from "../../common/create-card-element";
|
||||
import createErrorCardConfig from "../../common/create-error-card-config";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { LovelaceCard } from "../../types";
|
||||
import { ConfigError } from "../types";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
|
||||
export class HuiCardPreview extends HTMLElement {
|
||||
private _hass?: HomeAssistant;
|
@ -1,11 +1,12 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import "./hui-edit-card";
|
||||
import "./hui-migrate-config";
|
||||
import "./hui-dialog-pick-card";
|
||||
import { EditCardDialogParams } from "./show-edit-card-dialog";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -18,66 +19,67 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export interface EditCardDialogParams {
|
||||
cardConfig?: LovelaceCardConfig;
|
||||
viewId?: string | number;
|
||||
add: boolean;
|
||||
reloadLovelace: () => void;
|
||||
}
|
||||
|
||||
export class HuiDialogEditCard extends LitElement {
|
||||
protected hass?: HomeAssistant;
|
||||
private _params?: EditCardDialogParams;
|
||||
private _cardConfig?: LovelaceCardConfig;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
_params: {},
|
||||
_cardConfig: {},
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._cardPicked = this._cardPicked.bind(this);
|
||||
this._cancel = this._cancel.bind(this);
|
||||
}
|
||||
|
||||
public async showDialog(params: EditCardDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
await this.updateComplete;
|
||||
(this.shadowRoot!.children[0] as any).showDialog();
|
||||
this._cardConfig =
|
||||
params.path.length === 2
|
||||
? (this._cardConfig = params.lovelace.config.views[
|
||||
params.path[0]
|
||||
].cards![params.path[1]])
|
||||
: undefined;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
if (
|
||||
(!this._params.add &&
|
||||
this._params.cardConfig &&
|
||||
!this._params.cardConfig.id) ||
|
||||
(this._params.add && !this._params.viewId)
|
||||
) {
|
||||
if (!this._cardConfig) {
|
||||
// Card picker
|
||||
return html`
|
||||
<hui-migrate-config
|
||||
<hui-dialog-pick-card
|
||||
.hass="${this.hass}"
|
||||
@reload-lovelace="${this._params.reloadLovelace}"
|
||||
></hui-migrate-config>
|
||||
.cardPicked="${this._cardPicked}"
|
||||
></hui-dialog-pick-card>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<hui-edit-card
|
||||
.hass="${this.hass}"
|
||||
.viewId="${this._params.viewId}"
|
||||
.cardConfig="${this._params.cardConfig}"
|
||||
@reload-lovelace="${this._params.reloadLovelace}"
|
||||
@cancel-edit-card="${this._cancel}"
|
||||
.lovelace="${this._params.lovelace}"
|
||||
.path="${this._params.path}"
|
||||
.cardConfig="${this._cardConfig}"
|
||||
.closeDialog="${this._cancel}"
|
||||
>
|
||||
</hui-edit-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private _cardPicked(cardConf: LovelaceCardConfig) {
|
||||
this._cardConfig = cardConf;
|
||||
}
|
||||
|
||||
private _cancel() {
|
||||
this._params = {
|
||||
add: false,
|
||||
reloadLovelace: () => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
this._params = undefined;
|
||||
this._cardConfig = undefined;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
|
||||
import "./hui-card-picker";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
|
||||
export class HuiDialogPickCard extends hassLocalizeLitMixin(LitElement) {
|
||||
public hass?: HomeAssistant;
|
||||
public cardPicked?: (cardConf: LovelaceCardConfig) => void;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<paper-dialog with-backdrop opened>
|
||||
<h2>${this.localize("ui.panel.lovelace.editor.edit_card.header")}</h2>
|
||||
<paper-dialog-scrollable>
|
||||
<hui-card-picker
|
||||
.hass="${this.hass}"
|
||||
.cardPicked="${this.cardPicked}"
|
||||
></hui-card-picker>
|
||||
</paper-dialog-scrollable>
|
||||
<div class="paper-dialog-buttons">
|
||||
<paper-button @click="${this._skipPick}">SKIP</paper-button>
|
||||
</div>
|
||||
</paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _skipPick() {
|
||||
this.cardPicked!({ type: "" });
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-dialog-pick-card": HuiDialogPickCard;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("hui-dialog-pick-card", HuiDialogPickCard);
|
@ -15,31 +15,22 @@ import "@polymer/paper-dialog/paper-dialog";
|
||||
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import {
|
||||
addCard,
|
||||
updateCardConfig,
|
||||
LovelaceCardConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
|
||||
|
||||
import "./hui-yaml-editor";
|
||||
import "./hui-card-picker";
|
||||
import "./hui-card-preview";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
// tslint:disable-next-line
|
||||
import { HuiCardPreview } from "./hui-card-preview";
|
||||
import { LovelaceCardEditor } from "../types";
|
||||
import {
|
||||
YamlChangedEvent,
|
||||
CardPickedEvent,
|
||||
ConfigValue,
|
||||
ConfigError,
|
||||
} from "./types";
|
||||
import { extYamlSchema } from "./yaml-ext-schema";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { getCardElementTag } from "../common/get-card-element-tag";
|
||||
import { LovelaceCardEditor, Lovelace } from "../../types";
|
||||
import { YamlChangedEvent, ConfigValue, ConfigError } from "../types";
|
||||
import { extYamlSchema } from "../yaml-ext-schema";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
import { getCardElementTag } from "../../common/get-card-element-tag";
|
||||
import { addCard, replaceCard } from "../config-util";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -52,17 +43,30 @@ declare global {
|
||||
"config-changed": {
|
||||
config: LovelaceCardConfig;
|
||||
};
|
||||
"cancel-edit-card": {};
|
||||
}
|
||||
}
|
||||
|
||||
export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
public hass?: HomeAssistant;
|
||||
public lovelace?: Lovelace;
|
||||
public path?: [number] | [number, number];
|
||||
public cardConfig?: LovelaceCardConfig;
|
||||
public closeDialog?: () => void;
|
||||
private _configElement?: LovelaceCardEditor | null;
|
||||
private _uiEditor?: boolean;
|
||||
private _configValue?: ConfigValue;
|
||||
private _configState?: string;
|
||||
private _loading?: boolean;
|
||||
private _saving: boolean;
|
||||
private _errorMsg?: TemplateResult;
|
||||
private _cardType?: string;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
cardConfig: {},
|
||||
viewId: {},
|
||||
_cardId: {},
|
||||
viewIndex: {},
|
||||
_cardIndex: {},
|
||||
_configElement: {},
|
||||
_configValue: {},
|
||||
_configState: {},
|
||||
@ -81,38 +85,15 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
return this.shadowRoot!.querySelector("hui-card-preview")!;
|
||||
}
|
||||
|
||||
public cardConfig?: LovelaceCardConfig;
|
||||
public viewId?: string | number;
|
||||
protected hass?: HomeAssistant;
|
||||
private _cardId?: string;
|
||||
private _configElement?: LovelaceCardEditor | null;
|
||||
private _uiEditor?: boolean;
|
||||
private _configValue?: ConfigValue;
|
||||
private _configState?: string;
|
||||
private _loading?: boolean;
|
||||
private _saving: boolean;
|
||||
private _errorMsg?: TemplateResult;
|
||||
private _cardType?: string;
|
||||
|
||||
protected constructor() {
|
||||
super();
|
||||
this._saving = false;
|
||||
}
|
||||
|
||||
public async showDialog(): Promise<void> {
|
||||
// Wait till dialog is rendered.
|
||||
if (this._dialog == null) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
this._dialog.open();
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
super.updated(changedProperties);
|
||||
if (
|
||||
!changedProperties.has("cardConfig") &&
|
||||
!changedProperties.has("viewId")
|
||||
) {
|
||||
|
||||
if (!changedProperties.has("cardConfig")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -122,17 +103,8 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
this._errorMsg = undefined;
|
||||
this._configElement = undefined;
|
||||
|
||||
if (this.cardConfig && String(this.cardConfig.id) !== this._cardId) {
|
||||
this._loading = true;
|
||||
this._cardId = String(this.cardConfig.id);
|
||||
this._loadConfigElement(this.cardConfig);
|
||||
} else {
|
||||
this._cardId = undefined;
|
||||
}
|
||||
|
||||
if (this.viewId && !this.cardConfig) {
|
||||
this._resizeDialog();
|
||||
}
|
||||
this._loading = true;
|
||||
this._loadConfigElement(this.cardConfig!);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@ -147,7 +119,6 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
content = html`
|
||||
<hui-yaml-editor
|
||||
.hass="${this.hass}"
|
||||
.cardId="${this._cardId}"
|
||||
.yaml="${this._configValue!.value}"
|
||||
@yaml-changed="${this._handleYamlChanged}"
|
||||
></hui-yaml-editor>
|
||||
@ -157,18 +128,11 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
<hr />
|
||||
<hui-card-preview .hass="${this.hass}"> </hui-card-preview>
|
||||
`;
|
||||
} else if (this.viewId && !this.cardConfig) {
|
||||
content = html`
|
||||
<hui-card-picker
|
||||
.hass="${this.hass}"
|
||||
@card-picked="${this._handleCardPicked}"
|
||||
></hui-card-picker>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<paper-dialog with-backdrop>
|
||||
<paper-dialog with-backdrop opened>
|
||||
<h2>${this.localize("ui.panel.lovelace.editor.edit_card.header")}</h2>
|
||||
<paper-spinner
|
||||
?active="${this._loading}"
|
||||
@ -203,7 +167,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
)
|
||||
}</paper-button
|
||||
>
|
||||
<paper-button @click="${this._closeDialog}"
|
||||
<paper-button @click="${this.closeDialog}"
|
||||
>${this.localize("ui.common.cancel")}</paper-button
|
||||
>
|
||||
<paper-button
|
||||
@ -272,15 +236,6 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
private _save(): void {
|
||||
this._saving = true;
|
||||
this._updateConfigInBackend();
|
||||
}
|
||||
|
||||
private _saveDone(): void {
|
||||
this._saving = false;
|
||||
}
|
||||
|
||||
private async _loadedDialog(): Promise<void> {
|
||||
await this.updateComplete;
|
||||
this._loading = false;
|
||||
@ -292,58 +247,42 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
fireEvent(this._dialog, "iron-resize");
|
||||
}
|
||||
|
||||
private _closeDialog(): void {
|
||||
this.cardConfig = undefined;
|
||||
this.viewId = undefined;
|
||||
fireEvent(this, "cancel-edit-card");
|
||||
this._dialog.close();
|
||||
}
|
||||
|
||||
private async _updateConfigInBackend(): Promise<void> {
|
||||
private async _save(): Promise<void> {
|
||||
if (!this._isConfigValid()) {
|
||||
alert("Your config is not valid, please fix your config before saving.");
|
||||
this._saveDone();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._isConfigChanged()) {
|
||||
this._closeDialog();
|
||||
this._saveDone();
|
||||
this.closeDialog!();
|
||||
return;
|
||||
}
|
||||
|
||||
this._saving = true;
|
||||
|
||||
const cardConf: LovelaceCardConfig =
|
||||
this._configValue!.format === "yaml"
|
||||
? yaml.safeLoad(this._configValue!.value!, {
|
||||
schema: extYamlSchema,
|
||||
})
|
||||
: this._configValue!.value!;
|
||||
|
||||
try {
|
||||
if (this.viewId) {
|
||||
await addCard(
|
||||
this.hass!,
|
||||
String(this.viewId),
|
||||
this._configValue!.value!,
|
||||
this._configValue!.format
|
||||
);
|
||||
} else {
|
||||
await updateCardConfig(
|
||||
this.hass!,
|
||||
this._cardId!,
|
||||
this._configValue!.value!,
|
||||
this._configValue!.format
|
||||
);
|
||||
}
|
||||
fireEvent(this, "reload-lovelace");
|
||||
this._closeDialog();
|
||||
this._saveDone();
|
||||
const lovelace = this.lovelace!;
|
||||
await lovelace.saveConfig(
|
||||
this._creatingCard
|
||||
? addCard(lovelace.config, this.path as [number], cardConf)
|
||||
: replaceCard(
|
||||
lovelace.config,
|
||||
this.path as [number, number],
|
||||
cardConf
|
||||
)
|
||||
);
|
||||
this.closeDialog!();
|
||||
} catch (err) {
|
||||
alert(`Saving failed: ${err.message}`);
|
||||
this._saveDone();
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleCardPicked(ev: CardPickedEvent): Promise<void> {
|
||||
const succes = await this._loadConfigElement(ev.detail.config);
|
||||
if (!succes) {
|
||||
this._configValue = {
|
||||
format: "yaml",
|
||||
value: yaml.safeDump(ev.detail.config),
|
||||
};
|
||||
} finally {
|
||||
this._saving = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,14 +333,10 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
|
||||
private async _toggleEditor(): Promise<void> {
|
||||
if (this._uiEditor && this._configValue!.format === "json") {
|
||||
if (this._isConfigChanged()) {
|
||||
this._configValue = {
|
||||
format: "yaml",
|
||||
value: yaml.safeDump(this._configValue!.value),
|
||||
};
|
||||
} else {
|
||||
this._configValue = { format: "yaml", value: undefined };
|
||||
}
|
||||
this._configValue = {
|
||||
format: "yaml",
|
||||
value: yaml.safeDump(this._configValue!.value),
|
||||
};
|
||||
this._uiEditor = !this._uiEditor;
|
||||
} else if (this._configElement && this._configValue!.format === "yaml") {
|
||||
const yamlConfig = this._configValue!.value;
|
||||
@ -438,12 +373,12 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _isConfigChanged(): boolean {
|
||||
if (this.viewId) {
|
||||
if (this._creatingCard) {
|
||||
return true;
|
||||
}
|
||||
const configValue =
|
||||
this._configValue!.format === "yaml"
|
||||
? yaml.safeDump(this._configValue!.value)
|
||||
? yaml.safeLoad(this._configValue!.value)
|
||||
: this._configValue!.value;
|
||||
return JSON.stringify(configValue) !== JSON.stringify(this.cardConfig);
|
||||
}
|
||||
@ -465,6 +400,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
if (elClass && elClass.getConfigElement) {
|
||||
configElement = await elClass.getConfigElement();
|
||||
} else {
|
||||
this._configValue = { format: "yaml", value: yaml.safeDump(conf) };
|
||||
this._uiEditor = false;
|
||||
this._configElement = null;
|
||||
return false;
|
||||
@ -477,6 +413,10 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
Your config is not supported by the UI editor:<br /><b>${err.message}</b
|
||||
><br />Falling back to YAML editor.
|
||||
`;
|
||||
this._configValue = {
|
||||
format: "yaml",
|
||||
value: yaml.safeDump(conf),
|
||||
};
|
||||
this._uiEditor = false;
|
||||
this._configElement = null;
|
||||
return false;
|
||||
@ -492,6 +432,10 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
this._updatePreview(conf);
|
||||
return true;
|
||||
}
|
||||
|
||||
private get _creatingCard(): boolean {
|
||||
return this.path!.length === 1;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
@ -1,42 +1,29 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { getCardConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
export class HuiYAMLEditor extends LitElement {
|
||||
public cardId?: string;
|
||||
protected hass?: HomeAssistant;
|
||||
private _yaml?: string;
|
||||
private _loading?: boolean;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return { _yaml: {}, cardId: {} };
|
||||
return { _yaml: {} };
|
||||
}
|
||||
|
||||
set yaml(yaml: string) {
|
||||
if (yaml === undefined) {
|
||||
this._loading = true;
|
||||
this._loadConfig();
|
||||
return;
|
||||
} else {
|
||||
this._yaml = yaml;
|
||||
if (this._loading) {
|
||||
this._loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<paper-spinner
|
||||
?active="${this._loading}"
|
||||
alt="Loading"
|
||||
class="center"
|
||||
></paper-spinner>
|
||||
<paper-textarea
|
||||
max-rows="10"
|
||||
.value="${this._yaml}"
|
||||
@ -51,31 +38,10 @@ export class HuiYAMLEditor extends LitElement {
|
||||
paper-textarea {
|
||||
--paper-input-container-shared-input-style_-_font-family: monospace;
|
||||
}
|
||||
.center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
}
|
||||
paper-spinner[active] {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _loadConfig(): Promise<void> {
|
||||
if (!this.hass || !this.cardId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._yaml = await getCardConfig(this.hass, this.cardId);
|
||||
if (this._loading) {
|
||||
this._loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private _valueChanged(ev: Event): void {
|
||||
const target = ev.target! as any;
|
||||
this._yaml = target.value;
|
@ -1,5 +1,5 @@
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Lovelace } from "../../types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -13,10 +13,8 @@ const dialogShowEvent = "show-edit-card";
|
||||
const dialogTag = "hui-dialog-edit-card";
|
||||
|
||||
export interface EditCardDialogParams {
|
||||
cardConfig?: LovelaceCardConfig;
|
||||
viewId?: string | number;
|
||||
add: boolean;
|
||||
reloadLovelace: () => void;
|
||||
lovelace: Lovelace;
|
||||
path: [number] | [number, number];
|
||||
}
|
||||
|
||||
const registerEditCardDialog = (element: HTMLElement) =>
|
@ -33,7 +33,6 @@ const entitiesConfigStruct = struct.union([
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
id: "string|number",
|
||||
title: "string|number?",
|
||||
theme: "string?",
|
||||
show_header_toggle: "boolean?",
|
||||
|
@ -32,7 +32,6 @@ const entitiesConfigStruct = struct.union([
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
id: "string|number",
|
||||
title: "string|number?",
|
||||
theme: "string?",
|
||||
columns: "number?",
|
||||
@ -93,6 +92,7 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
></hui-theme-select-editor>
|
||||
<paper-input
|
||||
label="Columns"
|
||||
type="number"
|
||||
value="${this._columns}"
|
||||
.configValue="${"columns"}"
|
||||
@value-changed="${this._valueChanged}"
|
||||
@ -127,22 +127,21 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
const target = ev.target! as EditorTarget;
|
||||
|
||||
if (
|
||||
(target.configValue! === "title" && target.value === this._title) ||
|
||||
(target.configValue! === "theme" && target.value === this._theme) ||
|
||||
(target.configValue! === "columns" && target.value === this._columns)
|
||||
) {
|
||||
if (this[`_${target.configValue}`] === target.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.detail && ev.detail.entities) {
|
||||
this._config.entities = ev.detail.entities;
|
||||
this._configEntities = processEditorEntities(this._config.entities);
|
||||
} else if (target.configValue) {
|
||||
let value: any = target.value;
|
||||
if (target.type === "number") {
|
||||
value = Number(value);
|
||||
}
|
||||
this._config = {
|
||||
...this._config,
|
||||
[target.configValue!]:
|
||||
target.checked !== undefined ? target.checked : target.value,
|
||||
target.checked !== undefined ? target.checked : value,
|
||||
};
|
||||
}
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
|
149
src/panels/lovelace/editor/config-util.ts
Normal file
149
src/panels/lovelace/editor/config-util.ts
Normal file
@ -0,0 +1,149 @@
|
||||
import {
|
||||
LovelaceConfig,
|
||||
LovelaceCardConfig,
|
||||
LovelaceViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
|
||||
export const addCard = (
|
||||
config: LovelaceConfig,
|
||||
path: [number],
|
||||
cardConfig: LovelaceCardConfig
|
||||
): LovelaceConfig => {
|
||||
const [viewIndex] = path;
|
||||
const views: LovelaceViewConfig[] = [];
|
||||
|
||||
config.views.forEach((viewConf, index) => {
|
||||
if (index !== viewIndex) {
|
||||
views.push(config.views[index]);
|
||||
return;
|
||||
}
|
||||
|
||||
const cards = viewConf.cards
|
||||
? [...viewConf.cards, cardConfig]
|
||||
: [cardConfig];
|
||||
|
||||
views.push({
|
||||
...viewConf,
|
||||
cards,
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
...config,
|
||||
views,
|
||||
};
|
||||
};
|
||||
|
||||
export const replaceCard = (
|
||||
config: LovelaceConfig,
|
||||
path: [number, number],
|
||||
cardConfig: LovelaceCardConfig
|
||||
): LovelaceConfig => {
|
||||
const [viewIndex, cardIndex] = path;
|
||||
const views: LovelaceViewConfig[] = [];
|
||||
|
||||
config.views.forEach((viewConf, index) => {
|
||||
if (index !== viewIndex) {
|
||||
views.push(config.views[index]);
|
||||
return;
|
||||
}
|
||||
|
||||
views.push({
|
||||
...viewConf,
|
||||
cards: (viewConf.cards || []).map((origConf, ind) =>
|
||||
ind === cardIndex ? cardConfig : origConf
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
...config,
|
||||
views,
|
||||
};
|
||||
};
|
||||
|
||||
export const deleteCard = (
|
||||
config: LovelaceConfig,
|
||||
path: [number, number]
|
||||
): LovelaceConfig => {
|
||||
const [viewIndex, cardIndex] = path;
|
||||
const views: LovelaceViewConfig[] = [];
|
||||
|
||||
config.views.forEach((viewConf, index) => {
|
||||
if (index !== viewIndex) {
|
||||
views.push(config.views[index]);
|
||||
return;
|
||||
}
|
||||
|
||||
views.push({
|
||||
...viewConf,
|
||||
cards: (viewConf.cards || []).filter(
|
||||
(_origConf, ind) => ind !== cardIndex
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
...config,
|
||||
views,
|
||||
};
|
||||
};
|
||||
|
||||
export const swapCard = (
|
||||
config: LovelaceConfig,
|
||||
path1: [number, number],
|
||||
path2: [number, number]
|
||||
): LovelaceConfig => {
|
||||
const card1 = config.views[path1[0]].cards![path1[1]];
|
||||
const card2 = config.views[path2[0]].cards![path2[1]];
|
||||
|
||||
const origView1 = config.views[path1[0]];
|
||||
const newView1 = {
|
||||
...origView1,
|
||||
cards: origView1.cards!.map((origCard, index) =>
|
||||
index === path1[1] ? card2 : origCard
|
||||
),
|
||||
};
|
||||
|
||||
const origView2 = path1[0] === path2[0] ? newView1 : config.views[path2[0]];
|
||||
const newView2 = {
|
||||
...origView2,
|
||||
cards: origView2.cards!.map((origCard, index) =>
|
||||
index === path2[1] ? card1 : origCard
|
||||
),
|
||||
};
|
||||
|
||||
return {
|
||||
...config,
|
||||
views: config.views.map((origView, index) =>
|
||||
index === path2[0] ? newView2 : index === path1[0] ? newView1 : origView
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
export const addView = (
|
||||
config: LovelaceConfig,
|
||||
viewConfig: LovelaceViewConfig
|
||||
): LovelaceConfig => ({
|
||||
...config,
|
||||
views: config.views.concat(viewConfig),
|
||||
});
|
||||
|
||||
export const replaceView = (
|
||||
config: LovelaceConfig,
|
||||
viewIndex: number,
|
||||
viewConfig: LovelaceViewConfig
|
||||
): LovelaceConfig => ({
|
||||
...config,
|
||||
views: config.views.map((origView, index) =>
|
||||
index === viewIndex ? viewConfig : origView
|
||||
),
|
||||
});
|
||||
|
||||
export const deleteView = (
|
||||
config: LovelaceConfig,
|
||||
viewIndex: number
|
||||
): LovelaceConfig => ({
|
||||
...config,
|
||||
views: config.views.filter((_origView, index) => index !== viewIndex),
|
||||
});
|
@ -1,17 +1,15 @@
|
||||
import { deleteCard } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { Lovelace } from "../types";
|
||||
import { deleteCard } from "./config-util";
|
||||
|
||||
export async function confDeleteCard(
|
||||
hass: HomeAssistant,
|
||||
cardId: string,
|
||||
reloadLovelace: () => void
|
||||
lovelace: Lovelace,
|
||||
path: [number, number]
|
||||
): Promise<void> {
|
||||
if (!confirm("Are you sure you want to delete this card?")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await deleteCard(hass, String(cardId));
|
||||
reloadLovelace();
|
||||
await lovelace.saveConfig(deleteCard(lovelace.config, path));
|
||||
} catch (err) {
|
||||
alert(`Deleting failed: ${err.message}`);
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
import { deleteView } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export async function confDeleteView(
|
||||
hass: HomeAssistant,
|
||||
viewId: string,
|
||||
reloadLovelace: () => void
|
||||
): Promise<void> {
|
||||
if (!confirm("Are you sure you want to delete this view?")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await deleteView(hass, String(viewId));
|
||||
reloadLovelace();
|
||||
} catch (err) {
|
||||
alert(`Deleting failed: ${err.message}`);
|
||||
}
|
||||
}
|
@ -10,40 +10,8 @@ import "@polymer/paper-button/paper-button";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
import {
|
||||
saveConfig,
|
||||
migrateConfig,
|
||||
LovelaceConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"show-save-config": SaveDialogParams;
|
||||
}
|
||||
}
|
||||
|
||||
const dialogShowEvent = "show-save-config";
|
||||
const dialogTag = "hui-dialog-save-config";
|
||||
|
||||
export interface SaveDialogParams {
|
||||
config: LovelaceConfig;
|
||||
reloadLovelace: () => void;
|
||||
}
|
||||
|
||||
export const registerSaveDialog = (element: HTMLElement) =>
|
||||
fireEvent(element, "register-dialog", {
|
||||
dialogShowEvent,
|
||||
dialogTag,
|
||||
dialogImport: () => import("./hui-dialog-save-config"),
|
||||
});
|
||||
|
||||
export const showSaveDialog = (
|
||||
element: HTMLElement,
|
||||
saveDialogParams: SaveDialogParams
|
||||
) => fireEvent(element, dialogShowEvent, saveDialogParams);
|
||||
import { SaveDialogParams } from "./show-save-config-dialog";
|
||||
|
||||
export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
||||
protected hass?: HomeAssistant;
|
||||
@ -137,13 +105,11 @@ export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
this._saving = true;
|
||||
delete this._params.config._frontendAuto;
|
||||
try {
|
||||
await saveConfig(this.hass, this._params.config, "json");
|
||||
await migrateConfig(this.hass);
|
||||
const lovelace = this._params!.lovelace;
|
||||
await lovelace.saveConfig(lovelace.config);
|
||||
this._saving = false;
|
||||
this._closeDialog();
|
||||
this._params.reloadLovelace!();
|
||||
} catch (err) {
|
||||
alert(`Saving failed: ${err.message}`);
|
||||
this._saving = false;
|
||||
@ -157,4 +123,4 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(dialogTag, HuiSaveConfig);
|
||||
customElements.define("hui-dialog-save-config", HuiSaveConfig);
|
||||
|
@ -1,113 +0,0 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
// tslint:disable-next-line
|
||||
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { migrateConfig } from "../../../data/lovelace";
|
||||
|
||||
export class HuiMigrateConfig extends hassLocalizeLitMixin(LitElement) {
|
||||
protected hass?: HomeAssistant;
|
||||
private _migrating?: boolean;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return { _hass: {}, _migrating: {} };
|
||||
}
|
||||
|
||||
private get _dialog(): PaperDialogElement {
|
||||
return this.shadowRoot!.querySelector("paper-dialog")!;
|
||||
}
|
||||
|
||||
public async showDialog(): Promise<void> {
|
||||
// Wait till dialog is rendered.
|
||||
if (this._dialog == null) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
this._dialog.open();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<paper-dialog with-backdrop>
|
||||
<h2>${this.localize("ui.panel.lovelace.editor.migrate.header")}</h2>
|
||||
<paper-dialog-scrollable>
|
||||
<p>${this.localize("ui.panel.lovelace.editor.migrate.para_no_id")}</p>
|
||||
<p>
|
||||
${this.localize("ui.panel.lovelace.editor.migrate.para_migrate")}
|
||||
</p>
|
||||
</paper-dialog-scrollable>
|
||||
<div class="paper-dialog-buttons">
|
||||
<paper-button @click="${this._closeDialog}"
|
||||
>${this.localize("ui.common.cancel")}</paper-button
|
||||
>
|
||||
<paper-button
|
||||
?disabled="${this._migrating}"
|
||||
@click="${this._migrateConfig}"
|
||||
>
|
||||
<paper-spinner
|
||||
?active="${this._migrating}"
|
||||
alt="Saving"
|
||||
></paper-spinner>
|
||||
${
|
||||
this.localize("ui.panel.lovelace.editor.migrate.migrate")
|
||||
}</paper-button
|
||||
>
|
||||
</div>
|
||||
</paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
return html`
|
||||
<style>
|
||||
paper-dialog {
|
||||
width: 650px;
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
}
|
||||
paper-spinner[active] {
|
||||
display: block;
|
||||
}
|
||||
paper-button paper-spinner {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
||||
private _closeDialog(): void {
|
||||
this._dialog.close();
|
||||
}
|
||||
|
||||
private async _migrateConfig(): Promise<void> {
|
||||
this._migrating = true;
|
||||
try {
|
||||
await migrateConfig(this.hass!);
|
||||
this._closeDialog();
|
||||
this._migrating = false;
|
||||
fireEvent(this, "reload-lovelace");
|
||||
} catch (err) {
|
||||
alert(`Migration failed: ${err.message}`);
|
||||
this._migrating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-migrate-config": HuiMigrateConfig;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("hui-migrate-config", HuiMigrateConfig);
|
33
src/panels/lovelace/editor/show-save-config-dialog.ts
Normal file
33
src/panels/lovelace/editor/show-save-config-dialog.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { Lovelace } from "../types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"show-save-config": SaveDialogParams;
|
||||
}
|
||||
}
|
||||
|
||||
const dialogShowEvent = "show-save-config";
|
||||
const dialogTag = "hui-dialog-save-config";
|
||||
|
||||
export interface SaveDialogParams {
|
||||
lovelace: Lovelace;
|
||||
}
|
||||
|
||||
let registeredDialog = false;
|
||||
|
||||
export const showSaveDialog = (
|
||||
element: HTMLElement,
|
||||
saveDialogParams: SaveDialogParams
|
||||
) => {
|
||||
if (!registeredDialog) {
|
||||
registeredDialog = true;
|
||||
fireEvent(element, "register-dialog", {
|
||||
dialogShowEvent,
|
||||
dialogTag,
|
||||
dialogImport: () => import("./hui-dialog-save-config"),
|
||||
});
|
||||
}
|
||||
fireEvent(element, dialogShowEvent, saveDialogParams);
|
||||
};
|
@ -1,5 +1,6 @@
|
||||
import { LovelaceCardConfig, LovelaceViewConfig } from "../../../data/lovelace";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { InputType } from "zlib";
|
||||
|
||||
export interface YamlChangedEvent extends Event {
|
||||
detail: {
|
||||
@ -7,12 +8,6 @@ export interface YamlChangedEvent extends Event {
|
||||
};
|
||||
}
|
||||
|
||||
export interface CardPickedEvent extends Event {
|
||||
detail: {
|
||||
config: LovelaceCardConfig;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ViewEditEvent extends Event {
|
||||
detail: {
|
||||
config: LovelaceViewConfig;
|
||||
@ -41,6 +36,7 @@ export interface EditorTarget extends EventTarget {
|
||||
index?: number;
|
||||
checked?: boolean;
|
||||
configValue?: string;
|
||||
type?: InputType;
|
||||
}
|
||||
|
||||
export interface CardPickTarget extends EventTarget {
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import "./hui-edit-view";
|
||||
import "./hui-migrate-config";
|
||||
import { EditViewDialogParams } from "./show-edit-view-dialog";
|
||||
|
||||
declare global {
|
||||
@ -39,24 +38,11 @@ export class HuiDialogEditView extends LitElement {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
if (
|
||||
!this._params.add &&
|
||||
this._params.viewConfig &&
|
||||
!("id" in this._params.viewConfig)
|
||||
) {
|
||||
return html`
|
||||
<hui-migrate-config
|
||||
.hass="${this.hass}"
|
||||
@reload-lovelace="${this._params.reloadLovelace}"
|
||||
></hui-migrate-config>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<hui-edit-view
|
||||
.hass="${this.hass}"
|
||||
.viewConfig="${this._params.viewConfig}"
|
||||
.add="${this._params.add}"
|
||||
.reloadLovelace="${this._params.reloadLovelace}"
|
||||
.lovelace="${this._params.lovelace}"
|
||||
.viewIndex="${this._params.viewIndex}"
|
||||
>
|
||||
</hui-edit-view>
|
||||
`;
|
@ -1,9 +1,4 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
@ -11,53 +6,51 @@ import "@polymer/paper-tabs/paper-tab";
|
||||
import "@polymer/paper-tabs/paper-tabs";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-icon-button/paper-icon-button.js";
|
||||
import "@polymer/paper-item/paper-item.js";
|
||||
import "@polymer/paper-listbox/paper-listbox.js";
|
||||
import "@polymer/paper-menu-button/paper-menu-button.js";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
// tslint:disable-next-line
|
||||
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import "../components/hui-entity-editor";
|
||||
import "./config-elements/hui-view-editor";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "./hui-view-editor";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import {
|
||||
addView,
|
||||
updateViewConfig,
|
||||
LovelaceViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { EntitiesEditorEvent, ViewEditEvent } from "./types";
|
||||
import { processEditorEntities } from "./process-editor-entities";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { confDeleteView } from "./delete-view";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
LovelaceCardConfig,
|
||||
} from "../../../../data/lovelace";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
|
||||
import { EntitiesEditorEvent, ViewEditEvent } from "../types";
|
||||
import { processEditorEntities } from "../process-editor-entities";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
import { navigate } from "../../../../common/navigate";
|
||||
import { Lovelace } from "../../types";
|
||||
import { deleteView, addView, replaceView } from "../config-util";
|
||||
|
||||
export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
public lovelace?: Lovelace;
|
||||
public viewIndex?: number;
|
||||
protected hass?: HomeAssistant;
|
||||
private _config?: LovelaceViewConfig;
|
||||
private _badges?: EntityConfig[];
|
||||
private _cards?: LovelaceCardConfig[];
|
||||
private _saving: boolean;
|
||||
private _curTabIndex: number;
|
||||
private _curTab?: string;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
viewConfig: {},
|
||||
add: {},
|
||||
lovelace: {},
|
||||
viewIndex: {},
|
||||
_config: {},
|
||||
_badges: {},
|
||||
_cards: {},
|
||||
_saving: {},
|
||||
_curTab: {},
|
||||
};
|
||||
}
|
||||
|
||||
public viewConfig?: LovelaceViewConfig;
|
||||
public add?: boolean;
|
||||
public reloadLovelace?: () => {};
|
||||
protected hass?: HomeAssistant;
|
||||
private _config?: LovelaceViewConfig;
|
||||
private _badges?: EntityConfig[];
|
||||
private _saving: boolean;
|
||||
private _curTabIndex: number;
|
||||
private _curTab?: string;
|
||||
|
||||
protected constructor() {
|
||||
super();
|
||||
this._saving = false;
|
||||
@ -69,28 +62,21 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
if (this._dialog == null) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
this._dialog.open();
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
super.updated(changedProperties);
|
||||
if (!changedProperties.has("viewConfig") && !changedProperties.has("add")) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
this.viewConfig &&
|
||||
(!changedProperties.get("viewConfig") ||
|
||||
this.viewConfig.id !==
|
||||
(changedProperties.get("viewConfig") as LovelaceViewConfig).id)
|
||||
) {
|
||||
const { cards, badges, ...viewConfig } = this.viewConfig;
|
||||
this._config = viewConfig;
|
||||
this._badges = badges ? processEditorEntities(badges) : [];
|
||||
} else if (changedProperties.has("add")) {
|
||||
if (this.viewIndex === undefined) {
|
||||
this._config = {};
|
||||
this._badges = [];
|
||||
this._cards = [];
|
||||
} else {
|
||||
const { cards, badges, ...viewConfig } = this.lovelace!.config.views[
|
||||
this.viewIndex
|
||||
];
|
||||
this._config = viewConfig;
|
||||
this._badges = badges ? processEditorEntities(badges) : [];
|
||||
this._cards = cards;
|
||||
}
|
||||
this._resizeDialog();
|
||||
|
||||
this._dialog.open();
|
||||
}
|
||||
|
||||
private get _dialog(): PaperDialogElement {
|
||||
@ -139,6 +125,18 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
</paper-tabs>
|
||||
<paper-dialog-scrollable> ${content} </paper-dialog-scrollable>
|
||||
<div class="paper-dialog-buttons">
|
||||
${
|
||||
this.viewIndex !== undefined
|
||||
? html`
|
||||
<paper-icon-button
|
||||
class="delete"
|
||||
title="Delete"
|
||||
icon="hass:delete"
|
||||
@click="${this._delete}"
|
||||
></paper-icon-button>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<paper-button @click="${this._closeDialog}"
|
||||
>${this.localize("ui.common.cancel")}</paper-button
|
||||
>
|
||||
@ -152,15 +150,6 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
></paper-spinner>
|
||||
${this.localize("ui.common.save")}</paper-button
|
||||
>
|
||||
<paper-menu-button no-animations>
|
||||
<paper-icon-button
|
||||
icon="hass:dots-vertical"
|
||||
slot="dropdown-trigger"
|
||||
></paper-icon-button>
|
||||
<paper-listbox slot="dropdown-content">
|
||||
<paper-item @click="${this._delete}">Delete</paper-item>
|
||||
</paper-listbox>
|
||||
</paper-menu-button>
|
||||
</div>
|
||||
</paper-dialog>
|
||||
`;
|
||||
@ -182,6 +171,10 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
height: 14px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
paper-icon-button.delete {
|
||||
margin-right: auto;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
paper-spinner {
|
||||
display: none;
|
||||
}
|
||||
@ -199,23 +192,27 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
private _save(): void {
|
||||
this._saving = true;
|
||||
this._updateConfigInBackend();
|
||||
}
|
||||
|
||||
private _delete() {
|
||||
if (this._config!.cards && this._config!.cards!.length > 0) {
|
||||
private async _delete() {
|
||||
if (this._cards && this._cards.length > 0) {
|
||||
alert(
|
||||
"You can't delete a view that has card in them. Remove the cards first."
|
||||
"You can't delete a view that has cards in it. Remove the cards first."
|
||||
);
|
||||
return;
|
||||
}
|
||||
confDeleteView(this.hass!, this._config!.id!, () => {
|
||||
|
||||
if (!confirm("Are you sure you want to delete this view?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.lovelace!.saveConfig(
|
||||
deleteView(this.lovelace!.config, this.viewIndex!)
|
||||
);
|
||||
this._closeDialog();
|
||||
this.reloadLovelace!();
|
||||
navigate(this, `/lovelace/0`);
|
||||
});
|
||||
} catch (err) {
|
||||
alert(`Deleting failed: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async _resizeDialog(): Promise<void> {
|
||||
@ -225,9 +222,9 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
|
||||
private _closeDialog(): void {
|
||||
this._curTabIndex = 0;
|
||||
this.lovelace = undefined;
|
||||
this._config = {};
|
||||
this._badges = [];
|
||||
this.viewConfig = undefined;
|
||||
this._dialog.close();
|
||||
}
|
||||
|
||||
@ -239,39 +236,35 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
this._resizeDialog();
|
||||
}
|
||||
|
||||
private async _updateConfigInBackend(): Promise<void> {
|
||||
private async _save(): Promise<void> {
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
if (!this._isConfigChanged()) {
|
||||
this._closeDialog();
|
||||
this._saving = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._badges) {
|
||||
this._config.badges = this._badges.map((entityConf) => {
|
||||
return entityConf.entity;
|
||||
});
|
||||
}
|
||||
this._saving = true;
|
||||
|
||||
const viewConf: LovelaceViewConfig = {
|
||||
cards: this._cards,
|
||||
badges: this._badges!.map((entityConf) => entityConf.entity),
|
||||
...this._config,
|
||||
};
|
||||
|
||||
const lovelace = this.lovelace!;
|
||||
|
||||
try {
|
||||
if (this.add) {
|
||||
this._config.cards = [];
|
||||
await addView(this.hass!, this._config, "json");
|
||||
} else {
|
||||
await updateViewConfig(
|
||||
this.hass!,
|
||||
String(this.viewConfig!.id!),
|
||||
this._config,
|
||||
"json"
|
||||
);
|
||||
}
|
||||
this.reloadLovelace!();
|
||||
await lovelace.saveConfig(
|
||||
this._creatingView
|
||||
? addView(lovelace.config, viewConf)
|
||||
: replaceView(lovelace.config, this.viewIndex!, viewConf)
|
||||
);
|
||||
this._closeDialog();
|
||||
this._saving = false;
|
||||
} catch (err) {
|
||||
alert(`Saving failed: ${err.message}`);
|
||||
} finally {
|
||||
this._saving = false;
|
||||
}
|
||||
}
|
||||
@ -290,10 +283,15 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _isConfigChanged(): boolean {
|
||||
if (!this.add) {
|
||||
return true;
|
||||
}
|
||||
return JSON.stringify(this._config) !== JSON.stringify(this.viewConfig);
|
||||
return (
|
||||
this._creatingView ||
|
||||
JSON.stringify(this._config) !==
|
||||
JSON.stringify(this.lovelace!.config.views[this.viewIndex!])
|
||||
);
|
||||
}
|
||||
|
||||
private get _creatingView(): boolean {
|
||||
return this.viewIndex === undefined;
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { EditorTarget } from "../types";
|
||||
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { configElementStyle } from "../config-elements/config-elements-style";
|
||||
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceViewConfig } from "../../../../data/lovelace";
|
||||
@ -24,12 +24,11 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
return { hass: {}, _config: {} };
|
||||
}
|
||||
|
||||
get _id(): string {
|
||||
get _path(): string {
|
||||
if (!this._config) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return "id" in this._config ? this._config.id! : "";
|
||||
return this._config.path || "";
|
||||
}
|
||||
|
||||
get _title(): string {
|
||||
@ -68,12 +67,6 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
return html`
|
||||
${configElementStyle}
|
||||
<div class="card-config">
|
||||
<paper-input
|
||||
label="ID"
|
||||
value="${this._id}"
|
||||
.configValue="${"id"}"
|
||||
@value-changed="${this._valueChanged}"
|
||||
></paper-input>
|
||||
<paper-input
|
||||
label="Title"
|
||||
value="${this._title}"
|
||||
@ -86,6 +79,12 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
.configValue="${"icon"}"
|
||||
@value-changed="${this._valueChanged}"
|
||||
></paper-input>
|
||||
<paper-input
|
||||
label="URL Path"
|
||||
value="${this._path}"
|
||||
.configValue="${"path"}"
|
||||
@value-changed="${this._valueChanged}"
|
||||
></paper-input>
|
||||
<hui-theme-select-editor
|
||||
.hass="${this.hass}"
|
||||
.value="${this._theme}"
|
@ -1,5 +1,5 @@
|
||||
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceViewConfig } from "../../../data/lovelace";
|
||||
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Lovelace } from "../../types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@ -18,9 +18,8 @@ const dialogShowEvent = "show-edit-view";
|
||||
const dialogTag = "hui-dialog-edit-view";
|
||||
|
||||
export interface EditViewDialogParams {
|
||||
viewConfig?: LovelaceViewConfig;
|
||||
add?: boolean;
|
||||
reloadLovelace: () => void;
|
||||
lovelace: Lovelace;
|
||||
viewIndex?: number;
|
||||
}
|
||||
|
||||
const registerEditViewDialog = (element: HTMLElement) =>
|
@ -1,154 +0,0 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
|
||||
import { registerSaveDialog } from "./editor/hui-dialog-save-config";
|
||||
import { fetchConfig } from "../../data/lovelace";
|
||||
import "../../layouts/hass-loading-screen";
|
||||
import "../../layouts/hass-error-screen";
|
||||
import "./hui-root";
|
||||
import localizeMixin from "../../mixins/localize-mixin";
|
||||
|
||||
let registeredDialog = false;
|
||||
|
||||
class Lovelace extends localizeMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
paper-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
<template is="dom-if" if="[[_equal(_state, "loaded")]]" restamp>
|
||||
<hui-root
|
||||
narrow="[[narrow]]"
|
||||
show-menu="[[showMenu]]"
|
||||
hass="[[hass]]"
|
||||
route="[[route]]"
|
||||
config="[[_config]]"
|
||||
columns="[[_columns]]"
|
||||
on-config-refresh="_forceFetchConfig"
|
||||
></hui-root>
|
||||
</template>
|
||||
<template
|
||||
is="dom-if"
|
||||
if="[[_equal(_state, "loading")]]"
|
||||
restamp
|
||||
>
|
||||
<hass-loading-screen
|
||||
narrow="[[narrow]]"
|
||||
show-menu="[[showMenu]]"
|
||||
></hass-loading-screen>
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equal(_state, "error")]]" restamp>
|
||||
<hass-error-screen
|
||||
title="Lovelace"
|
||||
error="[[_errorMsg]]"
|
||||
narrow="[[narrow]]"
|
||||
show-menu="[[showMenu]]"
|
||||
>
|
||||
<paper-button on-click="_forceFetchConfig"
|
||||
>Reload ui-lovelace.yaml</paper-button
|
||||
>
|
||||
</hass-error-screen>
|
||||
</template>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
|
||||
narrow: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
showMenu: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
route: Object,
|
||||
|
||||
_columns: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
},
|
||||
|
||||
_state: {
|
||||
type: String,
|
||||
value: "loading",
|
||||
},
|
||||
|
||||
_errorMsg: String,
|
||||
|
||||
_config: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static get observers() {
|
||||
return ["_updateColumns(narrow, showMenu)"];
|
||||
}
|
||||
|
||||
ready() {
|
||||
this._fetchConfig(false);
|
||||
this._updateColumns = this._updateColumns.bind(this);
|
||||
this.mqls = [300, 600, 900, 1200].map((width) => {
|
||||
const mql = matchMedia(`(min-width: ${width}px)`);
|
||||
mql.addListener(this._updateColumns);
|
||||
return mql;
|
||||
});
|
||||
this._updateColumns();
|
||||
super.ready();
|
||||
}
|
||||
|
||||
_updateColumns() {
|
||||
const matchColumns = this.mqls.reduce((cols, mql) => cols + mql.matches, 0);
|
||||
// Do -1 column if the menu is docked and open
|
||||
this._columns = Math.max(1, matchColumns - (!this.narrow && this.showMenu));
|
||||
}
|
||||
|
||||
_forceFetchConfig() {
|
||||
this._fetchConfig(true);
|
||||
}
|
||||
|
||||
async _fetchConfig(force) {
|
||||
try {
|
||||
const conf = await fetchConfig(this.hass, force);
|
||||
this.setProperties({
|
||||
_config: conf,
|
||||
_state: "loaded",
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code === "file_not_found") {
|
||||
const {
|
||||
generateLovelaceConfig,
|
||||
} = await import("./common/generate-lovelace-config");
|
||||
this.setProperties({
|
||||
_config: generateLovelaceConfig(this.hass, this.localize),
|
||||
_state: "loaded",
|
||||
});
|
||||
if (!registeredDialog) {
|
||||
registeredDialog = true;
|
||||
registerSaveDialog(this);
|
||||
}
|
||||
} else {
|
||||
this.setProperties({
|
||||
_state: "error",
|
||||
_errorMsg: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_equal(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-panel-lovelace", Lovelace);
|
185
src/panels/lovelace/ha-panel-lovelace.ts
Normal file
185
src/panels/lovelace/ha-panel-lovelace.ts
Normal file
@ -0,0 +1,185 @@
|
||||
import "@polymer/paper-button/paper-button";
|
||||
|
||||
import { fetchConfig, LovelaceConfig, saveConfig } from "../../data/lovelace";
|
||||
import "../../layouts/hass-loading-screen";
|
||||
import "../../layouts/hass-error-screen";
|
||||
import "./hui-root";
|
||||
import { HomeAssistant, PanelInfo } from "../../types";
|
||||
import { Lovelace } from "./types";
|
||||
import { LitElement, html, PropertyValues } from "@polymer/lit-element";
|
||||
import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||
|
||||
interface LovelacePanelConfig {
|
||||
mode: "yaml" | "storage";
|
||||
}
|
||||
|
||||
class LovelacePanel extends hassLocalizeLitMixin(LitElement) {
|
||||
public panel?: PanelInfo<LovelacePanelConfig>;
|
||||
public hass?: HomeAssistant;
|
||||
public narrow?: boolean;
|
||||
public showMenu?: boolean;
|
||||
public route?: object;
|
||||
private _columns?: number;
|
||||
private _state?: "loading" | "loaded" | "error";
|
||||
private _errorMsg?: string;
|
||||
private lovelace?: Lovelace;
|
||||
private mqls?: MediaQueryList[];
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {},
|
||||
lovelace: {},
|
||||
narrow: { type: Boolean, value: false },
|
||||
showMenu: { type: Boolean, value: false },
|
||||
route: {},
|
||||
_columns: { type: Number, value: 1 },
|
||||
_state: { type: String, value: "loading" },
|
||||
_errorMsg: String,
|
||||
_config: { type: {}, value: null },
|
||||
};
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
const state = this._state!;
|
||||
|
||||
if (state === "loaded") {
|
||||
return html`
|
||||
<hui-root
|
||||
.narrow="${this.narrow}"
|
||||
.showMenu="${this.showMenu}"
|
||||
.hass="${this.hass}"
|
||||
.lovelace="${this.lovelace}"
|
||||
.route="${this.route}"
|
||||
.columns="${this._columns}"
|
||||
@config-refresh="${this._forceFetchConfig}"
|
||||
></hui-root>
|
||||
`;
|
||||
}
|
||||
|
||||
if (state === "error") {
|
||||
return html`
|
||||
<style>
|
||||
paper-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
<hass-error-screen
|
||||
title="Lovelace"
|
||||
.error="${this._errorMsg}"
|
||||
.narrow="${this.narrow}"
|
||||
.showMenu="${this.showMenu}"
|
||||
>
|
||||
<paper-button on-click="_forceFetchConfig"
|
||||
>Reload ui-lovelace.yaml</paper-button
|
||||
>
|
||||
</hass-error-screen>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hass-loading-screen
|
||||
.narrow="${this.narrow}"
|
||||
.showMenu="${this.showMenu}"
|
||||
></hass-loading-screen>
|
||||
`;
|
||||
}
|
||||
|
||||
public updated(changedProps: PropertyValues): void {
|
||||
if (changedProps.has("narrow") || changedProps.has("showMenu")) {
|
||||
this._updateColumns();
|
||||
}
|
||||
}
|
||||
|
||||
public firstUpdated() {
|
||||
this._fetchConfig(false);
|
||||
this._updateColumns = this._updateColumns.bind(this);
|
||||
this.mqls = [300, 600, 900, 1200].map((width) => {
|
||||
const mql = matchMedia(`(min-width: ${width}px)`);
|
||||
mql.addListener(this._updateColumns);
|
||||
return mql;
|
||||
});
|
||||
this._updateColumns();
|
||||
}
|
||||
|
||||
private _updateColumns() {
|
||||
const matchColumns = this.mqls!.reduce(
|
||||
(cols, mql) => cols + Number(mql.matches),
|
||||
0
|
||||
);
|
||||
// Do -1 column if the menu is docked and open
|
||||
this._columns = Math.max(
|
||||
1,
|
||||
matchColumns - Number(!this.narrow && this.showMenu)
|
||||
);
|
||||
}
|
||||
|
||||
private _forceFetchConfig() {
|
||||
this._fetchConfig(true);
|
||||
}
|
||||
|
||||
private async _fetchConfig(force) {
|
||||
let conf;
|
||||
let gen: boolean;
|
||||
|
||||
try {
|
||||
conf = await fetchConfig(this.hass!, force);
|
||||
gen = false;
|
||||
} catch (err) {
|
||||
if (err.code !== "config_not_found") {
|
||||
// tslint:disable-next-line
|
||||
console.log(err);
|
||||
this._state = "error";
|
||||
this._errorMsg = err.message;
|
||||
return;
|
||||
}
|
||||
const {
|
||||
generateLovelaceConfig,
|
||||
} = await import("./common/generate-lovelace-config");
|
||||
conf = generateLovelaceConfig(this.hass!, this.localize);
|
||||
gen = true;
|
||||
}
|
||||
|
||||
this._state = "loaded";
|
||||
this.lovelace = {
|
||||
config: conf,
|
||||
autoGen: gen,
|
||||
editMode: this.lovelace ? this.lovelace.editMode : false,
|
||||
mode: this.panel!.config.mode,
|
||||
setEditMode: (editMode: boolean) => {
|
||||
if (!editMode || !this.lovelace!.autoGen) {
|
||||
this._updateLovelace({ editMode });
|
||||
return;
|
||||
}
|
||||
showSaveDialog(this, {
|
||||
lovelace: this.lovelace!,
|
||||
});
|
||||
},
|
||||
saveConfig: async (newConfig: LovelaceConfig): Promise<void> => {
|
||||
const { config, autoGen } = this.lovelace!;
|
||||
try {
|
||||
// Optimistic update
|
||||
this._updateLovelace({ config: newConfig, autoGen: false });
|
||||
await saveConfig(this.hass!, newConfig);
|
||||
} catch (err) {
|
||||
// tslint:disable-next-line
|
||||
console.error(err);
|
||||
// Rollback the optimistic update
|
||||
this._updateLovelace({ config, autoGen });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private _updateLovelace(props: Partial<Lovelace>) {
|
||||
this.lovelace = {
|
||||
...this.lovelace!,
|
||||
...props,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-panel-lovelace", LovelacePanel);
|
@ -32,8 +32,7 @@ import "./hui-unused-entities";
|
||||
import "./hui-view";
|
||||
import debounce from "../../common/util/debounce";
|
||||
import createCardElement from "./common/create-card-element";
|
||||
import { showSaveDialog } from "./editor/hui-dialog-save-config";
|
||||
import { showEditViewDialog } from "./editor/show-edit-view-dialog";
|
||||
import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
|
||||
|
||||
// CSS and JS should only be imported once. Modules and HTML are safe.
|
||||
const CSS_CACHE = {};
|
||||
@ -59,20 +58,28 @@ class HUIRoot extends NavigateMixin(
|
||||
--paper-tabs-selection-bar-color: var(--text-primary-color, #FFF);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
paper-tab.iron-selected .edit-view-icon{
|
||||
display: inline-flex;
|
||||
}
|
||||
.edit-view-icon {
|
||||
padding-left: 8px;
|
||||
display: none;
|
||||
}
|
||||
#add-view {
|
||||
position: absolute;
|
||||
height: 44px;
|
||||
}
|
||||
#add-view ha-icon {
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 5px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
app-toolbar a {
|
||||
color: var(--text-primary-color, white);
|
||||
}
|
||||
paper-button.warning:not([disabled]) {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
#add-view ha-icon {
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
#view {
|
||||
min-height: calc(100vh - 112px);
|
||||
/**
|
||||
@ -90,9 +97,6 @@ class HUIRoot extends NavigateMixin(
|
||||
paper-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
.edit-view-icon {
|
||||
padding-left: 8px;
|
||||
}
|
||||
</style>
|
||||
<app-route route="[[route]]" pattern="/:view" data="{{routeData}}"></app-route>
|
||||
<hui-notification-drawer
|
||||
@ -148,7 +152,7 @@ class HUIRoot extends NavigateMixin(
|
||||
<template is="dom-if" if="[[!item.icon]]">
|
||||
[[_computeTabTitle(item.title)]]
|
||||
</template>
|
||||
<template is='dom-if' if="[[_computeEditVisible(_editMode, config.views)]]">
|
||||
<template is='dom-if' if="[[_editMode]]">
|
||||
<ha-icon class="edit-view-icon" on-click="_editView" icon="hass:pencil"></ha-icon>
|
||||
</template>
|
||||
</paper-tab>
|
||||
@ -176,8 +180,12 @@ class HUIRoot extends NavigateMixin(
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
computed: "_computeConfig(lovelace)",
|
||||
observer: "_configChanged",
|
||||
},
|
||||
lovelace: {
|
||||
type: Object,
|
||||
},
|
||||
columns: {
|
||||
type: Number,
|
||||
observer: "_columnsChanged",
|
||||
@ -211,6 +219,7 @@ class HUIRoot extends NavigateMixin(
|
||||
_editMode: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
computed: "_computeEditMode(lovelace)",
|
||||
observer: "_editModeChanged",
|
||||
},
|
||||
|
||||
@ -253,12 +262,12 @@ class HUIRoot extends NavigateMixin(
|
||||
_routeChanged(route) {
|
||||
const views = this.config && this.config.views;
|
||||
if (route.path === "" && route.prefix === "/lovelace" && views) {
|
||||
this.navigate(`/lovelace/${views[0].id || 0}`, true);
|
||||
this.navigate(`/lovelace/${views[0].path || 0}`, true);
|
||||
} else if (this.routeData.view) {
|
||||
const view = this.routeData.view;
|
||||
let index = 0;
|
||||
for (let i = 0; i < views.length; i++) {
|
||||
if (views[i].id === view || i === parseInt(view)) {
|
||||
if (views[i].path === view || i === parseInt(view)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
@ -267,8 +276,8 @@ class HUIRoot extends NavigateMixin(
|
||||
}
|
||||
}
|
||||
|
||||
_computeViewId(id, index) {
|
||||
return id || index;
|
||||
_computeViewPath(path, index) {
|
||||
return path || index;
|
||||
}
|
||||
|
||||
_computeTitle(config) {
|
||||
@ -299,22 +308,8 @@ class HUIRoot extends NavigateMixin(
|
||||
window.open("https://www.home-assistant.io/lovelace/", "_blank");
|
||||
}
|
||||
|
||||
_computeEditVisible(editMode, views) {
|
||||
return editMode && views[this._curView];
|
||||
}
|
||||
|
||||
_editModeEnable() {
|
||||
if (this.config._frontendAuto) {
|
||||
showSaveDialog(this, {
|
||||
config: this.config,
|
||||
reloadLovelace: () => {
|
||||
this.fire("config-refresh");
|
||||
this._editMode = true;
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
this._editMode = true;
|
||||
this.lovelace.setEditMode(true);
|
||||
if (this.config.views.length < 2) {
|
||||
this.$.view.classList.remove("tabs-hidden");
|
||||
this.fire("iron-resize");
|
||||
@ -322,7 +317,7 @@ class HUIRoot extends NavigateMixin(
|
||||
}
|
||||
|
||||
_editModeDisable() {
|
||||
this._editMode = false;
|
||||
this.lovelace.setEditMode(false);
|
||||
if (this.config.views.length < 2) {
|
||||
this.$.view.classList.add("tabs-hidden");
|
||||
this.fire("iron-resize");
|
||||
@ -335,20 +330,14 @@ class HUIRoot extends NavigateMixin(
|
||||
|
||||
_editView() {
|
||||
showEditViewDialog(this, {
|
||||
viewConfig: this.config.views[this._curView],
|
||||
add: false,
|
||||
reloadLovelace: () => {
|
||||
this.fire("config-refresh");
|
||||
},
|
||||
lovelace: this.lovelace,
|
||||
viewIndex: this._curView,
|
||||
});
|
||||
}
|
||||
|
||||
_addView() {
|
||||
showEditViewDialog(this, {
|
||||
add: true,
|
||||
reloadLovelace: () => {
|
||||
this.fire("config-refresh");
|
||||
},
|
||||
lovelace: this.lovelace,
|
||||
});
|
||||
}
|
||||
|
||||
@ -359,8 +348,8 @@ class HUIRoot extends NavigateMixin(
|
||||
|
||||
_navigateView(viewIndex) {
|
||||
if (viewIndex !== this._curView) {
|
||||
const id = this.config.views[viewIndex].id || viewIndex;
|
||||
this.navigate(`/lovelace/${id}`);
|
||||
const path = this.config.views[viewIndex].path || viewIndex;
|
||||
this.navigate(`/lovelace/${path}`);
|
||||
}
|
||||
scrollToTarget(this, this.$.layout.header.scrollTarget);
|
||||
}
|
||||
@ -389,12 +378,12 @@ class HUIRoot extends NavigateMixin(
|
||||
if (viewConfig.panel) {
|
||||
view = createCardElement(viewConfig.cards[0]);
|
||||
view.isPanel = true;
|
||||
view.editMode = this._editMode;
|
||||
} else {
|
||||
view = document.createElement("hui-view");
|
||||
view.lovelace = this.lovelace;
|
||||
view.config = viewConfig;
|
||||
view.columns = this.columns;
|
||||
view.editMode = this._editMode;
|
||||
view.index = viewIndex;
|
||||
}
|
||||
if (viewConfig.background) background = viewConfig.background;
|
||||
}
|
||||
@ -451,5 +440,13 @@ class HUIRoot extends NavigateMixin(
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_computeConfig(lovelace) {
|
||||
return lovelace ? lovelace.config : null;
|
||||
}
|
||||
|
||||
_computeEditMode(lovelace) {
|
||||
return lovelace ? lovelace.editMode : false;
|
||||
}
|
||||
}
|
||||
customElements.define("hui-root", HUIRoot);
|
||||
|
@ -11,7 +11,7 @@ import EventsMixin from "../../mixins/events-mixin";
|
||||
import localizeMixin from "../../mixins/localize-mixin";
|
||||
import createCardElement from "./common/create-card-element";
|
||||
import { computeCardSize } from "./common/compute-card-size";
|
||||
import { showEditCardDialog } from "./editor/show-edit-card-dialog";
|
||||
import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog";
|
||||
|
||||
class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
@ -82,7 +82,7 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
<div id="badges"></div>
|
||||
<div id="columns"></div>
|
||||
<paper-fab
|
||||
hidden$="{{!editMode}}"
|
||||
hidden$="[[!lovelace.editMode]]"
|
||||
elevated="2"
|
||||
icon="hass:plus"
|
||||
title=[[localize("ui.panel.lovelace.editor.edit_card.add")]]
|
||||
@ -97,9 +97,11 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
type: Object,
|
||||
observer: "_hassChanged",
|
||||
},
|
||||
lovelace: Object,
|
||||
config: Object,
|
||||
columns: Number,
|
||||
editMode: Boolean,
|
||||
index: Number,
|
||||
};
|
||||
}
|
||||
|
||||
@ -119,11 +121,8 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
|
||||
_addCard() {
|
||||
showEditCardDialog(this, {
|
||||
viewId: "id" in this.config ? String(this.config.id) : undefined,
|
||||
add: true,
|
||||
reloadLovelace: () => {
|
||||
this.fire("config-refresh");
|
||||
},
|
||||
lovelace: this.lovelace,
|
||||
path: [this.index],
|
||||
});
|
||||
}
|
||||
|
||||
@ -169,23 +168,23 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
|
||||
const elements = [];
|
||||
const elementsToAppend = [];
|
||||
for (const cardConfig of config.cards) {
|
||||
config.cards.forEach((cardConfig, cardIndex) => {
|
||||
const element = createCardElement(cardConfig);
|
||||
element.hass = this.hass;
|
||||
elements.push(element);
|
||||
|
||||
if (!this.editMode) {
|
||||
if (!this.lovelace.editMode) {
|
||||
elementsToAppend.push(element);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = document.createElement("hui-card-options");
|
||||
wrapper.hass = this.hass;
|
||||
wrapper.cardConfig = cardConfig;
|
||||
wrapper.editMode = this.editMode;
|
||||
wrapper.lovelace = this.lovelace;
|
||||
wrapper.path = [this.index, cardIndex];
|
||||
wrapper.appendChild(element);
|
||||
elementsToAppend.push(wrapper);
|
||||
}
|
||||
});
|
||||
|
||||
let columns = [];
|
||||
const columnEntityCount = [];
|
||||
|
@ -1,5 +1,14 @@
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { LovelaceCardConfig } from "../../data/lovelace";
|
||||
import { LovelaceCardConfig, LovelaceConfig } from "../../data/lovelace";
|
||||
|
||||
export interface Lovelace {
|
||||
config: LovelaceConfig;
|
||||
editMode: boolean;
|
||||
autoGen: boolean;
|
||||
mode: "yaml" | "storage";
|
||||
setEditMode: (editMode: boolean) => void;
|
||||
saveConfig: (newConfig: LovelaceConfig) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface LovelaceCard extends HTMLElement {
|
||||
hass?: HomeAssistant;
|
||||
|
@ -159,3 +159,11 @@ export type GroupEntity = HassEntityBase & {
|
||||
control?: "hidden";
|
||||
};
|
||||
};
|
||||
|
||||
export interface PanelInfo<T = unknown> {
|
||||
component_name: string;
|
||||
icon?: string;
|
||||
title?: string;
|
||||
url_path: string;
|
||||
config: T;
|
||||
}
|
||||
|
54
test-mocha/panels/lovelace/editor/config-util.spec.ts
Normal file
54
test-mocha/panels/lovelace/editor/config-util.spec.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import * as assert from "assert";
|
||||
|
||||
import { swapCard } from "../../../../src/panels/lovelace/editor/config-util";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
|
||||
describe("swapCard", () => {
|
||||
it("swaps 2 cards in same view", () => {
|
||||
const config: LovelaceConfig = {
|
||||
views: [
|
||||
{},
|
||||
{
|
||||
cards: [{ type: "card1" }, { type: "card2" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = swapCard(config, [1, 0], [1, 1]);
|
||||
const expected = {
|
||||
views: [
|
||||
{},
|
||||
{
|
||||
cards: [{ type: "card2" }, { type: "card1" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
assert.deepEqual(expected, result);
|
||||
});
|
||||
|
||||
it("swaps 2 cards in different views", () => {
|
||||
const config: LovelaceConfig = {
|
||||
views: [
|
||||
{
|
||||
cards: [{ type: "v1-c1" }, { type: "v1-c2" }],
|
||||
},
|
||||
{
|
||||
cards: [{ type: "v2-c1" }, { type: "v2-c2" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const result = swapCard(config, [0, 0], [1, 1]);
|
||||
const expected = {
|
||||
views: [
|
||||
{
|
||||
cards: [{ type: "v2-c2" }, { type: "v1-c2" }],
|
||||
},
|
||||
{
|
||||
cards: [{ type: "v2-c1" }, { type: "v1-c1" }],
|
||||
},
|
||||
],
|
||||
};
|
||||
assert.deepEqual(expected, result);
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"panel": {
|
||||
"config": "Configuració",
|
||||
"states": "Visió general",
|
||||
"states": "Visualització general",
|
||||
"map": "Mapa",
|
||||
"logbook": "Diari de registre",
|
||||
"history": "Historial",
|
||||
@ -26,9 +26,9 @@
|
||||
"alarm_control_panel": {
|
||||
"armed": "Activada",
|
||||
"disarmed": "Desactivada",
|
||||
"armed_home": "Activada, casa",
|
||||
"armed_away": "Activada, fora",
|
||||
"armed_night": "Activada, nit",
|
||||
"armed_home": "Activada, mode a casa",
|
||||
"armed_away": "Activada, mode fora",
|
||||
"armed_night": "Activada, mode nit",
|
||||
"pending": "Pendent",
|
||||
"arming": "Activant",
|
||||
"disarming": "Desactivant",
|
||||
@ -101,20 +101,20 @@
|
||||
"on": "Fred"
|
||||
},
|
||||
"door": {
|
||||
"off": "Tancat",
|
||||
"on": "Obert"
|
||||
"off": "Tancada",
|
||||
"on": "Oberta"
|
||||
},
|
||||
"garage_door": {
|
||||
"off": "Obert",
|
||||
"on": "Obert"
|
||||
"off": "Tancada",
|
||||
"on": "Oberta"
|
||||
},
|
||||
"heat": {
|
||||
"off": "Normal",
|
||||
"on": "Calent"
|
||||
},
|
||||
"window": {
|
||||
"off": "Tancat",
|
||||
"on": "Obert"
|
||||
"off": "Tancada",
|
||||
"on": "Oberta"
|
||||
},
|
||||
"lock": {
|
||||
"off": "Bloquejat",
|
||||
@ -122,8 +122,8 @@
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
"off": "Apagat",
|
||||
"on": "Encès"
|
||||
"off": "Desactivat",
|
||||
"on": "Activat"
|
||||
},
|
||||
"camera": {
|
||||
"recording": "Enregistrant",
|
||||
@ -133,8 +133,8 @@
|
||||
"climate": {
|
||||
"off": "Apagat",
|
||||
"on": "Encès",
|
||||
"heat": "Escalfar",
|
||||
"cool": "Refredar",
|
||||
"heat": "Calent",
|
||||
"cool": "Fred",
|
||||
"idle": "Inactiu",
|
||||
"auto": "Automàtic",
|
||||
"dry": "Assecar",
|
||||
@ -142,7 +142,7 @@
|
||||
"eco": "Econòmic",
|
||||
"electric": "Elèctric",
|
||||
"performance": "Rendiment",
|
||||
"high_demand": "Plena potència",
|
||||
"high_demand": "Alta potència",
|
||||
"heat_pump": "Bomba de calor",
|
||||
"gas": "Gas",
|
||||
"manual": "Manual"
|
||||
@ -152,9 +152,9 @@
|
||||
"configured": "Configurat"
|
||||
},
|
||||
"cover": {
|
||||
"open": "Obert",
|
||||
"open": "Oberta",
|
||||
"opening": "Obrint",
|
||||
"closed": "Tancat",
|
||||
"closed": "Tancada",
|
||||
"closing": "Tancant",
|
||||
"stopped": "Aturat"
|
||||
},
|
||||
@ -210,14 +210,14 @@
|
||||
"on": "Encès"
|
||||
},
|
||||
"scene": {
|
||||
"scening": "Escena"
|
||||
"scening": "Escena activa"
|
||||
},
|
||||
"script": {
|
||||
"off": "Desactivat",
|
||||
"on": "Activat"
|
||||
},
|
||||
"sensor": {
|
||||
"off": "Apagat",
|
||||
"off": "Desactivat",
|
||||
"on": "Activat"
|
||||
},
|
||||
"sun": {
|
||||
@ -258,31 +258,31 @@
|
||||
},
|
||||
"vacuum": {
|
||||
"cleaning": "Netejant",
|
||||
"docked": "Aparcat",
|
||||
"docked": "Aparcada",
|
||||
"error": "Error",
|
||||
"idle": "Inactiu",
|
||||
"off": "Off",
|
||||
"on": "On",
|
||||
"paused": "Aturat",
|
||||
"off": "Apagada",
|
||||
"on": "Encesa",
|
||||
"paused": "Pausada",
|
||||
"returning": "Retornant a la base"
|
||||
}
|
||||
},
|
||||
"state_badge": {
|
||||
"default": {
|
||||
"unknown": "Desc",
|
||||
"unknown": "Descon.",
|
||||
"unavailable": "No disp."
|
||||
},
|
||||
"alarm_control_panel": {
|
||||
"armed": "Activada",
|
||||
"disarmed": "Desactiv.",
|
||||
"armed_home": "Activ.",
|
||||
"armed_away": "Activ.",
|
||||
"armed_night": "Activ.",
|
||||
"pending": "Pend.",
|
||||
"arming": "Activant",
|
||||
"disarming": "Desactiv.",
|
||||
"triggered": "Alarma",
|
||||
"armed_custom_bypass": "Activada"
|
||||
"armed": "Activad.",
|
||||
"disarmed": "Desacti.",
|
||||
"armed_home": "Activad.",
|
||||
"armed_away": "Activad.",
|
||||
"armed_night": "Activad.",
|
||||
"pending": "Pendent",
|
||||
"arming": "Activan.",
|
||||
"disarming": "Desacti.",
|
||||
"triggered": "Dispara.",
|
||||
"armed_custom_bypass": "Activad."
|
||||
},
|
||||
"device_tracker": {
|
||||
"home": "A casa",
|
||||
@ -292,9 +292,9 @@
|
||||
"ui": {
|
||||
"panel": {
|
||||
"shopping-list": {
|
||||
"clear_completed": "Esborrar completats",
|
||||
"add_item": "Afegir element",
|
||||
"microphone_tip": "Toqueu el micròfon a la part superior dreta i dieu \"Add candy to my shopping list\""
|
||||
"clear_completed": "Suprimir completats",
|
||||
"add_item": "Afegir article",
|
||||
"microphone_tip": "Clica el micròfon a la part superior dreta i digues \"Add candy to my shopping list\""
|
||||
},
|
||||
"history": {
|
||||
"showing_entries": "Mostrant entrades de",
|
||||
@ -304,31 +304,31 @@
|
||||
"showing_entries": "Mostrant entrades de"
|
||||
},
|
||||
"mailbox": {
|
||||
"empty": "No teniu missatges",
|
||||
"empty": "No tens missatges",
|
||||
"playback_title": "Reproducció de missatges",
|
||||
"delete_prompt": "Vols suprimir aquest missatge?",
|
||||
"delete_button": "Suprimir"
|
||||
},
|
||||
"config": {
|
||||
"header": "Configurar Home Assistant",
|
||||
"introduction": "Aquí és possible configurar els vostres components i Home Assistant. Encara no és possible configurar tot des de la interfície d'usuari, però estem treballant.",
|
||||
"header": "Configuració de Home Assistant",
|
||||
"introduction": "Aquí pots configurar Home Assistant i els seus components. Encara no és possible configurar-ho tot des de la interfície d'usuari, però hi estem treballant.",
|
||||
"core": {
|
||||
"caption": "General",
|
||||
"description": "Validar la configuració i controlar el servidor",
|
||||
"description": "Valida la configuració i controla el servidor",
|
||||
"section": {
|
||||
"core": {
|
||||
"header": "Configuració i control del servidor",
|
||||
"introduction": "Sabem que canviar la configuració pot ser un procés molest. Aquesta secció intentarà facilitar una mica més la vostra vida.",
|
||||
"introduction": "Sabem que canviar la configuració pot ser un procés molest. Aquesta secció intenta facilitar-te una mica més la vida.",
|
||||
"validation": {
|
||||
"heading": "Validació de la configuració",
|
||||
"introduction": "Valideu la configuració si recentment heu fet alguns canvis a la vostra configuració i voleu assegurar-vos que sigui vàlida.",
|
||||
"introduction": "Valida la configuració si recentment has fet algun canvi a la configuració i vols assegurar-te de que no té problemes.",
|
||||
"check_config": "Comprovar la configuració",
|
||||
"valid": "La configuració és válida!",
|
||||
"valid": "La configuració és vàlida!",
|
||||
"invalid": "La configuració és invàlida"
|
||||
},
|
||||
"reloading": {
|
||||
"heading": "Recarregar configuració",
|
||||
"introduction": "Algunes parts de la configuració de Home Assistant es poden recarregar sense necessitat de reiniciar. Utilizant aquestes opcions, es descarregarà la configuració actual i es carregarà la nova.",
|
||||
"heading": "Recàrrega de la configuració",
|
||||
"introduction": "Algunes parts de la configuració de Home Assistant es poden recarregar sense necessitat de reiniciar-les. Les opcions de sota esborraran la configuració antiga i carregaran la nova.",
|
||||
"core": "Recarregar el nucli",
|
||||
"group": "Recarregar grups",
|
||||
"automation": "Recarregar automatismes",
|
||||
@ -336,7 +336,7 @@
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Gestió del servidor",
|
||||
"introduction": "Controlar el servidor de Home Assistant... des de Home Assistant.",
|
||||
"introduction": "Controla el servidor de Home Assistant... des de Home Assistant.",
|
||||
"restart": "Reiniciar",
|
||||
"stop": "Aturar"
|
||||
}
|
||||
@ -345,31 +345,31 @@
|
||||
},
|
||||
"customize": {
|
||||
"caption": "Personalització",
|
||||
"description": "Personalitza les teves entitats (customization)"
|
||||
"description": "Personalitza les entitats"
|
||||
},
|
||||
"automation": {
|
||||
"caption": "Automatisme",
|
||||
"description": "Crear i editar automatismes",
|
||||
"caption": "Automatització",
|
||||
"description": "Crea i edita automatismes",
|
||||
"picker": {
|
||||
"header": "Editor d'automatismes",
|
||||
"introduction": "L'editor d'automatismes permet crear i editar automatismes. Llegiu [les instruccions] (https:\/\/home-assistant.io\/docs\/automation\/editor\/) per assegurar-vos que heu configurat Home Assistant correctament.",
|
||||
"pick_automation": "Seleccioneu l'automatisme per editar",
|
||||
"no_automations": "No hem pogut trobar cap automatisme editable",
|
||||
"introduction": "L'editor d'automatismes permet crear i editar automatismes. Llegeix [les instruccions](https:\/\/home-assistant.io\/docs\/automation\/editor\/) per assegurar-te que has configurat el Home Assistant correctament.",
|
||||
"pick_automation": "Selecciona l'automatisme a editar",
|
||||
"no_automations": "No s'ha pogut trobar cap automatisme editable",
|
||||
"add_automation": "Afegir automatisme"
|
||||
},
|
||||
"editor": {
|
||||
"introduction": "Utilitzeu els automatismes per donar vida a la vostra casa",
|
||||
"introduction": "Utilitza els automatismes per donar més vida a la teva casa",
|
||||
"default_name": "Nou automatisme",
|
||||
"save": "Desar",
|
||||
"unsaved_confirm": "Hi han canvis no desats. Segur que voleu sortir?",
|
||||
"unsaved_confirm": "Hi ha canvis no desats. Segur que vols sortir?",
|
||||
"alias": "Nom",
|
||||
"triggers": {
|
||||
"header": "Activadors",
|
||||
"introduction": "Els activadors són les regles que fan començar a processar un automatisme. És possible especificar diversos activadors pel mateix automatisme. Una vegada que s'iniciï un activador, Home Assistant validarà les condicions, si n'hi ha, i cridará l'acció.\n\n[Més informació sobre activadors] (https:\/\/home-assistant.io\/docs\/automation\/trigger\/)",
|
||||
"introduction": "Els activadors són les regles que fan que es dispari un automatisme. Pots definir més d'un activadors per cada automatisme. Una vegada s'iniciï un activador, el Home Assistant validarà les condicions (si n'hi ha) i finalment cridarà l'acció.\n\n[Més informació sobre activadors](https:\/\/home-assistant.io\/docs\/automation\/trigger\/)",
|
||||
"add": "Afegir activador",
|
||||
"duplicate": "Duplicar",
|
||||
"delete": "Suprimir",
|
||||
"delete_confirm": "Segur que voleu suprimir-ho?",
|
||||
"delete_confirm": "Segur que vols suprimir-ho?",
|
||||
"unsupported_platform": "Plataforma {platform} no suportada.",
|
||||
"type_select": "Tipus d'activador",
|
||||
"type": {
|
||||
@ -387,8 +387,8 @@
|
||||
"homeassistant": {
|
||||
"label": "Home Assistant",
|
||||
"event": "Esdeveniment:",
|
||||
"start": "Iniciar",
|
||||
"shutdown": "Aturar"
|
||||
"start": "Inici",
|
||||
"shutdown": "Aturada"
|
||||
},
|
||||
"mqtt": {
|
||||
"label": "MQTT",
|
||||
@ -404,17 +404,17 @@
|
||||
"sun": {
|
||||
"label": "Sol",
|
||||
"event": "Esdeveniment:",
|
||||
"sunrise": "Alba",
|
||||
"sunset": "Capvespre",
|
||||
"offset": "Diferencial (opcional)"
|
||||
"sunrise": "de l'Alba",
|
||||
"sunset": "del Capvespre",
|
||||
"offset": "Òfset (opcional)"
|
||||
},
|
||||
"template": {
|
||||
"label": "Plantilla",
|
||||
"value_template": "Plantilla de valor"
|
||||
},
|
||||
"time": {
|
||||
"label": "Temps",
|
||||
"at": "A"
|
||||
"label": "Temporal",
|
||||
"at": "A les"
|
||||
},
|
||||
"zone": {
|
||||
"label": "Zona",
|
||||
@ -428,11 +428,11 @@
|
||||
},
|
||||
"conditions": {
|
||||
"header": "Condicions",
|
||||
"introduction": "Les condicions són una part opcional d'un automatisme i es poden utilitzar per evitar que es produeixi una acció quan s'activi. Les condicions semblen molt similars als activadors però funcionen de forma diferent. Un activador analitzarà els esdeveniments que ocorren en el sistema mentre que una condició només observa com es veu el sistema en un moment donat. Un activador pot observar que s'està activant un interruptor mentres que una condició només pot veure si un commutador està activat o desactivat.\n\n[Més informació sobre les condicions.] (Https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)",
|
||||
"introduction": "Les condicions són una part opcional d'un automatisme i es poden utilitzar per permetre o evitar que es produeixi l'acció quan s'activa l'automatisme. Les condicions són similars als activadors però funcionen de forma diferent: un activador analitza els esdeveniments que ocorren en el sistema mentre que una condició només observa com està el sistema en un moment determinat, per exemple, un activador se n'adonarà de quan s'està activant un interruptor mentre que una condició només pot veure si un interruptor està activat o desactivat.\n\n[Més informació sobre les condicions](https:\/\/home-assistant.io\/docs\/scripts\/conditions\/).",
|
||||
"add": "Afegir condició",
|
||||
"duplicate": "Duplicar",
|
||||
"delete": "Suprimir",
|
||||
"delete_confirm": "Segur que voleu suprimir-ho?",
|
||||
"delete_confirm": "Segur que vols suprimir-ho?",
|
||||
"unsupported_condition": "Condició {condition} no suportada.",
|
||||
"type_select": "Tipus de condició",
|
||||
"type": {
|
||||
@ -450,8 +450,8 @@
|
||||
"label": "Sol",
|
||||
"before": "Abans:",
|
||||
"after": "Després:",
|
||||
"before_offset": "Diferencial previ (opcional)",
|
||||
"after_offset": "Diferencial posterior (opcional)",
|
||||
"before_offset": "Òfset anterior (opcional)",
|
||||
"after_offset": "Òfset posterior (opcional)",
|
||||
"sunrise": "Alba",
|
||||
"sunset": "Capvespre"
|
||||
},
|
||||
@ -460,7 +460,7 @@
|
||||
"value_template": "Plantilla de valor"
|
||||
},
|
||||
"time": {
|
||||
"label": "Temps",
|
||||
"label": "Temporal",
|
||||
"after": "Després",
|
||||
"before": "Abans"
|
||||
},
|
||||
@ -473,11 +473,11 @@
|
||||
},
|
||||
"actions": {
|
||||
"header": "Accions",
|
||||
"introduction": "Les accions són les que farà Home Assistant quan s'activi l'automatisme.\n\n[Més informació sobre les accions.] (Https:\/\/home-assistant.io\/docs\/automation\/action\/)",
|
||||
"introduction": "Les accions són allò que farà Home Assistant quan s'activi l'automatisme i es compleixin totes les condicions (si n'hi ha).\n\n[Més informació sobre les accions](https:\/\/home-assistant.io\/docs\/automation\/action\/).",
|
||||
"add": "Afegir acció",
|
||||
"duplicate": "Duplicar",
|
||||
"delete": "Suprimir",
|
||||
"delete_confirm": "Segur que voleu suprimir-ho?",
|
||||
"delete_confirm": "Segur que vols suprimir-ho?",
|
||||
"unsupported_action": "Acció {action} no suportada.",
|
||||
"type_select": "Tipus d'acció",
|
||||
"type": {
|
||||
@ -490,9 +490,9 @@
|
||||
"delay": "Retard"
|
||||
},
|
||||
"wait_template": {
|
||||
"label": "Esperar",
|
||||
"label": "Espera",
|
||||
"wait_template": "Plantilla d'espera",
|
||||
"timeout": "Temps máxim d'espera (opcional)"
|
||||
"timeout": "Temps màxim d'espera (opcional)"
|
||||
},
|
||||
"condition": {
|
||||
"label": "Condició"
|
||||
@ -507,8 +507,8 @@
|
||||
}
|
||||
},
|
||||
"script": {
|
||||
"caption": "Programes",
|
||||
"description": "Crear i editar programes (scripts)"
|
||||
"caption": "Programació",
|
||||
"description": "Crea i edita programes (scripts)"
|
||||
},
|
||||
"zwave": {
|
||||
"caption": "Z-Wave",
|
||||
@ -516,7 +516,7 @@
|
||||
},
|
||||
"users": {
|
||||
"caption": "Usuaris",
|
||||
"description": "Gestionar els usuaris",
|
||||
"description": "Gestiona els usuaris",
|
||||
"picker": {
|
||||
"title": "Usuaris"
|
||||
},
|
||||
@ -535,18 +535,18 @@
|
||||
},
|
||||
"integrations": {
|
||||
"caption": "Integracions",
|
||||
"description": "Gestioneu dispositius i serveis connectats",
|
||||
"discovered": "Descobert",
|
||||
"description": "Gestiona dispositius i serveis connectats",
|
||||
"discovered": "Descobertes",
|
||||
"configured": "Configurades",
|
||||
"new": "Configureu una nova integració",
|
||||
"new": "Configura una nova integració",
|
||||
"configure": "Configurar",
|
||||
"none": "Encara no hi ha res configurat",
|
||||
"config_entry": {
|
||||
"no_devices": "Aquesta integració no té dispositius.",
|
||||
"no_device": "Entitats sense dispositius",
|
||||
"delete_confirm": "Esteu segur que voleu suprimir aquesta integració?",
|
||||
"restart_confirm": "Reinicieu el Home Assistant per acabar d'eliminar aquesta integració",
|
||||
"manuf": "per {manufacturer}",
|
||||
"delete_confirm": "Estas segur que vols suprimir aquesta integració?",
|
||||
"restart_confirm": "Reinicia el Home Assistant per acabar d'eliminar aquesta integració",
|
||||
"manuf": "de {manufacturer}",
|
||||
"hub": "Connectat a través de",
|
||||
"firmware": "Firmware: {version}",
|
||||
"device_unavailable": "dispositiu no disponible",
|
||||
@ -557,9 +557,9 @@
|
||||
"profile": {
|
||||
"push_notifications": {
|
||||
"header": "Notificacions push",
|
||||
"description": "Envia notificacions a aquest dispositiu",
|
||||
"description": "Envia notificacions a aquest dispositiu.",
|
||||
"error_load_platform": "Configurar notify.html5.",
|
||||
"error_use_https": "Requereix tenir SSL habilitat a la interfície (frontend).",
|
||||
"error_use_https": "Requereix tenir SSL habilitat per a la interfície (frontend).",
|
||||
"push_notifications": "Notificacions push",
|
||||
"link_promo": "Més informació"
|
||||
},
|
||||
@ -571,15 +571,15 @@
|
||||
"themes": {
|
||||
"header": "Tema",
|
||||
"error_no_theme": "No hi ha temes disponibles.",
|
||||
"link_promo": "Més informació sobre temes",
|
||||
"link_promo": "Crea temes personalitzats",
|
||||
"dropdown_label": "Tema"
|
||||
},
|
||||
"refresh_tokens": {
|
||||
"header": "Refresca els testimonis d'autenticació",
|
||||
"description": "Cada testimoni d'autenticació d'actualització representa un inici de sessió diferent. Els testimonis d'autenticació d'actualització s'eliminaran automàticament quan tanqueu la sessió. A sota hi ha una llista de testimonis d'autenticació d'actualització que estan actius actualment al vostre compte.",
|
||||
"description": "Cada testimoni d'autenticació d'actualització representa un inici de sessió diferent. Els testimonis d'autenticació d'actualització s'eliminaran automàticament quan tanquis la sessió. A sota hi ha una llista de testimonis d'autenticació d'actualització que estan actius actualment al teu compte.",
|
||||
"token_title": "Refresca el testimoni d'autenticació del {clientId}",
|
||||
"created_at": "Creat el {date}",
|
||||
"confirm_delete": "Esteu segur que voleu suprimir el testimoni d'autenticació d'actualització per {name}?",
|
||||
"confirm_delete": "Estas segur que vols suprimir el testimoni d'autenticació d'actualització per {name}?",
|
||||
"delete_failed": "No s'ha pogut suprimir el testimoni d'autenticació d'actualització.",
|
||||
"last_used": "Darrer ús el {date} des de {location}",
|
||||
"not_used": "Mai no s'ha utilitzat",
|
||||
@ -587,21 +587,21 @@
|
||||
},
|
||||
"long_lived_access_tokens": {
|
||||
"header": "Testimonis d'autenticació d'accés de llarga durada",
|
||||
"description": "Creeu testimonis d'autenticació d'accés de llarga durada per permetre als vostres programes (scripts) interactuar amb la vostra instància de Home Assistant. Cada testimoni d'autenticació serà vàlid durant deu anys després de la seva creació. Els següents testimoni d'autenticació d'accés de llarga durada estan actius actualment.",
|
||||
"learn_auth_requests": "Apren a fer sol·licituds autenticades.",
|
||||
"description": "Crea testimonis d'autenticació d'accés de llarga durada per permetre als teus programes (scripts) interactuar amb la instància de Home Assistant. Cada testimoni d'autenticació serà vàlid durant deu anys després de la seva creació. Els següents testimonis d'autenticació d'accés de llarga durada estan actius actualment.",
|
||||
"learn_auth_requests": "Aprèn a fer sol·licituds autenticades.",
|
||||
"created_at": "Creat el {date}",
|
||||
"confirm_delete": "Esteu segur que voleu suprimir el testimoni d'autenticació d'accés per {name}?",
|
||||
"confirm_delete": "Estàs segur que vols suprimir el testimoni d'autenticació d'accés per {name}?",
|
||||
"delete_failed": "No s'ha pogut suprimir el testimoni d'autenticació d'accés.",
|
||||
"create": "Crea un testimoni d'autenticació",
|
||||
"create_failed": "No s'ha pogut crear el testimoni d'autenticació d'accés.",
|
||||
"prompt_name": "Nom?",
|
||||
"prompt_copy_token": "Copieu el testimoni d'autenticació (token) d'accés. No es tornarà a mostrar més endavant.",
|
||||
"prompt_copy_token": "Copia't el testimoni d'autenticació (token) d'accés. No es tornarà a mostrar més endavant.",
|
||||
"empty_state": "Encara no tens testimonis d'autenticaciós d'accés de llarga durada.",
|
||||
"last_used": "Darrer ús el {date} des de {location}",
|
||||
"not_used": "Mai no s'ha utilitzat"
|
||||
},
|
||||
"current_user": "Heu iniciat la sessió com a {fullName}.",
|
||||
"is_owner": "Sou propietari.",
|
||||
"current_user": "Has iniciat la sessió com a {fullName}.",
|
||||
"is_owner": "Ets propietari.",
|
||||
"logout": "Tancar sessió",
|
||||
"change_password": {
|
||||
"header": "Canvi de contrasenya",
|
||||
@ -615,11 +615,11 @@
|
||||
"header": "Mòduls d'autenticació amb múltiples passos",
|
||||
"disable": "Desactiva",
|
||||
"enable": "Activa",
|
||||
"confirm_disable": "Esteu segur que voleu desactivar {name}?"
|
||||
"confirm_disable": "Estàs segur que vols desactivar {name}?"
|
||||
},
|
||||
"mfa_setup": {
|
||||
"title_aborted": "S'ha avortat",
|
||||
"title_success": "Correcte!",
|
||||
"title_success": "Èxit!",
|
||||
"step_done": "Configuració feta per a {step}",
|
||||
"close": "Tanca",
|
||||
"submit": "Enviar"
|
||||
@ -647,7 +647,7 @@
|
||||
"data": {
|
||||
"code": "Codi de verificació en dos passos"
|
||||
},
|
||||
"description": "Obriu el **{mfa_module_name}** al vostre dispositiu per veure el codi de verificació en dos passos i verificar la vostra identitat:"
|
||||
"description": "Obre el **{mfa_module_name}** al teu dispositiu per veure el codi de verificació en dos passos i verifica la teva identitat:"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
@ -655,7 +655,7 @@
|
||||
"invalid_code": "El codi d'autenticació no és vàlid"
|
||||
},
|
||||
"abort": {
|
||||
"login_expired": "La sessió ha caducat, torneu a iniciar la sessió."
|
||||
"login_expired": "La sessió ha caducat, torna a iniciar la sessió."
|
||||
}
|
||||
},
|
||||
"legacy_api_password": {
|
||||
@ -664,22 +664,22 @@
|
||||
"data": {
|
||||
"password": "Contrasenya API"
|
||||
},
|
||||
"description": "Introduïu la contrasenya API en la vostra configuració http:"
|
||||
"description": "Introdueix la contrasenya API a la configuració http:"
|
||||
},
|
||||
"mfa": {
|
||||
"data": {
|
||||
"code": "Codi de verificació en dos passos"
|
||||
},
|
||||
"description": "Obriu el **{mfa_module_name}** al vostre dispositiu per veure el codi de verificació en dos passos i verificar la vostra identitat:"
|
||||
"description": "Obre el **{mfa_module_name}** al teu dispositiu per veure el codi de verificació en dos passos i verifica la teva identitat:"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "Contrasenya API no vàlida",
|
||||
"invalid_auth": "Contrasenya API invàlida",
|
||||
"invalid_code": "El codi d'autenticació no és vàlid"
|
||||
},
|
||||
"abort": {
|
||||
"no_api_password_set": "No teniu una contrasenya API configurada.",
|
||||
"login_expired": "La sessió ha caducat, torneu a iniciar la sessió."
|
||||
"login_expired": "La sessió ha caducat, torna a iniciar la sessió."
|
||||
}
|
||||
},
|
||||
"trusted_networks": {
|
||||
@ -688,7 +688,7 @@
|
||||
"data": {
|
||||
"user": "Usuari"
|
||||
},
|
||||
"description": "Seleccioneu l'usuari amb el qual iniciar la sessió:"
|
||||
"description": "Selecciona l'usuari amb el qual iniciar la sessió:"
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
@ -710,29 +710,48 @@
|
||||
},
|
||||
"create_account": "Crear un compte",
|
||||
"error": {
|
||||
"required_fields": "Ompliu tots els camps obligatoris"
|
||||
"required_fields": "Omple tots els camps obligatoris"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lovelace": {
|
||||
"cards": {
|
||||
"shopping-list": {
|
||||
"checked_items": "Elements seleccionats",
|
||||
"clear_items": "Esborra els elements seleccionats",
|
||||
"checked_items": "Articles seleccionats",
|
||||
"clear_items": "Esborrar els articles seleccionats",
|
||||
"add_item": "Afegir element"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"edit_card": {
|
||||
"header": "Targeta de Configuració",
|
||||
"save": "Desa",
|
||||
"toggle_editor": "Commuta l'editor"
|
||||
"save": "Desar",
|
||||
"toggle_editor": "Commutar l'editor",
|
||||
"pick_card": "Tria la targeta que vols afegir.",
|
||||
"add": "Afegir targeta",
|
||||
"edit": "Editar",
|
||||
"delete": "Suprimir"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Configuració incompatible",
|
||||
"para_no_id": "Aquest element no té ID. Afegiu un ID per aquest element a 'ui-lovelace.yaml'.",
|
||||
"para_no_id": "Aquest element no té ID. Afegeix un ID per aquest element a 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant pot afegir ID's a totes les vostres targetes i visualitzacions automàticament fent clic al botó \"Migrar la configuració\".",
|
||||
"migrate": "Migrar la configuració"
|
||||
},
|
||||
"header": "Editar la interfície d'usuari (UI)",
|
||||
"configure_ui": "Configurar la interfície d'usuari",
|
||||
"edit_view": {
|
||||
"header": "Configuració de la visualització",
|
||||
"add": "Afegeix visualització",
|
||||
"edit": "Editar visualització",
|
||||
"delete": "Suprimir visualització"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Pren el control de la interfície d'usuari Lovelace",
|
||||
"para": "De manera predeterminada, Home Assistant mantindrà al dia la teva interfície d'usuari, actualitzant-la quan hi hagi noves entitats o nous components de Lovelace disponibles. Si prens el control, ja no es faran aquests canvis automàticament.",
|
||||
"para_sure": "Estàs segur que vols prendre el control de la interfície d'usuari?",
|
||||
"cancel": "M'ho he repensat",
|
||||
"save": "Prendre el control"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Carregant",
|
||||
"cancel": "Cancel·lar"
|
||||
"cancel": "Cancel·lar",
|
||||
"save": "Desar"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\n one {dia}\n other {dies}\n}",
|
||||
@ -802,14 +822,14 @@
|
||||
"code": "Codi",
|
||||
"clear_code": "Esborrar",
|
||||
"disarm": "Desactivar",
|
||||
"arm_home": "Activar, casa",
|
||||
"arm_home": "Activar, a casa",
|
||||
"arm_away": "Activar, fora",
|
||||
"arm_night": "Activar, nit",
|
||||
"armed_custom_bypass": "Bypass personalitzat"
|
||||
},
|
||||
"automation": {
|
||||
"last_triggered": "Última activació",
|
||||
"trigger": "Activar"
|
||||
"last_triggered": "Última execució",
|
||||
"trigger": "Executar"
|
||||
},
|
||||
"cover": {
|
||||
"position": "Posició",
|
||||
@ -817,13 +837,13 @@
|
||||
},
|
||||
"fan": {
|
||||
"speed": "Velocitat",
|
||||
"oscillate": "Oscil·lar",
|
||||
"oscillate": "Oscil·lació",
|
||||
"direction": "Direcció"
|
||||
},
|
||||
"light": {
|
||||
"brightness": "Brillantor",
|
||||
"color_temperature": "Temperatura de color",
|
||||
"white_value": "Valor del blanc",
|
||||
"white_value": "Ajust de blanc",
|
||||
"effect": "Efecte"
|
||||
},
|
||||
"media_player": {
|
||||
@ -839,7 +859,7 @@
|
||||
"operation": "Funcionament",
|
||||
"fan_mode": "Mode ventilació",
|
||||
"swing_mode": "Mode oscil·lació",
|
||||
"away_mode": "Mode absent",
|
||||
"away_mode": "Mode fora",
|
||||
"aux_heat": "Calefactor auxiliar"
|
||||
},
|
||||
"lock": {
|
||||
@ -861,7 +881,7 @@
|
||||
"on_off": "On \/ Off",
|
||||
"target_temperature": "Temperatura desitjada",
|
||||
"operation": "Funcionament",
|
||||
"away_mode": "Mode absent"
|
||||
"away_mode": "Mode fora"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
@ -899,7 +919,7 @@
|
||||
},
|
||||
"dialogs": {
|
||||
"more_info_settings": {
|
||||
"save": "Desa",
|
||||
"save": "Desar",
|
||||
"name": "Nom",
|
||||
"entity_id": "ID de l'entitat"
|
||||
}
|
||||
@ -916,8 +936,8 @@
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
"alarm_control_panel": "Panell d'alarma",
|
||||
"automation": "Automatisme",
|
||||
"alarm_control_panel": "Panell de control d'alarma",
|
||||
"automation": "Automatismes",
|
||||
"binary_sensor": "Sensor binari",
|
||||
"calendar": "Calendari",
|
||||
"camera": "Càmera",
|
||||
@ -935,21 +955,21 @@
|
||||
"input_select": "Entrada de selecció",
|
||||
"input_number": "Entrada numèrica",
|
||||
"input_text": "Entrada de text",
|
||||
"light": "Llum",
|
||||
"lock": "Pany",
|
||||
"light": "Llums",
|
||||
"lock": "Panys",
|
||||
"mailbox": "Bústia",
|
||||
"media_player": "Reproductor",
|
||||
"media_player": "Reproductor multimèdia",
|
||||
"notify": "Notificacions",
|
||||
"plant": "Planta",
|
||||
"proximity": "Proximitat",
|
||||
"remote": "Comandaments",
|
||||
"scene": "Escenes",
|
||||
"script": "Programa",
|
||||
"script": "Programes (scripts)",
|
||||
"sensor": "Sensors",
|
||||
"sun": "Sol",
|
||||
"switch": "Interruptor",
|
||||
"switch": "Interruptors",
|
||||
"updater": "Actualitzador",
|
||||
"weblink": "Enllaç web",
|
||||
"weblink": "Enllaços web",
|
||||
"zwave": "Z-Wave",
|
||||
"vacuum": "Aspiradora"
|
||||
},
|
||||
|
@ -142,7 +142,8 @@
|
||||
"performance": "Perfformiad",
|
||||
"high_demand": "Galw uchel",
|
||||
"heat_pump": "Pwmp gwres",
|
||||
"gas": "Nwy"
|
||||
"gas": "Nwy",
|
||||
"manual": "Llawlyfr"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Ffurfweddu",
|
||||
|
@ -144,7 +144,8 @@
|
||||
"performance": "Ydeevne",
|
||||
"high_demand": "Høj efterspørgsel",
|
||||
"heat_pump": "Varmepumpe",
|
||||
"gas": "Gas"
|
||||
"gas": "Gas",
|
||||
"manual": "brugervejledning"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Konfigurer",
|
||||
|
@ -145,7 +145,7 @@
|
||||
"high_demand": "Hoher Verbrauch",
|
||||
"heat_pump": "Wärmepumpe",
|
||||
"gas": "Gas",
|
||||
"manual": "Handbuch"
|
||||
"manual": "Manuell"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Konfigurieren",
|
||||
@ -724,12 +724,30 @@
|
||||
},
|
||||
"editor": {
|
||||
"edit_card": {
|
||||
"header": "Kartenkonfiguration",
|
||||
"save": "Speichern",
|
||||
"toggle_editor": "Editor umschalten"
|
||||
"toggle_editor": "Editor umschalten",
|
||||
"pick_card": "Karte auswählen, die hinzugefügt werden soll.",
|
||||
"add": "Karte hinzufügen",
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Konfiguration inkompatibel",
|
||||
"para_no_id": "Dieses Element hat keine ID. Bitte füge diesem Element eine ID in 'ui-lovelace.yaml' hinzu."
|
||||
"para_no_id": "Dieses Element hat keine ID. Bitte füge diesem Element eine ID in 'ui-lovelace.yaml' hinzu.",
|
||||
"migrate": "Konfiguration migrieren"
|
||||
},
|
||||
"header": "Benutzeroberfläche bearbeiten",
|
||||
"configure_ui": "Benutzeroberfläche konfigurieren",
|
||||
"edit_view": {
|
||||
"header": "Konfiguration anzeigen",
|
||||
"add": "Ansicht hinzufügen",
|
||||
"edit": "Ansicht bearbeiten",
|
||||
"delete": "Ansicht löschen"
|
||||
},
|
||||
"save_config": {
|
||||
"cancel": "Abbrechen",
|
||||
"save": "Kontrolle übernehmen"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -740,7 +758,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Laden",
|
||||
"cancel": "Abbrechen"
|
||||
"cancel": "Abbrechen",
|
||||
"save": "Speichern"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {Tag}\nother {Tage}\n}",
|
||||
|
@ -96,7 +96,8 @@
|
||||
"performance": "Απόδοση",
|
||||
"high_demand": "Υψηλή ζήτηση",
|
||||
"heat_pump": "Αντλία θερμότητας",
|
||||
"gas": "Φυσικού αερίου"
|
||||
"gas": "Φυσικού αερίου",
|
||||
"manual": "Εγχειρίδιο"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Διαμορφώστε",
|
||||
|
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "Card Configuration",
|
||||
"save": "Save",
|
||||
"toggle_editor": "Toggle Editor"
|
||||
"toggle_editor": "Toggle Editor",
|
||||
"pick_card": "Pick the card you want to add.",
|
||||
"add": "Add Card",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Configuration Incompatible",
|
||||
"para_no_id": "This element doesn't have an ID. Please add an ID to this element in 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant can add ID's to all your cards and views automatically for you by pressing the 'Migrate config' button.",
|
||||
"migrate": "Migrate config"
|
||||
},
|
||||
"header": "Edit UI",
|
||||
"configure_ui": "Configure UI",
|
||||
"edit_view": {
|
||||
"header": "View Configuration",
|
||||
"add": "Add view",
|
||||
"edit": "Edit view",
|
||||
"delete": "Delete view"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Take control of your Lovelace UI",
|
||||
"para": "By default Home Assistant will maintain your user interface, updating it when new entities or Lovelace components become available. If you take control we will no longer make changes automatically for you.",
|
||||
"para_sure": "Are you sure you want to take control of your user interface?",
|
||||
"cancel": "Never mind",
|
||||
"save": "Take control"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Loading",
|
||||
"cancel": "Cancel"
|
||||
"cancel": "Cancel",
|
||||
"save": "Save"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\n one {day}\n other {days}\n}",
|
||||
|
@ -100,7 +100,8 @@
|
||||
"performance": "کارایی",
|
||||
"high_demand": "تقاضای بالا",
|
||||
"heat_pump": "پمپ حرارتی",
|
||||
"gas": "گاز"
|
||||
"gas": "گاز",
|
||||
"manual": "کتابچه راهنمای"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "پیکربندی",
|
||||
|
@ -144,7 +144,8 @@
|
||||
"performance": "ביצועים",
|
||||
"high_demand": "ביקוש גבוה",
|
||||
"heat_pump": "משאבת חום",
|
||||
"gas": "גז"
|
||||
"gas": "גז",
|
||||
"manual": "מדריך ל"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "הגדר",
|
||||
@ -723,7 +724,34 @@
|
||||
},
|
||||
"editor": {
|
||||
"edit_card": {
|
||||
"save": "שמור"
|
||||
"header": "הגדרות כרטיסייה",
|
||||
"save": "שמור",
|
||||
"toggle_editor": "החלף מצב עורך",
|
||||
"pick_card": "בחר את הכרטיסייה שברצונך להוסיף.",
|
||||
"add": "הוסף כרטיסייה",
|
||||
"edit": "ערוך",
|
||||
"delete": "מחק"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "ההגדרה לא מתאימה ",
|
||||
"para_no_id": "האלמנט הנוכחי לא מכיל מזהה יחודיי. בבקשה הוסף מזהה יחודי לאלמט זה בקובץ 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant יכול להוסיף מזהה יחודי לכל הכרטיסיות והתצוגות שלך בצורה אוטומטית בכך שתלחץ על לחצן ״הגר הגדרה״. ",
|
||||
"migrate": "הגר הגדרה"
|
||||
},
|
||||
"header": "ערוך UI",
|
||||
"configure_ui": "הגדר UI",
|
||||
"edit_view": {
|
||||
"header": "הצג הגדרות",
|
||||
"add": "הוסף תצוגה",
|
||||
"edit": "ערוך תצוגה",
|
||||
"delete": "מחק תצוגה"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "קח שליטה על Lovelace ממשק המשתמש שלך",
|
||||
"para": "כברירת מחדל Home Assistant יתחזק את ממשק המשתמש שלך , יעדכן אותו כאשר קומפוננטות או ישויות חדשות יהפכו לזמינות. אם תקח שליטה אנו לא נוכל לבצע שינויים בצורה אוטומטית בשבילך.",
|
||||
"para_sure": "האם אתה בטוח שאתה רוצה לקחת שליטה על ממשק המשתמש?",
|
||||
"cancel": "לא משנה",
|
||||
"save": "קח שליטה"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -734,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "טוען",
|
||||
"cancel": "ביטול"
|
||||
"cancel": "ביטול",
|
||||
"save": "שמור"
|
||||
},
|
||||
"duration": {
|
||||
"day": "יום ימים",
|
||||
|
@ -34,7 +34,8 @@
|
||||
"climate": {
|
||||
"heat": "गर्मी",
|
||||
"cool": "ठंडा",
|
||||
"dry": "सूखा"
|
||||
"dry": "सूखा",
|
||||
"manual": "गाइड"
|
||||
},
|
||||
"device_tracker": {
|
||||
"home": "घर"
|
||||
|
@ -292,7 +292,7 @@
|
||||
"ui": {
|
||||
"panel": {
|
||||
"shopping-list": {
|
||||
"clear_completed": "Törlés sikeres",
|
||||
"clear_completed": "Kijelöltek törlése",
|
||||
"add_item": "Tétel hozzáadása",
|
||||
"microphone_tip": "Koppints a jobb felső sarokban található mikrofonra, és mondd ki: \"Add candy to my shopping list\""
|
||||
},
|
||||
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "Kártya Konfiguráció",
|
||||
"save": "Mentés",
|
||||
"toggle_editor": "Szerkesztő"
|
||||
"toggle_editor": "Szerkesztő",
|
||||
"pick_card": "Válaszd ki a kártyát amit hozzá szeretnél adni.",
|
||||
"add": "Kártya hozzáadása",
|
||||
"edit": "Szerkesztés",
|
||||
"delete": "Törlés"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Inkompatibilis Konfiguráció",
|
||||
"para_no_id": "Ez az elem nem rendelkezik azonosítóval. Kérlek, adj hozzá egyet az 'ui-lovelace.yaml' fájlban!",
|
||||
"para_migrate": "A Home Assistant a 'Konfiguráció áttelepítése' gomb megnyomásával az összes kártyához és nézethez automatikusan létre tud hozni azonosítókat.",
|
||||
"migrate": "Konfiguráció áttelepítése"
|
||||
},
|
||||
"header": "Felhasználói felület szerkesztése",
|
||||
"configure_ui": "Felhasználói felület konfigurálása",
|
||||
"edit_view": {
|
||||
"header": "Nézet konfigurálása",
|
||||
"add": "Nézet hozzáadása",
|
||||
"edit": "Nézet szerkesztése",
|
||||
"delete": "Nézet törlése"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Vedd át az irányítást a Lovelace UI felett",
|
||||
"para": "Alapértelmezés szerint a Home Assistant kezeli a felhasználói felületet, és frissíti azt, amikor új entitások vagy Lovelace komponensek válnak elérhetővé. Ha átveszed az irányítást, többé nem fogunk automatikusan módosításokat végezni számodra.",
|
||||
"para_sure": "Biztosan át szeretnéd venni az irányítást a felhasználói felületed felett?",
|
||||
"cancel": "Mégsem",
|
||||
"save": "Irányítás átvétele"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Betöltés",
|
||||
"cancel": "Mégse"
|
||||
"cancel": "Mégse",
|
||||
"save": "Mentés"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {nap}\nother {nap}\n}",
|
||||
|
@ -143,7 +143,8 @@
|
||||
"performance": "Kinerja",
|
||||
"high_demand": "Permintaan yang tinggi",
|
||||
"heat_pump": "Pompa pemanas",
|
||||
"gas": "Gas"
|
||||
"gas": "Gas",
|
||||
"manual": "Manual"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Konfigurasi",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"fan_only": "ファンのみ",
|
||||
"eco": "エコ",
|
||||
"performance": "パフォーマンス",
|
||||
"gas": "ガス"
|
||||
"gas": "ガス",
|
||||
"manual": "マニュアル"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "設定",
|
||||
|
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "카드 구성",
|
||||
"save": "저장하기",
|
||||
"toggle_editor": "에디터 전환"
|
||||
"toggle_editor": "에디터 전환",
|
||||
"pick_card": "추가하려는 카드를 선택해주세요",
|
||||
"add": "카드 추가",
|
||||
"edit": "편집",
|
||||
"delete": "삭제"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "설정이 호환되지 않습니다",
|
||||
"para_no_id": "이 구성요소에는 ID가 없습니다. 'ui-lovelace.yaml' 에 구성요소의 ID를 추가해주세요.",
|
||||
"para_migrate": "Home Assistant 는 '설정 마이그레이션' 버튼을 눌러 자동으로 모든 카드와 보기에 ID를 추가 할 수 있습니다.",
|
||||
"migrate": "설정 마이그레이션"
|
||||
},
|
||||
"header": "UI 편집",
|
||||
"configure_ui": "UI 구성",
|
||||
"edit_view": {
|
||||
"header": "구성 보기",
|
||||
"add": "뷰 추가",
|
||||
"edit": "뷰 편집",
|
||||
"delete": "뷰 삭제"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Lovelace UI 직접 관리하기",
|
||||
"para": "기본적으로 Home Assistant 는 사용자 인터페이스를 유지 관리하고, 사용할 수 있는 새로운 구성요소 또는 Lovelace 구성요소가 있을 때 업데이트를 합니다. 사용자가 직접 관리하는 경우 Home Assistant 는 더 이상 자동으로 변경하지 않습니다.",
|
||||
"para_sure": "사용자 인터페이스를 직접 관리하시겠습니까?",
|
||||
"cancel": "아닙니다",
|
||||
"save": "직접 관리할께요"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "읽는중",
|
||||
"cancel": "취소"
|
||||
"cancel": "취소",
|
||||
"save": "저장"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {일}\nother {일}\n}",
|
||||
|
@ -301,7 +301,7 @@
|
||||
"period": "Zäitraum"
|
||||
},
|
||||
"logbook": {
|
||||
"showing_entries": "Weist Beiträg fir"
|
||||
"showing_entries": "Weist Beiträg fir"
|
||||
},
|
||||
"mailbox": {
|
||||
"empty": "Dir hutt keng Noriicht",
|
||||
@ -403,7 +403,7 @@
|
||||
},
|
||||
"sun": {
|
||||
"label": "Sonn",
|
||||
"event": "Evenement",
|
||||
"event": "Evenement:",
|
||||
"sunrise": "Sonnenopgank",
|
||||
"sunset": "Sonnenënnergank",
|
||||
"offset": "Versat (optional)"
|
||||
@ -726,13 +726,31 @@
|
||||
"edit_card": {
|
||||
"header": "Kaart Konfiguratioun",
|
||||
"save": "Späicheren",
|
||||
"toggle_editor": "Editeur ëmschalten"
|
||||
"toggle_editor": "Editeur ëmschalten",
|
||||
"pick_card": "Wielt d'Kaart aus déi soll dobäigesat ginn.",
|
||||
"add": "Kaart dobäisetzen",
|
||||
"edit": "Änneren",
|
||||
"delete": "Läschen"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Konfiguratioun net kompatibel",
|
||||
"para_no_id": "Dëst Element huet keng ID. Definéiert w.e.g. eng ID fir dëst Element am 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant kann ID's zu all äre Kaarten automatesch dobäisetzen andeem dir de Knäppche 'Konfiguratioun migréieren' dréckt.",
|
||||
"migrate": "Konfiguratioun migréieren"
|
||||
},
|
||||
"header": "UI änneren",
|
||||
"configure_ui": "UI konfiguréieren",
|
||||
"edit_view": {
|
||||
"header": "Konfiguratioun kucken",
|
||||
"add": "Vue dobäisetzen",
|
||||
"edit": "Vue änneren",
|
||||
"delete": "Vue läschen"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Kontroll iwwert Loveloce UI iwwerhuelen",
|
||||
"para_sure": "Sécher fir d'Kontrolle iwwert de Benotzer Interface z'iwwerhuelen?",
|
||||
"cancel": "Vergiess et",
|
||||
"save": "Kontroll iwwerhuelen"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +761,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Lued",
|
||||
"cancel": "Ofbriechen"
|
||||
"cancel": "Ofbriechen",
|
||||
"save": "Späicheren"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {dag}\nother {deeg}\n}",
|
||||
|
@ -66,5 +66,10 @@
|
||||
},
|
||||
"domain": {
|
||||
"zwave": "Z-Wave"
|
||||
},
|
||||
"state": {
|
||||
"climate": {
|
||||
"manual": "Rankinis"
|
||||
}
|
||||
}
|
||||
}
|
@ -144,7 +144,8 @@
|
||||
"performance": "Veiktspēja",
|
||||
"high_demand": "Augsts pieprasījums",
|
||||
"heat_pump": "Siltumsūknis",
|
||||
"gas": "Gāze"
|
||||
"gas": "Gāze",
|
||||
"manual": "Rokasgrāmata"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Konfigurēt",
|
||||
|
@ -144,7 +144,8 @@
|
||||
"performance": "Yting",
|
||||
"high_demand": "Høg etterspurnad",
|
||||
"heat_pump": "Varmepumpe",
|
||||
"gas": "Gass"
|
||||
"gas": "Gass",
|
||||
"manual": "Håndbok"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Konfigurerer",
|
||||
|
@ -237,7 +237,7 @@
|
||||
},
|
||||
"query_stage": {
|
||||
"initializing": "Initialiserer ({query_stage})",
|
||||
"dead": "Død ({query_stage})"
|
||||
"dead": "Død ({query_stage})"
|
||||
}
|
||||
},
|
||||
"weather": {
|
||||
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "Kortkonfigurasjon",
|
||||
"save": "Lagre",
|
||||
"toggle_editor": "Bytt redigering"
|
||||
"toggle_editor": "Bytt redigering",
|
||||
"pick_card": "Velge det kortet du ønsker å legge til.",
|
||||
"add": "Legg til kort",
|
||||
"edit": "Rediger",
|
||||
"delete": "Slett"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Konfigurasjon inkompatibel",
|
||||
"para_no_id": "Dette elementet har ingen ID. Vennligst legg til en ID til dette elementet i 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant kan legge til ID-er til alle dine kort og visninger automatisk for deg ved å trykke på 'Overfør konfigurasjon' knappen.",
|
||||
"migrate": "Overfør konfigurasjon"
|
||||
},
|
||||
"header": "Rediger brukergrensesnitt",
|
||||
"configure_ui": "Konfigurer brukergrensesnitt",
|
||||
"edit_view": {
|
||||
"header": "Vis konfigurasjon",
|
||||
"add": "Legg til visning",
|
||||
"edit": "Rediger visning",
|
||||
"delete": "Slett visning"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Ta kontroll over Lovelace brukergrensesnittet ditt",
|
||||
"para": "Home Assistant hjelper som standard med å vedlikeholde brukergrensesnittet ditt, oppdaterer det når nye enheter eller Lovelace-komponenter blir tilgjengelige. Hvis du tar kontroll, vil vi ikke lenger gjøre endringer automatisk for deg.",
|
||||
"para_sure": "Er du sikker på at du vil ta kontroll over brukergrensesnittet ditt?",
|
||||
"cancel": "Glem det",
|
||||
"save": "Ta kontroll"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Laster",
|
||||
"cancel": "Avbryt"
|
||||
"cancel": "Avbryt",
|
||||
"save": "Lagre"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {dag}\nother {dager}\n}",
|
||||
|
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "Konfiguracja karty",
|
||||
"save": "Zapisz",
|
||||
"toggle_editor": "Przełącz edytor"
|
||||
"toggle_editor": "Przełącz edytor",
|
||||
"pick_card": "Wybierz kartę, którą chcesz dodać.",
|
||||
"add": "Dodaj kartę",
|
||||
"edit": "Edytuj",
|
||||
"delete": "Usuń"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Konfiguracja niekompatybilna",
|
||||
"para_no_id": "Ten element nie ma ID. Dodaj ID do tego elementu w \"ui-lovelace.yaml\".",
|
||||
"para_migrate": "Home Assistant może automatycznie dodać ID do wszystkich twoich kart i widoków, po kliknięciu przycisku \"Migracja konfiguracji\".",
|
||||
"migrate": "Migracja konfiguracji"
|
||||
},
|
||||
"header": "Edycja interfejsu użytkownika",
|
||||
"configure_ui": "Konfiguracja interfejsu użytkownika",
|
||||
"edit_view": {
|
||||
"header": "Konfiguracja widoku",
|
||||
"add": "Dodaj widok",
|
||||
"edit": "Edytuj widok",
|
||||
"delete": "Usuń widok"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Przejmij kontrolę nad interfejsem użytkownika Lovelace",
|
||||
"para": "Domyślnie Home Assistant będzie zarządzać interfejsem użytkownika, aktualizując go, gdy pojawią się nowe encje lub komponenty Lovelace. Jeśli przejmiesz kontrolę, Home Assistant nie będzie już automatycznie wprowadzać dla ciebie zmian.",
|
||||
"para_sure": "Czy na pewno chcesz przejąć kontrolę nad interfejsem użytkownika?",
|
||||
"cancel": "Nieważne",
|
||||
"save": "Przejmuję kontrolę"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Ładowanie",
|
||||
"cancel": "Anuluj"
|
||||
"cancel": "Anuluj",
|
||||
"save": "Zapisz"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\n one {dzień}\n other {dni}\n}",
|
||||
|
@ -144,7 +144,8 @@
|
||||
"performance": "Performanţă",
|
||||
"high_demand": "Consum mare",
|
||||
"heat_pump": "Pompă de căldură",
|
||||
"gas": "Gaz"
|
||||
"gas": "Gaz",
|
||||
"manual": "Manual"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Configurează",
|
||||
|
@ -699,7 +699,7 @@
|
||||
}
|
||||
},
|
||||
"page-onboarding": {
|
||||
"intro": "Готовы пробудить свой дом, восстановить свою конфиденциальность и присоединиться к всемирному сообществу умельцев?",
|
||||
"intro": "Готовы ли вы разбудить свой дом, восстановить свою конфиденциальность и присоединиться к всемирному сообществу?",
|
||||
"user": {
|
||||
"intro": "Давайте начнём с создания учётной записи пользователя.",
|
||||
"required_field": "Обязательное поле",
|
||||
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "Настройка карточки",
|
||||
"save": "Сохранить",
|
||||
"toggle_editor": "Переключить редактор"
|
||||
"toggle_editor": "Переключить редактор",
|
||||
"pick_card": "Выберите карточку, которую Вы хотите добавить",
|
||||
"add": "Добавить карточку",
|
||||
"edit": "Изменить",
|
||||
"delete": "Удалить"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Конфигурация несовместима",
|
||||
"para_no_id": "Этот элемент не имеет ID. Добавьте ID для этого элемента в 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant может автоматически добавить ID для всех карточек и видов, если нажать кнопку 'Перенести настройки'.",
|
||||
"para_migrate": "Home Assistant может автоматически добавить ID для всех карточек и вкладок, если нажать кнопку 'Перенести настройки'.",
|
||||
"migrate": "Перенести настройки"
|
||||
},
|
||||
"header": "Редактирование интерфейса",
|
||||
"configure_ui": "Настройка интерфейса",
|
||||
"edit_view": {
|
||||
"header": "Настройки вкладки",
|
||||
"add": "Добавить вкладку",
|
||||
"edit": "Изменить вкладку",
|
||||
"delete": "Удалить вкладку"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Получение контроля над пользовательским интерфейсом Lovelace",
|
||||
"para": "По умолчанию Home Assistant будет обслуживать ваш пользовательский интерфейс, автоматически добавляя новые объекты и новые компоненты Lovelace, если они доступны. Если вы получите контроль над пользовательским интерфейсом, изменения больше не будут вноситься автоматически.",
|
||||
"para_sure": "Вы уверены, что хотите самостоятельно контролировать пользовательский интерфейс?",
|
||||
"cancel": "Оставить как есть",
|
||||
"save": "Получить контроль"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Загрузка",
|
||||
"cancel": "Отменить"
|
||||
"cancel": "Отменить",
|
||||
"save": "Сохранить"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {д.}\nother {д.}\n}",
|
||||
|
@ -143,7 +143,8 @@
|
||||
"performance": "Výkon",
|
||||
"high_demand": "Vysoký výkon",
|
||||
"heat_pump": "Tepelné čerpadlo",
|
||||
"gas": "Plyn"
|
||||
"gas": "Plyn",
|
||||
"manual": "Manuálny"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Konfigurovať",
|
||||
|
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "Konfiguracija kartice",
|
||||
"save": "Shrani",
|
||||
"toggle_editor": "Preklop na urejevalnik"
|
||||
"toggle_editor": "Preklop na urejevalnik",
|
||||
"pick_card": "Izberite kartico, ki jo želite dodati.",
|
||||
"add": "Dodaj kartico",
|
||||
"edit": "Uredi",
|
||||
"delete": "Izbriši"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Konfiguracija Nezdružljiva",
|
||||
"para_no_id": "Ta element nima ID-ja. Prosimo, dodajte ID tega elementa v 'ui-lovelace.yaml'.",
|
||||
"para_migrate": "Home Assistant lahko doda ID-je vsem vašim karticam in pogledom samodejno s pritiskom gumba »Migriraj nastavitve«.",
|
||||
"migrate": "Migriraj nastavitve"
|
||||
},
|
||||
"header": "Uredi UI",
|
||||
"configure_ui": "Konfiguriraj UI",
|
||||
"edit_view": {
|
||||
"header": "Prikaži konfiguracijo",
|
||||
"add": "Dodaj pogled",
|
||||
"edit": "Uredi pogled",
|
||||
"delete": "Izbriši pogled"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Prevzemite nadzor nad lovelace vmesnikom",
|
||||
"para": "Home Assistant bo privzeto vzdrževal vaš uporabniški vmesnik, ga posodabljal, ko bodo na voljo nove entitete ali komponente Lovelace. Če prevzamete nadzor, vam ga ne bo več samodejno popravljal.",
|
||||
"para_sure": "Ali ste prepričani, da želite prevzeti nadzor nad vašim vmesnikom?",
|
||||
"cancel": "Pozabi",
|
||||
"save": "Prevzemite nadzor"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "Nalaganje",
|
||||
"cancel": "Prekliči"
|
||||
"cancel": "Prekliči",
|
||||
"save": "Shrani"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {Dan}\nother {Dni}\n}",
|
||||
|
@ -92,6 +92,9 @@
|
||||
"sunny": "Sunčano",
|
||||
"windy": "Vetrovito",
|
||||
"windy-variant": "Vetrovito"
|
||||
},
|
||||
"climate": {
|
||||
"manual": "Упутство"
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,9 @@
|
||||
"query_stage": {
|
||||
"initializing": "Učitavanje ({query_stage})"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"manual": "Упутство"
|
||||
}
|
||||
},
|
||||
"state_badge": {
|
||||
|
@ -113,7 +113,8 @@
|
||||
"performance": "செயல்திறன்",
|
||||
"high_demand": "அதிக தேவை",
|
||||
"heat_pump": "வெப்ப பம்ப்",
|
||||
"gas": "வாயு"
|
||||
"gas": "வாயு",
|
||||
"manual": "கையேடு"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "உள்ளமை",
|
||||
|
@ -142,7 +142,8 @@
|
||||
"performance": "ప్రదర్శన",
|
||||
"high_demand": "అధిక డిమాండ్",
|
||||
"heat_pump": "వేడి పంపు",
|
||||
"gas": "వాయువు"
|
||||
"gas": "వాయువు",
|
||||
"manual": "మాన్యువల్"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "కాన్ఫిగర్",
|
||||
|
@ -142,7 +142,8 @@
|
||||
"performance": "ประสิทธิภาพ",
|
||||
"high_demand": "ความต้องการสูง",
|
||||
"heat_pump": "ปั๊มความร้อน",
|
||||
"gas": "แก๊ส"
|
||||
"gas": "แก๊ส",
|
||||
"manual": "คู่มือ"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "ตั้งค่า",
|
||||
|
@ -144,7 +144,8 @@
|
||||
"performance": "Продуктивність",
|
||||
"high_demand": "Велике споживання",
|
||||
"heat_pump": "Тепловий насос",
|
||||
"gas": "Газ"
|
||||
"gas": "Газ",
|
||||
"manual": "Вручну"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Налаштувати",
|
||||
@ -247,6 +248,7 @@
|
||||
"lightning": "Блискавка",
|
||||
"lightning-rainy": "Блискавка, дощ",
|
||||
"partlycloudy": "Невелика хмарність",
|
||||
"pouring": "Злива",
|
||||
"rainy": "Дощова",
|
||||
"snowy": "Сніжно",
|
||||
"snowy-rainy": "Сніг, дощ",
|
||||
@ -278,22 +280,11 @@
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"sidebar": {
|
||||
"log_out": "Вийти",
|
||||
"developer_tools": "Інструменти для розробників"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Завантаження",
|
||||
"cancel": "Скасувати"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\n one {д.}\n other {д.}\n}",
|
||||
"week": "{count} {count, plural,\n one {тиж.}\n other {тиж.}\n}",
|
||||
"second": "{count} {count, plural,\n one {сек.}\n other {сек.}\n}",
|
||||
"minute": "{count} {count, plural,\n one {хв.}\n other {хв.}\n}",
|
||||
"hour": "{count} {count, plural,\n one {год.}\n other {год.}\n}"
|
||||
},
|
||||
"panel": {
|
||||
"shopping-list": {
|
||||
"add_item": "Додати елемент",
|
||||
"microphone_tip": "Торкніться мікрофона у верхньому правому куті та скажіть \"Add candy to my shopping list\""
|
||||
},
|
||||
"history": {
|
||||
"showing_entries": "Показані записи для",
|
||||
"period": "Період"
|
||||
@ -360,11 +351,50 @@
|
||||
"alias": "Назва",
|
||||
"triggers": {
|
||||
"header": "Тригери",
|
||||
"unsupported_platform": "Непідтримувана платформа: {platform}",
|
||||
"type": {
|
||||
"homeassistant": {
|
||||
"start": "Початок",
|
||||
"shutdown": "Завершення роботи"
|
||||
},
|
||||
"sun": {
|
||||
"label": "Сонце",
|
||||
"sunrise": "Схід сонця",
|
||||
"sunset": "Захід сонця",
|
||||
"offset": "Зміщення (необов'язково)"
|
||||
},
|
||||
"time": {
|
||||
"label": "Час"
|
||||
},
|
||||
"state": {
|
||||
"for": "Протягом"
|
||||
}
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"type": {
|
||||
"sun": {
|
||||
"before": "Перед:",
|
||||
"after": "Після:",
|
||||
"before_offset": "Перед зміщенням (необов'язково)",
|
||||
"after_offset": "Після зміщення (необов'язково)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"header": "Дії",
|
||||
"add": "Додати дію",
|
||||
"unsupported_action": "Непідтримувана дія: {action}",
|
||||
"type_select": "Тип дії",
|
||||
"type": {
|
||||
"delay": {
|
||||
"label": "Затримка"
|
||||
},
|
||||
"wait_template": {
|
||||
"label": "Чекати",
|
||||
"timeout": "Тайм-аут (необов'язково)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -507,7 +537,8 @@
|
||||
"mfa": {
|
||||
"data": {
|
||||
"code": "Двофакторний ідентифікаційний код"
|
||||
}
|
||||
},
|
||||
"description": "Відкрийте **{mfa_module_name}** на своєму пристрої, щоб переглянути свій двофакторний код автентифікації та підтвердити свою особу:"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
@ -525,6 +556,11 @@
|
||||
"password": "Пароль API"
|
||||
},
|
||||
"description": "Будь ласка, введіть пароль API в ваш http конфіг:"
|
||||
},
|
||||
"mfa": {
|
||||
"data": {
|
||||
"code": "Двофакторний Код Автентифікації"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
@ -565,8 +601,51 @@
|
||||
"required_fields": "Заповніть усі необхідні поля"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lovelace": {
|
||||
"cards": {
|
||||
"shopping-list": {
|
||||
"add_item": "Додати елемент"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"edit_card": {
|
||||
"header": "Конфігурація картки",
|
||||
"save": "Зберегти",
|
||||
"pick_card": "Виберіть картку, яку хочете додати.",
|
||||
"add": "Додати картку",
|
||||
"edit": "Редагувати",
|
||||
"delete": "Видалити"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "Конфігурація несумісна"
|
||||
},
|
||||
"header": "Редагування інтерфейсу",
|
||||
"edit_view": {
|
||||
"header": "Перегляд Конфігурації "
|
||||
},
|
||||
"save_config": {
|
||||
"header": "Візьміть під свій контроль Lovelace UI"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sidebar": {
|
||||
"log_out": "Вийти",
|
||||
"developer_tools": "Інструменти для розробників"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Завантаження",
|
||||
"cancel": "Скасувати",
|
||||
"save": "Зберегти"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\n one {д.}\n other {д.}\n}",
|
||||
"week": "{count} {count, plural,\n one {тиж.}\n other {тиж.}\n}",
|
||||
"second": "{count} {count, plural,\n one {сек.}\n other {сек.}\n}",
|
||||
"minute": "{count} {count, plural,\n one {хв.}\n other {хв.}\n}",
|
||||
"hour": "{count} {count, plural,\n one {год.}\n other {год.}\n}"
|
||||
},
|
||||
"login-form": {
|
||||
"password": "Пароль",
|
||||
"remember": "Запам'ятати",
|
||||
@ -642,6 +721,12 @@
|
||||
"lock": "Блокувати",
|
||||
"unlock": "Розблокувати"
|
||||
},
|
||||
"vacuum": {
|
||||
"actions": {
|
||||
"turn_on": "Ввімкнути",
|
||||
"turn_off": "Вимкнути"
|
||||
}
|
||||
},
|
||||
"water_heater": {
|
||||
"currently": "В даний час",
|
||||
"on_off": "Вкл \/ викл",
|
||||
|
@ -140,7 +140,8 @@
|
||||
"performance": "Hiệu suất",
|
||||
"high_demand": "Nhu cầu cao",
|
||||
"heat_pump": "Bơm nhiệt",
|
||||
"gas": "Khí"
|
||||
"gas": "Khí",
|
||||
"manual": "Hướng dẫn"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Cấu hình",
|
||||
|
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "卡片配置",
|
||||
"save": "保存",
|
||||
"toggle_editor": "切换编辑器"
|
||||
"toggle_editor": "切换编辑器",
|
||||
"pick_card": "请选择要添加的卡片。",
|
||||
"add": "添加卡片",
|
||||
"edit": "编辑",
|
||||
"delete": "删除"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "配置不兼容",
|
||||
"para_no_id": "此元素没有 ID。请在 'ui-lovelace.yaml' 中为此元素添加 ID。",
|
||||
"para_migrate": "通过点击“迁移配置”按钮,Home Assistant 可以自动为您的所有卡片和视图添加 ID。",
|
||||
"migrate": "迁移配置"
|
||||
},
|
||||
"header": "编辑 UI",
|
||||
"configure_ui": "配置 UI",
|
||||
"edit_view": {
|
||||
"header": "查看配置",
|
||||
"add": "添加视图",
|
||||
"edit": "编辑视图",
|
||||
"delete": "删除视图"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "自行编辑您的 Lovelace UI",
|
||||
"para": "默认情况下,Home Assistant 将维护您的用户界面,并在新的实体或 Lovelace 组件可用时更新它。如果您选择自行编辑,我们将不再自动为您进行更改。",
|
||||
"para_sure": "您确定要自行编辑用户界面吗?",
|
||||
"cancel": "没关系",
|
||||
"save": "自行编辑"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "加载中",
|
||||
"cancel": "取消"
|
||||
"cancel": "取消",
|
||||
"save": "保存"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {天}\nother {天}\n}",
|
||||
|
@ -726,13 +726,32 @@
|
||||
"edit_card": {
|
||||
"header": "卡片設定",
|
||||
"save": "儲存",
|
||||
"toggle_editor": "切換編輯器"
|
||||
"toggle_editor": "切換編輯器",
|
||||
"pick_card": "選擇所要新增的卡片。",
|
||||
"add": "新增卡片",
|
||||
"edit": "編輯",
|
||||
"delete": "刪除"
|
||||
},
|
||||
"migrate": {
|
||||
"header": "設定不相容",
|
||||
"para_no_id": "該元件未含 ID,請於「ui-lovelace.yaml」中為該元件新增 ID。",
|
||||
"para_migrate": "Home Assistant 能於您點選「遷移設定」按鈕後,自動新增 ID 與視圖至所有卡片。",
|
||||
"migrate": "遷移設定"
|
||||
},
|
||||
"header": "編輯 UI",
|
||||
"configure_ui": "設定 UI",
|
||||
"edit_view": {
|
||||
"header": "檢視設定",
|
||||
"add": "新增視圖",
|
||||
"edit": "編輯視圖",
|
||||
"delete": "刪除視圖"
|
||||
},
|
||||
"save_config": {
|
||||
"header": "自行編輯 Lovelace UI",
|
||||
"para": "Home Assistant 於預設下,將維護您的使用者介面、於新物件或 Lovelace 元件可使用時進行更新。假如選擇自行編輯,系統將不再為您自動進行變更。",
|
||||
"para_sure": "確定要自行編輯使用者介面?",
|
||||
"cancel": "取消",
|
||||
"save": "儲存"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,7 +762,8 @@
|
||||
},
|
||||
"common": {
|
||||
"loading": "讀取中",
|
||||
"cancel": "取消"
|
||||
"cancel": "取消",
|
||||
"save": "儲存"
|
||||
},
|
||||
"duration": {
|
||||
"day": "{count} {count, plural,\none {天}\nother {天}\n}",
|
||||
|
Loading…
x
Reference in New Issue
Block a user