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:
Paul Bottein 2024-08-28 15:49:38 +02:00 committed by GitHub
parent c556742ff4
commit 19f057a51b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 137 additions and 53 deletions

View File

@ -21,13 +21,45 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
@property({ attribute: false }) public computeLabel?: (
schema: HaFormSchema,
data?: HaFormDataContainer
data?: HaFormDataContainer,
options?: { path?: string[] }
) => string;
@property({ attribute: false }) public computeHelper?: (
schema: HaFormSchema
schema: HaFormSchema,
options?: { path?: 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() {
return html`
<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>
`
: nothing}
${this.schema.title}
${this.schema.title || this.computeLabel?.(this.schema)}
</div>
<div class="content">
${this._renderDescription()}
<ha-form
.hass=${this.hass}
.data=${this.data}
.schema=${this.schema.schema}
.disabled=${this.disabled}
.computeLabel=${this.computeLabel}
.computeHelper=${this.computeHelper}
.computeLabel=${this._computeLabel}
.computeHelper=${this._computeHelper}
></ha-form>
</div>
</ha-expansion-panel>
@ -71,6 +104,9 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
.content {
padding: 12px;
}
.content p {
margin: 0 0 24px;
}
ha-expansion-panel {
display: block;
--expansion-panel-content-padding: 0;

View File

@ -31,7 +31,7 @@ const LOAD_ELEMENTS = {
};
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);
@ -73,10 +73,6 @@ export class HaForm extends LitElement implements HaFormElement {
schema: any
) => string | undefined;
@property({ attribute: false }) public localizeValue?: (
key: string
) => string;
protected getFormProperties(): Record<string, any> {
return {};
}
@ -149,7 +145,6 @@ export class HaForm extends LitElement implements HaFormElement {
.disabled=${item.disabled || this.disabled || false}
.placeholder=${item.required ? "" : item.default}
.helper=${this._computeHelper(item)}
.localizeValue=${this.localizeValue}
.required=${item.required || false}
.context=${this._generateContext(item)}
></ha-selector>`
@ -204,9 +199,10 @@ export class HaForm extends LitElement implements HaFormElement {
if (ev.target === this) return;
const newValue = !schema.name
? ev.detail.value
: { [schema.name]: ev.detail.value };
const newValue =
!schema.name || ("flatten" in schema && schema.flatten)
? ev.detail.value
: { [schema.name]: ev.detail.value };
this.data = {
...this.data,

View File

@ -31,15 +31,15 @@ export interface HaFormBaseSchema {
export interface HaFormGridSchema extends HaFormBaseSchema {
type: "grid";
name: string;
flatten?: boolean;
column_min_width?: string;
schema: readonly HaFormSchema[];
}
export interface HaFormExpandableSchema extends HaFormBaseSchema {
type: "expandable";
name: "";
title: string;
flatten?: boolean;
title?: string;
icon?: string;
iconPath?: string;
expanded?: boolean;
@ -100,7 +100,7 @@ export type SchemaUnion<
SchemaArray extends readonly HaFormSchema[],
Schema = SchemaArray[number],
> = Schema extends HaFormGridSchema | HaFormExpandableSchema
? SchemaUnion<Schema["schema"]>
? SchemaUnion<Schema["schema"]> | Schema
: Schema;
export interface HaFormDataContainer {

View File

@ -162,8 +162,14 @@ export class HaLocationSelector extends LitElement {
private _computeLabel = (
entry: SchemaUnion<ReturnType<typeof this._schema>>
): string =>
this.hass.localize(`ui.components.selectors.location.${entry.name}`);
): string => {
if (entry.name) {
return this.hass.localize(
`ui.components.selectors.location.${entry.name}`
);
}
return "";
};
static styles = css`
ha-locations-editor {

View File

@ -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 (
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
);
},
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(
`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
);
return description
? html`<ha-markdown breaks .content=${description}></ha-markdown>`
: "";

View File

@ -49,13 +49,15 @@ export interface FlowConfig {
renderShowFormStepFieldLabel(
hass: HomeAssistant,
step: DataEntryFlowStepForm,
field: HaFormSchema
field: HaFormSchema,
options: { path?: string[]; [key: string]: any }
): string;
renderShowFormStepFieldHelper(
hass: HomeAssistant,
step: DataEntryFlowStepForm,
field: HaFormSchema
field: HaFormSchema,
options: { path?: string[]; [key: string]: any }
): TemplateResult | string;
renderShowFormStepFieldError(

View File

@ -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 (
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
);
},
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(
`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
);
return description

View File

@ -225,11 +225,24 @@ class StepFlowForm extends LitElement {
this._stepData = ev.detail.value;
}
private _labelCallback = (field: HaFormSchema): string =>
this.flowConfig.renderShowFormStepFieldLabel(this.hass, this.step, field);
private _labelCallback = (field: HaFormSchema, _data, options): string =>
this.flowConfig.renderShowFormStepFieldLabel(
this.hass,
this.step,
field,
options
);
private _helperCallback = (field: HaFormSchema): string | TemplateResult =>
this.flowConfig.renderShowFormStepFieldHelper(this.hass, this.step, field);
private _helperCallback = (
field: HaFormSchema,
options
): string | TemplateResult =>
this.flowConfig.renderShowFormStepFieldHelper(
this.hass,
this.step,
field,
options
);
private _errorCallback = (error: string) =>
this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error);

View File

@ -96,20 +96,20 @@ export const showRepairsFlowDialog = (
: "";
},
renderShowFormStepFieldLabel(hass, step, field) {
renderShowFormStepFieldLabel(hass, step, field, options) {
return hass.localize(
`component.${issue.domain}.issues.${
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
);
},
renderShowFormStepFieldHelper(hass, step, field) {
renderShowFormStepFieldHelper(hass, step, field, options) {
const description = hass.localize(
`component.${issue.domain}.issues.${
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
);
return description

View File

@ -74,10 +74,10 @@ export class HuiEntityBadgeEditor
[
{ name: "entity", selector: { entity: {} } },
{
name: "",
name: "appearance",
type: "expandable",
flatten: true,
iconPath: mdiPalette,
title: localize(`ui.panel.lovelace.editor.badge.entity.appearance`),
schema: [
{
name: "",
@ -153,9 +153,9 @@ export class HuiEntityBadgeEditor
],
},
{
name: "",
name: "interactions",
type: "expandable",
title: localize(`ui.panel.lovelace.editor.badge.entity.interactions`),
flatten: true,
iconPath: mdiGestureTap,
schema: [
{
@ -238,6 +238,8 @@ export class HuiEntityBadgeEditor
case "state_content":
case "show_entity_picture":
case "displayed_elements":
case "appearance":
case "interactions":
return this.hass!.localize(
`ui.panel.lovelace.editor.badge.entity.${schema.name}`
);

View File

@ -14,7 +14,6 @@ import {
union,
} from "superstruct";
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
import { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
import type {
HaFormSchema,
@ -69,18 +68,14 @@ export class HuiTileCardEditor
}
private _schema = memoizeOne(
(
localize: LocalizeFunc,
entityId: string | undefined,
hideState: boolean
) =>
(entityId: string | undefined, hideState: boolean) =>
[
{ name: "entity", selector: { entity: {} } },
{
name: "",
name: "appearance",
flatten: true,
type: "expandable",
iconPath: mdiPalette,
title: localize(`ui.panel.lovelace.editor.card.tile.appearance`),
schema: [
{
name: "",
@ -136,9 +131,9 @@ export class HuiTileCardEditor
],
},
{
name: "",
name: "interactions",
type: "expandable",
title: localize(`ui.panel.lovelace.editor.card.tile.interactions`),
flatten: true,
iconPath: mdiGestureTap,
schema: [
{
@ -178,7 +173,6 @@ export class HuiTileCardEditor
: undefined;
const schema = this._schema(
this.hass!.localize,
this._config.entity,
this._config.hide_state ?? false
);
@ -306,6 +300,8 @@ export class HuiTileCardEditor
case "vertical":
case "hide_state":
case "state_content":
case "appearance":
case "interactions":
return this.hass!.localize(
`ui.panel.lovelace.editor.card.tile.${schema.name}`
);