1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-04-02 00:27:49 +01:00

Use form instead of schema for element-sub-editor (#30210)

* Use form instead of schema for element-sub-editor

* fix after merge dev
This commit is contained in:
karwosts
2026-03-23 01:28:07 -07:00
committed by GitHub
parent dba8cefa67
commit db05b07997
10 changed files with 160 additions and 132 deletions

View File

@@ -41,20 +41,22 @@ const cardConfigStruct = assign(
})
);
const SUB_SCHEMA = [
{ name: "entity", selector: { entity: {} }, required: true },
{
name: "name",
selector: { entity_name: {} },
context: {
entity: "entity",
const SUB_FORM = {
schema: [
{ name: "entity", selector: { entity: {} }, required: true },
{
name: "name",
selector: { entity_name: {} },
context: {
entity: "entity",
},
},
},
{
name: "color",
selector: { ui_color: {} },
},
] as const;
{
name: "color",
selector: { ui_color: {} },
},
] as const,
};
const SCHEMA = [{ name: "title", selector: { text: {} } }] as const;
@@ -127,7 +129,7 @@ export class HuiDistributionCardEditor
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.schema=${SUB_SCHEMA}
.form=${SUB_FORM}
@go-back=${this._goBack}
@config-changed=${this._handleSubElementChanged}
>

View File

@@ -29,7 +29,6 @@ import {
import type { EntityBadgeConfig } from "../../badges/types";
import type { LovelaceBadgeEditor } from "../../types";
import { ACTION_RELATED_CONTEXT } from "../../components/hui-action-editor";
import "../hui-sub-element-editor";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceBadgeConfig } from "../structs/base-badge-struct";
import { entityNameStruct } from "../structs/entity-name-struct";

View File

@@ -41,56 +41,58 @@ const cardConfigStruct = assign(
})
);
const SUB_SCHEMA = [
{ name: "entity", selector: { entity: {} }, required: true },
{
name: "name",
selector: { entity_name: {} },
context: {
entity: "entity",
},
},
{
type: "grid",
name: "",
schema: [
{
name: "icon",
selector: {
icon: {},
},
context: {
icon_entity: "entity",
},
},
{ name: "show_last_changed", selector: { boolean: {} } },
{ name: "show_state", selector: { boolean: {} }, default: true },
],
},
{
name: "tap_action",
selector: {
ui_action: {
default_action: "more-info",
const SUB_FORM = {
schema: [
{ name: "entity", selector: { entity: {} }, required: true },
{
name: "name",
selector: { entity_name: {} },
context: {
entity: "entity",
},
},
context: ACTION_RELATED_CONTEXT,
},
{
name: "",
type: "optional_actions",
flatten: true,
schema: (["hold_action", "double_tap_action"] as const).map((action) => ({
name: action,
{
type: "grid",
name: "",
schema: [
{
name: "icon",
selector: {
icon: {},
},
context: {
icon_entity: "entity",
},
},
{ name: "show_last_changed", selector: { boolean: {} } },
{ name: "show_state", selector: { boolean: {} }, default: true },
],
},
{
name: "tap_action",
selector: {
ui_action: {
default_action: "none" as const,
default_action: "more-info",
},
},
context: ACTION_RELATED_CONTEXT,
})),
},
] as const;
},
{
name: "",
type: "optional_actions",
flatten: true,
schema: (["hold_action", "double_tap_action"] as const).map((action) => ({
name: action,
selector: {
ui_action: {
default_action: "none" as const,
},
},
context: ACTION_RELATED_CONTEXT,
})),
},
] as const,
};
const SCHEMA = [
{ name: "title", selector: { text: {} } },
@@ -144,7 +146,7 @@ export class HuiGlanceCardEditor
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.schema=${SUB_SCHEMA}
.form=${SUB_FORM}
@go-back=${this._goBack}
@config-changed=${this._handleSubEntityChanged}
>

View File

@@ -43,16 +43,18 @@ const cardConfigStruct = assign(
})
);
const SUB_SCHEMA = [
{ name: "entity", selector: { entity: {} }, required: true },
{
name: "name",
selector: { entity_name: {} },
context: {
entity: "entity",
const SUB_FORM = {
schema: [
{ name: "entity", selector: { entity: {} }, required: true },
{
name: "name",
selector: { entity_name: {} },
context: {
entity: "entity",
},
},
},
] as const;
] as const,
};
@customElement("hui-history-graph-card-editor")
export class HuiHistoryGraphCardEditor
@@ -131,7 +133,7 @@ export class HuiHistoryGraphCardEditor
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.schema=${SUB_SCHEMA}
.form=${SUB_FORM}
@go-back=${this._goBack}
@config-changed=${this._handleSubEntityChanged}
>

View File

@@ -21,7 +21,10 @@ import { hasLocation } from "../../../../common/entity/has_location";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import { orderProperties } from "../../../../common/util/order-properties";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import type {
HaFormSchema,
SchemaUnion,
} from "../../../../components/ha-form/types";
import { MAP_CARD_MARKER_LABEL_MODES } from "../../../../components/map/ha-map";
import "../../../../components/ha-formfield";
import "../../../../components/ha-selector/ha-selector-select";
@@ -152,9 +155,9 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
] as const
);
private _subSchema = memoizeOne(
(localize: LocalizeFunc, entityId: string, includeEntities: string[]) =>
[
private _subForm = memoizeOne(
(localize: LocalizeFunc, entityId: string, includeEntities: string[]) => ({
schema: [
{
name: "entity",
selector: {
@@ -207,7 +210,20 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
{ name: "focus", default: true, selector: { boolean: {} } },
],
},
] as const
] as const,
computeLabel: (item: HaFormSchema) => {
if (item.name === "focus") {
return localize("ui.panel.lovelace.editor.card.map.focus");
}
return undefined;
},
computeHelper: (item: HaFormSchema) => {
if (item.name === "focus") {
return localize("ui.panel.lovelace.editor.card.map.focus_helper");
}
return undefined;
},
})
);
public setConfig(config: MapCardConfig): void {
@@ -258,7 +274,7 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.schema=${this._subSchema(
.form=${this._subForm(
this.hass.localize,
entityId,
this._locationEntities

View File

@@ -176,55 +176,54 @@ export class HuiPictureGlanceCardEditor
] as const satisfies HaFormSchema[]
);
private _subSchema = memoizeOne(
(entityId: string) =>
[
{ name: "entity", selector: { entity: {} }, required: true },
{
type: "grid",
name: "",
schema: [
{
name: "icon",
selector: {
icon: {},
},
context: {
icon_entity: "entity",
},
private _subForm = memoizeOne((entityId: string) => ({
schema: [
{ name: "entity", selector: { entity: {} }, required: true },
{
type: "grid",
name: "",
schema: [
{
name: "icon",
selector: {
icon: {},
},
{ name: "show_state", selector: { boolean: {} } },
],
},
{
name: "tap_action",
selector: {
ui_action: {
default_action: DOMAINS_TOGGLE.has(computeDomain(entityId))
? "toggle"
: "more-info",
context: {
icon_entity: "entity",
},
},
context: ACTION_RELATED_CONTEXT,
{ name: "show_state", selector: { boolean: {} } },
],
},
{
name: "tap_action",
selector: {
ui_action: {
default_action: DOMAINS_TOGGLE.has(computeDomain(entityId))
? "toggle"
: "more-info",
},
},
{
name: "",
type: "optional_actions",
flatten: true,
schema: (["hold_action", "double_tap_action"] as const).map(
(action) => ({
name: action,
selector: {
ui_action: {
default_action: "none" as const,
},
context: ACTION_RELATED_CONTEXT,
},
{
name: "",
type: "optional_actions",
flatten: true,
schema: (["hold_action", "double_tap_action"] as const).map(
(action) => ({
name: action,
selector: {
ui_action: {
default_action: "none" as const,
},
context: ACTION_RELATED_CONTEXT,
})
),
},
] as const
);
},
context: ACTION_RELATED_CONTEXT,
})
),
},
] as const,
}));
public setConfig(config: PictureGlanceCardConfig): void {
assert(config, cardConfigStruct);
@@ -242,7 +241,7 @@ export class HuiPictureGlanceCardEditor
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.schema=${this._subSchema(
.form=${this._subForm(
(this._subElementEditorConfig.elementConfig! as EntityConfig).entity
)}
@go-back=${this._goBack}

View File

@@ -1,14 +1,11 @@
import { customElement } from "lit/decorators";
import { assert, assign, boolean, object, optional, string } from "superstruct";
import "../../../../components/ha-form/ha-form";
import type {
EntityBadgeConfig,
StateLabelBadgeConfig,
} from "../../badges/types";
import "../hui-sub-element-editor";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceBadgeConfig } from "../structs/base-badge-struct";
import "./hui-card-features-editor";
import { HuiEntityBadgeEditor } from "./hui-entity-badge-editor";
const badgeConfigStruct = assign(

View File

@@ -1,25 +1,34 @@
import type { PropertyValues } from "lit";
import { customElement, property } from "lit/decorators";
import type { HaFormSchema } from "../../../components/ha-form/types";
import type { LovelaceConfigForm } from "../types";
import type { HuiFormEditor } from "./config-elements/hui-form-editor";
import { HuiElementEditor } from "./hui-element-editor";
@customElement("hui-form-element-editor")
export class HuiFormElementEditor extends HuiElementEditor {
@property({ attribute: false }) public schema!: HaFormSchema[];
@property({ attribute: false }) public form!: LovelaceConfigForm;
protected async getConfigForm(): Promise<LovelaceConfigForm | undefined> {
return { schema: this.schema };
return this.form;
}
protected updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
if (changedProperties.has("schema") && this._configElement) {
if (changedProperties.has("form") && this._configElement) {
// Propagate schema changes directly to the existing form editor element
// so dynamic changes (e.g. disabled flags based on selected entity) are
// reflected without needing to tear down and recreate the editor.
(this._configElement as HuiFormEditor).schema = this.schema;
const { schema, assertConfig, computeLabel, computeHelper } = this.form;
(this._configElement as HuiFormEditor).schema = schema;
if (computeLabel) {
(this._configElement as HuiFormEditor).computeLabel = computeLabel;
}
if (computeHelper) {
(this._configElement as HuiFormEditor).computeHelper = computeHelper;
}
if (assertConfig) {
(this._configElement as HuiFormEditor).assertConfig = assertConfig;
}
}
}
}

View File

@@ -15,6 +15,7 @@ import type { HuiElementEditor } from "./hui-element-editor";
import "./hui-form-element-editor";
import "./picture-element-editor/hui-picture-element-element-editor";
import type { GUIModeChangedEvent, SubElementEditorConfig } from "./types";
import type { LovelaceConfigForm } from "../types";
declare global {
interface HASSDomEvents {
@@ -28,7 +29,7 @@ export class HuiSubElementEditor extends LitElement {
@property({ attribute: false }) public config!: SubElementEditorConfig;
@property({ attribute: false }) public schema?;
@property({ attribute: false }) public form?: LovelaceConfigForm;
@state() private _guiModeAvailable = true;
@@ -84,13 +85,13 @@ export class HuiSubElementEditor extends LitElement {
private _renderEditor() {
const type = this.config.type;
if (this.schema) {
if (this.form) {
return html`
<hui-form-element-editor
class="editor"
.hass=${this.hass}
.value=${this.config.elementConfig}
.schema=${this.schema}
.form=${this.form}
.context=${this.config.context}
@config-changed=${this._handleConfigChanged}
></hui-form-element-editor>

View File

@@ -9220,7 +9220,6 @@
"cover": "Cover",
"fill": "Fill"
},
"focus": "Focus",
"hold_action": "Hold behavior",
"hours_to_show": "Hours to show",
"days_to_show": "Days to show",
@@ -9296,6 +9295,8 @@
"name": "Map",
"geo_location_sources": "Geolocation sources",
"no_geo_location_sources": "No geolocation sources available",
"focus": "Focus",
"focus_helper": "Include this entity when calculating the autofit",
"appearance": "Appearance",
"theme_mode": "Theme mode",
"theme_modes": {