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 { createCloseHeading } from "../../../../src/components/ha-dialog";
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-settings-row";
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 { RegistriesDialogParams } from "./show-dialog-registries";
const SCHEMA: HaFormSchema[] = [
const SCHEMA = [
{
name: "registry",
required: true,
@ -35,7 +35,7 @@ const SCHEMA: HaFormSchema[] = [
required: true,
selector: { text: { type: "password" } },
},
];
] as const;
@customElement("dialog-hassio-registries")
class HassioRegistriesDialog extends LitElement {
@ -135,8 +135,8 @@ class HassioRegistriesDialog extends LitElement {
`;
}
private _computeLabel = (schema: HaFormSchema) =>
this.supervisor.localize(`dialog.registries.${schema.name}`) || schema.name;
private _computeLabel = (schema: SchemaUnion<typeof SCHEMA>) =>
this.supervisor.localize(`dialog.registries.${schema.name}`);
private _valueChanged(ev: CustomEvent) {
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() public computeError?: (schema: HaFormSchema, error) => string;
@property() public computeError?: (schema: any, error) => string;
@property() public computeLabel?: (
schema: any,
data?: HaFormDataContainer
data: HaFormDataContainer
) => string;
@property() public computeHelper?: (schema: HaFormSchema) => string;
@property() public computeHelper?: (schema: any) => string | undefined;
public focus() {
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 "../ha-alert";
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";
const MANUAL_SCHEMA = [
{ name: "media_content_id", required: false, selector: { text: {} } },
{ name: "media_content_type", required: false, selector: { text: {} } },
];
] as const;
@customElement("ha-selector-media")
export class HaMediaSelector extends LitElement {
@ -163,7 +163,9 @@ export class HaMediaSelector extends LitElement {
</ha-card>`}`;
}
private _computeLabelCallback = (schema: HaFormSchema): string =>
private _computeLabelCallback = (
schema: SchemaUnion<typeof MANUAL_SCHEMA>
): string =>
this.hass.localize(`ui.components.selectors.media.${schema.name}`);
private _entityChanged(ev: CustomEvent) {

View File

@ -8,7 +8,7 @@ import { BlueprintInput } from "./blueprint";
import { DeviceCondition, DeviceTrigger } from "./device_automation";
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 {
attributes: HassEntityAttributeBase & {

View File

@ -28,7 +28,12 @@ import {
import { BlueprintInput } from "./blueprint";
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({
alias: optional(string()),
@ -275,7 +280,7 @@ export const canRun = (state: ScriptEntity) => {
}
if (
state.state === "on" &&
MODES_MAX.includes(state.attributes.mode) &&
isMaxMode(state.attributes.mode) &&
state.attributes.current! < state.attributes.max!
) {
return true;

View File

@ -14,7 +14,7 @@ import {
Trigger,
triggerAutomationActions,
} from "../../../data/automation";
import { Action, MODES, MODES_MAX } from "../../../data/script";
import { Action, isMaxMode, MODES } from "../../../data/script";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
@ -27,13 +27,13 @@ import "./trigger/ha-automation-trigger";
export class HaManualAutomationEditor extends LitElement {
@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;
@ -114,7 +114,7 @@ export class HaManualAutomationEditor extends LitElement {
`
)}
</ha-select>
${this.config.mode && MODES_MAX.includes(this.config.mode)
${this.config.mode && isMaxMode(this.config.mode)
? html`
<br /><ha-textfield
.label=${this.hass.localize(
@ -300,7 +300,7 @@ export class HaManualAutomationEditor extends LitElement {
mode,
};
if (!MODES_MAX.includes(mode)) {
if (!isMaxMode(mode)) {
delete value.max;
}

View File

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

View File

@ -5,7 +5,7 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
import { createCloseHeading } from "../../../../components/ha-dialog";
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 { haStyleDialog } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
@ -132,53 +132,68 @@ export class DialogLovelaceResourceDetail extends LitElement {
`;
}
private _schema = memoizeOne((data) => [
{
name: "url",
required: true,
selector: {
text: {},
},
},
{
name: "res_type",
required: true,
selector: {
select: {
options: [
{
value: "module",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.module"
),
},
{
value: "css",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.css"
),
},
data.type === "js" && {
value: "js",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.js"
),
},
data.type === "html" && {
value: "html",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.html"
),
},
].filter(Boolean),
private _schema = memoizeOne(
(data) =>
[
{
name: "url",
required: true,
selector: {
text: {},
},
},
},
},
]);
{
name: "res_type",
required: true,
selector: {
select: {
options: [
{
value: "module",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.module"
),
},
{
value: "css",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.css"
),
},
...(data.type === "js"
? ([
{
value: "js",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.js"
),
},
] as const)
: []),
...(data.type === "html"
? ([
{
value: "html",
label: this.hass!.localize(
"ui.panel.config.lovelace.resources.types.html"
),
},
] as const)
: []),
],
},
},
},
] as const
);
private _computeLabel = (entry: HaFormSchema): string =>
private _computeLabel = (
entry: SchemaUnion<ReturnType<typeof this._schema>>
): string =>
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) {

View File

@ -30,8 +30,7 @@ import "../../../components/ha-card";
import "../../../components/ha-fab";
import type {
HaFormDataContainer,
HaFormSchema,
HaFormSelector,
SchemaUnion,
} from "../../../components/ha-form/types";
import "../../../components/ha-icon-button";
import "../../../components/ha-svg-icon";
@ -41,6 +40,7 @@ import {
Action,
deleteScript,
getScriptEditorInitData,
isMaxMode,
ManualScriptConfig,
MODES,
MODES_MAX,
@ -65,11 +65,11 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@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;
@ -86,8 +86,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@query("ha-yaml-editor", true) private _editor?: HaYamlEditor;
private _schema = memoizeOne(
(hasID: boolean, useBluePrint?: boolean, currentMode?: string) => {
const schema: HaFormSchema[] = [
(
hasID: boolean,
useBluePrint?: boolean,
currentMode?: typeof MODES[number]
) =>
[
{
name: "alias",
selector: {
@ -102,49 +106,45 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
icon: {},
},
},
];
if (!hasID) {
schema.push({
name: "id",
selector: {
text: {},
},
});
}
if (!useBluePrint) {
schema.push({
name: "mode",
selector: {
select: {
options: MODES.map((mode) => ({
label: `
${
this.hass.localize(
`ui.panel.config.script.editor.modes.${mode}`
) || mode
}
`,
value: mode,
})),
},
},
});
}
if (currentMode && MODES_MAX.includes(currentMode)) {
schema.push({
name: "max",
required: true,
selector: {
number: { mode: "box", min: 1, max: Infinity },
},
});
}
return schema;
}
...(!hasID
? ([
{
name: "id",
selector: {
text: {},
},
},
] as const)
: []),
...(!useBluePrint
? ([
{
name: "mode",
selector: {
select: {
options: MODES.map((mode) => ({
label: this.hass.localize(
`ui.panel.config.script.editor.modes.${mode}`
),
value: mode,
})),
},
},
},
] as const)
: []),
...(currentMode && isMaxMode(currentMode)
? ([
{
name: "max",
required: true,
selector: {
number: { mode: "box", min: 1, max: Infinity },
},
},
] as const)
: []),
] as const
);
protected render(): TemplateResult {
@ -161,10 +161,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
const data = {
mode: MODES[0],
icon: undefined,
max:
this._config.mode && MODES_MAX.includes(this._config.mode)
? 10
: undefined,
max: this._config.mode && isMaxMode(this._config.mode) ? 10 : undefined,
...this._config,
id: this._entityId,
};
@ -506,15 +503,18 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}
private _computeLabelCallback = (
schema: HaFormSelector,
schema: SchemaUnion<ReturnType<typeof this._schema>>,
data: HaFormDataContainer
): string => {
switch (schema.name) {
case "mode":
return this.hass.localize("ui.panel.config.script.editor.modes.label");
case "max":
// Mode must be one of max modes per schema definition above
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:
return this.hass.localize(
@ -524,7 +524,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
};
private _computeHelperCallback = (
schema: HaFormSelector
schema: SchemaUnion<ReturnType<typeof this._schema>>
): string | undefined => {
if (schema.name === "mode") {
return this.hass.localize(
@ -562,7 +562,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
private _modeChanged(mode) {
this._config = { ...this._config!, mode };
if (!MODES_MAX.includes(mode)) {
if (!isMaxMode(mode)) {
delete this._config.max;
}
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 { createCloseHeading } from "../../../components/ha-dialog";
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 { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
@ -123,51 +123,54 @@ class DialogZoneDetail extends LitElement {
`;
}
private _schema = memoizeOne((icon?: string): HaFormSchema[] => [
{
name: "name",
required: true,
selector: {
text: {},
},
},
{
name: "icon",
required: false,
selector: {
icon: {},
},
},
{
name: "location",
required: true,
selector: { location: { radius: true, icon } },
},
{
name: "",
type: "grid",
schema: [
private _schema = memoizeOne(
(icon?: string) =>
[
{
name: "latitude",
name: "name",
required: true,
selector: { text: {} },
selector: {
text: {},
},
},
{
name: "longitude",
name: "icon",
required: false,
selector: {
icon: {},
},
},
{
name: "location",
required: true,
selector: { location: { radius: true, icon } },
},
{
name: "",
type: "grid",
schema: [
{
name: "latitude",
required: true,
selector: { text: {} },
},
{
name: "longitude",
required: true,
selector: { text: {} },
selector: { text: {} },
},
],
},
],
},
{ name: "passive_note", type: "constant" },
{ name: "passive", selector: { boolean: {} } },
{
name: "radius",
required: false,
selector: { number: { min: 0, max: 999999, mode: "box" } },
},
]);
{ name: "passive_note", type: "constant" },
{ name: "passive", selector: { boolean: {} } },
{
name: "radius",
required: false,
selector: { number: { min: 0, max: 999999, mode: "box" } },
},
] as const
);
private _formData = memoizeOne((data: ZoneMutableParams) => ({
...data,
@ -197,8 +200,9 @@ class DialogZoneDetail extends LitElement {
this._data = value;
}
private _computeLabel = (entry: HaFormSchema): string =>
this.hass.localize(`ui.panel.config.zone.detail.${entry.name}`);
private _computeLabel = (
entry: SchemaUnion<ReturnType<typeof this._schema>>
): string => this.hass.localize(`ui.panel.config.zone.detail.${entry.name}`);
private async _updateEntry() {
this._submitting = true;

View File

@ -8,13 +8,13 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import { computeDomain } from "../../../../common/entity/compute_domain";
import { domainIcon } from "../../../../common/entity/domain_icon";
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 { EntitiesCardEntityConfig } from "../../cards/types";
import type { LovelaceRowEditor } from "../../types";
import { entitiesConfigStruct } from "../structs/entities-struct";
const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = {
const SecondaryInfoValues = {
none: {},
"entity-id": {},
"last-changed": {},
@ -23,7 +23,7 @@ const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = {
position: { domains: ["cover"] },
"tilt-position": { domains: ["cover"] },
brightness: { domains: ["light"] },
};
} as const;
@customElement("hui-generic-entity-row-editor")
export class HuiGenericEntityRowEditor
@ -45,7 +45,7 @@ export class HuiGenericEntityRowEditor
icon: string | undefined,
entityState: HassEntity,
localize: LocalizeFunc
): HaFormSchema[] => {
) => {
const domain = computeDomain(entity);
return [
@ -73,23 +73,23 @@ export class HuiGenericEntityRowEditor
name: "secondary_info",
selector: {
select: {
options: Object.keys(SecondaryInfoValues)
.filter(
options: (
Object.keys(SecondaryInfoValues).filter(
(info) =>
!("domains" in SecondaryInfoValues[info]) ||
("domains" in SecondaryInfoValues[info] &&
SecondaryInfoValues[info].domains!.includes(domain))
)
.map((info) => ({
value: info,
label: localize(
`ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}`
),
})),
) as Array<keyof typeof SecondaryInfoValues>
).map((info) => ({
value: info,
label: localize(
`ui.panel.lovelace.editor.card.entities.secondary_info_values.${info}`
),
})),
},
},
},
];
] as const;
}
);
@ -122,21 +122,19 @@ export class HuiGenericEntityRowEditor
fireEvent(this, "config-changed", { config: ev.detail.value });
}
private _computeLabelCallback = (schema: HaFormSchema) => {
if (schema.name === "entity") {
return this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.entity"
);
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "secondary_info":
return this.hass!.localize(
`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";
import { fireEvent } from "../../../../common/dom/fire_event";
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 { LogbookCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
@ -29,7 +29,7 @@ const cardConfigStruct = assign(
})
);
const SCHEMA: HaFormSchema[] = [
const SCHEMA = [
{ name: "title", selector: { text: {} } },
{
name: "",
@ -39,7 +39,7 @@ const SCHEMA: HaFormSchema[] = [
{ name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } },
],
},
];
] as const;
@customElement("hui-logbook-card-editor")
export class HuiLogbookCardEditor
@ -98,23 +98,19 @@ export class HuiLogbookCardEditor
fireEvent(this, "config-changed", { config: ev.detail.value });
}
private _computeLabelCallback = (schema: HaFormSchema) => {
if (schema.name === "theme") {
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
switch (schema.name) {
case "theme":
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
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.logbook.${schema.name}`
)
);
};
}

View File

@ -26,7 +26,7 @@ import { entitiesConfigStruct } from "../structs/entities-struct";
import { EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { HaFormSchema } from "../../../../components/ha-form/types";
import { SchemaUnion } from "../../../../components/ha-form/types";
const cardConfigStruct = assign(
baseLovelaceCardConfig,
@ -41,7 +41,7 @@ const cardConfigStruct = assign(
})
);
const SCHEMA: HaFormSchema[] = [
const SCHEMA = [
{ name: "title", selector: { text: {} } },
{
name: "",
@ -53,7 +53,7 @@ const SCHEMA: HaFormSchema[] = [
{ name: "hours_to_show", selector: { number: { mode: "box", min: 1 } } },
],
},
];
] as const;
@customElement("hui-map-card-editor")
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 });
}
private _computeLabelCallback = (schema: HaFormSchema) =>
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(`ui.panel.lovelace.editor.card.map.${schema.name}`);
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
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}`
);
}
};
static get styles(): CSSResultGroup {
return [

View File

@ -16,7 +16,7 @@ import {
import { fireEvent } from "../../../../common/dom/fire_event";
import { computeDomain } from "../../../../common/entity/compute_domain";
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 { SensorCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
@ -52,61 +52,58 @@ export class HuiSensorCardEditor
}
private _schema = memoizeOne(
(
entity: string,
icon: string | undefined,
entityState: HassEntity
): HaFormSchema[] => [
{
name: "entity",
selector: {
entity: { domain: ["counter", "input_number", "number", "sensor"] },
(entity: string, icon: string | undefined, entityState: HassEntity) =>
[
{
name: "entity",
selector: {
entity: { domain: ["counter", "input_number", "number", "sensor"] },
},
},
},
{ name: "name", selector: { text: {} } },
{
type: "grid",
name: "",
schema: [
{
name: "icon",
selector: {
icon: {
placeholder: icon || entityState?.attributes.icon,
fallbackPath:
!icon && !entityState?.attributes.icon && entityState
? domainIcon(computeDomain(entity), entityState)
: undefined,
{ name: "name", selector: { text: {} } },
{
type: "grid",
name: "",
schema: [
{
name: "icon",
selector: {
icon: {
placeholder: icon || entityState?.attributes.icon,
fallbackPath:
!icon && !entityState?.attributes.icon && entityState
? domainIcon(computeDomain(entity), entityState)
: undefined,
},
},
},
},
{
name: "graph",
selector: {
select: {
options: [
{
value: "none",
label: "None",
},
{
value: "line",
label: "Line",
},
],
{
name: "graph",
selector: {
select: {
options: [
{
value: "none",
label: "None",
},
{
value: "line",
label: "Line",
},
],
},
},
},
},
{ name: "unit", selector: { text: {} } },
{ name: "detail", selector: { boolean: {} } },
{ name: "theme", selector: { theme: {} } },
{
name: "hours_to_show",
selector: { number: { min: 1, mode: "box" } },
},
],
},
]
{ name: "unit", selector: { text: {} } },
{ name: "detail", selector: { boolean: {} } },
{ name: "theme", selector: { theme: {} } },
{
name: "hours_to_show",
selector: { number: { min: 1, mode: "box" } },
},
],
},
] as const
);
protected render(): TemplateResult {
@ -146,33 +143,29 @@ export class HuiSensorCardEditor
fireEvent(this, "config-changed", { config });
}
private _computeLabelCallback = (schema: HaFormSchema) => {
if (schema.name === "entity") {
return this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.entity"
);
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "theme":
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
case "detail":
return this.hass!.localize(
"ui.panel.lovelace.editor.card.sensor.show_more_detail"
);
case "graph":
return this.hass!.localize(
"ui.panel.lovelace.editor.card.sensor.graph_type"
);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
}
if (schema.name === "theme") {
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
}
if (schema.name === "detail") {
return this.hass!.localize(
"ui.panel.lovelace.editor.card.sensor.show_more_detail"
);
}
return (
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(`ui.panel.lovelace.editor.card.sensor.${schema.name}`)
);
};
static get styles(): CSSResultGroup {

View File

@ -16,7 +16,7 @@ import {
import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeFunc } from "../../../../common/translations/localize";
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 { StatisticsGraphCardConfig } from "../../cards/types";
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")
export class HuiStatisticsGraphCardEditor
@ -71,54 +71,57 @@ export class HuiStatisticsGraphCardEditor
: [];
}
private _schema = memoizeOne((localize: LocalizeFunc) => [
{ name: "title", selector: { text: {} } },
{
name: "",
type: "grid",
schema: [
private _schema = memoizeOne(
(localize: LocalizeFunc) =>
[
{ name: "title", selector: { text: {} } },
{
name: "period",
required: true,
selector: {
select: {
options: periods.map((period) => ({
value: period,
label: localize(
`ui.panel.lovelace.editor.card.statistics-graph.periods.${period}`
),
})),
name: "",
type: "grid",
schema: [
{
name: "period",
required: true,
selector: {
select: {
options: periods.map((period) => ({
value: period,
label: localize(
`ui.panel.lovelace.editor.card.statistics-graph.periods.${period}`
),
})),
},
},
},
{
name: "days_to_show",
required: true,
selector: { number: { min: 1, mode: "box" } },
},
{
name: "stat_types",
required: true,
type: "multi_select",
options: [
["mean", "Mean"],
["min", "Min"],
["max", "Max"],
["sum", "Sum"],
],
},
{
name: "chart_type",
required: true,
type: "select",
options: [
["line", "Line"],
["bar", "Bar"],
],
},
},
},
{
name: "days_to_show",
required: true,
selector: { number: { min: 1, mode: "box" } },
},
{
name: "stat_types",
required: true,
type: "multi_select",
options: [
["mean", "Mean"],
["min", "Min"],
["max", "Max"],
["sum", "Sum"],
],
},
{
name: "chart_type",
required: true,
type: "select",
options: [
["line", "Line"],
["bar", "Bar"],
],
},
],
},
]);
] as const
);
protected render(): TemplateResult {
if (!this.hass || !this._config) {
@ -169,13 +172,22 @@ export class HuiStatisticsGraphCardEditor
});
}
private _computeLabelCallback = (schema: HaFormSchema) =>
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(
`ui.panel.lovelace.editor.card.statistics-graph.${schema.name}`
);
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "chart_type":
case "stat_types":
case "period":
return this.hass!.localize(
`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`
ha-statistics-picker {

View File

@ -12,7 +12,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { UNAVAILABLE } from "../../../../data/entity";
import type { WeatherEntity } from "../../../../data/weather";
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(
baseLovelaceCardConfig,
@ -66,12 +66,8 @@ export class HuiWeatherForecastCardEditor
}
private _schema = memoize(
(
entity: string,
localize: LocalizeFunc,
hasForecast?: boolean
): HaFormSchema[] => {
const schema: HaFormSchema[] = [
(entity: string, localize: LocalizeFunc, hasForecast?: boolean) =>
[
{
name: "entity",
required: true,
@ -89,38 +85,38 @@ export class HuiWeatherForecastCardEditor
{ name: "theme", selector: { theme: {} } },
],
},
];
if (hasForecast) {
schema.push({
name: "forecast",
selector: {
select: {
options: [
{
value: "show_both",
label: localize(
"ui.panel.lovelace.editor.card.weather-forecast.show_both"
),
...(hasForecast
? ([
{
name: "forecast",
selector: {
select: {
options: [
{
value: "show_both",
label: localize(
"ui.panel.lovelace.editor.card.weather-forecast.show_both"
),
},
{
value: "show_current",
label: localize(
"ui.panel.lovelace.editor.card.weather-forecast.show_only_current"
),
},
{
value: "show_forecast",
label: localize(
"ui.panel.lovelace.editor.card.weather-forecast.show_only_forecast"
),
},
],
},
},
{
value: "show_current",
label: localize(
"ui.panel.lovelace.editor.card.weather-forecast.show_only_current"
),
},
{
value: "show_forecast",
label: localize(
"ui.panel.lovelace.editor.card.weather-forecast.show_only_forecast"
),
},
],
},
},
});
}
return schema;
}
},
] as const)
: []),
] as const
);
protected render(): TemplateResult {
@ -175,31 +171,31 @@ export class HuiWeatherForecastCardEditor
fireEvent(this, "config-changed", { config });
}
private _computeLabelCallback = (schema: HaFormSchema) => {
if (schema.name === "entity") {
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.entity"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.required"
)})`;
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "entity":
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.entity"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.required"
)})`;
case "theme":
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
case "forecast":
return this.hass!.localize(
"ui.panel.lovelace.editor.card.weather-forecast.weather_to_show"
);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
}
if (schema.name === "theme") {
return `${this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.theme"
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
}
return (
this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
) ||
this.hass!.localize(
`ui.panel.lovelace.editor.card.weather_forecast.${schema.name}`
)
);
};
}

View File

@ -4,7 +4,8 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
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 { HomeAssistant } from "../../../../types";
import {
@ -25,38 +26,43 @@ declare global {
export class HuiViewEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public isNew!: boolean;
@property({ type: Boolean }) public isNew!: boolean;
@state() private _config!: LovelaceViewConfig;
private _suggestedPath = false;
private _schema = memoizeOne((localize): HaFormSchema[] => [
{ name: "title", selector: { text: {} } },
{
name: "icon",
selector: {
icon: {},
},
},
{ name: "path", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
{
name: "type",
selector: {
select: {
options: [
DEFAULT_VIEW_LAYOUT,
SIDEBAR_VIEW_LAYOUT,
PANEL_VIEW_LAYOUT,
].map((type) => ({
value: type,
label: localize(`ui.panel.lovelace.editor.edit_view.types.${type}`),
})),
private _schema = memoizeOne(
(localize: LocalizeFunc) =>
[
{ name: "title", selector: { text: {} } },
{
name: "icon",
selector: {
icon: {},
},
},
},
},
]);
{ name: "path", selector: { text: {} } },
{ name: "theme", selector: { theme: {} } },
{
name: "type",
selector: {
select: {
options: [
DEFAULT_VIEW_LAYOUT,
SIDEBAR_VIEW_LAYOUT,
PANEL_VIEW_LAYOUT,
].map((type) => ({
value: type,
label: localize(
`ui.panel.lovelace.editor.edit_view.types.${type}`
),
})),
},
},
},
] as const
);
set config(config: LovelaceViewConfig) {
this._config = config;
@ -114,15 +120,19 @@ export class HuiViewEditor extends LitElement {
fireEvent(this, "view-config-changed", { config });
}
private _computeLabelCallback = (schema: HaFormSchema) => {
if (schema.name === "path") {
return this.hass!.localize(`ui.panel.lovelace.editor.card.generic.url`);
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "path":
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}`
);
}
return (
this.hass!.localize(
`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"
},
"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_script": "Delete script",
"save_script": "Save script",
@ -2756,6 +2757,7 @@
"name": "Name",
"icon": "Icon",
"icon_error_msg": "Icon should be in the format ''prefix:iconname'', for example: ''mdi:home''",
"location": "Map Location",
"radius": "Radius",
"latitude": "Latitude",
"longitude": "Longitude",
@ -3936,7 +3938,6 @@
"geo_location_sources": "Geolocation Sources",
"dark_mode": "Dark Mode?",
"default_zoom": "Default Zoom",
"hours_to_show": "Hours to Show",
"source": "Source",
"description": "The Map card that allows you to display entities on a map."
},
@ -3992,6 +3993,7 @@
"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.",
"weather_to_show": "Weather to Show",
"show_both": "Show current Weather and Forecast",
"show_only_current": "Show only current Weather",
"show_only_forecast": "Show only Forecast"