mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-10 10:07:19 +00:00
Compare commits
4 Commits
dev
...
lovelace_d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b44542c83c | ||
|
|
36518bbce7 | ||
|
|
bb0c14cc57 | ||
|
|
0cacc535ca |
@@ -246,7 +246,7 @@ export class HaGenericPicker extends LitElement {
|
|||||||
|
|
||||||
private _unknownValue = memoizeOne(
|
private _unknownValue = memoizeOne(
|
||||||
(value?: string, items?: (PickerComboBoxItem | string)[]) => {
|
(value?: string, items?: (PickerComboBoxItem | string)[]) => {
|
||||||
if (value === undefined || value === null || value === "" || !items) {
|
if (value === undefined || !items) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,11 @@ import {
|
|||||||
mdiLightningBolt,
|
mdiLightningBolt,
|
||||||
mdiPlayBoxMultiple,
|
mdiPlayBoxMultiple,
|
||||||
mdiTooltipAccount,
|
mdiTooltipAccount,
|
||||||
mdiViewDashboard,
|
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import type { HomeAssistant, PanelInfo } from "../types";
|
import type { HomeAssistant, PanelInfo } from "../types";
|
||||||
|
|
||||||
/** Panel to show when no panel is picked. */
|
/** Panel to show when no panel is picked. */
|
||||||
export const DEFAULT_PANEL = "lovelace";
|
export const DEFAULT_PANEL = "home";
|
||||||
|
|
||||||
export const getLegacyDefaultPanelUrlPath = (): string | null => {
|
export const getLegacyDefaultPanelUrlPath = (): string | null => {
|
||||||
const defaultPanel = window.localStorage.getItem("defaultPanel");
|
const defaultPanel = window.localStorage.getItem("defaultPanel");
|
||||||
@@ -33,10 +32,6 @@ export const getDefaultPanel = (hass: HomeAssistant): PanelInfo => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getPanelNameTranslationKey = (panel: PanelInfo) => {
|
export const getPanelNameTranslationKey = (panel: PanelInfo) => {
|
||||||
if (panel.url_path === "lovelace") {
|
|
||||||
return "panel.states" as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (panel.url_path === "profile") {
|
if (panel.url_path === "profile") {
|
||||||
return "panel.profile" as const;
|
return "panel.profile" as const;
|
||||||
}
|
}
|
||||||
@@ -77,8 +72,6 @@ export const getPanelIcon = (panel: PanelInfo): string | undefined => {
|
|||||||
switch (panel.component_name) {
|
switch (panel.component_name) {
|
||||||
case "profile":
|
case "profile":
|
||||||
return "mdi:account";
|
return "mdi:account";
|
||||||
case "lovelace":
|
|
||||||
return "mdi:view-dashboard";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,9 +84,8 @@ export const PANEL_ICON_PATHS = {
|
|||||||
energy: mdiLightningBolt,
|
energy: mdiLightningBolt,
|
||||||
history: mdiChartBox,
|
history: mdiChartBox,
|
||||||
logbook: mdiFormatListBulletedType,
|
logbook: mdiFormatListBulletedType,
|
||||||
lovelace: mdiViewDashboard,
|
|
||||||
profile: mdiAccount,
|
|
||||||
map: mdiTooltipAccount,
|
map: mdiTooltipAccount,
|
||||||
|
profile: mdiAccount,
|
||||||
"media-browser": mdiPlayBoxMultiple,
|
"media-browser": mdiPlayBoxMultiple,
|
||||||
todo: mdiClipboardList,
|
todo: mdiClipboardList,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export class HassRouterPage extends ReactiveElement {
|
|||||||
|
|
||||||
private _initialLoadDone = false;
|
private _initialLoadDone = false;
|
||||||
|
|
||||||
|
private _showLoadingScreenTimeout?: number;
|
||||||
|
|
||||||
private _computeTail = memoizeOne((route: Route) => {
|
private _computeTail = memoizeOne((route: Route) => {
|
||||||
const dividerPos = route.path.indexOf("/", 1);
|
const dividerPos = route.path.indexOf("/", 1);
|
||||||
return dividerPos === -1
|
return dividerPos === -1
|
||||||
@@ -153,7 +155,11 @@ export class HassRouterPage extends ReactiveElement {
|
|||||||
? routeOptions.load()
|
? routeOptions.load()
|
||||||
: Promise.resolve();
|
: Promise.resolve();
|
||||||
|
|
||||||
let showLoadingScreenTimeout: undefined | number;
|
// Clear any existing loading screen timeout from previous navigation
|
||||||
|
if (this._showLoadingScreenTimeout) {
|
||||||
|
clearTimeout(this._showLoadingScreenTimeout);
|
||||||
|
this._showLoadingScreenTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Check when loading the page source failed.
|
// Check when loading the page source failed.
|
||||||
loadProm.catch((err) => {
|
loadProm.catch((err) => {
|
||||||
@@ -170,8 +176,9 @@ export class HassRouterPage extends ReactiveElement {
|
|||||||
this.removeChild(this.lastChild!);
|
this.removeChild(this.lastChild!);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showLoadingScreenTimeout) {
|
if (this._showLoadingScreenTimeout) {
|
||||||
clearTimeout(showLoadingScreenTimeout);
|
clearTimeout(this._showLoadingScreenTimeout);
|
||||||
|
this._showLoadingScreenTimeout = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show error screen
|
// Show error screen
|
||||||
@@ -191,7 +198,7 @@ export class HassRouterPage extends ReactiveElement {
|
|||||||
// That way we won't have a double fast flash on fast connections.
|
// That way we won't have a double fast flash on fast connections.
|
||||||
let created = false;
|
let created = false;
|
||||||
|
|
||||||
showLoadingScreenTimeout = window.setTimeout(() => {
|
this._showLoadingScreenTimeout = window.setTimeout(() => {
|
||||||
if (created || this._currentPage !== newPage) {
|
if (created || this._currentPage !== newPage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const titleInvalid = !this._data.title || !this._data.title.trim();
|
const titleInvalid = !this._data.title || !this._data.title.trim();
|
||||||
const isLovelaceDashboard = this._params.urlPath === "lovelace";
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
@@ -85,20 +84,16 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
|||||||
? this.hass.localize(
|
? this.hass.localize(
|
||||||
"ui.panel.config.lovelace.dashboards.cant_edit_yaml"
|
"ui.panel.config.lovelace.dashboards.cant_edit_yaml"
|
||||||
)
|
)
|
||||||
: isLovelaceDashboard
|
: html`
|
||||||
? this.hass.localize(
|
<ha-form
|
||||||
"ui.panel.config.lovelace.dashboards.cant_edit_lovelace"
|
.schema=${this._schema(this._params)}
|
||||||
)
|
.data=${this._data}
|
||||||
: html`
|
.hass=${this.hass}
|
||||||
<ha-form
|
.error=${this._error}
|
||||||
.schema=${this._schema(this._params)}
|
.computeLabel=${this._computeLabel}
|
||||||
.data=${this._data}
|
@value-changed=${this._valueChanged}
|
||||||
.hass=${this.hass}
|
></ha-form>
|
||||||
.error=${this._error}
|
`}
|
||||||
.computeLabel=${this._computeLabel}
|
|
||||||
@value-changed=${this._valueChanged}
|
|
||||||
></ha-form>
|
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
${this._params.urlPath
|
${this._params.urlPath
|
||||||
? html`
|
? html`
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import "../../../../components/ha-md-list-item";
|
|||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
import "../../../../components/ha-tooltip";
|
import "../../../../components/ha-tooltip";
|
||||||
import { saveFrontendSystemData } from "../../../../data/frontend";
|
import { saveFrontendSystemData } from "../../../../data/frontend";
|
||||||
import type { LovelacePanelConfig } from "../../../../data/lovelace";
|
|
||||||
import type { LovelaceRawConfig } from "../../../../data/lovelace/config/types";
|
import type { LovelaceRawConfig } from "../../../../data/lovelace/config/types";
|
||||||
import {
|
import {
|
||||||
isStrategyDashboard,
|
isStrategyDashboard,
|
||||||
@@ -306,23 +305,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
|
|
||||||
private _getItems = memoize(
|
private _getItems = memoize(
|
||||||
(dashboards: LovelaceDashboard[], defaultUrlPath: string | null) => {
|
(dashboards: LovelaceDashboard[], defaultUrlPath: string | null) => {
|
||||||
const mode = (this.hass.panels?.lovelace?.config as LovelacePanelConfig)
|
const result: DataTableItem[] = [];
|
||||||
.mode;
|
|
||||||
const isDefault = defaultUrlPath === "lovelace";
|
|
||||||
const result: DataTableItem[] = [
|
|
||||||
{
|
|
||||||
icon: "mdi:view-dashboard",
|
|
||||||
title: this.hass.localize("panel.states"),
|
|
||||||
default: isDefault,
|
|
||||||
show_in_sidebar: true,
|
|
||||||
require_admin: false,
|
|
||||||
url_path: "lovelace",
|
|
||||||
mode: mode,
|
|
||||||
filename: mode === "yaml" ? "ui-lovelace.yaml" : "",
|
|
||||||
type: "built_in",
|
|
||||||
localized_type: this._localizeType("built_in"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
PANEL_DASHBOARDS.forEach((panel) => {
|
PANEL_DASHBOARDS.forEach((panel) => {
|
||||||
const panelInfo = this.hass.panels[panel];
|
const panelInfo = this.hass.panels[panel];
|
||||||
|
|||||||
@@ -88,18 +88,16 @@ export class HuiEnergyGasGraphCard
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._config.title
|
<div class="card-header">
|
||||||
? html` <div class="card-header">
|
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||||
<span>${this._config.title}</span>
|
${this._total
|
||||||
${this._total
|
? html`<hui-energy-graph-chip
|
||||||
? html`<hui-energy-graph-chip
|
.tooltip=${this._formatTotal(this._total)}
|
||||||
.tooltip=${this._formatTotal(this._total)}
|
>
|
||||||
>
|
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
||||||
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
</hui-energy-graph-chip>`
|
||||||
</hui-energy-graph-chip>`
|
: nothing}
|
||||||
: nothing}
|
</div>
|
||||||
</div>`
|
|
||||||
: nothing}
|
|
||||||
<div
|
<div
|
||||||
class="content ${classMap({
|
class="content ${classMap({
|
||||||
"has-header": !!this._config.title,
|
"has-header": !!this._config.title,
|
||||||
|
|||||||
@@ -90,18 +90,16 @@ export class HuiEnergySolarGraphCard
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._config.title
|
<div class="card-header">
|
||||||
? html` <div class="card-header">
|
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||||
<span>${this._config.title}</span>
|
${this._total
|
||||||
${this._total
|
? html`<hui-energy-graph-chip
|
||||||
? html`<hui-energy-graph-chip
|
.tooltip=${this._formatTotal(this._total)}
|
||||||
.tooltip=${this._formatTotal(this._total)}
|
>
|
||||||
>
|
${formatNumber(this._total, this.hass.locale)} kWh
|
||||||
${formatNumber(this._total, this.hass.locale)} kWh
|
</hui-energy-graph-chip>`
|
||||||
</hui-energy-graph-chip>`
|
: nothing}
|
||||||
: nothing}
|
</div>
|
||||||
</div>`
|
|
||||||
: nothing}
|
|
||||||
<div
|
<div
|
||||||
class="content ${classMap({
|
class="content ${classMap({
|
||||||
"has-header": !!this._config.title,
|
"has-header": !!this._config.title,
|
||||||
|
|||||||
@@ -103,21 +103,19 @@ export class HuiEnergyUsageGraphCard
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._config.title
|
<div class="card-header">
|
||||||
? html` <div class="card-header">
|
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||||
<span>${this._config.title}</span>
|
${this._total
|
||||||
${this._total
|
? html`<hui-energy-graph-chip
|
||||||
? html`<hui-energy-graph-chip
|
.tooltip=${this._formatTotal(this._total)}
|
||||||
.tooltip=${this._formatTotal(this._total)}
|
>
|
||||||
>
|
${this.hass.localize(
|
||||||
${this.hass.localize(
|
"ui.panel.lovelace.cards.energy.energy_usage_graph.total_usage",
|
||||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.total_usage",
|
{ num: formatNumber(this._total, this.hass.locale) }
|
||||||
{ num: formatNumber(this._total, this.hass.locale) }
|
)}
|
||||||
)}
|
</hui-energy-graph-chip>`
|
||||||
</hui-energy-graph-chip>`
|
: nothing}
|
||||||
: nothing}
|
</div>
|
||||||
</div>`
|
|
||||||
: nothing}
|
|
||||||
<div
|
<div
|
||||||
class="content ${classMap({
|
class="content ${classMap({
|
||||||
"has-header": !!this._config.title,
|
"has-header": !!this._config.title,
|
||||||
|
|||||||
@@ -88,18 +88,16 @@ export class HuiEnergyWaterGraphCard
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._config.title
|
<div class="card-header">
|
||||||
? html` <div class="card-header">
|
<span>${this._config.title ? this._config.title : nothing}</span>
|
||||||
<span>${this._config.title ? this._config.title : nothing}</span>
|
${this._total
|
||||||
${this._total
|
? html`<hui-energy-graph-chip
|
||||||
? html`<hui-energy-graph-chip
|
.tooltip=${this._formatTotal(this._total)}
|
||||||
.tooltip=${this._formatTotal(this._total)}
|
>
|
||||||
>
|
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
||||||
${formatNumber(this._total, this.hass.locale)} ${this._unit}
|
</hui-energy-graph-chip>`
|
||||||
</hui-energy-graph-chip>`
|
: nothing}
|
||||||
: nothing}
|
</div>
|
||||||
</div>`
|
|
||||||
: nothing}
|
|
||||||
<div
|
<div
|
||||||
class="content ${classMap({
|
class="content ${classMap({
|
||||||
"has-header": !!this._config.title,
|
"has-header": !!this._config.title,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
|||||||
import type { PropertyValues, TemplateResult } from "lit";
|
import type { PropertyValues, TemplateResult } from "lit";
|
||||||
import { html, LitElement } from "lit";
|
import { html, LitElement } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { navigate } from "../../common/navigate";
|
||||||
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
||||||
import {
|
import {
|
||||||
addSearchParam,
|
addSearchParam,
|
||||||
@@ -10,6 +11,7 @@ import {
|
|||||||
} from "../../common/url/search-params";
|
} from "../../common/url/search-params";
|
||||||
import { debounce } from "../../common/util/debounce";
|
import { debounce } from "../../common/util/debounce";
|
||||||
import { deepEqual } from "../../common/util/deep-equal";
|
import { deepEqual } from "../../common/util/deep-equal";
|
||||||
|
import "../../components/ha-button";
|
||||||
import { domainToName } from "../../data/integration";
|
import { domainToName } from "../../data/integration";
|
||||||
import { subscribeLovelaceUpdates } from "../../data/lovelace";
|
import { subscribeLovelaceUpdates } from "../../data/lovelace";
|
||||||
import type {
|
import type {
|
||||||
@@ -34,7 +36,6 @@ import { checkLovelaceConfig } from "./common/check-lovelace-config";
|
|||||||
import { loadLovelaceResources } from "./common/load-resources";
|
import { loadLovelaceResources } from "./common/load-resources";
|
||||||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||||
import "./hui-root";
|
import "./hui-root";
|
||||||
import "../../components/ha-button";
|
|
||||||
import { generateLovelaceDashboardStrategy } from "./strategies/get-strategy";
|
import { generateLovelaceDashboardStrategy } from "./strategies/get-strategy";
|
||||||
import type { Lovelace } from "./types";
|
import type { Lovelace } from "./types";
|
||||||
|
|
||||||
@@ -97,11 +98,6 @@ export class LovelacePanel extends LitElement {
|
|||||||
this.lovelace.rawConfig,
|
this.lovelace.rawConfig,
|
||||||
this.lovelace.mode
|
this.lovelace.mode
|
||||||
);
|
);
|
||||||
} else if (this.lovelace && this.lovelace.mode === "generated") {
|
|
||||||
// When lovelace is generated, we re-generate each time a user goes
|
|
||||||
// to the states panel to make sure new entities are shown.
|
|
||||||
this._panelState = "loading";
|
|
||||||
this._regenerateConfig();
|
|
||||||
} else if (this._fetchConfigOnConnect) {
|
} else if (this._fetchConfigOnConnect) {
|
||||||
// Config was changed when we were not at the lovelace panel
|
// Config was changed when we were not at the lovelace panel
|
||||||
this._fetchConfig(false);
|
this._fetchConfig(false);
|
||||||
@@ -296,15 +292,6 @@ export class LovelacePanel extends LitElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private async _regenerateConfig() {
|
|
||||||
const conf = await generateLovelaceDashboardStrategy(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
this.hass!
|
|
||||||
);
|
|
||||||
this._setLovelaceConfig(conf, DEFAULT_CONFIG, "generated");
|
|
||||||
this._panelState = "loaded";
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _subscribeUpdates() {
|
private async _subscribeUpdates() {
|
||||||
this._unsubUpdates = subscribeLovelaceUpdates(
|
this._unsubUpdates = subscribeLovelaceUpdates(
|
||||||
this.hass!.connection,
|
this.hass!.connection,
|
||||||
@@ -340,7 +327,7 @@ export class LovelacePanel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get urlPath() {
|
public get urlPath() {
|
||||||
return this.panel!.url_path === "lovelace" ? null : this.panel!.url_path;
|
return this.panel!.url_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _forceFetchConfig() {
|
private _forceFetchConfig() {
|
||||||
@@ -352,7 +339,7 @@ export class LovelacePanel extends LitElement {
|
|||||||
|
|
||||||
let conf: LovelaceConfig;
|
let conf: LovelaceConfig;
|
||||||
let rawConf: LovelaceRawConfig | undefined;
|
let rawConf: LovelaceRawConfig | undefined;
|
||||||
let confMode: Lovelace["mode"] = this.panel!.config.mode;
|
const confMode: Lovelace["mode"] = this.panel!.config.mode;
|
||||||
let confProm: Promise<LovelaceRawConfig> | undefined;
|
let confProm: Promise<LovelaceRawConfig> | undefined;
|
||||||
const preloadWindow = window as WindowWithPreloads;
|
const preloadWindow = window as WindowWithPreloads;
|
||||||
|
|
||||||
@@ -404,16 +391,8 @@ export class LovelacePanel extends LitElement {
|
|||||||
this._errorMsg = err.message;
|
this._errorMsg = err.message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.hass?.entities || !this.hass.devices || !this.hass.areas) {
|
navigate("/home");
|
||||||
// We need these to generate a dashboard, wait for them
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
conf = await generateLovelaceDashboardStrategy(
|
|
||||||
DEFAULT_CONFIG,
|
|
||||||
this.hass!
|
|
||||||
);
|
|
||||||
rawConf = DEFAULT_CONFIG;
|
|
||||||
confMode = "generated";
|
|
||||||
} finally {
|
} finally {
|
||||||
this._loading = false;
|
this._loading = false;
|
||||||
// Ignore updates for another 2 seconds.
|
// Ignore updates for another 2 seconds.
|
||||||
|
|||||||
Reference in New Issue
Block a user