mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Bump superstruct, add struct to automation action (#6436)
Co-authored-by: Zack Arnett <arnett.zackary@gmail.com>
This commit is contained in:
parent
235fd5603f
commit
16473c9177
@ -108,7 +108,7 @@
|
||||
"regenerator-runtime": "^0.13.2",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
"superstruct": "^0.6.1",
|
||||
"superstruct": "^0.10.12",
|
||||
"unfetch": "^4.1.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue2-daterange-picker": "^0.5.1",
|
||||
|
@ -46,8 +46,8 @@ export interface MqttTrigger {
|
||||
|
||||
export interface GeoLocationTrigger {
|
||||
platform: "geo_location";
|
||||
source: "string";
|
||||
zone: "string";
|
||||
source: string;
|
||||
zone: string;
|
||||
event: "enter" | "leave";
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,8 @@ import "./types/ha-automation-action-event";
|
||||
import "./types/ha-automation-action-scene";
|
||||
import "./types/ha-automation-action-service";
|
||||
import "./types/ha-automation-action-wait_template";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { handleStructError } from "../../../lovelace/common/structs/handle-errors";
|
||||
|
||||
const OPTIONS = [
|
||||
"condition",
|
||||
@ -87,12 +89,16 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
|
||||
@property() public totalActions!: number;
|
||||
|
||||
@internalProperty() private _warnings?: string[];
|
||||
|
||||
@internalProperty() private _uiModeAvailable = true;
|
||||
|
||||
@internalProperty() private _yamlMode = false;
|
||||
|
||||
protected render() {
|
||||
const type = getType(this.action);
|
||||
const selected = type ? OPTIONS.indexOf(type) : -1;
|
||||
const yamlMode = this._yamlMode || selected === -1;
|
||||
const yamlMode = this._yamlMode;
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
@ -137,7 +143,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
</mwc-icon-button>
|
||||
<mwc-list-item
|
||||
@request-selected=${this._switchYamlMode}
|
||||
.disabled=${selected === -1}
|
||||
.disabled=${!this._uiModeAvailable}
|
||||
>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
@ -159,6 +165,16 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
${this._warnings
|
||||
? html`<div class="warning">
|
||||
UI editor is not supported for this config:
|
||||
<br />
|
||||
<ul>
|
||||
${this._warnings.map((warning) => html`<li>${warning}</li>`)}
|
||||
</ul>
|
||||
You can still edit your config in yaml.
|
||||
</div>`
|
||||
: ""}
|
||||
${yamlMode
|
||||
? html`
|
||||
<div style="margin-right: 24px;">
|
||||
@ -200,7 +216,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>
|
||||
<div>
|
||||
<div @ui-mode-not-available=${this._handleUiModeNotAvailable}>
|
||||
${dynamicElement(`ha-automation-action-${type}`, {
|
||||
hass: this.hass,
|
||||
action: this.action,
|
||||
@ -212,6 +228,13 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleUiModeNotAvailable(ev: CustomEvent) {
|
||||
this._warnings = handleStructError(ev.detail);
|
||||
if (!this._yamlMode) {
|
||||
this._yamlMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
private _moveUp() {
|
||||
fireEvent(this, "move-action", { direction: "up" });
|
||||
}
|
||||
@ -241,6 +264,11 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
this._uiModeAvailable = OPTIONS.includes(type);
|
||||
if (!this._uiModeAvailable && !this._yamlMode) {
|
||||
this._yamlMode = false;
|
||||
}
|
||||
|
||||
if (type !== getType(this.action)) {
|
||||
const elClass = customElements.get(`ha-automation-action-${type}`);
|
||||
|
||||
@ -260,7 +288,10 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
private _switchYamlMode(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
@ -283,6 +314,13 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
mwc-list-item[disabled] {
|
||||
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
|
||||
}
|
||||
.warning {
|
||||
color: var(--warning-color);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.warning ul {
|
||||
margin: 4px 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,20 @@ import { ServiceAction } from "../../../../../data/script";
|
||||
import type { PolymerChangedEvent } from "../../../../../polymer-types";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement, handleChangeEvent } from "../ha-automation-action-row";
|
||||
import { assert, optional, object, string } from "superstruct";
|
||||
import { EntityId } from "../../../../lovelace/common/structs/is-entity-id";
|
||||
|
||||
const actionStruct = object({
|
||||
service: optional(string()),
|
||||
entity_id: optional(EntityId),
|
||||
data: optional(object()),
|
||||
});
|
||||
|
||||
@customElement("ha-automation-action-service")
|
||||
export class HaServiceAction extends LitElement implements ActionElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public action!: ServiceAction;
|
||||
@property({ attribute: false }) public action!: ServiceAction;
|
||||
|
||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||
|
||||
@ -60,6 +68,11 @@ export class HaServiceAction extends LitElement implements ActionElement {
|
||||
if (!changedProperties.has("action")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
assert(this.action, actionStruct);
|
||||
} catch (error) {
|
||||
fireEvent(this, "ui-mode-not-available", error);
|
||||
}
|
||||
if (this._actionData && this._actionData !== this.action.data) {
|
||||
if (this._yamlEditor) {
|
||||
this._yamlEditor.setValue(this.action.data);
|
||||
|
@ -18,6 +18,7 @@ import { Condition } from "../../../../data/automation";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "./ha-automation-condition-editor";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
|
||||
export interface ConditionElement extends LitElement {
|
||||
condition: Condition;
|
||||
@ -115,7 +116,10 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
private _switchYamlMode(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,13 @@ import { PaperListboxElement } from "@polymer/paper-listbox";
|
||||
const MODES = ["single", "restart", "queued", "parallel"];
|
||||
const MODES_MAX = ["queued", "parallel"];
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"ui-mode-not-available": Error;
|
||||
}
|
||||
}
|
||||
|
||||
export class HaAutomationEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
|
@ -34,6 +34,7 @@ import "./types/ha-automation-trigger-time";
|
||||
import "./types/ha-automation-trigger-time_pattern";
|
||||
import "./types/ha-automation-trigger-webhook";
|
||||
import "./types/ha-automation-trigger-zone";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
|
||||
const OPTIONS = [
|
||||
"device",
|
||||
@ -218,7 +219,10 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
private _switchYamlMode(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
|
24
src/panels/lovelace/common/structs/handle-errors.ts
Normal file
24
src/panels/lovelace/common/structs/handle-errors.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { StructError } from "superstruct";
|
||||
|
||||
export const handleStructError = (err: Error): string[] => {
|
||||
if (!(err instanceof StructError)) {
|
||||
return [err.message];
|
||||
}
|
||||
const errors: string[] = [];
|
||||
for (const failure of err.failures()) {
|
||||
if (failure.type === "never") {
|
||||
errors.push(
|
||||
`Key "${failure.path[0]}" is not supported by the UI editor.`
|
||||
);
|
||||
} else {
|
||||
errors.push(
|
||||
`The value of "${failure.path.join(
|
||||
"."
|
||||
)}" is not supported by the UI editor, we support "${
|
||||
failure.type
|
||||
}" but received "${JSON.stringify(failure.value)}".`
|
||||
);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
};
|
@ -1,9 +1,17 @@
|
||||
export function isEntityId(value: any): string | boolean {
|
||||
import { StructResult, StructContext, struct } from "superstruct";
|
||||
|
||||
const isEntityId = (value: unknown, context: StructContext): StructResult => {
|
||||
if (typeof value !== "string") {
|
||||
return "entity id should be a string";
|
||||
return [context.fail({ type: "string" })];
|
||||
}
|
||||
if (!value.includes(".")) {
|
||||
return "entity id should be in the format 'domain.entity'";
|
||||
return [
|
||||
context.fail({
|
||||
type: "entity id should be in the format 'domain.entity'",
|
||||
}),
|
||||
];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export const EntityId = struct("entity-id", isEntityId);
|
||||
|
@ -1,9 +1,17 @@
|
||||
export function isIcon(value: any): string | boolean {
|
||||
import { StructContext, StructResult, struct } from "superstruct";
|
||||
|
||||
const isIcon = (value: unknown, context: StructContext): StructResult => {
|
||||
if (typeof value !== "string") {
|
||||
return "icon should be a string";
|
||||
return [context.fail({ type: "string" })];
|
||||
}
|
||||
if (!value.includes(":")) {
|
||||
return "icon should be in the format 'mdi:icon'";
|
||||
return [
|
||||
context.fail({
|
||||
type: "icon should be in the format 'mdi:icon'",
|
||||
}),
|
||||
];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export const Icon = struct("icon", isIcon);
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { superstruct } from "superstruct";
|
||||
import { isEntityId } from "./is-entity-id";
|
||||
import { isIcon } from "./is-icon";
|
||||
|
||||
export const struct = superstruct({
|
||||
types: {
|
||||
"entity-id": isEntityId,
|
||||
icon: isIcon,
|
||||
},
|
||||
});
|
@ -26,6 +26,8 @@ import type { LovelaceCardEditor } from "../../types";
|
||||
import type { GUIModeChangedEvent } from "../types";
|
||||
import "../../../../components/ha-circular-progress";
|
||||
import { deepEqual } from "../../../../common/util/deep-equal";
|
||||
import { handleStructError } from "../../common/structs/handle-errors";
|
||||
import { GUISupportError } from "../gui-support-error";
|
||||
|
||||
export interface ConfigChangedEvent {
|
||||
config: LovelaceCardConfig;
|
||||
@ -69,7 +71,7 @@ export class HuiCardEditor extends LitElement {
|
||||
@internalProperty() private _error?: string;
|
||||
|
||||
// Warning: GUI editor can't handle configuration - ok to save
|
||||
@internalProperty() private _warning?: string;
|
||||
@internalProperty() private _warnings?: string[];
|
||||
|
||||
@internalProperty() private _loading = false;
|
||||
|
||||
@ -121,7 +123,7 @@ export class HuiCardEditor extends LitElement {
|
||||
}
|
||||
|
||||
public get hasWarning(): boolean {
|
||||
return this._warning !== undefined;
|
||||
return this._warnings !== undefined;
|
||||
}
|
||||
|
||||
public get hasError(): boolean {
|
||||
@ -194,10 +196,15 @@ export class HuiCardEditor extends LitElement {
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${this._warning
|
||||
${this._warnings
|
||||
? html`
|
||||
<div class="warning">
|
||||
${this._warning}
|
||||
UI editor is not supported for this config:
|
||||
<br />
|
||||
<ul>
|
||||
${this._warnings.map((warning) => html`<li>${warning}</li>`)}
|
||||
</ul>
|
||||
You can still edit your config in yaml.
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
@ -238,7 +245,7 @@ export class HuiCardEditor extends LitElement {
|
||||
let configElement = this._configElement;
|
||||
try {
|
||||
this._error = undefined;
|
||||
this._warning = undefined;
|
||||
this._warnings = undefined;
|
||||
|
||||
if (this._configElType !== cardType) {
|
||||
// If the card type has changed, we need to load a new GUI editor
|
||||
@ -254,7 +261,9 @@ export class HuiCardEditor extends LitElement {
|
||||
configElement = await elClass.getConfigElement();
|
||||
} else {
|
||||
configElement = undefined;
|
||||
throw Error(`WARNING: No visual editor available for: ${cardType}`);
|
||||
throw new GUISupportError(
|
||||
`No visual editor available for: ${cardType}`
|
||||
);
|
||||
}
|
||||
|
||||
this._configElement = configElement;
|
||||
@ -272,11 +281,14 @@ export class HuiCardEditor extends LitElement {
|
||||
try {
|
||||
this._configElement!.setConfig(this.value);
|
||||
} catch (err) {
|
||||
throw Error(`WARNING: ${err.message}`);
|
||||
throw new GUISupportError(
|
||||
"Config is not supported",
|
||||
handleStructError(err)
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.message.startsWith("WARNING:")) {
|
||||
this._warning = err.message.substr(8);
|
||||
if (err instanceof GUISupportError) {
|
||||
this._warnings = err.warnings ?? [err.message];
|
||||
} else {
|
||||
this._error = err;
|
||||
}
|
||||
@ -312,6 +324,9 @@ export class HuiCardEditor extends LitElement {
|
||||
.warning {
|
||||
color: var(--warning-color);
|
||||
}
|
||||
.warning ul {
|
||||
margin: 4px 0;
|
||||
}
|
||||
ha-circular-progress {
|
||||
display: block;
|
||||
margin: auto;
|
||||
|
@ -16,18 +16,18 @@ import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-icon";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { AlarmPanelCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { assert, object, string, optional, array } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
name: "string?",
|
||||
states: "array?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
states: optional(array()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["alarm_control_panel"];
|
||||
@ -40,7 +40,7 @@ export class HuiAlarmPanelCardEditor extends LitElement
|
||||
@internalProperty() private _config?: AlarmPanelCardConfig;
|
||||
|
||||
public setConfig(config: AlarmPanelCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -194,6 +194,7 @@ export class HuiAlarmPanelCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -13,7 +13,6 @@ import "../../../../components/ha-icon-input";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { ButtonCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
@ -27,19 +26,20 @@ import "../../../../components/ha-switch";
|
||||
import "../../../../components/ha-formfield";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import { assert, object, string, optional, boolean } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
name: "string?",
|
||||
show_name: "boolean?",
|
||||
icon: "string?",
|
||||
show_icon: "boolean?",
|
||||
icon_height: "string?",
|
||||
tap_action: struct.optional(actionConfigStruct),
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
theme: "string?",
|
||||
show_state: "boolean?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
show_name: optional(boolean()),
|
||||
icon: optional(string()),
|
||||
show_icon: optional(boolean()),
|
||||
icon_height: optional(string()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
theme: optional(string()),
|
||||
show_state: optional(boolean()),
|
||||
});
|
||||
|
||||
@customElement("hui-button-card-editor")
|
||||
@ -50,7 +50,7 @@ export class HuiButtonCardEditor extends LitElement
|
||||
@internalProperty() private _config?: ButtonCardConfig;
|
||||
|
||||
public setConfig(config: ButtonCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -258,6 +258,7 @@ export class HuiButtonCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
let newValue: string | undefined;
|
||||
|
@ -16,7 +16,6 @@ import "../../../../components/entity/ha-entity-picker";
|
||||
import { LovelaceConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { ConditionalCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import {
|
||||
ConfigChangedEvent,
|
||||
@ -24,16 +23,17 @@ import {
|
||||
} from "../card-editor/hui-card-editor";
|
||||
import "../card-editor/hui-card-picker";
|
||||
import { GUIModeChangedEvent } from "../types";
|
||||
import { string, any, object, optional, array, assert } from "superstruct";
|
||||
|
||||
const conditionStruct = struct({
|
||||
entity: "string",
|
||||
state: "string?",
|
||||
state_not: "string?",
|
||||
const conditionStruct = object({
|
||||
entity: string(),
|
||||
state: optional(string()),
|
||||
state_not: optional(string()),
|
||||
});
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
card: "any",
|
||||
conditions: struct.optional([conditionStruct]),
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
card: any(),
|
||||
conditions: optional(array(conditionStruct)),
|
||||
});
|
||||
|
||||
@customElement("hui-conditional-card-editor")
|
||||
@ -54,7 +54,8 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
@query("hui-card-editor") private _cardEditorEl?: HuiCardEditor;
|
||||
|
||||
public setConfig(config: ConditionalCardConfig): void {
|
||||
this._config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public refreshYamlEditor(focus) {
|
||||
@ -217,7 +218,7 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
}
|
||||
this._setMode(true);
|
||||
this._guiModeAvailable = true;
|
||||
this._config.card = ev.detail.config;
|
||||
this._config = { ...this._config, card: ev.detail.config };
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
@ -226,7 +227,7 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
this._config.card = ev.detail.config;
|
||||
this._config = { ...this._config, card: ev.detail.config };
|
||||
this._guiModeAvailable = ev.detail.guiModeAvailable;
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
@ -236,7 +237,8 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
this._config.card = {};
|
||||
this._config = { ...this._config, card: {} };
|
||||
// @ts-ignore
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
@ -245,10 +247,12 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
if (target.value === "" || !this._config) {
|
||||
return;
|
||||
}
|
||||
this._config.conditions.push({
|
||||
const conditions = [...this._config.conditions];
|
||||
conditions.push({
|
||||
entity: target.value,
|
||||
state: "",
|
||||
});
|
||||
this._config = { ...this._config, conditions };
|
||||
target.value = "";
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
@ -258,10 +262,11 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
if (!this._config || !target) {
|
||||
return;
|
||||
}
|
||||
const conditions = [...this._config.conditions];
|
||||
if (target.configValue === "entity" && target.value === "") {
|
||||
this._config.conditions.splice(target.index, 1);
|
||||
conditions.splice(target.index, 1);
|
||||
} else {
|
||||
const condition = this._config.conditions[target.index];
|
||||
const condition = { ...conditions[target.index] };
|
||||
if (target.configValue === "entity") {
|
||||
condition.entity = target.value;
|
||||
} else if (target.configValue === "state") {
|
||||
@ -281,8 +286,9 @@ export class HuiConditionalCardEditor extends LitElement
|
||||
delete condition.state_not;
|
||||
}
|
||||
}
|
||||
this._config.conditions[target.index] = condition;
|
||||
conditions[target.index] = condition;
|
||||
}
|
||||
this._config = { ...this._config, conditions };
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ import {
|
||||
EntitiesCardConfig,
|
||||
EntitiesCardEntityConfig,
|
||||
} from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { headerFooterConfigStructs } from "../../header-footer/types";
|
||||
@ -33,15 +32,24 @@ import {
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import {
|
||||
string,
|
||||
optional,
|
||||
object,
|
||||
boolean,
|
||||
array,
|
||||
union,
|
||||
assert,
|
||||
} from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string|number?",
|
||||
theme: "string?",
|
||||
show_header_toggle: "boolean?",
|
||||
entities: [entitiesConfigStruct],
|
||||
header: struct.optional(headerFooterConfigStructs),
|
||||
footer: struct.optional(headerFooterConfigStructs),
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(union([string(), boolean()])),
|
||||
theme: optional(string()),
|
||||
show_header_toggle: optional(boolean()),
|
||||
entities: array(entitiesConfigStruct),
|
||||
header: optional(headerFooterConfigStructs),
|
||||
footer: optional(headerFooterConfigStructs),
|
||||
});
|
||||
|
||||
@customElement("hui-entities-card-editor")
|
||||
@ -54,7 +62,7 @@ export class HuiEntitiesCardEditor extends LitElement
|
||||
@internalProperty() private _configEntities?: EntitiesCardEntityConfig[];
|
||||
|
||||
public setConfig(config: EntitiesCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
this._configEntities = processEditorEntities(config.entities);
|
||||
}
|
||||
@ -131,6 +139,7 @@ export class HuiEntitiesCardEditor extends LitElement
|
||||
this._configEntities = processEditorEntities(this._config.entities);
|
||||
} else if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -12,7 +12,6 @@ import { stateIcon } from "../../../../common/entity/state_icon";
|
||||
import "../../../../components/ha-icon-input";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { EntityCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
@ -20,16 +19,17 @@ import { headerFooterConfigStructs } from "../../header-footer/types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, object, optional, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
name: "string?",
|
||||
icon: "string?",
|
||||
attribute: "string?",
|
||||
unit: "string?",
|
||||
theme: "string?",
|
||||
footer: struct.optional(headerFooterConfigStructs),
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
icon: optional(string()),
|
||||
attribute: optional(string()),
|
||||
unit: optional(string()),
|
||||
theme: optional(string()),
|
||||
footer: optional(headerFooterConfigStructs),
|
||||
});
|
||||
|
||||
@customElement("hui-entity-card-editor")
|
||||
@ -40,7 +40,7 @@ export class HuiEntityCardEditor extends LitElement
|
||||
@internalProperty() private _config?: EntityCardConfig;
|
||||
|
||||
public setConfig(config: EntityCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -158,6 +158,7 @@ export class HuiEntityCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
let newValue: string | undefined;
|
||||
|
@ -14,23 +14,23 @@ import "../../../../components/ha-switch";
|
||||
import "../../../../components/ha-formfield";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { GaugeCardConfig, SeverityConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import { assert, object, string, optional, number } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
name: "string?",
|
||||
entity: "string?",
|
||||
unit: "string?",
|
||||
min: "number?",
|
||||
max: "number?",
|
||||
severity: "object?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
name: optional(string()),
|
||||
entity: optional(string()),
|
||||
unit: optional(string()),
|
||||
min: optional(number()),
|
||||
max: optional(number()),
|
||||
severity: optional(object()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["sensor"];
|
||||
@ -43,7 +43,7 @@ export class HuiGaugeCardEditor extends LitElement
|
||||
@internalProperty() private _config?: GaugeCardConfig;
|
||||
|
||||
public setConfig(config: GaugeCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -260,6 +260,7 @@ export class HuiGaugeCardEditor extends LitElement
|
||||
target.value === "" ||
|
||||
(target.type === "number" && isNaN(Number(target.value)))
|
||||
) {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
let value: any = target.value;
|
||||
|
@ -17,7 +17,6 @@ import "../../../../components/ha-switch";
|
||||
import "../../../../components/ha-formfield";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { ConfigEntity, GlanceCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
@ -29,16 +28,26 @@ import {
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import {
|
||||
string,
|
||||
union,
|
||||
object,
|
||||
optional,
|
||||
number,
|
||||
boolean,
|
||||
assert,
|
||||
array,
|
||||
} from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string|number?",
|
||||
theme: "string?",
|
||||
columns: "number?",
|
||||
show_name: "boolean?",
|
||||
show_state: "boolean?",
|
||||
show_icon: "boolean?",
|
||||
entities: [entitiesConfigStruct],
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(union([string(), number()])),
|
||||
theme: optional(string()),
|
||||
columns: optional(number()),
|
||||
show_name: optional(boolean()),
|
||||
show_state: optional(boolean()),
|
||||
show_icon: optional(boolean()),
|
||||
entities: array(entitiesConfigStruct),
|
||||
});
|
||||
|
||||
@customElement("hui-glance-card-editor")
|
||||
@ -51,7 +60,7 @@ export class HuiGlanceCardEditor extends LitElement
|
||||
@internalProperty() private _configEntities?: ConfigEntity[];
|
||||
|
||||
public setConfig(config: GlanceCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
this._configEntities = processEditorEntities(config.entities);
|
||||
}
|
||||
@ -191,6 +200,7 @@ export class HuiGlanceCardEditor extends LitElement
|
||||
target.value === "" ||
|
||||
(target.type === "number" && isNaN(Number(target.value)))
|
||||
) {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
let value: any = target.value;
|
||||
|
@ -10,28 +10,37 @@ import {
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HistoryGraphCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-entity-editor";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { processEditorEntities } from "../process-editor-entities";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import {
|
||||
assert,
|
||||
union,
|
||||
optional,
|
||||
string,
|
||||
object,
|
||||
array,
|
||||
number,
|
||||
} from "superstruct";
|
||||
import { EntityId } from "../../common/structs/is-entity-id";
|
||||
|
||||
const entitiesConfigStruct = struct.union([
|
||||
{
|
||||
entity: "entity-id",
|
||||
name: "string?",
|
||||
},
|
||||
"entity-id",
|
||||
const entitiesConfigStruct = union([
|
||||
object({
|
||||
entity: EntityId,
|
||||
name: optional(string()),
|
||||
}),
|
||||
EntityId,
|
||||
]);
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entities: [entitiesConfigStruct],
|
||||
title: "string?",
|
||||
hours_to_show: "number?",
|
||||
refresh_interval: "number?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entities: array(entitiesConfigStruct),
|
||||
title: optional(string()),
|
||||
hours_to_show: optional(number()),
|
||||
refresh_interval: optional(number()),
|
||||
});
|
||||
|
||||
@customElement("hui-history-graph-card-editor")
|
||||
@ -44,7 +53,7 @@ export class HuiHistoryGraphCardEditor extends LitElement
|
||||
@internalProperty() private _configEntities?: EntityConfig[];
|
||||
|
||||
public setConfig(config: HistoryGraphCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
this._configEntities = processEditorEntities(config.entities);
|
||||
}
|
||||
@ -131,6 +140,7 @@ export class HuiHistoryGraphCardEditor extends LitElement
|
||||
this._configEntities = processEditorEntities(this._config.entities);
|
||||
} else if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
let value: any = target.value;
|
||||
|
@ -11,17 +11,17 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HumidifierCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, object, optional, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string",
|
||||
name: "string?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: string(),
|
||||
name: optional(string()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["humidifier"];
|
||||
@ -34,7 +34,7 @@ export class HuiHumidifierCardEditor extends LitElement
|
||||
@internalProperty() private _config?: HumidifierCardConfig;
|
||||
|
||||
public setConfig(config: HumidifierCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ export class HuiHumidifierCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = { ...this._config, [target.configValue!]: target.value };
|
||||
|
@ -10,16 +10,16 @@ import {
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { IframeCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, assert, object, optional } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string?",
|
||||
url: "string?",
|
||||
aspect_ratio: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(string()),
|
||||
url: optional(string()),
|
||||
aspect_ratio: optional(string()),
|
||||
});
|
||||
|
||||
@customElement("hui-iframe-card-editor")
|
||||
@ -30,7 +30,7 @@ export class HuiIframeCardEditor extends LitElement
|
||||
@internalProperty() private _config?: IframeCardConfig;
|
||||
|
||||
public setConfig(config: IframeCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ export class HuiIframeCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = { ...this._config, [target.configValue!]: value };
|
||||
|
@ -13,7 +13,6 @@ import "../../../../components/ha-icon-input";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LightCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
@ -24,15 +23,16 @@ import {
|
||||
EntitiesEditorEvent,
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, object, optional, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
name: "string?",
|
||||
entity: "string?",
|
||||
theme: "string?",
|
||||
icon: "string?",
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
double_tap_action: struct.optional(actionConfigStruct),
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
name: optional(string()),
|
||||
entity: optional(string()),
|
||||
theme: optional(string()),
|
||||
icon: optional(string()),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
double_tap_action: optional(actionConfigStruct),
|
||||
});
|
||||
|
||||
const includeDomains = ["light"];
|
||||
@ -45,7 +45,8 @@ export class HuiLightCardEditor extends LitElement
|
||||
@internalProperty() private _config?: LightCardConfig;
|
||||
|
||||
public setConfig(config: LightCardConfig): void {
|
||||
this._config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
get _name(): string {
|
||||
@ -177,6 +178,7 @@ export class HuiLightCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -13,7 +13,6 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { PolymerChangedEvent } from "../../../../polymer-types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { MapCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-input-list-editor";
|
||||
import { EntityConfig } from "../../entity-rows/types";
|
||||
@ -28,16 +27,25 @@ import "../../../../components/ha-switch";
|
||||
import "../../../../components/ha-formfield";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import {
|
||||
string,
|
||||
optional,
|
||||
object,
|
||||
number,
|
||||
boolean,
|
||||
array,
|
||||
assert,
|
||||
} from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string?",
|
||||
aspect_ratio: "string?",
|
||||
default_zoom: "number?",
|
||||
dark_mode: "boolean?",
|
||||
entities: [entitiesConfigStruct],
|
||||
hours_to_show: "number?",
|
||||
geo_location_sources: "array?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(string()),
|
||||
aspect_ratio: optional(string()),
|
||||
default_zoom: optional(number()),
|
||||
dark_mode: optional(boolean()),
|
||||
entities: array(entitiesConfigStruct),
|
||||
hours_to_show: optional(number()),
|
||||
geo_location_sources: optional(array()),
|
||||
});
|
||||
|
||||
@customElement("hui-map-card-editor")
|
||||
@ -49,7 +57,7 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
|
||||
@internalProperty() private _configEntities?: EntityConfig[];
|
||||
|
||||
public setConfig(config: MapCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
this._configEntities = config.entities
|
||||
? processEditorEntities(config.entities)
|
||||
@ -195,6 +203,7 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
|
||||
value = Number(value);
|
||||
}
|
||||
if (target.value === "" || (target.type === "number" && isNaN(value))) {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else if (target.configValue) {
|
||||
this._config = {
|
||||
|
@ -11,17 +11,17 @@ import {
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { MarkdownCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, assert, object, optional } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string?",
|
||||
content: "string",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(string()),
|
||||
content: string(),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
@customElement("hui-markdown-card-editor")
|
||||
@ -32,7 +32,7 @@ export class HuiMarkdownCardEditor extends LitElement
|
||||
@internalProperty() private _config?: MarkdownCardConfig;
|
||||
|
||||
public setConfig(config: MarkdownCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -100,6 +100,7 @@ export class HuiMarkdownCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "" && target.configValue !== "content") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -10,13 +10,13 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { MediaControlCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { assert, object, string, optional } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["media_player"];
|
||||
@ -29,7 +29,7 @@ export class HuiMediaControlCardEditor extends LitElement
|
||||
@internalProperty() private _config?: MediaControlCardConfig;
|
||||
|
||||
public setConfig(config: MediaControlCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -71,6 +71,7 @@ export class HuiMediaControlCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -11,7 +11,6 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { PictureCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
@ -21,13 +20,14 @@ import {
|
||||
EntitiesEditorEvent,
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, object, optional, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
image: "string?",
|
||||
tap_action: struct.optional(actionConfigStruct),
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
image: optional(string()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
@customElement("hui-picture-card-editor")
|
||||
@ -38,7 +38,7 @@ export class HuiPictureCardEditor extends LitElement
|
||||
@internalProperty() private _config?: PictureCardConfig;
|
||||
|
||||
public setConfig(config: PictureCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -128,6 +128,7 @@ export class HuiPictureCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -16,7 +16,6 @@ import "../../../../components/ha-formfield";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { PictureEntityCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
@ -28,20 +27,21 @@ import {
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import { assert, object, string, optional, boolean } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string",
|
||||
image: "string?",
|
||||
name: "string?",
|
||||
camera_image: "string?",
|
||||
camera_view: "string?",
|
||||
aspect_ratio: "string?",
|
||||
tap_action: struct.optional(actionConfigStruct),
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
show_name: "boolean?",
|
||||
show_state: "boolean?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: string(),
|
||||
image: optional(string()),
|
||||
name: optional(string()),
|
||||
camera_image: optional(string()),
|
||||
camera_view: optional(string()),
|
||||
aspect_ratio: optional(string()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
show_name: optional(boolean()),
|
||||
show_state: optional(boolean()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["camera"];
|
||||
@ -54,7 +54,7 @@ export class HuiPictureEntityCardEditor extends LitElement
|
||||
@internalProperty() private _config?: PictureEntityCardConfig;
|
||||
|
||||
public setConfig(config: PictureEntityCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -275,6 +275,7 @@ export class HuiPictureEntityCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -15,7 +15,6 @@ import "../../../../components/entity/ha-entity-picker";
|
||||
import { ActionConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { PictureGlanceCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-action-editor";
|
||||
import "../../components/hui-entity-editor";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
@ -29,19 +28,20 @@ import {
|
||||
EntitiesEditorEvent,
|
||||
} from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { assert, string, object, optional, array } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string?",
|
||||
entity: "string?",
|
||||
image: "string?",
|
||||
camera_image: "string?",
|
||||
camera_view: "string?",
|
||||
aspect_ratio: "string?",
|
||||
tap_action: struct.optional(actionConfigStruct),
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
entities: [entitiesConfigStruct],
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(string()),
|
||||
entity: optional(string()),
|
||||
image: optional(string()),
|
||||
camera_image: optional(string()),
|
||||
camera_view: optional(string()),
|
||||
aspect_ratio: optional(string()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
entities: array(entitiesConfigStruct),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["camera"];
|
||||
@ -56,7 +56,7 @@ export class HuiPictureGlanceCardEditor extends LitElement
|
||||
@internalProperty() private _configEntities?: EntityConfig[];
|
||||
|
||||
public setConfig(config: PictureGlanceCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
this._configEntities = processEditorEntities(config.entities);
|
||||
}
|
||||
@ -262,6 +262,7 @@ export class HuiPictureGlanceCardEditor extends LitElement
|
||||
}
|
||||
|
||||
if (value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -12,17 +12,17 @@ import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-icon";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { PlantStatusCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { assert, object, string, optional } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string",
|
||||
name: "string?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: string(),
|
||||
name: optional(string()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["plant"];
|
||||
@ -35,7 +35,7 @@ export class HuiPlantStatusCardEditor extends LitElement
|
||||
@internalProperty() private _config?: PlantStatusCardConfig;
|
||||
|
||||
public setConfig(config: PlantStatusCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ export class HuiPlantStatusCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -16,22 +16,22 @@ import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-icon-input";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { SensorCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { string, assert, object, optional, number } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
name: "string?",
|
||||
icon: "string?",
|
||||
graph: "string?",
|
||||
unit: "string?",
|
||||
detail: "number?",
|
||||
theme: "string?",
|
||||
hours_to_show: "number?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
icon: optional(string()),
|
||||
graph: optional(string()),
|
||||
unit: optional(string()),
|
||||
detail: optional(number()),
|
||||
theme: optional(string()),
|
||||
hours_to_show: optional(number()),
|
||||
});
|
||||
|
||||
const includeDomains = ["sensor"];
|
||||
@ -44,7 +44,7 @@ export class HuiSensorCardEditor extends LitElement
|
||||
@internalProperty() private _config?: SensorCardConfig;
|
||||
|
||||
public setConfig(config: SensorCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -205,6 +205,7 @@ export class HuiSensorCardEditor extends LitElement
|
||||
target.value === "" ||
|
||||
(target.type === "number" && isNaN(Number(target.value)))
|
||||
) {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
let value: any = target.value;
|
||||
|
@ -13,15 +13,15 @@ import { isComponentLoaded } from "../../../../common/config/is_component_loaded
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { ShoppingListCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { string, assert, object, optional } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
title: "string?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
title: optional(string()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
@customElement("hui-shopping-list-card-editor")
|
||||
@ -32,7 +32,7 @@ export class HuiShoppingListEditor extends LitElement
|
||||
@internalProperty() private _config?: ShoppingListCardConfig;
|
||||
|
||||
public setConfig(config: ShoppingListCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ export class HuiShoppingListEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
@ -16,7 +16,6 @@ import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import { LovelaceConfig } from "../../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { StackCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import {
|
||||
ConfigChangedEvent,
|
||||
@ -24,11 +23,12 @@ import {
|
||||
} from "../card-editor/hui-card-editor";
|
||||
import "../card-editor/hui-card-picker";
|
||||
import { GUIModeChangedEvent } from "../types";
|
||||
import { assert, object, string, array, any, optional } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
cards: ["any"],
|
||||
title: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
cards: array(any()),
|
||||
title: optional(string()),
|
||||
});
|
||||
|
||||
@customElement("hui-stack-card-editor")
|
||||
@ -48,8 +48,9 @@ export class HuiStackCardEditor extends LitElement
|
||||
|
||||
@query("hui-card-editor") private _cardEditorEl?: HuiCardEditor;
|
||||
|
||||
public setConfig(config: StackCardConfig): void {
|
||||
this._config = cardConfigStruct(config);
|
||||
public setConfig(config: Readonly<StackCardConfig>): void {
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public refreshYamlEditor(focus) {
|
||||
@ -162,7 +163,9 @@ export class HuiStackCardEditor extends LitElement
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
this._config.cards[this._selectedCard] = ev.detail.config;
|
||||
const cards = [...this._config.cards];
|
||||
cards[this._selectedCard] = ev.detail.config;
|
||||
this._config = { ...this._config, cards };
|
||||
this._guiModeAvailable = ev.detail.guiModeAvailable;
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
@ -173,7 +176,8 @@ export class HuiStackCardEditor extends LitElement
|
||||
return;
|
||||
}
|
||||
const config = ev.detail.config;
|
||||
this._config.cards.push(config);
|
||||
const cards = [...this._config.cards, config];
|
||||
this._config = { ...this._config, cards };
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
@ -181,7 +185,9 @@ export class HuiStackCardEditor extends LitElement
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
this._config.cards.splice(this._selectedCard, 1);
|
||||
const cards = [...this._config.cards];
|
||||
cards.splice(this._selectedCard, 1);
|
||||
this._config = { ...this._config, cards };
|
||||
this._selectedCard = Math.max(0, this._selectedCard - 1);
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
@ -192,8 +198,13 @@ export class HuiStackCardEditor extends LitElement
|
||||
}
|
||||
const source = this._selectedCard;
|
||||
const target = ev.target.id === "move-before" ? source - 1 : source + 1;
|
||||
const card = this._config.cards.splice(this._selectedCard, 1)[0];
|
||||
this._config.cards.splice(target, 0, card);
|
||||
const cards = [...this._config.cards];
|
||||
const card = cards.splice(this._selectedCard, 1)[0];
|
||||
cards.splice(target, 0, card);
|
||||
this._config = {
|
||||
...this._config,
|
||||
cards,
|
||||
};
|
||||
this._selectedCard = target;
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
@ -11,17 +11,17 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { ThermostatCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { object, string, optional, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string",
|
||||
name: "string?",
|
||||
theme: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: string(),
|
||||
name: optional(string()),
|
||||
theme: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["climate"];
|
||||
@ -34,7 +34,7 @@ export class HuiThermostatCardEditor extends LitElement
|
||||
@internalProperty() private _config?: ThermostatCardConfig;
|
||||
|
||||
public setConfig(config: ThermostatCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ export class HuiThermostatCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = { ...this._config, [target.configValue!]: target.value };
|
||||
|
@ -12,20 +12,20 @@ import "../../../../components/ha-switch";
|
||||
import "../../../../components/ha-formfield";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { WeatherForecastCardConfig } from "../../cards/types";
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import "../../components/hui-theme-select-editor";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import { object, string, optional, boolean, assert } from "superstruct";
|
||||
|
||||
const cardConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string?",
|
||||
name: "string?",
|
||||
theme: "string?",
|
||||
show_forecast: "boolean?",
|
||||
secondary_info_attribute: "string?",
|
||||
const cardConfigStruct = object({
|
||||
type: string(),
|
||||
entity: optional(string()),
|
||||
name: optional(string()),
|
||||
theme: optional(string()),
|
||||
show_forecast: optional(boolean()),
|
||||
secondary_info_attribute: optional(string()),
|
||||
});
|
||||
|
||||
const includeDomains = ["weather"];
|
||||
@ -38,7 +38,7 @@ export class HuiWeatherForecastCardEditor extends LitElement
|
||||
@internalProperty() private _config?: WeatherForecastCardConfig;
|
||||
|
||||
public setConfig(config: WeatherForecastCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
@ -139,6 +139,7 @@ export class HuiWeatherForecastCardEditor extends LitElement
|
||||
}
|
||||
if (target.configValue) {
|
||||
if (target.value === "") {
|
||||
this._config = { ...this._config };
|
||||
delete this._config[target.configValue!];
|
||||
} else {
|
||||
this._config = {
|
||||
|
9
src/panels/lovelace/editor/gui-support-error.ts
Normal file
9
src/panels/lovelace/editor/gui-support-error.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export class GUISupportError extends Error {
|
||||
public warnings?: string[] = [];
|
||||
|
||||
constructor(message: string, warnings?: string[]) {
|
||||
super(message);
|
||||
this.name = "GUISupportError";
|
||||
this.warnings = warnings;
|
||||
}
|
||||
}
|
@ -4,8 +4,10 @@ import {
|
||||
LovelaceViewConfig,
|
||||
ShowViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { struct } from "../common/structs/struct";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { optional, string, object, union } from "superstruct";
|
||||
import { EntityId } from "../common/structs/is-entity-id";
|
||||
import { Icon } from "../common/structs/is-icon";
|
||||
|
||||
export interface YamlChangedEvent extends Event {
|
||||
detail: {
|
||||
@ -66,19 +68,19 @@ export interface CardPickTarget extends EventTarget {
|
||||
config: LovelaceCardConfig;
|
||||
}
|
||||
|
||||
export const actionConfigStruct = struct({
|
||||
action: "string",
|
||||
navigation_path: "string?",
|
||||
url_path: "string?",
|
||||
service: "string?",
|
||||
service_data: "object?",
|
||||
export const actionConfigStruct = object({
|
||||
action: string(),
|
||||
navigation_path: optional(string()),
|
||||
url_path: optional(string()),
|
||||
service: optional(string()),
|
||||
service_data: optional(object()),
|
||||
});
|
||||
|
||||
export const entitiesConfigStruct = struct.union([
|
||||
{
|
||||
entity: "entity-id",
|
||||
name: "string?",
|
||||
icon: "icon?",
|
||||
},
|
||||
"entity-id",
|
||||
export const entitiesConfigStruct = union([
|
||||
object({
|
||||
entity: EntityId,
|
||||
name: optional(string()),
|
||||
icon: optional(Icon),
|
||||
}),
|
||||
EntityId,
|
||||
]);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
import { struct } from "../common/structs/struct";
|
||||
import { object, optional, union, string, number, array } from "superstruct";
|
||||
import { actionConfigStruct, entitiesConfigStruct } from "../editor/types";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
|
||||
@ -24,27 +24,27 @@ export interface PictureHeaderFooterConfig extends LovelaceHeaderFooterConfig {
|
||||
double_tap_action?: ActionConfig;
|
||||
}
|
||||
|
||||
export const pictureHeaderFooterConfigStruct = struct({
|
||||
type: "string",
|
||||
image: "string",
|
||||
tap_action: struct.optional(actionConfigStruct),
|
||||
hold_action: struct.optional(actionConfigStruct),
|
||||
double_tap_action: struct.optional(actionConfigStruct),
|
||||
export const pictureHeaderFooterConfigStruct = object({
|
||||
type: string(),
|
||||
image: string(),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
hold_action: optional(actionConfigStruct),
|
||||
double_tap_action: optional(actionConfigStruct),
|
||||
});
|
||||
|
||||
export const buttonsHeaderFooterConfigStruct = struct({
|
||||
type: "string",
|
||||
entities: [entitiesConfigStruct],
|
||||
export const buttonsHeaderFooterConfigStruct = object({
|
||||
type: string(),
|
||||
entities: array(entitiesConfigStruct),
|
||||
});
|
||||
|
||||
export const graphHeaderFooterConfigStruct = struct({
|
||||
type: "string",
|
||||
entity: "string",
|
||||
detail: "number?",
|
||||
hours_to_show: "number?",
|
||||
export const graphHeaderFooterConfigStruct = object({
|
||||
type: string(),
|
||||
entity: string(),
|
||||
detail: optional(string()),
|
||||
hours_to_show: optional(number()),
|
||||
});
|
||||
|
||||
export const headerFooterConfigStructs = struct.union([
|
||||
export const headerFooterConfigStructs = union([
|
||||
pictureHeaderFooterConfigStruct,
|
||||
buttonsHeaderFooterConfigStruct,
|
||||
graphHeaderFooterConfigStruct,
|
||||
|
@ -27,12 +27,12 @@ import {
|
||||
} from "../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { struct } from "./common/structs/struct";
|
||||
import type { Lovelace } from "./types";
|
||||
import { optional, array, string, object, type, assert } from "superstruct";
|
||||
|
||||
const lovelaceStruct = struct.interface({
|
||||
title: "string?",
|
||||
views: ["object"],
|
||||
const lovelaceStruct = type({
|
||||
title: optional(string()),
|
||||
views: array(object()),
|
||||
});
|
||||
|
||||
@customElement("hui-editor")
|
||||
@ -251,7 +251,7 @@ class LovelaceFullConfigEditor extends LitElement {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config = lovelaceStruct(config);
|
||||
assert(config, lovelaceStruct);
|
||||
} catch (err) {
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
|
@ -34,7 +34,7 @@ documentContainer.innerHTML = `<custom-style>
|
||||
--scrollbar-thumb-color: rgb(194, 194, 194);
|
||||
|
||||
--error-color: #db4437;
|
||||
--warning-color: #f4b400;
|
||||
--warning-color: #FF9800;
|
||||
--success-color: #0f9d58;
|
||||
--info-color: #4285f4;
|
||||
|
||||
|
45
yarn.lock
45
yarn.lock
@ -4411,16 +4411,6 @@ clone-buffer@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
|
||||
integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
|
||||
|
||||
clone-deep@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
|
||||
integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
|
||||
dependencies:
|
||||
for-own "^1.0.0"
|
||||
is-plain-object "^2.0.4"
|
||||
kind-of "^6.0.0"
|
||||
shallow-clone "^1.0.0"
|
||||
|
||||
clone-stats@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
|
||||
@ -6163,11 +6153,6 @@ follow-redirects@^1.0.0:
|
||||
dependencies:
|
||||
debug "^3.2.6"
|
||||
|
||||
for-in@^0.1.3:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
|
||||
integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
|
||||
|
||||
for-in@^1.0.1, for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
@ -7706,7 +7691,7 @@ kind-of@^5.0.0, kind-of@^5.0.2:
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
|
||||
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
||||
|
||||
kind-of@^6.0.0, kind-of@^6.0.1, kind-of@^6.0.2:
|
||||
kind-of@^6.0.0, kind-of@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
||||
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
|
||||
@ -8628,14 +8613,6 @@ mixin-deep@^1.2.0:
|
||||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mixin-object@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
|
||||
integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
|
||||
dependencies:
|
||||
for-in "^0.1.3"
|
||||
is-extendable "^0.1.1"
|
||||
|
||||
mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
@ -10785,15 +10762,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
shallow-clone@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
|
||||
integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
|
||||
dependencies:
|
||||
is-extendable "^0.1.1"
|
||||
kind-of "^5.0.0"
|
||||
mixin-object "^2.0.1"
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
@ -11300,13 +11268,10 @@ subarg@^1.0.0:
|
||||
dependencies:
|
||||
minimist "^1.1.0"
|
||||
|
||||
superstruct@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.6.1.tgz#148fc3d627bb59fcfe24aa1bd2a1b8c51b1db072"
|
||||
integrity sha512-LDbOKL5sNbOJ00Q36iYRhSexKIptZje0/mhNznnz04wT9CmsPDZg/K/UV1dgYuCwNMuOBHTbVROZsGB9EhhK4w==
|
||||
dependencies:
|
||||
clone-deep "^2.0.1"
|
||||
kind-of "^6.0.1"
|
||||
superstruct@^0.10.12:
|
||||
version "0.10.12"
|
||||
resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.10.12.tgz#7b2c8adaf61b75257265eac3b588f30017f996f0"
|
||||
integrity sha512-FiNhfegyytDI0QxrrEoeGknFM28SnoHqCBpkWewUm8jRNj74NVxLpiiePvkOo41Ze/aKMSHa/twWjNF81mKaQQ==
|
||||
|
||||
supports-color@6.0.0:
|
||||
version "6.0.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user