mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add select prev boots in error-log-card (#22528)
* Add select prev boots in error-log-card * Fix boot selector style in error-log-card
This commit is contained in:
parent
3180747a0a
commit
dc0cab9307
@ -65,6 +65,10 @@ export type HassioInfo = {
|
||||
timezone: string;
|
||||
};
|
||||
|
||||
export type HassioBoots = {
|
||||
boots: Record<number, string>;
|
||||
};
|
||||
|
||||
export type HassioPanelInfo = PanelInfo<
|
||||
| undefined
|
||||
| {
|
||||
@ -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
|
||||
? {
|
||||
@ -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
|
||||
@ -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,
|
||||
|
@ -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>
|
||||
@ -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`
|
||||
|
@ -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,
|
||||
@ -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,
|
||||
@ -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;
|
||||
|
||||
@ -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 =
|
||||
@ -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">
|
||||
@ -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}
|
||||
@ -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) {
|
||||
@ -221,6 +295,7 @@ class ErrorLogCard extends LitElement {
|
||||
(changedProps.has("show") && this.show) ||
|
||||
(changedProps.has("provider") && this.show)
|
||||
) {
|
||||
this._boot = 0;
|
||||
this._loadLogs();
|
||||
}
|
||||
|
||||
@ -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, "-");
|
||||
@ -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")) {
|
||||
@ -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")) {
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ export interface DownloadLogsDialogParams {
|
||||
header?: string;
|
||||
provider: string;
|
||||
defaultLineCount?: number;
|
||||
boot: number;
|
||||
}
|
||||
|
||||
export const showDownloadLogsDialog = (
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user