mirror of
				https://github.com/home-assistant/frontend.git
				synced 2025-10-31 14:39:38 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			20251029.0
			...
			dashboard_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 1b44c7ce64 | 
| @@ -0,0 +1,30 @@ | ||||
| import { customElement } from "lit/decorators"; | ||||
| import { LovelaceDashboardStrategyConfig } from "../../../../data/lovelace/config/types"; | ||||
| import { getLovelaceStrategy } from "../../strategies/get-strategy"; | ||||
| import { LovelaceStrategyEditor } from "../../strategies/types"; | ||||
| import { HuiElementEditor } from "../hui-element-editor"; | ||||
|  | ||||
| @customElement("hui-dashboard-strategy-element-editor") | ||||
| export class HuiDashboardStrategyElementEditor extends HuiElementEditor<LovelaceDashboardStrategyConfig> { | ||||
|   protected async getConfigElement(): Promise< | ||||
|     LovelaceStrategyEditor | undefined | ||||
|   > { | ||||
|     const elClass = await getLovelaceStrategy( | ||||
|       "dashboard", | ||||
|       this.configElementType! | ||||
|     ); | ||||
|  | ||||
|     // Check if a GUI editor exists | ||||
|     if (elClass && elClass.getConfigElement) { | ||||
|       return elClass.getConfigElement(); | ||||
|     } | ||||
|  | ||||
|     return undefined; | ||||
|   } | ||||
| } | ||||
|  | ||||
| declare global { | ||||
|   interface HTMLElementTagNameMap { | ||||
|     "hui-dashboard-strategy-element-editor": HuiDashboardStrategyElementEditor; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,75 @@ | ||||
| import { html, LitElement, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators"; | ||||
| import { fireEvent } from "../../../../common/dom/fire_event"; | ||||
| import "../../../../components/ha-form/ha-form"; | ||||
| import type { | ||||
|   HaFormSchema, | ||||
|   SchemaUnion, | ||||
| } from "../../../../components/ha-form/types"; | ||||
| import type { HomeAssistant } from "../../../../types"; | ||||
| import { OriginalStatesDashboardStrategyConfig } from "../../strategies/original-states-dashboard-strategy"; | ||||
| import { LovelaceStrategyEditor } from "../../strategies/types"; | ||||
|  | ||||
| const SCHEMA = [ | ||||
|   { | ||||
|     name: "no_area_group", | ||||
|     selector: { | ||||
|       boolean: {}, | ||||
|     }, | ||||
|   }, | ||||
| ] as const satisfies readonly HaFormSchema[]; | ||||
|  | ||||
| @customElement("hui-original-states-dashboard-strategy-editor") | ||||
| export class HuiOriginalStatesDashboarStrategyEditor | ||||
|   extends LitElement | ||||
|   implements LovelaceStrategyEditor | ||||
| { | ||||
|   @property({ attribute: false }) public hass?: HomeAssistant; | ||||
|  | ||||
|   @state() | ||||
|   private _config?: OriginalStatesDashboardStrategyConfig; | ||||
|  | ||||
|   public setConfig(config: OriginalStatesDashboardStrategyConfig): void { | ||||
|     this._config = config; | ||||
|   } | ||||
|  | ||||
|   protected render() { | ||||
|     if (!this.hass || !this._config) { | ||||
|       return nothing; | ||||
|     } | ||||
|  | ||||
|     const data = this._config; | ||||
|  | ||||
|     return html` | ||||
|       <ha-form | ||||
|         .hass=${this.hass} | ||||
|         .data=${data} | ||||
|         .schema=${SCHEMA} | ||||
|         .computeLabel=${this._computeLabelCallback} | ||||
|         @value-changed=${this._valueChanged} | ||||
|       ></ha-form> | ||||
|     `; | ||||
|   } | ||||
|  | ||||
|   private _valueChanged(ev: CustomEvent): void { | ||||
|     const config = ev.detail.value; | ||||
|     fireEvent(this, "config-changed", { config }); | ||||
|   } | ||||
|  | ||||
|   private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => { | ||||
|     switch (schema.name) { | ||||
|       case "no_area_group": | ||||
|         return "Do not group by area"; | ||||
|       default: | ||||
|         return this.hass!.localize( | ||||
|           `ui.panel.lovelace.editor.card.generic.${schema.name}` | ||||
|         ); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| declare global { | ||||
|   interface HTMLElementTagNameMap { | ||||
|     "hui-original-states-dashboard-strategy-editor": HuiOriginalStatesDashboarStrategyEditor; | ||||
|   } | ||||
| } | ||||
| @@ -16,8 +16,9 @@ import "../../../components/ha-alert"; | ||||
| import "../../../components/ha-circular-progress"; | ||||
| import "../../../components/ha-code-editor"; | ||||
| import type { HaCodeEditor } from "../../../components/ha-code-editor"; | ||||
| import type { LovelaceCardConfig } from "../../../data/lovelace/config/card"; | ||||
| import type { LovelaceConfig } from "../../../data/lovelace/config/types"; | ||||
| import { LovelaceCardConfig } from "../../../data/lovelace/config/card"; | ||||
| import { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; | ||||
| import { LovelaceConfig } from "../../../data/lovelace/config/types"; | ||||
| import type { HomeAssistant } from "../../../types"; | ||||
| import type { LovelaceRowConfig } from "../entity-rows/types"; | ||||
| import { LovelaceHeaderFooterConfig } from "../header-footer/types"; | ||||
| @@ -36,7 +37,8 @@ export interface ConfigChangedEvent { | ||||
|     | LovelaceCardConfig | ||||
|     | LovelaceRowConfig | ||||
|     | LovelaceHeaderFooterConfig | ||||
|     | LovelaceTileFeatureConfig; | ||||
|     | LovelaceTileFeatureConfig | ||||
|     | LovelaceStrategyConfig; | ||||
|   error?: string; | ||||
|   guiModeAvailable?: boolean; | ||||
| } | ||||
|   | ||||
| @@ -19,12 +19,12 @@ import { | ||||
| import "@polymer/paper-tabs/paper-tab"; | ||||
| import "@polymer/paper-tabs/paper-tabs"; | ||||
| import { | ||||
|   css, | ||||
|   CSSResultGroup, | ||||
|   html, | ||||
|   LitElement, | ||||
|   PropertyValues, | ||||
|   TemplateResult, | ||||
|   css, | ||||
|   html, | ||||
| } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators"; | ||||
| import { classMap } from "lit/directives/class-map"; | ||||
| @@ -64,11 +64,15 @@ 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 type { Lovelace } from "./types"; | ||||
| import "./views/hui-view"; | ||||
| import type { HUIView } from "./views/hui-view"; | ||||
| import { LovelaceViewConfig } from "../../data/lovelace/config/view"; | ||||
| import { LovelaceConfig } from "../../data/lovelace/config/types"; | ||||
| import { | ||||
|   LovelaceConfig, | ||||
|   isStrategyDashboard, | ||||
| } from "../../data/lovelace/config/types"; | ||||
|  | ||||
| @customElement("hui-root") | ||||
| class HUIRoot extends LitElement { | ||||
| @@ -804,6 +808,13 @@ class HUIRoot extends LitElement { | ||||
|       }); | ||||
|       return; | ||||
|     } | ||||
|     if (isStrategyDashboard(this.lovelace!.rawConfig)) { | ||||
|       showDashboardStrategyEditorDialog(this, { | ||||
|         config: this.lovelace!.rawConfig, | ||||
|         saveConfig: this.lovelace!.saveConfig, | ||||
|       }); | ||||
|       return; | ||||
|     } | ||||
|     this.lovelace!.setEditMode(true); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,129 @@ | ||||
| import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; | ||||
| import { customElement, property, query, state } from "lit/decorators"; | ||||
| import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event"; | ||||
| import "../../../../components/ha-button"; | ||||
| import { createCloseHeading } from "../../../../components/ha-dialog"; | ||||
| import { LovelaceStrategyConfig } from "../../../../data/lovelace/config/strategy"; | ||||
| import { haStyle, 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 type { DashboardStrategyEditorDialogParams } from "./show-dialog-dashboard-strategy-editor"; | ||||
|  | ||||
| @customElement("dialog-dashboard-strategy-editor") | ||||
| class DialogDashboardStrategyEditor extends LitElement { | ||||
|   @property({ attribute: false }) public hass!: HomeAssistant; | ||||
|  | ||||
|   @state() private _params?: DashboardStrategyEditorDialogParams; | ||||
|  | ||||
|   @state() private _strategyConfig?: LovelaceStrategyConfig; | ||||
|  | ||||
|   @state() private _GUImode = true; | ||||
|  | ||||
|   @state() private _guiModeAvailable? = true; | ||||
|  | ||||
|   @query("hui-dashboard-strategy-element-editor") | ||||
|   private _strategyEditorEl?: HuiDashboardStrategyElementEditor; | ||||
|  | ||||
|   public async showDialog( | ||||
|     params: DashboardStrategyEditorDialogParams | ||||
|   ): Promise<void> { | ||||
|     this._params = params; | ||||
|     this._strategyConfig = params.config.strategy; | ||||
|     await this.updateComplete; | ||||
|   } | ||||
|  | ||||
|   public closeDialog(): void { | ||||
|     this._params = undefined; | ||||
|     this._strategyConfig = undefined; | ||||
|     fireEvent(this, "dialog-closed", { dialog: this.localName }); | ||||
|   } | ||||
|  | ||||
|   private _handleConfigChanged(ev: HASSDomEvent<ConfigChangedEvent>) { | ||||
|     ev.stopPropagation(); | ||||
|     this._guiModeAvailable = ev.detail.guiModeAvailable; | ||||
|     this._strategyConfig = ev.detail.config as LovelaceStrategyConfig; | ||||
|   } | ||||
|  | ||||
|   private _handleGUIModeChanged(ev: HASSDomEvent<GUIModeChangedEvent>): void { | ||||
|     ev.stopPropagation(); | ||||
|     this._GUImode = ev.detail.guiMode; | ||||
|     this._guiModeAvailable = ev.detail.guiModeAvailable; | ||||
|   } | ||||
|  | ||||
|   private _toggleMode(): void { | ||||
|     this._strategyEditorEl?.toggleMode(); | ||||
|   } | ||||
|  | ||||
|   private _opened() { | ||||
|     this._strategyEditorEl?.focusYamlEditor(); | ||||
|   } | ||||
|  | ||||
|   private async _save(): Promise<void> { | ||||
|     await this._params!.saveConfig({ | ||||
|       ...this._params!.config, | ||||
|       strategy: this._strategyConfig!, | ||||
|     }); | ||||
|     showSaveSuccessToast(this, this.hass); | ||||
|     this.closeDialog(); | ||||
|   } | ||||
|  | ||||
|   protected render() { | ||||
|     if (!this._params || !this._strategyConfig) { | ||||
|       return nothing; | ||||
|     } | ||||
|  | ||||
|     const config = cleanLegacyStrategyConfig(this._strategyConfig); | ||||
|  | ||||
|     return html` | ||||
|       <ha-dialog | ||||
|         open | ||||
|         @closed=${this.closeDialog} | ||||
|         .heading=${createCloseHeading(this.hass, "Edit dashboard")} | ||||
|         @opened=${this._opened} | ||||
|       > | ||||
|         <hui-dashboard-strategy-element-editor | ||||
|           .hass=${this.hass} | ||||
|           .lovelace=${this._params.config} | ||||
|           .value=${config} | ||||
|           @config-changed=${this._handleConfigChanged} | ||||
|           @GUImode-changed=${this._handleGUIModeChanged} | ||||
|           dialogInitialFocus | ||||
|         ></hui-dashboard-strategy-element-editor> | ||||
|         ${this._strategyConfig !== undefined | ||||
|           ? html` | ||||
|               <ha-button | ||||
|                 slot="secondaryAction" | ||||
|                 @click=${this._toggleMode} | ||||
|                 .disabled=${!this._guiModeAvailable} | ||||
|                 class="gui-mode-button" | ||||
|               > | ||||
|                 ${this.hass!.localize( | ||||
|                   !this._strategyEditorEl || this._GUImode | ||||
|                     ? "ui.panel.lovelace.editor.edit_card.show_code_editor" | ||||
|                     : "ui.panel.lovelace.editor.edit_card.show_visual_editor" | ||||
|                 )} | ||||
|               </ha-button> | ||||
|               <ha-button @click=${this._save} slot="primaryAction"> | ||||
|                 ${this.hass!.localize("ui.common.save")} | ||||
|               </ha-button> | ||||
|             ` | ||||
|           : nothing} | ||||
|       </ha-dialog> | ||||
|     `; | ||||
|   } | ||||
|  | ||||
|   static get styles(): CSSResultGroup { | ||||
|     return [haStyle, haStyleDialog, css``]; | ||||
|   } | ||||
| } | ||||
|  | ||||
| declare global { | ||||
|   interface HTMLElementTagNameMap { | ||||
|     "dialog-dashboard-strategy-editor": DialogDashboardStrategyEditor; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| import { fireEvent } from "../../../../common/dom/fire_event"; | ||||
| import { LovelaceDashboardStrategyConfig } from "../../../../data/lovelace/config/types"; | ||||
|  | ||||
| export interface DashboardStrategyEditorDialogParams { | ||||
|   config: LovelaceDashboardStrategyConfig; | ||||
|   saveConfig: (config: LovelaceDashboardStrategyConfig) => void; | ||||
| } | ||||
|  | ||||
| export const loadDashboardStrategyEditorDialog = () => | ||||
|   import("./dialog-dashboard-strategy-editor"); | ||||
|  | ||||
| export const showDashboardStrategyEditorDialog = ( | ||||
|   element: HTMLElement, | ||||
|   params: DashboardStrategyEditorDialogParams | ||||
| ): void => { | ||||
|   fireEvent(element, "show-dialog", { | ||||
|     dialogTag: "dialog-dashboard-strategy-editor", | ||||
|     dialogImport: loadDashboardStrategyEditorDialog, | ||||
|     dialogParams: params, | ||||
|   }); | ||||
| }; | ||||
| @@ -9,7 +9,7 @@ import { | ||||
|   isStrategyView, | ||||
| } from "../../../data/lovelace/config/view"; | ||||
| import { AsyncReturnType, HomeAssistant } from "../../../types"; | ||||
| import { isLegacyStrategy } from "./legacy-strategy"; | ||||
| import { cleanLegacyStrategyConfig, isLegacyStrategy } from "./legacy-strategy"; | ||||
| import { | ||||
|   LovelaceDashboardStrategy, | ||||
|   LovelaceStrategy, | ||||
| @@ -40,7 +40,7 @@ type StrategyConfig<T extends LovelaceStrategyConfigType> = AsyncReturnType< | ||||
|   Strategies[T]["generate"] | ||||
| >; | ||||
|  | ||||
| const getLovelaceStrategy = async <T extends LovelaceStrategyConfigType>( | ||||
| export const getLovelaceStrategy = async <T extends LovelaceStrategyConfigType>( | ||||
|   configType: T, | ||||
|   strategyType: string | ||||
| ): Promise<LovelaceStrategy> => { | ||||
| @@ -109,12 +109,7 @@ const generateStrategy = async <T extends LovelaceStrategyConfigType>( | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     const config = { | ||||
|       ...strategyConfig, | ||||
|       ...strategyConfig.options, | ||||
|     }; | ||||
|  | ||||
|     delete config.options; | ||||
|     const config = cleanLegacyStrategyConfig(strategyConfig); | ||||
|  | ||||
|     return await strategy.generate(config, hass); | ||||
|   } catch (err: any) { | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; | ||||
| import { | ||||
|   LovelaceConfig, | ||||
|   LovelaceRawConfig, | ||||
| @@ -27,3 +28,16 @@ export interface LovelaceViewStrategy { | ||||
|     hass: HomeAssistant; | ||||
|   }): Promise<LovelaceViewConfig>; | ||||
| } | ||||
|  | ||||
| export const cleanLegacyStrategyConfig = (config: LovelaceStrategyConfig) => { | ||||
|   if (!(Object.keys(config).length === 2 && "options" in config)) { | ||||
|     return config; | ||||
|   } | ||||
|   const cleanedConfig = { | ||||
|     ...config, | ||||
|     ...config.options, | ||||
|   }; | ||||
|  | ||||
|   delete cleanedConfig.options; | ||||
|   return cleanedConfig; | ||||
| }; | ||||
|   | ||||
| @@ -1,22 +1,39 @@ | ||||
| import { ReactiveElement } from "lit"; | ||||
| import { customElement } from "lit/decorators"; | ||||
| import { HomeAssistant } from "../../../types"; | ||||
| import { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; | ||||
| import { LovelaceConfig } from "../../../data/lovelace/config/types"; | ||||
| import { HomeAssistant } from "../../../types"; | ||||
| import { LovelaceStrategyEditor } from "./types"; | ||||
|  | ||||
| export type OriginalStatesDashboardStrategyConfig = LovelaceStrategyConfig & { | ||||
|   no_area_group?: boolean; | ||||
| }; | ||||
|  | ||||
| @customElement("original-states-dashboard-strategy") | ||||
| export class OriginalStatesDashboardStrategy extends ReactiveElement { | ||||
|   static async generate( | ||||
|     _config: LovelaceStrategyConfig, | ||||
|     config: OriginalStatesDashboardStrategyConfig, | ||||
|     hass: HomeAssistant | ||||
|   ): Promise<LovelaceConfig> { | ||||
|     return { | ||||
|       title: hass.config.location_name, | ||||
|       views: [ | ||||
|         { | ||||
|           strategy: { type: "original-states" }, | ||||
|           strategy: { | ||||
|             type: "original-states", | ||||
|             no_area_group: config.no_area_group, | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   public static async getConfigElement(): Promise<LovelaceStrategyEditor> { | ||||
|     await import( | ||||
|       "../editor/dashboard-strategy-editor/hui-original-states-dashboard-strategy-editor" | ||||
|     ); | ||||
|     return document.createElement( | ||||
|       "hui-original-states-dashboard-strategy-editor" | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,15 +3,18 @@ import { ReactiveElement } from "lit"; | ||||
| import { customElement } from "lit/decorators"; | ||||
| import { isComponentLoaded } from "../../../common/config/is_component_loaded"; | ||||
| import { getEnergyPreferences } from "../../../data/energy"; | ||||
| import { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; | ||||
| import { LovelaceViewConfig } from "../../../data/lovelace/config/view"; | ||||
| import { HomeAssistant } from "../../../types"; | ||||
| import { generateDefaultViewConfig } from "../common/generate-lovelace-config"; | ||||
|  | ||||
| export type OriginalStatesViewStrategyConfig = { | ||||
|   no_area_group?: boolean; | ||||
| }; | ||||
|  | ||||
| @customElement("original-states-view-strategy") | ||||
| export class OriginalStatesViewStrategy extends ReactiveElement { | ||||
|   static async generate( | ||||
|     _config: LovelaceStrategyConfig, | ||||
|     config: OriginalStatesViewStrategyConfig, | ||||
|     hass: HomeAssistant | ||||
|   ): Promise<LovelaceViewConfig> { | ||||
|     if (hass.config.state === STATE_NOT_RUNNING) { | ||||
| @@ -37,7 +40,7 @@ export class OriginalStatesViewStrategy extends ReactiveElement { | ||||
|     // User can override default view. If they didn't, we will add one | ||||
|     // that contains all entities. | ||||
|     const view = generateDefaultViewConfig( | ||||
|       hass.areas, | ||||
|       config.no_area_group ? {} : hass.areas, | ||||
|       hass.devices, | ||||
|       hass.entities, | ||||
|       hass.states, | ||||
|   | ||||
| @@ -2,9 +2,11 @@ import { LovelaceConfig } from "../../../data/lovelace/config/types"; | ||||
| import { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy"; | ||||
| import { LovelaceViewConfig } from "../../../data/lovelace/config/view"; | ||||
| import { HomeAssistant } from "../../../types"; | ||||
| import { LovelaceGenericElementEditor } from "../types"; | ||||
|  | ||||
| export type LovelaceStrategy<T = any> = { | ||||
|   generate(config: LovelaceStrategyConfig, hass: HomeAssistant): Promise<T>; | ||||
|   getConfigElement?: () => LovelaceStrategyEditor; | ||||
| }; | ||||
|  | ||||
| export interface LovelaceDashboardStrategy | ||||
| @@ -12,3 +14,7 @@ export interface LovelaceDashboardStrategy | ||||
|  | ||||
| export interface LovelaceViewStrategy | ||||
|   extends LovelaceStrategy<LovelaceViewConfig> {} | ||||
|  | ||||
| export interface LovelaceStrategyEditor extends LovelaceGenericElementEditor { | ||||
|   setConfig(config: LovelaceStrategyConfig): void; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user