Compare commits

..

4 Commits

Author SHA1 Message Date
Paul Bottein
6947092be1 Update drag icon 2025-10-15 10:11:14 +02:00
karwosts
33a7aacd83 Use media selector in picture-glance and picture-elements (#27506) 2025-10-15 08:31:19 +03:00
karwosts
39546615bb Missing translation on back button (#27510) 2025-10-15 06:09:30 +02:00
J. Nick Koston
be51cbc944 Add support for next_flow on abort (#27491) 2025-10-14 11:45:11 -10:00
43 changed files with 683 additions and 962 deletions

View File

@@ -1,4 +1,4 @@
import { mdiDrag, mdiEye, mdiEyeOff } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiEye, mdiEyeOff } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
@@ -129,7 +129,7 @@ export class DialogDataTableSettings extends LitElement {
${canMove && isVisible
? html`<ha-svg-icon
class="handle"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
slot="graphic"
></ha-svg-icon>`
: nothing}

View File

@@ -1,13 +1,13 @@
import { mdiDrag } from "@mdi/js";
import { mdiDragHorizontalVariant } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import { isValidEntityId } from "../../common/entity/valid_entity_id";
import type { HaEntityPickerEntityFilterFunc } from "../../data/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../types";
import "../ha-sortable";
import "./ha-entity-picker";
import type { HaEntityPickerEntityFilterFunc } from "../../data/entity";
@customElement("ha-entities-picker")
class HaEntitiesPicker extends LitElement {
@@ -118,7 +118,7 @@ class HaEntitiesPicker extends LitElement {
? html`
<ha-svg-icon
class="entity-handle"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
`
: nothing}

View File

@@ -1,5 +1,5 @@
import "@material/mwc-menu/mwc-menu-surface";
import { mdiDrag, mdiPlus } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiPlus } from "@mdi/js";
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
import type { IFuseOptions } from "fuse.js";
import Fuse from "fuse.js";
@@ -173,7 +173,10 @@ export class HaEntityNamePicker extends LitElement {
.disabled=${this.disabled}
class=${!isValid ? "invalid" : ""}
>
<ha-svg-icon slot="icon" .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
slot="icon"
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
<span>${label}</span>
</ha-input-chip>
`;

View File

@@ -1,4 +1,4 @@
import { mdiDrag } from "@mdi/js";
import { mdiDragHorizontalVariant } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
@@ -195,7 +195,10 @@ class HaEntityStatePicker extends LitElement {
.label=${label}
selected
>
<ha-svg-icon slot="icon" .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
slot="icon"
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
${label}
</ha-input-chip>
`;

View File

@@ -1,4 +1,4 @@
import { mdiDrag, mdiTextureBox } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiTextureBox } from "@mdi/js";
import type { TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
@@ -105,7 +105,7 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
<ha-svg-icon
class="handle"
slot="icons"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
`}
<ha-items-display-editor

View File

@@ -1,7 +1,6 @@
import "@home-assistant/webawesome/dist/components/drawer/drawer";
import { css, html, LitElement, type PropertyValues } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { haStyleScrollbar } from "../resources/styles";
import { customElement, property, state } from "lit/decorators";
export const BOTTOM_SHEET_ANIMATION_DURATION_MS = 300;
@@ -14,8 +13,6 @@ export class HaBottomSheet extends LitElement {
@state() private _drawerOpen = false;
@query(".body") public bodyContainer!: HTMLDivElement;
private _handleAfterHide() {
this.open = false;
const ev = new Event("closed", {
@@ -40,61 +37,49 @@ export class HaBottomSheet extends LitElement {
@wa-after-hide=${this._handleAfterHide}
without-header
>
<slot name="header"></slot>
<div class="body ha-scrollbar">
<slot></slot>
</div>
<slot></slot>
</wa-drawer>
`;
}
static styles = [
haStyleScrollbar,
css`
wa-drawer {
--wa-color-surface-raised: transparent;
--spacing: 0;
--size: var(--ha-bottom-sheet-height, auto);
--show-duration: ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms;
--hide-duration: ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms;
}
wa-drawer::part(dialog) {
max-height: var(--ha-bottom-sheet-max-height, 90vh);
align-items: center;
}
wa-drawer::part(body) {
max-width: var(--ha-bottom-sheet-max-width);
width: 100%;
border-top-left-radius: var(
--ha-bottom-sheet-border-radius,
var(--ha-dialog-border-radius, var(--ha-border-radius-2xl))
);
border-top-right-radius: var(
--ha-bottom-sheet-border-radius,
var(--ha-dialog-border-radius, var(--ha-border-radius-2xl))
);
background-color: var(
--ha-bottom-sheet-surface-background,
var(--ha-dialog-surface-background, var(--mdc-theme-surface, #fff)),
);
padding: var(
--ha-bottom-sheet-padding,
0 var(--safe-area-inset-right) var(--safe-area-inset-bottom)
var(--safe-area-inset-left)
);
}
:host([flexcontent]) wa-drawer::part(body) {
display: flex;
flex-direction: column;
}
:host([flexcontent]) .body {
flex: 1;
max-width: 100%;
display: flex;
flex-direction: column;
}
`,
];
static styles = css`
wa-drawer {
--wa-color-surface-raised: transparent;
--spacing: 0;
--size: var(--ha-bottom-sheet-height, auto);
--show-duration: ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms;
--hide-duration: ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms;
}
wa-drawer::part(dialog) {
max-height: var(--ha-bottom-sheet-max-height, 90vh);
align-items: center;
}
wa-drawer::part(body) {
max-width: var(--ha-bottom-sheet-max-width);
width: 100%;
border-top-left-radius: var(
--ha-bottom-sheet-border-radius,
var(--ha-dialog-border-radius, var(--ha-border-radius-2xl))
);
border-top-right-radius: var(
--ha-bottom-sheet-border-radius,
var(--ha-dialog-border-radius, var(--ha-border-radius-2xl))
);
background-color: var(
--ha-bottom-sheet-surface-background,
var(--ha-dialog-surface-background, var(--mdc-theme-surface, #fff)),
);
padding: var(
--ha-bottom-sheet-padding,
0 var(--safe-area-inset-right) var(--safe-area-inset-bottom)
var(--safe-area-inset-left)
);
}
:host([flexcontent]) wa-drawer::part(body) {
display: flex;
}
`;
}
declare global {

View File

@@ -31,9 +31,6 @@ export class HaButtonToggleGroup extends LitElement {
@property({ type: Boolean, reflect: true, attribute: "no-wrap" })
public nowrap = false;
@property({ type: Boolean, reflect: true, attribute: "full-width" })
public fullWidth = false;
@property() public variant:
| "brand"
| "neutral"
@@ -41,13 +38,6 @@ export class HaButtonToggleGroup extends LitElement {
| "warning"
| "danger" = "brand";
@property({ attribute: "active-variant" }) public activeVariant?:
| "brand"
| "neutral"
| "success"
| "warning"
| "danger";
protected render(): TemplateResult {
return html`
<wa-button-group childSelector="ha-button">
@@ -56,9 +46,7 @@ export class HaButtonToggleGroup extends LitElement {
html`<ha-button
iconTag="ha-svg-icon"
class="icon"
.variant=${this.active !== button.value || !this.activeVariant
? this.variant
: this.activeVariant}
.variant=${this.variant}
.size=${this.size}
.value=${button.value}
@click=${this._handleClick}
@@ -90,19 +78,6 @@ export class HaButtonToggleGroup extends LitElement {
:host([no-wrap]) wa-button-group::part(base) {
flex-wrap: nowrap;
}
wa-button-group {
padding: var(--ha-button-toggle-group-padding);
}
:host([full-width]) wa-button-group,
:host([full-width]) wa-button-group::part(base) {
width: 100%;
}
:host([full-width]) ha-button {
flex: 1;
}
`;
}

View File

@@ -1,5 +1,5 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import { mdiDrag, mdiEye, mdiEyeOff } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiEye, mdiEyeOff } from "@mdi/js";
import type { TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
@@ -178,7 +178,7 @@ export class HaItemDisplayEditor extends LitElement {
? this._dragHandleKeydown
: undefined}
class="handle"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
slot="end"
></ha-svg-icon>
`

View File

@@ -107,14 +107,15 @@ export class HaMediaSelector extends LitElement {
supportsFeature(stateObj, MediaPlayerEntityFeature.BROWSE_MEDIA));
if (this.selector.media?.image_upload && !this.value) {
return html`<ha-picture-upload
.hass=${this.hass}
.value=${null}
.contentIdHelper=${this.selector.media?.content_id_helper}
select-media
full-media
@media-picked=${this._pictureUploadMediaPicked}
></ha-picture-upload>`;
return html`${this.label ? html`<label>${this.label}</label>` : nothing}
<ha-picture-upload
.hass=${this.hass}
.value=${null}
.contentIdHelper=${this.selector.media?.content_id_helper}
select-media
full-media
@media-picked=${this._pictureUploadMediaPicked}
></ha-picture-upload>`;
}
return html`
@@ -141,6 +142,7 @@ export class HaMediaSelector extends LitElement {
`}
${!supportsBrowse
? html`
${this.label ? html`<label>${this.label}</label>` : nothing}
<ha-alert>
${this.hass.localize(
"ui.components.selectors.media.browse_not_supported"
@@ -154,7 +156,8 @@ export class HaMediaSelector extends LitElement {
.computeHelper=${this._computeHelperCallback}
></ha-form>
`
: html`<ha-card
: html`${this.label ? html`<label>${this.label}</label>` : nothing}
<ha-card
outlined
tabindex="0"
role="button"

View File

@@ -1,4 +1,9 @@
import { mdiClose, mdiDelete, mdiDrag, mdiPencil } from "@mdi/js";
import {
mdiClose,
mdiDelete,
mdiDragHorizontalVariant,
mdiPencil,
} from "@mdi/js";
import { css, html, LitElement, nothing, type PropertyValues } from "lit";
import { customElement, property, query } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -92,7 +97,7 @@ export class HaObjectSelector extends LitElement {
? html`
<ha-svg-icon
class="handle"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
slot="start"
></ha-svg-icon>
`

View File

@@ -1,4 +1,4 @@
import { mdiDrag } from "@mdi/js";
import { mdiDragHorizontalVariant } from "@mdi/js";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
@@ -197,7 +197,7 @@ export class HaSelectSelector extends LitElement {
? html`
<ha-svg-icon
slot="icon"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
`
: nothing}

View File

@@ -1,12 +1,12 @@
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "@home-assistant/webawesome/dist/components/dialog/dialog";
import { mdiClose } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-dialog-header";
import "./ha-icon-button";
import type { HomeAssistant } from "../types";
import { fireEvent } from "../common/dom/fire_event";
import { haStyleScrollbar } from "../resources/styles";
export type DialogWidth = "small" | "medium" | "large" | "full";
@@ -90,8 +90,6 @@ export class HaWaDialog extends LitElement {
@state()
private _open = false;
@query(".body") public bodyContainer!: HTMLDivElement;
protected updated(
changedProperties: Map<string | number | symbol, unknown>
): void {
@@ -109,7 +107,6 @@ export class HaWaDialog extends LitElement {
.lightDismiss=${!this.preventScrimClose}
without-header
@wa-show=${this._handleShow}
@wa-after-show=${this._handleAfterShow}
@wa-after-hide=${this._handleAfterHide}
>
<slot name="header">
@@ -149,10 +146,6 @@ export class HaWaDialog extends LitElement {
(this.querySelector("[autofocus]") as HTMLElement | null)?.focus();
};
private _handleAfterShow = () => {
fireEvent(this, "after-show");
};
private _handleAfterHide = () => {
this._open = false;
fireEvent(this, "closed");
@@ -179,7 +172,7 @@ export class HaWaDialog extends LitElement {
)
)
);
--width: min(var(--ha-dialog-width-md, 580px), var(--full-width));
--width: var(--ha-dialog-width-md, min(580px, var(--full-width)));
--spacing: var(--dialog-content-padding, var(--ha-space-6));
--show-duration: var(--ha-dialog-show-duration, 200ms);
--hide-duration: var(--ha-dialog-hide-duration, 200ms);
@@ -200,11 +193,11 @@ export class HaWaDialog extends LitElement {
}
:host([width="small"]) wa-dialog {
--width: min(var(--ha-dialog-width-sm, 320px), var(--full-width));
--width: var(--ha-dialog-width-sm, min(320px, var(--full-width)));
}
:host([width="large"]) wa-dialog {
--width: min(var(--ha-dialog-width-lg, 720px), var(--full-width));
--width: var(--ha-dialog-width-lg, min(720px, var(--full-width)));
}
:host([width="full"]) wa-dialog {
@@ -218,7 +211,6 @@ export class HaWaDialog extends LitElement {
--ha-dialog-max-height,
calc(100% - var(--ha-space-20))
);
min-height: var(--ha-dialog-min-height);
position: var(--dialog-surface-position, relative);
margin-top: var(--dialog-surface-margin-top, auto);
display: flex;
@@ -295,7 +287,6 @@ export class HaWaDialog extends LitElement {
}
:host([flexcontent]) .body {
max-width: 100%;
flex: 1;
display: flex;
flex-direction: column;
}
@@ -324,7 +315,6 @@ declare global {
interface HASSDomEvents {
opened: undefined;
"after-show": undefined;
closed: undefined;
}
}

View File

@@ -6,6 +6,8 @@ import {
mdiCallSplit,
mdiCodeBraces,
mdiDevices,
mdiDotsHorizontal,
mdiExcavator,
mdiFormatListNumbered,
mdiGestureDoubleTap,
mdiHandBackRight,
@@ -14,10 +16,10 @@ import {
mdiRoomService,
mdiShuffleDisabled,
mdiTimerOutline,
mdiTools,
mdiTrafficLight,
} from "@mdi/js";
import type { AutomationElementGroupCollection } from "./automation";
import type { Action } from "./script";
import type { AutomationElementGroup } from "./automation";
export const ACTION_ICONS = {
condition: mdiAbTesting,
@@ -46,73 +48,37 @@ export const YAML_ONLY_ACTION_TYPES = new Set<keyof typeof ACTION_ICONS>([
"variables",
]);
export const ACTION_COLLECTIONS: AutomationElementGroupCollection[] = [
{
groups: {
device_id: {},
serviceGroups: {},
export const ACTION_GROUPS: AutomationElementGroup = {
device_id: {},
helpers: {
icon: mdiTools,
members: {},
},
building_blocks: {
icon: mdiExcavator,
members: {
condition: {},
delay: {},
wait_template: {},
wait_for_trigger: {},
repeat_count: {},
repeat_while: {},
repeat_until: {},
repeat_for_each: {},
choose: {},
if: {},
stop: {},
sequence: {},
parallel: {},
variables: {},
},
},
{
titleKey: "ui.panel.config.automation.editor.actions.groups.helpers.label",
groups: {
helpers: {},
},
},
{
titleKey: "ui.panel.config.automation.editor.actions.groups.other.label",
groups: {
other: {
icon: mdiDotsHorizontal,
members: {
event: {},
service: {},
set_conversation_response: {},
other: {},
},
},
] as const;
export const ACTION_BUILDING_BLOCKS_GROUP = {
condition: {},
delay: {},
wait_template: {},
wait_for_trigger: {},
repeat_count: {},
repeat_while: {},
repeat_until: {},
repeat_for_each: {},
choose: {},
if: {},
stop: {},
sequence: {},
parallel: {},
variables: {},
};
// These will be replaced with the correct action
export const VIRTUAL_ACTIONS: Partial<
Record<keyof typeof ACTION_BUILDING_BLOCKS_GROUP, Action>
> = {
repeat_count: {
repeat: {
count: 2,
sequence: [],
},
},
repeat_while: {
repeat: {
while: [],
sequence: [],
},
},
repeat_until: {
repeat: {
until: [],
sequence: [],
},
},
repeat_for_each: {
repeat: {
for_each: {},
sequence: [],
},
},
} as const;

View File

@@ -4,7 +4,6 @@ import type {
} from "home-assistant-js-websocket";
import { ensureArray } from "../common/array/ensure-array";
import { navigate } from "../common/navigate";
import type { LocalizeKeys } from "../common/translations/localize";
import { createSearchParam } from "../common/url/search-params";
import type { Context, HomeAssistant } from "../types";
import type { BlueprintInput } from "./blueprint";
@@ -294,11 +293,6 @@ export interface ShorthandNotCondition extends ShorthandBaseCondition {
not: Condition[];
}
export interface AutomationElementGroupCollection {
titleKey?: LocalizeKeys;
groups: AutomationElementGroup;
}
export type AutomationElementGroup = Record<
string,
{ icon?: string; members?: AutomationElementGroup }

View File

@@ -3,6 +3,8 @@ import {
mdiClockOutline,
mdiCodeBraces,
mdiDevices,
mdiDotsHorizontal,
mdiExcavator,
mdiGateOr,
mdiIdentifier,
mdiMapClock,
@@ -13,7 +15,7 @@ import {
mdiStateMachine,
mdiWeatherSunny,
} from "@mdi/js";
import type { AutomationElementGroupCollection } from "./automation";
import type { AutomationElementGroup } from "./automation";
export const CONDITION_ICONS = {
device: mdiDevices,
@@ -29,31 +31,25 @@ export const CONDITION_ICONS = {
zone: mdiMapMarkerRadius,
};
export const CONDITION_COLLECTIONS: AutomationElementGroupCollection[] = [
{
groups: {
device: {},
entity: { icon: mdiShape, members: { state: {}, numeric_state: {} } },
time_location: {
icon: mdiMapClock,
members: { sun: {}, time: {}, zone: {} },
},
},
export const CONDITION_GROUPS: AutomationElementGroup = {
device: {},
entity: { icon: mdiShape, members: { state: {}, numeric_state: {} } },
time_location: {
icon: mdiMapClock,
members: { sun: {}, time: {}, zone: {} },
},
{
titleKey: "ui.panel.config.automation.editor.conditions.groups.other.label",
groups: {
building_blocks: {
icon: mdiExcavator,
members: { and: {}, or: {}, not: {} },
},
other: {
icon: mdiDotsHorizontal,
members: {
template: {},
trigger: {},
},
},
] as const;
export const CONDITION_BUILDING_BLOCKS_GROUP = {
and: {},
or: {},
not: {},
};
} as const;
export const CONDITION_BUILDING_BLOCKS = ["and", "or", "not"];

View File

@@ -79,6 +79,7 @@ export interface DataEntryFlowStepAbort {
reason: string;
description_placeholders?: Record<string, string>;
translation_domain?: string;
next_flow?: [FlowType, string]; // [flow_type, flow_id]
}
export interface DataEntryFlowStepProgress {

View File

@@ -4,6 +4,7 @@ import {
mdiClockOutline,
mdiCodeBraces,
mdiDevices,
mdiDotsHorizontal,
mdiFormatListBulleted,
mdiGestureDoubleTap,
mdiMapClock,
@@ -22,7 +23,7 @@ import {
import { mdiHomeAssistant } from "../resources/home-assistant-logo-svg";
import type {
AutomationElementGroupCollection,
AutomationElementGroup,
Trigger,
TriggerList,
} from "./automation";
@@ -48,26 +49,16 @@ export const TRIGGER_ICONS = {
list: mdiFormatListBulleted,
};
export const TRIGGER_COLLECTIONS: AutomationElementGroupCollection[] = [
{
groups: {
device: {},
entity: { icon: mdiShape, members: { state: {}, numeric_state: {} } },
time_location: {
icon: mdiMapClock,
members: {
calendar: {},
sun: {},
time: {},
time_pattern: {},
zone: {},
},
},
},
export const TRIGGER_GROUPS: AutomationElementGroup = {
device: {},
entity: { icon: mdiShape, members: { state: {}, numeric_state: {} } },
time_location: {
icon: mdiMapClock,
members: { calendar: {}, sun: {}, time: {}, time_pattern: {}, zone: {} },
},
{
titleKey: "ui.panel.config.automation.editor.triggers.groups.other.label",
groups: {
other: {
icon: mdiDotsHorizontal,
members: {
event: {},
geo_location: {},
homeassistant: {},
@@ -79,7 +70,7 @@ export const TRIGGER_COLLECTIONS: AutomationElementGroupCollection[] = [
persistent_notification: {},
},
},
] as const;
} as const;
export const isTriggerList = (trigger: Trigger): trigger is TriggerList =>
"triggers" in trigger;

View File

@@ -472,7 +472,10 @@ class DataEntryFlowDialog extends LitElement {
this._step = undefined;
await this.updateComplete;
this._step = _step;
if (_step.type === "create_entry" && _step.next_flow) {
if (
(_step.type === "create_entry" || _step.type === "abort") &&
_step.next_flow
) {
// skip device rename if there is a chained flow
this._step = undefined;
this._handler = undefined;
@@ -486,32 +489,36 @@ class DataEntryFlowDialog extends LitElement {
carryOverDevices: this._devices(
this._params!.flowConfig.showDevices,
Object.values(this.hass.devices),
_step.result?.entry_id,
_step.type === "create_entry" ? _step.result?.entry_id : undefined,
this._params!.carryOverDevices
).map((device) => device.id),
dialogClosedCallback: this._params!.dialogClosedCallback,
});
} else if (_step.next_flow[0] === "options_flow") {
showOptionsFlowDialog(
this._params!.dialogParentElement!,
_step.result!,
{
continueFlowId: _step.next_flow[1],
navigateToResult: this._params!.navigateToResult,
dialogClosedCallback: this._params!.dialogClosedCallback,
}
);
if (_step.type === "create_entry") {
showOptionsFlowDialog(
this._params!.dialogParentElement!,
_step.result!,
{
continueFlowId: _step.next_flow[1],
navigateToResult: this._params!.navigateToResult,
dialogClosedCallback: this._params!.dialogClosedCallback,
}
);
}
} else if (_step.next_flow[0] === "config_subentries_flow") {
showSubConfigFlowDialog(
this._params!.dialogParentElement!,
_step.result!,
_step.next_flow[0],
{
continueFlowId: _step.next_flow[1],
navigateToResult: this._params!.navigateToResult,
dialogClosedCallback: this._params!.dialogClosedCallback,
}
);
if (_step.type === "create_entry") {
showSubConfigFlowDialog(
this._params!.dialogParentElement!,
_step.result!,
_step.next_flow[0],
{
continueFlowId: _step.next_flow[1],
navigateToResult: this._params!.navigateToResult,
dialogClosedCallback: this._params!.dialogClosedCallback,
}
);
}
} else {
this.closeDialog();
showAlertDialog(this._params!.dialogParentElement!, {

View File

@@ -1,10 +1,9 @@
import { mdiDrag, mdiPlus } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiPlus } from "@mdi/js";
import deepClone from "deep-clone-simple";
import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, queryAll, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { ensureArray } from "../../../../common/array/ensure-array";
import { storage } from "../../../../common/decorators/storage";
import { fireEvent } from "../../../../common/dom/fire_event";
import { stopPropagation } from "../../../../common/dom/stop_propagation";
@@ -16,18 +15,19 @@ import {
ACTION_BUILDING_BLOCKS,
getService,
isService,
VIRTUAL_ACTIONS,
} from "../../../../data/action";
import type { AutomationClipboard } from "../../../../data/automation";
import type { Action } from "../../../../data/script";
import type { HomeAssistant } from "../../../../types";
import {
PASTE_VALUE,
VIRTUAL_ACTIONS,
showAddAutomationElementDialog,
} from "../show-add-automation-element-dialog";
import { automationRowsStyles } from "../styles";
import type HaAutomationActionRow from "./ha-automation-action-row";
import { getAutomationActionType } from "./ha-automation-action-row";
import { ensureArray } from "../../../../common/array/ensure-array";
@customElement("ha-automation-action")
export default class HaAutomationAction extends LitElement {
@@ -115,7 +115,9 @@ export default class HaAutomationAction extends LitElement {
@click=${stopPropagation}
.index=${idx}
>
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
`
: nothing}
@@ -134,6 +136,17 @@ export default class HaAutomationAction extends LitElement {
"ui.panel.config.automation.editor.actions.add"
)}
</ha-button>
<ha-button
.disabled=${this.disabled}
@click=${this._addActionBuildingBlockDialog}
appearance="plain"
.size=${this.root ? "medium" : "small"}
>
<ha-svg-icon .path=${mdiPlus} slot="start"></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.add_building_block"
)}
</ha-button>
</div>
</div>
</ha-sortable>
@@ -209,6 +222,15 @@ export default class HaAutomationAction extends LitElement {
});
}
private _addActionBuildingBlockDialog() {
showAddAutomationElementDialog(this, {
type: "action",
add: this._addAction,
clipboardItem: getAutomationActionType(this._clipboard?.action),
group: "building_blocks",
});
}
private _addAction = (action: string) => {
let actions: Action[];
if (action === PASTE_VALUE) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import { mdiDrag, mdiPlus } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiPlus } from "@mdi/js";
import deepClone from "deep-clone-simple";
import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
@@ -193,7 +193,9 @@ export default class HaAutomationCondition extends LitElement {
@click=${stopPropagation}
.index=${idx}
>
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
`
: nothing}
@@ -212,6 +214,17 @@ export default class HaAutomationCondition extends LitElement {
"ui.panel.config.automation.editor.conditions.add"
)}
</ha-button>
<ha-button
.disabled=${this.disabled}
appearance="plain"
.size=${this.root ? "medium" : "small"}
@click=${this._addConditionBuildingBlockDialog}
>
<ha-svg-icon .path=${mdiPlus} slot="start"></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.add_building_block"
)}
</ha-button>
</div>
</div>
</ha-sortable>
@@ -229,6 +242,15 @@ export default class HaAutomationCondition extends LitElement {
});
}
private _addConditionBuildingBlockDialog() {
showAddAutomationElementDialog(this, {
type: "condition",
add: this._addCondition,
clipboardItem: this._clipboard?.condition?.condition,
group: "building_blocks",
});
}
private _addCondition = (value) => {
let conditions: Condition[];
if (value === PASTE_VALUE) {

View File

@@ -1,4 +1,4 @@
import { mdiDrag, mdiPlus } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiPlus } from "@mdi/js";
import deepClone from "deep-clone-simple";
import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
@@ -100,7 +100,9 @@ export default class HaAutomationOption extends LitElement {
@click=${stopPropagation}
.index=${idx}
>
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
`
: nothing}

View File

@@ -1,11 +1,45 @@
import { fireEvent } from "../../../common/dom/fire_event";
import type { ACTION_GROUPS } from "../../../data/action";
import type { ActionType } from "../../../data/script";
export const PASTE_VALUE = "__paste__";
// These will be replaced with the correct action
export const VIRTUAL_ACTIONS: Record<
keyof (typeof ACTION_GROUPS)["building_blocks"]["members"],
ActionType
> = {
repeat_count: {
repeat: {
count: 2,
sequence: [],
},
},
repeat_while: {
repeat: {
while: [],
sequence: [],
},
},
repeat_until: {
repeat: {
until: [],
sequence: [],
},
},
repeat_for_each: {
repeat: {
for_each: {},
sequence: [],
},
},
} as const;
export interface AddAutomationElementDialogParams {
type: "trigger" | "condition" | "action";
add: (key: string) => void;
clipboardItem: string | undefined;
group?: string;
}
const loadDialog = () => import("./add-automation-element-dialog");

View File

@@ -1,4 +1,4 @@
import { mdiDrag, mdiPlus } from "@mdi/js";
import { mdiDragHorizontalVariant, mdiPlus } from "@mdi/js";
import deepClone from "deep-clone-simple";
import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
@@ -110,7 +110,9 @@ export default class HaAutomationTrigger extends LitElement {
@click=${stopPropagation}
.index=${idx}
>
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
`
: nothing}

View File

@@ -1,4 +1,10 @@
import { mdiDelete, mdiDevices, mdiDrag, mdiPencil, mdiPlus } from "@mdi/js";
import {
mdiDelete,
mdiDevices,
mdiDragHorizontalVariant,
mdiPencil,
mdiPlus,
} from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { repeat } from "lit/directives/repeat";
@@ -89,7 +95,9 @@ export class EnergyDeviceSettings extends LitElement {
(device) => html`
<div class="row" .device=${device}>
<div class="handle">
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
<span class="content"
>${device.name ||

View File

@@ -1,4 +1,4 @@
import { mdiDelete, mdiDrag } from "@mdi/js";
import { mdiDelete, mdiDragHorizontalVariant } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
@@ -111,7 +111,9 @@ class HaInputSelectForm extends LitElement {
<ha-list-item class="option" hasMeta>
<div class="optioncontent">
<div class="handle">
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
${option}
</div>

View File

@@ -126,7 +126,16 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
return nothing;
}
let image: string | undefined = this._config.image;
let image: string | undefined =
(typeof this._config?.image === "object" &&
this._config.image.media_content_id) ||
(this._config.image as string | undefined);
const darkModeImage: string | undefined =
(typeof this._config?.dark_mode_image === "object" &&
this._config.dark_mode_image.media_content_id) ||
(this._config.dark_mode_image as string | undefined);
if (this._config.image_entity) {
const stateObj: ImageEntity | PersonEntity | undefined =
this.hass.states[this._config.image_entity];
@@ -156,7 +165,7 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
.entity=${this._config.entity}
.aspectRatio=${this._config.aspect_ratio}
.darkModeFilter=${this._config.dark_mode_filter}
.darkModeImage=${this._config.dark_mode_image}
.darkModeImage=${darkModeImage}
></hui-image>
${this._elements}
</div>

View File

@@ -179,7 +179,10 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
return nothing;
}
let image: string | undefined = this._config.image;
let image: string | undefined =
(typeof this._config?.image === "object" &&
this._config.image.media_content_id) ||
(this._config.image as string | undefined);
if (this._config.image_entity) {
const stateObj: ImageEntity | PersonEntity | undefined =
this.hass.states[this._config.image_entity];

View File

@@ -5,7 +5,7 @@ import {
mdiDelete,
mdiDeleteSweep,
mdiDotsVertical,
mdiDrag,
mdiDragHorizontalVariant,
mdiPlus,
mdiSort,
} from "@mdi/js";
@@ -522,7 +522,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
"ui.panel.lovelace.cards.todo-list.drag_and_drop"
)}
class="reorderButton handle"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
slot="meta"
>
</ha-svg-icon>

View File

@@ -459,7 +459,7 @@ export interface PictureCardConfig extends LovelaceCardConfig {
export interface PictureElementsCardConfig extends LovelaceCardConfig {
title?: string;
image?: string;
image?: string | MediaSelectorValue;
image_entity?: string;
camera_image?: string;
camera_view?: HuiImage["cameraView"];
@@ -469,7 +469,7 @@ export interface PictureElementsCardConfig extends LovelaceCardConfig {
entity?: string;
elements: LovelaceElementConfig[];
theme?: string;
dark_mode_image?: string;
dark_mode_image?: string | MediaSelectorValue;
dark_mode_filter?: string;
}
@@ -494,7 +494,7 @@ export interface PictureEntityCardConfig extends LovelaceCardConfig {
export interface PictureGlanceCardConfig extends LovelaceCardConfig {
entities: (string | PictureGlanceEntityConfig)[];
title?: string;
image?: string;
image?: string | MediaSelectorValue;
image_entity?: string;
camera_image?: string;
camera_view?: HuiImage["cameraView"];

View File

@@ -1,4 +1,4 @@
import { mdiClose, mdiDrag, mdiPencil } from "@mdi/js";
import { mdiClose, mdiDragHorizontalVariant, mdiPencil } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
@@ -66,7 +66,11 @@ export class HuiEntityEditor extends LitElement {
return html`
<ha-md-list-item class="item">
<ha-svg-icon class="handle" .path=${mdiDrag} slot="start"></ha-svg-icon>
<ha-svg-icon
class="handle"
.path=${mdiDragHorizontalVariant}
slot="start"
></ha-svg-icon>
<div slot="headline" class="label">${primary}</div>
${secondary
@@ -152,7 +156,9 @@ export class HuiEntityEditor extends LitElement {
(entityConf, index) => html`
<div class="entity" data-entity-id=${entityConf.entity}>
<div class="handle">
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
<ha-entity-picker
.hass=${this.hass}

View File

@@ -1,4 +1,4 @@
import { mdiDelete, mdiDrag, mdiPencil } from "@mdi/js";
import { mdiDelete, mdiDragHorizontalVariant, mdiPencil } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators";
@@ -31,7 +31,7 @@ export class HuiSectionEditMode extends LitElement {
<ha-svg-icon
aria-hidden="true"
class="handle"
.path=${mdiDrag}
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
<ha-icon-button
.label=${this.hass.localize("ui.common.edit")}

View File

@@ -2,7 +2,15 @@ import memoizeOne from "memoize-one";
import { mdiGestureTap } from "@mdi/js";
import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { any, assert, literal, object, optional, string } from "superstruct";
import {
any,
assert,
literal,
object,
optional,
string,
union,
} from "superstruct";
import type { LocalizeFunc } from "../../../../../common/translations/localize";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/ha-form/ha-form";
@@ -15,7 +23,7 @@ import { actionConfigStruct } from "../../structs/action-struct";
const imageElementConfigStruct = object({
type: literal("image"),
entity: optional(string()),
image: optional(string()),
image: optional(union([string(), object()])),
style: optional(any()),
title: optional(string()),
tap_action: optional(actionConfigStruct),
@@ -87,7 +95,20 @@ export class HuiImageElementEditor
},
],
},
{ name: "image", selector: { image: {} } },
{
name: "image",
selector: {
media: {
accept: ["image/*"] as string[],
clearable: true,
image_upload: true,
hide_content_type: true,
content_id_helper: localize(
"ui.panel.lovelace.editor.card.picture.content_id_helper"
),
},
},
},
{ name: "camera_image", selector: { entity: { domain: "camera" } } },
{
name: "camera_view",
@@ -119,7 +140,7 @@ export class HuiImageElementEditor
return html`
<ha-form
.hass=${this.hass}
.data=${this._config}
.data=${this._processData(this._config)}
.schema=${this._schema(this.hass.localize)}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
@@ -127,6 +148,13 @@ export class HuiImageElementEditor
`;
}
private _processData = memoizeOne((config: ImageElementConfig) => ({
...config,
...(typeof config.image === "string"
? { image: { media_content_id: config.image } }
: {}),
}));
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
}

View File

@@ -1,4 +1,9 @@
import { mdiDelete, mdiDrag, mdiPencil, mdiPlus } from "@mdi/js";
import {
mdiDelete,
mdiDragHorizontalVariant,
mdiPencil,
mdiPlus,
} from "@mdi/js";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
@@ -345,7 +350,9 @@ export class HuiCardFeaturesEditor extends LitElement {
return html`
<div class="feature">
<div class="handle">
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
<div class="feature-content">
<div>

View File

@@ -1,5 +1,10 @@
import "@material/mwc-menu/mwc-menu-surface";
import { mdiDelete, mdiDrag, mdiPencil, mdiPlus } from "@mdi/js";
import {
mdiDelete,
mdiDragHorizontalVariant,
mdiPencil,
mdiPlus,
} from "@mdi/js";
import type { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
@@ -86,7 +91,9 @@ export class HuiHeadingBadgesEditor extends LitElement {
return html`
<div class="badge">
<div class="handle">
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon
.path=${mdiDragHorizontalVariant}
></ha-svg-icon>
</div>
<div class="badge-content">
<span>${label}</span>

View File

@@ -11,6 +11,7 @@ import {
optional,
string,
type,
union,
} from "superstruct";
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
import { fireEvent } from "../../../../common/dom/fire_event";
@@ -37,14 +38,14 @@ const genericElementConfigStruct = type({
const cardConfigStruct = assign(
baseLovelaceCardConfig,
object({
image: optional(string()),
image: optional(union([string(), object()])),
camera_image: optional(string()),
camera_view: optional(string()),
elements: array(genericElementConfigStruct),
title: optional(string()),
state_filter: optional(any()),
theme: optional(string()),
dark_mode_image: optional(string()),
dark_mode_image: optional(union([string(), object()])),
dark_mode_filter: optional(any()),
})
);
@@ -76,8 +77,34 @@ export class HuiPictureElementsCardEditor
),
schema: [
{ name: "title", selector: { text: {} } },
{ name: "image", selector: { image: {} } },
{ name: "dark_mode_image", selector: { image: {} } },
{
name: "image",
selector: {
media: {
accept: ["image/*"] as string[],
clearable: true,
image_upload: true,
hide_content_type: true,
content_id_helper: localize(
"ui.panel.lovelace.editor.card.picture.content_id_helper"
),
},
},
},
{
name: "dark_mode_image",
selector: {
media: {
accept: ["image/*"] as string[],
clearable: true,
image_upload: true,
hide_content_type: true,
content_id_helper: localize(
"ui.panel.lovelace.editor.card.picture.content_id_helper"
),
},
},
},
{
name: "camera_image",
selector: { entity: { domain: "camera" } },
@@ -124,7 +151,7 @@ export class HuiPictureElementsCardEditor
return html`
<ha-form
.hass=${this.hass}
.data=${this._config}
.data=${this._processData(this._config)}
.schema=${this._schema(this.hass.localize)}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._formChanged}
@@ -138,6 +165,16 @@ export class HuiPictureElementsCardEditor
`;
}
private _processData = memoizeOne((config: PictureElementsCardConfig) => ({
...config,
...(typeof config.image === "string"
? { image: { media_content_id: config.image } }
: {}),
...(typeof config.dark_mode_image === "string"
? { dark_mode_image: { media_content_id: config.dark_mode_image } }
: {}),
}));
private _formChanged(ev: CustomEvent): void {
ev.stopPropagation();
if (!this._config || !this.hass) {

View File

@@ -11,6 +11,7 @@ import {
object,
optional,
string,
union,
} from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeFunc } from "../../../../common/translations/localize";
@@ -40,7 +41,7 @@ const cardConfigStruct = assign(
object({
title: optional(string()),
entity: optional(string()),
image: optional(string()),
image: optional(union([string(), object()])),
image_entity: optional(string()),
camera_image: optional(string()),
camera_view: optional(enums(["auto", "live"])),
@@ -71,7 +72,20 @@ export class HuiPictureGlanceCardEditor
(localize: LocalizeFunc) =>
[
{ name: "title", selector: { text: {} } },
{ name: "image", selector: { image: {} } },
{
name: "image",
selector: {
media: {
accept: ["image/*"] as string[],
clearable: true,
image_upload: true,
hide_content_type: true,
content_id_helper: localize(
"ui.panel.lovelace.editor.card.picture.content_id_helper"
),
},
},
},
{
name: "image_entity",
selector: { entity: { domain: ["image", "person"] } },
@@ -232,12 +246,10 @@ export class HuiPictureGlanceCardEditor
`;
}
const data = { camera_view: "auto", fit_mode: "cover", ...this._config };
return html`
<ha-form
.hass=${this.hass}
.data=${data}
.data=${this._processData(this._config)}
.schema=${this._schema(this.hass.localize)}
.computeLabel=${this._computeLabelCallback}
.computeHelper=${this._computeHelperCallback}
@@ -255,6 +267,15 @@ export class HuiPictureGlanceCardEditor
`;
}
private _processData = memoizeOne((config: PictureGlanceCardConfig) => ({
camera_view: "auto",
fit_mode: "cover",
...config,
...(typeof config.image === "string"
? { image: { media_content_id: config.image } }
: {}),
}));
private _goBack(): void {
this._subElementEditorConfig = undefined;
}

View File

@@ -1,4 +1,4 @@
import { mdiClose, mdiDrag, mdiPencil } from "@mdi/js";
import { mdiClose, mdiDragHorizontalVariant, mdiPencil } from "@mdi/js";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
@@ -59,7 +59,7 @@ export class HuiEntitiesCardRowEditor extends LitElement {
(entityConf, index) => html`
<div class="entity">
<div class="handle">
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
<ha-svg-icon .path=${mdiDragHorizontalVariant}></ha-svg-icon>
</div>
${entityConf.type
? html`

View File

@@ -153,13 +153,21 @@ export class HuiPictureElementsCardRowEditor extends LitElement {
(element as ServiceButtonElementConfig).service ??
""
);
case "image":
return (
element.title ??
(element as ImageElementConfig).image ??
(element as ImageElementConfig).camera_image ??
""
);
case "image": {
if (element.title) {
return element.title;
}
const config = element as ImageElementConfig;
if (config.image) {
if (typeof config.image === "string") {
return config.image;
}
return (
config.image.metadata?.title || config.image.media_content_id || ""
);
}
return config.camera_image || "";
}
case "conditional":
return (
element.title ??

View File

@@ -50,6 +50,12 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
stateObj = this.hass.states[this._config.image_entity] as ImageEntity;
}
const image = stateObj
? computeImageUrl(stateObj)
: (typeof this._config?.image === "object" &&
this._config.image.media_content_id) ||
(this._config.image as string | undefined);
return html`
<div
@action=${this._handleAction}
@@ -67,7 +73,7 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
<hui-image
.hass=${this.hass}
.entity=${this._config.entity}
.image=${stateObj ? computeImageUrl(stateObj) : this._config.image}
.image=${image}
.stateImage=${this._config.state_image}
.cameraImage=${this._config.camera_image}
.cameraView=${this._config.camera_view}

View File

@@ -3,6 +3,7 @@ import type { ActionConfig } from "../../../data/lovelace/config/action";
import type { HomeAssistant } from "../../../types";
import type { Condition } from "../common/validate-condition";
import type { HuiImage } from "../components/hui-image";
import type { MediaSelectorValue } from "../../../data/selector";
interface LovelaceElementConfigBase {
type: string;
@@ -45,7 +46,7 @@ export interface ImageElementConfig extends LovelaceElementConfigBase {
tap_action?: ActionConfig;
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
image?: string;
image?: string | MediaSelectorValue;
image_entity?: string;
state_image?: string;
camera_image?: string;

View File

@@ -518,6 +518,7 @@ class HUIRoot extends LitElement {
${isSubview
? html`
<ha-icon-button-arrow-prev
.hass=${this.hass}
slot="navigationIcon"
@click=${this._goBack}
></ha-icon-button-arrow-prev>

View File

@@ -3909,6 +3909,7 @@
"edit_yaml": "Edit in YAML",
"edit_ui": "Edit in visual editor",
"copy_to_clipboard": "Copy to clipboard",
"search_in": "Search · {group}",
"unknown_entity": "unknown entity",
"edit_unknown_device": "Editor not available for unknown device",
"switch_ui_yaml_error": "There are currently YAML errors in the automation, and it cannot be parsed. Switching to UI mode may cause pending changes to be lost. Press cancel to correct any errors before proceeding to prevent loss of pending changes, or continue if you are sure.",
@@ -3921,7 +3922,6 @@
"item_pasted": "{item} pasted",
"ctrl": "Ctrl",
"del": "Del",
"blocks": "Blocks",
"triggers": {
"name": "Triggers",
"header": "When",
@@ -3929,7 +3929,7 @@
"learn_more": "Learn more about triggers",
"triggered": "Triggered",
"add": "Add trigger",
"empty_search": "No triggers found for {term}",
"search": "Search trigger",
"id": "Trigger ID",
"id_helper": "Helps identify each run based on which trigger fired.",
"optional": "Optional",
@@ -3950,16 +3950,14 @@
"trigger": "Trigger",
"copied_to_clipboard": "Trigger copied to clipboard",
"cut_to_clipboard": "Trigger cut to clipboard",
"select": "Select a trigger",
"groups": {
"device": {
"label": "Device"
},
"entity": {
"label": "Entity"
"label": "Entity",
"description": "When something happens to an entity."
},
"time_location": {
"label": "Time and location"
"label": "Time and location",
"description": "When someone enters or leaves a zone, or at a specific time."
},
"other": {
"label": "Other triggers"
@@ -4192,7 +4190,7 @@
"description": "All conditions added here need to be satisfied for the automation to run. A condition can be satisfied or not at any given time, for example: ''If {user} is home''. You can use building blocks to create more complex conditions.",
"learn_more": "Learn more about conditions",
"add": "Add condition",
"empty_search": "No conditions and blocks found for {term}",
"search": "Search condition",
"add_building_block": "Add building block",
"test": "Test",
"testing_error": "Condition did not pass",
@@ -4214,19 +4212,21 @@
"condition": "Condition",
"copied_to_clipboard": "Condition copied to clipboard",
"cut_to_clipboard": "Condition cut to clipboard",
"select": "Select a condition",
"groups": {
"entity": {
"label": "Entity"
"label": "Entity",
"description": "If an entity is in a specific state."
},
"time_location": {
"label": "Time and location"
"label": "Time and location",
"description": "If someone is in a zone or if the current time is before or after a specified time."
},
"other": {
"label": "Other conditions"
},
"building_blocks": {
"label": "Building blocks"
"label": "Building blocks",
"description": "Build more complex conditions."
}
},
"type": {
@@ -4357,7 +4357,7 @@
"description": "All actions added here will be performed in sequence when the automation runs. An action usually controls one of your areas, devices, or entities, for example: 'Turn on the lights'. You can use building blocks to create more complex sequences of actions.",
"learn_more": "Learn more about actions",
"add": "Add action",
"empty_search": "No actions and blocks found for {term}",
"search": "Search action",
"add_building_block": "Add building block",
"invalid_action": "Invalid action",
"run": "Run action",
@@ -4381,7 +4381,6 @@
"action": "Action",
"copied_to_clipboard": "Action copied to clipboard",
"cut_to_clipboard": "Action cut to clipboard",
"select": "Select an action",
"groups": {
"helpers": {
"label": "Helpers"
@@ -4390,7 +4389,8 @@
"label": "Other actions"
},
"building_blocks": {
"label": "Building blocks"
"label": "Building blocks",
"description": "Build more complex sequences of actions."
}
},
"type": {