Compare commits

..
17 changed files with 157 additions and 220 deletions

No files matched your search

+3 -1
View File
@@ -153,7 +153,9 @@ gulp.task("rspack-watch-app", () => {
: createAppConfig({ isProdBuild: false, latestBuild: true })
).watch({ poll: isWsl }, doneHandler());
gulp.watch(
path.join(paths.translations_src, "en.json"),
// Watch the folder via a glob; git replaces en.json on checkout/stash,
// which can permanently drop a watch on the file itself
path.join(paths.translations_src, "*.json"),
gulp.series("build-translations", "copy-translations-app")
);
});
+5
View File
@@ -38,6 +38,10 @@ export class HaBaseTimeInput extends LitElement {
*/
@property() label?: string;
/** Accessible name for the input when it has no visible label. */
@property({ attribute: "accessible-label" })
public accessibleLabel?: string;
/**
* Helper for the input
*/
@@ -178,6 +182,7 @@ export class HaBaseTimeInput extends LitElement {
class="time-input-wrap"
role="group"
aria-labelledby=${ifDefined(this.label ? "label" : undefined)}
aria-label=${ifDefined(this.label ? undefined : this.accessibleLabel)}
>
${
this.enableSign
+5
View File
@@ -50,6 +50,10 @@ export class HaDateInput extends LitElement {
@property() public label?: string;
/** Accessible name for the input when it has no visible label. */
@property({ attribute: "accessible-label" })
public accessibleLabel?: string;
@property() public helper?: string;
@property({ attribute: "can-clear", type: Boolean }) public canClear = false;
@@ -65,6 +69,7 @@ export class HaDateInput extends LitElement {
.label=${this.label ?? ""}
.hint=${this.helper ?? ""}
.disabled=${this.disabled}
.accessibleLabel=${this.accessibleLabel}
readonly
@click=${this._openDialog}
@keydown=${this._keyDown}
+10 -34
View File
@@ -1,9 +1,9 @@
import type {
HaFormBaseSchema,
HaFormCondition,
HaFormDataContainer,
HaFormFieldCondition,
HaFormSchema,
HaFormVisible,
} from "./types";
const isEmpty = (value: unknown): boolean =>
@@ -57,10 +57,11 @@ export const evaluateCondition = (
return matchFieldCondition(condition, data);
};
export const isVisible = (
visible: HaFormVisible | undefined,
export const isFieldVisible = (
schema: HaFormSchema,
data: HaFormDataContainer | undefined
): boolean => {
const { visible } = schema as HaFormBaseSchema;
if (visible === undefined || visible === true) {
return true;
}
@@ -71,26 +72,10 @@ export const isVisible = (
return conditions.every((condition) => evaluateCondition(condition, data));
};
export const combineVisible = (
...options: (HaFormVisible | undefined)[]
): HaFormVisible => {
const conditions: HaFormCondition[] = [];
for (const visible of options) {
if (visible === undefined || visible === true) {
continue;
}
if (visible === false) {
return false;
}
conditions.push(...(Array.isArray(visible) ? visible : [visible]));
}
return conditions;
};
// Hiding a field drops its value, which can flip another field's condition, so
// resolve the set to a fixpoint. Fields are given in order as name and visible.
// resolve the set to a fixpoint.
export const getHiddenFields = (
fields: readonly (readonly [string, HaFormVisible | undefined])[],
schema: readonly HaFormSchema[],
data: HaFormDataContainer | undefined
): Set<string> => {
const hidden = new Set<string>();
@@ -98,23 +83,14 @@ export const getHiddenFields = (
let changed = true;
while (changed) {
changed = false;
for (const [name, visible] of fields) {
if (hidden.has(name) || isVisible(visible, evalData)) {
for (const field of schema) {
if (hidden.has(field.name) || isFieldVisible(field, evalData)) {
continue;
}
hidden.add(name);
delete evalData[name];
hidden.add(field.name);
delete evalData[field.name];
changed = true;
}
}
return hidden;
};
export const getHiddenSchemaFields = (
schema: readonly HaFormSchema[],
data: HaFormDataContainer | undefined
): Set<string> =>
getHiddenFields(
schema.map((field) => [field.name, field.visible] as const),
data
);
+2 -2
View File
@@ -2,7 +2,7 @@ import type { PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, queryAll } from "lit/decorators";
import type { HomeAssistant } from "../../types";
import { getHiddenSchemaFields } from "./conditions";
import { getHiddenFields } from "./conditions";
import "./ha-form";
import type { HaForm } from "./ha-form";
import type {
@@ -68,7 +68,7 @@ export class HaFormGrid extends LitElement implements HaFormElement {
}
protected render(): TemplateResult {
const hiddenFields = getHiddenSchemaFields(this.schema.schema, this.data);
const hiddenFields = getHiddenFields(this.schema.schema, this.data);
return html`
${this.schema.schema
+3 -3
View File
@@ -7,7 +7,7 @@ import { resolveSelectorContext } from "../../data/selector";
import type { HomeAssistant, ValueChangedEvent } from "../../types";
import "../ha-alert";
import "../ha-selector/ha-selector";
import { getHiddenSchemaFields } from "./conditions";
import { getHiddenFields } from "./conditions";
import type {
HaFormData,
HaFormDataContainer,
@@ -136,7 +136,7 @@ export class HaForm extends LitElement implements HaFormElement {
let isValid = true;
let firstInvalidElement: HTMLElement | undefined;
const hiddenFields = getHiddenSchemaFields(this.schema, this.data);
const hiddenFields = getHiddenFields(this.schema, this.data);
const visibleSchema = this.schema.filter(
(item) => !hiddenFields.has(item.name)
);
@@ -195,7 +195,7 @@ export class HaForm extends LitElement implements HaFormElement {
}
protected render(): TemplateResult {
const renderHiddenFields = getHiddenSchemaFields(this.schema, this.data);
const renderHiddenFields = getHiddenFields(this.schema, this.data);
return html`
<div class="root" part="root">
+1 -3
View File
@@ -25,7 +25,7 @@ export interface HaFormBaseSchema {
disabled?: boolean;
// Field is visible while the condition holds (visible by default).
// Serializable so it can be shared with the backend and other renderers.
visible?: HaFormVisible;
visible?: boolean | HaFormCondition | HaFormCondition[];
description?: {
suffix?: string;
// This value will be set initially when form is loaded
@@ -34,8 +34,6 @@ export interface HaFormBaseSchema {
context?: Record<string, string>;
}
export type HaFormVisible = boolean | HaFormCondition | HaFormCondition[];
export type HaFormConditionOperator =
"eq" | "not_eq" | "in" | "not_in" | "exists" | "not_exists";
+5
View File
@@ -15,6 +15,10 @@ export class HaTimeInput extends LitElement {
@property() public label?: string;
/** Accessible name for the input when it has no visible label. */
@property({ attribute: "accessible-label" })
public accessibleLabel?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@@ -61,6 +65,7 @@ export class HaTimeInput extends LitElement {
return html`
<ha-base-time-input
.label=${this.label}
.accessibleLabel=${this.accessibleLabel}
.hours=${hours}
.minutes=${minutes}
.seconds=${seconds}
-3
View File
@@ -1,4 +1,3 @@
import type { HaFormVisible } from "../components/ha-form/types";
import type { HomeAssistant } from "../types";
import type { ManualAutomationConfig } from "./automation";
import type { ManualScriptConfig } from "./script";
@@ -28,7 +27,6 @@ export interface BlueprintInput {
description?: string;
selector?: Selector;
default?: any;
visible?: HaFormVisible;
}
export interface BlueprintInputSection {
@@ -36,7 +34,6 @@ export interface BlueprintInputSection {
icon?: string;
description?: string;
collapsed?: boolean;
visible?: HaFormVisible;
input: Record<string, BlueprintInput | null>;
}
+3 -3
View File
@@ -9,7 +9,7 @@ import { fireEvent, type HASSDomEvent } from "../../common/dom/fire_event";
import { isNavigationClick } from "../../common/dom/is-navigation-click";
import "../../components/ha-alert";
import { computeInitialHaFormData } from "../../components/ha-form/compute-initial-ha-form-data";
import { getHiddenSchemaFields } from "../../components/ha-form/conditions";
import { getHiddenFields } from "../../components/ha-form/conditions";
import "../../components/ha-form/ha-form";
import type {
HaFormSchema,
@@ -228,7 +228,7 @@ class StepFlowForm extends LitElement {
schema: readonly HaFormSchema[],
data: Record<string, any>
) => {
const hidden = getHiddenSchemaFields(schema, data);
const hidden = getHiddenFields(schema, data);
return schema.every(
(field) =>
hidden.has(field.name) ||
@@ -259,7 +259,7 @@ class StepFlowForm extends LitElement {
const flowId = this.step.flow_id;
const hiddenFields = getHiddenSchemaFields(this.step.data_schema, stepData);
const hiddenFields = getHiddenFields(this.step.data_schema, stepData);
const toSendData: Record<string, unknown> = {};
Object.keys(stepData).forEach((key) => {
@@ -5,14 +5,6 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-blueprint-picker";
import "../../../components/ha-card";
import {
combineVisible,
getHiddenFields,
} from "../../../components/ha-form/conditions";
import type {
HaFormDataContainer,
HaFormVisible,
} from "../../../components/ha-form/types";
import "../../../components/ha-spinner";
import "../../../components/ha-markdown";
import "../../../components/ha-selector/ha-selector";
@@ -21,7 +13,6 @@ import type { BlueprintAutomationConfig } from "../../../data/automation";
import type {
BlueprintInput,
BlueprintInputSection,
BlueprintMetaData,
BlueprintOrError,
Blueprints,
} from "../../../data/blueprint";
@@ -55,17 +46,19 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
}
// Values of all inputs, including those inside sections, falling back to
// their defaults, so selector contexts and visible conditions can name any
// other input
// their defaults, so a selector context can name any other input
private _inputValues = memoizeOne(
(
input: HaFormDataContainer | undefined,
metadataInput: BlueprintMetaData["input"]
): HaFormDataContainer => {
const values: HaFormDataContainer = {};
input: Record<string, unknown> | undefined,
metadataInput:
| Record<string, BlueprintInput | BlueprintInputSection | null>
| undefined
): Record<string, unknown> => {
const values: Record<string, unknown> = {};
const addInputs = (inputs: Record<string, BlueprintInput | null>) => {
for (const [key, value] of Object.entries(inputs)) {
values[key] = input && key in input ? input[key] : value?.default;
values[key] =
input && key in input ? input[key] : (value?.default ?? undefined);
}
};
for (const [key, value] of Object.entries(metadataInput ?? {})) {
@@ -79,46 +72,6 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
}
);
private _hiddenInputs = memoizeOne(
(
values: HaFormDataContainer,
metadataInput: BlueprintMetaData["input"]
): Set<string> => {
const fields: [string, HaFormVisible | undefined][] = [];
for (const [key, value] of Object.entries(metadataInput ?? {})) {
if (value && "input" in value) {
for (const [inputKey, input] of Object.entries(value.input ?? {})) {
fields.push([
inputKey,
combineVisible(value.visible, input?.visible),
]);
}
} else {
fields.push([key, value?.visible]);
}
}
return getHiddenFields(fields, values);
}
);
private get _metadataInput() {
return this._blueprint && "metadata" in this._blueprint
? this._blueprint.metadata.input
: undefined;
}
private get _values() {
return this._inputValues(
// The input holds the values of the inputs by key
this._config.use_blueprint.input as HaFormDataContainer | undefined,
this._metadataInput
);
}
private get _hidden() {
return this._hiddenInputs(this._values, this._metadataInput);
}
protected abstract get _config():
BlueprintAutomationConfig | BlueprintScriptConfig;
@@ -177,25 +130,10 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
? Object.entries(blueprint.metadata.input).map(
([key, value]) => {
if (value && "input" in value) {
const inputs = Object.entries(
value.input ?? {}
).filter(
([inputKey]) => !this._hidden.has(inputKey)
);
if (!inputs.length) {
return nothing;
}
const section = this._renderSection(
key,
value,
inputs
);
const section = this._renderSection(key, value);
border = false;
return section;
}
if (this._hidden.has(key)) {
return nothing;
}
const row = this._renderSettingRow(
key,
value,
@@ -217,15 +155,13 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
`;
}
private _renderSection(
sectionKey: string,
section: BlueprintInputSection,
inputs: [string, BlueprintInput | null][]
) {
private _renderSection(sectionKey: string, section: BlueprintInputSection) {
const title = section?.name || sectionKey;
const anyRequired = inputs.some(
([, item]) => item === null || item.default === undefined
);
const anyRequired =
section.input &&
Object.values(section.input).some(
(item) => item === null || item.default === undefined
);
const expanded = !section.collapsed || anyRequired;
return html`<ha-expansion-panel
@@ -253,7 +189,13 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
? html`<ha-markdown .content=${section.description}></ha-markdown>`
: nothing
}
${inputs.map(([key, value]) => this._renderSettingRow(key, value, true))}
${
section.input
? Object.entries(section.input).map(([key, value]) =>
this._renderSettingRow(key, value, true)
)
: nothing
}
</div>
</ha-expansion-panel>`;
}
@@ -281,7 +223,17 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
.selector=${selector}
.context=${
value?.selector
? resolveSelectorContext(value.selector, this._values)
? resolveSelectorContext(
value.selector,
this._inputValues(
// The input holds the values of the inputs by key
this._config.use_blueprint.input as
Record<string, unknown> | undefined,
this._blueprint && "metadata" in this._blueprint
? this._blueprint.metadata.input
: undefined
)
)
: undefined
}
.key=${key}
@@ -44,11 +44,14 @@ class HuiDateEntityRow extends LitElement implements LovelaceRow {
const unavailable = stateObj.state === UNAVAILABLE;
const name = this.hass.formatEntityName(stateObj, this._config.name);
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<ha-date-input
.locale=${this.hass.locale}
.disabled=${unavailable}
.accessibleLabel=${name}
.value=${
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? undefined
@@ -72,6 +72,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
</ha-date-input>
<ha-time-input
.value=${time}
.accessibleLabel=${name}
.disabled=${unavailable}
.locale=${this.hass.locale}
@value-changed=${this._timeChanged}
@@ -68,6 +68,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
? html`
<ha-date-input
.label=${stateObj.attributes.has_time ? name : undefined}
.accessibleLabel=${stateObj.attributes.has_time ? undefined : name}
.locale=${this.hass.locale}
.disabled=${stateObj.state === UNAVAILABLE}
.value=${stateToIsoDateString(stateObj)}
@@ -88,6 +89,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
? stateObj.state.split(" ")[1]
: stateObj.state
}
.accessibleLabel=${name}
.locale=${this.hass.locale}
.disabled=${stateObj.state === UNAVAILABLE}
@value-changed=${this._timeChanged}
@@ -44,6 +44,8 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
const unavailable = stateObj.state === UNAVAILABLE;
const name = this.hass.formatEntityName(stateObj, this._config.name);
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<ha-time-input
@@ -52,6 +54,7 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
? undefined
: stateObj.state
}
.accessibleLabel=${name}
.locale=${this.hass.locale}
.disabled=${unavailable}
@value-changed=${this._timeChanged}
+1
View File
@@ -29,6 +29,7 @@ const marketplaceTableParams = {
source: "string?",
sort: "string?",
direction: "string?",
group: "string?",
} satisfies Redirect["params"];
export const getMyRedirects = (): Redirects => ({
@@ -2,111 +2,106 @@ import { describe, expect, it } from "vitest";
import {
getHiddenFields,
getHiddenSchemaFields,
isVisible,
isFieldVisible,
} from "../../../src/components/ha-form/conditions";
import type {
HaFormSchema,
HaFormVisible,
} from "../../../src/components/ha-form/types";
import type { HaFormSchema } from "../../../src/components/ha-form/types";
describe("isVisible", () => {
const field = (visible: HaFormSchema["visible"]): HaFormSchema =>
({ name: "field", selector: { text: {} }, visible }) as HaFormSchema;
describe("isFieldVisible", () => {
it("shows a field without a visible condition", () => {
expect(isVisible(undefined, { a: 1 })).toBe(true);
expect(isFieldVisible(field(undefined), { a: 1 })).toBe(true);
});
it("honors a boolean visible", () => {
expect(isVisible(true, {})).toBe(true);
expect(isVisible(false, {})).toBe(false);
expect(isFieldVisible(field(true), {})).toBe(true);
expect(isFieldVisible(field(false), {})).toBe(false);
});
describe("operators", () => {
it("eq (default) matches equal values", () => {
expect(isVisible({ field: "a", value: 1 }, { a: 1 })).toBe(true);
expect(isVisible({ field: "a", value: 1 }, { a: 2 })).toBe(false);
expect(isFieldVisible(field({ field: "a", value: 1 }), { a: 1 })).toBe(
true
);
expect(isFieldVisible(field({ field: "a", value: 1 }), { a: 2 })).toBe(
false
);
});
it("not_eq matches different values", () => {
const visible: HaFormVisible = {
field: "a",
operator: "not_eq",
value: 1,
};
expect(isVisible(visible, { a: 2 })).toBe(true);
expect(isVisible(visible, { a: 1 })).toBe(false);
const schema = field({ field: "a", operator: "not_eq", value: 1 });
expect(isFieldVisible(schema, { a: 2 })).toBe(true);
expect(isFieldVisible(schema, { a: 1 })).toBe(false);
});
it("in matches membership", () => {
const visible: HaFormVisible = {
field: "a",
operator: "in",
value: ["x", "y"],
};
expect(isVisible(visible, { a: "y" })).toBe(true);
expect(isVisible(visible, { a: "z" })).toBe(false);
const schema = field({ field: "a", operator: "in", value: ["x", "y"] });
expect(isFieldVisible(schema, { a: "y" })).toBe(true);
expect(isFieldVisible(schema, { a: "z" })).toBe(false);
});
it("not_in matches non-membership", () => {
const visible: HaFormVisible = {
const schema = field({
field: "a",
operator: "not_in",
value: ["x", "y"],
};
expect(isVisible(visible, { a: "z" })).toBe(true);
expect(isVisible(visible, { a: "x" })).toBe(false);
});
expect(isFieldVisible(schema, { a: "z" })).toBe(true);
expect(isFieldVisible(schema, { a: "x" })).toBe(false);
});
it("exists matches a defined non-empty value", () => {
const visible: HaFormVisible = { field: "a", operator: "exists" };
expect(isVisible(visible, { a: "x" })).toBe(true);
expect(isVisible(visible, { a: "" })).toBe(false);
expect(isVisible(visible, {})).toBe(false);
const schema = field({ field: "a", operator: "exists" });
expect(isFieldVisible(schema, { a: "x" })).toBe(true);
expect(isFieldVisible(schema, { a: "" })).toBe(false);
expect(isFieldVisible(schema, {})).toBe(false);
});
it("not_exists matches a missing or empty value", () => {
const visible: HaFormVisible = { field: "a", operator: "not_exists" };
expect(isVisible(visible, {})).toBe(true);
expect(isVisible(visible, { a: null } as any)).toBe(true);
expect(isVisible(visible, { a: "x" })).toBe(false);
const schema = field({ field: "a", operator: "not_exists" });
expect(isFieldVisible(schema, {})).toBe(true);
expect(isFieldVisible(schema, { a: null } as any)).toBe(true);
expect(isFieldVisible(schema, { a: "x" })).toBe(false);
});
});
describe("combinators", () => {
it("and requires every condition", () => {
const visible: HaFormVisible = {
const schema = field({
condition: "and",
conditions: [
{ field: "a", value: 1 },
{ field: "b", value: 2 },
],
};
expect(isVisible(visible, { a: 1, b: 2 })).toBe(true);
expect(isVisible(visible, { a: 1, b: 9 })).toBe(false);
});
expect(isFieldVisible(schema, { a: 1, b: 2 })).toBe(true);
expect(isFieldVisible(schema, { a: 1, b: 9 })).toBe(false);
});
it("or requires any condition", () => {
const visible: HaFormVisible = {
const schema = field({
condition: "or",
conditions: [
{ field: "a", value: 1 },
{ field: "b", value: 2 },
],
};
expect(isVisible(visible, { a: 9, b: 2 })).toBe(true);
expect(isVisible(visible, { a: 9, b: 9 })).toBe(false);
});
expect(isFieldVisible(schema, { a: 9, b: 2 })).toBe(true);
expect(isFieldVisible(schema, { a: 9, b: 9 })).toBe(false);
});
it("not negates its conditions", () => {
const visible: HaFormVisible = {
const schema = field({
condition: "not",
conditions: [{ field: "a", value: 1 }],
};
expect(isVisible(visible, { a: 2 })).toBe(true);
expect(isVisible(visible, { a: 1 })).toBe(false);
});
expect(isFieldVisible(schema, { a: 2 })).toBe(true);
expect(isFieldVisible(schema, { a: 1 })).toBe(false);
});
it("nests combinators", () => {
const visible: HaFormVisible = {
const schema = field({
condition: "and",
conditions: [
{ field: "a", value: 1 },
@@ -118,65 +113,57 @@ describe("isVisible", () => {
],
},
],
};
expect(isVisible(visible, { a: 1, b: 9, c: 3 })).toBe(true);
expect(isVisible(visible, { a: 1, b: 9, c: 9 })).toBe(false);
expect(isVisible(visible, { a: 9, b: 2, c: 3 })).toBe(false);
});
expect(isFieldVisible(schema, { a: 1, b: 9, c: 3 })).toBe(true);
expect(isFieldVisible(schema, { a: 1, b: 9, c: 9 })).toBe(false);
expect(isFieldVisible(schema, { a: 9, b: 2, c: 3 })).toBe(false);
});
});
it("treats an array of conditions as AND", () => {
const visible: HaFormVisible = [
const schema = field([
{ field: "a", value: 1 },
{ field: "b", value: 2 },
];
expect(isVisible(visible, { a: 1, b: 2 })).toBe(true);
expect(isVisible(visible, { a: 1, b: 9 })).toBe(false);
]);
expect(isFieldVisible(schema, { a: 1, b: 2 })).toBe(true);
expect(isFieldVisible(schema, { a: 1, b: 9 })).toBe(false);
});
it("handles missing data", () => {
expect(isVisible({ field: "a", value: 1 }, undefined)).toBe(false);
expect(isFieldVisible(field({ field: "a", value: 1 }), undefined)).toBe(
false
);
});
});
describe("getHiddenFields", () => {
const named = (
name: string,
visible?: HaFormSchema["visible"]
): HaFormSchema =>
({ name, selector: { text: {} }, visible }) as HaFormSchema;
it("collects the fields that are not visible", () => {
const fields = [
["mode", undefined],
["token", { field: "mode", value: "advanced" }],
] as const;
expect([...getHiddenFields(fields, { mode: "simple" })]).toEqual(["token"]);
expect([...getHiddenFields(fields, { mode: "advanced" })]).toEqual([]);
const schema = [
named("mode"),
named("token", { field: "mode", value: "advanced" }),
];
expect([...getHiddenFields(schema, { mode: "simple" })]).toEqual(["token"]);
expect([...getHiddenFields(schema, { mode: "advanced" })]).toEqual([]);
});
it("treats a hidden field as absent to the other conditions", () => {
// "token" is hidden, so its value must not satisfy the condition on "extra"
const fields = [
["mode", undefined],
["token", { field: "mode", value: "advanced" }],
["extra", { field: "token", operator: "exists" }],
] as const;
const schema = [
named("mode"),
named("token", { field: "mode", value: "advanced" }),
named("extra", { field: "token", operator: "exists" }),
];
expect([
...getHiddenFields(fields, { mode: "simple", token: "stale" }),
...getHiddenFields(schema, { mode: "simple", token: "stale" }),
]).toEqual(["token", "extra"]);
expect([
...getHiddenFields(fields, { mode: "advanced", token: "kept" }),
...getHiddenFields(schema, { mode: "advanced", token: "kept" }),
]).toEqual([]);
});
});
describe("getHiddenSchemaFields", () => {
it("reads the visible condition of each schema field", () => {
const schema = [
{ name: "mode", selector: { text: {} } },
{
name: "token",
selector: { text: {} },
visible: { field: "mode", value: "advanced" },
},
] as HaFormSchema[];
expect([...getHiddenSchemaFields(schema, { mode: "simple" })]).toEqual([
"token",
]);
});
});