Migrate integrations page to TypeScript (#3500)

This commit is contained in:
Paulus Schoutsen 2019-08-19 15:12:57 -07:00 committed by GitHub
parent 6c109c15ef
commit 355e3d7911
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 457 additions and 470 deletions

View File

@ -1,8 +1,4 @@
import { HomeAssistant } from "../types"; 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 { export interface ConfigEntry {
entry_id: string; entry_id: string;
@ -14,114 +10,10 @@ export interface ConfigEntry {
supports_options: boolean; 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) => export const getConfigEntries = (hass: HomeAssistant) =>
hass.callApi<ConfigEntry[]>("GET", "config/config_entries/entry"); hass.callApi<ConfigEntry[]>("GET", "config/config_entries/entry");
export const localizeConfigFlowTitle = ( export const deleteConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
localize: LocalizeFunc, hass.callApi<{
flow: DataEntryFlowProgress require_restart: boolean;
) => { }>("DELETE", `config/config_entries/entry/${configEntryId}`);
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}`);

83
src/data/config_flow.ts Normal file
View 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
View 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}`);

View File

@ -4,7 +4,7 @@ import {
handleConfigFlowStep, handleConfigFlowStep,
deleteConfigFlow, deleteConfigFlow,
createConfigFlow, createConfigFlow,
} from "../../data/config_entries"; } from "../../data/config_flow";
import { html } from "lit-element"; import { html } from "lit-element";
import { localizeKey } from "../../common/translations/localize"; import { localizeKey } from "../../common/translations/localize";
import { import {

View File

@ -3,14 +3,14 @@ import {
handleOptionsFlowStep, handleOptionsFlowStep,
deleteOptionsFlow, deleteOptionsFlow,
createOptionsFlow, createOptionsFlow,
ConfigEntry, } from "../../data/options_flow";
} from "../../data/config_entries";
import { html } from "lit-element"; import { html } from "lit-element";
import { localizeKey } from "../../common/translations/localize"; import { localizeKey } from "../../common/translations/localize";
import { import {
showFlowDialog, showFlowDialog,
loadDataEntryFlowDialog, loadDataEntryFlowDialog,
} from "./show-dialog-data-entry-flow"; } from "./show-dialog-data-entry-flow";
import { ConfigEntry } from "../../data/config_entries";
export const loadOptionsFlowDialog = loadDataEntryFlowDialog; export const loadOptionsFlowDialog = loadDataEntryFlowDialog;

View File

@ -14,12 +14,7 @@ import {
showConfigFlowDialog, showConfigFlowDialog,
} from "../dialogs/config-flow/show-dialog-config-flow"; } from "../dialogs/config-flow/show-dialog-config-flow";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
import { import { getConfigEntries, ConfigEntry } from "../data/config_entries";
getConfigFlowsInProgress,
getConfigEntries,
ConfigEntry,
localizeConfigFlowTitle,
} from "../data/config_entries";
import { compare } from "../common/string/compare"; import { compare } from "../common/string/compare";
import "./integration-badge"; import "./integration-badge";
import { LocalizeFunc } from "../common/translations/localize"; import { LocalizeFunc } from "../common/translations/localize";
@ -28,6 +23,10 @@ import { fireEvent } from "../common/dom/fire_event";
import { onboardIntegrationStep } from "../data/onboarding"; import { onboardIntegrationStep } from "../data/onboarding";
import { genClientId } from "home-assistant-js-websocket"; import { genClientId } from "home-assistant-js-websocket";
import { DataEntryFlowProgress } from "../data/data_entry_flow"; import { DataEntryFlowProgress } from "../data/data_entry_flow";
import {
localizeConfigFlowTitle,
getConfigFlowsInProgress,
} from "../data/config_flow";
@customElement("onboarding-integrations") @customElement("onboarding-integrations")
class OnboardingIntegrations extends LitElement { class OnboardingIntegrations extends LitElement {

View File

@ -23,7 +23,7 @@ import {
loadConfigFlowDialog, loadConfigFlowDialog,
showConfigFlowDialog, showConfigFlowDialog,
} from "../../../dialogs/config-flow/show-dialog-config-flow"; } from "../../../dialogs/config-flow/show-dialog-config-flow";
import { localizeConfigFlowTitle } from "../../../data/config_entries"; import { localizeConfigFlowTitle } from "../../../data/config_flow";
/* /*
* @appliesMixin LocalizeMixin * @appliesMixin LocalizeMixin
@ -113,7 +113,7 @@ class HaConfigManagerDashboard extends LocalizeMixin(
</div> </div>
</template> </template>
<template is="dom-repeat" items="[[entries]]"> <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>
<paper-item-body two-line> <paper-item-body two-line>
<div> <div>
@ -176,8 +176,6 @@ class HaConfigManagerDashboard extends LocalizeMixin(
*/ */
progress: Array, progress: Array,
handlers: Array,
rtl: { rtl: {
type: Boolean, type: Boolean,
reflectToAttribute: true, reflectToAttribute: true,

View File

@ -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);

View 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);

View File

@ -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);

View 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;
}
}