feat: Add a simple mode to the visual card editor (#2588)

This commit is contained in:
Dermot Duffy
2026-07-21 19:13:29 -07:00
committed by GitHub
parent b6e1de5999
commit e29c0826cf
56 changed files with 1722 additions and 353 deletions
+40 -24
View File
@@ -17,6 +17,7 @@ import {
} from '../../components-lib/editor/titles';
import type { ConfigPath } from '../../components-lib/editor/types';
import { CONF_CAMERAS } from '../../config/const';
import type { EditorMode } from '../../config/schema/editor';
import type { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import editorExpanderBodyStyle from '../../scss/editor-expander-body.scss';
@@ -45,6 +46,11 @@ export class AdvancedCameraCardEditorCameras extends LitElement {
@property({ attribute: false })
public input?: FormsInput;
// Which editor this list is part of. The simple editor shows fewer of a
// camera's settings, and none of its triggers.
@property()
public mode?: EditorMode;
private _pagesController = new ListPagesController(this);
private _formsController = new ListFormsController(this, (path) =>
renderDocumentation(path),
@@ -103,8 +109,7 @@ export class AdvancedCameraCardEditorCameras extends LitElement {
private _renderCamera(index: number, hidden: boolean): TemplateResult {
const camera = this._formsController.getList(CAMERAS_PATH)[index];
const eventsPath: ConfigPath = [CONF_CAMERAS, index, 'triggers', 'events'];
const events = this._formsController.getList(eventsPath);
const fullMode = this.mode !== 'simple';
return html`
<advanced-camera-card-editor-page
@@ -114,32 +119,43 @@ export class AdvancedCameraCardEditorCameras extends LitElement {
>
${renderForms(
this.hass,
this._formsController.getFormContexts({ kind: 'camera', index }),
this._formsController.getFormContexts(
fullMode ? { kind: 'full-camera', index } : { kind: 'simple-camera', index },
),
)}
<ha-expansion-panel
outlined
.header=${localize('config.cameras.triggers.editor_label')}
>
<advanced-camera-card-icon
slot="leading-icon"
.icon=${{ icon: 'mdi:magnify-scan' }}
></advanced-camera-card-icon>
${this._renderContained(html`
${renderDocumentation([CONF_CAMERAS, 'triggers'])}
${renderForms(
this.hass,
this._formsController.getFormContexts({
kind: 'camera-triggers',
cameraIndex: index,
}),
)}
${this._renderEvents(eventsPath, events)}
`)}
</ha-expansion-panel>
${fullMode ? this._renderTriggers(index) : nothing}
</advanced-camera-card-editor-page>
`;
}
private _renderTriggers(index: number): TemplateResult {
const eventsPath: ConfigPath = [CONF_CAMERAS, index, 'triggers', 'events'];
const events = this._formsController.getList(eventsPath);
return html`
<ha-expansion-panel
outlined
.header=${localize('config.cameras.triggers.editor_label')}
>
<advanced-camera-card-icon
slot="leading-icon"
.icon=${{ icon: 'mdi:magnify-scan' }}
></advanced-camera-card-icon>
${this._renderContained(html`
${renderDocumentation([CONF_CAMERAS, 'triggers'])}
${renderForms(
this.hass,
this._formsController.getFormContexts({
kind: 'full-camera-triggers',
cameraIndex: index,
}),
)}
${this._renderEvents(eventsPath, events)}
`)}
</ha-expansion-panel>
`;
}
// The Home Assistant events the triggers watch for, a group of their own
// within the triggers panel: they are one kind of trigger among the others,
// not a sibling of the whole trigger set.
@@ -216,7 +232,7 @@ export class AdvancedCameraCardEditorCameras extends LitElement {
${renderForms(
this.hass,
this._formsController.getFormContexts({
kind: 'camera-event',
kind: 'full-camera-event',
cameraIndex,
eventIndex,
}),
+2 -3
View File
@@ -8,6 +8,7 @@ import {
import { customElement, property } from 'lit/decorators.js';
import { getDocURL } from '../../components-lib/editor/doc-links';
import type { ConfigPath } from '../../components-lib/editor/types';
import { localize } from '../../localize/localize';
import editorDocLinkStyle from '../../scss/editor-doc-link.scss';
@@ -48,9 +49,7 @@ export class AdvancedCameraCardEditorDocLink extends LitElement {
* @param path The configuration path.
* @returns A rendered template, or null when the path has no documentation.
*/
export const renderDocumentation = (
path: (string | number)[],
): TemplateResult | null => {
export const renderDocumentation = (path: ConfigPath): TemplateResult | null => {
const url = getDocURL(path);
return url
? html`<advanced-camera-card-editor-doc-link
+1 -1
View File
@@ -64,7 +64,7 @@ export class AdvancedCameraCardEditorFolders extends LitElement {
>
${renderForms(
this.hass,
this._controller.getFormContexts({ kind: 'folder', index }),
this._controller.getFormContexts({ kind: 'full-folder', index }),
)}
<ha-alert alert-type="info">
${localize('config.folders.ha.path_info')}
+3 -2
View File
@@ -14,6 +14,7 @@ import type {
} from '../../components-lib/editor/forms-controller';
import type { FormRequest } from '../../components-lib/editor/schema/registry';
import { SectionController } from '../../components-lib/editor/section-controller';
import type { ConfigPath } from '../../components-lib/editor/types';
import type { HomeAssistant } from '../../ha/types';
import editorSectionStyle from '../../scss/editor-section.scss';
import { renderDocumentation } from './doc-link';
@@ -47,7 +48,7 @@ export class AdvancedCameraCardEditorSection extends LitElement {
// The path whose documentation the section links to; the section's own forms
// supply the links for everything within them.
@property({ attribute: false })
public documentationPath?: (string | number)[];
public docPath?: ConfigPath;
// Content shown after the section's schema forms, of which there may be
// none. Called only once the section has been opened, and in the render that
@@ -96,7 +97,7 @@ export class AdvancedCameraCardEditorSection extends LitElement {
@expanded-will-change=${this._stopPropagation}
@expanded-changed=${this._stopPropagation}
>
${this.documentationPath ? renderDocumentation(this.documentationPath) : nothing}
${this.docPath ? renderDocumentation(this.docPath) : nothing}
${renderForms(this.hass, this._controller.getContexts())}
${this.renderCustomContent?.() ?? nothing}
</div>