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