Fix localize key types related to form schemas (Group 3) (#13400)

* Fix key type errors for card editors (Round 4)

* Fix key type errors for remaining form schemas
This commit is contained in:
Steve Repsher 2022-08-17 23:57:26 -04:00 committed by GitHub
parent 12e57dfcae
commit d7b888f761
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 503 additions and 457 deletions

View File

@ -4,7 +4,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { createCloseHeading } from "../../../../src/components/ha-dialog"; import { createCloseHeading } from "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-form/ha-form"; import "../../../../src/components/ha-form/ha-form";
import { HaFormSchema } from "../../../../src/components/ha-form/types"; import type { SchemaUnion } from "../../../../src/components/ha-form/types";
import "../../../../src/components/ha-icon-button"; import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-settings-row"; import "../../../../src/components/ha-settings-row";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
@ -19,7 +19,7 @@ import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types"; import type { HomeAssistant } from "../../../../src/types";
import { RegistriesDialogParams } from "./show-dialog-registries"; import { RegistriesDialogParams } from "./show-dialog-registries";
const SCHEMA: HaFormSchema[] = [ const SCHEMA = [
{ {
name: "registry", name: "registry",
required: true, required: true,
@ -35,7 +35,7 @@ const SCHEMA: HaFormSchema[] = [
required: true, required: true,
selector: { text: { type: "password" } }, selector: { text: { type: "password" } },
}, },
]; ] as const;
@customElement("dialog-hassio-registries") @customElement("dialog-hassio-registries")
class HassioRegistriesDialog extends LitElement { class HassioRegistriesDialog extends LitElement {
@ -135,8 +135,8 @@ class HassioRegistriesDialog extends LitElement {
`; `;
} }
private _computeLabel = (schema: HaFormSchema) => private _computeLabel = (schema: SchemaUnion<typeof SCHEMA>) =>
this.supervisor.localize(`dialog.registries.${schema.name}`) || schema.name; this.supervisor.localize(`dialog.registries.${schema.name}`);
private _valueChanged(ev: CustomEvent) { private _valueChanged(ev: CustomEvent) {
this._input = ev.detail.value; this._input = ev.detail.value;

View File

@ -41,14 +41,14 @@ export class HaForm extends LitElement implements HaFormElement {
@property({ type: Boolean }) public disabled = false; @property({ type: Boolean }) public disabled = false;
@property() public computeError?: (schema: HaFormSchema, error) => string; @property() public computeError?: (schema: any, error) => string;
@property() public computeLabel?: ( @property() public computeLabel?: (
schema: any, schema: any,
data?: HaFormDataContainer data: HaFormDataContainer
) => string; ) => string;
@property() public computeHelper?: (schema: HaFormSchema) => string; @property() public computeHelper?: (schema: any) => string | undefined;
public focus() { public focus() {
const root = this.shadowRoot?.querySelector(".root"); const root = this.shadowRoot?.querySelector(".root");

View File

@ -15,13 +15,13 @@ import type { HomeAssistant } from "../../types";
import { brandsUrl, extractDomainFromBrandUrl } from "../../util/brands-url"; import { brandsUrl, extractDomainFromBrandUrl } from "../../util/brands-url";
import "../ha-alert"; import "../ha-alert";
import "../ha-form/ha-form"; import "../ha-form/ha-form";
import type { HaFormSchema } from "../ha-form/types"; import type { SchemaUnion } from "../ha-form/types";
import { showMediaBrowserDialog } from "../media-player/show-media-browser-dialog"; import { showMediaBrowserDialog } from "../media-player/show-media-browser-dialog";
const MANUAL_SCHEMA = [ const MANUAL_SCHEMA = [
{ name: "media_content_id", required: false, selector: { text: {} } }, { name: "media_content_id", required: false, selector: { text: {} } },
{ name: "media_content_type", required: false, selector: { text: {} } }, { name: "media_content_type", required: false, selector: { text: {} } },
]; ] as const;
@customElement("ha-selector-media") @customElement("ha-selector-media")
export class HaMediaSelector extends LitElement { export class HaMediaSelector extends LitElement {
@ -163,7 +163,9 @@ export class HaMediaSelector extends LitElement {
</ha-card>`}`; </ha-card>`}`;
} }
private _computeLabelCallback = (schema: HaFormSchema): string => private _computeLabelCallback = (
schema: SchemaUnion<typeof MANUAL_SCHEMA>
): string =>
this.hass.localize(`ui.components.selectors.media.${schema.name}`); this.hass.localize(`ui.components.selectors.media.${schema.name}`);
private _entityChanged(ev: CustomEvent) { private _entityChanged(ev: CustomEvent) {

View File

@ -8,7 +8,7 @@ import { BlueprintInput } from "./blueprint";
import { DeviceCondition, DeviceTrigger } from "./device_automation"; import { DeviceCondition, DeviceTrigger } from "./device_automation";
import { Action, MODES } from "./script"; import { Action, MODES } from "./script";
export const AUTOMATION_DEFAULT_MODE: ManualAutomationConfig["mode"] = "single"; export const AUTOMATION_DEFAULT_MODE: typeof MODES[number] = "single";
export interface AutomationEntity extends HassEntityBase { export interface AutomationEntity extends HassEntityBase {
attributes: HassEntityAttributeBase & { attributes: HassEntityAttributeBase & {

View File

@ -28,7 +28,12 @@ import {
import { BlueprintInput } from "./blueprint"; import { BlueprintInput } from "./blueprint";
export const MODES = ["single", "restart", "queued", "parallel"] as const; export const MODES = ["single", "restart", "queued", "parallel"] as const;
export const MODES_MAX = ["queued", "parallel"]; export const MODES_MAX = ["queued", "parallel"] as const;
export const isMaxMode = (
mode: typeof MODES[number]
): mode is typeof MODES_MAX[number] =>
MODES_MAX.includes(mode as typeof MODES_MAX[number]);
export const baseActionStruct = object({ export const baseActionStruct = object({
alias: optional(string()), alias: optional(string()),
@ -275,7 +280,7 @@ export const canRun = (state: ScriptEntity) => {
} }
if ( if (
state.state === "on" && state.state === "on" &&
MODES_MAX.includes(state.attributes.mode) && isMaxMode(state.attributes.mode) &&
state.attributes.current! < state.attributes.max! state.attributes.current! < state.attributes.max!
) { ) {
return true; return true;

View File

@ -14,7 +14,7 @@ import {
Trigger, Trigger,
triggerAutomationActions, triggerAutomationActions,
} from "../../../data/automation"; } from "../../../data/automation";
import { Action, MODES, MODES_MAX } from "../../../data/script"; import { Action, isMaxMode, MODES } from "../../../data/script";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types"; import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url"; import { documentationUrl } from "../../../util/documentation-url";
@ -27,13 +27,13 @@ import "./trigger/ha-automation-trigger";
export class HaManualAutomationEditor extends LitElement { export class HaManualAutomationEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property() public isWide!: boolean; @property({ type: Boolean }) public isWide!: boolean;
@property() public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@property() public config!: ManualAutomationConfig; @property({ attribute: false }) public config!: ManualAutomationConfig;
@property() public stateObj?: HassEntity; @property({ attribute: false }) public stateObj?: HassEntity;
@state() private _showDescription = false; @state() private _showDescription = false;
@ -114,7 +114,7 @@ export class HaManualAutomationEditor extends LitElement {
` `
)} )}
</ha-select> </ha-select>
${this.config.mode && MODES_MAX.includes(this.config.mode) ${this.config.mode && isMaxMode(this.config.mode)
? html` ? html`
<br /><ha-textfield <br /><ha-textfield
.label=${this.hass.localize( .label=${this.hass.localize(
@ -300,7 +300,7 @@ export class HaManualAutomationEditor extends LitElement {
mode, mode,
}; };
if (!MODES_MAX.includes(mode)) { if (!isMaxMode(mode)) {
delete value.max; delete value.max;
} }

View File

@ -6,7 +6,7 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import { slugify } from "../../../../common/string/slugify"; import { slugify } from "../../../../common/string/slugify";
import { createCloseHeading } from "../../../../components/ha-dialog"; import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-form/ha-form"; import "../../../../components/ha-form/ha-form";
import { HaFormSchema } from "../../../../components/ha-form/types"; import { SchemaUnion } from "../../../../components/ha-form/types";
import { CoreFrontendUserData } from "../../../../data/frontend"; import { CoreFrontendUserData } from "../../../../data/frontend";
import { import {
LovelaceDashboard, LovelaceDashboard,
@ -174,12 +174,15 @@ export class DialogLovelaceDashboardDetail extends LitElement {
icon: {}, icon: {},
}, },
}, },
!params.dashboard && ...(!params.dashboard && userData?.showAdvanced
userData?.showAdvanced && { ? ([
{
name: "url_path", name: "url_path",
required: true, required: true,
selector: { text: {} }, selector: { text: {} },
}, },
] as const)
: []),
{ {
name: "require_admin", name: "require_admin",
required: true, required: true,
@ -194,10 +197,12 @@ export class DialogLovelaceDashboardDetail extends LitElement {
boolean: {}, boolean: {},
}, },
}, },
].filter(Boolean) ] as const
); );
private _computeLabel = (entry: HaFormSchema): string => private _computeLabel = (
entry: SchemaUnion<ReturnType<typeof this._schema>>
): string =>
this.hass.localize( this.hass.localize(
`ui.panel.config.lovelace.dashboards.detail.${ `ui.panel.config.lovelace.dashboards.detail.${
entry.name === "show_in_sidebar" entry.name === "show_in_sidebar"

View File

@ -5,7 +5,7 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import { createCloseHeading } from "../../../../components/ha-dialog"; import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-form/ha-form"; import "../../../../components/ha-form/ha-form";
import { HaFormSchema } from "../../../../components/ha-form/types"; import { SchemaUnion } from "../../../../components/ha-form/types";
import { LovelaceResourcesMutableParams } from "../../../../data/lovelace"; import { LovelaceResourcesMutableParams } from "../../../../data/lovelace";
import { haStyleDialog } from "../../../../resources/styles"; import { haStyleDialog } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types"; import { HomeAssistant } from "../../../../types";
@ -132,7 +132,9 @@ export class DialogLovelaceResourceDetail extends LitElement {
`; `;
} }
private _schema = memoizeOne((data) => [ private _schema = memoizeOne(
(data) =>
[
{ {
name: "url", name: "url",
required: true, required: true,
@ -158,27 +160,40 @@ export class DialogLovelaceResourceDetail extends LitElement {
"ui.panel.config.lovelace.resources.types.css" "ui.panel.config.lovelace.resources.types.css"
), ),
}, },
data.type === "js" && { ...(data.type === "js"
? ([
{
value: "js", value: "js",
label: this.hass!.localize( label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.js" "ui.panel.config.lovelace.resources.types.js"
), ),
}, },
data.type === "html" && { ] as const)
: []),
...(data.type === "html"
? ([
{
value: "html", value: "html",
label: this.hass!.localize( label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.html" "ui.panel.config.lovelace.resources.types.html"
), ),
}, },
].filter(Boolean), ] as const)
: []),
],
}, },
}, },
}, },
]); ] as const
);
private _computeLabel = (entry: HaFormSchema): string => private _computeLabel = (
entry: SchemaUnion<ReturnType<typeof this._schema>>
): string =>
this.hass.localize( this.hass.localize(
`ui.panel.config.lovelace.resources.detail.${entry.name}` `ui.panel.config.lovelace.resources.detail.${
entry.name === "res_type" ? "type" : entry.name
}`
); );
private _valueChanged(ev: CustomEvent) { private _valueChanged(ev: CustomEvent) {

View File

@ -30,8 +30,7 @@ import "../../../components/ha-card";
import "../../../components/ha-fab"; import "../../../components/ha-fab";
import type { import type {
HaFormDataContainer, HaFormDataContainer,
HaFormSchema, SchemaUnion,
HaFormSelector,
} from "../../../components/ha-form/types"; } from "../../../components/ha-form/types";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
@ -41,6 +40,7 @@ import {
Action, Action,
deleteScript, deleteScript,
getScriptEditorInitData, getScriptEditorInitData,
isMaxMode,
ManualScriptConfig, ManualScriptConfig,
MODES, MODES,
MODES_MAX, MODES_MAX,
@ -65,11 +65,11 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@property() public scriptEntityId: string | null = null; @property() public scriptEntityId: string | null = null;
@property() public route!: Route; @property({ attribute: false }) public route!: Route;
@property() public isWide?: boolean; @property({ type: Boolean }) public isWide = false;
@property() public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@state() private _config?: ScriptConfig; @state() private _config?: ScriptConfig;
@ -86,8 +86,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@query("ha-yaml-editor", true) private _editor?: HaYamlEditor; @query("ha-yaml-editor", true) private _editor?: HaYamlEditor;
private _schema = memoizeOne( private _schema = memoizeOne(
(hasID: boolean, useBluePrint?: boolean, currentMode?: string) => { (
const schema: HaFormSchema[] = [ hasID: boolean,
useBluePrint?: boolean,
currentMode?: typeof MODES[number]
) =>
[
{ {
name: "alias", name: "alias",
selector: { selector: {
@ -102,49 +106,45 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
icon: {}, icon: {},
}, },
}, },
]; ...(!hasID
? ([
if (!hasID) { {
schema.push({
name: "id", name: "id",
selector: { selector: {
text: {}, text: {},
}, },
}); },
} ] as const)
: []),
if (!useBluePrint) { ...(!useBluePrint
schema.push({ ? ([
{
name: "mode", name: "mode",
selector: { selector: {
select: { select: {
options: MODES.map((mode) => ({ options: MODES.map((mode) => ({
label: ` label: this.hass.localize(
${
this.hass.localize(
`ui.panel.config.script.editor.modes.${mode}` `ui.panel.config.script.editor.modes.${mode}`
) || mode ),
}
`,
value: mode, value: mode,
})), })),
}, },
}, },
}); },
} ] as const)
: []),
if (currentMode && MODES_MAX.includes(currentMode)) { ...(currentMode && isMaxMode(currentMode)
schema.push({ ? ([
{
name: "max", name: "max",
required: true, required: true,
selector: { selector: {
number: { mode: "box", min: 1, max: Infinity }, number: { mode: "box", min: 1, max: Infinity },
}, },
}); },
} ] as const)
: []),
return schema; ] as const
}
); );
protected render(): TemplateResult { protected render(): TemplateResult {
@ -161,10 +161,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
const data = { const data = {
mode: MODES[0], mode: MODES[0],
icon: undefined, icon: undefined,
max: max: this._config.mode && isMaxMode(this._config.mode) ? 10 : undefined,
this._config.mode && MODES_MAX.includes(this._config.mode)
? 10
: undefined,
...this._config, ...this._config,
id: this._entityId, id: this._entityId,
}; };
@ -506,15 +503,18 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
} }
private _computeLabelCallback = ( private _computeLabelCallback = (
schema: HaFormSelector, schema: SchemaUnion<ReturnType<typeof this._schema>>,
data: HaFormDataContainer data: HaFormDataContainer
): string => { ): string => {
switch (schema.name) { switch (schema.name) {
case "mode": case "mode":
return this.hass.localize("ui.panel.config.script.editor.modes.label"); return this.hass.localize("ui.panel.config.script.editor.modes.label");
case "max": case "max":
// Mode must be one of max modes per schema definition above
return this.hass.localize( return this.hass.localize(
`ui.panel.config.script.editor.max.${data.mode}` `ui.panel.config.script.editor.max.${
data.mode as typeof MODES_MAX[number]
}`
); );
default: default:
return this.hass.localize( return this.hass.localize(
@ -524,7 +524,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}; };
private _computeHelperCallback = ( private _computeHelperCallback = (
schema: HaFormSelector schema: SchemaUnion<ReturnType<typeof this._schema>>
): string | undefined => { ): string | undefined => {
if (schema.name === "mode") { if (schema.name === "mode") {
return this.hass.localize( return this.hass.localize(
@ -562,7 +562,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
private _modeChanged(mode) { private _modeChanged(mode) {
this._config = { ...this._config!, mode }; this._config = { ...this._config!, mode };
if (!MODES_MAX.includes(mode)) { if (!isMaxMode(mode)) {
delete this._config.max; delete this._config.max;
} }
this._dirty = true; this._dirty = true;

View File

@ -6,7 +6,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
import { addDistanceToCoord } from "../../../common/location/add_distance_to_coord"; import { addDistanceToCoord } from "../../../common/location/add_distance_to_coord";
import { createCloseHeading } from "../../../components/ha-dialog"; import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-form/ha-form"; import "../../../components/ha-form/ha-form";
import { HaFormSchema } from "../../../components/ha-form/types"; import { SchemaUnion } from "../../../components/ha-form/types";
import { getZoneEditorInitData, ZoneMutableParams } from "../../../data/zone"; import { getZoneEditorInitData, ZoneMutableParams } from "../../../data/zone";
import { haStyleDialog } from "../../../resources/styles"; import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
@ -123,7 +123,9 @@ class DialogZoneDetail extends LitElement {
`; `;
} }
private _schema = memoizeOne((icon?: string): HaFormSchema[] => [ private _schema = memoizeOne(
(icon?: string) =>
[
{ {
name: "name", name: "name",
required: true, required: true,
@ -167,7 +169,8 @@ class DialogZoneDetail extends LitElement {
required: false, required: false,
selector: { number: { min: 0, max: 999999, mode: "box" } }, selector: { number: { min: 0, max: 999999, mode: "box" } },
}, },
]); ] as const
);
private _formData = memoizeOne((data: ZoneMutableParams) => ({ private _formData = memoizeOne((data: ZoneMutableParams) => ({
...data, ...data,
@ -197,8 +200,9 @@ class DialogZoneDetail extends LitElement {
this._data = value; this._data = value;
} }
private _computeLabel = (entry: HaFormSchema): string => private _computeLabel = (
this.hass.localize(`ui.panel.config.zone.detail.${entry.name}`); entry: SchemaUnion<ReturnType<typeof this._schema>>
): string => this.hass.localize(`ui.panel.config.zone.detail.${entry.name}`);
private async _updateEntry() { private async _updateEntry() {
this._submitting = true; this._submitting = true;

View File

@ -8,13 +8,13 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import { computeDomain } from "../../../../common/entity/compute_domain"; import { computeDomain } from "../../../../common/entity/compute_domain";
import { domainIcon } from "../../../../common/entity/domain_icon"; import { domainIcon } from "../../../../common/entity/domain_icon";
import type { LocalizeFunc } from "../../../../common/translations/localize"; import type { LocalizeFunc } from "../../../../common/translations/localize";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import type { EntitiesCardEntityConfig } from "../../cards/types"; import type { EntitiesCardEntityConfig } from "../../cards/types";
import type { LovelaceRowEditor } from "../../types"; import type { LovelaceRowEditor } from "../../types";
import { entitiesConfigStruct } from "../structs/entities-struct"; import { entitiesConfigStruct } from "../structs/entities-struct";
const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = { const SecondaryInfoValues = {
none: {}, none: {},
"entity-id": {}, "entity-id": {},
"last-changed": {}, "last-changed": {},
@ -23,7 +23,7 @@ const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = {
position: { domains: ["cover"] }, position: { domains: ["cover"] },
"tilt-position": { domains: ["cover"] }, "tilt-position": { domains: ["cover"] },
brightness: { domains: ["light"] }, brightness: { domains: ["light"] },
}; } as const;
@customElement("hui-generic-entity-row-editor") @customElement("hui-generic-entity-row-editor")
export class HuiGenericEntityRowEditor export class HuiGenericEntityRowEditor
@ -45,7 +45,7 @@ export class HuiGenericEntityRowEditor
icon: string | undefined, icon: string | undefined,
entityState: HassEntity, entityState: HassEntity,
localize: LocalizeFunc localize: LocalizeFunc
): HaFormSchema[] => { ) => {
const domain = computeDomain(entity); const domain = computeDomain(entity);
return [ return [
@ -73,14 +73,14 @@ export class HuiGenericEntityRowEditor
name: "secondary_info", name: "secondary_info",
selector: { selector: {
select: { select: {
options: Object.keys(SecondaryInfoValues) options: (
.filter( Object.keys(SecondaryInfoValues).filter(
(info) => (info) =>
!("domains" in SecondaryInfoValues[info]) || !("domains" in SecondaryInfoValues[info]) ||
("domains" in SecondaryInfoValues[info] && ("domains" in SecondaryInfoValues[info] &&
SecondaryInfoValues[info].domains!.includes(domain)) SecondaryInfoValues[info].domains!.includes(domain))
) ) as Array<keyof typeof SecondaryInfoValues>
.map((info) => ({ ).map((info) => ({
value: info, value: info,
label: localize( label: localize(
`ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}` `ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}`
@ -89,7 +89,7 @@ export class HuiGenericEntityRowEditor
}, },
}, },
}, },
]; ] as const;
} }
); );
@ -122,21 +122,19 @@ export class HuiGenericEntityRowEditor
fireEvent(this, "config-changed", { config: ev.detail.value }); fireEvent(this, "config-changed", { config: ev.detail.value });
} }
private _computeLabelCallback = (schema: HaFormSchema) => { private _computeLabelCallback = (
if (schema.name === "entity") { schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "secondary_info":
return this.hass!.localize( return this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.entity" `ui.panel.lovelace.editor.card.entity-row.${schema.name}`
);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
); );
} }
return (
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(
`ui.panel.lovelace.editor.card.entity-row.${schema.name}`
)
);
}; };
} }

View File

@ -12,7 +12,7 @@ import {
} from "superstruct"; } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-entities-picker"; import "../../../../components/entity/ha-entities-picker";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import type { LogbookCardConfig } from "../../cards/types"; import type { LogbookCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types"; import type { LovelaceCardEditor } from "../../types";
@ -29,7 +29,7 @@ const cardConfigStruct = assign(
}) })
); );
const SCHEMA: HaFormSchema[] = [ const SCHEMA = [
{ name: "title", selector: { text: {} } }, { name: "title", selector: { text: {} } },
{ {
name: "", name: "",
@ -39,7 +39,7 @@ const SCHEMA: HaFormSchema[] = [
{ name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } }, { name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } },
], ],
}, },
]; ] as const;
@customElement("hui-logbook-card-editor") @customElement("hui-logbook-card-editor")
export class HuiLogbookCardEditor export class HuiLogbookCardEditor
@ -98,23 +98,19 @@ export class HuiLogbookCardEditor
fireEvent(this, "config-changed", { config: ev.detail.value }); fireEvent(this, "config-changed", { config: ev.detail.value });
} }
private _computeLabelCallback = (schema: HaFormSchema) => { private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
if (schema.name === "theme") { switch (schema.name) {
case "theme":
return `${this.hass!.localize( return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme" "ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize( )} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional" "ui.panel.lovelace.editor.card.config.optional"
)})`; )})`;
} default:
return this.hass!.localize(
return (
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}` `ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(
`ui.panel.lovelace.editor.card.logbook.${schema.name}`
)
); );
}
}; };
} }

View File

@ -26,7 +26,7 @@ import { entitiesConfigStruct } from "../structs/entities-struct";
import { EntitiesEditorEvent } from "../types"; import { EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style"; import { configElementStyle } from "./config-elements-style";
import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { HaFormSchema } from "../../../../components/ha-form/types"; import { SchemaUnion } from "../../../../components/ha-form/types";
const cardConfigStruct = assign( const cardConfigStruct = assign(
baseLovelaceCardConfig, baseLovelaceCardConfig,
@ -41,7 +41,7 @@ const cardConfigStruct = assign(
}) })
); );
const SCHEMA: HaFormSchema[] = [ const SCHEMA = [
{ name: "title", selector: { text: {} } }, { name: "title", selector: { text: {} } },
{ {
name: "", name: "",
@ -53,7 +53,7 @@ const SCHEMA: HaFormSchema[] = [
{ name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } }, { name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } },
], ],
}, },
]; ] as const;
@customElement("hui-map-card-editor") @customElement("hui-map-card-editor")
export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor { export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
@ -149,11 +149,19 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
fireEvent(this, "config-changed", { config: ev.detail.value }); fireEvent(this, "config-changed", { config: ev.detail.value });
} }
private _computeLabelCallback = (schema: HaFormSchema) => private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
this.hass!.localize( switch (schema.name) {
case "dark_mode":
case "default_zoom":
return this.hass!.localize(
`ui.panel.lovelace.editor.card.map.${schema.name}`
);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}` `ui.panel.lovelace.editor.card.generic.${schema.name}`
) || );
this.hass!.localize(`ui.panel.lovelace.editor.card.map.${schema.name}`); }
};
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return [ return [

View File

@ -16,7 +16,7 @@ import {
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import { computeDomain } from "../../../../common/entity/compute_domain"; import { computeDomain } from "../../../../common/entity/compute_domain";
import { domainIcon } from "../../../../common/entity/domain_icon"; import { domainIcon } from "../../../../common/entity/domain_icon";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import type { SensorCardConfig } from "../../cards/types"; import type { SensorCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types"; import type { LovelaceCardEditor } from "../../types";
@ -52,11 +52,8 @@ export class HuiSensorCardEditor
} }
private _schema = memoizeOne( private _schema = memoizeOne(
( (entity: string, icon: string | undefined, entityState: HassEntity) =>
entity: string, [
icon: string | undefined,
entityState: HassEntity
): HaFormSchema[] => [
{ {
name: "entity", name: "entity",
selector: { selector: {
@ -106,7 +103,7 @@ export class HuiSensorCardEditor
}, },
], ],
}, },
] ] as const
); );
protected render(): TemplateResult { protected render(): TemplateResult {
@ -146,33 +143,29 @@ export class HuiSensorCardEditor
fireEvent(this, "config-changed", { config }); fireEvent(this, "config-changed", { config });
} }
private _computeLabelCallback = (schema: HaFormSchema) => { private _computeLabelCallback = (
if (schema.name === "entity") { schema: SchemaUnion<ReturnType<typeof this._schema>>
return this.hass!.localize( ) => {
"ui.panel.lovelace.editor.card.generic.entity" switch (schema.name) {
); case "theme":
}
if (schema.name === "theme") {
return `${this.hass!.localize( return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme" "ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize( )} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional" "ui.panel.lovelace.editor.card.config.optional"
)})`; )})`;
} case "detail":
if (schema.name === "detail") {
return this.hass!.localize( return this.hass!.localize(
"ui.panel.lovelace.editor.card.sensor.show_more_detail" "ui.panel.lovelace.editor.card.sensor.show_more_detail"
); );
} case "graph":
return this.hass!.localize(
return ( "ui.panel.lovelace.editor.card.sensor.graph_type"
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(`ui.panel.lovelace.editor.card.sensor.${schema.name}`)
); );
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
}
}; };
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {

View File

@ -16,7 +16,7 @@ import {
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeFunc } from "../../../../common/translations/localize"; import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/entity/ha-statistics-picker"; import "../../../../components/entity/ha-statistics-picker";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import type { StatisticsGraphCardConfig } from "../../cards/types"; import type { StatisticsGraphCardConfig } from "../../cards/types";
import { processConfigEntities } from "../../common/process-config-entities"; import { processConfigEntities } from "../../common/process-config-entities";
@ -50,7 +50,7 @@ const cardConfigStruct = assign(
}) })
); );
const periods = ["5minute", "hour", "day", "month"]; const periods = ["5minute", "hour", "day", "month"] as const;
@customElement("hui-statistics-graph-card-editor") @customElement("hui-statistics-graph-card-editor")
export class HuiStatisticsGraphCardEditor export class HuiStatisticsGraphCardEditor
@ -71,7 +71,9 @@ export class HuiStatisticsGraphCardEditor
: []; : [];
} }
private _schema = memoizeOne((localize: LocalizeFunc) => [ private _schema = memoizeOne(
(localize: LocalizeFunc) =>
[
{ name: "title", selector: { text: {} } }, { name: "title", selector: { text: {} } },
{ {
name: "", name: "",
@ -118,7 +120,8 @@ export class HuiStatisticsGraphCardEditor
}, },
], ],
}, },
]); ] as const
);
protected render(): TemplateResult { protected render(): TemplateResult {
if (!this.hass || !this._config) { if (!this.hass || !this._config) {
@ -169,13 +172,22 @@ export class HuiStatisticsGraphCardEditor
}); });
} }
private _computeLabelCallback = (schema: HaFormSchema) => private _computeLabelCallback = (
this.hass!.localize( schema: SchemaUnion<ReturnType<typeof this._schema>>
`ui.panel.lovelace.editor.card.generic.${schema.name}` ) => {
) || switch (schema.name) {
this.hass!.localize( case "chart_type":
case "stat_types":
case "period":
return this.hass!.localize(
`ui.panel.lovelace.editor.card.statistics-graph.${schema.name}` `ui.panel.lovelace.editor.card.statistics-graph.${schema.name}`
); );
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
}
};
static styles: CSSResultGroup = css` static styles: CSSResultGroup = css`
ha-statistics-picker { ha-statistics-picker {

View File

@ -12,7 +12,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { UNAVAILABLE } from "../../../../data/entity"; import { UNAVAILABLE } from "../../../../data/entity";
import type { WeatherEntity } from "../../../../data/weather"; import type { WeatherEntity } from "../../../../data/weather";
import type { LocalizeFunc } from "../../../../common/translations/localize"; import type { LocalizeFunc } from "../../../../common/translations/localize";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { SchemaUnion } from "../../../../components/ha-form/types";
const cardConfigStruct = assign( const cardConfigStruct = assign(
baseLovelaceCardConfig, baseLovelaceCardConfig,
@ -66,12 +66,8 @@ export class HuiWeatherForecastCardEditor
} }
private _schema = memoize( private _schema = memoize(
( (entity: string, localize: LocalizeFunc, hasForecast?: boolean) =>
entity: string, [
localize: LocalizeFunc,
hasForecast?: boolean
): HaFormSchema[] => {
const schema: HaFormSchema[] = [
{ {
name: "entity", name: "entity",
required: true, required: true,
@ -89,9 +85,9 @@ export class HuiWeatherForecastCardEditor
{ name: "theme", selector: { theme: {} } }, { name: "theme", selector: { theme: {} } },
], ],
}, },
]; ...(hasForecast
if (hasForecast) { ? ([
schema.push({ {
name: "forecast", name: "forecast",
selector: { selector: {
select: { select: {
@ -117,10 +113,10 @@ export class HuiWeatherForecastCardEditor
], ],
}, },
}, },
}); },
} ] as const)
return schema; : []),
} ] as const
); );
protected render(): TemplateResult { protected render(): TemplateResult {
@ -175,31 +171,31 @@ export class HuiWeatherForecastCardEditor
fireEvent(this, "config-changed", { config }); fireEvent(this, "config-changed", { config });
} }
private _computeLabelCallback = (schema: HaFormSchema) => { private _computeLabelCallback = (
if (schema.name === "entity") { schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "entity":
return `${this.hass!.localize( return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.entity" "ui.panel.lovelace.editor.card.generic.entity"
)} (${this.hass!.localize( )} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.required" "ui.panel.lovelace.editor.card.config.required"
)})`; )})`;
} case "theme":
if (schema.name === "theme") {
return `${this.hass!.localize( return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme" "ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize( )} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional" "ui.panel.lovelace.editor.card.config.optional"
)})`; )})`;
} case "forecast":
return this.hass!.localize(
return ( "ui.panel.lovelace.editor.card.weather-forecast.weather_to_show"
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(
`ui.panel.lovelace.editor.card.weather_forecast.${schema.name}`
)
); );
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
}
}; };
} }

View File

@ -4,7 +4,8 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import { slugify } from "../../../../common/string/slugify"; import { slugify } from "../../../../common/string/slugify";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { LocalizeFunc } from "../../../../common/translations/localize";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { LovelaceViewConfig } from "../../../../data/lovelace"; import type { LovelaceViewConfig } from "../../../../data/lovelace";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import { import {
@ -25,13 +26,15 @@ declare global {
export class HuiViewEditor extends LitElement { export class HuiViewEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property() public isNew!: boolean; @property({ type: Boolean }) public isNew!: boolean;
@state() private _config!: LovelaceViewConfig; @state() private _config!: LovelaceViewConfig;
private _suggestedPath = false; private _suggestedPath = false;
private _schema = memoizeOne((localize): HaFormSchema[] => [ private _schema = memoizeOne(
(localize: LocalizeFunc) =>
[
{ name: "title", selector: { text: {} } }, { name: "title", selector: { text: {} } },
{ {
name: "icon", name: "icon",
@ -51,12 +54,15 @@ export class HuiViewEditor extends LitElement {
PANEL_VIEW_LAYOUT, PANEL_VIEW_LAYOUT,
].map((type) => ({ ].map((type) => ({
value: type, value: type,
label: localize(`ui.panel.lovelace.editor.edit_view.types.${type}`), label: localize(
`ui.panel.lovelace.editor.edit_view.types.${type}`
),
})), })),
}, },
}, },
}, },
]); ] as const
);
set config(config: LovelaceViewConfig) { set config(config: LovelaceViewConfig) {
this._config = config; this._config = config;
@ -114,15 +120,19 @@ export class HuiViewEditor extends LitElement {
fireEvent(this, "view-config-changed", { config }); fireEvent(this, "view-config-changed", { config });
} }
private _computeLabelCallback = (schema: HaFormSchema) => { private _computeLabelCallback = (
if (schema.name === "path") { schema: SchemaUnion<ReturnType<typeof this._schema>>
return this.hass!.localize(`ui.panel.lovelace.editor.card.generic.url`); ) => {
} switch (schema.name) {
return ( case "path":
this.hass!.localize( return this.hass!.localize("ui.panel.lovelace.editor.card.generic.url");
case "type":
return this.hass.localize("ui.panel.lovelace.editor.edit_view.type");
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}` `ui.panel.lovelace.editor.card.generic.${schema.name}`
) || this.hass.localize("ui.panel.lovelace.editor.edit_view.type")
); );
}
}; };
} }

View File

@ -2274,6 +2274,7 @@
"parallel": "Max number of parallel runs" "parallel": "Max number of parallel runs"
}, },
"load_error_not_editable": "Only scripts inside scripts.yaml are editable.", "load_error_not_editable": "Only scripts inside scripts.yaml are editable.",
"load_error_unknown": "Error loading script ({err_no}).",
"delete_confirm": "Are you sure you want to delete this script?", "delete_confirm": "Are you sure you want to delete this script?",
"delete_script": "Delete script", "delete_script": "Delete script",
"save_script": "Save script", "save_script": "Save script",
@ -2756,6 +2757,7 @@
"name": "Name", "name": "Name",
"icon": "Icon", "icon": "Icon",
"icon_error_msg": "Icon should be in the format ''prefix:iconname'', for example: ''mdi:home''", "icon_error_msg": "Icon should be in the format ''prefix:iconname'', for example: ''mdi:home''",
"location": "Map Location",
"radius": "Radius", "radius": "Radius",
"latitude": "Latitude", "latitude": "Latitude",
"longitude": "Longitude", "longitude": "Longitude",
@ -3936,7 +3938,6 @@
"geo_location_sources": "Geolocation Sources", "geo_location_sources": "Geolocation Sources",
"dark_mode": "Dark Mode?", "dark_mode": "Dark Mode?",
"default_zoom": "Default Zoom", "default_zoom": "Default Zoom",
"hours_to_show": "Hours to Show",
"source": "Source", "source": "Source",
"description": "The Map card that allows you to display entities on a map." "description": "The Map card that allows you to display entities on a map."
}, },
@ -3992,6 +3993,7 @@
"weather-forecast": { "weather-forecast": {
"name": "Weather Forecast", "name": "Weather Forecast",
"description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.", "description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.",
"weather_to_show": "Weather to Show",
"show_both": "Show current Weather and Forecast", "show_both": "Show current Weather and Forecast",
"show_only_current": "Show only current Weather", "show_only_current": "Show only current Weather",
"show_only_forecast": "Show only Forecast" "show_only_forecast": "Show only Forecast"