Skip to content

Commit

Permalink
Add select prev boots in error-log-card (#22528)
Browse files Browse the repository at this point in the history
* Add select prev boots in error-log-card

* Fix boot selector style in error-log-card
  • Loading branch information
wendevlin authored Oct 28, 2024
1 parent 3180747 commit dc0cab9
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 11 deletions.
25 changes: 19 additions & 6 deletions src/data/hassio/supervisor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export type HassioInfo = {
timezone: string;
};

export type HassioBoots = {
boots: Record<number, string>;
};

export type HassioPanelInfo = PanelInfo<
| undefined
| {
Expand Down Expand Up @@ -177,14 +181,18 @@ export const fetchHassioInfo = async (
);
};

export const fetchHassioBoots = async (hass: HomeAssistant) =>
hass.callApi<HassioResponse<HassioBoots>>("GET", `hassio/host/logs/boots`);

export const fetchHassioLogs = async (
hass: HomeAssistant,
provider: string,
range?: string
range?: string,
boot = 0
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs`,
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs/boots/${boot}`,
undefined,
range
? {
Expand All @@ -197,11 +205,12 @@ export const fetchHassioLogsFollow = async (
hass: HomeAssistant,
provider: string,
signal: AbortSignal,
lines = 100
lines = 100,
boot = 0
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs/follow?lines=${lines}`,
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs/boots/${boot}/follow?lines=${lines}`,
undefined,
undefined,
signal
Expand All @@ -212,10 +221,14 @@ export const getHassioLogDownloadUrl = (provider: string) =>
provider.includes("_") ? `addons/${provider}` : provider
}/logs`;

export const getHassioLogDownloadLinesUrl = (provider: string, lines: number) =>
export const getHassioLogDownloadLinesUrl = (
provider: string,
lines: number,
boot = 0
) =>
`/api/hassio/${
provider.includes("_") ? `addons/${provider}` : provider
}/logs?lines=${lines}`;
}/logs/boots/${boot}?lines=${lines}`;

export const setSupervisorOption = async (
hass: HomeAssistant,
Expand Down
13 changes: 11 additions & 2 deletions src/panels/config/logs/dialog-download-logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ class DownloadLogsDialog extends LitElement {
<span slot="title" id="dialog-light-color-favorite-title">
${this.hass.localize("ui.panel.config.logs.download_full_log")}
</span>
<span slot="subtitle"> ${this._dialogParams.header} </span>
<span slot="subtitle">
${this._dialogParams.header}${this._dialogParams.boot === 0
? ""
: ` ⸱ ${this._dialogParams.boot === -1 ? this.hass.localize("ui.panel.config.logs.previous") : this.hass.localize("ui.panel.config.logs.startups_ago", { boot: this._dialogParams.boot * -1 })}`}
</span>
</ha-dialog-header>
<div slot="content" class="content">
<div>
Expand Down Expand Up @@ -104,9 +108,14 @@ class DownloadLogsDialog extends LitElement {

private async _dowloadLogs() {
const provider = this._dialogParams!.provider;
const boot = this._dialogParams!.boot;

const timeString = new Date().toISOString().replace(/:/g, "-");
const downloadUrl = getHassioLogDownloadLinesUrl(provider, this._lineCount);
const downloadUrl = getHassioLogDownloadLinesUrl(
provider,
this._lineCount,
boot
);
const logFileName =
provider !== "core"
? `${provider}_${timeString}.log`
Expand Down
114 changes: 111 additions & 3 deletions src/panels/config/logs/error-log-card.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import "@material/mwc-list/mwc-list-item";
import { mdiArrowCollapseDown, mdiDownload, mdiRefresh } from "@mdi/js";
import {
mdiArrowCollapseDown,
mdiDownload,
mdiMenuDown,
mdiRefresh,
} from "@mdi/js";
import {
css,
CSSResultGroup,
Expand All @@ -22,12 +27,17 @@ import "../../../components/ha-button";
import "../../../components/ha-icon-button";
import "../../../components/ha-svg-icon";
import "../../../components/ha-circular-progress";
import "../../../components/chips/ha-assist-chip";
import "../../../components/ha-menu";
import "../../../components/ha-md-menu-item";
import "../../../components/ha-md-divider";

import { getSignedPath } from "../../../data/auth";

import { fetchErrorLog, getErrorLogDownloadUrl } from "../../../data/error_log";
import { extractApiErrorMessage } from "../../../data/hassio/common";
import {
fetchHassioBoots,
fetchHassioLogs,
fetchHassioLogsFollow,
getHassioLogDownloadUrl,
Expand All @@ -40,6 +50,7 @@ import { atLeastVersion } from "../../../common/config/version";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { debounce } from "../../../common/util/debounce";
import { showDownloadLogsDialog } from "./show-dialog-download-logs";
import type { HaMenu } from "../../../components/ha-menu";

const NUMBER_OF_LINES = 100;

Expand All @@ -64,6 +75,8 @@ class ErrorLogCard extends LitElement {

@query("ha-ansi-to-html") private _ansiToHtmlElement?: HaAnsiToHtml;

@query("#boots-menu") private _bootsMenu?: HaMenu;

@state() private _firstCursor?: string;

@state() private _scrolledToBottomController =
Expand Down Expand Up @@ -92,6 +105,10 @@ class ErrorLogCard extends LitElement {

@state() private _numberOfLines?: number;

@state() private _boot = 0;

@state() private _boots?: number[];

protected render(): TemplateResult {
return html`
<div class="error-log-intro">
Expand All @@ -105,6 +122,60 @@ class ErrorLogCard extends LitElement {
this.hass.localize("ui.panel.config.logs.show_full_logs")}
</h1>
<div class="action-buttons">
${this._streamSupported && Array.isArray(this._boots)
? html`
<ha-assist-chip
.label=${this._boot === 0
? this.hass.localize("ui.panel.config.logs.current")
: this._boot === -1
? this.hass.localize("ui.panel.config.logs.previous")
: this.hass.localize(
"ui.panel.config.logs.startups_ago",
{ boot: this._boot * -1 }
)}
id="boots-anchor"
@click=${this._toggleBootsMenu}
>
<ha-svg-icon
slot="trailing-icon"
.path=${mdiMenuDown}
></ha-svg-icon
></ha-assist-chip>
<ha-menu
anchor="boots-anchor"
id="boots-menu"
positioning="fixed"
>
${this._boots.map(
(boot) => html`
<ha-md-menu-item
.value=${boot}
@click=${this._setBoot}
.selected=${boot === this._boot}
>
${boot === 0
? this.hass.localize(
"ui.panel.config.logs.current"
)
: boot === -1
? this.hass.localize(
"ui.panel.config.logs.previous"
)
: this.hass.localize(
"ui.panel.config.logs.startups_ago",
{ boot: boot * -1 }
)}
</ha-md-menu-item>
${boot === 0
? html`<ha-md-divider
role="separator"
></ha-md-divider>`
: nothing}
`
)}
</ha-menu>
`
: nothing}
<ha-icon-button
.path=${mdiDownload}
@click=${this._downloadFullLog}
Expand Down Expand Up @@ -212,6 +283,9 @@ class ErrorLogCard extends LitElement {
if (this.hass?.config.recovery_mode || this.show) {
this.hass.loadFragmentTranslation("config");
}

// just needs to be loaded once, because only the host endpoints provide boots information
this._loadBoots();
}

protected updated(changedProps) {
Expand All @@ -221,6 +295,7 @@ class ErrorLogCard extends LitElement {
(changedProps.has("show") && this.show) ||
(changedProps.has("provider") && this.show)
) {
this._boot = 0;
this._loadLogs();
}

Expand Down Expand Up @@ -262,6 +337,7 @@ class ErrorLogCard extends LitElement {
header: this.header,
provider: this.provider,
defaultLineCount: this._numberOfLines,
boot: this._boot,
});
} else {
const timeString = new Date().toISOString().replace(/:/g, "-");
Expand Down Expand Up @@ -306,7 +382,8 @@ class ErrorLogCard extends LitElement {
this.hass,
this.provider,
this._logStreamAborter.signal,
NUMBER_OF_LINES
NUMBER_OF_LINES,
this._boot
);

if (response.headers.has("X-First-Cursor")) {
Expand Down Expand Up @@ -437,7 +514,8 @@ class ErrorLogCard extends LitElement {
const response = await fetchHassioLogs(
this.hass,
this.provider,
`entries=${this._firstCursor}:-100:100`
`entries=${this._firstCursor}:-100:100`,
this._boot
);

if (response.headers.has("X-First-Cursor")) {
Expand Down Expand Up @@ -488,6 +566,31 @@ class ErrorLogCard extends LitElement {
return isVisible;
};

private async _loadBoots() {
if (this._streamSupported && isComponentLoaded(this.hass, "hassio")) {
try {
const { data } = await fetchHassioBoots(this.hass);
this._boots = Object.keys(data.boots)
.map(Number)
.sort((a, b) => b - a);
} catch (err: any) {
// eslint-disable-next-line no-console
console.error(err);
}
}
}

private _toggleBootsMenu() {
if (this._bootsMenu) {
this._bootsMenu.open = !this._bootsMenu.open;
}
}

private _setBoot(ev: any) {
this._boot = ev.target.value;
this._loadLogs();
}

static styles: CSSResultGroup = css`
.error-log-intro {
text-align: center;
Expand Down Expand Up @@ -600,6 +703,11 @@ class ErrorLogCard extends LitElement {
justify-content: center;
padding: 16px;
}
ha-assist-chip {
--ha-assist-chip-container-shape: 10px;
--md-assist-chip-trailing-space: 8px;
}
`;
}

Expand Down
1 change: 1 addition & 0 deletions src/panels/config/logs/show-dialog-download-logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface DownloadLogsDialogParams {
header?: string;
provider: string;
defaultLineCount?: number;
boot: number;
}

export const showDownloadLogsDialog = (
Expand Down
3 changes: 3 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2490,6 +2490,9 @@
"scroll_down_button": "New logs - Click to scroll",
"provider_not_found": "Log provider not found",
"provider_not_available": "Logs for ''{provider}'' are not available on your system.",
"current": "Current",
"previous": "Previous",
"startups_ago": "{boot} startups ago",
"detail": {
"logger": "Logger",
"source": "Source",
Expand Down

0 comments on commit dc0cab9

Please sign in to comment.