Compare commits

..

4 Commits

Author SHA1 Message Date
J. Nick Koston
6b4493078d switch 2025-09-01 09:40:03 -05:00
J. Nick Koston
369c7eb370 cleanup 2025-08-31 10:10:36 -05:00
J. Nick Koston
538b9125f8 Show scanner current state in the Bluetooth UI
The state updates live as the scanner changes mode, and provides
a warning on what to do if the scanner gets in a bad state
2025-08-31 09:59:13 -05:00
J. Nick Koston
58ac95ed4f Show scanner current state in the Bluetooth UI
The state updates live as the scanner changes mode, and provides
a warning on what to do if the scanner gets in a bad state
2025-08-31 09:54:13 -05:00
45 changed files with 466 additions and 766 deletions

View File

@@ -1106,7 +1106,7 @@ export default {
friendly_name: "Philips Hue",
entity_picture: null,
description:
"Press the button on the bridge to register Philips Hue with Home Assistant.",
"Press the button on the bridge to register Philips Hue with Home Assistant.\n\n![Description image](/static/images/config_philips_hue.jpg)",
submit_caption: "I have pressed the button",
},
last_changed: "2018-07-19T10:44:46.515160+00:00",

View File

@@ -123,7 +123,7 @@
"lit": "3.3.1",
"lit-html": "3.3.1",
"luxon": "3.7.1",
"marked": "16.2.1",
"marked": "16.2.0",
"memoize-one": "6.0.0",
"node-vibrant": "4.0.3",
"object-hash": "3.0.0",
@@ -159,7 +159,7 @@
"@octokit/plugin-retry": "8.0.1",
"@octokit/rest": "22.0.0",
"@rsdoctor/rspack-plugin": "1.2.3",
"@rspack/core": "1.5.1",
"@rspack/core": "1.5.0",
"@rspack/dev-server": "1.1.4",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.22",

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -25,8 +25,6 @@ export class HaAutomationRow extends LitElement {
@property({ type: Boolean, reflect: true, attribute: "building-block" })
public buildingBlock = false;
@property({ type: Boolean, reflect: true }) public highlight?: boolean;
@query(".row")
private _rowElement?: HTMLDivElement;
@@ -170,20 +168,9 @@ export class HaAutomationRow extends LitElement {
margin: 0 12px;
}
:host([sort-selected]) .row {
outline: solid;
outline-color: rgba(var(--rgb-accent-color), 0.6);
outline-offset: -2px;
outline-width: 2px;
background-color: rgba(var(--rgb-accent-color), 0.08);
}
.row:hover {
background-color: rgba(var(--rgb-primary-text-color), 0.04);
}
:host([highlight]) .row {
background-color: rgba(var(--rgb-primary-color), 0.08);
}
:host([highlight]) .row:hover {
background-color: rgba(var(--rgb-primary-color), 0.16);
box-shadow:
0px 0px 8px 4px rgba(var(--rgb-accent-color), 0.8),
inset 0px 2px 8px 4px rgba(var(--rgb-accent-color), 0.4);
}
`;
}

View File

@@ -393,13 +393,10 @@ export class HaItemDisplayEditor extends LitElement {
--md-list-item-one-line-container-height: 48px;
}
ha-md-list-item.drag-selected {
--md-focus-ring-color: rgba(var(--rgb-accent-color), 0.6);
box-shadow:
0px 0px 8px 4px rgba(var(--rgb-accent-color), 0.8),
inset 0px 2px 8px 4px rgba(var(--rgb-accent-color), 0.4);
border-radius: 8px;
outline: solid;
outline-color: rgba(var(--rgb-accent-color), 0.6);
outline-offset: -2px;
outline-width: 2px;
background-color: rgba(var(--rgb-accent-color), 0.08);
}
ha-md-list-item ha-icon-button {
margin-left: -12px;

View File

@@ -556,6 +556,7 @@ export interface AutomationClipboard {
}
export interface BaseSidebarConfig {
toggleYamlMode: () => boolean;
delete: () => void;
close: (focus?: boolean) => void;
}
@@ -567,7 +568,6 @@ export interface TriggerSidebarConfig extends BaseSidebarConfig {
duplicate: () => void;
cut: () => void;
copy: () => void;
toggleYamlMode: () => void;
config: Trigger;
yamlMode: boolean;
uiSupported: boolean;
@@ -581,7 +581,6 @@ export interface ConditionSidebarConfig extends BaseSidebarConfig {
duplicate: () => void;
cut: () => void;
copy: () => void;
toggleYamlMode: () => void;
config: Condition;
yamlMode: boolean;
uiSupported: boolean;
@@ -595,7 +594,6 @@ export interface ActionSidebarConfig extends BaseSidebarConfig {
cut: () => void;
copy: () => void;
run: () => void;
toggleYamlMode: () => void;
config: {
action: Action;
};
@@ -617,7 +615,6 @@ export interface ScriptFieldSidebarConfig extends BaseSidebarConfig {
key: string;
excludeKeys: string[];
};
toggleYamlMode: () => void;
yamlMode: boolean;
}

View File

@@ -55,6 +55,13 @@ export interface BluetoothAllocationsData {
allocated: string[];
}
export interface BluetoothScannerState {
source: string;
adapter: string;
current_mode: "active" | "passive" | null;
requested_mode: "active" | "passive" | null;
}
export const subscribeBluetoothScannersDetailsUpdates = (
conn: Connection,
store: Store<BluetoothScannersDetails>
@@ -170,3 +177,20 @@ export const subscribeBluetoothConnectionAllocations = (
params
);
};
export const subscribeBluetoothScannerState = (
conn: Connection,
callbackFunction: (scannerState: BluetoothScannerState) => void,
configEntryId?: string
): Promise<() => Promise<void>> => {
const params: { type: string; config_entry_id?: string } = {
type: "bluetooth/subscribe_scanner_state",
};
if (configEntryId) {
params.config_entry_id = configEntryId;
}
return conn.subscribeMessage<BluetoothScannerState>(
(scannerState) => callbackFunction(scannerState),
params
);
};

View File

@@ -97,7 +97,7 @@ export default class HaAutomationActionEditor extends LitElement {
if (!ev.detail.isValid) {
return;
}
fireEvent(this, "yaml-changed", {
fireEvent(this, "value-changed", {
value: migrateAutomationAction(ev.detail.value),
});
}

View File

@@ -151,8 +151,6 @@ export default class HaAutomationActionRow extends LitElement {
@property({ type: Boolean }) public last?: boolean;
@property({ type: Boolean }) public highlight?: boolean;
@property({ type: Boolean, attribute: "sidebar" })
public optionsInSidebar = false;
@@ -449,7 +447,6 @@ export default class HaAutomationActionRow extends LitElement {
))}
.collapsed=${this._collapsed}
.selected=${this._selected}
.highlight=${this.highlight}
@toggle-collapsed=${this._toggleCollapse}
.buildingBlock=${[
...ACTION_BUILDING_BLOCKS,
@@ -691,7 +688,7 @@ export default class HaAutomationActionRow extends LitElement {
},
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
return this._yamlMode;
},
disable: this._onDisable,
delete: this._onDelete,

View File

@@ -6,6 +6,7 @@ import { customElement, property, queryAll, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { storage } from "../../../../common/decorators/storage";
import { fireEvent } from "../../../../common/dom/fire_event";
import { listenMediaQuery } from "../../../../common/dom/media_query";
import { nextRender } from "../../../../common/util/render-status";
import "../../../../components/ha-button";
import "../../../../components/ha-sortable";
@@ -45,6 +46,8 @@ export default class HaAutomationAction extends LitElement {
@property({ type: Boolean, attribute: "sidebar" }) public optionsInSidebar =
false;
@state() private _showReorder = false;
@state() private _rowSortSelected?: number;
@state()
@@ -65,12 +68,27 @@ export default class HaAutomationAction extends LitElement {
private _actionKeys = new WeakMap<Action, string>();
private _unsubMql?: () => void;
public connectedCallback() {
super.connectedCallback();
this._unsubMql = listenMediaQuery("(min-width: 600px)", (matches) => {
this._showReorder = matches;
});
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
protected render() {
return html`
<ha-sortable
handle-selector=".handle"
draggable-selector="ha-automation-action-row"
.disabled=${this.disabled}
.disabled=${!this._showReorder || this.disabled}
group="actions"
invert-swap
@item-moved=${this._actionMoved}
@@ -97,12 +115,12 @@ export default class HaAutomationAction extends LitElement {
@move-up=${this._moveUp}
@value-changed=${this._actionChanged}
.hass=${this.hass}
.highlight=${this.highlightedActions?.includes(action)}
?highlight=${this.highlightedActions?.includes(action)}
.optionsInSidebar=${this.optionsInSidebar}
.sortSelected=${this._rowSortSelected === idx}
@stop-sort-selection=${this._stopSortSelection}
>
${!this.disabled
${this._showReorder && !this.disabled
? html`
<div
tabindex="0"

View File

@@ -103,7 +103,8 @@ export default class HaAutomationConditionEditor extends LitElement {
if (!ev.detail.isValid) {
return;
}
fireEvent(this, "yaml-changed", { value: ev.detail.value });
// @ts-ignore
fireEvent(this, "value-changed", { value: ev.detail.value, yaml: true });
}
private _onUiChanged(ev: CustomEvent) {

View File

@@ -116,8 +116,6 @@ export default class HaAutomationConditionRow extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ type: Boolean }) public highlight?: boolean;
@property({ type: Boolean, attribute: "sort-selected" })
public sortSelected = false;
@@ -357,7 +355,6 @@ export default class HaAutomationConditionRow extends LitElement {
)}
.collapsed=${this._collapsed}
.selected=${this._selected}
.highlight=${this.highlight}
@click=${this._toggleSidebar}
@toggle-collapsed=${this._toggleCollapse}
.buildingBlock=${CONDITION_BUILDING_BLOCKS.includes(
@@ -663,7 +660,7 @@ export default class HaAutomationConditionRow extends LitElement {
},
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
return this._yamlMode;
},
disable: this._onDisable,
delete: this._onDelete,

View File

@@ -6,6 +6,7 @@ import { customElement, property, queryAll, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { storage } from "../../../../common/decorators/storage";
import { fireEvent } from "../../../../common/dom/fire_event";
import { listenMediaQuery } from "../../../../common/dom/media_query";
import { nextRender } from "../../../../common/util/render-status";
import "../../../../components/ha-button";
import "../../../../components/ha-button-menu";
@@ -43,6 +44,8 @@ export default class HaAutomationCondition extends LitElement {
@property({ type: Boolean, attribute: "sidebar" }) public optionsInSidebar =
false;
@state() private _showReorder = false;
@state() private _rowSortSelected?: number;
@state()
@@ -63,6 +66,21 @@ export default class HaAutomationCondition extends LitElement {
private _conditionKeys = new WeakMap<Condition, string>();
private _unsubMql?: () => void;
public connectedCallback() {
super.connectedCallback();
this._unsubMql = listenMediaQuery("(min-width: 600px)", (matches) => {
this._showReorder = matches;
});
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
protected updated(changedProperties: PropertyValues) {
if (!changedProperties.has("conditions")) {
return;
@@ -147,7 +165,7 @@ export default class HaAutomationCondition extends LitElement {
<ha-sortable
handle-selector=".handle"
draggable-selector="ha-automation-condition-row"
.disabled=${this.disabled}
.disabled=${!this._showReorder || this.disabled}
group="conditions"
invert-swap
@item-moved=${this._conditionMoved}
@@ -175,12 +193,12 @@ export default class HaAutomationCondition extends LitElement {
@move-up=${this._moveUp}
@value-changed=${this._conditionChanged}
.hass=${this.hass}
.highlight=${this.highlightedConditions?.includes(cond)}
?highlight=${this.highlightedConditions?.includes(cond)}
.optionsInSidebar=${this.optionsInSidebar}
.sortSelected=${this._rowSortSelected === idx}
@stop-sort-selection=${this._stopSortSelection}
>
${!this.disabled
${this._showReorder && !this.disabled
? html`
<div
tabindex="0"

View File

@@ -1,5 +1,6 @@
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-bottom-sheet";
import type { HaBottomSheet } from "../../../components/ha-bottom-sheet";
import {
@@ -33,8 +34,6 @@ export default class HaAutomationSidebar extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "sidebar-key" }) public sidebarKey?: string;
@state() private _yamlMode = false;
@query("ha-bottom-sheet") private _bottomSheetElement?: HaBottomSheet;
@@ -53,7 +52,6 @@ export default class HaAutomationSidebar extends LitElement {
.narrow=${this.narrow}
.disabled=${this.disabled}
.yamlMode=${this._yamlMode}
.sidebarKey=${this.sidebarKey}
@toggle-yaml-mode=${this._toggleYamlMode}
@close-sidebar=${this._handleCloseSidebar}
></ha-automation-sidebar-trigger>
@@ -69,7 +67,6 @@ export default class HaAutomationSidebar extends LitElement {
.narrow=${this.narrow}
.disabled=${this.disabled}
.yamlMode=${this._yamlMode}
.sidebarKey=${this.sidebarKey}
@toggle-yaml-mode=${this._toggleYamlMode}
@close-sidebar=${this._handleCloseSidebar}
></ha-automation-sidebar-condition>
@@ -85,7 +82,6 @@ export default class HaAutomationSidebar extends LitElement {
.narrow=${this.narrow}
.disabled=${this.disabled}
.yamlMode=${this._yamlMode}
.sidebarKey=${this.sidebarKey}
@toggle-yaml-mode=${this._toggleYamlMode}
@close-sidebar=${this._handleCloseSidebar}
></ha-automation-sidebar-action>
@@ -114,7 +110,6 @@ export default class HaAutomationSidebar extends LitElement {
.narrow=${this.narrow}
.disabled=${this.disabled}
.yamlMode=${this._yamlMode}
.sidebarKey=${this.sidebarKey}
@toggle-yaml-mode=${this._toggleYamlMode}
@close-sidebar=${this._handleCloseSidebar}
></ha-automation-sidebar-script-field-selector>
@@ -130,7 +125,6 @@ export default class HaAutomationSidebar extends LitElement {
.narrow=${this.narrow}
.disabled=${this.disabled}
.yamlMode=${this._yamlMode}
.sidebarKey=${this.sidebarKey}
@toggle-yaml-mode=${this._toggleYamlMode}
@close-sidebar=${this._handleCloseSidebar}
></ha-automation-sidebar-script-field>
@@ -203,7 +197,13 @@ export default class HaAutomationSidebar extends LitElement {
}
private _toggleYamlMode = () => {
(this.config as ActionSidebarConfig)?.toggleYamlMode();
this._yamlMode = this.config!.toggleYamlMode();
fireEvent(this, "value-changed", {
value: {
...this.config,
yamlMode: this._yamlMode,
},
});
};
static styles = css`
@@ -235,8 +235,5 @@ declare global {
interface HASSDomEvents {
"toggle-yaml-mode": undefined;
"yaml-changed": {
value: unknown;
};
}
}

View File

@@ -92,8 +92,6 @@ export class HaManualAutomationEditor extends LitElement {
@state() private _sidebarConfig?: SidebarConfig;
@state() private _sidebarKey?: string;
@query("ha-automation-sidebar") private _sidebarElement?: HaAutomationSidebar;
private _previousConfig?: ManualAutomationConfig;
@@ -289,7 +287,6 @@ export class HaManualAutomationEditor extends LitElement {
.config=${this._sidebarConfig}
@value-changed=${this._sidebarConfigChanged}
.disabled=${this.disabled}
.sidebarKey=${this._sidebarKey}
></ha-automation-sidebar>
</div>
</div>
@@ -317,7 +314,6 @@ export class HaManualAutomationEditor extends LitElement {
// deselect previous selected row
this._sidebarConfig?.close?.();
this._sidebarConfig = ev.detail;
this._sidebarKey = JSON.stringify(this._sidebarConfig);
await this._sidebarElement?.updateComplete;
this._sidebarElement?.focus();

View File

@@ -395,6 +395,7 @@ export default class HaAutomationOptionRow extends LitElement {
rename: () => {
this._renameOption();
},
toggleYamlMode: () => false, // no yaml mode for options
delete: this._removeOption,
duplicate: this._duplicateOption,
defaultOption: !!this.defaultActions,

View File

@@ -6,6 +6,7 @@ import { customElement, property, queryAll, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { storage } from "../../../../common/decorators/storage";
import { fireEvent } from "../../../../common/dom/fire_event";
import { listenMediaQuery } from "../../../../common/dom/media_query";
import { nextRender } from "../../../../common/util/render-status";
import "../../../../components/ha-button";
import "../../../../components/ha-sortable";
@@ -34,6 +35,8 @@ export default class HaAutomationOption extends LitElement {
@property({ type: Boolean, attribute: "show-default" })
public showDefaultActions = false;
@state() private _showReorder = false;
@state() private _rowSortSelected?: number;
@state()
@@ -54,12 +57,27 @@ export default class HaAutomationOption extends LitElement {
private _optionsKeys = new WeakMap<Option, string>();
private _unsubMql?: () => void;
public connectedCallback() {
super.connectedCallback();
this._unsubMql = listenMediaQuery("(min-width: 600px)", (matches) => {
this._showReorder = matches;
});
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
protected render() {
return html`
<ha-sortable
handle-selector=".handle"
draggable-selector="ha-automation-option-row"
.disabled=${this.disabled}
.disabled=${!this._showReorder || this.disabled}
group="options"
invert-swap
@item-moved=${this._optionMoved}
@@ -89,7 +107,7 @@ export default class HaAutomationOption extends LitElement {
.sortSelected=${this._rowSortSelected === idx}
@stop-sort-selection=${this._stopSortSelection}
>
${!this.disabled
${this._showReorder && !this.disabled
? html`
<div
tabindex="0"

View File

@@ -1,12 +1,11 @@
import { css, type CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-button";
import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-yaml-editor";
import { css, type CSSResultGroup, html, LitElement, nothing } from "lit";
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
import { haStyle, haStyleDialog } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
import { fireEvent } from "../../../../common/dom/fire_event";
import { haStyle, haStyleDialog } from "../../../../resources/styles";
import { createCloseHeading } from "../../../../components/ha-dialog";
import "../trigger/ha-automation-trigger-row";
import type { PasteReplaceDialogParams } from "./show-dialog-paste-replace";
@customElement("ha-dialog-paste-replace")

View File

@@ -11,7 +11,6 @@ import {
} from "@mdi/js";
import { html, LitElement } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import type { LocalizeKeys } from "../../../../common/translations/localize";
@@ -42,8 +41,6 @@ export default class HaAutomationSidebarAction extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "sidebar-key" }) public sidebarKey?: string;
@state() private _warnings?: string[];
@query(".sidebar-editor")
@@ -184,22 +181,18 @@ export default class HaAutomationSidebarAction extends LitElement {
</ha-md-menu-item>
${description && !this.yamlMode
? html`<div class="description">${description}</div>`
: keyed(
this.sidebarKey,
html`<ha-automation-action-editor
class="sidebar-editor"
.hass=${this.hass}
.action=${actionConfig}
.yamlMode=${this.yamlMode}
.uiSupported=${this.config.uiSupported}
@value-changed=${this._valueChangedSidebar}
@yaml-changed=${this._yamlChangedSidebar}
sidebar
narrow
.disabled=${this.disabled}
@ui-mode-not-available=${this._handleUiModeNotAvailable}
></ha-automation-action-editor>`
)}
: html`<ha-automation-action-editor
class="sidebar-editor"
.hass=${this.hass}
.action=${actionConfig}
.yamlMode=${this.yamlMode}
.uiSupported=${this.config.uiSupported}
@value-changed=${this._valueChangedSidebar}
sidebar
narrow
.disabled=${this.disabled}
@ui-mode-not-available=${this._handleUiModeNotAvailable}
></ha-automation-action-editor>`}
</ha-automation-sidebar-card>`;
}
@@ -227,12 +220,6 @@ export default class HaAutomationSidebarAction extends LitElement {
}
}
private _yamlChangedSidebar(ev: CustomEvent) {
ev.stopPropagation();
this.config?.save?.(ev.detail.value);
}
private _toggleYamlMode = () => {
fireEvent(this, "toggle-yaml-mode");
};

View File

@@ -11,7 +11,6 @@ import {
} from "@mdi/js";
import { html, LitElement } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import type { ConditionSidebarConfig } from "../../../../data/automation";
@@ -36,8 +35,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "sidebar-key" }) public sidebarKey?: string;
@state() private _warnings?: string[];
@query(".sidebar-editor")
@@ -176,21 +173,17 @@ export default class HaAutomationSidebarCondition extends LitElement {
</ha-md-menu-item>
${description && !this.yamlMode
? html`<div class="description">${description}</div>`
: keyed(
this.sidebarKey,
html`<ha-automation-condition-editor
class="sidebar-editor"
.hass=${this.hass}
.condition=${this.config.config}
.yamlMode=${this.yamlMode}
.uiSupported=${this.config.uiSupported}
@value-changed=${this._valueChangedSidebar}
@yaml-changed=${this._yamlChangedSidebar}
.disabled=${this.disabled}
@ui-mode-not-available=${this._handleUiModeNotAvailable}
sidebar
></ha-automation-condition-editor>`
)}
: html`<ha-automation-condition-editor
class="sidebar-editor"
.hass=${this.hass}
.condition=${this.config.config}
.yamlMode=${this.yamlMode}
.uiSupported=${this.config.uiSupported}
@value-changed=${this._valueChangedSidebar}
.disabled=${this.disabled}
@ui-mode-not-available=${this._handleUiModeNotAvailable}
sidebar
></ha-automation-condition-editor> `}
</ha-automation-sidebar-card>`;
}
@@ -216,12 +209,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
}
}
private _yamlChangedSidebar(ev: CustomEvent) {
ev.stopPropagation();
this.config?.save?.(ev.detail.value);
}
private _toggleYamlMode = () => {
fireEvent(this, "toggle-yaml-mode");
};

View File

@@ -1,7 +1,6 @@
import { mdiDelete, mdiPlaylistEdit } from "@mdi/js";
import { html, LitElement } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeKeys } from "../../../../common/translations/localize";
import type { ScriptFieldSidebarConfig } from "../../../../data/automation";
@@ -25,8 +24,6 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "sidebar-key" }) public sidebarKey?: string;
@state() private _warnings?: string[];
@query(".sidebar-editor")
@@ -84,18 +81,14 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
)}
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
</ha-md-menu-item>
${keyed(
this.sidebarKey,
html`<ha-script-field-selector-editor
class="sidebar-editor"
.hass=${this.hass}
.field=${this.config.config.field}
.disabled=${this.disabled}
@value-changed=${this._valueChangedSidebar}
@yaml-changed=${this._yamlChangedSidebar}
.yamlMode=${this.yamlMode}
></ha-script-field-selector-editor>`
)}
<ha-script-field-selector-editor
class="sidebar-editor"
.hass=${this.hass}
.field=${this.config.config.field}
.disabled=${this.disabled}
@value-changed=${this._valueChangedSidebar}
.yamlMode=${this.yamlMode}
></ha-script-field-selector-editor>
</ha-automation-sidebar-card>`;
}
@@ -123,12 +116,6 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
}
}
private _yamlChangedSidebar(ev: CustomEvent) {
ev.stopPropagation();
this.config?.save?.(ev.detail.value);
}
private _toggleYamlMode = () => {
fireEvent(this, "toggle-yaml-mode");
};

View File

@@ -1,7 +1,6 @@
import { mdiDelete, mdiPlaylistEdit } from "@mdi/js";
import { html, LitElement } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { ScriptFieldSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
@@ -24,8 +23,6 @@ export default class HaAutomationSidebarScriptField extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "sidebar-key" }) public sidebarKey?: string;
@state() private _warnings?: string[];
@query(".sidebar-editor")
@@ -77,20 +74,16 @@ export default class HaAutomationSidebarScriptField extends LitElement {
)}
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
</ha-md-menu-item>
${keyed(
this.sidebarKey,
html`<ha-script-field-editor
class="sidebar-editor"
.hass=${this.hass}
.field=${this.config.config.field}
.key=${this.config.config.key}
.excludeKeys=${this.config.config.excludeKeys}
.disabled=${this.disabled}
.yamlMode=${this.yamlMode}
@value-changed=${this._valueChangedSidebar}
@yaml-changed=${this._yamlChangedSidebar}
></ha-script-field-editor>`
)}
<ha-script-field-editor
class="sidebar-editor"
.hass=${this.hass}
.field=${this.config.config.field}
.key=${this.config.config.key}
.excludeKeys=${this.config.config.excludeKeys}
.disabled=${this.disabled}
.yamlMode=${this.yamlMode}
@value-changed=${this._valueChangedSidebar}
></ha-script-field-editor>
</ha-automation-sidebar-card>`;
}
@@ -117,12 +110,6 @@ export default class HaAutomationSidebarScriptField extends LitElement {
}
}
private _yamlChangedSidebar(ev: CustomEvent) {
ev.stopPropagation();
this.config?.save?.(ev.detail.value);
}
private _toggleYamlMode = () => {
fireEvent(this, "toggle-yaml-mode");
};

View File

@@ -11,7 +11,6 @@ import {
} from "@mdi/js";
import { html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import type { TriggerSidebarConfig } from "../../../../data/automation";
@@ -36,8 +35,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "sidebar-key" }) public sidebarKey?: string;
@state() private _requestShowId = false;
@state() private _warnings?: string[];
@@ -186,22 +183,18 @@ export default class HaAutomationSidebarTrigger extends LitElement {
)}
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
</ha-md-menu-item>
${keyed(
this.sidebarKey,
html`<ha-automation-trigger-editor
class="sidebar-editor"
.hass=${this.hass}
.trigger=${this.config.config}
@value-changed=${this._valueChangedSidebar}
@yaml-changed=${this._yamlChangedSidebar}
.uiSupported=${this.config.uiSupported}
.showId=${this._requestShowId}
.yamlMode=${this.yamlMode}
.disabled=${this.disabled}
@ui-mode-not-available=${this._handleUiModeNotAvailable}
sidebar
></ha-automation-trigger-editor>`
)}
<ha-automation-trigger-editor
class="sidebar-editor"
.hass=${this.hass}
.trigger=${this.config.config}
@value-changed=${this._valueChangedSidebar}
.uiSupported=${this.config.uiSupported}
.showId=${this._requestShowId}
.yamlMode=${this.yamlMode}
.disabled=${this.disabled}
@ui-mode-not-available=${this._handleUiModeNotAvailable}
sidebar
></ha-automation-trigger-editor>
</ha-automation-sidebar-card>
`;
}
@@ -228,12 +221,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
}
}
private _yamlChangedSidebar(ev: CustomEvent) {
ev.stopPropagation();
this.config?.save?.(ev.detail.value);
}
private _toggleYamlMode = () => {
fireEvent(this, "toggle-yaml-mode");
};

View File

@@ -37,6 +37,12 @@ export const rowStyles = css`
ha-tooltip {
cursor: default;
}
:host([highlight]) ha-card {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--state-inactive-color);
border-color: var(--state-inactive-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
.hidden {
display: none;
}

View File

@@ -121,7 +121,7 @@ export default class HaAutomationTriggerEditor extends LitElement {
if (!ev.detail.isValid) {
return;
}
fireEvent(this, "yaml-changed", {
fireEvent(this, "value-changed", {
value: migrateAutomationTrigger(ev.detail.value),
});
}

View File

@@ -113,8 +113,6 @@ export default class HaAutomationTriggerRow extends LitElement {
@property({ type: Boolean }) public last?: boolean;
@property({ type: Boolean }) public highlight?: boolean;
@property({ type: Boolean, attribute: "sidebar" })
public optionsInSidebar = false;
@@ -351,7 +349,6 @@ export default class HaAutomationTriggerRow extends LitElement {
this.trigger.enabled === false}
@click=${this._toggleSidebar}
.selected=${this._selected}
.highlight=${this.highlight}
.sortSelected=${this.sortSelected}
>${this._selected
? "selected"
@@ -497,7 +494,7 @@ export default class HaAutomationTriggerRow extends LitElement {
},
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
return this._yamlMode;
},
disable: this._onDisable,
delete: this._onDelete,

View File

@@ -6,6 +6,7 @@ import { customElement, property, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { storage } from "../../../../common/decorators/storage";
import { fireEvent } from "../../../../common/dom/fire_event";
import { listenMediaQuery } from "../../../../common/dom/media_query";
import { nextRender } from "../../../../common/util/render-status";
import "../../../../components/ha-button";
import "../../../../components/ha-button-menu";
@@ -44,6 +45,8 @@ export default class HaAutomationTrigger extends LitElement {
@property({ type: Boolean }) public root = false;
@state() private _showReorder = false;
@state() private _rowSortSelected?: number;
@state()
@@ -61,12 +64,27 @@ export default class HaAutomationTrigger extends LitElement {
private _triggerKeys = new WeakMap<Trigger, string>();
private _unsubMql?: () => void;
public connectedCallback() {
super.connectedCallback();
this._unsubMql = listenMediaQuery("(min-width: 600px)", (matches) => {
this._showReorder = matches;
});
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
protected render() {
return html`
<ha-sortable
handle-selector=".handle"
draggable-selector="ha-automation-trigger-row"
.disabled=${this.disabled}
.disabled=${!this._showReorder || this.disabled}
group="triggers"
invert-swap
@item-moved=${this._triggerMoved}
@@ -92,12 +110,12 @@ export default class HaAutomationTrigger extends LitElement {
.hass=${this.hass}
.disabled=${this.disabled}
.narrow=${this.narrow}
.highlight=${this.highlightedTriggers?.includes(trg)}
?highlight=${this.highlightedTriggers?.includes(trg)}
.optionsInSidebar=${this.optionsInSidebar}
.sortSelected=${this._rowSortSelected === idx}
@stop-sort-selection=${this._stopSortSelection}
>
${!this.disabled
${this._showReorder && !this.disabled
? html`
<div
tabindex="0"

View File

@@ -1,5 +1,5 @@
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../../../components/ha-card";
import "../../../../../components/ha-code-editor";
@@ -11,13 +11,19 @@ import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-d
import "../../../../../layouts/hass-subpage";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
import { subscribeBluetoothConnectionAllocations } from "../../../../../data/bluetooth";
import {
subscribeBluetoothConnectionAllocations,
subscribeBluetoothScannerState,
} from "../../../../../data/bluetooth";
import {
getValueInPercentage,
roundWithOneDecimal,
} from "../../../../../util/calculate";
import "../../../../../components/ha-metric";
import type { BluetoothAllocationsData } from "../../../../../data/bluetooth";
import type {
BluetoothAllocationsData,
BluetoothScannerState,
} from "../../../../../data/bluetooth";
@customElement("bluetooth-config-dashboard")
export class BluetoothConfigDashboard extends LitElement {
@@ -29,16 +35,21 @@ export class BluetoothConfigDashboard extends LitElement {
@state() private _connectionAllocationsError?: string;
@state() private _scannerState?: BluetoothScannerState;
private _configEntry = new URLSearchParams(window.location.search).get(
"config_entry"
);
private _unsubConnectionAllocations?: (() => Promise<void>) | undefined;
private _unsubScannerState?: (() => Promise<void>) | undefined;
public connectedCallback(): void {
super.connectedCallback();
if (this.hass) {
this._subscribeBluetoothConnectionAllocations();
this._subscribeBluetoothScannerState();
}
}
@@ -61,12 +72,29 @@ export class BluetoothConfigDashboard extends LitElement {
}
}
private async _subscribeBluetoothScannerState(): Promise<void> {
if (this._unsubScannerState || !this._configEntry) {
return;
}
this._unsubScannerState = await subscribeBluetoothScannerState(
this.hass.connection,
(scannerState) => {
this._scannerState = scannerState;
},
this._configEntry
);
}
public disconnectedCallback() {
super.disconnectedCallback();
if (this._unsubConnectionAllocations) {
this._unsubConnectionAllocations();
this._unsubConnectionAllocations = undefined;
}
if (this._unsubScannerState) {
this._unsubScannerState();
this._unsubScannerState = undefined;
}
}
protected render(): TemplateResult {
@@ -78,6 +106,7 @@ export class BluetoothConfigDashboard extends LitElement {
"ui.panel.config.bluetooth.settings_title"
)}
>
<div class="card-content">${this._renderScannerState()}</div>
<div class="card-actions">
<ha-button @click=${this._openOptionFlow}
>${this.hass.localize(
@@ -142,6 +171,92 @@ export class BluetoothConfigDashboard extends LitElement {
private _getUsedAllocations = (used: number, total: number) =>
roundWithOneDecimal(getValueInPercentage(used, 0, total));
private _renderScannerState() {
if (!this._configEntry || !this._scannerState) {
return html`<div>
${this.hass.localize(
"ui.panel.config.bluetooth.no_scanner_state_available"
)}
</div>`;
}
const scannerState = this._scannerState;
const formatMode = (mode: string | null) => {
switch (mode) {
case null:
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_none"
);
case "active":
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_active"
);
case "passive":
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_passive"
);
default:
return mode; // Fallback for unknown modes
}
};
return html`
<div class="scanner-state">
<div class="state-row">
<span
>${this.hass.localize(
"ui.panel.config.bluetooth.current_scanning_mode"
)}:</span
>
<span class="state-value"
>${formatMode(scannerState.current_mode)}</span
>
</div>
<div class="state-row">
<span
>${this.hass.localize(
"ui.panel.config.bluetooth.requested_scanning_mode"
)}:</span
>
<span class="state-value"
>${formatMode(scannerState.requested_mode)}</span
>
</div>
${scannerState.current_mode !== scannerState.requested_mode
? html`<ha-alert alert-type="warning">
<div>
${this.hass.localize(
"ui.panel.config.bluetooth.scanner_mode_mismatch",
{
requested: formatMode(scannerState.requested_mode),
current: formatMode(scannerState.current_mode),
}
)}
</div>
<ul>
<li>
${this.hass.localize(
"ui.panel.config.bluetooth.scanner_mode_mismatch_proxy"
)}
</li>
<li>
${this.hass.localize(
"ui.panel.config.bluetooth.scanner_mode_mismatch_usb"
)}
</li>
<li>
${this.hass.localize(
"ui.panel.config.bluetooth.scanner_mode_mismatch_onboard"
)}
</li>
</ul>
</ha-alert>`
: nothing}
</div>
`;
}
private _renderConnectionAllocations() {
if (this._connectionAllocationsError) {
return html`<ha-alert alert-type="error"
@@ -220,6 +335,18 @@ export class BluetoothConfigDashboard extends LitElement {
display: flex;
justify-content: flex-end;
}
.scanner-state {
margin-bottom: 16px;
}
.state-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 4px 0;
}
.state-value {
font-weight: 500;
}
`,
];
}

View File

@@ -152,12 +152,7 @@ export default class HaScriptFieldEditor extends LitElement {
ev.stopPropagation();
const value = { ...ev.detail.value };
if (
typeof value !== "object" ||
Object.keys(value).length !== 1 ||
!value[Object.keys(value)[0]] ||
!value[Object.keys(value)[0]].selector
) {
if (typeof value !== "object" || Object.keys(value).length !== 1) {
this._yamlError = "yaml_error";
return;
}
@@ -170,7 +165,7 @@ export default class HaScriptFieldEditor extends LitElement {
const newValue = { ...value[key], key };
fireEvent(this, "yaml-changed", { value: newValue });
fireEvent(this, "value-changed", { value: newValue });
}
private _computeLabelCallback = (

View File

@@ -32,8 +32,6 @@ export default class HaScriptFieldRow extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ type: Boolean }) public highlight?: boolean;
@state() private _yamlMode = false;
@state() private _selected = false;
@@ -63,7 +61,6 @@ export default class HaScriptFieldRow extends LitElement {
left-chevron
@toggle-collapsed=${this._toggleCollapse}
.collapsed=${this._collapsed}
.highlight=${this.highlight}
>
<h3 slot="header">${this.key}</h3>
@@ -86,7 +83,6 @@ export default class HaScriptFieldRow extends LitElement {
.leftChevron=${SELECTOR_SELECTOR_BUILDING_BLOCKS.includes(
Object.keys(this.field.selector)[0]
)}
.highlight=${this.highlight}
>
<h3 slot="header">
${this.hass.localize(
@@ -222,7 +218,7 @@ export default class HaScriptFieldRow extends LitElement {
},
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
return this._yamlMode;
},
delete: this._onDelete,
config: {
@@ -335,6 +331,13 @@ export default class HaScriptFieldRow extends LitElement {
li[role="separator"] {
border-bottom-color: var(--divider-color);
}
:host([highlight]) ha-card {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--state-inactive-color);
border-color: var(--state-inactive-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
.selector-row {
padding: 12px 0 16px 16px;
}

View File

@@ -132,7 +132,7 @@ export default class HaScriptFieldSelectorEditor extends LitElement {
return;
}
fireEvent(this, "yaml-changed", { value });
fireEvent(this, "value-changed", { value });
}
private _computeLabelCallback = (

View File

@@ -43,7 +43,7 @@ export default class HaScriptFields extends LitElement {
.disabled=${this.disabled}
@value-changed=${this._fieldChanged}
.hass=${this.hass}
.highlight=${this.highlightedFields?.[key] !== undefined}
?highlight=${this.highlightedFields?.[key] !== undefined}
.narrow=${this.narrow}
>
</ha-script-field-row>

View File

@@ -73,8 +73,6 @@ export class HaManualScriptEditor extends LitElement {
@state() private _sidebarConfig?: SidebarConfig;
@state() private _sidebarKey?: string;
@query("ha-script-fields")
private _scriptFields?: HaScriptFields;
@@ -225,7 +223,6 @@ export class HaManualScriptEditor extends LitElement {
</div>
<div class="sidebar-positioner">
<ha-automation-sidebar
.sidebarKey=${this._sidebarKey}
tabindex="-1"
class=${classMap({ hidden: !this._sidebarConfig })}
.narrow=${this.narrow}
@@ -466,7 +463,6 @@ export class HaManualScriptEditor extends LitElement {
// deselect previous selected row
this._sidebarConfig?.close?.();
this._sidebarConfig = ev.detail;
this._sidebarKey = JSON.stringify(this._sidebarConfig);
await this._sidebarElement?.updateComplete;
this._sidebarElement?.focus();

View File

@@ -19,6 +19,7 @@ import type {
import { getSensorNumericDeviceClasses } from "../../../data/sensor";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { getGraphColorByIndex } from "../../../common/color/colors";
import { computeTimelineColor } from "../../../components/chart/timeline-color";
import { downSampleLineData } from "../../../components/chart/down-sample";
import { fireEvent } from "../../../common/dom/fire_event";
@@ -92,19 +93,20 @@ class HuiHistoryChartCardFeature
const width = this.clientWidth;
const height = this.clientHeight;
if (line) {
const { points, yAxisOrigin } = this._generateLinePoints(line);
const { paths, filledPaths } = this._getLinePaths(points, yAxisOrigin);
const points = this._generateLinePoints(line);
const { paths, filledPaths } = this._getLinePaths(points);
const color = getGraphColorByIndex(0, this.style);
return html`
<div class="line" @click=${this._handleClick}>
${svg`<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
${paths.map(
(path) =>
svg`<path d="${path}" stroke="var(--feature-color)" stroke-width="1" stroke-linecap="round" fill="none" />`
svg`<path d="${path}" stroke="${color}" stroke-width="1" stroke-linecap="round" fill="none" />`
)}
${filledPaths.map(
(path) =>
svg`<path d="${path}" stroke="none" stroke-linecap="round" fill="var(--feature-color)" fill-opacity="0.2" />`
svg`<path d="${path}" stroke="none" stroke-linecap="round" fill="${color}" fill-opacity="0.2" />`
)}
</svg>`}
</div>
@@ -159,13 +161,9 @@ class HuiHistoryChartCardFeature
);
}
private _generateLinePoints(line: LineChartUnit): {
points: { x: number; y: number }[];
yAxisOrigin: number;
} {
private _generateLinePoints(line: LineChartUnit): { x: number; y: number }[] {
const width = this.clientWidth;
const height = this.clientHeight;
let yAxisOrigin = height;
let minY = Number(line.data[0].states[0].state);
let maxY = Number(line.data[0].states[0].state);
const minX = line.data[0].states[0].last_changed;
@@ -174,7 +172,8 @@ class HuiHistoryChartCardFeature
const stateValue = Number(stateData.state);
if (stateValue < minY) {
minY = stateValue;
} else if (stateValue > maxY) {
}
if (stateValue > maxY) {
maxY = stateValue;
}
});
@@ -188,21 +187,9 @@ class HuiHistoryChartCardFeature
minX,
maxX
);
if (maxY < 0) {
// all values are negative
// add margin
maxY += rangeY * 0.1;
maxY = Math.min(0, maxY);
yAxisOrigin = 0;
} else if (minY < 0) {
// some values are negative
yAxisOrigin = (maxY / (maxY - minY || 1)) * height;
} else {
// all values are positive
// add margin
minY -= rangeY * 0.1;
minY = Math.max(0, minY);
}
// add margin to the min and max
minY -= rangeY * 0.1;
maxY += rangeY * 0.1;
const yDenom = maxY - minY || 1;
const xDenom = maxX - minX || 1;
const points = sampledData!.map((point) => {
@@ -211,7 +198,7 @@ class HuiHistoryChartCardFeature
return { x, y };
});
points.push({ x: width, y: points[points.length - 1].y });
return { points, yAxisOrigin };
return points;
}
private _generateTimelineRanges(timeline: TimelineEntity) {
@@ -247,10 +234,7 @@ class HuiHistoryChartCardFeature
return ranges;
}
private _getLinePaths(
points: { x: number; y: number }[],
yAxisOrigin: number
) {
private _getLinePaths(points: { x: number; y: number }[]) {
const paths: string[] = [];
const filledPaths: string[] = [];
if (!points.length) {
@@ -285,7 +269,7 @@ class HuiHistoryChartCardFeature
paths.push(path);
filledPaths.push(
path +
` L ${next!.x},${yAxisOrigin} L ${pathPoints[0].x},${yAxisOrigin} Z`
` L ${next!.x},${this.clientHeight} L ${pathPoints[0].x},${this.clientHeight} Z`
);
});

View File

@@ -138,7 +138,6 @@ export class HuiHeadingCard extends LitElement implements LovelaceCard {
flex-direction: column;
justify-content: flex-end;
height: 100%;
min-height: 24px;
}
[role="button"] {
cursor: pointer;
@@ -148,7 +147,7 @@ export class HuiHeadingCard extends LitElement implements LovelaceCard {
transition: transform 180ms ease-in-out;
}
.container {
padding: 0 4px;
padding: 2px 4px;
display: flex;
flex-direction: row;
justify-content: space-between;

View File

@@ -1,372 +0,0 @@
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { styleMap } from "lit/directives/style-map";
import { computeCssColor } from "../../../common/color/compute-color";
import { computeDomain } from "../../../common/entity/compute_domain";
import { generateEntityFilter } from "../../../common/entity/entity_filter";
import { formatNumber } from "../../../common/number/format_number";
import "../../../components/ha-card";
import "../../../components/ha-icon";
import "../../../components/ha-ripple";
import "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-info";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import "../../../state-display/state-display";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import {
findEntities,
getSummaryLabel,
HOME_SUMMARIES_FILTERS,
HOME_SUMMARIES_ICONS,
type HomeSummary,
} from "../strategies/home/helpers/home-summaries";
import type { LovelaceCard, LovelaceGridOptions } from "../types";
import type { HomeSummaryCard } from "./types";
const COLORS: Record<HomeSummary, string> = {
lights: "amber",
climate: "deep-orange",
security: "blue",
media_players: "purple",
};
@customElement("hui-home-summary-card")
export class HuiHomeSummaryCard extends LitElement implements LovelaceCard {
@property({ attribute: false }) public hass?: HomeAssistant;
@state() private _config?: HomeSummaryCard;
public setConfig(config: HomeSummaryCard): void {
this._config = config;
}
public getCardSize(): number {
return this._config?.vertical ? 2 : 1;
}
public getGridOptions(): LovelaceGridOptions {
const columns = 6;
let min_columns = 6;
let rows = 1;
if (this._config?.vertical) {
rows++;
min_columns = 3;
}
return {
columns,
rows,
min_columns,
min_rows: rows,
};
}
private _handleAction(ev: ActionHandlerEvent) {
handleAction(this, this.hass!, this._config!, ev.detail.action!);
}
private get _hasCardAction() {
return (
hasAction(this._config?.tap_action) ||
hasAction(this._config?.hold_action) ||
hasAction(this._config?.double_tap_action)
);
}
private _computeSummaryState(): string {
if (!this._config || !this.hass) {
return "";
}
const allEntities = Object.keys(this.hass!.states);
const areas = Object.values(this.hass.areas);
const areasFilter = generateEntityFilter(this.hass, {
area: areas.map((area) => area.area_id),
});
const entitiesInsideArea = allEntities.filter(areasFilter);
switch (this._config.summary) {
case "lights": {
// Number of lights on
const lightsFilters = HOME_SUMMARIES_FILTERS.lights.map((filter) =>
generateEntityFilter(this.hass!, filter)
);
const lightEntities = findEntities(entitiesInsideArea, lightsFilters);
const onLights = lightEntities.filter((entityId) => {
const s = this.hass!.states[entityId]?.state;
return s === "on";
});
return onLights.length
? this.hass.localize("ui.card.home-summary.count_lights_on", {
count: onLights.length,
})
: this.hass.localize("ui.card.home-summary.all_lights_off");
}
case "climate": {
// Min/Max temperature of the areas
const areaSensors = areas
.map((area) => area.temperature_entity_id)
.filter(Boolean);
const sensorsValues = areaSensors
.map(
(entityId) => parseFloat(this.hass!.states[entityId!].state) || NaN
)
.filter((value) => !isNaN(value));
if (sensorsValues.length === 0) {
return "";
}
const minTemp = Math.min(...sensorsValues);
const maxTemp = Math.max(...sensorsValues);
if (isNaN(minTemp) || isNaN(maxTemp)) {
return "";
}
const formattedMinTemp = formatNumber(minTemp, this.hass?.locale, {
minimumFractionDigits: 1,
maximumFractionDigits: 1,
});
const formattedMaxTemp = formatNumber(maxTemp, this.hass?.locale, {
minimumFractionDigits: 1,
maximumFractionDigits: 1,
});
return formattedMinTemp === formattedMaxTemp
? `${formattedMinTemp}°`
: `${formattedMinTemp} - ${formattedMaxTemp}°`;
}
case "security": {
// Alarm and lock status
const securityFilters = HOME_SUMMARIES_FILTERS.security.map((filter) =>
generateEntityFilter(this.hass!, filter)
);
const securityEntities = findEntities(
entitiesInsideArea,
securityFilters
);
const locks = securityEntities.filter((entityId) => {
const domain = computeDomain(entityId);
return domain === "lock";
});
const alarms = securityEntities.filter((entityId) => {
const domain = computeDomain(entityId);
return domain === "alarm_control_panel";
});
const disarmedAlarms = alarms.filter((entityId) => {
const s = this.hass!.states[entityId]?.state;
return s === "disarmed";
});
if (!locks.length && !alarms.length) {
return "";
}
const unlockedLocks = locks.filter((entityId) => {
const s = this.hass!.states[entityId]?.state;
return s === "unlocked" || s === "jammed" || s === "open";
});
if (unlockedLocks.length) {
return this.hass.localize(
"ui.card.home-summary.count_locks_unlocked",
{
count: unlockedLocks.length,
}
);
}
if (disarmedAlarms.length) {
return this.hass.localize(
"ui.card.home-summary.count_alarms_disarmed",
{
count: disarmedAlarms.length,
}
);
}
return this.hass.localize("ui.card.home-summary.all_secure");
}
case "media_players": {
// Playing media
const mediaPlayerFilters = HOME_SUMMARIES_FILTERS.media_players.map(
(filter) => generateEntityFilter(this.hass!, filter)
);
const mediaPlayerEntities = findEntities(
entitiesInsideArea,
mediaPlayerFilters
);
const playingMedia = mediaPlayerEntities.filter((entityId) => {
const s = this.hass!.states[entityId]?.state;
return s === "playing";
});
return playingMedia.length
? this.hass.localize("ui.card.home-summary.count_media_playing", {
count: playingMedia.length,
})
: this.hass.localize("ui.card.home-summary.no_media_playing");
}
}
return "";
}
protected render() {
if (!this._config || !this.hass) {
return nothing;
}
const contentClasses = { vertical: Boolean(this._config.vertical) };
const color = computeCssColor(COLORS[this._config.summary]);
const style = {
"--tile-color": color,
};
const secondary = this._computeSummaryState();
const label = getSummaryLabel(this.hass.localize, this._config.summary);
const icon = HOME_SUMMARIES_ICONS[this._config.summary];
return html`
<ha-card style=${styleMap(style)}>
<div
class="background"
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config!.hold_action),
hasDoubleClick: hasAction(this._config!.double_tap_action),
})}
role=${ifDefined(this._hasCardAction ? "button" : undefined)}
tabindex=${ifDefined(this._hasCardAction ? "0" : undefined)}
aria-labelledby="info"
>
<ha-ripple .disabled=${!this._hasCardAction}></ha-ripple>
</div>
<div class="container">
<div class="content ${classMap(contentClasses)}">
<ha-tile-icon>
<ha-icon slot="icon" .icon=${icon}></ha-icon>
</ha-tile-icon>
<ha-tile-info
id="info"
.primary=${label}
.secondary=${secondary}
></ha-tile-info>
</div>
</div>
</ha-card>
`;
}
static styles = css`
:host {
--tile-color: var(--state-inactive-color);
-webkit-tap-highlight-color: transparent;
}
ha-card:has(.background:focus-visible) {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--tile-color);
border-color: var(--tile-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
ha-card {
--ha-ripple-color: var(--tile-color);
--ha-ripple-hover-opacity: 0.04;
--ha-ripple-pressed-opacity: 0.12;
height: 100%;
transition:
box-shadow 180ms ease-in-out,
border-color 180ms ease-in-out;
display: flex;
flex-direction: column;
justify-content: space-between;
}
ha-card.active {
--tile-color: var(--state-icon-color);
}
[role="button"] {
cursor: pointer;
pointer-events: auto;
}
[role="button"]:focus {
outline: none;
}
.background {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
border-radius: var(--ha-card-border-radius, 12px);
margin: calc(-1 * var(--ha-card-border-width, 1px));
overflow: hidden;
}
.container {
margin: calc(-1 * var(--ha-card-border-width, 1px));
display: flex;
flex-direction: column;
flex: 1;
}
.container.horizontal {
flex-direction: row;
}
.content {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
padding: 10px;
flex: 1;
min-width: 0;
box-sizing: border-box;
pointer-events: none;
gap: 10px;
}
.vertical {
flex-direction: column;
text-align: center;
justify-content: center;
}
.vertical ha-tile-info {
width: 100%;
flex: none;
}
ha-tile-icon {
--tile-icon-color: var(--tile-color);
position: relative;
padding: 6px;
margin: -6px;
}
ha-tile-info {
position: relative;
min-width: 0;
transition: background-color 180ms ease-in-out;
box-sizing: border-box;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"hui-home-summary-card": HuiHomeSummaryCard;
}
}

View File

@@ -26,7 +26,6 @@ import type {
import type { LovelaceHeaderFooterConfig } from "../header-footer/types";
import type { LovelaceHeadingBadgeConfig } from "../heading-badges/types";
import type { TimeFormat } from "../../../data/translation";
import type { HomeSummary } from "../strategies/home/helpers/home-summaries";
export type AlarmPanelCardConfigState =
| "arm_away"
@@ -589,11 +588,3 @@ export interface HeadingCardConfig extends LovelaceCardConfig {
/** @deprecated Use `badges` instead */
entities?: LovelaceHeadingBadgeConfig[];
}
export interface HomeSummaryCard extends LovelaceCardConfig {
summary: HomeSummary;
vertical?: boolean;
tap_action?: ActionConfig;
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
}

View File

@@ -68,7 +68,6 @@ const LAZY_LOAD_TYPES = {
"energy-sankey": () => import("../cards/energy/hui-energy-sankey-card"),
"entity-filter": () => import("../cards/hui-entity-filter-card"),
error: () => import("../cards/hui-error-card"),
"home-summary": () => import("../cards/hui-home-summary-card"),
gauge: () => import("../cards/hui-gauge-card"),
"history-graph": () => import("../cards/hui-history-graph-card"),
"horizontal-stack": () => import("../cards/hui-horizontal-stack-card"),

View File

@@ -355,10 +355,7 @@ class HUIRoot extends LitElement {
overflowItems.forEach((i) => {
const title = [this.hass!.localize(i.key), i.suffix].join(" ");
const action = i.subItems
? (e) => {
if (!shouldHandleRequestSelectedEvent(e)) {
return;
}
? () => {
showListItemsDialog(this, {
title: title,
items: i.subItems!.map((si) => ({

View File

@@ -15,6 +15,7 @@ import type { HomeAssistant } from "../../../../../types";
import { supportsAlarmModesCardFeature } from "../../../card-features/hui-alarm-modes-card-feature";
import { supportsCoverOpenCloseCardFeature } from "../../../card-features/hui-cover-open-close-card-feature";
import { supportsFanSpeedCardFeature } from "../../../card-features/hui-fan-speed-card-feature";
import { supportsHistoryChartCardFeature } from "../../../card-features/hui-history-chart-card-feature";
import { supportsLightBrightnessCardFeature } from "../../../card-features/hui-light-brightness-card-feature";
import { supportsLockCommandsCardFeature } from "../../../card-features/hui-lock-commands-card-feature";
import { supportsTargetTemperatureCardFeature } from "../../../card-features/hui-target-temperature-card-feature";
@@ -237,7 +238,12 @@ export const computeAreaTileCardConfig =
let feature: LovelaceCardFeatureConfig | undefined;
if (includeFeature) {
if (supportsLightBrightnessCardFeature(hass, context)) {
if (supportsHistoryChartCardFeature(hass, context)) {
feature = {
type: "history-chart",
hours_to_show: 24,
};
} else if (supportsLightBrightnessCardFeature(hass, context)) {
feature = {
type: "light-brightness",
};

View File

@@ -12,30 +12,11 @@ import {
} from "../areas/helpers/areas-strategy-helper";
import { getHomeStructure } from "./helpers/home-structure";
import { findEntities, HOME_SUMMARIES_FILTERS } from "./helpers/home-summaries";
import { computeStateName } from "../../../../common/entity/compute_state_name";
import { computeObjectId } from "../../../../common/entity/compute_object_id";
export interface HomeClimateViewStrategyConfig {
type: "home-climate";
}
const createTempHumidBadge = (hass: HomeAssistant, entityId: string) => {
const stateObj = hass.states[entityId];
return {
type: "tile",
entity: entityId,
name: stateObj
? computeStateName(stateObj)
: computeObjectId(entityId).replace(/_/g, " "),
features: [
{
type: "history-chart",
hours_to_show: 3,
},
],
};
};
const processAreasForClimate = (
areaIds: string[],
hass: HomeAssistant,
@@ -65,14 +46,10 @@ const processAreasForClimate = (
});
if (hass.areas[areaId].temperature_entity_id) {
cards.push(
createTempHumidBadge(hass, hass.areas[areaId].temperature_entity_id)
);
cards.push(computeTileCard(hass.areas[areaId].temperature_entity_id));
}
if (hass.areas[areaId].humidity_entity_id) {
cards.push(
createTempHumidBadge(hass, hass.areas[areaId].humidity_entity_id)
);
cards.push(computeTileCard(hass.areas[areaId].humidity_entity_id));
}
for (const entityId of areaEntities) {

View File

@@ -9,12 +9,16 @@ import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
import type { HomeAssistant } from "../../../../types";
import type {
AreaCardConfig,
HomeSummaryCard,
ButtonCardConfig,
MarkdownCardConfig,
TileCardConfig,
WeatherForecastCardConfig,
} from "../../cards/types";
import { getAreas } from "../areas/helpers/areas-strategy-helper";
import {
getSummaryLabel,
HOME_SUMMARIES_ICONS,
} from "./helpers/home-summaries";
export interface HomeMainViewStrategyConfig {
type: "home-main";
@@ -110,57 +114,61 @@ export class HomeMainViewStrategy extends ReactiveElement {
heading: hass.localize("ui.panel.lovelace.strategy.home.summaries"),
},
{
type: "home-summary",
summary: "lights",
vertical: true,
type: "button",
icon: HOME_SUMMARIES_ICONS.lights,
name: getSummaryLabel(hass.localize, "lights"),
icon_height: "24px",
grid_options: {
rows: 2,
columns: 4,
},
tap_action: {
action: "navigate",
navigation_path: "lights",
},
} satisfies ButtonCardConfig,
{
type: "button",
icon: HOME_SUMMARIES_ICONS.climate,
name: getSummaryLabel(hass.localize, "climate"),
icon_height: "30px",
grid_options: {
rows: 2,
columns: 4,
},
} satisfies HomeSummaryCard,
{
type: "home-summary",
summary: "climate",
vertical: true,
tap_action: {
action: "navigate",
navigation_path: "climate",
},
} satisfies ButtonCardConfig,
{
type: "button",
icon: HOME_SUMMARIES_ICONS.security,
name: getSummaryLabel(hass.localize, "security"),
icon_height: "30px",
grid_options: {
rows: 2,
columns: 4,
},
} satisfies HomeSummaryCard,
{
type: "home-summary",
summary: "security",
vertical: true,
tap_action: {
action: "navigate",
navigation_path: "security",
},
} satisfies ButtonCardConfig,
{
type: "button",
icon: HOME_SUMMARIES_ICONS.media_players,
name: getSummaryLabel(hass.localize, "media_players"),
icon_height: "30px",
grid_options: {
rows: 2,
columns: 4,
},
} satisfies HomeSummaryCard,
{
type: "home-summary",
summary: "media_players",
vertical: true,
tap_action: {
action: "navigate",
navigation_path: "media-players",
},
grid_options: {
rows: 2,
columns: 4,
},
} satisfies HomeSummaryCard,
} satisfies ButtonCardConfig,
],
};

View File

@@ -13,8 +13,6 @@ import {
import { getHomeStructure } from "./helpers/home-structure";
import { findEntities, HOME_SUMMARIES_FILTERS } from "./helpers/home-summaries";
import { computeDomain } from "../../../../common/entity/compute_domain";
import { computeStateName } from "../../../../common/entity/compute_state_name";
import { computeObjectId } from "../../../../common/entity/compute_object_id";
export interface HomeSecurityViewStrategyConfig {
type: "home-security";
@@ -27,6 +25,7 @@ const processAreasForSecurity = (
): LovelaceCardConfig[] => {
const cards: LovelaceCardConfig[] = [];
const computeTileCard = computeAreaTileCardConfig(hass, "", false);
const computeTileCardWithFeature = computeAreaTileCardConfig(hass, "", true);
for (const areaId of areaIds) {
const area = hass.areas[areaId];
@@ -49,23 +48,10 @@ const processAreasForSecurity = (
});
for (const entityId of areaEntities) {
const stateObj = hass.states[entityId];
cards.push(
computeDomain(entityId) === "binary_sensor" &&
stateObj?.attributes.device_class === "motion"
? {
type: "tile",
entity: entityId,
name: stateObj
? computeStateName(stateObj)
: computeObjectId(entityId).replace(/_/g, " "),
features: [
{
type: "history-chart",
hours_to_show: 6,
},
],
}
hass.states[entityId]?.attributes.device_class === "motion"
? computeTileCardWithFeature(entityId)
: computeTileCard(entityId)
);
}

View File

@@ -201,15 +201,6 @@
"open_door_confirm": "Really open?",
"open_door_done": "Done"
},
"home-summary": {
"all_lights_off": "All off",
"count_lights_on": "{count} {count, plural,\n one {on}\n other {on}\n}",
"count_locks_unlocked": "{count} {count, plural,\n one {unlocked}\n other {unlocked}\n}",
"count_alarms_disarmed": "{count} {count, plural,\n one {disarmed}\n other {disarmed}\n}",
"all_secure": "All secure",
"no_media_playing": "No media playing",
"count_media_playing": "{count} {count, plural,\n one {playing}\n other {playing}\n}"
},
"media_player": {
"source": "Source",
"sound_mode": "Sound mode",
@@ -5127,7 +5118,7 @@
"integration": "Integration",
"config_entry": "Config entry"
},
"enabled_description": "Disabled devices and services will not be shown and entities belonging to them will be disabled, too.",
"enabled_description": "Disabled devices will not be shown and entities belonging to the device will be disabled and not added to Home Assistant.",
"open_configuration_url": "Visit",
"set_up_voice_assistant": "Set up voice assistant",
"download_diagnostics": "Download diagnostics",
@@ -5724,6 +5715,16 @@
"no_advertisements_found": "No matching Bluetooth advertisements found",
"no_connection_slot_allocations": "No connection slot allocations information available",
"no_active_connection_support": "This adapter does not support making active (GATT) connections.",
"no_scanner_state_available": "No scanner state available",
"current_scanning_mode": "Current scanning mode",
"requested_scanning_mode": "Requested scanning mode",
"scanning_mode_none": "none",
"scanning_mode_active": "active",
"scanning_mode_passive": "passive",
"scanner_mode_mismatch": "Scanner requested {requested} mode but is operating in {current} mode. The scanner is in a bad state and needs to be power cycled.",
"scanner_mode_mismatch_proxy": "For proxies: reboot the device",
"scanner_mode_mismatch_usb": "For USB adapters: unplug and plug back in",
"scanner_mode_mismatch_onboard": "For onboard adapters: power down the system completely and power it back up",
"address": "Address",
"name": "Name",
"source": "Source",

110
yarn.lock
View File

@@ -3990,92 +3990,92 @@ __metadata:
languageName: node
linkType: hard
"@rspack/binding-darwin-arm64@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-darwin-arm64@npm:1.5.1"
"@rspack/binding-darwin-arm64@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-darwin-arm64@npm:1.5.0"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-darwin-x64@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-darwin-x64@npm:1.5.1"
"@rspack/binding-darwin-x64@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-darwin-x64@npm:1.5.0"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-gnu@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-linux-arm64-gnu@npm:1.5.1"
"@rspack/binding-linux-arm64-gnu@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-linux-arm64-gnu@npm:1.5.0"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-musl@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-linux-arm64-musl@npm:1.5.1"
"@rspack/binding-linux-arm64-musl@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-linux-arm64-musl@npm:1.5.0"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-linux-x64-gnu@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-linux-x64-gnu@npm:1.5.1"
"@rspack/binding-linux-x64-gnu@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-linux-x64-gnu@npm:1.5.0"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-x64-musl@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-linux-x64-musl@npm:1.5.1"
"@rspack/binding-linux-x64-musl@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-linux-x64-musl@npm:1.5.0"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-wasm32-wasi@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-wasm32-wasi@npm:1.5.1"
"@rspack/binding-wasm32-wasi@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-wasm32-wasi@npm:1.5.0"
dependencies:
"@napi-rs/wasm-runtime": "npm:^1.0.1"
conditions: cpu=wasm32
languageName: node
linkType: hard
"@rspack/binding-win32-arm64-msvc@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-win32-arm64-msvc@npm:1.5.1"
"@rspack/binding-win32-arm64-msvc@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-win32-arm64-msvc@npm:1.5.0"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-win32-ia32-msvc@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-win32-ia32-msvc@npm:1.5.1"
"@rspack/binding-win32-ia32-msvc@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-win32-ia32-msvc@npm:1.5.0"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@rspack/binding-win32-x64-msvc@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding-win32-x64-msvc@npm:1.5.1"
"@rspack/binding-win32-x64-msvc@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding-win32-x64-msvc@npm:1.5.0"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@rspack/binding@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/binding@npm:1.5.1"
"@rspack/binding@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/binding@npm:1.5.0"
dependencies:
"@rspack/binding-darwin-arm64": "npm:1.5.1"
"@rspack/binding-darwin-x64": "npm:1.5.1"
"@rspack/binding-linux-arm64-gnu": "npm:1.5.1"
"@rspack/binding-linux-arm64-musl": "npm:1.5.1"
"@rspack/binding-linux-x64-gnu": "npm:1.5.1"
"@rspack/binding-linux-x64-musl": "npm:1.5.1"
"@rspack/binding-wasm32-wasi": "npm:1.5.1"
"@rspack/binding-win32-arm64-msvc": "npm:1.5.1"
"@rspack/binding-win32-ia32-msvc": "npm:1.5.1"
"@rspack/binding-win32-x64-msvc": "npm:1.5.1"
"@rspack/binding-darwin-arm64": "npm:1.5.0"
"@rspack/binding-darwin-x64": "npm:1.5.0"
"@rspack/binding-linux-arm64-gnu": "npm:1.5.0"
"@rspack/binding-linux-arm64-musl": "npm:1.5.0"
"@rspack/binding-linux-x64-gnu": "npm:1.5.0"
"@rspack/binding-linux-x64-musl": "npm:1.5.0"
"@rspack/binding-wasm32-wasi": "npm:1.5.0"
"@rspack/binding-win32-arm64-msvc": "npm:1.5.0"
"@rspack/binding-win32-ia32-msvc": "npm:1.5.0"
"@rspack/binding-win32-x64-msvc": "npm:1.5.0"
dependenciesMeta:
"@rspack/binding-darwin-arm64":
optional: true
@@ -4097,23 +4097,23 @@ __metadata:
optional: true
"@rspack/binding-win32-x64-msvc":
optional: true
checksum: 10/a6756a35bda55fd9e21b1ce142ca18e228d92832dc213027a19314981f8f12e6510dd862a9724ee96dee61755b3dd30ce73b2bb117d150e9f5ce73ba8fe4b57a
checksum: 10/bf0d6cfbc17dcf0c7e90ca8068ddc69baf73423a02a7240ae0d8d83aa4f2fae02b5a0778dc3550090653d3fd0d2024cc370c600bb681ae67e55404938d25329e
languageName: node
linkType: hard
"@rspack/core@npm:1.5.1":
version: 1.5.1
resolution: "@rspack/core@npm:1.5.1"
"@rspack/core@npm:1.5.0":
version: 1.5.0
resolution: "@rspack/core@npm:1.5.0"
dependencies:
"@module-federation/runtime-tools": "npm:0.18.0"
"@rspack/binding": "npm:1.5.1"
"@rspack/binding": "npm:1.5.0"
"@rspack/lite-tapable": "npm:1.0.1"
peerDependencies:
"@swc/helpers": ">=0.5.1"
peerDependenciesMeta:
"@swc/helpers":
optional: true
checksum: 10/b7a6269d5bdbcad140d172ebe951f4693711573d4f38e4c676c250a9cc6c1bdf602ad5187eeacc07ff12b74d510b746c92e3f112c8ab4dca46846c595d2876b0
checksum: 10/ce8a2a43ac6335f15e0ef942b3233454c38598331f42e40c09a6a1e12e42ce901188f772dedbe9e15f188b5cc346b565f0eb4405d46b6bd109295daa7c1327f2
languageName: node
linkType: hard
@@ -9377,7 +9377,7 @@ __metadata:
"@octokit/rest": "npm:22.0.0"
"@replit/codemirror-indentation-markers": "npm:6.5.3"
"@rsdoctor/rspack-plugin": "npm:1.2.3"
"@rspack/core": "npm:1.5.1"
"@rspack/core": "npm:1.5.0"
"@rspack/dev-server": "npm:1.1.4"
"@shoelace-style/shoelace": "npm:2.20.1"
"@swc/helpers": "npm:0.5.17"
@@ -9466,7 +9466,7 @@ __metadata:
lodash.template: "npm:4.5.0"
luxon: "npm:3.7.1"
map-stream: "npm:0.0.7"
marked: "npm:16.2.1"
marked: "npm:16.2.0"
memoize-one: "npm:6.0.0"
node-vibrant: "npm:4.0.3"
object-hash: "npm:3.0.0"
@@ -11137,12 +11137,12 @@ __metadata:
languageName: node
linkType: hard
"marked@npm:16.2.1":
version: 16.2.1
resolution: "marked@npm:16.2.1"
"marked@npm:16.2.0":
version: 16.2.0
resolution: "marked@npm:16.2.0"
bin:
marked: bin/marked.js
checksum: 10/67e911a7dd416869649dee18dc4a9683c0ccd8e72ba0fee3b3f578f857416e69780013e9d63762c600e6f9cf997c5af9fa0507a2053f8e65d39c5459c245c0cd
checksum: 10/0a73dcfbe500514d2f1106da99708beed8a31de586e2826e1aa47ca0e0a4850b1e9598569b09d5366d4f4dee2d279a13f32616ed1ee75c832068eb7dd660f66f
languageName: node
linkType: hard