Add map strategy (#20067)
This commit is contained in:
parent
56a23c5c3d
commit
31797c55df
|
@ -1,20 +1,32 @@
|
|||
import "@material/mwc-list/mwc-list";
|
||||
import { mdiPencilOutline, mdiShape } from "@mdi/js";
|
||||
import { mdiMap, mdiPencilOutline, mdiShape } from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-list-item";
|
||||
import { LovelaceRawConfig } from "../../../data/lovelace/config/types";
|
||||
import { HassDialog } from "../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||
import { NewDashboardDialogParams } from "./show-dialog-new-dashboard";
|
||||
import { LovelaceRawConfig } from "../../../data/lovelace/config/types";
|
||||
|
||||
const EMPTY_CONFIG: LovelaceRawConfig = { views: [{ title: "Home" }] };
|
||||
|
||||
type Strategy = {
|
||||
type: string;
|
||||
iconPath: string;
|
||||
};
|
||||
|
||||
const STRATEGIES = [
|
||||
{
|
||||
type: "map",
|
||||
iconPath: mdiMap,
|
||||
},
|
||||
] as const satisfies Strategy[];
|
||||
|
||||
@customElement("ha-dialog-new-dashboard")
|
||||
class DialogNewDashboard extends LitElement implements HassDialog {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
@ -100,16 +112,55 @@ class DialogNewDashboard extends LitElement implements HassDialog {
|
|||
>
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
${STRATEGIES.map(
|
||||
(strategy) => html`
|
||||
<ha-list-item
|
||||
hasmeta
|
||||
twoline
|
||||
graphic="icon"
|
||||
.strategy=${strategy.type}
|
||||
@request-selected=${this._selected}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${strategy.iconPath}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.lovelace.dashboards.dialog_new.strategy.${strategy.type}.title`
|
||||
)}
|
||||
<span slot="secondary">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.lovelace.dashboards.dialog_new.strategy.${strategy.type}.description`
|
||||
)}
|
||||
</span>
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</mwc-list>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _generateStrategyConfig(strategy: string) {
|
||||
return {
|
||||
strategy: {
|
||||
type: strategy,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private async _selected(ev) {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
const config = (ev.currentTarget! as any).config;
|
||||
|
||||
const target = ev.currentTarget as any;
|
||||
const config =
|
||||
target.config ||
|
||||
(target.strategy && this._generateStrategyConfig(target.strategy)) ||
|
||||
null;
|
||||
|
||||
this._params?.selectConfig(config);
|
||||
this.closeDialog();
|
||||
}
|
||||
|
|
|
@ -6,22 +6,22 @@ import {
|
|||
} from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-header";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import { LovelaceStrategyConfig } from "../../../../data/lovelace/config/strategy";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { showSaveSuccessToast } from "../../../../util/toast-saved-success";
|
||||
import "../../editor/dashboard-strategy-editor/hui-dashboard-strategy-element-editor";
|
||||
import type { HuiDashboardStrategyElementEditor } from "../../editor/dashboard-strategy-editor/hui-dashboard-strategy-element-editor";
|
||||
import { ConfigChangedEvent } from "../../editor/hui-element-editor";
|
||||
import { GUIModeChangedEvent } from "../../editor/types";
|
||||
import { cleanLegacyStrategyConfig } from "../legacy-strategy";
|
||||
import { HASSDomEvent, fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-button-menu";
|
||||
import "../../../../../components/ha-dialog";
|
||||
import "../../../../../components/ha-dialog-header";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import { LovelaceStrategyConfig } from "../../../../../data/lovelace/config/strategy";
|
||||
import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { showSaveSuccessToast } from "../../../../../util/toast-saved-success";
|
||||
import "../hui-dashboard-strategy-element-editor";
|
||||
import type { HuiDashboardStrategyElementEditor } from "../hui-dashboard-strategy-element-editor";
|
||||
import { ConfigChangedEvent } from "../../hui-element-editor";
|
||||
import { GUIModeChangedEvent } from "../../types";
|
||||
import { cleanLegacyStrategyConfig } from "../../../strategies/legacy-strategy";
|
||||
import type { DashboardStrategyEditorDialogParams } from "./show-dialog-dashboard-strategy-editor";
|
||||
|
||||
@customElement("dialog-dashboard-strategy-editor")
|
|
@ -1,5 +1,5 @@
|
|||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { LovelaceDashboardStrategyConfig } from "../../../../data/lovelace/config/types";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { LovelaceDashboardStrategyConfig } from "../../../../../data/lovelace/config/types";
|
||||
|
||||
export interface DashboardStrategyEditorDialogParams {
|
||||
config: LovelaceDashboardStrategyConfig;
|
|
@ -7,7 +7,7 @@ import type {
|
|||
SchemaUnion,
|
||||
} from "../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { OriginalStatesDashboardStrategyConfig } from "../../strategies/original-states-dashboard-strategy";
|
||||
import { OriginalStatesDashboardStrategyConfig } from "../../strategies/original-states/original-states-dashboard-strategy";
|
||||
import { LovelaceStrategyEditor } from "../../strategies/types";
|
||||
|
||||
const SCHEMA = [
|
||||
|
@ -38,7 +38,7 @@ const SCHEMA = [
|
|||
] as const satisfies readonly HaFormSchema[];
|
||||
|
||||
@customElement("hui-original-states-dashboard-strategy-editor")
|
||||
export class HuiOriginalStatesDashboarStrategyEditor
|
||||
export class HuiOriginalStatesDashboardStrategyEditor
|
||||
extends LitElement
|
||||
implements LovelaceStrategyEditor
|
||||
{
|
||||
|
@ -88,6 +88,6 @@ export class HuiOriginalStatesDashboarStrategyEditor
|
|||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-original-states-dashboard-strategy-editor": HuiOriginalStatesDashboarStrategyEditor;
|
||||
"hui-original-states-dashboard-strategy-editor": HuiOriginalStatesDashboardStrategyEditor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ import { documentationUrl } from "../../util/documentation-url";
|
|||
import { swapView } from "./editor/config-util";
|
||||
import { showEditLovelaceDialog } from "./editor/lovelace-editor/show-edit-lovelace-dialog";
|
||||
import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
|
||||
import { showDashboardStrategyEditorDialog } from "./strategies/device-registry-detail/show-dialog-dashboard-strategy-editor";
|
||||
import { showDashboardStrategyEditorDialog } from "./editor/dashboard-strategy-editor/dialogs/show-dialog-dashboard-strategy-editor";
|
||||
import type { Lovelace } from "./types";
|
||||
import "./views/hui-view";
|
||||
import type { HUIView } from "./views/hui-view";
|
||||
|
@ -75,6 +75,7 @@ import {
|
|||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||
import { isLegacyStrategyConfig } from "./strategies/legacy-strategy";
|
||||
import { LocalizeKeys } from "../../common/translations/localize";
|
||||
import { getLovelaceStrategy } from "./strategies/get-strategy";
|
||||
|
||||
@customElement("hui-root")
|
||||
class HUIRoot extends LitElement {
|
||||
|
@ -709,7 +710,7 @@ class HUIRoot extends LitElement {
|
|||
this._enableEditMode();
|
||||
}
|
||||
|
||||
private _enableEditMode(): void {
|
||||
private async _enableEditMode() {
|
||||
if (this._yamlMode) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass!.localize("ui.panel.lovelace.editor.yaml_unsupported"),
|
||||
|
@ -720,6 +721,18 @@ class HUIRoot extends LitElement {
|
|||
isStrategyDashboard(this.lovelace!.rawConfig) &&
|
||||
!isLegacyStrategyConfig(this.lovelace!.rawConfig.strategy)
|
||||
) {
|
||||
const strategyClass = await getLovelaceStrategy(
|
||||
"dashboard",
|
||||
this.lovelace!.rawConfig.strategy.type
|
||||
).catch((_err) => undefined);
|
||||
if (strategyClass?.noEditor) {
|
||||
showSaveDialog(this, {
|
||||
lovelace: this.lovelace!,
|
||||
mode: "storage",
|
||||
narrow: this.narrow!,
|
||||
});
|
||||
return;
|
||||
}
|
||||
showDashboardStrategyEditorDialog(this, {
|
||||
config: this.lovelace!.rawConfig,
|
||||
saveConfig: this.lovelace!.saveConfig,
|
||||
|
|
|
@ -22,11 +22,15 @@ const CUSTOM_PREFIX = "custom:";
|
|||
|
||||
const STRATEGIES: Record<LovelaceStrategyConfigType, Record<string, any>> = {
|
||||
dashboard: {
|
||||
"original-states": () => import("./original-states-dashboard-strategy"),
|
||||
"original-states": () =>
|
||||
import("./original-states/original-states-dashboard-strategy"),
|
||||
map: () => import("./map/map-dashboard-strategy"),
|
||||
},
|
||||
view: {
|
||||
"original-states": () => import("./original-states-view-strategy"),
|
||||
"original-states": () =>
|
||||
import("./original-states/original-states-view-strategy"),
|
||||
energy: () => import("../../energy/strategies/energy-view-strategy"),
|
||||
map: () => import("./map/map-view-strategy"),
|
||||
},
|
||||
section: {},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { MapViewStrategyConfig } from "./map-view-strategy";
|
||||
|
||||
export type MapDashboardStrategyConfig = MapViewStrategyConfig;
|
||||
|
||||
@customElement("map-dashboard-strategy")
|
||||
export class MapDashboardStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
config: MapDashboardStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceConfig> {
|
||||
return {
|
||||
title: hass.localize("panel.map"),
|
||||
views: [
|
||||
{
|
||||
strategy: config,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
static noEditor = true;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"map-dashboard-strategy": MapDashboardStrategy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeStateDomain } from "../../../../common/entity/compute_state_domain";
|
||||
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { MapCardConfig } from "../../cards/types";
|
||||
|
||||
export type MapViewStrategyConfig = {
|
||||
type: "map";
|
||||
};
|
||||
|
||||
const getMapEntities = (hass: HomeAssistant) => {
|
||||
const personSources = new Set<string>();
|
||||
const locationEntities: string[] = [];
|
||||
Object.values(hass.states).forEach((entity) => {
|
||||
if (
|
||||
entity.state === "home" ||
|
||||
!("latitude" in entity.attributes) ||
|
||||
!("longitude" in entity.attributes)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
locationEntities.push(entity.entity_id);
|
||||
if (computeStateDomain(entity) === "person" && entity.attributes.source) {
|
||||
personSources.add(entity.attributes.source);
|
||||
}
|
||||
});
|
||||
|
||||
return locationEntities.filter((entity) => !personSources.has(entity));
|
||||
};
|
||||
|
||||
@customElement("map-view-strategy")
|
||||
export class MapViewStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
_config: MapViewStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const entities = getMapEntities(hass);
|
||||
return {
|
||||
type: "panel",
|
||||
title: hass.localize("panel.map"),
|
||||
icon: "mdi:map",
|
||||
cards: [
|
||||
{
|
||||
type: "map",
|
||||
auto_fit: true,
|
||||
entities: entities,
|
||||
} as MapCardConfig,
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"map-view-strategy": MapViewStrategy;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { LovelaceConfig } from "../../../data/lovelace/config/types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { OriginalStatesViewStrategyConfig } from "./original-states-view-strategy";
|
||||
import { LovelaceStrategyEditor } from "./types";
|
||||
import { LovelaceStrategyEditor } from "../types";
|
||||
|
||||
export type OriginalStatesDashboardStrategyConfig =
|
||||
OriginalStatesViewStrategyConfig;
|
||||
|
@ -26,7 +26,7 @@ export class OriginalStatesDashboardStrategy extends ReactiveElement {
|
|||
|
||||
public static async getConfigElement(): Promise<LovelaceStrategyEditor> {
|
||||
await import(
|
||||
"../editor/dashboard-strategy-editor/hui-original-states-dashboard-strategy-editor"
|
||||
"../../editor/dashboard-strategy-editor/hui-original-states-dashboard-strategy-editor"
|
||||
);
|
||||
return document.createElement(
|
||||
"hui-original-states-dashboard-strategy-editor"
|
|
@ -1,12 +1,12 @@
|
|||
import { STATE_NOT_RUNNING } from "home-assistant-js-websocket";
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import type { AreaFilterValue } from "../../../components/ha-area-filter";
|
||||
import { getEnergyPreferences } from "../../../data/energy";
|
||||
import { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { generateDefaultViewConfig } from "../common/generate-lovelace-config";
|
||||
import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
|
||||
import type { AreaFilterValue } from "../../../../components/ha-area-filter";
|
||||
import { getEnergyPreferences } from "../../../../data/energy";
|
||||
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { generateDefaultViewConfig } from "../../common/generate-lovelace-config";
|
||||
|
||||
export type OriginalStatesViewStrategyConfig = {
|
||||
type: "original-states";
|
|
@ -8,6 +8,7 @@ import { LovelaceGenericElementEditor } from "../types";
|
|||
export type LovelaceStrategy<T = any> = {
|
||||
generate(config: LovelaceStrategyConfig, hass: HomeAssistant): Promise<T>;
|
||||
getConfigElement?: () => LovelaceStrategyEditor;
|
||||
noEditor?: boolean;
|
||||
};
|
||||
|
||||
export interface LovelaceDashboardStrategy
|
||||
|
|
|
@ -2207,7 +2207,13 @@
|
|||
"create_empty": "New dashboard from scratch",
|
||||
"create_empty_description": "Start with an empty dashboard from scratch",
|
||||
"default": "Default dashboard",
|
||||
"default_description": "Display your devices grouped by area"
|
||||
"default_description": "Display your devices grouped by area",
|
||||
"strategy": {
|
||||
"map": {
|
||||
"title": "[%key:panel::map%]",
|
||||
"description": "Display people and your devices on a map"
|
||||
}
|
||||
}
|
||||
},
|
||||
"picker": {
|
||||
"headers": {
|
||||
|
|
Loading…
Reference in New Issue