Align dashboard data table with other data tables (#27206)

* Align dashboard data table with other data tables

* Update ha-config-lovelace-dashboards.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update ha-config-lovelace-dashboards.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
pull/27224/head
Paul Bottein 2025-09-27 17:07:01 +02:00 committed by GitHub
parent 33a0b32cc5
commit c814b8e888
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 141 additions and 101 deletions

View File

@ -1,8 +1,9 @@
import {
mdiCheck,
mdiCheckCircleOutline,
mdiDelete,
mdiDotsVertical,
mdiOpenInNew,
mdiPencil,
mdiPlus,
} from "@mdi/js";
import type { PropertyValues } from "lit";
@ -20,10 +21,11 @@ import type {
RowClickedEvent,
SortingChangedEvent,
} from "../../../../components/data-table/ha-data-table";
import "../../../../components/ha-button";
import "../../../../components/ha-fab";
import "../../../../components/ha-icon";
import "../../../../components/ha-button";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-icon-overflow-menu";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-list-item";
import "../../../../components/ha-svg-icon";
@ -224,87 +226,94 @@ export class HaConfigLovelaceDashboards extends LitElement {
: html``,
};
columns.url_path = {
columns.actions = {
title: "",
label: localize(
"ui.panel.config.lovelace.dashboards.picker.headers.url"
),
filterable: true,
label: this.hass.localize("ui.panel.config.generic.headers.actions"),
type: "overflow-menu",
showNarrow: true,
template: (dashboard) =>
narrow
? html`
<ha-icon-button
.path=${mdiOpenInNew}
.urlPath=${dashboard.url_path}
@click=${this._navigate}
.label=${this.hass.localize(
"ui.panel.config.lovelace.dashboards.picker.open"
)}
></ha-icon-button>
`
: html`
<ha-button
href="/${dashboard.url_path}"
size="small"
appearance="plain"
>${this.hass.localize(
"ui.panel.config.lovelace.dashboards.picker.open"
)}</ha-button
>
`,
moveable: false,
hideable: false,
template: (dashboard) => html`
<ha-icon-overflow-menu
.hass=${this.hass}
narrow
.items=${[
{
path: mdiPencil,
label: this.hass.localize(
"ui.panel.config.lovelace.dashboards.picker.edit"
),
action: () => this._handleEdit(dashboard),
},
...(this._canDelete(dashboard.url_path)
? [
{
label: this.hass.localize(
"ui.panel.config.lovelace.dashboards.picker.delete"
),
path: mdiDelete,
action: () => this._handleDelete(dashboard),
warning: true,
},
]
: []),
]}
>
</ha-icon-overflow-menu>
`,
};
return columns;
}
);
private _getItems = memoize((dashboards: LovelaceDashboard[]) => {
const defaultMode = (
this.hass.panels?.lovelace?.config as LovelacePanelConfig
).mode;
const defaultUrlPath = this.hass.defaultPanel;
const isDefault = defaultUrlPath === "lovelace";
const result: DataTableItem[] = [
{
icon: "hass:view-dashboard",
title: this.hass.localize("panel.states"),
default: isDefault,
show_in_sidebar: isDefault,
require_admin: false,
url_path: "lovelace",
mode: defaultMode,
filename: defaultMode === "yaml" ? "ui-lovelace.yaml" : "",
iconColor: "var(--primary-color)",
},
];
if (isComponentLoaded(this.hass, "energy")) {
result.push({
icon: "hass:lightning-bolt",
title: this.hass.localize(`ui.panel.config.dashboard.energy.main`),
show_in_sidebar: true,
mode: "storage",
url_path: "energy",
filename: "",
iconColor: "var(--label-badge-yellow)",
default: false,
require_admin: false,
});
}
result.push(
...dashboards
.sort((a, b) =>
stringCompare(a.title, b.title, this.hass.locale.language)
)
.map((dashboard) => ({
private _getItems = memoize(
(dashboards: LovelaceDashboard[], defaultUrlPath: string) => {
const defaultMode = (
this.hass.panels?.lovelace?.config as LovelacePanelConfig
).mode;
const isDefault = defaultUrlPath === "lovelace";
const result: DataTableItem[] = [
{
icon: "hass:view-dashboard",
title: this.hass.localize("panel.states"),
default: isDefault,
show_in_sidebar: isDefault,
require_admin: false,
url_path: "lovelace",
mode: defaultMode,
filename: defaultMode === "yaml" ? "ui-lovelace.yaml" : "",
iconColor: "var(--primary-color)",
},
];
if (isComponentLoaded(this.hass, "energy")) {
result.push({
icon: "hass:lightning-bolt",
title: this.hass.localize(`ui.panel.config.dashboard.energy.main`),
show_in_sidebar: true,
mode: "storage",
url_path: "energy",
filename: "",
...dashboard,
default: defaultUrlPath === dashboard.url_path,
}))
);
return result;
});
iconColor: "var(--label-badge-yellow)",
default: false,
require_admin: false,
});
}
result.push(
...dashboards
.sort((a, b) =>
stringCompare(a.title, b.title, this.hass.locale.language)
)
.map((dashboard) => ({
filename: "",
...dashboard,
default: defaultUrlPath === dashboard.url_path,
}))
);
return result;
}
);
protected render() {
if (!this.hass || this._dashboards === undefined) {
@ -324,7 +333,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
this._dashboards,
this.hass.localize
)}
.data=${this._getItems(this._dashboards)}
.data=${this._getItems(this._dashboards, this.hass.defaultPanel)}
.initialSorting=${this._activeSorting}
.columnOrder=${this._activeColumnOrder}
.hiddenColumns=${this._activeHiddenColumns}
@ -332,7 +341,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@row-click=${this._editDashboard}
@row-click=${this._handleRowClicked}
id="url_path"
has-fab
clickable
@ -370,13 +379,14 @@ export class HaConfigLovelaceDashboards extends LitElement {
this._dashboards = await fetchDashboards(this.hass);
}
private _navigate(ev: Event) {
private _handleRowClicked(ev: CustomEvent) {
ev.stopPropagation();
navigate(`/${(ev.target as any).urlPath}`);
const urlPath = (ev.detail as RowClickedEvent).id;
navigate(`/${urlPath}`);
}
private _editDashboard(ev: CustomEvent) {
const urlPath = (ev.detail as RowClickedEvent).id;
private _handleEdit(item: DataTableItem) {
const urlPath = item.url_path;
if (urlPath === "energy") {
navigate("/config/energy");
@ -386,6 +396,23 @@ export class HaConfigLovelaceDashboards extends LitElement {
this._openDetailDialog(dashboard, urlPath);
}
private _canDelete(urlPath: string) {
if (urlPath === "lovelace" || urlPath === "energy") {
return false;
}
return true;
}
private _handleDelete = async (item: DataTableItem) => {
const dashboard = this._dashboards.find(
(res) => res.url_path === item.url_path
);
if (!dashboard) {
return;
}
this._deleteDashboard(dashboard);
};
private async _addDashboard() {
showNewDashboardDialog(this, {
selectConfig: async (config) => {
@ -445,33 +472,44 @@ export class HaConfigLovelaceDashboards extends LitElement {
);
},
removeDashboard: async () => {
const confirm = await showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.lovelace.dashboards.confirm_delete_title",
{ dashboard_title: dashboard!.title }
),
text: this.hass!.localize(
"ui.panel.config.lovelace.dashboards.confirm_delete_text"
),
confirmText: this.hass!.localize("ui.common.delete"),
destructive: true,
});
if (!confirm) {
return false;
}
try {
await deleteDashboard(this.hass!, dashboard!.id);
this._dashboards = this._dashboards!.filter(
(res) => res !== dashboard
);
return true;
} catch (_err: any) {
if (!dashboard) {
return false;
}
return this._deleteDashboard(dashboard);
},
});
}
private async _deleteDashboard(
dashboard: LovelaceDashboard
): Promise<boolean> {
if (!this._canDelete(dashboard.url_path)) {
return false;
}
const confirm = await showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.lovelace.dashboards.confirm_delete_title",
{ dashboard_title: dashboard.title }
),
text: this.hass!.localize(
"ui.panel.config.lovelace.dashboards.confirm_delete_text"
),
confirmText: this.hass!.localize("ui.common.delete"),
destructive: true,
});
if (!confirm) {
return false;
}
try {
await deleteDashboard(this.hass!, dashboard.id);
this._dashboards = this._dashboards.filter((res) => res !== dashboard);
return true;
} catch (_err: any) {
return false;
}
}
private _handleSortingChanged(ev: CustomEvent) {
this._activeSorting = ev.detail;
}

View File

@ -3416,6 +3416,8 @@
"url": "Open"
},
"open": "Open",
"edit": "Edit",
"delete": "Delete",
"add_dashboard": "Add dashboard"
},
"confirm_delete_title": "Delete {dashboard_title}?",