mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-09 18:36:35 +00:00
20241106.0 (#22695)
This commit is contained in:
commit
ce39b1a2c8
@ -38,12 +38,13 @@ class HassioAddonLogDashboard extends LitElement {
|
||||
@value-changed=${this._filterChanged}
|
||||
.hass=${this.hass}
|
||||
.filter=${this._filter}
|
||||
.label=${this.hass.localize("ui.panel.config.logs.search")}
|
||||
.label=${this.supervisor.localize("ui.panel.config.logs.search")}
|
||||
></search-input>
|
||||
</div>
|
||||
<div class="content">
|
||||
<error-log-card
|
||||
.hass=${this.hass}
|
||||
.localizeFunc=${this.supervisor.localize}
|
||||
.header=${this.addon.name}
|
||||
.provider=${this.addon.slug}
|
||||
show
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20241105.0"
|
||||
version = "20241106.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
query,
|
||||
state as litState,
|
||||
} from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
|
||||
interface State {
|
||||
bold: boolean;
|
||||
@ -26,12 +27,15 @@ interface State {
|
||||
export class HaAnsiToHtml extends LitElement {
|
||||
@property() public content!: string;
|
||||
|
||||
@property({ type: Boolean, attribute: "wrap-disabled" }) public wrapDisabled =
|
||||
false;
|
||||
|
||||
@query("pre") private _pre?: HTMLPreElement;
|
||||
|
||||
@litState() private _filter = "";
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`<pre></pre>`;
|
||||
return html`<pre class=${classMap({ wrap: !this.wrapDisabled })}></pre>`;
|
||||
}
|
||||
|
||||
protected firstUpdated(_changedProperties: PropertyValues): void {
|
||||
@ -47,9 +51,11 @@ export class HaAnsiToHtml extends LitElement {
|
||||
return css`
|
||||
pre {
|
||||
overflow-x: auto;
|
||||
margin: 0;
|
||||
}
|
||||
pre.wrap {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
margin: 0;
|
||||
}
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
|
@ -26,7 +26,10 @@ export class HaTraceLogbook extends LitElement {
|
||||
.entries=${this.logbookEntries}
|
||||
.narrow=${this.narrow}
|
||||
></ha-logbook-renderer>
|
||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||
<hat-logbook-note
|
||||
.hass=${this.hass}
|
||||
.domain=${this.trace.domain}
|
||||
></hat-logbook-note>
|
||||
`
|
||||
: html`<div class="padded-box">
|
||||
No Logbook entries found for this step.
|
||||
|
@ -291,7 +291,10 @@ export class HaTracePathDetails extends LitElement {
|
||||
.entries=${entries}
|
||||
.narrow=${this.narrow}
|
||||
></ha-logbook-renderer>
|
||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||
<hat-logbook-note
|
||||
.hass=${this.hass}
|
||||
.domain=${this.trace.domain}
|
||||
></hat-logbook-note>
|
||||
`
|
||||
: html`<div class="padded-box">
|
||||
${this.hass!.localize(
|
||||
|
@ -28,7 +28,10 @@ export class HaTraceTimeline extends LitElement {
|
||||
allowPick
|
||||
>
|
||||
</hat-trace-timeline>
|
||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||
<hat-logbook-note
|
||||
.hass=${this.hass}
|
||||
.domain=${this.trace.domain}
|
||||
></hat-logbook-note>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,22 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
|
||||
@customElement("hat-logbook-note")
|
||||
class HatLogbookNote extends LitElement {
|
||||
@property() public domain = "automation";
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public domain: "automation" | "script" = "automation";
|
||||
|
||||
render() {
|
||||
return html`
|
||||
Not all shown logbook entries might be related to this ${this.domain}.
|
||||
`;
|
||||
if (this.domain === "script") {
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.not_all_entries_are_related_script_note"
|
||||
);
|
||||
}
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.not_all_entries_are_related_automation_note"
|
||||
);
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
@ -52,59 +52,61 @@ class MoreInfoUpdate extends LitElement {
|
||||
|
||||
return html`
|
||||
<div class="content">
|
||||
${this.stateObj.attributes.in_progress
|
||||
? supportsFeature(this.stateObj, UpdateEntityFeature.PROGRESS) &&
|
||||
this.stateObj.attributes.update_percentage !== null
|
||||
? html`<mwc-linear-progress
|
||||
.progress=${this.stateObj.attributes.update_percentage / 100}
|
||||
buffer=""
|
||||
></mwc-linear-progress>`
|
||||
: html`<mwc-linear-progress indeterminate></mwc-linear-progress>`
|
||||
: nothing}
|
||||
<h3>${this.stateObj.attributes.title}</h3>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: nothing}
|
||||
<div class="row">
|
||||
<div class="key">
|
||||
${this.hass.formatEntityAttributeName(
|
||||
this.stateObj,
|
||||
"installed_version"
|
||||
)}
|
||||
<div class="summary">
|
||||
${this.stateObj.attributes.in_progress
|
||||
? supportsFeature(this.stateObj, UpdateEntityFeature.PROGRESS) &&
|
||||
this.stateObj.attributes.update_percentage !== null
|
||||
? html`<mwc-linear-progress
|
||||
.progress=${this.stateObj.attributes.update_percentage / 100}
|
||||
buffer=""
|
||||
></mwc-linear-progress>`
|
||||
: html`<mwc-linear-progress indeterminate></mwc-linear-progress>`
|
||||
: nothing}
|
||||
<h3>${this.stateObj.attributes.title}</h3>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: nothing}
|
||||
<div class="row">
|
||||
<div class="key">
|
||||
${this.hass.formatEntityAttributeName(
|
||||
this.stateObj,
|
||||
"installed_version"
|
||||
)}
|
||||
</div>
|
||||
<div class="value">
|
||||
${this.stateObj.attributes.installed_version ??
|
||||
this.hass.localize("state.default.unavailable")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
${this.stateObj.attributes.installed_version ??
|
||||
this.hass.localize("state.default.unavailable")}
|
||||
<div class="row">
|
||||
<div class="key">
|
||||
${this.hass.formatEntityAttributeName(
|
||||
this.stateObj,
|
||||
"latest_version"
|
||||
)}
|
||||
</div>
|
||||
<div class="value">
|
||||
${this.stateObj.attributes.latest_version ??
|
||||
this.hass.localize("state.default.unavailable")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="key">
|
||||
${this.hass.formatEntityAttributeName(
|
||||
this.stateObj,
|
||||
"latest_version"
|
||||
)}
|
||||
</div>
|
||||
<div class="value">
|
||||
${this.stateObj.attributes.latest_version ??
|
||||
this.hass.localize("state.default.unavailable")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this.stateObj.attributes.release_url
|
||||
? html`<div class="row">
|
||||
<div class="key">
|
||||
<a
|
||||
href=${this.stateObj.attributes.release_url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.update.release_announcement"
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
</div>`
|
||||
: nothing}
|
||||
${this.stateObj.attributes.release_url
|
||||
? html`<div class="row">
|
||||
<div class="key">
|
||||
<a
|
||||
href=${this.stateObj.attributes.release_url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.update.release_announcement"
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
${supportsFeature(this.stateObj!, UpdateEntityFeature.RELEASE_NOTES) &&
|
||||
!this._error
|
||||
? this._releaseNotes === undefined
|
||||
@ -293,6 +295,11 @@ class MoreInfoUpdate extends LitElement {
|
||||
ha-expansion-panel {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.summary {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
@ -308,7 +315,9 @@ class MoreInfoUpdate extends LitElement {
|
||||
);
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
margin: 0 -24px -24px -24px;
|
||||
margin: 0 -24px 0 -24px;
|
||||
margin-bottom: calc(-1 * max(env(safe-area-inset-bottom), 24px));
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -264,6 +264,7 @@ export interface ExternalConfig {
|
||||
hasAssist: boolean;
|
||||
hasBarCodeScanner: number;
|
||||
canSetupImprov: boolean;
|
||||
downloadFileSupported: boolean;
|
||||
}
|
||||
|
||||
export class ExternalMessaging {
|
||||
|
@ -370,7 +370,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog {
|
||||
}`,
|
||||
description:
|
||||
this.hass.localize(
|
||||
`component.${domain}.services.${service}.description`
|
||||
`component.${dmn}.services.${service}.description`
|
||||
) || services[dmn][service]?.description,
|
||||
});
|
||||
}
|
||||
|
@ -17,19 +17,21 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { fileDownload } from "../../../util/file_download";
|
||||
import type { DownloadLogsDialogParams } from "./show-dialog-download-logs";
|
||||
|
||||
const DEFAULT_LINE_COUNT = 500;
|
||||
|
||||
@customElement("dialog-download-logs")
|
||||
class DownloadLogsDialog extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _dialogParams?: DownloadLogsDialogParams;
|
||||
|
||||
@state() private _lineCount = 100;
|
||||
@state() private _lineCount = DEFAULT_LINE_COUNT;
|
||||
|
||||
@query("ha-md-dialog") private _dialogElement!: HaMdDialog;
|
||||
|
||||
public showDialog(dialogParams: DownloadLogsDialogParams) {
|
||||
this._dialogParams = dialogParams;
|
||||
this._lineCount = this._dialogParams?.defaultLineCount ?? 100;
|
||||
this._lineCount = this._dialogParams?.defaultLineCount || 500;
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
@ -38,7 +40,7 @@ class DownloadLogsDialog extends LitElement {
|
||||
|
||||
private _dialogClosed() {
|
||||
this._dialogParams = undefined;
|
||||
this._lineCount = 100;
|
||||
this._lineCount = DEFAULT_LINE_COUNT;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
@ -48,7 +50,7 @@ class DownloadLogsDialog extends LitElement {
|
||||
}
|
||||
|
||||
const numberOfLinesOptions = [100, 500, 1000, 5000, 10000];
|
||||
if (!numberOfLinesOptions.includes(this._lineCount)) {
|
||||
if (!numberOfLinesOptions.includes(this._lineCount) && this._lineCount) {
|
||||
numberOfLinesOptions.push(this._lineCount);
|
||||
numberOfLinesOptions.sort((a, b) => a - b);
|
||||
}
|
||||
@ -63,7 +65,7 @@ class DownloadLogsDialog extends LitElement {
|
||||
.path=${mdiClose}
|
||||
></ha-icon-button>
|
||||
<span slot="title" id="dialog-light-color-favorite-title">
|
||||
${this.hass.localize("ui.panel.config.logs.download_full_log")}
|
||||
${this.hass.localize("ui.panel.config.logs.download_logs")}
|
||||
</span>
|
||||
<span slot="subtitle">
|
||||
${this._dialogParams.header}${this._dialogParams.boot === 0
|
||||
@ -95,7 +97,7 @@ class DownloadLogsDialog extends LitElement {
|
||||
<ha-button @click=${this.closeDialog}>
|
||||
${this.hass.localize("ui.common.cancel")}
|
||||
</ha-button>
|
||||
<ha-button @click=${this._dowloadLogs}>
|
||||
<ha-button @click=${this._downloadLogs}>
|
||||
${this.hass.localize("ui.common.download")}
|
||||
</ha-button>
|
||||
</div>
|
||||
@ -103,7 +105,7 @@ class DownloadLogsDialog extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private async _dowloadLogs() {
|
||||
private async _downloadLogs() {
|
||||
const provider = this._dialogParams!.provider;
|
||||
const boot = this._dialogParams!.boot;
|
||||
|
||||
|
@ -1,9 +1,16 @@
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
|
||||
import {
|
||||
mdiArrowCollapseDown,
|
||||
mdiDotsVertical,
|
||||
mdiCircle,
|
||||
mdiDownload,
|
||||
mdiFormatListNumbered,
|
||||
mdiMenuDown,
|
||||
mdiRefresh,
|
||||
mdiWrap,
|
||||
mdiWrapDisabled,
|
||||
} from "@mdi/js";
|
||||
import {
|
||||
css,
|
||||
@ -31,6 +38,8 @@ import "../../../components/chips/ha-assist-chip";
|
||||
import "../../../components/ha-menu";
|
||||
import "../../../components/ha-md-menu-item";
|
||||
import "../../../components/ha-md-divider";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-list-item";
|
||||
|
||||
import { getSignedPath } from "../../../data/auth";
|
||||
|
||||
@ -40,10 +49,14 @@ import {
|
||||
fetchHassioBoots,
|
||||
fetchHassioLogs,
|
||||
fetchHassioLogsFollow,
|
||||
getHassioLogDownloadLinesUrl,
|
||||
getHassioLogDownloadUrl,
|
||||
} from "../../../data/hassio/supervisor";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { fileDownload } from "../../../util/file_download";
|
||||
import {
|
||||
downloadFileSupported,
|
||||
fileDownload,
|
||||
} from "../../../util/file_download";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import type { ConnectionStatus } from "../../../data/connection-status";
|
||||
import { atLeastVersion } from "../../../common/config/version";
|
||||
@ -51,6 +64,7 @@ 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";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
|
||||
const NUMBER_OF_LINES = 100;
|
||||
|
||||
@ -58,6 +72,8 @@ const NUMBER_OF_LINES = 100;
|
||||
class ErrorLogCard extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public localizeFunc?: LocalizeFunc<any>;
|
||||
|
||||
@property() public filter = "";
|
||||
|
||||
@property() public header?: string;
|
||||
@ -109,30 +125,42 @@ class ErrorLogCard extends LitElement {
|
||||
|
||||
@state() private _boots?: number[];
|
||||
|
||||
@state() private _showBootsSelect = false;
|
||||
|
||||
@state() private _wrapLines = true;
|
||||
|
||||
@state() private _downloadSupported;
|
||||
|
||||
@state() private _logsFileLink;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const localize = this.localizeFunc || this.hass.localize;
|
||||
return html`
|
||||
<div class="error-log-intro">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
: nothing}
|
||||
<ha-card outlined class=${classMap({ hidden: this.show === false })}>
|
||||
<div class="header">
|
||||
<h1 class="card-header">
|
||||
${this.header ||
|
||||
this.hass.localize("ui.panel.config.logs.show_full_logs")}
|
||||
${this.header || localize("ui.panel.config.logs.show_full_logs")}
|
||||
</h1>
|
||||
<div class="action-buttons">
|
||||
${this._streamSupported && Array.isArray(this._boots)
|
||||
${this._streamSupported &&
|
||||
Array.isArray(this._boots) &&
|
||||
this._showBootsSelect
|
||||
? html`
|
||||
<ha-assist-chip
|
||||
.title=${localize(
|
||||
"ui.panel.config.logs.haos_boots_title"
|
||||
)}
|
||||
.label=${this._boot === 0
|
||||
? this.hass.localize("ui.panel.config.logs.current")
|
||||
? 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 }
|
||||
)}
|
||||
? localize("ui.panel.config.logs.previous")
|
||||
: localize("ui.panel.config.logs.startups_ago", {
|
||||
boot: this._boot * -1,
|
||||
})}
|
||||
id="boots-anchor"
|
||||
@click=${this._toggleBootsMenu}
|
||||
>
|
||||
@ -154,14 +182,10 @@ class ErrorLogCard extends LitElement {
|
||||
.selected=${boot === this._boot}
|
||||
>
|
||||
${boot === 0
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.logs.current"
|
||||
)
|
||||
? localize("ui.panel.config.logs.current")
|
||||
: boot === -1
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.logs.previous"
|
||||
)
|
||||
: this.hass.localize(
|
||||
? localize("ui.panel.config.logs.previous")
|
||||
: localize(
|
||||
"ui.panel.config.logs.startups_ago",
|
||||
{ boot: boot * -1 }
|
||||
)}
|
||||
@ -176,20 +200,61 @@ class ErrorLogCard extends LitElement {
|
||||
</ha-menu>
|
||||
`
|
||||
: nothing}
|
||||
${this._downloadSupported
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.path=${mdiDownload}
|
||||
@click=${this._downloadLogs}
|
||||
.label=${localize("ui.panel.config.logs.download_logs")}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: this._logsFileLink
|
||||
? html`
|
||||
<a
|
||||
href=${this._logsFileLink}
|
||||
target="_blank"
|
||||
class="download-link"
|
||||
>
|
||||
<ha-icon-button
|
||||
.path=${mdiDownload}
|
||||
.label=${localize(
|
||||
"ui.panel.config.logs.download_logs"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
</a>
|
||||
`
|
||||
: nothing}
|
||||
<ha-icon-button
|
||||
.path=${mdiDownload}
|
||||
@click=${this._downloadFullLog}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.logs.download_full_log"
|
||||
.path=${this._wrapLines ? mdiWrapDisabled : mdiWrap}
|
||||
@click=${this._toggleLineWrap}
|
||||
.label=${localize(
|
||||
`ui.panel.config.logs.${this._wrapLines ? "full_width" : "wrap_lines"}`
|
||||
)}
|
||||
></ha-icon-button>
|
||||
${!this._streamSupported || this._error
|
||||
? html`<ha-icon-button
|
||||
.path=${mdiRefresh}
|
||||
@click=${this._loadLogs}
|
||||
.label=${this.hass.localize("ui.common.refresh")}
|
||||
.label=${localize("ui.common.refresh")}
|
||||
></ha-icon-button>`
|
||||
: nothing}
|
||||
${this._streamSupported && Array.isArray(this._boots)
|
||||
? html`
|
||||
<ha-button-menu @action=${this._handleOverflowAction}>
|
||||
<ha-icon-button slot="trigger" .path=${mdiDotsVertical}>
|
||||
</ha-icon-button>
|
||||
<ha-list-item graphic="icon">
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiFormatListNumbered}
|
||||
></ha-svg-icon>
|
||||
${localize(
|
||||
`ui.panel.config.logs.${this._showBootsSelect ? "hide" : "show"}_haos_boots`
|
||||
)}
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content error-log">
|
||||
@ -202,25 +267,22 @@ class ErrorLogCard extends LitElement {
|
||||
</div>`
|
||||
: nothing}
|
||||
${this._loadingState === "loading"
|
||||
? html`<div>
|
||||
${this.hass.localize("ui.panel.config.logs.loading_log")}
|
||||
</div>`
|
||||
? html`<div>${localize("ui.panel.config.logs.loading_log")}</div>`
|
||||
: this._loadingState === "empty"
|
||||
? html`<div>
|
||||
${this.hass.localize("ui.panel.config.logs.no_errors")}
|
||||
</div>`
|
||||
? html`<div>${localize("ui.panel.config.logs.no_errors")}</div>`
|
||||
: nothing}
|
||||
${this._loadingState === "loaded" &&
|
||||
this.filter &&
|
||||
this._noSearchResults
|
||||
? html`<div>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.logs.no_issues_search",
|
||||
{ term: this.filter }
|
||||
)}
|
||||
${localize("ui.panel.config.logs.no_issues_search", {
|
||||
term: this.filter,
|
||||
})}
|
||||
</div>`
|
||||
: nothing}
|
||||
<ha-ansi-to-html></ha-ansi-to-html>
|
||||
<ha-ansi-to-html
|
||||
?wrap-disabled=${!this._wrapLines}
|
||||
></ha-ansi-to-html>
|
||||
<div id="scroll-bottom-marker"></div>
|
||||
</div>
|
||||
<ha-button
|
||||
@ -236,24 +298,36 @@ class ErrorLogCard extends LitElement {
|
||||
.path=${mdiArrowCollapseDown}
|
||||
slot="icon"
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.logs.scroll_down_button")}
|
||||
${localize("ui.panel.config.logs.scroll_down_button")}
|
||||
<ha-svg-icon
|
||||
.path=${mdiArrowCollapseDown}
|
||||
slot="trailingIcon"
|
||||
></ha-svg-icon>
|
||||
</ha-button>
|
||||
${this._streamSupported &&
|
||||
this._loadingState !== "loading" &&
|
||||
!this._error
|
||||
? html`<div class="live-indicator">
|
||||
<ha-svg-icon path=${mdiCircle}></ha-svg-icon>
|
||||
Live
|
||||
</div>`
|
||||
: nothing}
|
||||
</ha-card>
|
||||
${this.show === false
|
||||
? html`
|
||||
<ha-button outlined @click=${this._downloadFullLog}>
|
||||
<ha-svg-icon .path=${mdiDownload}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.logs.download_full_log")}
|
||||
</ha-button>
|
||||
${this._downloadSupported
|
||||
? html`
|
||||
<ha-button outlined @click=${this._downloadLogs}>
|
||||
<ha-svg-icon .path=${mdiDownload}></ha-svg-icon>
|
||||
${localize("ui.panel.config.logs.download_logs")}
|
||||
</ha-button>
|
||||
`
|
||||
: nothing}
|
||||
<mwc-button raised @click=${this._showLogs}>
|
||||
${this.hass.localize("ui.panel.config.logs.load_logs")}
|
||||
${localize("ui.panel.config.logs.load_logs")}
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -268,6 +342,9 @@ class ErrorLogCard extends LitElement {
|
||||
11
|
||||
);
|
||||
}
|
||||
if (this._downloadSupported === undefined && this.hass) {
|
||||
this._downloadSupported = downloadFileSupported(this.hass);
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
@ -331,7 +408,7 @@ class ErrorLogCard extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
private async _downloadFullLog(): Promise<void> {
|
||||
private async _downloadLogs(): Promise<void> {
|
||||
if (this._streamSupported) {
|
||||
showDownloadLogsDialog(this, {
|
||||
header: this.header,
|
||||
@ -378,6 +455,18 @@ class ErrorLogCard extends LitElement {
|
||||
isComponentLoaded(this.hass, "hassio") &&
|
||||
this.provider
|
||||
) {
|
||||
// check if there are any logs at all
|
||||
const testResponse = await fetchHassioLogs(
|
||||
this.hass,
|
||||
this.provider,
|
||||
`entries=:-1:`,
|
||||
this._boot
|
||||
);
|
||||
const testLogs = await testResponse.text();
|
||||
if (!testLogs.trim()) {
|
||||
this._loadingState = "empty";
|
||||
}
|
||||
|
||||
const response = await fetchHassioLogsFollow(
|
||||
this.hass,
|
||||
this.provider,
|
||||
@ -438,6 +527,17 @@ class ErrorLogCard extends LitElement {
|
||||
} else {
|
||||
this._newLogsIndicator = true;
|
||||
}
|
||||
|
||||
if (!this._downloadSupported) {
|
||||
const downloadUrl = getHassioLogDownloadLinesUrl(
|
||||
this.provider,
|
||||
this._numberOfLines,
|
||||
this._boot
|
||||
);
|
||||
getSignedPath(this.hass, downloadUrl).then((signedUrl) => {
|
||||
this._logsFileLink = signedUrl.path;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -461,10 +561,13 @@ class ErrorLogCard extends LitElement {
|
||||
if (err.name === "AbortError") {
|
||||
return;
|
||||
}
|
||||
this._error = this.hass.localize("ui.panel.config.logs.failed_get_logs", {
|
||||
provider: this.provider,
|
||||
error: extractApiErrorMessage(err),
|
||||
});
|
||||
this._error = (this.localizeFunc || this.hass.localize)(
|
||||
"ui.panel.config.logs.failed_get_logs",
|
||||
{
|
||||
provider: this.provider,
|
||||
error: extractApiErrorMessage(err),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,6 +688,18 @@ class ErrorLogCard extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _toggleLineWrap() {
|
||||
this._wrapLines = !this._wrapLines;
|
||||
}
|
||||
|
||||
private _handleOverflowAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._showBootsSelect = !this._showBootsSelect;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _toggleBootsMenu() {
|
||||
if (this._bootsMenu) {
|
||||
this._bootsMenu.open = !this._bootsMenu.open;
|
||||
@ -597,6 +712,9 @@ class ErrorLogCard extends LitElement {
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = css`
|
||||
:host {
|
||||
direction: var(--direction);
|
||||
}
|
||||
.error-log-intro {
|
||||
text-align: center;
|
||||
margin: 16px;
|
||||
@ -646,7 +764,7 @@ class ErrorLogCard extends LitElement {
|
||||
position: relative;
|
||||
font-family: var(--code-font-family, monospace);
|
||||
clear: both;
|
||||
text-align: left;
|
||||
text-align: start;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
overflow-y: scroll;
|
||||
@ -713,6 +831,36 @@ class ErrorLogCard extends LitElement {
|
||||
--ha-assist-chip-container-shape: 10px;
|
||||
--md-assist-chip-trailing-space: 8px;
|
||||
}
|
||||
|
||||
@keyframes breathe {
|
||||
from {
|
||||
opacity: 0.8;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.live-indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
inset-inline-end: 16px;
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 8px;
|
||||
background-color: var(--primary-color);
|
||||
color: var(--text-primary-color);
|
||||
padding: 4px 8px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.live-indicator ha-svg-icon {
|
||||
animation: breathe 1s cubic-bezier(0.5, 0, 1, 1) infinite alternate;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.download-link {
|
||||
color: var(--text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../components/ha-card";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { hasConfigChanged } from "../../common/has-changed";
|
||||
import "../../components/hui-energy-period-selector";
|
||||
import "../../../../components/ha-card";
|
||||
import type { LovelaceCard, LovelaceLayoutOptions } from "../../types";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../../types";
|
||||
import type { EnergyCardBaseConfig } from "../types";
|
||||
|
||||
@customElement("hui-energy-date-selection-card")
|
||||
@ -21,10 +21,10 @@ export class HuiEnergyDateSelectionCard
|
||||
return 1;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_rows: 1,
|
||||
grid_columns: 4,
|
||||
rows: 1,
|
||||
columns: 12,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ import "../components/hui-warning";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { AreaCardConfig } from "./types";
|
||||
|
||||
@ -534,10 +534,11 @@ export class HuiAreaCard
|
||||
forwardHaptic("light");
|
||||
}
|
||||
|
||||
getLayoutOptions(): LovelaceLayoutOptions {
|
||||
getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: 4,
|
||||
grid_rows: 3,
|
||||
columns: 12,
|
||||
rows: 3,
|
||||
min_columns: 3,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { ButtonCardConfig } from "./types";
|
||||
|
||||
@ -134,20 +134,23 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
if (
|
||||
this._config?.show_icon &&
|
||||
(this._config?.show_name || this._config?.show_state)
|
||||
) {
|
||||
return {
|
||||
grid_rows: 2,
|
||||
grid_columns: 2,
|
||||
grid_min_rows: 2,
|
||||
rows: 2,
|
||||
columns: 6,
|
||||
min_columns: 2,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
return {
|
||||
grid_rows: 1,
|
||||
grid_columns: 1,
|
||||
rows: 1,
|
||||
columns: 3,
|
||||
min_columns: 2,
|
||||
min_rows: 1,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import { createHeaderFooterElement } from "../create-element/create-header-footer-element";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceGridOptions,
|
||||
LovelaceHeaderFooter,
|
||||
LovelaceLayoutOptions,
|
||||
} from "../types";
|
||||
import type { HuiErrorCard } from "./hui-error-card";
|
||||
import type { EntityCardConfig } from "./types";
|
||||
@ -249,12 +249,12 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: 2,
|
||||
grid_rows: 2,
|
||||
grid_min_columns: 2,
|
||||
grid_min_rows: 2,
|
||||
columns: 6,
|
||||
rows: 2,
|
||||
min_columns: 6,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ import "../heading-badges/hui-heading-badge";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { HeadingCardConfig } from "./types";
|
||||
|
||||
@ -65,10 +65,11 @@ export class HuiHeadingCard extends LitElement implements LovelaceCard {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: "full",
|
||||
grid_rows: this._config?.heading_style === "subtitle" ? "auto" : 1,
|
||||
columns: "full",
|
||||
rows: this._config?.heading_style === "subtitle" ? "auto" : 1,
|
||||
min_columns: 3,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { HumidifierCardConfig } from "./types";
|
||||
|
||||
@ -171,21 +171,21 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
const grid_columns = 4;
|
||||
let grid_rows = 5;
|
||||
let grid_min_rows = 2;
|
||||
const grid_min_columns = 2;
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
const columns = 12;
|
||||
let rows = 5;
|
||||
let min_rows = 2;
|
||||
const min_columns = 6;
|
||||
if (this._config?.features?.length) {
|
||||
const featureHeight = Math.ceil((this._config.features.length * 2) / 3);
|
||||
grid_rows += featureHeight;
|
||||
grid_min_rows += featureHeight;
|
||||
rows += featureHeight;
|
||||
min_rows += featureHeight;
|
||||
}
|
||||
return {
|
||||
grid_columns,
|
||||
grid_rows,
|
||||
grid_min_rows,
|
||||
grid_min_columns,
|
||||
columns,
|
||||
rows,
|
||||
min_columns,
|
||||
min_rows,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { IFRAME_SANDBOX } from "../../../util/iframe";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { IframeCardConfig } from "./types";
|
||||
|
||||
@ -113,11 +113,12 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: "full",
|
||||
grid_rows: 4,
|
||||
grid_min_rows: 2,
|
||||
columns: "full",
|
||||
rows: 4,
|
||||
min_columns: 3,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,8 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/map/ha-map";
|
||||
import type {
|
||||
@ -23,15 +23,15 @@ import type {
|
||||
} from "../../../components/map/ha-map";
|
||||
import type { HistoryStates } from "../../../data/history";
|
||||
import { subscribeHistoryStatesTimeWindow } from "../../../data/history";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { findEntities } from "../common/find-entities";
|
||||
import {
|
||||
hasConfigChanged,
|
||||
hasConfigOrEntitiesChanged,
|
||||
} from "../common/has-changed";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { findEntities } from "../common/find-entities";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import type { EntityConfig } from "../entity-rows/types";
|
||||
import type { LovelaceCard, LovelaceLayoutOptions } from "../types";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../types";
|
||||
import type { MapCardConfig } from "./types";
|
||||
|
||||
export const DEFAULT_HOURS_TO_SHOW = 0;
|
||||
@ -431,12 +431,12 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
);
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: "full",
|
||||
grid_rows: 4,
|
||||
grid_min_columns: 2,
|
||||
grid_min_rows: 2,
|
||||
columns: "full",
|
||||
rows: 4,
|
||||
min_columns: 6,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { findEntities } from "../common/find-entities";
|
||||
import type { GraphHeaderFooterConfig } from "../header-footer/types";
|
||||
import type { LovelaceCardEditor, LovelaceLayoutOptions } from "../types";
|
||||
import type { LovelaceCardEditor, LovelaceGridOptions } from "../types";
|
||||
import { HuiEntityCard } from "./hui-entity-card";
|
||||
import type { EntityCardConfig, SensorCardConfig } from "./types";
|
||||
|
||||
@ -73,12 +73,12 @@ class HuiSensorCard extends HuiEntityCard {
|
||||
super.setConfig(entityCardConfig);
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: 2,
|
||||
grid_rows: 2,
|
||||
grid_min_columns: 2,
|
||||
grid_min_rows: 2,
|
||||
columns: 6,
|
||||
rows: 2,
|
||||
min_columns: 6,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceHeaderFooter,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { HuiErrorCard } from "./hui-error-card";
|
||||
import type { EntityCardConfig, StatisticCardConfig } from "./types";
|
||||
@ -249,12 +249,12 @@ export class HuiStatisticCard extends LitElement implements LovelaceCard {
|
||||
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
return {
|
||||
grid_columns: 2,
|
||||
grid_rows: 2,
|
||||
grid_min_columns: 2,
|
||||
grid_min_rows: 2,
|
||||
columns: 6,
|
||||
rows: 2,
|
||||
min_columns: 6,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { ThermostatCardConfig } from "./types";
|
||||
|
||||
@ -163,21 +163,21 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
const grid_columns = 4;
|
||||
let grid_rows = 5;
|
||||
let grid_min_rows = 2;
|
||||
const grid_min_columns = 2;
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
const columns = 12;
|
||||
let rows = 5;
|
||||
let min_rows = 2;
|
||||
const min_columns = 6;
|
||||
if (this._config?.features?.length) {
|
||||
const featureHeight = Math.ceil((this._config.features.length * 2) / 3);
|
||||
grid_rows += featureHeight;
|
||||
grid_min_rows += featureHeight;
|
||||
rows += featureHeight;
|
||||
min_rows += featureHeight;
|
||||
}
|
||||
return {
|
||||
grid_columns,
|
||||
grid_rows,
|
||||
grid_min_rows,
|
||||
grid_min_columns,
|
||||
columns,
|
||||
rows,
|
||||
min_columns,
|
||||
min_rows,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ import { hasAction } from "../common/has-action";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import { renderTileBadge } from "./tile/badges/tile-badge";
|
||||
import type { ThermostatCardConfig, TileCardConfig } from "./types";
|
||||
@ -109,22 +109,22 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
const grid_columns = 2;
|
||||
let grid_min_columns = 2;
|
||||
let grid_rows = 1;
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
const columns = 6;
|
||||
let min_columns = 6;
|
||||
let rows = 1;
|
||||
if (this._config?.features?.length) {
|
||||
grid_rows += this._config.features.length;
|
||||
rows += this._config.features.length;
|
||||
}
|
||||
if (this._config?.vertical) {
|
||||
grid_rows++;
|
||||
grid_min_columns = 1;
|
||||
rows++;
|
||||
min_columns = 3;
|
||||
}
|
||||
return {
|
||||
grid_columns,
|
||||
grid_rows,
|
||||
grid_min_rows: grid_rows,
|
||||
grid_min_columns,
|
||||
columns,
|
||||
rows,
|
||||
min_columns,
|
||||
min_rows: rows,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
LovelaceGridOptions,
|
||||
} from "../types";
|
||||
import type { WeatherForecastCardConfig } from "./types";
|
||||
|
||||
@ -418,31 +418,31 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
return typeof item !== "undefined" && item !== null;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
if (
|
||||
this._config?.show_current !== false &&
|
||||
this._config?.show_forecast !== false
|
||||
) {
|
||||
return {
|
||||
grid_columns: 4,
|
||||
grid_min_columns: 2,
|
||||
grid_rows: 4,
|
||||
grid_min_rows: 4,
|
||||
columns: 12,
|
||||
rows: 4,
|
||||
min_columns: 6,
|
||||
min_rows: 4,
|
||||
};
|
||||
}
|
||||
if (this._config?.show_forecast !== false) {
|
||||
return {
|
||||
grid_columns: 4,
|
||||
grid_min_columns: 2,
|
||||
grid_rows: 3,
|
||||
grid_min_rows: 3,
|
||||
columns: 12,
|
||||
rows: 3,
|
||||
min_columns: 6,
|
||||
min_rows: 3,
|
||||
};
|
||||
}
|
||||
return {
|
||||
grid_columns: 4,
|
||||
grid_min_columns: 2,
|
||||
grid_rows: 2,
|
||||
grid_min_rows: 2,
|
||||
columns: 12,
|
||||
rows: 2,
|
||||
min_columns: 6,
|
||||
min_rows: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ export class HuiCardEditMode extends LitElement {
|
||||
}
|
||||
|
||||
private _handleAction(ev) {
|
||||
switch (ev.target.action) {
|
||||
switch (ev.currentTarget.action) {
|
||||
case "edit":
|
||||
this._editCard();
|
||||
break;
|
||||
|
@ -2492,10 +2492,15 @@
|
||||
"show_full_logs": "Show full logs",
|
||||
"select_number_of_lines": "Select number of lines to download",
|
||||
"lines": "Lines",
|
||||
"download_full_log": "Download full log",
|
||||
"download_logs": "Download logs",
|
||||
"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.",
|
||||
"haos_boots_title": "Logs of HAOS startup",
|
||||
"show_haos_boots": "Show HAOS startups",
|
||||
"hide_haos_boots": "Hide HAOS startups",
|
||||
"full_width": "Full width",
|
||||
"wrap_lines": "Wrap lines",
|
||||
"current": "Current",
|
||||
"previous": "Previous",
|
||||
"startups_ago": "{boot} startups ago",
|
||||
@ -3581,7 +3586,9 @@
|
||||
"stopped_unknown_reason": "Stopped because of unknown reason {reason} at {time} (runtime: {executiontime} seconds)",
|
||||
"disabled": "(disabled)",
|
||||
"triggered_by": "{triggeredBy, select, \n alias {{alias} triggered}\n other {Triggered} \n} {triggeredPath, select, \n trigger {by the {trigger}}\n other {manually} \n} at {time}",
|
||||
"path_error": "Unable to extract path {path}. Download trace and report as bug."
|
||||
"path_error": "Unable to extract path {path}. Download trace and report as bug.",
|
||||
"not_all_entries_are_related_automation_note": "Not all shown logbook entries might be related to this automation.",
|
||||
"not_all_entries_are_related_script_note": "Not all shown logbook entries might be related to this script."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -7848,6 +7855,62 @@
|
||||
"restore": "[%key:ui::components::data-table::settings::restore%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel": {
|
||||
"config": {
|
||||
"logs": {
|
||||
"caption": "[%key:ui::panel::config::logs::caption%]",
|
||||
"description": "[%key:ui::panel::config::logs::description%]",
|
||||
"details": "[%key:ui::panel::config::logs::details%]",
|
||||
"search": "[%key:ui::panel::config::logs::search%]",
|
||||
"failed_get_logs": "[%key:ui::panel::config::logs::failed_get_logs%]",
|
||||
"no_issues_search": "[%key:ui::panel::config::logs::no_issues_search%]",
|
||||
"load_logs": "[%key:ui::panel::config::logs::load_logs%]",
|
||||
"nr_of_lines": "[%key:ui::panel::config::logs::nr_of_lines%]",
|
||||
"loading_log": "[%key:ui::panel::config::logs::loading_log%]",
|
||||
"no_errors": "[%key:ui::panel::config::logs::no_errors%]",
|
||||
"no_issues": "[%key:ui::panel::config::logs::no_issues%]",
|
||||
"clear": "[%key:ui::panel::config::logs::clear%]",
|
||||
"refresh": "[%key:ui::panel::config::logs::refresh%]",
|
||||
"copy": "[%key:ui::panel::config::logs::copy%]",
|
||||
"log_provider": "[%key:ui::panel::config::logs::log_provider%]",
|
||||
"multiple_messages": "[%key:ui::panel::config::logs::multiple_messages%]",
|
||||
"level": {
|
||||
"critical": "[%key:ui::panel::config::logs::level::critical%]",
|
||||
"error": "[%key:ui::panel::config::logs::level::error%]",
|
||||
"warning": "[%key:ui::panel::config::logs::level::warning%]",
|
||||
"info": "[%key:ui::panel::config::logs::level::info%]",
|
||||
"debug": "[%key:ui::panel::config::logs::level::debug%]"
|
||||
},
|
||||
"custom_integration": "[%key:ui::panel::config::logs::custom_integration%]",
|
||||
"error_from_custom_integration": "[%key:ui::panel::config::logs::error_from_custom_integration%]",
|
||||
"show_full_logs": "[%key:ui::panel::config::logs::show_full_logs%]",
|
||||
"select_number_of_lines": "[%key:ui::panel::config::logs::select_number_of_lines%]",
|
||||
"lines": "[%key:ui::panel::config::logs::lines%]",
|
||||
"download_logs": "[%key:ui::panel::config::logs::download_logs%]",
|
||||
"scroll_down_button": "[%key:ui::panel::config::logs::scroll_down_button%]",
|
||||
"provider_not_found": "[%key:ui::panel::config::logs::provider_not_found%]",
|
||||
"provider_not_available": "[%key:ui::panel::config::logs::provider_not_available%]",
|
||||
"haos_boots_title": "[%key:ui::panel::config::logs::haos_boots_title%]",
|
||||
"show_haos_boots": "[%key:ui::panel::config::logs::show_haos_boots%]",
|
||||
"hide_haos_boots": "[%key:ui::panel::config::logs::hide_haos_boots%]",
|
||||
"full_width": "[%key:ui::panel::config::logs::full_width%]",
|
||||
"wrap_lines": "[%key:ui::panel::config::logs::wrap_lines%]",
|
||||
"current": "[%key:ui::panel::config::logs::current%]",
|
||||
"previous": "[%key:ui::panel::config::logs::previous%]",
|
||||
"startups_ago": "[%key:ui::panel::config::logs::startups_ago%]",
|
||||
"detail": {
|
||||
"logger": "[%key:ui::panel::config::logs::detail::logger%]",
|
||||
"source": "[%key:ui::panel::config::logs::detail::source%]",
|
||||
"integration": "[%key:ui::panel::config::integrations::integration%]",
|
||||
"documentation": "[%key:ui::panel::config::logs::detail::documentation%]",
|
||||
"issues": "[%key:ui::panel::config::logs::detail::issues%]",
|
||||
"first_occurred": "[%key:ui::panel::config::logs::detail::first_occurred%]",
|
||||
"occurrences": "[%key:ui::panel::config::logs::detail::occurrences%]",
|
||||
"last_logged": "[%key:ui::panel::config::logs::detail::last_logged%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { isIosApp } from "./is_ios";
|
||||
|
||||
export const fileDownload = (href: string, filename = ""): void => {
|
||||
const a = document.createElement("a");
|
||||
a.target = "_blank";
|
||||
@ -8,3 +11,6 @@ export const fileDownload = (href: string, filename = ""): void => {
|
||||
a.dispatchEvent(new MouseEvent("click"));
|
||||
document.body.removeChild(a);
|
||||
};
|
||||
|
||||
export const downloadFileSupported = (hass: HomeAssistant): boolean =>
|
||||
!isIosApp(hass) || !!hass.auth.external?.config.downloadFileSupported;
|
||||
|
5
src/util/is_ios.ts
Normal file
5
src/util/is_ios.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { isSafari } from "./is_safari";
|
||||
|
||||
export const isIosApp = (hass: HomeAssistant): boolean =>
|
||||
isSafari && !!hass.auth.external;
|
Loading…
x
Reference in New Issue
Block a user