Skip to content

Commit

Permalink
Better disabled/error handling on config/helpers page (#22237)
Browse files Browse the repository at this point in the history
* Add a way to fix/remove broken helpers

* more disabled/sources fixes

* Update src/translations/en.json

Co-authored-by: Simon Lamon <[email protected]>

* Update ha-config-helpers.ts

---------

Co-authored-by: Simon Lamon <[email protected]>
  • Loading branch information
karwosts and silamon authored Nov 9, 2024
1 parent 9e002f7 commit e183047
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 44 deletions.
111 changes: 99 additions & 12 deletions src/panels/config/helpers/ha-config-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@ import { ResizeController } from "@lit-labs/observers/resize-controller";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import {
mdiAlertCircle,
mdiCancel,
mdiChevronRight,
mdiCog,
mdiDotsVertical,
mdiMenuDown,
mdiPencilOff,
mdiProgressHelper,
mdiPlus,
mdiTag,
mdiTrashCan,
} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { debounce } from "../../../common/util/debounce";
import { computeCssColor } from "../../../common/color/compute-color";
import { storage } from "../../../common/decorators/storage";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
Expand Down Expand Up @@ -54,7 +58,11 @@ import {
subscribeCategoryRegistry,
} from "../../../data/category_registry";
import type { ConfigEntry } from "../../../data/config_entries";
import { subscribeConfigEntries } from "../../../data/config_entries";
import {
ERROR_STATES,
deleteConfigEntry,
subscribeConfigEntries,
} from "../../../data/config_entries";
import { getConfigFlowHandlers } from "../../../data/config_flow";
import { fullEntitiesContext } from "../../../data/context";
import type {
Expand Down Expand Up @@ -97,6 +105,7 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
import { configSections } from "../ha-panel-config";
import "../integrations/ha-integration-overflow-menu";
import { renderConfigEntryError } from "../integrations/ha-config-integration-page";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import { isHelperDomain } from "./const";
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
Expand Down Expand Up @@ -220,6 +229,12 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
callback: (entries) => entries[0]?.contentRect.width,
});

private _debouncedFetchEntitySources = debounce(
() => this._fetchEntitySources(),
500,
false
);

public hassSubscribe() {
return [
subscribeConfigEntries(
Expand All @@ -236,6 +251,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
} else if (message.type === "updated") {
newEntries[message.entry.entry_id] = message.entry;
}
if (
this._entitySource &&
this._configEntries &&
message.entry.state === "loaded" &&
this._configEntries[message.entry.entry_id]?.state !== "loaded"
) {
this._debouncedFetchEntitySources();
}
});
this._configEntries = newEntries;
},
Expand Down Expand Up @@ -352,6 +375,19 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
.hass=${this.hass}
narrow
.items=${[
...(helper.configEntry &&
ERROR_STATES.includes(helper.configEntry.state)
? [
{
path: mdiAlertCircle,
label: this.hass.localize(
"ui.panel.config.helpers.picker.error_information"
),
warning: true,
action: () => this._showError(helper),
},
]
: []),
{
path: mdiCog,
label: this.hass.localize(
Expand All @@ -366,6 +402,19 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
),
action: () => this._editCategory(helper),
},
...(helper.configEntry &&
helper.editable &&
ERROR_STATES.includes(helper.configEntry.state) &&
helper.entity === undefined
? [
{
path: mdiTrashCan,
label: this.hass.localize("ui.common.delete"),
warning: true,
action: () => this._deleteEntry(helper),
},
]
: []),
]}
>
</ha-icon-overflow-menu>
Expand Down Expand Up @@ -417,17 +466,27 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
};
});

const entries = Object.values(configEntriesCopy).map((configEntry) => ({
id: configEntry.entry_id,
entity_id: "",
icon: mdiAlertCircle,
name: configEntry.title || "",
editable: true,
type: configEntry.domain,
configEntry,
entity: undefined,
selectable: false,
}));
const entries = Object.values(configEntriesCopy).map((configEntry) => {
const entityEntry = Object.values(entityEntries).find(
(entry) => entry.config_entry_id === configEntry.entry_id
);
const entityIsDisabled = !!entityEntry?.disabled_by;
return {
id: entityIsDisabled ? entityEntry.entity_id : configEntry.entry_id,
entity_id: entityIsDisabled ? entityEntry.entity_id : "",
icon: entityIsDisabled
? mdiCancel
: configEntry.state === "setup_in_progress"
? mdiProgressHelper
: mdiAlertCircle,
name: configEntry.title || "",
editable: true,
type: configEntry.domain,
configEntry,
entity: undefined,
selectable: entityIsDisabled,
};
});

return [...states, ...entries]
.filter((item) =>
Expand Down Expand Up @@ -1081,6 +1140,34 @@ ${rejected
}
}

private _showError(helper: HelperItem) {
showAlertDialog(this, {
title: this.hass.localize("ui.errors.config.configuration_error"),
text: renderConfigEntryError(this.hass, helper.configEntry!),
warning: true,
});
}

private async _deleteEntry(helper: HelperItem) {
const confirmed = await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_entry.delete_confirm_title",
{ title: helper.configEntry!.title }
),
text: this.hass.localize(
"ui.panel.config.integrations.config_entry.delete_confirm_text"
),
confirmText: this.hass!.localize("ui.common.delete"),
dismissText: this.hass!.localize("ui.common.cancel"),
destructive: true,
});

if (!confirmed) {
return;
}
deleteConfigEntry(this.hass, helper.id);
}

private _openSettings(helper: HelperItem) {
if (helper.entity) {
showMoreInfoDialog(this, {
Expand Down
64 changes: 33 additions & 31 deletions src/panels/config/integrations/ha-config-integration-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,38 @@ import { fileDownload } from "../../../util/file_download";
import type { DataEntryFlowProgressExtended } from "./ha-config-integrations";
import { showAddIntegrationDialog } from "./show-add-integration-dialog";

export const renderConfigEntryError = (
hass: HomeAssistant,
entry: ConfigEntry
): TemplateResult => {
if (entry.reason) {
if (entry.error_reason_translation_key) {
const lokalisePromExc = hass
.loadBackendTranslation("exceptions", entry.domain)
.then(
(localize) =>
localize(
`component.${entry.domain}.exceptions.${entry.error_reason_translation_key}.message`,
entry.error_reason_translation_placeholders ?? undefined
) || entry.reason
);
return html`${until(lokalisePromExc)}`;
}
const lokalisePromError = hass
.loadBackendTranslation("config", entry.domain)
.then(
(localize) =>
localize(`component.${entry.domain}.config.error.${entry.reason}`) ||
entry.reason
);
return html`${until(lokalisePromError, entry.reason)}`;
}
return html`
<br />
${hass.localize("ui.panel.config.integrations.config_entry.check_the_logs")}
`;
};

@customElement("ha-config-integration-page")
class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
Expand Down Expand Up @@ -618,37 +650,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
stateText = [
`ui.panel.config.integrations.config_entry.state.${item.state}`,
];
if (item.reason) {
if (item.error_reason_translation_key) {
const lokalisePromExc = this.hass
.loadBackendTranslation("exceptions", item.domain)
.then(
(localize) =>
localize(
`component.${item.domain}.exceptions.${item.error_reason_translation_key}.message`,
item.error_reason_translation_placeholders ?? undefined
) || item.reason
);
stateTextExtra = html`${until(lokalisePromExc)}`;
} else {
const lokalisePromError = this.hass
.loadBackendTranslation("config", item.domain)
.then(
(localize) =>
localize(
`component.${item.domain}.config.error.${item.reason}`
) || item.reason
);
stateTextExtra = html`${until(lokalisePromError, item.reason)}`;
}
} else {
stateTextExtra = html`
<br />
${this.hass.localize(
"ui.panel.config.integrations.config_entry.check_the_logs"
)}
`;
}
stateTextExtra = renderConfigEntryError(this.hass, item);
}

const devices = this._getConfigEntryDevices(item);
Expand Down
3 changes: 2 additions & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2343,7 +2343,8 @@
},
"create_helper": "Create helper",
"no_helpers": "Looks like you don't have any helpers yet!",
"search": "Search {number} helpers"
"search": "Search {number} helpers",
"error_information": "Error information"
},
"dialog": {
"create": "Create",
Expand Down

0 comments on commit e183047

Please sign in to comment.