Add ignore discovery button (#4354)

* Add ignore discovery button

* Add seperate list for ignored integrations

* Move translations

* Add zeroconf
This commit is contained in:
Bram Kragten 2019-12-18 16:22:17 +01:00 committed by Paulus Schoutsen
parent dd17a153d2
commit 2c57ab60f1
4 changed files with 202 additions and 49 deletions

View File

@ -4,6 +4,8 @@ import { debounce } from "../common/util/debounce";
import { getCollection, Connection } from "home-assistant-js-websocket"; import { getCollection, Connection } from "home-assistant-js-websocket";
import { LocalizeFunc } from "../common/translations/localize"; import { LocalizeFunc } from "../common/translations/localize";
export const DISCOVERY_SOURCES = ["homekit", "ssdp", "zeroconf"];
export const createConfigFlow = (hass: HomeAssistant, handler: string) => export const createConfigFlow = (hass: HomeAssistant, handler: string) =>
hass.callApi<DataEntryFlowStep>("POST", "config/config_entries/flow", { hass.callApi<DataEntryFlowStep>("POST", "config/config_entries/flow", {
handler, handler,
@ -26,6 +28,9 @@ export const handleConfigFlowStep = (
data data
); );
export const ignoreConfigFlow = (hass: HomeAssistant, flowId: string) =>
hass.callWS({ type: "config_entries/ignore_flow", flow_id: flowId });
export const deleteConfigFlow = (hass: HomeAssistant, flowId: string) => export const deleteConfigFlow = (hass: HomeAssistant, flowId: string) =>
hass.callApi("DELETE", `config/config_entries/flow/${flowId}`); hass.callApi("DELETE", `config/config_entries/flow/${flowId}`);

View File

@ -2,6 +2,7 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes";
import "@polymer/paper-tooltip/paper-tooltip"; import "@polymer/paper-tooltip/paper-tooltip";
import "@material/mwc-button"; import "@material/mwc-button";
import "@polymer/iron-icon/iron-icon"; import "@polymer/iron-icon/iron-icon";
import "@polymer/paper-listbox/paper-listbox";
import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item-body";
@ -23,7 +24,11 @@ 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_flow"; import {
localizeConfigFlowTitle,
ignoreConfigFlow,
DISCOVERY_SOURCES,
} from "../../../data/config_flow";
import { import {
LitElement, LitElement,
TemplateResult, TemplateResult,
@ -34,10 +39,11 @@ import {
CSSResult, CSSResult,
} from "lit-element"; } from "lit-element";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { ConfigEntry } from "../../../data/config_entries"; import { ConfigEntry, deleteConfigEntry } from "../../../data/config_entries";
import { fireEvent } from "../../../common/dom/fire_event"; import { fireEvent } from "../../../common/dom/fire_event";
import { EntityRegistryEntry } from "../../../data/entity_registry"; import { EntityRegistryEntry } from "../../../data/entity_registry";
import { DataEntryFlowProgress } from "../../../data/data_entry_flow"; import { DataEntryFlowProgress } from "../../../data/data_entry_flow";
import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation";
@customElement("ha-config-entries-dashboard") @customElement("ha-config-entries-dashboard")
export class HaConfigManagerDashboard extends LitElement { export class HaConfigManagerDashboard extends LitElement {
@ -56,6 +62,7 @@ export class HaConfigManagerDashboard extends LitElement {
* For example, can be discovered devices that require more config. * For example, can be discovered devices that require more config.
*/ */
@property() private configEntriesInProgress!: DataEntryFlowProgress[]; @property() private configEntriesInProgress!: DataEntryFlowProgress[];
@property() private _showIgnored = false;
public connectedCallback() { public connectedCallback() {
super.connectedCallback(); super.connectedCallback();
@ -67,6 +74,67 @@ export class HaConfigManagerDashboard extends LitElement {
<hass-subpage <hass-subpage
header=${this.hass.localize("ui.panel.config.integrations.caption")} header=${this.hass.localize("ui.panel.config.integrations.caption")}
> >
<paper-menu-button
close-on-activate
no-animations
horizontal-align="right"
horizontal-offset="-5"
slot="toolbar-icon"
>
<paper-icon-button
icon="hass:dots-vertical"
slot="dropdown-trigger"
alt="menu"
></paper-icon-button>
<paper-listbox
slot="dropdown-content"
role="listbox"
selected="{{selectedItem}}"
>
<paper-item @click=${this._toggleShowIgnored}>
${this.hass.localize(
this._showIgnored
? "ui.panel.config.integrations.ignore.hide_ignored"
: "ui.panel.config.integrations.ignore.show_ignored"
)}
</paper-item>
</paper-listbox>
</paper-menu-button>
${this._showIgnored
? html`
<ha-config-section>
<span slot="header"
>${this.hass.localize(
"ui.panel.config.integrations.ignore.ignored"
)}</span
>
<ha-card>
${this.configEntries
.filter((item) => item.source === "ignore")
.map(
(item: ConfigEntry) => html`
<paper-item>
<paper-item-body>
${this.hass.localize(
`component.${item.domain}.config.title`
)}
</paper-item-body>
<paper-icon-button
@click=${this._removeIgnoredIntegration}
.entry=${item}
icon="hass:delete"
aria-label=${this.hass.localize(
"ui.panel.config.integrations.details"
)}
></paper-icon-button>
</paper-item>
`
)}
</ha-card>
</ha-config-section>
`
: ""}
${this.configEntriesInProgress.length ${this.configEntriesInProgress.length
? html` ? html`
<ha-config-section> <ha-config-section>
@ -82,9 +150,22 @@ export class HaConfigManagerDashboard extends LitElement {
<paper-item-body> <paper-item-body>
${localizeConfigFlowTitle(this.hass.localize, flow)} ${localizeConfigFlowTitle(this.hass.localize, flow)}
</paper-item-body> </paper-item-body>
${DISCOVERY_SOURCES.includes(flow.context.source) &&
flow.context.unique_id
? html`
<mwc-button
@click=${this._ignoreFlow}
.flow=${flow}
>
${this.hass.localize(
"ui.panel.config.integrations.ignore.ignore"
)}
</mwc-button>
`
: ""}
<mwc-button <mwc-button
@click=${this._continueFlow} @click=${this._continueFlow}
data-id="${flow.flow_id}" .flowId=${flow.flow_id}
>${this.hass.localize( >${this.hass.localize(
"ui.panel.config.integrations.configure" "ui.panel.config.integrations.configure"
)}</mwc-button )}</mwc-button
@ -98,15 +179,15 @@ export class HaConfigManagerDashboard extends LitElement {
: ""} : ""}
<ha-config-section class="configured"> <ha-config-section class="configured">
<span slot="header" <span slot="header">
>${this.hass.localize( ${this.hass.localize("ui.panel.config.integrations.configured")}
"ui.panel.config.integrations.configured" </span>
)}</span
>
<ha-card> <ha-card>
${this.entityRegistryEntries.length ${this.entityRegistryEntries.length
? this.configEntries.map( ? this.configEntries.map((item: any, idx) =>
(item: any, idx) => html` item.source === "ignore"
? ""
: html`
<a <a
href="/config/integrations/config_entry/${item.entry_id}" href="/config/integrations/config_entry/${item.entry_id}"
> >
@ -126,7 +207,9 @@ export class HaConfigManagerDashboard extends LitElement {
.stateObj=${entity} .stateObj=${entity}
></ha-state-icon> ></ha-state-icon>
<paper-tooltip position="bottom" <paper-tooltip position="bottom"
>${computeStateName(entity)}</paper-tooltip >${computeStateName(
entity
)}</paper-tooltip
> >
</span> </span>
` `
@ -176,12 +259,64 @@ export class HaConfigManagerDashboard extends LitElement {
private _continueFlow(ev: Event) { private _continueFlow(ev: Event) {
showConfigFlowDialog(this, { showConfigFlowDialog(this, {
continueFlowId: continueFlowId: (ev.target! as any).flowId,
(ev.target as HTMLElement).getAttribute("data-id") || undefined,
dialogClosedCallback: () => fireEvent(this, "hass-reload-entries"), dialogClosedCallback: () => fireEvent(this, "hass-reload-entries"),
}); });
} }
private _ignoreFlow(ev: Event) {
const flow = (ev.target! as any).flow;
showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.integrations.ignore.confirm_ignore_title",
"name",
localizeConfigFlowTitle(this.hass.localize, flow)
),
text: this.hass!.localize(
"ui.panel.config.integrations.ignore.confirm_ignore"
),
confirmBtnText: this.hass!.localize(
"ui.panel.config.integrations.ignore.ignore"
),
confirm: () => {
ignoreConfigFlow(this.hass, flow.flow_id);
fireEvent(this, "hass-reload-entries");
},
});
}
private _toggleShowIgnored() {
this._showIgnored = !this._showIgnored;
}
private async _removeIgnoredIntegration(ev: Event) {
const entry = (ev.target! as any).entry;
showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.integrations.ignore.confirm_delete_ignore_title",
"name",
this.hass.localize(`component.${entry.domain}.config.title`)
),
text: this.hass!.localize(
"ui.panel.config.integrations.ignore.confirm_delete_ignore"
),
confirmBtnText: this.hass!.localize(
"ui.panel.config.integrations.ignore.stop_ignore"
),
confirm: async () => {
const result = await deleteConfigEntry(this.hass, entry.entry_id);
if (result.require_restart) {
alert(
this.hass.localize(
"ui.panel.config.integrations.config_entry.restart_confirm"
)
);
}
fireEvent(this, "hass-reload-entries");
},
});
}
private _getEntities(configEntry: ConfigEntry): HassEntity[] { private _getEntities(configEntry: ConfigEntry): HassEntity[] {
if (!this.entityRegistryEntries) { if (!this.entityRegistryEntries) {
return []; return [];
@ -203,8 +338,7 @@ export class HaConfigManagerDashboard extends LitElement {
overflow: hidden; overflow: hidden;
} }
mwc-button { mwc-button {
top: 3px; align-self: center;
margin-right: -0.57em;
} }
.config-entry-row { .config-entry-row {
display: flex; display: flex;
@ -229,6 +363,9 @@ export class HaConfigManagerDashboard extends LitElement {
right: auto; right: auto;
left: 16px; left: 16px;
} }
.overflow {
width: 56px;
}
`; `;
} }
} }

View File

@ -116,7 +116,7 @@ class HaConfigIntegrations extends HassRouterPage {
private _loadData() { private _loadData() {
getConfigEntries(this.hass).then((configEntries) => { getConfigEntries(this.hass).then((configEntries) => {
this._configEntries = configEntries.sort((conf1, conf2) => this._configEntries = configEntries.sort((conf1, conf2) =>
compare(conf1.title, conf2.title) compare(conf1.domain + conf1.title, conf2.domain + conf2.title)
); );
}); });
if (this._unsubs) { if (this._unsubs) {

View File

@ -1307,6 +1307,17 @@
"none": "Nothing configured yet", "none": "Nothing configured yet",
"integration_not_found": "Integration not found.", "integration_not_found": "Integration not found.",
"details": "Integration details", "details": "Integration details",
"ignore": {
"ignore": "Ignore",
"confirm_ignore_title": "Ignore discovery of {name}?",
"confirm_ignore": "Are you sure you don't want to setup this integration? You can undo this by clicking the 'Show ignored integrations' in the overflow menu on the top right.",
"show_ignored": "Show ignored integrations",
"hide_ignored": "Hide ignored integrations",
"ignored": "Ignored",
"confirm_delete_ignore_title": "Stop ignoring {name}?",
"confirm_delete_ignore": "This will make the integration appear in your discovered integrations again when it gets discovered. This might require a restart or take some time.",
"stop_ignore": "Stop ignoring"
},
"config_entry": { "config_entry": {
"settings_button": "Edit settings for {integration}", "settings_button": "Edit settings for {integration}",
"system_options_button": "System options for {integration}", "system_options_button": "System options for {integration}",