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": {