From d8bab6aba943d256799766de1113e9b574cf316e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 31 May 2021 15:40:50 -0700 Subject: [PATCH] Add support for disable polling system option (#9316) --- gallery/src/demos/demo-integration-card.ts | 12 +- src/data/config_entries.ts | 17 +- .../dialog-config-entry-system-options.ts | 166 ++++++++++-------- ...show-dialog-config-entry-system-options.ts | 7 +- .../integrations/ha-integration-card.ts | 6 + .../integrations/ha-integration-header.ts | 14 +- src/translations/en.json | 6 +- 7 files changed, 138 insertions(+), 90 deletions(-) diff --git a/gallery/src/demos/demo-integration-card.ts b/gallery/src/demos/demo-integration-card.ts index 1e23303bc4..97e581f2cc 100644 --- a/gallery/src/demos/demo-integration-card.ts +++ b/gallery/src/demos/demo-integration-card.ts @@ -28,10 +28,13 @@ const createConfigEntry = ( title, source: "zeroconf", state: "loaded", - connection_class: "local_push", supports_options: false, supports_unload: true, disabled_by: null, + system_options: { + disable_new_entities: false, + disable_polling: false, + }, reason: null, ...override, }); @@ -64,6 +67,12 @@ const configPanelEntry = createConfigEntry("Config Panel", { const optionsFlowEntry = createConfigEntry("Options Flow", { supports_options: true, }); +const disabledPollingEntry = createConfigEntry("Disabled Polling", { + system_options: { + disable_new_entities: false, + disable_polling: true, + }, +}); const setupErrorEntry = createConfigEntry("Setup Error", { state: "setup_error", }); @@ -136,6 +145,7 @@ const configEntries: Array<{ { items: [loadedEntry] }, { items: [configPanelEntry] }, { items: [optionsFlowEntry] }, + { items: [disabledPollingEntry] }, { items: [nameAsDomainEntry] }, { items: [longNameEntry] }, { items: [longNonBreakingNameEntry] }, diff --git a/src/data/config_entries.ts b/src/data/config_entries.ts index 9bb203c942..8e4de41a9e 100644 --- a/src/data/config_entries.ts +++ b/src/data/config_entries.ts @@ -12,9 +12,9 @@ export interface ConfigEntry { | "setup_retry" | "not_loaded" | "failed_unload"; - connection_class: string; supports_options: boolean; supports_unload: boolean; + system_options: ConfigEntrySystemOptions; disabled_by: "user" | null; reason: string | null; } @@ -25,6 +25,7 @@ export interface ConfigEntryMutableParams { export interface ConfigEntrySystemOptions { disable_new_entities: boolean; + disable_polling: boolean; } export const getConfigEntries = (hass: HomeAssistant) => @@ -72,21 +73,15 @@ export const enableConfigEntry = (hass: HomeAssistant, configEntryId: string) => disabled_by: null, }); -export const getConfigEntrySystemOptions = ( - hass: HomeAssistant, - configEntryId: string -) => - hass.callWS({ - type: "config_entries/system_options/list", - entry_id: configEntryId, - }); - export const updateConfigEntrySystemOptions = ( hass: HomeAssistant, configEntryId: string, params: Partial ) => - hass.callWS({ + hass.callWS<{ + require_restart: boolean; + system_options: ConfigEntrySystemOptions; + }>({ type: "config_entries/system_options/update", entry_id: configEntryId, ...params, diff --git a/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts b/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts index bd1f6bbcd1..92cac06fef 100644 --- a/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts +++ b/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts @@ -3,17 +3,14 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { computeRTLDirection } from "../../common/util/compute_rtl"; -import "../../components/ha-circular-progress"; import "../../components/ha-dialog"; import "../../components/ha-formfield"; import "../../components/ha-switch"; import type { HaSwitch } from "../../components/ha-switch"; -import { - getConfigEntrySystemOptions, - updateConfigEntrySystemOptions, -} from "../../data/config_entries"; +import { updateConfigEntrySystemOptions } from "../../data/config_entries"; import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; +import { showAlertDialog } from "../generic/show-dialog-box"; import { ConfigEntrySystemOptionsDialogParams } from "./show-dialog-config-entry-system-options"; @customElement("dialog-config-entry-system-options") @@ -22,12 +19,12 @@ class DialogConfigEntrySystemOptions extends LitElement { @state() private _disableNewEntities!: boolean; + @state() private _disablePolling!: boolean; + @state() private _error?: string; @state() private _params?: ConfigEntrySystemOptionsDialogParams; - @state() private _loading = false; - @state() private _submitting = false; public async showDialog( @@ -35,13 +32,8 @@ class DialogConfigEntrySystemOptions extends LitElement { ): Promise { 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; + this._disableNewEntities = params.entry.system_options.disable_new_entities; + this._disablePolling = params.entry.system_options.disable_polling; } public closeDialog(): void { @@ -66,45 +58,57 @@ class DialogConfigEntrySystemOptions extends LitElement { this._params.entry.domain )} > -
- ${this._loading - ? html` -
- -
- ` - : html` - ${this._error - ? html`
${this._error}
` - : ""} -
- - ${this.hass.localize( - "ui.dialogs.config_entry_system_options.enable_new_entities_label" - )} -

-

- ${this.hass.localize( - "ui.dialogs.config_entry_system_options.enable_new_entities_description", - "integration", - this.hass.localize( - `component.${this._params.entry.domain}.title` - ) || this._params.entry.domain - )} -

`} - .dir=${computeRTLDirection(this.hass)} - > - - -
-
- `} -
+ ${this._error ? html`
${this._error}
` : ""} + + ${this.hass.localize( + "ui.dialogs.config_entry_system_options.enable_new_entities_label" + )} +

+

+ ${this.hass.localize( + "ui.dialogs.config_entry_system_options.enable_new_entities_description", + "integration", + this.hass.localize( + `component.${this._params.entry.domain}.title` + ) || this._params.entry.domain + )} +

`} + .dir=${computeRTLDirection(this.hass)} + > + +
+ ${this._allowUpdatePolling() + ? html` + + ${this.hass.localize( + "ui.dialogs.config_entry_system_options.enable_polling_label" + )} +

+

+ ${this.hass.localize( + "ui.dialogs.config_entry_system_options.enable_polling_description", + "integration", + this.hass.localize( + `component.${this._params.entry.domain}.title` + ) || this._params.entry.domain + )} +

`} + .dir=${computeRTLDirection(this.hass)} + > + +
+ ` + : ""} ${this.hass.localize("ui.dialogs.config_entry_system_options.update")} @@ -123,21 +127,53 @@ class DialogConfigEntrySystemOptions extends LitElement { `; } + private _allowUpdatePolling() { + return ( + this._params!.manifest && + (this._params!.manifest.iot_class === "local_polling" || + this._params!.manifest.iot_class === "cloud_polling") + ); + } + private _disableNewEntitiesChanged(ev: Event): void { this._error = undefined; this._disableNewEntities = !(ev.target as HaSwitch).checked; } + private _disablePollingChanged(ev: Event): void { + this._error = undefined; + this._disablePolling = !(ev.target as HaSwitch).checked; + } + private async _updateEntry(): Promise { this._submitting = true; + const data: Parameters[2] = { + disable_new_entities: this._disableNewEntities, + }; + if (this._allowUpdatePolling()) { + data.disable_polling = this._disablePolling; + } try { - await updateConfigEntrySystemOptions( + const result = await updateConfigEntrySystemOptions( this.hass, this._params!.entry.entry_id, - { - disable_new_entities: this._disableNewEntities, - } + data ); + if (result.require_restart) { + await showAlertDialog(this, { + text: this.hass.localize( + "ui.dialogs.config_entry_system_options.restart_home_assistant" + ), + }); + } + const curEntry = this._params!.entry; + this._params!.entryUpdated({ + ...curEntry, + system_options: { + ...curEntry.system_options, + ...data, + }, + }); this._params = undefined; } catch (err) { this._error = err.message || "Unknown error"; @@ -150,20 +186,6 @@ class DialogConfigEntrySystemOptions extends LitElement { return [ haStyleDialog, css` - .init-spinner { - padding: 50px 100px; - text-align: center; - } - - .form { - padding-top: 6px; - padding-bottom: 24px; - color: var(--primary-text-color); - } - .secondary { - color: var(--secondary-text-color); - } - .error { color: var(--error-color); } diff --git a/src/dialogs/config-entry-system-options/show-dialog-config-entry-system-options.ts b/src/dialogs/config-entry-system-options/show-dialog-config-entry-system-options.ts index 6b8a6c0329..77415e02cd 100644 --- a/src/dialogs/config-entry-system-options/show-dialog-config-entry-system-options.ts +++ b/src/dialogs/config-entry-system-options/show-dialog-config-entry-system-options.ts @@ -1,12 +1,11 @@ import { fireEvent } from "../../common/dom/fire_event"; import { ConfigEntry } from "../../data/config_entries"; +import { IntegrationManifest } from "../../data/integration"; export interface ConfigEntrySystemOptionsDialogParams { entry: ConfigEntry; - // updateEntry: ( - // updates: Partial - // ) => Promise; - // removeEntry: () => Promise; + manifest?: IntegrationManifest; + entryUpdated(entry: ConfigEntry): void; } export const loadConfigEntrySystemOptionsDialog = () => diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index cbd7de5aab..4e2a103c48 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -110,6 +110,7 @@ export class HaIntegrationCard extends LitElement { : undefined} .localizedDomainName=${item ? item.localized_domain_name : undefined} .manifest=${this.manifest} + .configEntry=${item} > ${this.items.length > 1 ? html` @@ -466,6 +467,11 @@ export class HaIntegrationCard extends LitElement { private _showSystemOptions(configEntry: ConfigEntry) { showConfigEntrySystemOptionsDialog(this, { entry: configEntry, + manifest: this.manifest, + entryUpdated: (entry) => + fireEvent(this, "entry-updated", { + entry, + }), }); } diff --git a/src/panels/config/integrations/ha-integration-header.ts b/src/panels/config/integrations/ha-integration-header.ts index cd189da48b..d18ba01670 100644 --- a/src/panels/config/integrations/ha-integration-header.ts +++ b/src/panels/config/integrations/ha-integration-header.ts @@ -1,8 +1,9 @@ -import { mdiCloud, mdiPackageVariant } from "@mdi/js"; +import { mdiCloud, mdiPackageVariant, mdiSyncOff } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import "../../../components/ha-svg-icon"; +import { ConfigEntry } from "../../../data/config_entries"; import { domainToName, IntegrationManifest } from "../../../data/integration"; import { HomeAssistant } from "../../../types"; import { brandsUrl } from "../../../util/brands-url"; @@ -21,6 +22,8 @@ export class HaIntegrationHeader extends LitElement { @property({ attribute: false }) public manifest?: IntegrationManifest; + @property({ attribute: false }) public configEntry?: ConfigEntry; + protected render(): TemplateResult { let primary: string; let secondary: string | undefined; @@ -59,6 +62,15 @@ export class HaIntegrationHeader extends LitElement { ), ]); } + + if (this.configEntry?.system_options.disable_polling) { + icons.push([ + mdiSyncOff, + this.hass.localize( + "ui.panel.config.integrations.config_entry.disabled_polling" + ), + ]); + } } return html` diff --git a/src/translations/en.json b/src/translations/en.json index 584e25f33e..dae343b3c2 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -759,7 +759,10 @@ "config_entry_system_options": { "title": "System Options for {integration}", "enable_new_entities_label": "Enable newly added entities.", - "enable_new_entities_description": "If disabled, newly discovered entities for {integration} will not be automatically added to Home Assistant.", + "enable_new_entities_description": "If newly discovered devices for {integration} should be automatically added.", + "enable_polling_label": "Enable polling for updates.", + "enable_polling_description": "If Home Assistant should automatically poll {integration} entities for updates.", + "restart_home_assistant": "You need to restart Home Assistant for your changes to take effect.", "update": "Update" }, "zha_reconfigure_device": { @@ -2182,6 +2185,7 @@ }, "provided_by_custom_integration": "Provided by a custom integration", "depends_on_cloud": "Depends on the cloud", + "disabled_polling": "Automatic polling for updated data disabled", "state": { "loaded": "Loaded", "setup_error": "Failed to set up",