mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 11:46:42 +00:00
Migrate integrations page to TypeScript (#3500)
This commit is contained in:
parent
6c109c15ef
commit
355e3d7911
@ -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,10 @@ 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 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);
|
||||
};
|
||||
|
||||
// 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 = (
|
||||
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}`);
|
||||
export const deleteConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
|
||||
hass.callApi<{
|
||||
require_restart: boolean;
|
||||
}>("DELETE", `config/config_entries/entry/${configEntryId}`);
|
||||
|
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/config_entries/flow",
|
||||
});
|
||||
|
||||
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);
|
||||
};
|
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}`);
|
@ -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,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 {
|
||||
|
@ -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);
|
189
src/panels/config/integrations/ha-config-entry-page.ts
Normal file
189
src/panels/config/integrations/ha-config-entry-page.ts
Normal file
@ -0,0 +1,189 @@
|
||||
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";
|
||||
|
||||
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: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 _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);
|
@ -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 "./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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user