diff --git a/src/data/logbook.ts b/src/data/logbook.ts index 6e7a289b90..9e5f2ac4a6 100644 --- a/src/data/logbook.ts +++ b/src/data/logbook.ts @@ -25,6 +25,7 @@ export interface LogbookEntry { context_entity_id?: string; context_entity_id_name?: string; context_name?: string; + context_message?: string; state?: string; } diff --git a/src/panels/logbook/ha-logbook.ts b/src/panels/logbook/ha-logbook.ts index adb946efa8..680eb38603 100644 --- a/src/panels/logbook/ha-logbook.ts +++ b/src/panels/logbook/ha-logbook.ts @@ -22,9 +22,17 @@ import "../../components/ha-circular-progress"; import "../../components/ha-relative-time"; import { LogbookEntry } from "../../data/logbook"; import { TraceContexts } from "../../data/trace"; -import { haStyle, haStyleScrollbar } from "../../resources/styles"; +import { + haStyle, + haStyleScrollbar, + buttonLinkStyle, +} from "../../resources/styles"; import { HomeAssistant } from "../../types"; +const EVENT_LOCALIZE_MAP = { + script_started: "from_script", +}; + @customElement("ha-logbook") class HaLogbook extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -119,6 +127,7 @@ class HaLogbook extends LitElement { return html``; } + const seenEntityIds: string[] = []; const previous = this.entries[index - 1]; const stateObj = item.entity_id ? this.hass.states[item.entity_id] @@ -167,42 +176,48 @@ class HaLogbook extends LitElement { : ""}
- ${!this.noName - ? html`${item.name}` + ${!this.noName // Used for more-info panel (single entity case) + ? this._renderEntity(item.entity_id, item.name) + : ""} + ${item.message + ? html`${this._formatMessageWithPossibleEntity( + item.message, + seenEntityIds, + item.entity_id + )}` + : item.source + ? html` ${this._formatMessageWithPossibleEntity( + item.source, + seenEntityIds, + undefined, + "ui.components.logbook.by" + )}` : ""} - ${item.message} ${item_username ? ` ${this.hass.localize( - "ui.components.logbook.by" + "ui.components.logbook.by_user" )} ${item_username}` - : !item.context_event_type - ? "" - : item.context_event_type === "call_service" - ? // Service Call - ` ${this.hass.localize("ui.components.logbook.by_service")} - ${item.context_domain}.${item.context_service}` - : item.context_entity_id === item.entity_id - ? // HomeKit or something that self references - ` ${this.hass.localize("ui.components.logbook.by")} - ${ - item.context_name - ? item.context_name - : item.context_event_type - }` - : // Another entity such as an automation or script - html` ${this.hass.localize("ui.components.logbook.by")} - ${item.context_entity_id_name}`} + : ``} + ${item.context_event_type + ? this._formatEventBy(item, seenEntityIds) + : ""} + ${item.context_message + ? html` ${this._formatMessageWithPossibleEntity( + item.context_message, + seenEntityIds, + item.context_entity_id, + "ui.components.logbook.for" + )}` + : ""} + ${item.context_entity_id && + !seenEntityIds.includes(item.context_entity_id) + ? // Another entity such as an automation or script + html` ${this.hass.localize("ui.components.logbook.for")} + ${this._renderEntity( + item.context_entity_id, + item.context_entity_id_name + )}` + : ""}
+ ${displayName} + `; + } + + private _formatMessageWithPossibleEntity( + message: string, + seenEntities: string[], + possibleEntity?: string, + localizePrefix?: string + ) { + // + // As we are looking at a log(book), we are doing entity_id + // "highlighting"/"colorizing". The goal is to make it easy for + // the user to access the entity that caused the event. + // + // If there is an entity_id in the message that is also in the + // state machine, we search the message for the entity_id and + // replace it with _renderEntity + // + if (message.indexOf(".") !== -1) { + const messageParts = message.split(" "); + for (let i = 0, size = messageParts.length; i < size; i++) { + if (messageParts[i] in this.hass.states) { + const entityId = messageParts[i]; + if (seenEntities.includes(entityId)) { + return ""; + } + seenEntities.push(entityId); + const messageEnd = messageParts.splice(i); + messageEnd.shift(); // remove the entity + return html` ${messageParts.join(" ")} + ${this._renderEntity( + entityId, + this.hass.states[entityId].attributes.friendly_name + )} + ${messageEnd.join(" ")}`; + } + } + } + // + // When we have a message has a specific entity_id attached to + // it, and the entity_id is not in the message, we look + // for the friendly name of the entity and replace that with + // _renderEntity if its there so the user can quickly get to + // that entity. + // + if (possibleEntity && possibleEntity in this.hass.states) { + const possibleEntityName = + this.hass.states[possibleEntity].attributes.friendly_name; + if (possibleEntityName && message.endsWith(possibleEntityName)) { + if (seenEntities.includes(possibleEntity)) { + return ""; + } + seenEntities.push(possibleEntity); + message = message.substring( + 0, + message.length - possibleEntityName.length + ); + return html` ${localizePrefix ? this.hass.localize(localizePrefix) : ""} + ${message} ${this._renderEntity(possibleEntity, possibleEntityName)}`; + } + } + return message; + } + private _entityClicked(ev: Event) { const entityId = (ev.currentTarget as any).entityId; if (!entityId) { @@ -275,6 +407,7 @@ class HaLogbook extends LitElement { return [ haStyle, haStyleScrollbar, + buttonLinkStyle, css` :host([virtualize]) { display: block; diff --git a/src/translations/en.json b/src/translations/en.json index 550d03c627..afcc88b7f9 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -344,8 +344,14 @@ }, "logbook": { "entries_not_found": "No logbook events found.", + "by_user": "by user", "by": "by", - "by_service": "by service", + "from": "from", + "for": "for", + "event": "event", + "from_service": "from service", + "from_automation": "from automation", + "from_script": "from script", "show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]", "retrieval_error": "Could not load logbook", "messages": {