mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +00:00
commit
831b23347e
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20190815.0",
|
||||
version="20190820.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -1,8 +1,4 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
import { createCollection } from "home-assistant-js-websocket";
|
||||
import { debounce } from "../common/util/debounce";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { DataEntryFlowStep, DataEntryFlowProgress } from "./data_entry_flow";
|
||||
|
||||
export interface ConfigEntry {
|
||||
entry_id: string;
|
||||
@ -14,114 +10,34 @@ export interface ConfigEntry {
|
||||
supports_options: boolean;
|
||||
}
|
||||
|
||||
export const createConfigFlow = (hass: HomeAssistant, handler: string) =>
|
||||
hass.callApi<DataEntryFlowStep>("POST", "config/config_entries/flow", {
|
||||
handler,
|
||||
});
|
||||
|
||||
export const fetchConfigFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"GET",
|
||||
`config/config_entries/flow/${flowId}`
|
||||
);
|
||||
|
||||
export const handleConfigFlowStep = (
|
||||
hass: HomeAssistant,
|
||||
flowId: string,
|
||||
data: { [key: string]: any }
|
||||
) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"POST",
|
||||
`config/config_entries/flow/${flowId}`,
|
||||
data
|
||||
);
|
||||
|
||||
export const deleteConfigFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi("DELETE", `config/config_entries/flow/${flowId}`);
|
||||
|
||||
export const getConfigFlowsInProgress = (hass: HomeAssistant) =>
|
||||
hass.callApi<DataEntryFlowProgress[]>("GET", "config/config_entries/flow");
|
||||
|
||||
export const getConfigFlowHandlers = (hass: HomeAssistant) =>
|
||||
hass.callApi<string[]>("GET", "config/config_entries/flow_handlers");
|
||||
|
||||
const fetchConfigFlowInProgress = (conn) =>
|
||||
conn.sendMessagePromise({
|
||||
type: "config/entity_registry/list",
|
||||
});
|
||||
|
||||
const subscribeConfigFlowInProgressUpdates = (conn, store) =>
|
||||
debounce(
|
||||
conn.subscribeEvents(
|
||||
() =>
|
||||
fetchConfigFlowInProgress(conn).then((flows) =>
|
||||
store.setState(flows, true)
|
||||
),
|
||||
500,
|
||||
true
|
||||
),
|
||||
"config_entry_discovered"
|
||||
);
|
||||
|
||||
export const subscribeConfigFlowInProgress = (
|
||||
hass: HomeAssistant,
|
||||
onChange: (flows: DataEntryFlowProgress[]) => void
|
||||
) =>
|
||||
createCollection<DataEntryFlowProgress[]>(
|
||||
"_configFlowProgress",
|
||||
fetchConfigFlowInProgress,
|
||||
subscribeConfigFlowInProgressUpdates,
|
||||
hass.connection,
|
||||
onChange
|
||||
);
|
||||
export interface ConfigEntrySystemOptions {
|
||||
disable_new_entities: boolean;
|
||||
}
|
||||
|
||||
export const getConfigEntries = (hass: HomeAssistant) =>
|
||||
hass.callApi<ConfigEntry[]>("GET", "config/config_entries/entry");
|
||||
|
||||
export const localizeConfigFlowTitle = (
|
||||
localize: LocalizeFunc,
|
||||
flow: DataEntryFlowProgress
|
||||
) => {
|
||||
const placeholders = flow.context.title_placeholders || {};
|
||||
const placeholderKeys = Object.keys(placeholders);
|
||||
if (placeholderKeys.length === 0) {
|
||||
return localize(`component.${flow.handler}.config.title`);
|
||||
}
|
||||
const args: string[] = [];
|
||||
placeholderKeys.forEach((key) => {
|
||||
args.push(key);
|
||||
args.push(placeholders[key]);
|
||||
});
|
||||
return localize(`component.${flow.handler}.config.flow_title`, ...args);
|
||||
};
|
||||
export const deleteConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
|
||||
hass.callApi<{
|
||||
require_restart: boolean;
|
||||
}>("DELETE", `config/config_entries/entry/${configEntryId}`);
|
||||
|
||||
// Options flow
|
||||
|
||||
export const createOptionsFlow = (hass: HomeAssistant, handler: string) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"POST",
|
||||
"config/config_entries/options/flow",
|
||||
{
|
||||
handler,
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchOptionsFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"GET",
|
||||
`config/config_entries/options/flow/${flowId}`
|
||||
);
|
||||
|
||||
export const handleOptionsFlowStep = (
|
||||
export const getConfigEntrySystemOptions = (
|
||||
hass: HomeAssistant,
|
||||
flowId: string,
|
||||
data: { [key: string]: any }
|
||||
configEntryId: string
|
||||
) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"POST",
|
||||
`config/config_entries/options/flow/${flowId}`,
|
||||
data
|
||||
);
|
||||
hass.callWS<ConfigEntrySystemOptions>({
|
||||
type: "config_entries/system_options/list",
|
||||
entry_id: configEntryId,
|
||||
});
|
||||
|
||||
export const deleteOptionsFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi("DELETE", `config/config_entries/options/flow/${flowId}`);
|
||||
export const updateConfigEntrySystemOptions = (
|
||||
hass: HomeAssistant,
|
||||
configEntryId: string,
|
||||
params: Partial<ConfigEntrySystemOptions>
|
||||
) =>
|
||||
hass.callWS({
|
||||
type: "config_entries/system_options/update",
|
||||
entry_id: configEntryId,
|
||||
...params,
|
||||
});
|
||||
|
83
src/data/config_flow.ts
Normal file
83
src/data/config_flow.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
import { DataEntryFlowStep, DataEntryFlowProgress } from "./data_entry_flow";
|
||||
import { debounce } from "../common/util/debounce";
|
||||
import { createCollection } from "home-assistant-js-websocket";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
|
||||
export const createConfigFlow = (hass: HomeAssistant, handler: string) =>
|
||||
hass.callApi<DataEntryFlowStep>("POST", "config/config_entries/flow", {
|
||||
handler,
|
||||
});
|
||||
|
||||
export const fetchConfigFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"GET",
|
||||
`config/config_entries/flow/${flowId}`
|
||||
);
|
||||
|
||||
export const handleConfigFlowStep = (
|
||||
hass: HomeAssistant,
|
||||
flowId: string,
|
||||
data: { [key: string]: any }
|
||||
) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"POST",
|
||||
`config/config_entries/flow/${flowId}`,
|
||||
data
|
||||
);
|
||||
|
||||
export const deleteConfigFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi("DELETE", `config/config_entries/flow/${flowId}`);
|
||||
|
||||
export const getConfigFlowsInProgress = (hass: HomeAssistant) =>
|
||||
hass.callApi<DataEntryFlowProgress[]>("GET", "config/config_entries/flow");
|
||||
|
||||
export const getConfigFlowHandlers = (hass: HomeAssistant) =>
|
||||
hass.callApi<string[]>("GET", "config/config_entries/flow_handlers");
|
||||
|
||||
const fetchConfigFlowInProgress = (conn) =>
|
||||
conn.sendMessagePromise({
|
||||
type: "config_entries/flow/progress",
|
||||
});
|
||||
|
||||
const subscribeConfigFlowInProgressUpdates = (conn, store) =>
|
||||
conn.subscribeEvents(
|
||||
debounce(
|
||||
() =>
|
||||
fetchConfigFlowInProgress(conn).then((flows) =>
|
||||
store.setState(flows, true)
|
||||
),
|
||||
500,
|
||||
true
|
||||
),
|
||||
"config_entry_discovered"
|
||||
);
|
||||
|
||||
export const subscribeConfigFlowInProgress = (
|
||||
hass: HomeAssistant,
|
||||
onChange: (flows: DataEntryFlowProgress[]) => void
|
||||
) =>
|
||||
createCollection<DataEntryFlowProgress[]>(
|
||||
"_configFlowProgress",
|
||||
fetchConfigFlowInProgress,
|
||||
subscribeConfigFlowInProgressUpdates,
|
||||
hass.connection,
|
||||
onChange
|
||||
);
|
||||
|
||||
export const localizeConfigFlowTitle = (
|
||||
localize: LocalizeFunc,
|
||||
flow: DataEntryFlowProgress
|
||||
) => {
|
||||
const placeholders = flow.context.title_placeholders || {};
|
||||
const placeholderKeys = Object.keys(placeholders);
|
||||
if (placeholderKeys.length === 0) {
|
||||
return localize(`component.${flow.handler}.config.title`);
|
||||
}
|
||||
const args: string[] = [];
|
||||
placeholderKeys.forEach((key) => {
|
||||
args.push(key);
|
||||
args.push(placeholders[key]);
|
||||
});
|
||||
return localize(`component.${flow.handler}.config.flow_title`, ...args);
|
||||
};
|
@ -9,12 +9,13 @@ export interface EntityRegistryEntry {
|
||||
platform: string;
|
||||
config_entry_id?: string;
|
||||
device_id?: string;
|
||||
disabled_by?: string;
|
||||
disabled_by: string | null;
|
||||
}
|
||||
|
||||
export interface EntityRegistryEntryUpdateParams {
|
||||
name: string | null;
|
||||
new_entity_id: string;
|
||||
name?: string | null;
|
||||
disabled_by?: string | null;
|
||||
new_entity_id?: string;
|
||||
}
|
||||
|
||||
export const computeEntityRegistryName = (
|
||||
|
31
src/data/options_flow.ts
Normal file
31
src/data/options_flow.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
import { DataEntryFlowStep } from "./data_entry_flow";
|
||||
|
||||
export const createOptionsFlow = (hass: HomeAssistant, handler: string) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"POST",
|
||||
"config/config_entries/options/flow",
|
||||
{
|
||||
handler,
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchOptionsFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"GET",
|
||||
`config/config_entries/options/flow/${flowId}`
|
||||
);
|
||||
|
||||
export const handleOptionsFlowStep = (
|
||||
hass: HomeAssistant,
|
||||
flowId: string,
|
||||
data: { [key: string]: any }
|
||||
) =>
|
||||
hass.callApi<DataEntryFlowStep>(
|
||||
"POST",
|
||||
`config/config_entries/options/flow/${flowId}`,
|
||||
data
|
||||
);
|
||||
|
||||
export const deleteOptionsFlow = (hass: HomeAssistant, flowId: string) =>
|
||||
hass.callApi("DELETE", `config/config_entries/options/flow/${flowId}`);
|
@ -0,0 +1,175 @@
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
CSSResult,
|
||||
TemplateResult,
|
||||
customElement,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import "../../components/dialog/ha-paper-dialog";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { ConfigEntrySystemOptionsDialogParams } from "./show-dialog-config-entry-system-options";
|
||||
import {
|
||||
getConfigEntrySystemOptions,
|
||||
updateConfigEntrySystemOptions,
|
||||
} from "../../data/config_entries";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
|
||||
@customElement("dialog-config-entry-system-options")
|
||||
class DialogConfigEntrySystemOptions extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() private _disableNewEntities!: boolean;
|
||||
@property() private _error?: string;
|
||||
@property() private _params?: ConfigEntrySystemOptionsDialogParams;
|
||||
@property() private _loading?: boolean;
|
||||
@property() private _submitting?: boolean;
|
||||
|
||||
public async showDialog(
|
||||
params: ConfigEntrySystemOptionsDialogParams
|
||||
): Promise<void> {
|
||||
this._params = params;
|
||||
this._error = undefined;
|
||||
this._loading = true;
|
||||
const systemOptions = await getConfigEntrySystemOptions(
|
||||
this.hass,
|
||||
params.entry.entry_id
|
||||
);
|
||||
this._loading = false;
|
||||
this._disableNewEntities = systemOptions.disable_new_entities;
|
||||
await this.updateComplete;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-paper-dialog
|
||||
with-backdrop
|
||||
opened
|
||||
@opened-changed="${this._openedChanged}"
|
||||
>
|
||||
<h2>
|
||||
${this.hass.localize("ui.dialogs.config_entry_system_options.title")}
|
||||
</h2>
|
||||
<paper-dialog-scrollable>
|
||||
${this._loading
|
||||
? html`
|
||||
<div class="init-spinner">
|
||||
<paper-spinner-lite active></paper-spinner-lite>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
${this._error
|
||||
? html`
|
||||
<div class="error">${this._error}</div>
|
||||
`
|
||||
: ""}
|
||||
<div class="form">
|
||||
<paper-toggle-button
|
||||
.checked=${!this._disableNewEntities}
|
||||
@checked-changed=${this._disableNewEntitiesChanged}
|
||||
.disabled=${this._submitting}
|
||||
>
|
||||
<div>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.config_entry_system_options.enable_new_entities_label"
|
||||
)}
|
||||
</div>
|
||||
<div class="secondary">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.config_entry_system_options.enable_new_entities_description"
|
||||
)}
|
||||
</div>
|
||||
</paper-toggle-button>
|
||||
</div>
|
||||
`}
|
||||
</paper-dialog-scrollable>
|
||||
${!this._loading
|
||||
? html`
|
||||
<div class="paper-dialog-buttons">
|
||||
<mwc-button
|
||||
@click="${this._updateEntry}"
|
||||
.disabled=${this._submitting}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entity_registry.editor.update"
|
||||
)}
|
||||
</mwc-button>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</ha-paper-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _disableNewEntitiesChanged(ev: PolymerChangedEvent<boolean>): void {
|
||||
this._error = undefined;
|
||||
this._disableNewEntities = !ev.detail.value;
|
||||
}
|
||||
|
||||
private async _updateEntry(): Promise<void> {
|
||||
this._submitting = true;
|
||||
try {
|
||||
await updateConfigEntrySystemOptions(
|
||||
this.hass,
|
||||
this._params!.entry.entry_id,
|
||||
{
|
||||
disable_new_entities: this._disableNewEntities,
|
||||
}
|
||||
);
|
||||
this._params = undefined;
|
||||
} catch (err) {
|
||||
this._error = err.message || "Unknown error";
|
||||
} finally {
|
||||
this._submitting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
|
||||
if (!(ev.detail as any).value) {
|
||||
this._params = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-paper-dialog {
|
||||
min-width: 400px;
|
||||
max-width: 500px;
|
||||
}
|
||||
.init-spinner {
|
||||
padding: 50px 100px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-config-entry-system-options": DialogConfigEntrySystemOptions;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { ConfigEntry } from "../../data/config_entries";
|
||||
|
||||
export interface ConfigEntrySystemOptionsDialogParams {
|
||||
entry: ConfigEntry;
|
||||
// updateEntry: (
|
||||
// updates: Partial<EntityRegistryEntryUpdateParams>
|
||||
// ) => Promise<unknown>;
|
||||
// removeEntry: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
export const loadConfigEntrySystemOptionsDialog = () =>
|
||||
import(/* webpackChunkName: "config-entry-system-options" */ "./dialog-config-entry-system-options");
|
||||
|
||||
export const showConfigEntrySystemOptionsDialog = (
|
||||
element: HTMLElement,
|
||||
systemLogDetailParams: ConfigEntrySystemOptionsDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-config-entry-system-options",
|
||||
dialogImport: loadConfigEntrySystemOptionsDialog,
|
||||
dialogParams: systemLogDetailParams,
|
||||
});
|
||||
};
|
@ -4,7 +4,7 @@ import {
|
||||
handleConfigFlowStep,
|
||||
deleteConfigFlow,
|
||||
createConfigFlow,
|
||||
} from "../../data/config_entries";
|
||||
} from "../../data/config_flow";
|
||||
import { html } from "lit-element";
|
||||
import { localizeKey } from "../../common/translations/localize";
|
||||
import {
|
||||
|
@ -3,14 +3,14 @@ import {
|
||||
handleOptionsFlowStep,
|
||||
deleteOptionsFlow,
|
||||
createOptionsFlow,
|
||||
ConfigEntry,
|
||||
} from "../../data/config_entries";
|
||||
} from "../../data/options_flow";
|
||||
import { html } from "lit-element";
|
||||
import { localizeKey } from "../../common/translations/localize";
|
||||
import {
|
||||
showFlowDialog,
|
||||
loadDataEntryFlowDialog,
|
||||
} from "./show-dialog-data-entry-flow";
|
||||
import { ConfigEntry } from "../../data/config_entries";
|
||||
|
||||
export const loadOptionsFlowDialog = loadDataEntryFlowDialog;
|
||||
|
||||
|
@ -14,16 +14,16 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
|
||||
import "../../../components/dialog/ha-paper-dialog";
|
||||
import "../../components/dialog/ha-paper-dialog";
|
||||
|
||||
import { DeviceRegistryDetailDialogParams } from "./show-dialog-device-registry-detail";
|
||||
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import {
|
||||
subscribeAreaRegistry,
|
||||
AreaRegistryEntry,
|
||||
} from "../../../data/area_registry";
|
||||
} from "../../data/area_registry";
|
||||
|
||||
@customElement("dialog-device-registry-detail")
|
||||
class DialogDeviceRegistryDetail extends LitElement {
|
||||
@ -74,7 +74,7 @@ class DialogDeviceRegistryDetail extends LitElement {
|
||||
opened
|
||||
@opened-changed="${this._openedChanged}"
|
||||
>
|
||||
<h2>${device.name}</h2>
|
||||
<h2>${device.name || "Unnamed device"}</h2>
|
||||
<paper-dialog-scrollable>
|
||||
${this._error
|
||||
? html`
|
@ -1,8 +1,8 @@
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import {
|
||||
DeviceRegistryEntry,
|
||||
DeviceRegistryEntryMutableParams,
|
||||
} from "../../../data/device_registry";
|
||||
} from "../../data/device_registry";
|
||||
|
||||
export interface DeviceRegistryDetailDialogParams {
|
||||
device: DeviceRegistryEntry;
|
@ -14,12 +14,7 @@ import {
|
||||
showConfigFlowDialog,
|
||||
} from "../dialogs/config-flow/show-dialog-config-flow";
|
||||
import { HomeAssistant } from "../types";
|
||||
import {
|
||||
getConfigFlowsInProgress,
|
||||
getConfigEntries,
|
||||
ConfigEntry,
|
||||
localizeConfigFlowTitle,
|
||||
} from "../data/config_entries";
|
||||
import { getConfigEntries, ConfigEntry } from "../data/config_entries";
|
||||
import { compare } from "../common/string/compare";
|
||||
import "./integration-badge";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
@ -28,6 +23,10 @@ import { fireEvent } from "../common/dom/fire_event";
|
||||
import { onboardIntegrationStep } from "../data/onboarding";
|
||||
import { genClientId } from "home-assistant-js-websocket";
|
||||
import { DataEntryFlowProgress } from "../data/data_entry_flow";
|
||||
import {
|
||||
localizeConfigFlowTitle,
|
||||
getConfigFlowsInProgress,
|
||||
} from "../data/config_flow";
|
||||
|
||||
@customElement("onboarding-integrations")
|
||||
class OnboardingIntegrations extends LitElement {
|
||||
|
@ -2,12 +2,13 @@ import {
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
PropertyDeclarations,
|
||||
CSSResult,
|
||||
TemplateResult,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import "../../../components/dialog/ha-paper-dialog";
|
||||
|
||||
@ -20,21 +21,13 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
class DialogEntityRegistryDetail extends LitElement {
|
||||
public hass!: HomeAssistant;
|
||||
private _name!: string;
|
||||
private _entityId!: string;
|
||||
private _error?: string;
|
||||
private _params?: EntityRegistryDetailDialogParams;
|
||||
private _submitting?: boolean;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
_error: {},
|
||||
_name: {},
|
||||
_entityId: {},
|
||||
_params: {},
|
||||
};
|
||||
}
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() private _name!: string;
|
||||
@property() private _entityId!: string;
|
||||
@property() private _disabledBy!: string | null;
|
||||
@property() private _error?: string;
|
||||
@property() private _params?: EntityRegistryDetailDialogParams;
|
||||
@property() private _submitting?: boolean;
|
||||
|
||||
public async showDialog(
|
||||
params: EntityRegistryDetailDialogParams
|
||||
@ -43,6 +36,7 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
this._error = undefined;
|
||||
this._name = this._params.entry.name || "";
|
||||
this._entityId = this._params.entry.entity_id;
|
||||
this._disabledBy = this._params.entry.disabled_by;
|
||||
await this.updateComplete;
|
||||
}
|
||||
|
||||
@ -62,7 +56,11 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
opened
|
||||
@opened-changed="${this._openedChanged}"
|
||||
>
|
||||
<h2>${entry.entity_id}</h2>
|
||||
<h2>
|
||||
${stateObj
|
||||
? computeStateName(stateObj)
|
||||
: entry.name || entry.entity_id}
|
||||
</h2>
|
||||
<paper-dialog-scrollable>
|
||||
${!stateObj
|
||||
? html`
|
||||
@ -96,6 +94,35 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
.invalid=${invalidDomainUpdate}
|
||||
.disabled=${this._submitting}
|
||||
></paper-input>
|
||||
<div class="row">
|
||||
<paper-toggle-button
|
||||
.checked=${!this._disabledBy}
|
||||
@checked-changed=${this._disabledByChanged}
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entity_registry.editor.enabled_label"
|
||||
)}
|
||||
</div>
|
||||
<div class="secondary">
|
||||
${this._disabledBy && this._disabledBy !== "user"
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.entity_registry.editor.enabled_cause",
|
||||
"cause",
|
||||
this.hass.localize(
|
||||
`config_entry.disabled_by.${this._disabledBy}`
|
||||
)
|
||||
)
|
||||
: ""}
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entity_registry.editor.enabled_description"
|
||||
)}
|
||||
<br />Note: this might not work yet with all integrations.
|
||||
</div>
|
||||
</div>
|
||||
</paper-toggle-button>
|
||||
</div>
|
||||
</div>
|
||||
</paper-dialog-scrollable>
|
||||
<div class="paper-dialog-buttons">
|
||||
@ -136,6 +163,7 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
try {
|
||||
await this._params!.updateEntry({
|
||||
name: this._name.trim() || null,
|
||||
disabled_by: this._disabledBy,
|
||||
new_entity_id: this._entityId.trim(),
|
||||
});
|
||||
this._params = undefined;
|
||||
@ -162,6 +190,9 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
this._params = undefined;
|
||||
}
|
||||
}
|
||||
private _disabledByChanged(ev: PolymerChangedEvent<boolean>): void {
|
||||
this._disabledBy = ev.detail.value ? null : "user";
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
@ -169,6 +200,7 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
css`
|
||||
ha-paper-dialog {
|
||||
min-width: 400px;
|
||||
max-width: 450px;
|
||||
}
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
@ -179,6 +211,13 @@ class DialogEntityRegistryDetail extends LitElement {
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
.row {
|
||||
margin-top: 8px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import {
|
||||
} from "./show-dialog-entity-registry-detail";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { compare } from "../../../common/string/compare";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
class HaConfigEntityRegistry extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@ -82,7 +83,11 @@ class HaConfigEntityRegistry extends LitElement {
|
||||
${this._entities.map((entry) => {
|
||||
const state = this.hass!.states[entry.entity_id];
|
||||
return html`
|
||||
<paper-icon-item @click=${this._openEditEntry} .entry=${entry}>
|
||||
<paper-icon-item
|
||||
@click=${this._openEditEntry}
|
||||
.entry=${entry}
|
||||
class=${classMap({ "disabled-entry": !!entry.disabled_by })}
|
||||
>
|
||||
<ha-icon
|
||||
slot="item-icon"
|
||||
.icon=${state
|
||||
@ -92,15 +97,20 @@ class HaConfigEntityRegistry extends LitElement {
|
||||
<paper-item-body two-line>
|
||||
<div class="name">
|
||||
${computeEntityRegistryName(this.hass!, entry) ||
|
||||
this.hass!.localize(
|
||||
"ui.panel.config.entity_registry.picker.unavailable"
|
||||
)}
|
||||
`(${this.hass!.localize("state.default.unavailable")})`}
|
||||
</div>
|
||||
<div class="secondary entity-id">
|
||||
${entry.entity_id}
|
||||
</div>
|
||||
</paper-item-body>
|
||||
<div class="platform">${entry.platform}</div>
|
||||
<div class="platform">
|
||||
${entry.platform}
|
||||
${entry.disabled_by
|
||||
? html`
|
||||
<br />(disabled)
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</paper-icon-item>
|
||||
`;
|
||||
})}
|
||||
@ -171,15 +181,23 @@ Deleting an entry will not remove the entity from Home Assistant. To do this, yo
|
||||
color: var(--primary-color);
|
||||
}
|
||||
ha-card {
|
||||
margin-bottom: 24px;
|
||||
direction: ltr;
|
||||
overflow: hidden;
|
||||
}
|
||||
paper-icon-item {
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
ha-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.platform {
|
||||
text-align: right;
|
||||
margin: 0 0 0 8px;
|
||||
}
|
||||
.disabled-entry {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ import "@polymer/paper-item/paper-item-body";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../layouts/hass-subpage";
|
||||
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixIn from "../../../mixins/localize-mixin";
|
||||
import "../../../components/entity/state-badge";
|
||||
import { computeEntityRegistryName } from "../../../data/entity_registry";
|
||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
||||
import LocalizeMixIn from "../../../../mixins/localize-mixin";
|
||||
import "../../../../components/entity/state-badge";
|
||||
import { computeEntityRegistryName } from "../../../../data/entity_registry";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixIn
|
@ -0,0 +1,204 @@
|
||||
import memoizeOne from "memoize-one";
|
||||
import "../../../../layouts/hass-subpage";
|
||||
import "../../../../layouts/hass-error-screen";
|
||||
|
||||
import "../../../../components/entity/state-badge";
|
||||
import { compare } from "../../../../common/string/compare";
|
||||
|
||||
import "./ha-device-card";
|
||||
import "./ha-ce-entities-card";
|
||||
import { showOptionsFlowDialog } from "../../../../dialogs/config-flow/show-dialog-options-flow";
|
||||
import { property, LitElement, CSSResult, css, html } from "lit-element";
|
||||
import { navigate } from "../../../../common/navigate";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import {
|
||||
ConfigEntry,
|
||||
deleteConfigEntry,
|
||||
} from "../../../../data/config_entries";
|
||||
import { EntityRegistryEntry } from "../../../../data/entity_registry";
|
||||
import { DeviceRegistryEntry } from "../../../../data/device_registry";
|
||||
import { AreaRegistryEntry } from "../../../../data/area_registry";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { showConfigEntrySystemOptionsDialog } from "../../../../dialogs/config-entry-system-options/show-dialog-config-entry-system-options";
|
||||
|
||||
class HaConfigEntryPage extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public narrow!: boolean;
|
||||
@property() public configEntryId!: string;
|
||||
@property() public configEntries!: ConfigEntry[];
|
||||
@property() public entityRegistryEntries!: EntityRegistryEntry[];
|
||||
@property() public deviceRegistryEntries!: DeviceRegistryEntry[];
|
||||
@property() public areas!: AreaRegistryEntry[];
|
||||
|
||||
private get _configEntry(): ConfigEntry | undefined {
|
||||
return this.configEntries
|
||||
? this.configEntries.find(
|
||||
(entry) => entry.entry_id === this.configEntryId
|
||||
)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
private _computeConfigEntryDevices = memoizeOne(
|
||||
(configEntry: ConfigEntry, devices: DeviceRegistryEntry[]) => {
|
||||
if (!devices) {
|
||||
return [];
|
||||
}
|
||||
return devices
|
||||
.filter((device) =>
|
||||
device.config_entries.includes(configEntry.entry_id)
|
||||
)
|
||||
.sort(
|
||||
(dev1, dev2) =>
|
||||
Number(!!dev1.via_device_id) - Number(!!dev2.via_device_id) ||
|
||||
compare(dev1.name || "", dev2.name || "")
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
private _computeNoDeviceEntities = memoizeOne(
|
||||
(configEntry: ConfigEntry, entities: EntityRegistryEntry[]) => {
|
||||
if (!entities) {
|
||||
return [];
|
||||
}
|
||||
return entities.filter(
|
||||
(ent) => !ent.device_id && ent.config_entry_id === configEntry.entry_id
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const configEntry = this._configEntry;
|
||||
|
||||
if (!configEntry) {
|
||||
return html`
|
||||
<hass-error-screen error="Integration not found."></hass-error-screen>
|
||||
`;
|
||||
}
|
||||
|
||||
const configEntryDevices = this._computeConfigEntryDevices(
|
||||
configEntry,
|
||||
this.deviceRegistryEntries
|
||||
);
|
||||
|
||||
const noDeviceEntities = this._computeNoDeviceEntities(
|
||||
configEntry,
|
||||
this.entityRegistryEntries
|
||||
);
|
||||
|
||||
return html`
|
||||
<hass-subpage .header=${configEntry.title}>
|
||||
${configEntry.supports_options
|
||||
? html`
|
||||
<paper-icon-button
|
||||
slot="toolbar-icon"
|
||||
icon="hass:settings"
|
||||
@click=${this._showSettings}
|
||||
></paper-icon-button>
|
||||
`
|
||||
: ""}
|
||||
<paper-icon-button
|
||||
slot="toolbar-icon"
|
||||
icon="hass:message-settings-variant"
|
||||
@click=${this._showSystemOptions}
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
slot="toolbar-icon"
|
||||
icon="hass:delete"
|
||||
@click=${this._removeEntry}
|
||||
></paper-icon-button>
|
||||
<div class="content">
|
||||
${configEntryDevices.length === 0 && noDeviceEntities.length === 0
|
||||
? html`
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.no_devices"
|
||||
)}
|
||||
</p>
|
||||
`
|
||||
: ""}
|
||||
${configEntryDevices.map(
|
||||
(device) => html`
|
||||
<ha-device-card
|
||||
class="card"
|
||||
.hass=${this.hass}
|
||||
.areas=${this.areas}
|
||||
.devices=${this.deviceRegistryEntries}
|
||||
.device=${device}
|
||||
.entities=${this.entityRegistryEntries}
|
||||
.narrow=${this.narrow}
|
||||
></ha-device-card>
|
||||
`
|
||||
)}
|
||||
${noDeviceEntities.length > 0
|
||||
? html`
|
||||
<ha-ce-entities-card
|
||||
class="card"
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.no_device"
|
||||
)}
|
||||
.entities=${noDeviceEntities}
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-ce-entities-card>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
private _showSettings() {
|
||||
showOptionsFlowDialog(this, this._configEntry!);
|
||||
}
|
||||
|
||||
private _showSystemOptions() {
|
||||
showConfigEntrySystemOptionsDialog(this, {
|
||||
entry: this._configEntry!,
|
||||
});
|
||||
}
|
||||
|
||||
private _removeEntry() {
|
||||
if (
|
||||
!confirm(
|
||||
this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.delete_confirm"
|
||||
)
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleteConfigEntry(this.hass, this.configEntryId).then((result) => {
|
||||
fireEvent(this, "hass-reload-entries");
|
||||
if (result.require_restart) {
|
||||
alert(
|
||||
this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.restart_confirm"
|
||||
)
|
||||
);
|
||||
}
|
||||
navigate(this, "/config/integrations/dashboard", true);
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: center;
|
||||
}
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1 0 300px;
|
||||
min-width: 0;
|
||||
max-width: 500px;
|
||||
padding: 8px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-config-entry-page", HaConfigEntryPage);
|
@ -6,24 +6,23 @@ import "@polymer/paper-listbox/paper-listbox";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../layouts/hass-subpage";
|
||||
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import "../../../components/entity/state-badge";
|
||||
import { compare } from "../../../common/string/compare";
|
||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
||||
import computeStateName from "../../../../common/entity/compute_state_name";
|
||||
import "../../../../components/entity/state-badge";
|
||||
import { compare } from "../../../../common/string/compare";
|
||||
import {
|
||||
subscribeDeviceRegistry,
|
||||
updateDeviceRegistryEntry,
|
||||
} from "../../../data/device_registry";
|
||||
import { subscribeAreaRegistry } from "../../../data/area_registry";
|
||||
|
||||
} from "../../../../data/device_registry";
|
||||
import { subscribeAreaRegistry } from "../../../../data/area_registry";
|
||||
import {
|
||||
showDeviceRegistryDetailDialog,
|
||||
loadDeviceRegistryDetailDialog,
|
||||
} from "./show-dialog-device-registry-detail";
|
||||
showDeviceRegistryDetailDialog,
|
||||
} from "../../../../dialogs/device-registry-detail/show-dialog-device-registry-detail";
|
||||
|
||||
function computeEntityName(hass, entity) {
|
||||
if (entity.name) return entity.name;
|
@ -23,7 +23,7 @@ import {
|
||||
loadConfigFlowDialog,
|
||||
showConfigFlowDialog,
|
||||
} from "../../../dialogs/config-flow/show-dialog-config-flow";
|
||||
import { localizeConfigFlowTitle } from "../../../data/config_entries";
|
||||
import { localizeConfigFlowTitle } from "../../../data/config_flow";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
@ -113,7 +113,7 @@ class HaConfigManagerDashboard extends LocalizeMixin(
|
||||
</div>
|
||||
</template>
|
||||
<template is="dom-repeat" items="[[entries]]">
|
||||
<a href="/config/integrations/[[item.entry_id]]">
|
||||
<a href="/config/integrations/config_entry/[[item.entry_id]]">
|
||||
<paper-item>
|
||||
<paper-item-body two-line>
|
||||
<div>
|
||||
@ -176,8 +176,6 @@ class HaConfigManagerDashboard extends LocalizeMixin(
|
||||
*/
|
||||
progress: Array,
|
||||
|
||||
handlers: Array,
|
||||
|
||||
rtl: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
|
@ -1,184 +0,0 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
import "../../../layouts/hass-subpage";
|
||||
|
||||
import "../../../components/entity/state-badge";
|
||||
import { compare } from "../../../common/string/compare";
|
||||
|
||||
import "./ha-device-card";
|
||||
import "./ha-ce-entities-card";
|
||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import NavigateMixin from "../../../mixins/navigate-mixin";
|
||||
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||
|
||||
class HaConfigEntryPage extends NavigateMixin(
|
||||
EventsMixin(LocalizeMixin(PolymerElement))
|
||||
) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
.content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px;
|
||||
justify-content: center;
|
||||
}
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1 0 300px;
|
||||
min-width: 0;
|
||||
max-width: 500px;
|
||||
padding: 8px;
|
||||
}
|
||||
</style>
|
||||
<hass-subpage header="[[configEntry.title]]">
|
||||
<template is="dom-if" if="[[configEntry.supports_options]]">
|
||||
<paper-icon-button
|
||||
slot="toolbar-icon"
|
||||
icon="hass:settings"
|
||||
on-click="_showSettings"
|
||||
></paper-icon-button>
|
||||
</template>
|
||||
<paper-icon-button
|
||||
slot="toolbar-icon"
|
||||
icon="hass:delete"
|
||||
on-click="_removeEntry"
|
||||
></paper-icon-button>
|
||||
<div class="content">
|
||||
<template
|
||||
is="dom-if"
|
||||
if="[[_computeIsEmpty(_configEntryDevices, _noDeviceEntities)]]"
|
||||
>
|
||||
<p>
|
||||
[[localize('ui.panel.config.integrations.config_entry.no_devices')]]
|
||||
</p>
|
||||
</template>
|
||||
<template is="dom-repeat" items="[[_configEntryDevices]]" as="device">
|
||||
<ha-device-card
|
||||
class="card"
|
||||
hass="[[hass]]"
|
||||
areas="[[areas]]"
|
||||
devices="[[devices]]"
|
||||
device="[[device]]"
|
||||
entities="[[entities]]"
|
||||
narrow="[[narrow]]"
|
||||
></ha-device-card>
|
||||
</template>
|
||||
<template is="dom-if" if="[[_noDeviceEntities.length]]">
|
||||
<ha-ce-entities-card
|
||||
class="card"
|
||||
heading="[[localize('ui.panel.config.integrations.config_entry.no_device')]]"
|
||||
entities="[[_noDeviceEntities]]"
|
||||
hass="[[hass]]"
|
||||
narrow="[[narrow]]"
|
||||
></ha-ce-entities-card>
|
||||
</template>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
isWide: Boolean,
|
||||
narrow: Boolean,
|
||||
configEntry: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
|
||||
_configEntryDevices: {
|
||||
type: Array,
|
||||
computed: "_computeConfigEntryDevices(configEntry, devices)",
|
||||
},
|
||||
|
||||
/**
|
||||
* All entity registry entries for this config entry that do not belong
|
||||
* to a device.
|
||||
*/
|
||||
_noDeviceEntities: {
|
||||
type: Array,
|
||||
computed: "_computeNoDeviceEntities(configEntry, entities)",
|
||||
},
|
||||
|
||||
/**
|
||||
* Area registry entries
|
||||
*/
|
||||
areas: Array,
|
||||
|
||||
/**
|
||||
* Device registry entries
|
||||
*/
|
||||
devices: Array,
|
||||
|
||||
/**
|
||||
* Existing entries.
|
||||
*/
|
||||
entries: Array,
|
||||
|
||||
/**
|
||||
* Entity Registry entries.
|
||||
*/
|
||||
entities: Array,
|
||||
};
|
||||
}
|
||||
|
||||
_computeConfigEntryDevices(configEntry, devices) {
|
||||
if (!devices) return [];
|
||||
return devices
|
||||
.filter((device) => device.config_entries.includes(configEntry.entry_id))
|
||||
.sort(
|
||||
(dev1, dev2) =>
|
||||
!!dev1.via_device_id - !!dev2.via_device_id ||
|
||||
compare(dev1.name, dev2.name)
|
||||
);
|
||||
}
|
||||
|
||||
_computeNoDeviceEntities(configEntry, entities) {
|
||||
if (!entities) return [];
|
||||
return entities.filter(
|
||||
(ent) => !ent.device_id && ent.config_entry_id === configEntry.entry_id
|
||||
);
|
||||
}
|
||||
|
||||
_computeIsEmpty(configEntryDevices, noDeviceEntities) {
|
||||
return configEntryDevices.length === 0 && noDeviceEntities.length === 0;
|
||||
}
|
||||
|
||||
_showSettings() {
|
||||
showOptionsFlowDialog(this, this.configEntry);
|
||||
}
|
||||
|
||||
_removeEntry() {
|
||||
if (
|
||||
!confirm(
|
||||
this.localize(
|
||||
"ui.panel.config.integrations.config_entry.delete_confirm"
|
||||
)
|
||||
)
|
||||
)
|
||||
return;
|
||||
|
||||
const entryId = this.configEntry.entry_id;
|
||||
|
||||
this.hass
|
||||
.callApi("delete", `config/config_entries/entry/${entryId}`)
|
||||
.then((result) => {
|
||||
this.fire("hass-reload-entries");
|
||||
if (result.require_restart) {
|
||||
alert(
|
||||
this.localize(
|
||||
"ui.panel.config.integrations.config_entry.restart_confirm"
|
||||
)
|
||||
);
|
||||
}
|
||||
this.navigate("/config/integrations/dashboard", true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-config-entry-page", HaConfigEntryPage);
|
@ -1,161 +0,0 @@
|
||||
import "@polymer/app-route/app-route";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { Debouncer } from "@polymer/polymer/lib/utils/debounce";
|
||||
import { timeOut } from "@polymer/polymer/lib/utils/async";
|
||||
|
||||
import "./ha-config-entries-dashboard";
|
||||
import "./ha-config-entry-page";
|
||||
import NavigateMixin from "../../../mixins/navigate-mixin";
|
||||
import { compare } from "../../../common/string/compare";
|
||||
import { subscribeAreaRegistry } from "../../../data/area_registry";
|
||||
|
||||
class HaConfigIntegrations extends NavigateMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<app-route
|
||||
route="[[route]]"
|
||||
pattern="/:page"
|
||||
data="{{_routeData}}"
|
||||
tail="{{_routeTail}}"
|
||||
></app-route>
|
||||
|
||||
<template is="dom-if" if="[[_configEntry]]">
|
||||
<ha-config-entry-page
|
||||
hass="[[hass]]"
|
||||
config-entry="[[_configEntry]]"
|
||||
areas="[[_areas]]"
|
||||
entries="[[_entries]]"
|
||||
entities="[[_entities]]"
|
||||
devices="[[_devices]]"
|
||||
narrow="[[narrow]]"
|
||||
></ha-config-entry-page>
|
||||
</template>
|
||||
<template is="dom-if" if="[[!_configEntry]]">
|
||||
<ha-config-entries-dashboard
|
||||
hass="[[hass]]"
|
||||
entries="[[_entries]]"
|
||||
entities="[[_entities]]"
|
||||
handlers="[[_handlers]]"
|
||||
progress="[[_progress]]"
|
||||
></ha-config-entries-dashboard>
|
||||
</template>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
isWide: Boolean,
|
||||
narrow: Boolean,
|
||||
route: Object,
|
||||
|
||||
_configEntry: {
|
||||
type: Object,
|
||||
computed: "_computeConfigEntry(_routeData, _entries)",
|
||||
},
|
||||
|
||||
/**
|
||||
* Existing entries.
|
||||
*/
|
||||
_entries: Array,
|
||||
|
||||
/**
|
||||
* Entity Registry entries.
|
||||
*/
|
||||
_entities: Array,
|
||||
|
||||
/**
|
||||
* Device Registry entries.
|
||||
*/
|
||||
_devices: Array,
|
||||
|
||||
/**
|
||||
* Area Registry entries.
|
||||
*/
|
||||
_areas: Array,
|
||||
|
||||
/**
|
||||
* Current flows that are in progress and have not been started by a user.
|
||||
* For example, can be discovered devices that require more config.
|
||||
*/
|
||||
_progress: Array,
|
||||
|
||||
_handlers: Array,
|
||||
|
||||
_routeData: Object,
|
||||
_routeTail: Object,
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener("hass-reload-entries", () => this._loadData());
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._loadData();
|
||||
this._unsubAreas = subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||
this._areas = areas;
|
||||
});
|
||||
|
||||
this.hass.connection
|
||||
.subscribeEvents(() => {
|
||||
this._debouncer = Debouncer.debounce(
|
||||
this._debouncer,
|
||||
timeOut.after(500),
|
||||
() => this._loadData()
|
||||
);
|
||||
}, "config_entry_discovered")
|
||||
.then((unsub) => {
|
||||
this._unsubEvents = unsub;
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._unsubEvents) this._unsubEvents();
|
||||
if (this._unsubAreas) this._unsubAreas();
|
||||
}
|
||||
|
||||
_loadData() {
|
||||
this.hass.callApi("get", "config/config_entries/entry").then((entries) => {
|
||||
this._entries = entries.sort((conf1, conf2) =>
|
||||
compare(conf1.title, conf2.title)
|
||||
);
|
||||
});
|
||||
|
||||
this.hass.callApi("get", "config/config_entries/flow").then((progress) => {
|
||||
this._progress = progress;
|
||||
});
|
||||
|
||||
this.hass
|
||||
.callApi("get", "config/config_entries/flow_handlers")
|
||||
.then((handlers) => {
|
||||
this._handlers = handlers;
|
||||
});
|
||||
|
||||
this.hass
|
||||
.callWS({ type: "config/entity_registry/list" })
|
||||
.then((entities) => {
|
||||
this._entities = entities;
|
||||
});
|
||||
|
||||
this.hass
|
||||
.callWS({ type: "config/device_registry/list" })
|
||||
.then((devices) => {
|
||||
this._devices = devices;
|
||||
});
|
||||
}
|
||||
|
||||
_computeConfigEntry(routeData, entries) {
|
||||
return (
|
||||
!!entries &&
|
||||
!!routeData &&
|
||||
entries.find((ent) => ent.entry_id === routeData.page)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-config-integrations", HaConfigIntegrations);
|
140
src/panels/config/integrations/ha-config-integrations.ts
Normal file
140
src/panels/config/integrations/ha-config-integrations.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import "@polymer/app-route/app-route";
|
||||
|
||||
import "./ha-config-entries-dashboard";
|
||||
import "./config-entry/ha-config-entry-page";
|
||||
import { compare } from "../../../common/string/compare";
|
||||
import {
|
||||
subscribeAreaRegistry,
|
||||
AreaRegistryEntry,
|
||||
} from "../../../data/area_registry";
|
||||
import {
|
||||
HassRouterPage,
|
||||
RouterOptions,
|
||||
} from "../../../layouts/hass-router-page";
|
||||
import { property, customElement, PropertyValues } from "lit-element";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
||||
import {
|
||||
EntityRegistryEntry,
|
||||
subscribeEntityRegistry,
|
||||
} from "../../../data/entity_registry";
|
||||
import {
|
||||
DeviceRegistryEntry,
|
||||
subscribeDeviceRegistry,
|
||||
} from "../../../data/device_registry";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { DataEntryFlowProgress } from "../../../data/data_entry_flow";
|
||||
import { subscribeConfigFlowInProgress } from "../../../data/config_flow";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"hass-reload-entries": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("ha-config-integrations")
|
||||
class HaConfigIntegrations extends HassRouterPage {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public narrow!: boolean;
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "dashboard",
|
||||
preloadAll: true,
|
||||
routes: {
|
||||
dashboard: {
|
||||
tag: "ha-config-entries-dashboard",
|
||||
},
|
||||
config_entry: {
|
||||
tag: "ha-config-entry-page",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@property() private _configEntries?: ConfigEntry[];
|
||||
@property() private _configEntriesInProgress?: DataEntryFlowProgress[];
|
||||
@property() private _entityRegistryEntries?: EntityRegistryEntry[];
|
||||
@property() private _deviceRegistryEntries?: DeviceRegistryEntry[];
|
||||
@property() private _areas?: AreaRegistryEntry[];
|
||||
|
||||
private _unsubs?: UnsubscribeFunc[];
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
if (!this.hass) {
|
||||
return;
|
||||
}
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._unsubs) {
|
||||
while (this._unsubs.length) {
|
||||
this._unsubs.pop()!();
|
||||
}
|
||||
this._unsubs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this.addEventListener("hass-reload-entries", () => this._loadData());
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (!this._unsubs && changedProps.has("hass")) {
|
||||
this._loadData();
|
||||
}
|
||||
}
|
||||
|
||||
protected updatePageEl(pageEl) {
|
||||
pageEl.hass = this.hass;
|
||||
|
||||
if (this._currentPage === "dashboard") {
|
||||
pageEl.entities = this._entityRegistryEntries;
|
||||
pageEl.entries = this._configEntries;
|
||||
pageEl.progress = this._configEntriesInProgress;
|
||||
return;
|
||||
}
|
||||
|
||||
pageEl.entityRegistryEntries = this._entityRegistryEntries;
|
||||
pageEl.configEntries = this._configEntries;
|
||||
pageEl.configEntryId = this.routeTail.path.substr(1);
|
||||
pageEl.deviceRegistryEntries = this._deviceRegistryEntries;
|
||||
pageEl.areas = this._areas;
|
||||
pageEl.narrow = this.narrow;
|
||||
}
|
||||
|
||||
private _loadData() {
|
||||
getConfigEntries(this.hass).then((configEntries) => {
|
||||
this._configEntries = configEntries.sort((conf1, conf2) =>
|
||||
compare(conf1.title, conf2.title)
|
||||
);
|
||||
});
|
||||
if (this._unsubs) {
|
||||
return;
|
||||
}
|
||||
this._unsubs = [
|
||||
subscribeAreaRegistry(this.hass.connection, (areas) => {
|
||||
this._areas = areas;
|
||||
}),
|
||||
subscribeEntityRegistry(this.hass.connection, (entries) => {
|
||||
this._entityRegistryEntries = entries;
|
||||
}),
|
||||
subscribeDeviceRegistry(this.hass.connection, (entries) => {
|
||||
this._deviceRegistryEntries = entries;
|
||||
}),
|
||||
subscribeConfigFlowInProgress(this.hass, (flowsInProgress) => {
|
||||
this._configEntriesInProgress = flowsInProgress;
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-config-integrations": HaConfigIntegrations;
|
||||
}
|
||||
}
|
@ -117,9 +117,11 @@ class HaPanelDevInfo extends LitElement {
|
||||
</mwc-button>
|
||||
</p>
|
||||
</div>
|
||||
<system-health-card .hass=${this.hass}></system-health-card>
|
||||
<system-log-card .hass=${this.hass}></system-log-card>
|
||||
<error-log-card .hass=${this.hass}></error-log-card>
|
||||
<div class="content">
|
||||
<system-health-card .hass=${this.hass}></system-health-card>
|
||||
<system-log-card .hass=${this.hass}></system-log-card>
|
||||
<error-log-card .hass=${this.hass}></error-log-card>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -155,7 +157,6 @@ class HaPanelDevInfo extends LitElement {
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px 0px 16px 0;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
css,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
@ -31,13 +32,29 @@ export class HuiEntityEditor extends LitElement {
|
||||
<div class="entities">
|
||||
${this.entities.map((entityConf, index) => {
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.hass="${this.hass}"
|
||||
.value="${entityConf.entity}"
|
||||
.index="${index}"
|
||||
@change="${this._valueChanged}"
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>
|
||||
<div class="entity">
|
||||
<ha-entity-picker
|
||||
.hass="${this.hass}"
|
||||
.value="${entityConf.entity}"
|
||||
.index="${index}"
|
||||
@change="${this._valueChanged}"
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>
|
||||
<paper-icon-button
|
||||
title="Move entity down"
|
||||
icon="hass:arrow-down"
|
||||
.index="${index}"
|
||||
@click="${this._entityDown}"
|
||||
?disabled="${index === this.entities!.length - 1}"
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
title="Move entity up"
|
||||
icon="hass:arrow-up"
|
||||
.index="${index}"
|
||||
@click="${this._entityUp}"
|
||||
?disabled="${index === 0}"
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<ha-entity-picker
|
||||
@ -60,6 +77,30 @@ export class HuiEntityEditor extends LitElement {
|
||||
fireEvent(this, "entities-changed", { entities: newConfigEntities });
|
||||
}
|
||||
|
||||
private _entityUp(ev: Event): void {
|
||||
const target = ev.target! as EditorTarget;
|
||||
const newEntities = this.entities!.concat();
|
||||
|
||||
[newEntities[target.index! - 1], newEntities[target.index!]] = [
|
||||
newEntities[target.index!],
|
||||
newEntities[target.index! - 1],
|
||||
];
|
||||
|
||||
fireEvent(this, "entities-changed", { entities: newEntities });
|
||||
}
|
||||
|
||||
private _entityDown(ev: Event): void {
|
||||
const target = ev.target! as EditorTarget;
|
||||
const newEntities = this.entities!.concat();
|
||||
|
||||
[newEntities[target.index! + 1], newEntities[target.index!]] = [
|
||||
newEntities[target.index!],
|
||||
newEntities[target.index! + 1],
|
||||
];
|
||||
|
||||
fireEvent(this, "entities-changed", { entities: newEntities });
|
||||
}
|
||||
|
||||
private _valueChanged(ev: Event): void {
|
||||
const target = ev.target! as EditorTarget;
|
||||
const newConfigEntities = this.entities!.concat();
|
||||
@ -81,6 +122,13 @@ export class HuiEntityEditor extends LitElement {
|
||||
.entities {
|
||||
padding-left: 20px;
|
||||
}
|
||||
.entity {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.entity ha-entity-picker {
|
||||
flex-grow: 1;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ export class HuiCardEditor extends LitElement {
|
||||
if (this._yamlEditor) {
|
||||
this._yamlEditor.codemirror.refresh();
|
||||
}
|
||||
fireEvent(this as HTMLElement, "iron-resize");
|
||||
}, 1);
|
||||
this._error = undefined;
|
||||
} catch (err) {
|
||||
|
@ -367,6 +367,13 @@
|
||||
"system-users": "Users",
|
||||
"system-read-only": "Read-Only Users"
|
||||
},
|
||||
"config_entry": {
|
||||
"disabled_by": {
|
||||
"user": "User",
|
||||
"integration": "Integration",
|
||||
"config_entry": "Config Entry"
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"auth_store": {
|
||||
"ask": "Do you want to save this login?",
|
||||
@ -538,6 +545,11 @@
|
||||
"success": {
|
||||
"description": "Options successfully saved."
|
||||
}
|
||||
},
|
||||
"config_entry_system_options": {
|
||||
"title": "System Options",
|
||||
"enable_new_entities_label": "Enable newly added entities.",
|
||||
"enable_new_entities_description": "If disabled, newly discovered entities will not be automatically added to Home Assistant."
|
||||
}
|
||||
},
|
||||
"duration": {
|
||||
@ -847,12 +859,14 @@
|
||||
"header": "Entity Registry",
|
||||
"introduction": "Home Assistant keeps a registry of every entity it has ever seen that can be uniquely identified. Each of these entities will have an entity ID assigned which will be reserved for just this entity.",
|
||||
"introduction2": "Use the entity registry to override the name, change the entity ID or remove the entry from Home Assistant. Note, removing the entity registry entry won't remove the entity. To do that, follow the link below and remove it from the integrations page.",
|
||||
"integrations_page": "Integrations page",
|
||||
"unavailable": "(unavailable)"
|
||||
"integrations_page": "Integrations page"
|
||||
},
|
||||
"editor": {
|
||||
"unavailable": "This entity is not currently available.",
|
||||
"default_name": "New Area",
|
||||
"enabled_label": "Enable entity",
|
||||
"enabled_cause": "Disabled by {cause}.",
|
||||
"enabled_description": "Disabled entities will not be added to Home Assistant.",
|
||||
"delete": "DELETE",
|
||||
"update": "UPDATE"
|
||||
}
|
||||
|
@ -320,7 +320,7 @@
|
||||
"title": "Esdeveniments"
|
||||
},
|
||||
"templates": {
|
||||
"title": "Plantilles"
|
||||
"title": "Plantilla"
|
||||
},
|
||||
"mqtt": {
|
||||
"title": "MQTT"
|
||||
@ -349,10 +349,10 @@
|
||||
"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": "Valida la configuració i controla el servidor",
|
||||
"description": "Canviar la configuració general de Home Assistant",
|
||||
"section": {
|
||||
"core": {
|
||||
"header": "Configuració i control del servidor",
|
||||
"header": "Configuració general",
|
||||
"introduction": "Sabem que canviar la configuració pot ser un procés molest. Aquesta secció intenta facilitar-te una mica més la vida.",
|
||||
"core_config": {
|
||||
"edit_requires_storage": "L'editor està desactivat ja que la configuració es troba a configuration.yaml.",
|
||||
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Instruccions d'actualització"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Opcions"
|
||||
},
|
||||
"success": {
|
||||
"description": "Opcions guardades amb èxit."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Opdateringsvejledning"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Indstillinger"
|
||||
},
|
||||
"success": {
|
||||
"description": "Indstillingerne blev gemt."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -777,7 +777,8 @@
|
||||
"core": "Hauptsystem neu laden",
|
||||
"group": "Gruppen neu laden",
|
||||
"automation": "Automatisierungen neu laden",
|
||||
"script": "Skripte neu laden"
|
||||
"script": "Skripte neu laden",
|
||||
"scene": "Szenen neu laden"
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Serververwaltung",
|
||||
@ -1293,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Update-Anweisungen"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Optionen"
|
||||
},
|
||||
"success": {
|
||||
"description": "Optionen wurden erfolgreich gespeichert."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Update Instructions"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Options"
|
||||
},
|
||||
"success": {
|
||||
"description": "Options successfully saved."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -352,7 +352,7 @@
|
||||
"description": "Cambiar la configuración general de Home Assistant",
|
||||
"section": {
|
||||
"core": {
|
||||
"header": "Configuración y control del servidor",
|
||||
"header": "Configuración general",
|
||||
"introduction": "Cambiar tu configuración puede ser un proceso tedioso. Lo sabemos. Esta sección tratará de hacer tu vida un poco más fácil.",
|
||||
"core_config": {
|
||||
"edit_requires_storage": "Editor deshabilitado debido a la configuración almacenada en configuration.yaml.",
|
||||
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Instrucciones de actualización"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Opciones"
|
||||
},
|
||||
"success": {
|
||||
"description": "Las opciones se guardaron correctamente."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
@ -1316,7 +1324,7 @@
|
||||
"climate": "Climatización",
|
||||
"configurator": "Configurador",
|
||||
"conversation": "Conversación",
|
||||
"cover": "Cubierta",
|
||||
"cover": "Persiana",
|
||||
"device_tracker": "Rastreador de dispositivo",
|
||||
"fan": "Ventilador",
|
||||
"history_graph": "Historial gráfico",
|
||||
|
@ -326,7 +326,7 @@
|
||||
"title": "MQTT"
|
||||
},
|
||||
"info": {
|
||||
"title": "Info"
|
||||
"title": "Informazioni"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -622,7 +622,7 @@
|
||||
"instance": "Esempio",
|
||||
"index": "Indice",
|
||||
"unknown": "sconosciuto",
|
||||
"wakeup_interval": "Intervallo di sveglia"
|
||||
"wakeup_interval": "Intervallo di riattivazione"
|
||||
},
|
||||
"values": {
|
||||
"header": "Valori del nodo"
|
||||
@ -634,7 +634,7 @@
|
||||
"config_parameter": "Parametro di configurazione",
|
||||
"config_value": "Valore di configurazione",
|
||||
"true": "Vero",
|
||||
"false": "False",
|
||||
"false": "Falso",
|
||||
"set_config_parameter": "Imposta parametro di configurazione"
|
||||
}
|
||||
},
|
||||
@ -773,7 +773,7 @@
|
||||
},
|
||||
"reloading": {
|
||||
"heading": "Ricaricamento della configurazione",
|
||||
"introduction": "Alcune parti di Home Assistant possono essere ricaricate senza richiedere il riavvio. Cliccando su ricarica si rimuoverà la loro configurazione corrente e si caricherà quella nuova.",
|
||||
"introduction": "Alcune parti di Home Assistant possono essere ricaricate senza richiedere il riavvio. Cliccando su ricarica si rimuoverà la loro configurazione attuale e si caricherà la versione aggiornata.",
|
||||
"core": "Ricarica core",
|
||||
"group": "Ricarica i gruppi",
|
||||
"automation": "Ricarica automazioni",
|
||||
@ -1075,7 +1075,7 @@
|
||||
"demo_by": "di {name}",
|
||||
"next_demo": "Prossima demo",
|
||||
"introduction": "Benvenuto a casa! Questa è la demo di Home Assistant, qui pubblichiamo le migliori interfacce utente create dalla nostra community.",
|
||||
"learn_more": "Ulteriori informazioni su Home Assistant"
|
||||
"learn_more": "Scopri di più su Home Assistant"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Istruzioni per l'aggiornamento"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Opzioni"
|
||||
},
|
||||
"success": {
|
||||
"description": "Opzioni salvate correttamente."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "업데이트 방법"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "옵션"
|
||||
},
|
||||
"success": {
|
||||
"description": "옵션이 성공적으로 저장되었습니다."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Instruktioune fir d'Mise à jour"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Optiounen"
|
||||
},
|
||||
"success": {
|
||||
"description": "Optiounen erfollegräich gespäichert."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -352,7 +352,7 @@
|
||||
"description": "Wijzig je algemene Home Assistant configuratie",
|
||||
"section": {
|
||||
"core": {
|
||||
"header": "Configuratie en serverbeheer",
|
||||
"header": "Algemene Configuratie",
|
||||
"introduction": "Het aanpassen van je configuratie kan een moeizaam proces zijn. Dat weten we. Dit onderdeel probeert je het leven iets makkelijker te maken.",
|
||||
"core_config": {
|
||||
"edit_requires_storage": "Editor uitgeschakeld omdat de configuratie is opgeslagen in configuration.yaml",
|
||||
@ -777,7 +777,8 @@
|
||||
"core": "Herlaad kern",
|
||||
"group": "Herlaad groepen",
|
||||
"automation": "Herlaad automatiseringen",
|
||||
"script": "Herlaad scripts"
|
||||
"script": "Herlaad scripts",
|
||||
"scene": "Herlaad scenes"
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Serverbeheer",
|
||||
@ -1293,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Update-instructies"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Instellingen"
|
||||
},
|
||||
"success": {
|
||||
"description": "Instellingen succesvol opgeslagen."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Instrukcje aktualizacji"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Opcje"
|
||||
},
|
||||
"success": {
|
||||
"description": "Opcje zapisane pomyślnie."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -608,8 +608,8 @@
|
||||
"services": {
|
||||
"start_network": "Включить",
|
||||
"stop_network": "Отключить",
|
||||
"heal_network": "Исправить",
|
||||
"test_network": "Тестировать",
|
||||
"heal_network": "Исправить сеть",
|
||||
"test_network": "Тестировать ",
|
||||
"soft_reset": "Сброс",
|
||||
"save_config": "Сохранить конфигурацию",
|
||||
"add_node_secure": "Добавить защищенный узел",
|
||||
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Инструкция по обновлению"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Параметры"
|
||||
},
|
||||
"success": {
|
||||
"description": "Параметры успешно сохранены."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -732,7 +732,8 @@
|
||||
"core": "Znovu načítať jadro",
|
||||
"group": "Znovu načítať skupiny",
|
||||
"automation": "Znovu načítať automatizácie",
|
||||
"script": "Znovu načítať skripty"
|
||||
"script": "Znovu načítať skripty",
|
||||
"scene": "Znovu načítať scény"
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Správa servera",
|
||||
|
@ -620,12 +620,21 @@
|
||||
"common": {
|
||||
"value": "Vrednost",
|
||||
"instance": "Instanca",
|
||||
"index": "Indeks"
|
||||
"index": "Indeks",
|
||||
"unknown": "Neznano",
|
||||
"wakeup_interval": "Interval bujenja"
|
||||
},
|
||||
"values": {
|
||||
"header": "Vrednosti vozlišča"
|
||||
},
|
||||
"node_config": {
|
||||
"header": "Možnosti konfiguracije vozlišča",
|
||||
"seconds": "Sekund",
|
||||
"set_wakeup": "Nastavite Interval bujenja",
|
||||
"config_parameter": "Vrednostni parameter",
|
||||
"config_value": "vrednost nastavite",
|
||||
"true": "Prav",
|
||||
"false": "Lažno",
|
||||
"set_config_parameter": "Nastavite Config Parameter"
|
||||
}
|
||||
},
|
||||
@ -768,7 +777,8 @@
|
||||
"core": "Ponovno naloži jedro",
|
||||
"group": "Ponovno naloži skupine",
|
||||
"automation": "Ponovno naloži avtomatizacije",
|
||||
"script": "Ponovno naloži skripte"
|
||||
"script": "Ponovno naloži skripte",
|
||||
"scene": "Ponovno naloži scene"
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Upravljanje strežnika",
|
||||
@ -1284,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Navodila za posodabitev"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Možnosti"
|
||||
},
|
||||
"success": {
|
||||
"description": "Možnosti so uspešno shranjene."
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -129,11 +129,11 @@
|
||||
"climate": {
|
||||
"off": "Av",
|
||||
"on": "På",
|
||||
"heat": "Värmer",
|
||||
"cool": "Kyler",
|
||||
"heat": "Värme",
|
||||
"cool": "Kyla",
|
||||
"idle": "Inaktiv",
|
||||
"auto": "Automatisk",
|
||||
"dry": "Avfuktar",
|
||||
"dry": "Avfuktning",
|
||||
"fan_only": "Endast fläkt",
|
||||
"eco": "Eco",
|
||||
"electric": "Elektrisk",
|
||||
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "Uppdateringsanvisningar"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "Inställningar"
|
||||
},
|
||||
"success": {
|
||||
"description": "Inställningar sparade"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
@ -1377,9 +1385,9 @@
|
||||
},
|
||||
"hvac_action": {
|
||||
"off": "Av",
|
||||
"heating": "Uppvärmning",
|
||||
"cooling": "Kyla",
|
||||
"drying": "Avfuktning",
|
||||
"heating": "Värmer",
|
||||
"cooling": "Kyler",
|
||||
"drying": "Avfuktar",
|
||||
"idle": "Inaktiv",
|
||||
"fan": "Fläkt"
|
||||
}
|
||||
|
@ -596,7 +596,20 @@
|
||||
"network_management": {
|
||||
"header": "Z-Wave网络管理"
|
||||
},
|
||||
"network_status": {
|
||||
"network_stopped": "Z-Wave网络已停止",
|
||||
"network_starting": "启动Z-Wave网络......",
|
||||
"network_starting_note": "这可能需要一段时间,具体取决于您的网络规模。",
|
||||
"network_started": "Z-Wave网络开始",
|
||||
"network_started_note_some_queried": "已查询唤醒节点。睡眠节点将在唤醒时被查询。",
|
||||
"network_started_note_all_queried": "已查询所有节点。"
|
||||
},
|
||||
"services": {
|
||||
"start_network": "启动网络",
|
||||
"stop_network": "停止网络",
|
||||
"heal_network": "修复网络",
|
||||
"test_network": "测试网络",
|
||||
"soft_reset": "软复位",
|
||||
"save_config": "保存配置",
|
||||
"add_node": "添加节点",
|
||||
"remove_node": "删除节点",
|
||||
@ -604,9 +617,15 @@
|
||||
},
|
||||
"common": {
|
||||
"value": "值",
|
||||
"instance": "实例"
|
||||
"instance": "实例",
|
||||
"unknown": "未知",
|
||||
"wakeup_interval": "唤醒时间间隔"
|
||||
},
|
||||
"node_config": {
|
||||
"header": "节点配置选项",
|
||||
"seconds": "秒",
|
||||
"set_wakeup": "设置唤醒间隔",
|
||||
"config_parameter": "配置参数",
|
||||
"set_config_parameter": "设置配置参数"
|
||||
}
|
||||
},
|
||||
@ -731,6 +750,29 @@
|
||||
"device_tracker_picked": "跟踪设备",
|
||||
"device_tracker_pick": "选择要跟踪的设备"
|
||||
}
|
||||
},
|
||||
"server_control": {
|
||||
"section": {
|
||||
"validation": {
|
||||
"heading": "配置有效性",
|
||||
"check_config": "配置检查",
|
||||
"valid": "配置有效!",
|
||||
"invalid": "配置无效"
|
||||
},
|
||||
"reloading": {
|
||||
"heading": "配置重载中",
|
||||
"core": "重载核心模块",
|
||||
"group": "重载分组",
|
||||
"automation": "重载自动化",
|
||||
"script": "重载脚本",
|
||||
"scene": "重载场景"
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "服务器管理",
|
||||
"restart": "重新启动",
|
||||
"stop": "停止服务"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
@ -1238,6 +1280,14 @@
|
||||
"updater": {
|
||||
"title": "更新说明"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "选项"
|
||||
},
|
||||
"success": {
|
||||
"description": "选项已成功保存。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
@ -1294,6 +1294,14 @@
|
||||
"updater": {
|
||||
"title": "更新說明"
|
||||
}
|
||||
},
|
||||
"options_flow": {
|
||||
"form": {
|
||||
"header": "選項"
|
||||
},
|
||||
"success": {
|
||||
"description": "選項已儲存。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_store": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user