mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add title and description translation support to expandable form (#21745)
* Add title and description translation support to expandable form * Fix type * handle translations in sections * Rename prefix to path + refactor * Fix section name and description --------- Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
c556742ff4
commit
19f057a51b
@ -21,13 +21,45 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public computeLabel?: (
|
@property({ attribute: false }) public computeLabel?: (
|
||||||
schema: HaFormSchema,
|
schema: HaFormSchema,
|
||||||
data?: HaFormDataContainer
|
data?: HaFormDataContainer,
|
||||||
|
options?: { path?: string[] }
|
||||||
) => string;
|
) => string;
|
||||||
|
|
||||||
@property({ attribute: false }) public computeHelper?: (
|
@property({ attribute: false }) public computeHelper?: (
|
||||||
schema: HaFormSchema
|
schema: HaFormSchema,
|
||||||
|
options?: { path?: string[] }
|
||||||
) => string;
|
) => string;
|
||||||
|
|
||||||
|
private _renderDescription() {
|
||||||
|
const description = this.computeHelper?.(this.schema);
|
||||||
|
return description ? html`<p>${description}</p>` : nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeLabel = (
|
||||||
|
schema: HaFormSchema,
|
||||||
|
data?: HaFormDataContainer,
|
||||||
|
options?: { path?: string[] }
|
||||||
|
) => {
|
||||||
|
if (!this.computeLabel) return this.computeLabel;
|
||||||
|
|
||||||
|
return this.computeLabel(schema, data, {
|
||||||
|
...options,
|
||||||
|
path: [...(options?.path || []), this.schema.name],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private _computeHelper = (
|
||||||
|
schema: HaFormSchema,
|
||||||
|
options?: { path?: string[] }
|
||||||
|
) => {
|
||||||
|
if (!this.computeHelper) return this.computeHelper;
|
||||||
|
|
||||||
|
return this.computeHelper(schema, {
|
||||||
|
...options,
|
||||||
|
path: [...(options?.path || []), this.schema.name],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-expansion-panel outlined .expanded=${Boolean(this.schema.expanded)}>
|
<ha-expansion-panel outlined .expanded=${Boolean(this.schema.expanded)}>
|
||||||
@ -43,16 +75,17 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
|
|||||||
<ha-svg-icon .path=${this.schema.iconPath}></ha-svg-icon>
|
<ha-svg-icon .path=${this.schema.iconPath}></ha-svg-icon>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
${this.schema.title}
|
${this.schema.title || this.computeLabel?.(this.schema)}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
${this._renderDescription()}
|
||||||
<ha-form
|
<ha-form
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.data=${this.data}
|
.data=${this.data}
|
||||||
.schema=${this.schema.schema}
|
.schema=${this.schema.schema}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.computeLabel=${this.computeLabel}
|
.computeLabel=${this._computeLabel}
|
||||||
.computeHelper=${this.computeHelper}
|
.computeHelper=${this._computeHelper}
|
||||||
></ha-form>
|
></ha-form>
|
||||||
</div>
|
</div>
|
||||||
</ha-expansion-panel>
|
</ha-expansion-panel>
|
||||||
@ -71,6 +104,9 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
|
|||||||
.content {
|
.content {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
.content p {
|
||||||
|
margin: 0 0 24px;
|
||||||
|
}
|
||||||
ha-expansion-panel {
|
ha-expansion-panel {
|
||||||
display: block;
|
display: block;
|
||||||
--expansion-panel-content-padding: 0;
|
--expansion-panel-content-padding: 0;
|
||||||
|
@ -31,7 +31,7 @@ const LOAD_ELEMENTS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getValue = (obj, item) =>
|
const getValue = (obj, item) =>
|
||||||
obj ? (!item.name ? obj : obj[item.name]) : null;
|
obj ? (!item.name || item.flatten ? obj : obj[item.name]) : null;
|
||||||
|
|
||||||
const getError = (obj, item) => (obj && item.name ? obj[item.name] : null);
|
const getError = (obj, item) => (obj && item.name ? obj[item.name] : null);
|
||||||
|
|
||||||
@ -73,10 +73,6 @@ export class HaForm extends LitElement implements HaFormElement {
|
|||||||
schema: any
|
schema: any
|
||||||
) => string | undefined;
|
) => string | undefined;
|
||||||
|
|
||||||
@property({ attribute: false }) public localizeValue?: (
|
|
||||||
key: string
|
|
||||||
) => string;
|
|
||||||
|
|
||||||
protected getFormProperties(): Record<string, any> {
|
protected getFormProperties(): Record<string, any> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -149,7 +145,6 @@ export class HaForm extends LitElement implements HaFormElement {
|
|||||||
.disabled=${item.disabled || this.disabled || false}
|
.disabled=${item.disabled || this.disabled || false}
|
||||||
.placeholder=${item.required ? "" : item.default}
|
.placeholder=${item.required ? "" : item.default}
|
||||||
.helper=${this._computeHelper(item)}
|
.helper=${this._computeHelper(item)}
|
||||||
.localizeValue=${this.localizeValue}
|
|
||||||
.required=${item.required || false}
|
.required=${item.required || false}
|
||||||
.context=${this._generateContext(item)}
|
.context=${this._generateContext(item)}
|
||||||
></ha-selector>`
|
></ha-selector>`
|
||||||
@ -204,9 +199,10 @@ export class HaForm extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
if (ev.target === this) return;
|
if (ev.target === this) return;
|
||||||
|
|
||||||
const newValue = !schema.name
|
const newValue =
|
||||||
? ev.detail.value
|
!schema.name || ("flatten" in schema && schema.flatten)
|
||||||
: { [schema.name]: ev.detail.value };
|
? ev.detail.value
|
||||||
|
: { [schema.name]: ev.detail.value };
|
||||||
|
|
||||||
this.data = {
|
this.data = {
|
||||||
...this.data,
|
...this.data,
|
||||||
|
@ -31,15 +31,15 @@ export interface HaFormBaseSchema {
|
|||||||
|
|
||||||
export interface HaFormGridSchema extends HaFormBaseSchema {
|
export interface HaFormGridSchema extends HaFormBaseSchema {
|
||||||
type: "grid";
|
type: "grid";
|
||||||
name: string;
|
flatten?: boolean;
|
||||||
column_min_width?: string;
|
column_min_width?: string;
|
||||||
schema: readonly HaFormSchema[];
|
schema: readonly HaFormSchema[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HaFormExpandableSchema extends HaFormBaseSchema {
|
export interface HaFormExpandableSchema extends HaFormBaseSchema {
|
||||||
type: "expandable";
|
type: "expandable";
|
||||||
name: "";
|
flatten?: boolean;
|
||||||
title: string;
|
title?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
iconPath?: string;
|
iconPath?: string;
|
||||||
expanded?: boolean;
|
expanded?: boolean;
|
||||||
@ -100,7 +100,7 @@ export type SchemaUnion<
|
|||||||
SchemaArray extends readonly HaFormSchema[],
|
SchemaArray extends readonly HaFormSchema[],
|
||||||
Schema = SchemaArray[number],
|
Schema = SchemaArray[number],
|
||||||
> = Schema extends HaFormGridSchema | HaFormExpandableSchema
|
> = Schema extends HaFormGridSchema | HaFormExpandableSchema
|
||||||
? SchemaUnion<Schema["schema"]>
|
? SchemaUnion<Schema["schema"]> | Schema
|
||||||
: Schema;
|
: Schema;
|
||||||
|
|
||||||
export interface HaFormDataContainer {
|
export interface HaFormDataContainer {
|
||||||
|
@ -162,8 +162,14 @@ export class HaLocationSelector extends LitElement {
|
|||||||
|
|
||||||
private _computeLabel = (
|
private _computeLabel = (
|
||||||
entry: SchemaUnion<ReturnType<typeof this._schema>>
|
entry: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
): string =>
|
): string => {
|
||||||
this.hass.localize(`ui.components.selectors.location.${entry.name}`);
|
if (entry.name) {
|
||||||
|
return this.hass.localize(
|
||||||
|
`ui.components.selectors.location.${entry.name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
ha-locations-editor {
|
ha-locations-editor {
|
||||||
|
@ -76,19 +76,36 @@ export const showConfigFlowDialog = (
|
|||||||
: "";
|
: "";
|
||||||
},
|
},
|
||||||
|
|
||||||
renderShowFormStepFieldLabel(hass, step, field) {
|
renderShowFormStepFieldLabel(hass, step, field, options) {
|
||||||
|
if (field.type === "expandable") {
|
||||||
|
return hass.localize(
|
||||||
|
`component.${step.handler}.config.step.${step.step_id}.sections.${field.name}.name`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = options?.path?.[0] ? `sections.${options.path[0]}` : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
hass.localize(
|
hass.localize(
|
||||||
`component.${step.handler}.config.step.${step.step_id}.data.${field.name}`
|
`component.${step.handler}.config.step.${step.step_id}.${prefix}data.${field.name}`
|
||||||
) || field.name
|
) || field.name
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderShowFormStepFieldHelper(hass, step, field) {
|
renderShowFormStepFieldHelper(hass, step, field, options) {
|
||||||
|
if (field.type === "expandable") {
|
||||||
|
return hass.localize(
|
||||||
|
`component.${step.translation_domain || step.handler}.config.step.${step.step_id}.sections.${field.name}.description`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = options?.path?.[0] ? `sections.${options.path[0]}.` : "";
|
||||||
|
|
||||||
const description = hass.localize(
|
const description = hass.localize(
|
||||||
`component.${step.translation_domain || step.handler}.config.step.${step.step_id}.data_description.${field.name}`,
|
`component.${step.translation_domain || step.handler}.config.step.${step.step_id}.${prefix}data_description.${field.name}`,
|
||||||
step.description_placeholders
|
step.description_placeholders
|
||||||
);
|
);
|
||||||
|
|
||||||
return description
|
return description
|
||||||
? html`<ha-markdown breaks .content=${description}></ha-markdown>`
|
? html`<ha-markdown breaks .content=${description}></ha-markdown>`
|
||||||
: "";
|
: "";
|
||||||
|
@ -49,13 +49,15 @@ export interface FlowConfig {
|
|||||||
renderShowFormStepFieldLabel(
|
renderShowFormStepFieldLabel(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
step: DataEntryFlowStepForm,
|
step: DataEntryFlowStepForm,
|
||||||
field: HaFormSchema
|
field: HaFormSchema,
|
||||||
|
options: { path?: string[]; [key: string]: any }
|
||||||
): string;
|
): string;
|
||||||
|
|
||||||
renderShowFormStepFieldHelper(
|
renderShowFormStepFieldHelper(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
step: DataEntryFlowStepForm,
|
step: DataEntryFlowStepForm,
|
||||||
field: HaFormSchema
|
field: HaFormSchema,
|
||||||
|
options: { path?: string[]; [key: string]: any }
|
||||||
): TemplateResult | string;
|
): TemplateResult | string;
|
||||||
|
|
||||||
renderShowFormStepFieldError(
|
renderShowFormStepFieldError(
|
||||||
|
@ -93,17 +93,33 @@ export const showOptionsFlowDialog = (
|
|||||||
: "";
|
: "";
|
||||||
},
|
},
|
||||||
|
|
||||||
renderShowFormStepFieldLabel(hass, step, field) {
|
renderShowFormStepFieldLabel(hass, step, field, options) {
|
||||||
|
if (field.type === "expandable") {
|
||||||
|
return hass.localize(
|
||||||
|
`component.${configEntry.domain}.options.step.${step.step_id}.sections.${field.name}.name`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = options?.path?.[0] ? `sections.${options.path[0]}.` : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
hass.localize(
|
hass.localize(
|
||||||
`component.${configEntry.domain}.options.step.${step.step_id}.data.${field.name}`
|
`component.${configEntry.domain}.options.step.${step.step_id}.${prefix}data.${field.name}`
|
||||||
) || field.name
|
) || field.name
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderShowFormStepFieldHelper(hass, step, field) {
|
renderShowFormStepFieldHelper(hass, step, field, options) {
|
||||||
|
if (field.type === "expandable") {
|
||||||
|
return hass.localize(
|
||||||
|
`component.${step.translation_domain || configEntry.domain}.options.step.${step.step_id}.sections.${field.name}.description`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = options?.path?.[0] ? `sections.${options.path[0]}.` : "";
|
||||||
|
|
||||||
const description = hass.localize(
|
const description = hass.localize(
|
||||||
`component.${step.translation_domain || configEntry.domain}.options.step.${step.step_id}.data_description.${field.name}`,
|
`component.${step.translation_domain || configEntry.domain}.options.step.${step.step_id}.${prefix}data_description.${field.name}`,
|
||||||
step.description_placeholders
|
step.description_placeholders
|
||||||
);
|
);
|
||||||
return description
|
return description
|
||||||
|
@ -225,11 +225,24 @@ class StepFlowForm extends LitElement {
|
|||||||
this._stepData = ev.detail.value;
|
this._stepData = ev.detail.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _labelCallback = (field: HaFormSchema): string =>
|
private _labelCallback = (field: HaFormSchema, _data, options): string =>
|
||||||
this.flowConfig.renderShowFormStepFieldLabel(this.hass, this.step, field);
|
this.flowConfig.renderShowFormStepFieldLabel(
|
||||||
|
this.hass,
|
||||||
|
this.step,
|
||||||
|
field,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
private _helperCallback = (field: HaFormSchema): string | TemplateResult =>
|
private _helperCallback = (
|
||||||
this.flowConfig.renderShowFormStepFieldHelper(this.hass, this.step, field);
|
field: HaFormSchema,
|
||||||
|
options
|
||||||
|
): string | TemplateResult =>
|
||||||
|
this.flowConfig.renderShowFormStepFieldHelper(
|
||||||
|
this.hass,
|
||||||
|
this.step,
|
||||||
|
field,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
private _errorCallback = (error: string) =>
|
private _errorCallback = (error: string) =>
|
||||||
this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error);
|
this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error);
|
||||||
|
@ -96,20 +96,20 @@ export const showRepairsFlowDialog = (
|
|||||||
: "";
|
: "";
|
||||||
},
|
},
|
||||||
|
|
||||||
renderShowFormStepFieldLabel(hass, step, field) {
|
renderShowFormStepFieldLabel(hass, step, field, options) {
|
||||||
return hass.localize(
|
return hass.localize(
|
||||||
`component.${issue.domain}.issues.${
|
`component.${issue.domain}.issues.${
|
||||||
issue.translation_key || issue.issue_id
|
issue.translation_key || issue.issue_id
|
||||||
}.fix_flow.step.${step.step_id}.data.${field.name}`,
|
}.fix_flow.step.${step.step_id}.${options?.prefix ? `section.${options.prefix[0]}.` : ""}data.${field.name}`,
|
||||||
step.description_placeholders
|
step.description_placeholders
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderShowFormStepFieldHelper(hass, step, field) {
|
renderShowFormStepFieldHelper(hass, step, field, options) {
|
||||||
const description = hass.localize(
|
const description = hass.localize(
|
||||||
`component.${issue.domain}.issues.${
|
`component.${issue.domain}.issues.${
|
||||||
issue.translation_key || issue.issue_id
|
issue.translation_key || issue.issue_id
|
||||||
}.fix_flow.step.${step.step_id}.data_description.${field.name}`,
|
}.fix_flow.step.${step.step_id}.${options?.prefix ? `section.${options.prefix[0]}.` : ""}data_description.${field.name}`,
|
||||||
step.description_placeholders
|
step.description_placeholders
|
||||||
);
|
);
|
||||||
return description
|
return description
|
||||||
|
@ -74,10 +74,10 @@ export class HuiEntityBadgeEditor
|
|||||||
[
|
[
|
||||||
{ name: "entity", selector: { entity: {} } },
|
{ name: "entity", selector: { entity: {} } },
|
||||||
{
|
{
|
||||||
name: "",
|
name: "appearance",
|
||||||
type: "expandable",
|
type: "expandable",
|
||||||
|
flatten: true,
|
||||||
iconPath: mdiPalette,
|
iconPath: mdiPalette,
|
||||||
title: localize(`ui.panel.lovelace.editor.badge.entity.appearance`),
|
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
@ -153,9 +153,9 @@ export class HuiEntityBadgeEditor
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "",
|
name: "interactions",
|
||||||
type: "expandable",
|
type: "expandable",
|
||||||
title: localize(`ui.panel.lovelace.editor.badge.entity.interactions`),
|
flatten: true,
|
||||||
iconPath: mdiGestureTap,
|
iconPath: mdiGestureTap,
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
@ -238,6 +238,8 @@ export class HuiEntityBadgeEditor
|
|||||||
case "state_content":
|
case "state_content":
|
||||||
case "show_entity_picture":
|
case "show_entity_picture":
|
||||||
case "displayed_elements":
|
case "displayed_elements":
|
||||||
|
case "appearance":
|
||||||
|
case "interactions":
|
||||||
return this.hass!.localize(
|
return this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.badge.entity.${schema.name}`
|
`ui.panel.lovelace.editor.badge.entity.${schema.name}`
|
||||||
);
|
);
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
union,
|
union,
|
||||||
} from "superstruct";
|
} from "superstruct";
|
||||||
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
|
||||||
import "../../../../components/ha-form/ha-form";
|
import "../../../../components/ha-form/ha-form";
|
||||||
import type {
|
import type {
|
||||||
HaFormSchema,
|
HaFormSchema,
|
||||||
@ -69,18 +68,14 @@ export class HuiTileCardEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _schema = memoizeOne(
|
private _schema = memoizeOne(
|
||||||
(
|
(entityId: string | undefined, hideState: boolean) =>
|
||||||
localize: LocalizeFunc,
|
|
||||||
entityId: string | undefined,
|
|
||||||
hideState: boolean
|
|
||||||
) =>
|
|
||||||
[
|
[
|
||||||
{ name: "entity", selector: { entity: {} } },
|
{ name: "entity", selector: { entity: {} } },
|
||||||
{
|
{
|
||||||
name: "",
|
name: "appearance",
|
||||||
|
flatten: true,
|
||||||
type: "expandable",
|
type: "expandable",
|
||||||
iconPath: mdiPalette,
|
iconPath: mdiPalette,
|
||||||
title: localize(`ui.panel.lovelace.editor.card.tile.appearance`),
|
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
@ -136,9 +131,9 @@ export class HuiTileCardEditor
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "",
|
name: "interactions",
|
||||||
type: "expandable",
|
type: "expandable",
|
||||||
title: localize(`ui.panel.lovelace.editor.card.tile.interactions`),
|
flatten: true,
|
||||||
iconPath: mdiGestureTap,
|
iconPath: mdiGestureTap,
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
@ -178,7 +173,6 @@ export class HuiTileCardEditor
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const schema = this._schema(
|
const schema = this._schema(
|
||||||
this.hass!.localize,
|
|
||||||
this._config.entity,
|
this._config.entity,
|
||||||
this._config.hide_state ?? false
|
this._config.hide_state ?? false
|
||||||
);
|
);
|
||||||
@ -306,6 +300,8 @@ export class HuiTileCardEditor
|
|||||||
case "vertical":
|
case "vertical":
|
||||||
case "hide_state":
|
case "hide_state":
|
||||||
case "state_content":
|
case "state_content":
|
||||||
|
case "appearance":
|
||||||
|
case "interactions":
|
||||||
return this.hass!.localize(
|
return this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.${schema.name}`
|
`ui.panel.lovelace.editor.card.tile.${schema.name}`
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user