mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Simplify data table template (#17825)
* Simplify data table template * Fix backup and gallery
This commit is contained in:
parent
5e107d43d7
commit
3349031cbd
@ -343,7 +343,7 @@ export class DemoEntityState extends LitElement {
|
|||||||
const columns: DataTableColumnContainer<EntityRowData> = {
|
const columns: DataTableColumnContainer<EntityRowData> = {
|
||||||
icon: {
|
icon: {
|
||||||
title: "Icon",
|
title: "Icon",
|
||||||
template: (_, entry) => html`
|
template: (entry) => html`
|
||||||
<state-badge
|
<state-badge
|
||||||
.stateObj=${entry.stateObj}
|
.stateObj=${entry.stateObj}
|
||||||
.stateColor=${true}
|
.stateColor=${true}
|
||||||
@ -360,7 +360,7 @@ export class DemoEntityState extends LitElement {
|
|||||||
title: "State",
|
title: "State",
|
||||||
width: "20%",
|
width: "20%",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (_, entry) =>
|
template: (entry) =>
|
||||||
html`${computeStateDisplay(
|
html`${computeStateDisplay(
|
||||||
hass.localize,
|
hass.localize,
|
||||||
entry.stateObj,
|
entry.stateObj,
|
||||||
@ -371,14 +371,14 @@ export class DemoEntityState extends LitElement {
|
|||||||
},
|
},
|
||||||
device_class: {
|
device_class: {
|
||||||
title: "Device class",
|
title: "Device class",
|
||||||
template: (dc) => html`${dc ?? "-"}`,
|
template: (entry) => html`${entry.device_class ?? "-"}`,
|
||||||
width: "20%",
|
width: "20%",
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
domain: {
|
domain: {
|
||||||
title: "Domain",
|
title: "Domain",
|
||||||
template: (_, entry) => html`${computeDomain(entry.entity_id)}`,
|
template: (entry) => html`${computeDomain(entry.entity_id)}`,
|
||||||
width: "20%",
|
width: "20%",
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
@ -49,6 +49,10 @@ import { showHassioCreateBackupDialog } from "../dialogs/backup/show-dialog-hass
|
|||||||
import { supervisorTabs } from "../hassio-tabs";
|
import { supervisorTabs } from "../hassio-tabs";
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
|
type BackupItem = HassioBackup & {
|
||||||
|
secondary: string;
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("hassio-backups")
|
@customElement("hassio-backups")
|
||||||
export class HassioBackups extends LitElement {
|
export class HassioBackups extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -117,15 +121,15 @@ export class HassioBackups extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean): DataTableColumnContainer => ({
|
(narrow: boolean): DataTableColumnContainer<BackupItem> => ({
|
||||||
name: {
|
name: {
|
||||||
title: this.supervisor.localize("backup.name"),
|
title: this.supervisor.localize("backup.name"),
|
||||||
main: true,
|
main: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (entry: string, backup: any) =>
|
template: (backup) =>
|
||||||
html`${entry || backup.slug}
|
html`${backup.name || backup.slug}
|
||||||
<div class="secondary">${backup.secondary}</div>`,
|
<div class="secondary">${backup.secondary}</div>`,
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
@ -134,7 +138,7 @@ export class HassioBackups extends LitElement {
|
|||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: number) => Math.ceil(entry * 10) / 10 + " MB",
|
template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB",
|
||||||
},
|
},
|
||||||
location: {
|
location: {
|
||||||
title: this.supervisor.localize("backup.location"),
|
title: this.supervisor.localize("backup.location"),
|
||||||
@ -142,8 +146,8 @@ export class HassioBackups extends LitElement {
|
|||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: string | null) =>
|
template: (backup) =>
|
||||||
entry || this.supervisor.localize("backup.data_disk"),
|
backup.location || this.supervisor.localize("backup.data_disk"),
|
||||||
},
|
},
|
||||||
date: {
|
date: {
|
||||||
title: this.supervisor.localize("backup.created"),
|
title: this.supervisor.localize("backup.created"),
|
||||||
@ -152,8 +156,8 @@ export class HassioBackups extends LitElement {
|
|||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: string) =>
|
template: (backup) =>
|
||||||
relativeTime(new Date(entry), this.hass.locale),
|
relativeTime(new Date(backup.date), this.hass.locale),
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
title: "",
|
title: "",
|
||||||
@ -163,7 +167,7 @@ export class HassioBackups extends LitElement {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
private _backupData = memoizeOne((backups: HassioBackup[]) =>
|
private _backupData = memoizeOne((backups: HassioBackup[]): BackupItem[] =>
|
||||||
backups.map((backup) => ({
|
backups.map((backup) => ({
|
||||||
...backup,
|
...backup,
|
||||||
secondary: this._computeBackupContent(backup),
|
secondary: this._computeBackupContent(backup),
|
||||||
|
@ -74,7 +74,7 @@ export interface DataTableColumnData<T = any> extends DataTableSortColumnData {
|
|||||||
title: TemplateResult | string;
|
title: TemplateResult | string;
|
||||||
label?: TemplateResult | string;
|
label?: TemplateResult | string;
|
||||||
type?: "numeric" | "icon" | "icon-button" | "overflow-menu" | "flex";
|
type?: "numeric" | "icon" | "icon-button" | "overflow-menu" | "flex";
|
||||||
template?: (data: any, row: T) => TemplateResult | string | typeof nothing;
|
template?: (row: T) => TemplateResult | string | typeof nothing;
|
||||||
width?: string;
|
width?: string;
|
||||||
maxWidth?: string;
|
maxWidth?: string;
|
||||||
grows?: boolean;
|
grows?: boolean;
|
||||||
@ -431,7 +431,7 @@ export class HaDataTable extends LitElement {
|
|||||||
})
|
})
|
||||||
: ""}
|
: ""}
|
||||||
>
|
>
|
||||||
${column.template ? column.template(row[key], row) : row[key]}
|
${column.template ? column.template(row) : row[key]}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})}
|
})}
|
||||||
|
@ -62,17 +62,16 @@ export class HaConfigApplicationCredentials extends LitElement {
|
|||||||
),
|
),
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (_, entry: ApplicationCredential) => html`${entry.name}`,
|
template: (entry) => html`${entry.name}`,
|
||||||
},
|
},
|
||||||
clientId: {
|
client_id: {
|
||||||
title: localize(
|
title: localize(
|
||||||
"ui.panel.config.application_credentials.picker.headers.client_id"
|
"ui.panel.config.application_credentials.picker.headers.client_id"
|
||||||
),
|
),
|
||||||
width: "30%",
|
width: "30%",
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (_, entry: ApplicationCredential) =>
|
template: (entry) => html`${entry.client_id}`,
|
||||||
html`${entry.client_id}`,
|
|
||||||
},
|
},
|
||||||
application: {
|
application: {
|
||||||
title: localize(
|
title: localize(
|
||||||
@ -81,7 +80,7 @@ export class HaConfigApplicationCredentials extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
width: "30%",
|
width: "30%",
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
template: (_, entry) => html`${domainToName(localize, entry.domain)}`,
|
template: (entry) => html`${domainToName(localize, entry.domain)}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,6 +55,12 @@ import { findRelated } from "../../../data/search";
|
|||||||
import { fetchBlueprints } from "../../../data/blueprint";
|
import { fetchBlueprints } from "../../../data/blueprint";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
|
|
||||||
|
type AutomationItem = AutomationEntity & {
|
||||||
|
name: string;
|
||||||
|
last_triggered?: string | undefined;
|
||||||
|
disabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("ha-automation-picker")
|
@customElement("ha-automation-picker")
|
||||||
class HaAutomationPicker extends LitElement {
|
class HaAutomationPicker extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -79,7 +85,7 @@ class HaAutomationPicker extends LitElement {
|
|||||||
(
|
(
|
||||||
automations: AutomationEntity[],
|
automations: AutomationEntity[],
|
||||||
filteredAutomations?: string[] | null
|
filteredAutomations?: string[] | null
|
||||||
) => {
|
): AutomationItem[] => {
|
||||||
if (filteredAutomations === null) {
|
if (filteredAutomations === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -100,14 +106,14 @@ class HaAutomationPicker extends LitElement {
|
|||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean, _locale): DataTableColumnContainer => {
|
(narrow: boolean, _locale): DataTableColumnContainer => {
|
||||||
const columns: DataTableColumnContainer = {
|
const columns: DataTableColumnContainer<AutomationItem> = {
|
||||||
icon: {
|
icon: {
|
||||||
title: "",
|
title: "",
|
||||||
label: this.hass.localize(
|
label: this.hass.localize(
|
||||||
"ui.panel.config.automation.picker.headers.state"
|
"ui.panel.config.automation.picker.headers.state"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_, automation) =>
|
template: (automation) =>
|
||||||
html`<ha-state-icon
|
html`<ha-state-icon
|
||||||
.state=${automation}
|
.state=${automation}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
@ -128,12 +134,12 @@ class HaAutomationPicker extends LitElement {
|
|||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: narrow
|
template: narrow
|
||||||
? (name, automation: any) => {
|
? (automation) => {
|
||||||
const date = new Date(automation.attributes.last_triggered);
|
const date = new Date(automation.attributes.last_triggered);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const dayDifference = differenceInDays(now, date);
|
const dayDifference = differenceInDays(now, date);
|
||||||
return html`
|
return html`
|
||||||
${name}
|
${automation.name}
|
||||||
<div class="secondary">
|
<div class="secondary">
|
||||||
${this.hass.localize("ui.card.automation.last_triggered")}:
|
${this.hass.localize("ui.card.automation.last_triggered")}:
|
||||||
${automation.attributes.last_triggered
|
${automation.attributes.last_triggered
|
||||||
@ -156,20 +162,17 @@ class HaAutomationPicker extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
width: "20%",
|
width: "20%",
|
||||||
title: this.hass.localize("ui.card.automation.last_triggered"),
|
title: this.hass.localize("ui.card.automation.last_triggered"),
|
||||||
template: (last_triggered) => {
|
template: (automation) => {
|
||||||
const date = new Date(last_triggered);
|
if (!automation.last_triggered) {
|
||||||
|
return this.hass.localize("ui.components.relative_time.never");
|
||||||
|
}
|
||||||
|
const date = new Date(automation.last_triggered);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const dayDifference = differenceInDays(now, date);
|
const dayDifference = differenceInDays(now, date);
|
||||||
return html`
|
return html`
|
||||||
${last_triggered
|
${dayDifference > 3
|
||||||
? dayDifference > 3
|
? formatShortDateTime(date, this.hass.locale, this.hass.config)
|
||||||
? formatShortDateTime(
|
: relativeTime(date, this.hass.locale)}
|
||||||
date,
|
|
||||||
this.hass.locale,
|
|
||||||
this.hass.config
|
|
||||||
)
|
|
||||||
: relativeTime(date, this.hass.locale)
|
|
||||||
: this.hass.localize("ui.components.relative_time.never")}
|
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -178,8 +181,8 @@ class HaAutomationPicker extends LitElement {
|
|||||||
columns.disabled = this.narrow
|
columns.disabled = this.narrow
|
||||||
? {
|
? {
|
||||||
title: "",
|
title: "",
|
||||||
template: (disabled: boolean) =>
|
template: (automation) =>
|
||||||
disabled
|
automation.disabled
|
||||||
? html`
|
? html`
|
||||||
<simple-tooltip animation-delay="0" position="left">
|
<simple-tooltip animation-delay="0" position="left">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -196,8 +199,8 @@ class HaAutomationPicker extends LitElement {
|
|||||||
: {
|
: {
|
||||||
width: "20%",
|
width: "20%",
|
||||||
title: "",
|
title: "",
|
||||||
template: (disabled: boolean) =>
|
template: (automation) =>
|
||||||
disabled
|
automation.disabled
|
||||||
? html`
|
? html`
|
||||||
<ha-chip>
|
<ha-chip>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -212,7 +215,7 @@ class HaAutomationPicker extends LitElement {
|
|||||||
title: "",
|
title: "",
|
||||||
width: this.narrow ? undefined : "10%",
|
width: this.narrow ? undefined : "10%",
|
||||||
type: "overflow-menu",
|
type: "overflow-menu",
|
||||||
template: (_: string, automation: any) => html`
|
template: (automation) => html`
|
||||||
<ha-icon-overflow-menu
|
<ha-icon-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
narrow
|
narrow
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { mdiDelete, mdiDownload, mdiPlus } from "@mdi/js";
|
|
||||||
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
||||||
|
import { mdiDelete, mdiDownload, mdiPlus } from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
css,
|
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
html,
|
|
||||||
LitElement,
|
LitElement,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
css,
|
||||||
|
html,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoize from "memoize-one";
|
import memoize from "memoize-one";
|
||||||
@ -48,15 +48,15 @@ class HaConfigBackup extends LitElement {
|
|||||||
@state() private _backupData?: BackupData;
|
@state() private _backupData?: BackupData;
|
||||||
|
|
||||||
private _columns = memoize(
|
private _columns = memoize(
|
||||||
(narrow, _language): DataTableColumnContainer => ({
|
(narrow, _language): DataTableColumnContainer<BackupContent> => ({
|
||||||
name: {
|
name: {
|
||||||
title: this.hass.localize("ui.panel.config.backup.name"),
|
title: this.hass.localize("ui.panel.config.backup.name"),
|
||||||
main: true,
|
main: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (entry: string, backup: BackupContent) =>
|
template: (backup) =>
|
||||||
html`${entry}
|
html`${backup.name}
|
||||||
<div class="secondary">${backup.path}</div>`,
|
<div class="secondary">${backup.path}</div>`,
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
@ -65,7 +65,7 @@ class HaConfigBackup extends LitElement {
|
|||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: number) => Math.ceil(entry * 10) / 10 + " MB",
|
template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB",
|
||||||
},
|
},
|
||||||
date: {
|
date: {
|
||||||
title: this.hass.localize("ui.panel.config.backup.created"),
|
title: this.hass.localize("ui.panel.config.backup.created"),
|
||||||
@ -74,15 +74,15 @@ class HaConfigBackup extends LitElement {
|
|||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: string) =>
|
template: (backup) =>
|
||||||
relativeTime(new Date(entry), this.hass.locale),
|
relativeTime(new Date(backup.date), this.hass.locale),
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
title: "",
|
title: "",
|
||||||
width: "15%",
|
width: "15%",
|
||||||
type: "overflow-menu",
|
type: "overflow-menu",
|
||||||
template: (_: string, backup: BackupContent) =>
|
template: (backup) =>
|
||||||
html`<ha-icon-overflow-menu
|
html`<ha-icon-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
@ -10,14 +10,14 @@ import {
|
|||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
html,
|
|
||||||
LitElement,
|
LitElement,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
html,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { extractSearchParam } from "../../../common/url/search-params";
|
import { extractSearchParam } from "../../../common/url/search-params";
|
||||||
@ -32,7 +32,6 @@ import "../../../components/ha-icon-overflow-menu";
|
|||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import { showAutomationEditor } from "../../../data/automation";
|
import { showAutomationEditor } from "../../../data/automation";
|
||||||
import {
|
import {
|
||||||
BlueprintDomain,
|
|
||||||
BlueprintMetaData,
|
BlueprintMetaData,
|
||||||
Blueprints,
|
Blueprints,
|
||||||
deleteBlueprint,
|
deleteBlueprint,
|
||||||
@ -50,10 +49,12 @@ import { documentationUrl } from "../../../util/documentation-url";
|
|||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import { showAddBlueprintDialog } from "./show-dialog-import-blueprint";
|
import { showAddBlueprintDialog } from "./show-dialog-import-blueprint";
|
||||||
|
|
||||||
interface BlueprintMetaDataPath extends BlueprintMetaData {
|
type BlueprintMetaDataPath = BlueprintMetaData & {
|
||||||
path: string;
|
path: string;
|
||||||
error: boolean;
|
error: boolean;
|
||||||
}
|
type: "automation" | "script";
|
||||||
|
fullpath: string;
|
||||||
|
};
|
||||||
|
|
||||||
const createNewFunctions = {
|
const createNewFunctions = {
|
||||||
automation: (blueprintMeta: BlueprintMetaDataPath) => {
|
automation: (blueprintMeta: BlueprintMetaDataPath) => {
|
||||||
@ -86,7 +87,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
private _processedBlueprints = memoizeOne(
|
private _processedBlueprints = memoizeOne(
|
||||||
(blueprints: Record<string, Blueprints>) => {
|
(blueprints: Record<string, Blueprints>): BlueprintMetaDataPath[] => {
|
||||||
const result: any[] = [];
|
const result: any[] = [];
|
||||||
Object.entries(blueprints).forEach(([type, typeBlueprints]) =>
|
Object.entries(blueprints).forEach(([type, typeBlueprints]) =>
|
||||||
Object.entries(typeBlueprints).forEach(([path, blueprint]) => {
|
Object.entries(typeBlueprints).forEach(([path, blueprint]) => {
|
||||||
@ -125,9 +126,9 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: narrow
|
template: narrow
|
||||||
? (name, entity: any) => html`
|
? (blueprint) => html`
|
||||||
${name}<br />
|
${blueprint.name}<br />
|
||||||
<div class="secondary">${entity.path}</div>
|
<div class="secondary">${blueprint.path}</div>
|
||||||
`
|
`
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
@ -135,9 +136,9 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
"ui.panel.config.blueprint.overview.headers.type"
|
"ui.panel.config.blueprint.overview.headers.type"
|
||||||
),
|
),
|
||||||
template: (type: BlueprintDomain) =>
|
template: (blueprint) =>
|
||||||
html`${this.hass.localize(
|
html`${this.hass.localize(
|
||||||
`ui.panel.config.blueprint.overview.types.${type}`
|
`ui.panel.config.blueprint.overview.types.${blueprint.type}`
|
||||||
)}`,
|
)}`,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
@ -163,7 +164,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
title: "",
|
title: "",
|
||||||
width: this.narrow ? undefined : "10%",
|
width: this.narrow ? undefined : "10%",
|
||||||
type: "overflow-menu",
|
type: "overflow-menu",
|
||||||
template: (_: string, blueprint) =>
|
template: (blueprint) =>
|
||||||
blueprint.error
|
blueprint.error
|
||||||
? html`<ha-svg-icon
|
? html`<ha-svg-icon
|
||||||
style="color: var(--error-color); display: block; margin-inline-end: 12px; margin-inline-start: auto;"
|
style="color: var(--error-color); display: block; margin-inline-end: 12px; margin-inline-start: auto;"
|
||||||
@ -177,7 +178,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
{
|
{
|
||||||
path: mdiPlus,
|
path: mdiPlus,
|
||||||
label: this.hass.localize(
|
label: this.hass.localize(
|
||||||
`ui.panel.config.blueprint.overview.create_${blueprint.domain}`
|
`ui.panel.config.blueprint.overview.create_${blueprint.type}`
|
||||||
),
|
),
|
||||||
action: () => this._createNew(blueprint),
|
action: () => this._createNew(blueprint),
|
||||||
},
|
},
|
||||||
@ -324,7 +325,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||||
const blueprint = this._processedBlueprints(this.blueprints).find(
|
const blueprint = this._processedBlueprints(this.blueprints).find(
|
||||||
(b) => b.fullpath === ev.detail.id
|
(b) => b.fullpath === ev.detail.id
|
||||||
);
|
)!;
|
||||||
if (blueprint.error) {
|
if (blueprint.error) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.hass.localize("ui.panel.config.blueprint.overview.error", {
|
title: this.hass.localize("ui.panel.config.blueprint.overview.error", {
|
||||||
|
@ -2,27 +2,26 @@ import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
|||||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiCancel, mdiFilterVariant, mdiPlus } from "@mdi/js";
|
import { mdiCancel, mdiFilterVariant, mdiPlus } from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
css,
|
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
html,
|
|
||||||
LitElement,
|
LitElement,
|
||||||
nothing,
|
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
css,
|
||||||
|
html,
|
||||||
|
nothing,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import {
|
import {
|
||||||
protocolIntegrationPicked,
|
|
||||||
PROTOCOL_INTEGRATIONS,
|
PROTOCOL_INTEGRATIONS,
|
||||||
|
protocolIntegrationPicked,
|
||||||
} from "../../../common/integrations/protocolIntegrationPicked";
|
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
import {
|
import {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
DataTableRowData,
|
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
import "../../../components/entity/ha-battery-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
@ -33,9 +32,9 @@ import "../../../components/ha-icon-button";
|
|||||||
import { AreaRegistryEntry } from "../../../data/area_registry";
|
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries";
|
import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries";
|
||||||
import {
|
import {
|
||||||
computeDeviceName,
|
|
||||||
DeviceEntityLookup,
|
DeviceEntityLookup,
|
||||||
DeviceRegistryEntry,
|
DeviceRegistryEntry,
|
||||||
|
computeDeviceName,
|
||||||
} from "../../../data/device_registry";
|
} from "../../../data/device_registry";
|
||||||
import {
|
import {
|
||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
@ -231,7 +230,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
outputDevices = outputDevices.filter((device) => !device.disabled_by);
|
outputDevices = outputDevices.filter((device) => !device.disabled_by);
|
||||||
}
|
}
|
||||||
|
|
||||||
outputDevices = outputDevices.map((device) => {
|
const formattedOutputDevices = outputDevices.map((device) => {
|
||||||
const deviceEntries = sortConfigEntries(
|
const deviceEntries = sortConfigEntries(
|
||||||
device.config_entries
|
device.config_entries
|
||||||
.filter((entId) => entId in entryLookup)
|
.filter((entId) => entId in entryLookup)
|
||||||
@ -277,22 +276,25 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
this._numHiddenDevices = startLength - outputDevices.length;
|
this._numHiddenDevices = startLength - formattedOutputDevices.length;
|
||||||
return {
|
return {
|
||||||
devicesOutput: outputDevices,
|
devicesOutput: formattedOutputDevices,
|
||||||
filteredConfigEntry: filterConfigEntry,
|
filteredConfigEntry: filterConfigEntry,
|
||||||
filteredDomains,
|
filteredDomains,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne((narrow: boolean, showDisabled: boolean) => {
|
||||||
(narrow: boolean, showDisabled: boolean): DataTableColumnContainer => {
|
type DeviceItem = ReturnType<
|
||||||
const columns: DataTableColumnContainer = {
|
typeof this._devicesAndFilterDomains
|
||||||
|
>["devicesOutput"][number];
|
||||||
|
|
||||||
|
const columns: DataTableColumnContainer<DeviceItem> = {
|
||||||
icon: {
|
icon: {
|
||||||
title: "",
|
title: "",
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_icon, device) =>
|
template: (device) =>
|
||||||
device.domains.length
|
device.domains.length
|
||||||
? html`<img
|
? html`<img
|
||||||
alt=""
|
alt=""
|
||||||
@ -309,24 +311,20 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
|
|
||||||
if (narrow) {
|
if (narrow) {
|
||||||
columns.name = {
|
columns.name = {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize("ui.panel.config.devices.data_table.device"),
|
||||||
"ui.panel.config.devices.data_table.device"
|
|
||||||
),
|
|
||||||
main: true,
|
main: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (name, device: DataTableRowData) => html`
|
template: (device) => html`
|
||||||
${name}
|
${device.name}
|
||||||
<div class="secondary">${device.area} | ${device.integration}</div>
|
<div class="secondary">${device.area} | ${device.integration}</div>
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
columns.name = {
|
columns.name = {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize("ui.panel.config.devices.data_table.device"),
|
||||||
"ui.panel.config.devices.data_table.device"
|
|
||||||
),
|
|
||||||
main: true,
|
main: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
@ -375,14 +373,13 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
width: narrow ? "95px" : "15%",
|
width: narrow ? "95px" : "15%",
|
||||||
maxWidth: "95px",
|
maxWidth: "95px",
|
||||||
valueColumn: "battery_level",
|
valueColumn: "battery_level",
|
||||||
template: (batteryEntityPair: DeviceRowData["battery_entity"]) => {
|
template: (device) => {
|
||||||
|
const batteryEntityPair = device.battery_entity;
|
||||||
const battery =
|
const battery =
|
||||||
batteryEntityPair && batteryEntityPair[0]
|
batteryEntityPair && batteryEntityPair[0]
|
||||||
? this.hass.states[batteryEntityPair[0]]
|
? this.hass.states[batteryEntityPair[0]]
|
||||||
: undefined;
|
: undefined;
|
||||||
const batteryDomain = battery
|
const batteryDomain = battery ? computeStateDomain(battery) : undefined;
|
||||||
? computeStateDomain(battery)
|
|
||||||
: undefined;
|
|
||||||
const batteryCharging =
|
const batteryCharging =
|
||||||
batteryEntityPair && batteryEntityPair[1]
|
batteryEntityPair && batteryEntityPair[1]
|
||||||
? this.hass.states[batteryEntityPair[1]]
|
? this.hass.states[batteryEntityPair[1]]
|
||||||
@ -410,8 +407,8 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
"ui.panel.config.devices.data_table.disabled_by"
|
"ui.panel.config.devices.data_table.disabled_by"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (disabled_by) =>
|
template: (device) =>
|
||||||
disabled_by
|
device.disabled_by
|
||||||
? html`<div
|
? html`<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
style="display:inline-block; position: relative;"
|
style="display:inline-block; position: relative;"
|
||||||
@ -425,8 +422,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return columns;
|
return columns;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
public willUpdate(changedProps) {
|
public willUpdate(changedProps) {
|
||||||
if (changedProps.has("_searchParms")) {
|
if (changedProps.has("_searchParms")) {
|
||||||
|
@ -183,7 +183,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
"ui.panel.config.entities.picker.headers.state_icon"
|
"ui.panel.config.entities.picker.headers.state_icon"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_, entry: EntityRow) => html`
|
template: (entry) => html`
|
||||||
<ha-state-icon
|
<ha-state-icon
|
||||||
title=${ifDefined(entry.entity?.state)}
|
title=${ifDefined(entry.entity?.state)}
|
||||||
slot="item-icon"
|
slot="item-icon"
|
||||||
@ -201,12 +201,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: narrow
|
template: narrow
|
||||||
? (name, entity: EntityRow) => html`
|
? (entry) => html`
|
||||||
${name}<br />
|
${entry.name}<br />
|
||||||
<div class="secondary">
|
<div class="secondary">
|
||||||
${entity.entity_id} |
|
${entry.entity_id} |
|
||||||
${this.hass.localize(`component.${entity.platform}.title`) ||
|
${this.hass.localize(`component.${entry.platform}.title`) ||
|
||||||
entity.platform}
|
entry.platform}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: undefined,
|
: undefined,
|
||||||
@ -228,8 +228,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "20%",
|
width: "20%",
|
||||||
template: (platform) =>
|
template: (entry) =>
|
||||||
this.hass.localize(`component.${platform}.title`) || platform,
|
this.hass.localize(`component.${entry.platform}.title`) ||
|
||||||
|
entry.platform,
|
||||||
},
|
},
|
||||||
area: {
|
area: {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
@ -248,10 +249,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
hidden: narrow || !showDisabled,
|
hidden: narrow || !showDisabled,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "15%",
|
width: "15%",
|
||||||
template: (disabled_by: EntityRegistryEntry["disabled_by"]) =>
|
template: (entry) =>
|
||||||
disabled_by === null
|
entry.disabled_by === null
|
||||||
? "—"
|
? "—"
|
||||||
: this.hass.localize(`config_entry.disabled_by.${disabled_by}`),
|
: this.hass.localize(
|
||||||
|
`config_entry.disabled_by.${entry.disabled_by}`
|
||||||
|
),
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
@ -261,11 +264,11 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "68px",
|
width: "68px",
|
||||||
template: (_status, entity: EntityRow) =>
|
template: (entry) =>
|
||||||
entity.unavailable ||
|
entry.unavailable ||
|
||||||
entity.disabled_by ||
|
entry.disabled_by ||
|
||||||
entity.hidden_by ||
|
entry.hidden_by ||
|
||||||
entity.readonly
|
entry.readonly
|
||||||
? html`
|
? html`
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@ -273,32 +276,32 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
|||||||
>
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
color: entity.unavailable ? "var(--error-color)" : "",
|
color: entry.unavailable ? "var(--error-color)" : "",
|
||||||
})}
|
})}
|
||||||
.path=${entity.restored
|
.path=${entry.restored
|
||||||
? mdiRestoreAlert
|
? mdiRestoreAlert
|
||||||
: entity.unavailable
|
: entry.unavailable
|
||||||
? mdiAlertCircle
|
? mdiAlertCircle
|
||||||
: entity.disabled_by
|
: entry.disabled_by
|
||||||
? mdiCancel
|
? mdiCancel
|
||||||
: entity.hidden_by
|
: entry.hidden_by
|
||||||
? mdiEyeOff
|
? mdiEyeOff
|
||||||
: mdiPencilOff}
|
: mdiPencilOff}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
<simple-tooltip animation-delay="0" position="left">
|
<simple-tooltip animation-delay="0" position="left">
|
||||||
${entity.restored
|
${entry.restored
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.entities.picker.status.restored"
|
"ui.panel.config.entities.picker.status.restored"
|
||||||
)
|
)
|
||||||
: entity.unavailable
|
: entry.unavailable
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.entities.picker.status.unavailable"
|
"ui.panel.config.entities.picker.status.unavailable"
|
||||||
)
|
)
|
||||||
: entity.disabled_by
|
: entry.disabled_by
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.entities.picker.status.disabled"
|
"ui.panel.config.entities.picker.status.disabled"
|
||||||
)
|
)
|
||||||
: entity.hidden_by
|
: entry.hidden_by
|
||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.entities.picker.status.hidden"
|
"ui.panel.config.entities.picker.status.hidden"
|
||||||
)
|
)
|
||||||
|
@ -6,7 +6,10 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
import {
|
||||||
|
LocalizeFunc,
|
||||||
|
LocalizeKeys,
|
||||||
|
} from "../../../common/translations/localize";
|
||||||
import { extractSearchParam } from "../../../common/url/search-params";
|
import { extractSearchParam } from "../../../common/url/search-params";
|
||||||
import {
|
import {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
@ -27,6 +30,7 @@ import {
|
|||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import { domainToName } from "../../../data/integration";
|
import { domainToName } from "../../../data/integration";
|
||||||
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
||||||
|
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -38,9 +42,19 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
|||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "../integrations/ha-integration-overflow-menu";
|
import "../integrations/ha-integration-overflow-menu";
|
||||||
import { HelperDomain, isHelperDomain } from "./const";
|
import { isHelperDomain } from "./const";
|
||||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||||
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
|
||||||
|
type HelperItem = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
icon?: string;
|
||||||
|
entity_id: string;
|
||||||
|
editable?: boolean;
|
||||||
|
type: string;
|
||||||
|
configEntry?: ConfigEntry;
|
||||||
|
entity?: HassEntity;
|
||||||
|
};
|
||||||
|
|
||||||
// This groups items by a key but only returns last entry per key.
|
// This groups items by a key but only returns last entry per key.
|
||||||
const groupByOne = <T>(
|
const groupByOne = <T>(
|
||||||
@ -108,16 +122,16 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean, localize: LocalizeFunc): DataTableColumnContainer => {
|
(narrow: boolean, localize: LocalizeFunc): DataTableColumnContainer => {
|
||||||
const columns: DataTableColumnContainer = {
|
const columns: DataTableColumnContainer<HelperItem> = {
|
||||||
icon: {
|
icon: {
|
||||||
title: "",
|
title: "",
|
||||||
label: localize("ui.panel.config.helpers.picker.headers.icon"),
|
label: localize("ui.panel.config.helpers.picker.headers.icon"),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (icon, helper: any) =>
|
template: (helper) =>
|
||||||
helper.entity
|
helper.entity
|
||||||
? html`<ha-state-icon .state=${helper.entity}></ha-state-icon>`
|
? html`<ha-state-icon .state=${helper.entity}></ha-state-icon>`
|
||||||
: html`<ha-svg-icon
|
: html`<ha-svg-icon
|
||||||
.path=${icon}
|
.path=${helper.icon}
|
||||||
style="color: var(--error-color)"
|
style="color: var(--error-color)"
|
||||||
></ha-svg-icon>`,
|
></ha-svg-icon>`,
|
||||||
},
|
},
|
||||||
@ -128,10 +142,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
template: (name, item: any) => html`
|
template: (helper) => html`
|
||||||
${name}
|
${helper.name}
|
||||||
${narrow
|
${narrow
|
||||||
? html`<div class="secondary">${item.entity_id}</div> `
|
? html`<div class="secondary">${helper.entity_id}</div> `
|
||||||
: ""}
|
: ""}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@ -149,11 +163,13 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
width: "25%",
|
width: "25%",
|
||||||
filterable: true,
|
filterable: true,
|
||||||
template: (type: HelperDomain, row) =>
|
template: (helper) =>
|
||||||
row.configEntry
|
helper.configEntry
|
||||||
? domainToName(localize, type)
|
? domainToName(localize, helper.type)
|
||||||
: html`
|
: html`
|
||||||
${localize(`ui.panel.config.helpers.types.${type}`) || type}
|
${localize(
|
||||||
|
`ui.panel.config.helpers.types.${helper.type}` as LocalizeKeys
|
||||||
|
) || helper.type}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
columns.editable = {
|
columns.editable = {
|
||||||
@ -162,8 +178,8 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
"ui.panel.config.helpers.picker.headers.editable"
|
"ui.panel.config.helpers.picker.headers.editable"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (editable) => html`
|
template: (helper) => html`
|
||||||
${!editable
|
${!helper.editable
|
||||||
? html`
|
? html`
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@ -189,7 +205,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
stateItems: HassEntity[],
|
stateItems: HassEntity[],
|
||||||
entityEntries: Record<string, EntityRegistryEntry>,
|
entityEntries: Record<string, EntityRegistryEntry>,
|
||||||
configEntries: Record<string, ConfigEntry>
|
configEntries: Record<string, ConfigEntry>
|
||||||
) => {
|
): HelperItem[] => {
|
||||||
const configEntriesCopy = { ...configEntries };
|
const configEntriesCopy = { ...configEntries };
|
||||||
|
|
||||||
const states = stateItems.map((entityState) => {
|
const states = stateItems.map((entityState) => {
|
||||||
|
@ -38,7 +38,7 @@ export class ZHAClustersDataTable extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean): DataTableColumnContainer =>
|
(narrow: boolean): DataTableColumnContainer<ClusterRowData> =>
|
||||||
narrow
|
narrow
|
||||||
? {
|
? {
|
||||||
name: {
|
name: {
|
||||||
@ -57,7 +57,7 @@ export class ZHAClustersDataTable extends LitElement {
|
|||||||
},
|
},
|
||||||
id: {
|
id: {
|
||||||
title: "ID",
|
title: "ID",
|
||||||
template: (id: number) => html` ${formatAsPaddedHex(id)} `,
|
template: (cluster) => html` ${formatAsPaddedHex(cluster.id)} `,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
width: "25%",
|
width: "25%",
|
||||||
},
|
},
|
||||||
|
@ -67,9 +67,9 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (name, device: any) => html`
|
template: (device) => html`
|
||||||
<a href=${`/config/devices/device/${device.dev_id}`}>
|
<a href=${`/config/devices/device/${device.dev_id}`}>
|
||||||
${name}
|
${device.name}
|
||||||
</a>
|
</a>
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@ -86,9 +86,9 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (name, device: any) => html`
|
template: (device) => html`
|
||||||
<a href=${`/config/devices/device/${device.dev_id}`}>
|
<a href=${`/config/devices/device/${device.dev_id}`}>
|
||||||
${name}
|
${device.name}
|
||||||
</a>
|
</a>
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@ -102,10 +102,10 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
|||||||
sortable: false,
|
sortable: false,
|
||||||
filterable: false,
|
filterable: false,
|
||||||
width: "50%",
|
width: "50%",
|
||||||
template: (entities) => html`
|
template: (device) => html`
|
||||||
${entities.length
|
${device.entities.length
|
||||||
? entities.length > 3
|
? device.entities.length > 3
|
||||||
? html`${entities
|
? html`${device.entities
|
||||||
.slice(0, 2)
|
.slice(0, 2)
|
||||||
.map(
|
.map(
|
||||||
(entity) =>
|
(entity) =>
|
||||||
@ -115,8 +115,8 @@ export class ZHADeviceEndpointDataTable extends LitElement {
|
|||||||
${entity.name || entity.original_name}
|
${entity.name || entity.original_name}
|
||||||
</div>`
|
</div>`
|
||||||
)}
|
)}
|
||||||
<div>And ${entities.length - 2} more...</div>`
|
<div>And ${device.entities.length - 2} more...</div>`
|
||||||
: entities.map(
|
: device.entities.map(
|
||||||
(entity) =>
|
(entity) =>
|
||||||
html`<div
|
html`<div
|
||||||
style="overflow: hidden; text-overflow: ellipsis;"
|
style="overflow: hidden; text-overflow: ellipsis;"
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
} from "../../../../../components/data-table/ha-data-table";
|
} from "../../../../../components/data-table/ha-data-table";
|
||||||
import "../../../../../components/ha-fab";
|
import "../../../../../components/ha-fab";
|
||||||
import "../../../../../components/ha-icon-button";
|
import "../../../../../components/ha-icon-button";
|
||||||
import { fetchGroups, ZHADevice, ZHAGroup } from "../../../../../data/zha";
|
import { fetchGroups, ZHAGroup } from "../../../../../data/zha";
|
||||||
import "../../../../../layouts/hass-tabs-subpage-data-table";
|
import "../../../../../layouts/hass-tabs-subpage-data-table";
|
||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../../../types";
|
import { HomeAssistant, Route } from "../../../../../types";
|
||||||
@ -71,7 +71,7 @@ export class ZHAGroupsDashboard extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean): DataTableColumnContainer =>
|
(narrow: boolean): DataTableColumnContainer<GroupRowData> =>
|
||||||
narrow
|
narrow
|
||||||
? {
|
? {
|
||||||
name: {
|
name: {
|
||||||
@ -94,16 +94,14 @@ export class ZHAGroupsDashboard extends LitElement {
|
|||||||
title: this.hass.localize("ui.panel.config.zha.groups.group_id"),
|
title: this.hass.localize("ui.panel.config.zha.groups.group_id"),
|
||||||
type: "numeric",
|
type: "numeric",
|
||||||
width: "15%",
|
width: "15%",
|
||||||
template: (groupId: number) => html`
|
template: (group) => html` ${formatAsPaddedHex(group.group_id)} `,
|
||||||
${formatAsPaddedHex(groupId)}
|
|
||||||
`,
|
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
members: {
|
members: {
|
||||||
title: this.hass.localize("ui.panel.config.zha.groups.members"),
|
title: this.hass.localize("ui.panel.config.zha.groups.members"),
|
||||||
type: "numeric",
|
type: "numeric",
|
||||||
width: "15%",
|
width: "15%",
|
||||||
template: (members: ZHADevice[]) => html` ${members.length} `,
|
template: (group) => html` ${group.members.length} `,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -41,15 +41,15 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(narrow: boolean): DataTableColumnContainer => ({
|
(narrow: boolean): DataTableColumnContainer<ZwaveJSProvisioningEntry> => ({
|
||||||
included: {
|
included: {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
"ui.panel.config.zwave_js.provisioned.included"
|
"ui.panel.config.zwave_js.provisioned.included"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
width: "100px",
|
width: "100px",
|
||||||
template: (_info, provisioningEntry: any) =>
|
template: (entry) =>
|
||||||
provisioningEntry.additional_properties.nodeId
|
entry.additional_properties.nodeId
|
||||||
? html`
|
? html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
@ -81,14 +81,16 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (securityClasses: SecurityClass[]) =>
|
template: (entry) => {
|
||||||
securityClasses
|
const securityClasses = entry.security_classes;
|
||||||
|
return securityClasses
|
||||||
.map((secClass) =>
|
.map((secClass) =>
|
||||||
this.hass.localize(
|
this.hass.localize(
|
||||||
`ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}.title`
|
`ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}.title`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.join(", "),
|
.join(", ");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
unprovision: {
|
unprovision: {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
@ -96,13 +98,13 @@ class ZWaveJSProvisioned extends LitElement {
|
|||||||
),
|
),
|
||||||
type: "icon-button",
|
type: "icon-button",
|
||||||
width: "100px",
|
width: "100px",
|
||||||
template: (_info, provisioningEntry: any) => html`
|
template: (entry) => html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.zwave_js.provisioned.unprovison"
|
"ui.panel.config.zwave_js.provisioned.unprovison"
|
||||||
)}
|
)}
|
||||||
.path=${mdiDelete}
|
.path=${mdiDelete}
|
||||||
.provisioningEntry=${provisioningEntry}
|
.provisioningEntry=${entry}
|
||||||
@click=${this._unprovision}
|
@click=${this._unprovision}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
`,
|
`,
|
||||||
|
@ -68,12 +68,12 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
"ui.panel.config.lovelace.dashboards.picker.headers.icon"
|
"ui.panel.config.lovelace.dashboards.picker.headers.icon"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (icon: DataTableItem["icon"], dashboard) =>
|
template: (dashboard) =>
|
||||||
icon
|
dashboard.icon
|
||||||
? html`
|
? html`
|
||||||
<ha-icon
|
<ha-icon
|
||||||
slot="item-icon"
|
slot="item-icon"
|
||||||
.icon=${icon}
|
.icon=${dashboard.icon}
|
||||||
style=${ifDefined(
|
style=${ifDefined(
|
||||||
dashboard.iconColor
|
dashboard.iconColor
|
||||||
? `color: ${dashboard.iconColor}`
|
? `color: ${dashboard.iconColor}`
|
||||||
@ -91,9 +91,9 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (title: DataTableItem["title"], dashboard) => {
|
template: (dashboard) => {
|
||||||
const titleTemplate = html`
|
const titleTemplate = html`
|
||||||
${title}
|
${dashboard.title}
|
||||||
${dashboard.default
|
${dashboard.default
|
||||||
? html`
|
? html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
@ -132,10 +132,10 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "20%",
|
width: "20%",
|
||||||
template: (mode: DataTableItem["mode"]) => html`
|
template: (dashboard) => html`
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
`ui.panel.config.lovelace.dashboards.conf_mode.${mode}`
|
`ui.panel.config.lovelace.dashboards.conf_mode.${dashboard.mode}`
|
||||||
) || mode}
|
) || dashboard.mode}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
if (dashboards.some((dashboard) => dashboard.filename)) {
|
if (dashboards.some((dashboard) => dashboard.filename)) {
|
||||||
@ -155,8 +155,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
type: "icon",
|
type: "icon",
|
||||||
width: "100px",
|
width: "100px",
|
||||||
template: (requireAdmin: DataTableItem["require_admin"]) =>
|
template: (dashboard) =>
|
||||||
requireAdmin
|
dashboard.require_admin
|
||||||
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
||||||
: html`—`,
|
: html`—`,
|
||||||
};
|
};
|
||||||
@ -166,8 +166,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
width: "121px",
|
width: "121px",
|
||||||
template: (sidebar: DataTableItem["show_in_sidebar"]) =>
|
template: (dashboard) =>
|
||||||
sidebar
|
dashboard.show_in_sidebar
|
||||||
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
||||||
: html`—`,
|
: html`—`,
|
||||||
};
|
};
|
||||||
@ -180,12 +180,12 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
),
|
),
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "100px",
|
width: "100px",
|
||||||
template: (urlPath) =>
|
template: (dashboard) =>
|
||||||
narrow
|
narrow
|
||||||
? html`
|
? html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.path=${mdiOpenInNew}
|
.path=${mdiOpenInNew}
|
||||||
.urlPath=${urlPath}
|
.urlPath=${dashboard.url_path}
|
||||||
@click=${this._navigate}
|
@click=${this._navigate}
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.lovelace.dashboards.picker.open"
|
"ui.panel.config.lovelace.dashboards.picker.open"
|
||||||
@ -193,7 +193,9 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<mwc-button .urlPath=${urlPath} @click=${this._navigate}
|
<mwc-button
|
||||||
|
.urlPath=${dashboard.url_path}
|
||||||
|
@click=${this._navigate}
|
||||||
>${this.hass.localize(
|
>${this.hass.localize(
|
||||||
"ui.panel.config.lovelace.dashboards.picker.open"
|
"ui.panel.config.lovelace.dashboards.picker.open"
|
||||||
)}</mwc-button
|
)}</mwc-button
|
||||||
|
@ -40,7 +40,7 @@ export class HaConfigLovelaceRescources extends LitElement {
|
|||||||
@state() private _resources: LovelaceResource[] = [];
|
@state() private _resources: LovelaceResource[] = [];
|
||||||
|
|
||||||
private _columns = memoize(
|
private _columns = memoize(
|
||||||
(_language): DataTableColumnContainer => ({
|
(_language): DataTableColumnContainer<LovelaceResource> => ({
|
||||||
url: {
|
url: {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
"ui.panel.config.lovelace.resources.picker.headers.url"
|
"ui.panel.config.lovelace.resources.picker.headers.url"
|
||||||
@ -58,10 +58,10 @@ export class HaConfigLovelaceRescources extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "30%",
|
width: "30%",
|
||||||
template: (type: LovelaceResource["type"]) => html`
|
template: (resource) => html`
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
`ui.panel.config.lovelace.resources.types.${type}`
|
`ui.panel.config.lovelace.resources.types.${resource.type}`
|
||||||
) || type}
|
) || resource.type}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -47,6 +47,10 @@ import { formatShortDateTime } from "../../../common/datetime/format_date_time";
|
|||||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||||
import { isUnavailableState } from "../../../data/entity";
|
import { isUnavailableState } from "../../../data/entity";
|
||||||
|
|
||||||
|
type SceneItem = SceneEntity & {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("ha-scene-dashboard")
|
@customElement("ha-scene-dashboard")
|
||||||
class HaSceneDashboard extends LitElement {
|
class HaSceneDashboard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -66,7 +70,7 @@ class HaSceneDashboard extends LitElement {
|
|||||||
@state() private _filterValue?;
|
@state() private _filterValue?;
|
||||||
|
|
||||||
private _scenes = memoizeOne(
|
private _scenes = memoizeOne(
|
||||||
(scenes: SceneEntity[], filteredScenes?: string[] | null) => {
|
(scenes: SceneEntity[], filteredScenes?: string[] | null): SceneItem[] => {
|
||||||
if (filteredScenes === null) {
|
if (filteredScenes === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -83,14 +87,14 @@ class HaSceneDashboard extends LitElement {
|
|||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(_language, narrow): DataTableColumnContainer => {
|
(_language, narrow): DataTableColumnContainer => {
|
||||||
const columns: DataTableColumnContainer = {
|
const columns: DataTableColumnContainer<SceneItem> = {
|
||||||
icon: {
|
icon: {
|
||||||
title: "",
|
title: "",
|
||||||
label: this.hass.localize(
|
label: this.hass.localize(
|
||||||
"ui.panel.config.scene.picker.headers.state"
|
"ui.panel.config.scene.picker.headers.state"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_, scene) => html`
|
template: (scene) => html`
|
||||||
<ha-state-icon .state=${scene}></ha-state-icon>
|
<ha-state-icon .state=${scene}></ha-state-icon>
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@ -112,20 +116,18 @@ class HaSceneDashboard extends LitElement {
|
|||||||
),
|
),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
width: "30%",
|
width: "30%",
|
||||||
template: (last_activated) => {
|
template: (scene) => {
|
||||||
const date = new Date(last_activated);
|
const lastActivated = scene.state;
|
||||||
|
if (!lastActivated || isUnavailableState(lastActivated)) {
|
||||||
|
return this.hass.localize("ui.components.relative_time.never");
|
||||||
|
}
|
||||||
|
const date = new Date(scene.state);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const dayDifference = differenceInDays(now, date);
|
const dayDifference = differenceInDays(now, date);
|
||||||
return html`
|
return html`
|
||||||
${last_activated && !isUnavailableState(last_activated)
|
${dayDifference > 3
|
||||||
? dayDifference > 3
|
? formatShortDateTime(date, this.hass.locale, this.hass.config)
|
||||||
? formatShortDateTime(
|
: relativeTime(date, this.hass.locale)}
|
||||||
date,
|
|
||||||
this.hass.locale,
|
|
||||||
this.hass.config
|
|
||||||
)
|
|
||||||
: relativeTime(date, this.hass.locale)
|
|
||||||
: this.hass.localize("ui.components.relative_time.never")}
|
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -133,7 +135,7 @@ class HaSceneDashboard extends LitElement {
|
|||||||
columns.only_editable = {
|
columns.only_editable = {
|
||||||
title: "",
|
title: "",
|
||||||
width: "56px",
|
width: "56px",
|
||||||
template: (_info, scene: any) =>
|
template: (scene) =>
|
||||||
!scene.attributes.id
|
!scene.attributes.id
|
||||||
? html`
|
? html`
|
||||||
<simple-tooltip animation-delay="0" position="left">
|
<simple-tooltip animation-delay="0" position="left">
|
||||||
@ -152,7 +154,7 @@ class HaSceneDashboard extends LitElement {
|
|||||||
title: "",
|
title: "",
|
||||||
width: "72px",
|
width: "72px",
|
||||||
type: "overflow-menu",
|
type: "overflow-menu",
|
||||||
template: (_: string, scene: any) => html`
|
template: (scene) => html`
|
||||||
<ha-icon-overflow-menu
|
<ha-icon-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
narrow
|
narrow
|
||||||
|
@ -7,16 +7,15 @@ import {
|
|||||||
mdiPlus,
|
mdiPlus,
|
||||||
mdiTransitConnection,
|
mdiTransitConnection,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { differenceInDays } from "date-fns/esm";
|
import { differenceInDays } from "date-fns/esm";
|
||||||
|
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
|
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
|
||||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||||
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
@ -29,13 +28,18 @@ import "../../../components/ha-fab";
|
|||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-icon-overflow-menu";
|
import "../../../components/ha-icon-overflow-menu";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
|
import { fetchBlueprints } from "../../../data/blueprint";
|
||||||
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
|
ScriptEntity,
|
||||||
deleteScript,
|
deleteScript,
|
||||||
fetchScriptFileConfig,
|
fetchScriptFileConfig,
|
||||||
getScriptStateConfig,
|
getScriptStateConfig,
|
||||||
showScriptEditor,
|
showScriptEditor,
|
||||||
triggerScript,
|
triggerScript,
|
||||||
} from "../../../data/script";
|
} from "../../../data/script";
|
||||||
|
import { findRelated } from "../../../data/search";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -45,18 +49,18 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import { configSections } from "../ha-panel-config";
|
|
||||||
import { showNewAutomationDialog } from "../automation/show-dialog-new-automation";
|
import { showNewAutomationDialog } from "../automation/show-dialog-new-automation";
|
||||||
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
import { configSections } from "../ha-panel-config";
|
||||||
import { findRelated } from "../../../data/search";
|
|
||||||
import { fetchBlueprints } from "../../../data/blueprint";
|
type ScriptItem = ScriptEntity & {
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("ha-script-picker")
|
@customElement("ha-script-picker")
|
||||||
class HaScriptPicker extends LitElement {
|
class HaScriptPicker extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public scripts!: HassEntity[];
|
@property() public scripts!: ScriptEntity[];
|
||||||
|
|
||||||
@property() public isWide!: boolean;
|
@property() public isWide!: boolean;
|
||||||
|
|
||||||
@ -75,7 +79,10 @@ class HaScriptPicker extends LitElement {
|
|||||||
@state() private _filterValue?;
|
@state() private _filterValue?;
|
||||||
|
|
||||||
private _scripts = memoizeOne(
|
private _scripts = memoizeOne(
|
||||||
(scripts: HassEntity[], filteredScripts?: string[] | null) => {
|
(
|
||||||
|
scripts: ScriptEntity[],
|
||||||
|
filteredScripts?: string[] | null
|
||||||
|
): ScriptItem[] => {
|
||||||
if (filteredScripts === null) {
|
if (filteredScripts === null) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -93,7 +100,8 @@ class HaScriptPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _columns = memoizeOne((narrow, _locale): DataTableColumnContainer => {
|
private _columns = memoizeOne(
|
||||||
|
(narrow, _locale): DataTableColumnContainer<ScriptItem> => {
|
||||||
const columns: DataTableColumnContainer = {
|
const columns: DataTableColumnContainer = {
|
||||||
icon: {
|
icon: {
|
||||||
title: "",
|
title: "",
|
||||||
@ -101,7 +109,7 @@ class HaScriptPicker extends LitElement {
|
|||||||
"ui.panel.config.script.picker.headers.state"
|
"ui.panel.config.script.picker.headers.state"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_icon, script) =>
|
template: (script) =>
|
||||||
html`<ha-state-icon
|
html`<ha-state-icon
|
||||||
.state=${script}
|
.state=${script}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
@ -111,22 +119,24 @@ class HaScriptPicker extends LitElement {
|
|||||||
></ha-state-icon>`,
|
></ha-state-icon>`,
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
title: this.hass.localize("ui.panel.config.script.picker.headers.name"),
|
title: this.hass.localize(
|
||||||
|
"ui.panel.config.script.picker.headers.name"
|
||||||
|
),
|
||||||
main: true,
|
main: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: narrow
|
template: narrow
|
||||||
? (name, script: any) => {
|
? (script) => {
|
||||||
const date = new Date(script.attributes.last_triggered);
|
const date = new Date(script.last_triggered);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const dayDifference = differenceInDays(now, date);
|
const dayDifference = differenceInDays(now, date);
|
||||||
return html`
|
return html`
|
||||||
${name}
|
${script.name}
|
||||||
<div class="secondary">
|
<div class="secondary">
|
||||||
${this.hass.localize("ui.card.automation.last_triggered")}:
|
${this.hass.localize("ui.card.automation.last_triggered")}:
|
||||||
${script.attributes.last_triggered
|
${script.last_triggered
|
||||||
? dayDifference > 3
|
? dayDifference > 3
|
||||||
? formatShortDateTime(
|
? formatShortDateTime(
|
||||||
date,
|
date,
|
||||||
@ -146,14 +156,18 @@ class HaScriptPicker extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
width: "40%",
|
width: "40%",
|
||||||
title: this.hass.localize("ui.card.automation.last_triggered"),
|
title: this.hass.localize("ui.card.automation.last_triggered"),
|
||||||
template: (last_triggered) => {
|
template: (script) => {
|
||||||
const date = new Date(last_triggered);
|
const date = new Date(script.last_triggered);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const dayDifference = differenceInDays(now, date);
|
const dayDifference = differenceInDays(now, date);
|
||||||
return html`
|
return html`
|
||||||
${last_triggered
|
${script.last_triggered
|
||||||
? dayDifference > 3
|
? dayDifference > 3
|
||||||
? formatShortDateTime(date, this.hass.locale, this.hass.config)
|
? formatShortDateTime(
|
||||||
|
date,
|
||||||
|
this.hass.locale,
|
||||||
|
this.hass.config
|
||||||
|
)
|
||||||
: relativeTime(date, this.hass.locale)
|
: relativeTime(date, this.hass.locale)
|
||||||
: this.hass.localize("ui.components.relative_time.never")}
|
: this.hass.localize("ui.components.relative_time.never")}
|
||||||
`;
|
`;
|
||||||
@ -165,7 +179,7 @@ class HaScriptPicker extends LitElement {
|
|||||||
title: "",
|
title: "",
|
||||||
width: this.narrow ? undefined : "10%",
|
width: this.narrow ? undefined : "10%",
|
||||||
type: "overflow-menu",
|
type: "overflow-menu",
|
||||||
template: (_: string, script: any) => html`
|
template: (script) => html`
|
||||||
<ha-icon-overflow-menu
|
<ha-icon-overflow-menu
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
narrow
|
narrow
|
||||||
@ -200,7 +214,9 @@ class HaScriptPicker extends LitElement {
|
|||||||
action: () => this._duplicate(script),
|
action: () => this._duplicate(script),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.hass.localize("ui.panel.config.script.picker.delete"),
|
label: this.hass.localize(
|
||||||
|
"ui.panel.config.script.picker.delete"
|
||||||
|
),
|
||||||
path: mdiDelete,
|
path: mdiDelete,
|
||||||
action: () => this._deleteConfirm(script),
|
action: () => this._deleteConfirm(script),
|
||||||
warning: true,
|
warning: true,
|
||||||
@ -212,7 +228,8 @@ class HaScriptPicker extends LitElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
|
@ -36,6 +36,7 @@ import { showTagDetailDialog } from "./show-dialog-tag-detail";
|
|||||||
import "./tag-image";
|
import "./tag-image";
|
||||||
|
|
||||||
export interface TagRowData extends Tag {
|
export interface TagRowData extends Tag {
|
||||||
|
display_name: string;
|
||||||
last_scanned_datetime: Date | null;
|
last_scanned_datetime: Date | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,14 +56,13 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
|
|||||||
return this.hass.auth.external?.config.canWriteTag;
|
return this.hass.auth.external?.config.canWriteTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne((narrow: boolean, _language) => {
|
||||||
(narrow: boolean, _language): DataTableColumnContainer => {
|
const columns: DataTableColumnContainer<TagRowData> = {
|
||||||
const columns: DataTableColumnContainer = {
|
|
||||||
icon: {
|
icon: {
|
||||||
title: "",
|
title: "",
|
||||||
label: this.hass.localize("ui.panel.config.tag.headers.icon"),
|
label: this.hass.localize("ui.panel.config.tag.headers.icon"),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_icon, tag) => html`<tag-image .tag=${tag}></tag-image>`,
|
template: (tag) => html`<tag-image .tag=${tag}></tag-image>`,
|
||||||
},
|
},
|
||||||
display_name: {
|
display_name: {
|
||||||
title: this.hass.localize("ui.panel.config.tag.headers.name"),
|
title: this.hass.localize("ui.panel.config.tag.headers.name"),
|
||||||
@ -70,8 +70,8 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (name, tag: any) =>
|
template: (tag) =>
|
||||||
html`${name}
|
html`${tag.name}
|
||||||
${narrow
|
${narrow
|
||||||
? html`<div class="secondary">
|
? html`<div class="secondary">
|
||||||
${tag.last_scanned_datetime
|
${tag.last_scanned_datetime
|
||||||
@ -91,11 +91,11 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
direction: "desc",
|
direction: "desc",
|
||||||
width: "20%",
|
width: "20%",
|
||||||
template: (last_scanned_datetime) => html`
|
template: (tag) => html`
|
||||||
${last_scanned_datetime
|
${tag.last_scanned_datetime
|
||||||
? html`<ha-relative-time
|
? html`<ha-relative-time
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.datetime=${last_scanned_datetime}
|
.datetime=${tag.last_scanned_datetime}
|
||||||
capitalize
|
capitalize
|
||||||
></ha-relative-time>`
|
></ha-relative-time>`
|
||||||
: this.hass.localize("ui.panel.config.tag.never_scanned")}
|
: this.hass.localize("ui.panel.config.tag.never_scanned")}
|
||||||
@ -107,7 +107,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
|
|||||||
title: "",
|
title: "",
|
||||||
label: this.hass.localize("ui.panel.config.tag.headers.write"),
|
label: this.hass.localize("ui.panel.config.tag.headers.write"),
|
||||||
type: "icon-button",
|
type: "icon-button",
|
||||||
template: (_write, tag: any) =>
|
template: (tag) =>
|
||||||
html` <ha-icon-button
|
html` <ha-icon-button
|
||||||
.tag=${tag}
|
.tag=${tag}
|
||||||
@click=${this._handleWriteClick}
|
@click=${this._handleWriteClick}
|
||||||
@ -119,20 +119,18 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
|
|||||||
columns.automation = {
|
columns.automation = {
|
||||||
title: "",
|
title: "",
|
||||||
type: "icon-button",
|
type: "icon-button",
|
||||||
template: (_automation, tag: any) =>
|
template: (tag) =>
|
||||||
html` <ha-icon-button
|
html` <ha-icon-button
|
||||||
.tag=${tag}
|
.tag=${tag}
|
||||||
@click=${this._handleAutomationClick}
|
@click=${this._handleAutomationClick}
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize("ui.panel.config.tag.create_automation")}
|
||||||
"ui.panel.config.tag.create_automation"
|
|
||||||
)}
|
|
||||||
.path=${mdiRobot}
|
.path=${mdiRobot}
|
||||||
></ha-icon-button>`,
|
></ha-icon-button>`,
|
||||||
};
|
};
|
||||||
columns.edit = {
|
columns.edit = {
|
||||||
title: "",
|
title: "",
|
||||||
type: "icon-button",
|
type: "icon-button",
|
||||||
template: (_settings, tag: any) =>
|
template: (tag) =>
|
||||||
html` <ha-icon-button
|
html` <ha-icon-button
|
||||||
.tag=${tag}
|
.tag=${tag}
|
||||||
@click=${this._handleEditClick}
|
@click=${this._handleEditClick}
|
||||||
@ -141,8 +139,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
|
|||||||
></ha-icon-button>`,
|
></ha-icon-button>`,
|
||||||
};
|
};
|
||||||
return columns;
|
return columns;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
private _data = memoizeOne((tags: Tag[]): TagRowData[] =>
|
private _data = memoizeOne((tags: Tag[]): TagRowData[] =>
|
||||||
tags.map((tag) => ({
|
tags.map((tag) => ({
|
||||||
|
@ -49,14 +49,14 @@ export class HaConfigUsers extends LitElement {
|
|||||||
width: "25%",
|
width: "25%",
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (name, user) =>
|
template: (user) =>
|
||||||
narrow
|
narrow
|
||||||
? html` ${name}<br />
|
? html` ${user.name}<br />
|
||||||
<div class="secondary">
|
<div class="secondary">
|
||||||
${user.username ? `${user.username} |` : ""}
|
${user.username ? `${user.username} |` : ""}
|
||||||
${localize(`groups.${user.group_ids[0]}`)}
|
${localize(`groups.${user.group_ids[0]}`)}
|
||||||
</div>`
|
</div>`
|
||||||
: html` ${name ||
|
: html` ${user.name ||
|
||||||
this.hass!.localize(
|
this.hass!.localize(
|
||||||
"ui.panel.config.users.editor.unnamed_user"
|
"ui.panel.config.users.editor.unnamed_user"
|
||||||
)}`,
|
)}`,
|
||||||
@ -68,7 +68,7 @@ export class HaConfigUsers extends LitElement {
|
|||||||
width: "20%",
|
width: "20%",
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (username) => html`${username || "—"}`,
|
template: (user) => html`${user.name || "—"}`,
|
||||||
},
|
},
|
||||||
group_ids: {
|
group_ids: {
|
||||||
title: localize("ui.panel.config.users.picker.headers.group"),
|
title: localize("ui.panel.config.users.picker.headers.group"),
|
||||||
@ -77,8 +77,8 @@ export class HaConfigUsers extends LitElement {
|
|||||||
width: "20%",
|
width: "20%",
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (groupIds: User["group_ids"]) => html`
|
template: (user) => html`
|
||||||
${localize(`groups.${groupIds[0]}`)}
|
${localize(`groups.${user.group_ids[0]}`)}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
is_active: {
|
is_active: {
|
||||||
@ -90,8 +90,8 @@ export class HaConfigUsers extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
width: "80px",
|
width: "80px",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (is_active) =>
|
template: (user) =>
|
||||||
is_active
|
user.is_active
|
||||||
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
||||||
: "",
|
: "",
|
||||||
},
|
},
|
||||||
@ -104,8 +104,8 @@ export class HaConfigUsers extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
width: "80px",
|
width: "80px",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (generated) =>
|
template: (user) =>
|
||||||
generated
|
user.system_generated
|
||||||
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
||||||
: "",
|
: "",
|
||||||
},
|
},
|
||||||
@ -118,8 +118,10 @@ export class HaConfigUsers extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
width: "80px",
|
width: "80px",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (local) =>
|
template: (user) =>
|
||||||
local ? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>` : "",
|
user.local_only
|
||||||
|
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
|
||||||
|
: "",
|
||||||
},
|
},
|
||||||
icons: {
|
icons: {
|
||||||
title: "",
|
title: "",
|
||||||
@ -131,7 +133,7 @@ export class HaConfigUsers extends LitElement {
|
|||||||
filterable: false,
|
filterable: false,
|
||||||
width: "104px",
|
width: "104px",
|
||||||
hidden: !narrow,
|
hidden: !narrow,
|
||||||
template: (_, user) => {
|
template: (user) => {
|
||||||
const badges = computeUserBadges(this.hass, user, false);
|
const badges = computeUserBadges(this.hass, user, false);
|
||||||
return html`${badges.map(
|
return html`${badges.map(
|
||||||
([icon, tooltip]) =>
|
([icon, tooltip]) =>
|
||||||
|
@ -134,7 +134,7 @@ export class VoiceAssistantsExpose extends LitElement {
|
|||||||
title: "",
|
title: "",
|
||||||
type: "icon",
|
type: "icon",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (_, entry) => html`
|
template: (entry) => html`
|
||||||
<ha-state-icon
|
<ha-state-icon
|
||||||
title=${ifDefined(entry.entity?.state)}
|
title=${ifDefined(entry.entity?.state)}
|
||||||
.state=${entry.entity}
|
.state=${entry.entity}
|
||||||
@ -150,8 +150,8 @@ export class VoiceAssistantsExpose extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
grows: true,
|
grows: true,
|
||||||
template: (name, entry) => html`
|
template: (entry) => html`
|
||||||
${name}<br />
|
${entry.name}<br />
|
||||||
<div class="secondary">${entry.entity_id}</div>
|
<div class="secondary">${entry.entity_id}</div>
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@ -172,13 +172,13 @@ export class VoiceAssistantsExpose extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
width: "160px",
|
width: "160px",
|
||||||
type: "flex",
|
type: "flex",
|
||||||
template: (assistants, entry) =>
|
template: (entry) =>
|
||||||
html`${availableAssistants.map((key) => {
|
html`${availableAssistants.map((key) => {
|
||||||
const supported =
|
const supported =
|
||||||
!supportedEntities?.[key] ||
|
!supportedEntities?.[key] ||
|
||||||
supportedEntities[key].includes(entry.entity_id);
|
supportedEntities[key].includes(entry.entity_id);
|
||||||
const manual = entry.manAssistants?.includes(key);
|
const manual = entry.manAssistants?.includes(key);
|
||||||
return assistants.includes(key)
|
return entry.assistants.includes(key)
|
||||||
? html`
|
? html`
|
||||||
<voice-assistants-expose-assistant-icon
|
<voice-assistants-expose-assistant-icon
|
||||||
.assistant=${key}
|
.assistant=${key}
|
||||||
@ -199,14 +199,14 @@ export class VoiceAssistantsExpose extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
width: "15%",
|
width: "15%",
|
||||||
template: (aliases) =>
|
template: (entry) =>
|
||||||
aliases.length === 0
|
entry.aliases.length === 0
|
||||||
? "-"
|
? "-"
|
||||||
: aliases.length === 1
|
: entry.aliases.length === 1
|
||||||
? aliases[0]
|
? entry.aliases[0]
|
||||||
: this.hass.localize(
|
: this.hass.localize(
|
||||||
"ui.panel.config.voice_assistants.expose.aliases",
|
"ui.panel.config.voice_assistants.expose.aliases",
|
||||||
{ count: aliases.length }
|
{ count: entry.aliases.length }
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
remove: {
|
remove: {
|
||||||
|
@ -80,7 +80,9 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
private _columns = memoizeOne(
|
||||||
(localize: LocalizeFunc): DataTableColumnContainer => ({
|
(
|
||||||
|
localize: LocalizeFunc
|
||||||
|
): DataTableColumnContainer<DisplayedStatisticData> => ({
|
||||||
displayName: {
|
displayName: {
|
||||||
title: localize(
|
title: localize(
|
||||||
"ui.panel.developer-tools.tabs.statistics.data_table.name"
|
"ui.panel.developer-tools.tabs.statistics.data_table.name"
|
||||||
@ -123,8 +125,8 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
width: "30%",
|
width: "30%",
|
||||||
template: (issues_string) =>
|
template: (statistic) =>
|
||||||
html`${issues_string ??
|
html`${statistic.issues_string ??
|
||||||
localize("ui.panel.developer-tools.tabs.statistics.no_issue")}`,
|
localize("ui.panel.developer-tools.tabs.statistics.no_issue")}`,
|
||||||
},
|
},
|
||||||
fix: {
|
fix: {
|
||||||
@ -132,9 +134,12 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
|||||||
label: this.hass.localize(
|
label: this.hass.localize(
|
||||||
"ui.panel.developer-tools.tabs.statistics.fix_issue.fix"
|
"ui.panel.developer-tools.tabs.statistics.fix_issue.fix"
|
||||||
),
|
),
|
||||||
template: (_, data: any) =>
|
template: (statistic) =>
|
||||||
html`${data.issues
|
html`${statistic.issues
|
||||||
? html`<mwc-button @click=${this._fixIssue} .data=${data.issues}>
|
? html`<mwc-button
|
||||||
|
@click=${this._fixIssue}
|
||||||
|
.data=${statistic.issues}
|
||||||
|
>
|
||||||
${localize(
|
${localize(
|
||||||
"ui.panel.developer-tools.tabs.statistics.fix_issue.fix"
|
"ui.panel.developer-tools.tabs.statistics.fix_issue.fix"
|
||||||
)}
|
)}
|
||||||
@ -146,7 +151,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
|
|||||||
title: "",
|
title: "",
|
||||||
label: localize("ui.panel.developer-tools.tabs.statistics.adjust_sum"),
|
label: localize("ui.panel.developer-tools.tabs.statistics.adjust_sum"),
|
||||||
type: "icon-button",
|
type: "icon-button",
|
||||||
template: (_info, statistic: StatisticsMetaData) =>
|
template: (statistic) =>
|
||||||
statistic.has_sum
|
statistic.has_sum
|
||||||
? html`
|
? html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
|
@ -54,7 +54,7 @@ export class HuiEntityPickerTable extends LitElement {
|
|||||||
"ui.panel.lovelace.unused_entities.state_icon"
|
"ui.panel.lovelace.unused_entities.state_icon"
|
||||||
),
|
),
|
||||||
type: "icon",
|
type: "icon",
|
||||||
template: (_icon, entity: any) => html`
|
template: (entity) => html`
|
||||||
<state-badge
|
<state-badge
|
||||||
@click=${this._handleEntityClicked}
|
@click=${this._handleEntityClicked}
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
@ -68,9 +68,9 @@ export class HuiEntityPickerTable extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
grows: true,
|
grows: true,
|
||||||
direction: "asc",
|
direction: "asc",
|
||||||
template: (name, entity: any) => html`
|
template: (entity: any) => html`
|
||||||
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
|
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
|
||||||
${name}
|
${entity.name}
|
||||||
${narrow
|
${narrow
|
||||||
? html` <div class="secondary">${entity.entity_id}</div> `
|
? html` <div class="secondary">${entity.entity_id}</div> `
|
||||||
: ""}
|
: ""}
|
||||||
@ -103,10 +103,10 @@ export class HuiEntityPickerTable extends LitElement {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
width: "15%",
|
width: "15%",
|
||||||
hidden: narrow,
|
hidden: narrow,
|
||||||
template: (lastChanged: string) => html`
|
template: (entity) => html`
|
||||||
<ha-relative-time
|
<ha-relative-time
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.datetime=${lastChanged}
|
.datetime=${entity.last_changed}
|
||||||
capitalize
|
capitalize
|
||||||
></ha-relative-time>
|
></ha-relative-time>
|
||||||
`,
|
`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user