Skip to content

Commit

Permalink
Collapsible blueprint input sections (#19946)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
karwosts authored May 29, 2024
1 parent f1345af commit a629f01
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 44 deletions.
18 changes: 15 additions & 3 deletions src/components/ha-expansion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export class HaExpansionPanel extends LitElement {

@property({ type: Boolean, reflect: true }) leftChevron = false;

@property({ type: Boolean, reflect: true }) noCollapse = false;

@property() header?: string;

@property() secondary?: string;
Expand All @@ -34,16 +36,17 @@ export class HaExpansionPanel extends LitElement {
<div class="top ${classMap({ expanded: this.expanded })}">
<div
id="summary"
class=${classMap({ noCollapse: this.noCollapse })}
@click=${this._toggleContainer}
@keydown=${this._toggleContainer}
@focus=${this._focusChanged}
@blur=${this._focusChanged}
role="button"
tabindex="0"
tabindex=${this.noCollapse ? -1 : 0}
aria-expanded=${this.expanded}
aria-controls="sect1"
>
${this.leftChevron
${this.leftChevron && !this.noCollapse
? html`
<ha-svg-icon
.path=${mdiChevronDown}
Expand All @@ -57,7 +60,7 @@ export class HaExpansionPanel extends LitElement {
<slot class="secondary" name="secondary">${this.secondary}</slot>
</div>
</slot>
${!this.leftChevron
${!this.leftChevron && !this.noCollapse
? html`
<ha-svg-icon
.path=${mdiChevronDown}
Expand Down Expand Up @@ -106,6 +109,9 @@ export class HaExpansionPanel extends LitElement {
return;
}
ev.preventDefault();
if (this.noCollapse) {
return;
}
const newExpanded = !this.expanded;
fireEvent(this, "expanded-will-change", { expanded: newExpanded });
this._container.style.overflow = "hidden";
Expand All @@ -130,6 +136,9 @@ export class HaExpansionPanel extends LitElement {
}

private _focusChanged(ev) {
if (this.noCollapse) {
return;
}
this.shadowRoot!.querySelector(".top")!.classList.toggle(
"focused",
ev.type === "focus"
Expand Down Expand Up @@ -191,6 +200,9 @@ export class HaExpansionPanel extends LitElement {
font-weight: 500;
outline: none;
}
#summary.noCollapse {
cursor: default;
}
.summary-icon.expanded {
transform: rotate(180deg);
Expand Down
10 changes: 9 additions & 1 deletion src/data/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface Blueprint {
export interface BlueprintMetaData {
domain: BlueprintDomain;
name: string;
input?: Record<string, BlueprintInput | null>;
input?: Record<string, BlueprintInput | BlueprintInputSection | null>;
description?: string;
source_url?: string;
author?: string;
Expand All @@ -26,6 +26,14 @@ export interface BlueprintInput {
default?: any;
}

export interface BlueprintInputSection {
name?: string;
icon?: string;
description?: string;
collapsed?: boolean;
input: Record<string, BlueprintInput | null>;
}

export interface BlueprintImportResult {
suggested_filename: string;
raw_data: string;
Expand Down
150 changes: 110 additions & 40 deletions src/panels/config/blueprint/blueprint-generic-editor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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 { fireEvent } from "../../../common/dom/fire_event";
import { nestedArrayMove } from "../../../common/util/array-move";
Expand All @@ -11,7 +11,12 @@ import "../../../components/ha-markdown";
import "../../../components/ha-selector/ha-selector";
import "../../../components/ha-settings-row";
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 { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
Expand Down Expand Up @@ -46,6 +51,7 @@ export abstract class HaBlueprintGenericEditor extends LitElement {

protected renderCard() {
const blueprint = this._blueprint;
let border = true;
return html`
<ha-card
outlined
Expand Down Expand Up @@ -91,44 +97,14 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
Object.keys(blueprint.metadata.input).length
? Object.entries(blueprint.metadata.input).map(
([key, value]) => {
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}>
<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>`;
if (value && "input" in value) {
const section = this.renderSection(key, value);
border = false;
return section;
}
const row = this.renderSettingRow(key, value, border);
border = true;
return row;
}
)
: html`<p class="padding">
Expand All @@ -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();

private _blueprintChanged(ev) {
Expand Down Expand Up @@ -219,6 +274,7 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
}
ha-card.blueprint {
margin: 0 auto;
margin-bottom: 64px;
}
.padding {
padding: 16px;
Expand Down Expand Up @@ -253,8 +309,15 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
--paper-time-input-justify-content: flex-end;
--settings-row-content-width: 100%;
--settings-row-prefix-display: contents;
}
ha-settings-row.border {
border-top: 1px solid var(--divider-color);
}
ha-expansion-panel {
margin: 8px;
margin-left: 8px;
margin-right: 8px;
}
ha-alert {
margin-bottom: 16px;
display: block;
Expand All @@ -263,6 +326,13 @@ export abstract class HaBlueprintGenericEditor extends LitElement {
border-radius: var(--ha-card-border-radius, 12px);
overflow: hidden;
}
div.section-header {
display: flex;
vertical-align: middle;
}
ha-icon.section-header {
padding-right: 10px;
}
`,
];
}
Expand Down

0 comments on commit a629f01

Please sign in to comment.