mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 07:16:39 +00:00
Collapsible blueprint input sections (#19946)
* Deduplicate blueprint editor code * Collapsible blueprint sections * add description * renamed collapsed * unused import * unused import * Don't allow collapsing sections with required * Update to new schema
This commit is contained in:
parent
f1345af526
commit
a629f01300
@ -21,6 +21,8 @@ export class HaExpansionPanel extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean, reflect: true }) leftChevron = false;
|
@property({ type: Boolean, reflect: true }) leftChevron = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) noCollapse = false;
|
||||||
|
|
||||||
@property() header?: string;
|
@property() header?: string;
|
||||||
|
|
||||||
@property() secondary?: string;
|
@property() secondary?: string;
|
||||||
@ -34,16 +36,17 @@ export class HaExpansionPanel extends LitElement {
|
|||||||
<div class="top ${classMap({ expanded: this.expanded })}">
|
<div class="top ${classMap({ expanded: this.expanded })}">
|
||||||
<div
|
<div
|
||||||
id="summary"
|
id="summary"
|
||||||
|
class=${classMap({ noCollapse: this.noCollapse })}
|
||||||
@click=${this._toggleContainer}
|
@click=${this._toggleContainer}
|
||||||
@keydown=${this._toggleContainer}
|
@keydown=${this._toggleContainer}
|
||||||
@focus=${this._focusChanged}
|
@focus=${this._focusChanged}
|
||||||
@blur=${this._focusChanged}
|
@blur=${this._focusChanged}
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex=${this.noCollapse ? -1 : 0}
|
||||||
aria-expanded=${this.expanded}
|
aria-expanded=${this.expanded}
|
||||||
aria-controls="sect1"
|
aria-controls="sect1"
|
||||||
>
|
>
|
||||||
${this.leftChevron
|
${this.leftChevron && !this.noCollapse
|
||||||
? html`
|
? html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
.path=${mdiChevronDown}
|
.path=${mdiChevronDown}
|
||||||
@ -57,7 +60,7 @@ export class HaExpansionPanel extends LitElement {
|
|||||||
<slot class="secondary" name="secondary">${this.secondary}</slot>
|
<slot class="secondary" name="secondary">${this.secondary}</slot>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
${!this.leftChevron
|
${!this.leftChevron && !this.noCollapse
|
||||||
? html`
|
? html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
.path=${mdiChevronDown}
|
.path=${mdiChevronDown}
|
||||||
@ -106,6 +109,9 @@ export class HaExpansionPanel extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
if (this.noCollapse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const newExpanded = !this.expanded;
|
const newExpanded = !this.expanded;
|
||||||
fireEvent(this, "expanded-will-change", { expanded: newExpanded });
|
fireEvent(this, "expanded-will-change", { expanded: newExpanded });
|
||||||
this._container.style.overflow = "hidden";
|
this._container.style.overflow = "hidden";
|
||||||
@ -130,6 +136,9 @@ export class HaExpansionPanel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _focusChanged(ev) {
|
private _focusChanged(ev) {
|
||||||
|
if (this.noCollapse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.shadowRoot!.querySelector(".top")!.classList.toggle(
|
this.shadowRoot!.querySelector(".top")!.classList.toggle(
|
||||||
"focused",
|
"focused",
|
||||||
ev.type === "focus"
|
ev.type === "focus"
|
||||||
@ -191,6 +200,9 @@ export class HaExpansionPanel extends LitElement {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
#summary.noCollapse {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.summary-icon.expanded {
|
.summary-icon.expanded {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
|
@ -13,7 +13,7 @@ export interface Blueprint {
|
|||||||
export interface BlueprintMetaData {
|
export interface BlueprintMetaData {
|
||||||
domain: BlueprintDomain;
|
domain: BlueprintDomain;
|
||||||
name: string;
|
name: string;
|
||||||
input?: Record<string, BlueprintInput | null>;
|
input?: Record<string, BlueprintInput | BlueprintInputSection | null>;
|
||||||
description?: string;
|
description?: string;
|
||||||
source_url?: string;
|
source_url?: string;
|
||||||
author?: string;
|
author?: string;
|
||||||
@ -26,6 +26,14 @@ export interface BlueprintInput {
|
|||||||
default?: any;
|
default?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BlueprintInputSection {
|
||||||
|
name?: string;
|
||||||
|
icon?: string;
|
||||||
|
description?: string;
|
||||||
|
collapsed?: boolean;
|
||||||
|
input: Record<string, BlueprintInput | null>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BlueprintImportResult {
|
export interface BlueprintImportResult {
|
||||||
suggested_filename: string;
|
suggested_filename: string;
|
||||||
raw_data: string;
|
raw_data: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { nestedArrayMove } from "../../../common/util/array-move";
|
import { nestedArrayMove } from "../../../common/util/array-move";
|
||||||
@ -11,7 +11,12 @@ import "../../../components/ha-markdown";
|
|||||||
import "../../../components/ha-selector/ha-selector";
|
import "../../../components/ha-selector/ha-selector";
|
||||||
import "../../../components/ha-settings-row";
|
import "../../../components/ha-settings-row";
|
||||||
import { BlueprintAutomationConfig } from "../../../data/automation";
|
import { BlueprintAutomationConfig } from "../../../data/automation";
|
||||||
import { BlueprintOrError, Blueprints } from "../../../data/blueprint";
|
import {
|
||||||
|
BlueprintInput,
|
||||||
|
BlueprintInputSection,
|
||||||
|
BlueprintOrError,
|
||||||
|
Blueprints,
|
||||||
|
} from "../../../data/blueprint";
|
||||||
import { BlueprintScriptConfig } from "../../../data/script";
|
import { BlueprintScriptConfig } from "../../../data/script";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
@ -46,6 +51,7 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
|
|||||||
|
|
||||||
protected renderCard() {
|
protected renderCard() {
|
||||||
const blueprint = this._blueprint;
|
const blueprint = this._blueprint;
|
||||||
|
let border = true;
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
outlined
|
outlined
|
||||||
@ -91,44 +97,14 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
|
|||||||
Object.keys(blueprint.metadata.input).length
|
Object.keys(blueprint.metadata.input).length
|
||||||
? Object.entries(blueprint.metadata.input).map(
|
? Object.entries(blueprint.metadata.input).map(
|
||||||
([key, value]) => {
|
([key, value]) => {
|
||||||
const selector = value?.selector ?? { text: undefined };
|
if (value && "input" in value) {
|
||||||
const type = Object.keys(selector)[0];
|
const section = this.renderSection(key, value);
|
||||||
const enhancedSelector = [
|
border = false;
|
||||||
"action",
|
return section;
|
||||||
"condition",
|
}
|
||||||
"trigger",
|
const row = this.renderSettingRow(key, value, border);
|
||||||
].includes(type)
|
border = true;
|
||||||
? {
|
return row;
|
||||||
[type]: {
|
|
||||||
...selector[type],
|
|
||||||
path: [key],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: selector;
|
|
||||||
|
|
||||||
return html`<ha-settings-row .narrow=${this.narrow}>
|
|
||||||
<span slot="heading">${value?.name || key}</span>
|
|
||||||
<ha-markdown
|
|
||||||
slot="description"
|
|
||||||
class="card-content"
|
|
||||||
breaks
|
|
||||||
.content=${value?.description}
|
|
||||||
></ha-markdown>
|
|
||||||
${html`<ha-selector
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selector=${enhancedSelector}
|
|
||||||
.key=${key}
|
|
||||||
.disabled=${this.disabled}
|
|
||||||
.required=${value?.default === undefined}
|
|
||||||
.placeholder=${value?.default}
|
|
||||||
.value=${this._config.use_blueprint.input &&
|
|
||||||
key in this._config.use_blueprint.input
|
|
||||||
? this._config.use_blueprint.input[key]
|
|
||||||
: value?.default}
|
|
||||||
@value-changed=${this._inputChanged}
|
|
||||||
@item-moved=${this._itemMoved}
|
|
||||||
></ha-selector>`}
|
|
||||||
</ha-settings-row>`;
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
: html`<p class="padding">
|
: html`<p class="padding">
|
||||||
@ -141,6 +117,85 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderSection(sectionKey: string, section: BlueprintInputSection) {
|
||||||
|
const title = section?.name || sectionKey;
|
||||||
|
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
|
||||||
|
outlined
|
||||||
|
.expanded=${expanded}
|
||||||
|
.noCollapse=${anyRequired}
|
||||||
|
>
|
||||||
|
<div slot="header" role="heading" aria-level="3" class="section-header">
|
||||||
|
${section?.icon
|
||||||
|
? html` <ha-icon
|
||||||
|
class="section-header"
|
||||||
|
.icon=${section.icon}
|
||||||
|
></ha-icon>`
|
||||||
|
: nothing}
|
||||||
|
<ha-markdown .content=${title}></ha-markdown>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
${section?.description
|
||||||
|
? html`<ha-markdown .content=${section.description}></ha-markdown>`
|
||||||
|
: nothing}
|
||||||
|
${section.input
|
||||||
|
? Object.entries(section.input).map(([key, value]) =>
|
||||||
|
this.renderSettingRow(key, value, true)
|
||||||
|
)
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderSettingRow(
|
||||||
|
key: string,
|
||||||
|
value: BlueprintInput | null,
|
||||||
|
border: boolean
|
||||||
|
) {
|
||||||
|
const selector = value?.selector ?? { text: undefined };
|
||||||
|
const type = Object.keys(selector)[0];
|
||||||
|
const enhancedSelector = ["action", "condition", "trigger"].includes(type)
|
||||||
|
? {
|
||||||
|
[type]: {
|
||||||
|
...selector[type],
|
||||||
|
path: [key],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: selector;
|
||||||
|
return html`<ha-settings-row
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
class=${border ? "border" : ""}
|
||||||
|
>
|
||||||
|
<span slot="heading">${value?.name || key}</span>
|
||||||
|
<ha-markdown
|
||||||
|
slot="description"
|
||||||
|
class="card-content"
|
||||||
|
breaks
|
||||||
|
.content=${value?.description}
|
||||||
|
></ha-markdown>
|
||||||
|
${html`<ha-selector
|
||||||
|
.hass=${this.hass}
|
||||||
|
.selector=${enhancedSelector}
|
||||||
|
.key=${key}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
.required=${value?.default === undefined}
|
||||||
|
.placeholder=${value?.default}
|
||||||
|
.value=${this._config.use_blueprint.input &&
|
||||||
|
key in this._config.use_blueprint.input
|
||||||
|
? this._config.use_blueprint.input[key]
|
||||||
|
: value?.default}
|
||||||
|
@value-changed=${this._inputChanged}
|
||||||
|
@item-moved=${this._itemMoved}
|
||||||
|
></ha-selector>`}
|
||||||
|
</ha-settings-row>`;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract _getBlueprints();
|
protected abstract _getBlueprints();
|
||||||
|
|
||||||
private _blueprintChanged(ev) {
|
private _blueprintChanged(ev) {
|
||||||
@ -219,6 +274,7 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
|
|||||||
}
|
}
|
||||||
ha-card.blueprint {
|
ha-card.blueprint {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
margin-bottom: 64px;
|
||||||
}
|
}
|
||||||
.padding {
|
.padding {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -253,8 +309,15 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
|
|||||||
--paper-time-input-justify-content: flex-end;
|
--paper-time-input-justify-content: flex-end;
|
||||||
--settings-row-content-width: 100%;
|
--settings-row-content-width: 100%;
|
||||||
--settings-row-prefix-display: contents;
|
--settings-row-prefix-display: contents;
|
||||||
|
}
|
||||||
|
ha-settings-row.border {
|
||||||
border-top: 1px solid var(--divider-color);
|
border-top: 1px solid var(--divider-color);
|
||||||
}
|
}
|
||||||
|
ha-expansion-panel {
|
||||||
|
margin: 8px;
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
ha-alert {
|
ha-alert {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
display: block;
|
display: block;
|
||||||
@ -263,6 +326,13 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
|
|||||||
border-radius: var(--ha-card-border-radius, 12px);
|
border-radius: var(--ha-card-border-radius, 12px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
div.section-header {
|
||||||
|
display: flex;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
ha-icon.section-header {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user