Compare commits

..

3 Commits

Author SHA1 Message Date
Petar Petrov
9d78043915 Update src/translations/en.json
Co-authored-by: Norbert Rittel <norbert@rittel.de>
2025-10-06 16:58:54 +03:00
Petar Petrov
18bcc1c4f9 update translation 2025-10-06 12:55:29 +03:00
Petar Petrov
14133e28ad Add power configuration to Energy dashboard 2025-10-06 10:35:52 +03:00
44 changed files with 736 additions and 527 deletions

View File

@@ -36,14 +36,14 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
uses: github/codeql-action/autobuild@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -57,4 +57,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6
uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5

View File

@@ -19,11 +19,8 @@ jobs:
release:
name: Release
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: write # Required to upload release assets
id-token: write # For "Trusted Publisher" to PyPi
if: github.repository_owner == 'home-assistant'
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -49,20 +46,16 @@ jobs:
run: ./script/translations_download
env:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
- name: Build and release package
run: |
python3 -m pip install build
python3 -m pip install twine build
export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1
script/release
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
skip-existing: true
- name: Upload release assets
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
with:
files: |
dist/*.whl
@@ -115,7 +108,7 @@ jobs:
- name: Tar folder
run: tar -czf landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz -C landing-page/dist .
- name: Upload release asset
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
with:
files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz
@@ -144,6 +137,6 @@ jobs:
- name: Tar folder
run: tar -czf hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz -C hassio/build .
- name: Upload release asset
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
with:
files: hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 90 days stale policy
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90

View File

@@ -89,8 +89,8 @@
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.9.1",
"@tsparticles/preset-links": "3.2.0",
"@vaadin/combo-box": "24.9.2",
"@vaadin/vaadin-themable-mixin": "24.9.2",
"@vaadin/combo-box": "24.9.1",
"@vaadin/vaadin-themable-mixin": "24.9.1",
"@vibrant/color": "4.0.0",
"@vue/web-component-wrapper": "1.3.0",
"@webcomponents/scoped-custom-element-registry": "0.0.10",

View File

@@ -1,4 +1,5 @@
#!/bin/sh
# Pushes a new version to PyPi.
# Stop on errors
set -e
@@ -11,4 +12,5 @@ yarn install
script/build_frontend
rm -rf dist home_assistant_frontend.egg-info
python3 -m build -q
python3 -m build
python3 -m twine upload dist/*.whl --skip-existing

View File

@@ -1,141 +0,0 @@
import type {
ReactiveController,
ReactiveControllerHost,
} from "@lit/reactive-element/reactive-controller";
const UNDO_REDO_STACK_LIMIT = 75;
/**
* Configuration options for the UndoRedoController.
*
* @template ConfigType The type of configuration to manage.
*/
export interface UndoRedoControllerConfig<ConfigType> {
stackLimit?: number;
currentConfig: () => ConfigType;
apply: (config: ConfigType) => void;
}
/**
* A controller to manage undo and redo operations for a given configuration type.
*
* @template ConfigType The type of configuration to manage.
*/
export class UndoRedoController<ConfigType> implements ReactiveController {
private _host: ReactiveControllerHost;
private _undoStack: ConfigType[] = [];
private _redoStack: ConfigType[] = [];
private readonly _stackLimit: number = UNDO_REDO_STACK_LIMIT;
private readonly _apply: (config: ConfigType) => void = () => {
throw new Error("No apply function provided");
};
private readonly _currentConfig: () => ConfigType = () => {
throw new Error("No currentConfig function provided");
};
constructor(
host: ReactiveControllerHost,
options: UndoRedoControllerConfig<ConfigType>
) {
if (options.stackLimit !== undefined) {
this._stackLimit = options.stackLimit;
}
this._apply = options.apply;
this._currentConfig = options.currentConfig;
this._host = host;
host.addController(this);
}
hostConnected() {
window.addEventListener("undo-change", this._onUndoChange);
}
hostDisconnected() {
window.removeEventListener("undo-change", this._onUndoChange);
}
private _onUndoChange = (ev: Event) => {
ev.stopPropagation();
this.undo();
this._host.requestUpdate();
};
/**
* Indicates whether there are actions available to undo.
*
* @returns `true` if there are actions to undo, `false` otherwise.
*/
public get canUndo(): boolean {
return this._undoStack.length > 0;
}
/**
* Indicates whether there are actions available to redo.
*
* @returns `true` if there are actions to redo, `false` otherwise.
*/
public get canRedo(): boolean {
return this._redoStack.length > 0;
}
/**
* Commits the current configuration to the undo stack and clears the redo stack.
*
* @param config The current configuration to commit.
*/
public commit(config: ConfigType) {
if (this._undoStack.length >= this._stackLimit) {
this._undoStack.shift();
}
this._undoStack.push({ ...config });
this._redoStack = [];
}
/**
* Undoes the last action and applies the previous configuration
* while saving the current configuration to the redo stack.
*/
public undo() {
if (this._undoStack.length === 0) {
return;
}
this._redoStack.push({ ...this._currentConfig() });
const config = this._undoStack.pop()!;
this._apply(config);
this._host.requestUpdate();
}
/**
* Redoes the last undone action and reapplies the configuration
* while saving the current configuration to the undo stack.
*/
public redo() {
if (this._redoStack.length === 0) {
return;
}
this._undoStack.push({ ...this._currentConfig() });
const config = this._redoStack.pop()!;
this._apply(config);
this._host.requestUpdate();
}
/**
* Resets the undo and redo stacks, clearing all history.
*/
public reset() {
this._undoStack = [];
this._redoStack = [];
}
}
declare global {
interface HASSDomEvents {
"undo-change": undefined;
}
}

View File

@@ -31,10 +31,10 @@ export const isNavigationClick = (e: MouseEvent, preventDefault = true) => {
const location = window.location;
const origin = location.origin || location.protocol + "//" + location.host;
if (!href.startsWith(origin)) {
if (href.indexOf(origin) !== 0) {
return undefined;
}
href = href.slice(origin.length);
href = href.substr(origin.length);
if (href === "#") {
return undefined;

View File

@@ -1,3 +1,3 @@
/** Compute the object ID of a state. */
export const computeObjectId = (entityId: string): string =>
entityId.slice(entityId.indexOf(".") + 1);
entityId.substr(entityId.indexOf(".") + 1);

View File

@@ -14,7 +14,7 @@ export default function parseAspectRatio(input: string) {
}
try {
if (input.endsWith("%")) {
return { w: 100, h: parseOrThrow(input.slice(0, -1)) };
return { w: 100, h: parseOrThrow(input.substr(0, input.length - 1)) };
}
const arr = input.replace(":", "x").split("x");

View File

@@ -20,7 +20,6 @@ import "../ha-combo-box-item";
import "../ha-generic-picker";
import type { HaGenericPicker } from "../ha-generic-picker";
import "../ha-icon-button";
import "../ha-input-helper-text";
import type {
PickerComboBoxItem,
PickerComboBoxSearchFn,
@@ -465,6 +464,7 @@ export class HaStatisticPicker extends LitElement {
.hideClearIcon=${this.hideClearIcon}
.searchFn=${this._searchFn}
.valueRenderer=${this._valueRenderer}
.helper=${this.helper}
@value-changed=${this._valueChanged}
>
</ha-generic-picker>

View File

@@ -321,7 +321,7 @@ class HaHLSPlayer extends LitElement {
} else if (data.response.code >= 400) {
error += " (Stream never started)";
} else {
error += ` (${data.response.code})`;
error += " (" + data.response.code + ")";
}
}
this._setRetryableError(error);

View File

@@ -102,6 +102,7 @@ export type EnergySolarForecasts = Record<string, EnergySolarForecast>;
export interface DeviceConsumptionEnergyPreference {
// This is an ever increasing value
stat_consumption: string;
stat_power?: string;
name?: string;
included_in_stat?: string;
}
@@ -109,6 +110,8 @@ export interface DeviceConsumptionEnergyPreference {
export interface FlowFromGridSourceEnergyPreference {
// kWh meter
stat_energy_from: string;
// W meter
stat_power_from?: string;
// $ meter
stat_cost: string | null;
@@ -121,6 +124,8 @@ export interface FlowFromGridSourceEnergyPreference {
export interface FlowToGridSourceEnergyPreference {
// kWh meter
stat_energy_to: string;
// W meter
stat_power_to?: string;
// $ meter
stat_compensation: string | null;
@@ -143,6 +148,7 @@ export interface SolarSourceTypeEnergyPreference {
type: "solar";
stat_energy_from: string;
stat_power_from?: string;
config_entry_solar_forecast: string[] | null;
}
@@ -150,6 +156,8 @@ export interface BatterySourceTypeEnergyPreference {
type: "battery";
stat_energy_from: string;
stat_energy_to: string;
stat_power_from?: string;
stat_power_to?: string;
}
export interface GasSourceTypeEnergyPreference {
type: "gas";

View File

@@ -70,7 +70,9 @@ export class HaMoreInfoSettings extends LitElement {
if (!this.entry) {
return;
}
if (!(this.entry.platform in PLATFORMS_WITH_SETTINGS_TAB)) {
if (
!Object.keys(PLATFORMS_WITH_SETTINGS_TAB).includes(this.entry.platform)
) {
this._settingsElementTag = "entity-registry-settings";
return;
}

View File

@@ -167,7 +167,7 @@ export const provideHass = (
}
mockAPI(/states\/.+/, (_method, path, parameters) => {
const [domain, objectId] = path.slice(7).split(".", 2);
const [domain, objectId] = path.substr(7).split(".", 2);
if (!domain || !objectId) {
return;
}

View File

@@ -0,0 +1,60 @@
import type { LitElement } from "lit";
import type { Constructor } from "../types";
export const UndoRedoMixin = <T extends Constructor<LitElement>, ConfigType>(
superClass: T
) => {
class UndoRedoClass extends superClass {
private _undoStack: ConfigType[] = [];
private _redoStack: ConfigType[] = [];
protected _undoStackLimit = 75;
protected pushToUndo(config: ConfigType) {
if (this._undoStack.length >= this._undoStackLimit) {
this._undoStack.shift();
}
this._undoStack.push({ ...config });
this._redoStack = [];
}
public undo() {
const currentConfig = this.currentConfig;
if (this._undoStack.length === 0 || !currentConfig) {
return;
}
this._redoStack.push({ ...currentConfig });
const config = this._undoStack.pop()!;
this.applyUndoRedo(config);
}
public redo() {
const currentConfig = this.currentConfig;
if (this._redoStack.length === 0 || !currentConfig) {
return;
}
this._undoStack.push({ ...currentConfig });
const config = this._redoStack.pop()!;
this.applyUndoRedo(config);
}
public get canUndo(): boolean {
return this._undoStack.length > 0;
}
public get canRedo(): boolean {
return this._redoStack.length > 0;
}
protected get currentConfig(): ConfigType | undefined {
return undefined;
}
protected applyUndoRedo(_: ConfigType) {
throw new Error("applyUndoRedo not implemented");
}
}
return UndoRedoClass;
};

View File

@@ -209,7 +209,9 @@ class OnboardingRestoreBackup extends LitElement {
}
if (this._cloudStatus?.logged_in && !this._backupId) {
this._backup = backups.find(({ agents }) => CLOUD_AGENT in agents);
this._backup = backups.find(({ agents }) =>
Object.keys(agents).includes(CLOUD_AGENT)
);
if (!this._backup) {
this._view = "empty_cloud";

View File

@@ -70,6 +70,7 @@ import { describeAction } from "../../../../data/script_i18n";
import { callExecuteScript } from "../../../../data/service";
import {
showAlertDialog,
showConfirmationDialog,
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
@@ -649,19 +650,21 @@ export default class HaAutomationActionRow extends LitElement {
};
private _onDelete = () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected) {
fireEvent(this, "close-sidebar");
}
showToast(this, {
message: this.hass.localize("ui.common.successfully_deleted"),
duration: 4000,
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(window, "undo-change");
},
showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.automation.editor.actions.delete_confirm_title"
),
text: this.hass.localize(
"ui.panel.config.automation.editor.actions.delete_confirm_text"
),
dismissText: this.hass.localize("ui.common.cancel"),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
confirm: () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected) {
fireEvent(this, "close-sidebar");
}
},
});
};

View File

@@ -53,6 +53,7 @@ import { fullEntitiesContext } from "../../../../data/context";
import type { EntityRegistryEntry } from "../../../../data/entity_registry";
import {
showAlertDialog,
showConfirmationDialog,
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
@@ -531,19 +532,21 @@ export default class HaAutomationConditionRow extends LitElement {
};
private _onDelete = () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected) {
fireEvent(this, "close-sidebar");
}
showToast(this, {
message: this.hass.localize("ui.common.successfully_deleted"),
duration: 4000,
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(window, "undo-change");
},
showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.automation.editor.conditions.delete_confirm_title"
),
text: this.hass.localize(
"ui.panel.config.automation.editor.conditions.delete_confirm_text"
),
dismissText: this.hass.localize("ui.common.cancel"),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
confirm: () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected) {
fireEvent(this, "close-sidebar");
}
},
});
};

View File

@@ -74,7 +74,7 @@ import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info
import "../../../layouts/hass-subpage";
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { UndoRedoMixin } from "../../../mixins/undo-redo-mixin";
import { haStyle } from "../../../resources/styles";
import type { Entries, HomeAssistant, Route } from "../../../types";
import { isMac } from "../../../util/is_mac";
@@ -111,9 +111,12 @@ declare global {
}
}
export class HaAutomationEditor extends PreventUnsavedMixin(
KeyboardShortcutMixin(LitElement)
) {
const baseEditorMixins = PreventUnsavedMixin(KeyboardShortcutMixin(LitElement));
export class HaAutomationEditor extends UndoRedoMixin<
typeof baseEditorMixins,
AutomationConfig
>(baseEditorMixins) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public automationId: string | null = null;
@@ -180,11 +183,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
) => void;
private _undoRedoController = new UndoRedoController<AutomationConfig>(this, {
apply: (config) => this._applyUndoRedo(config),
currentConfig: () => this._config!,
});
protected willUpdate(changedProps) {
super.willUpdate(changedProps);
@@ -237,8 +235,8 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
slot="toolbar-icon"
.label=${this.hass.localize("ui.common.undo")}
.path=${mdiUndo}
@click=${this._undo}
.disabled=${!this._undoRedoController.canUndo}
@click=${this.undo}
.disabled=${!this.canUndo}
id="button-undo"
>
</ha-icon-button>
@@ -255,8 +253,8 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
slot="toolbar-icon"
.label=${this.hass.localize("ui.common.redo")}
.path=${mdiRedo}
@click=${this._redo}
.disabled=${!this._undoRedoController.canRedo}
@click=${this.redo}
.disabled=${!this.canRedo}
id="button-redo"
>
</ha-icon-button>
@@ -300,16 +298,16 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
${this._mode === "gui" && this.narrow
? html`<ha-list-item
graphic="icon"
@click=${this._undo}
.disabled=${!this._undoRedoController.canUndo}
@click=${this.undo}
.disabled=${!this.canUndo}
>
${this.hass.localize("ui.common.undo")}
<ha-svg-icon slot="graphic" .path=${mdiUndo}></ha-svg-icon>
</ha-list-item>
<ha-list-item
graphic="icon"
@click=${this._redo}
.disabled=${!this._undoRedoController.canRedo}
@click=${this.redo}
.disabled=${!this.canRedo}
>
${this.hass.localize("ui.common.redo")}
<ha-svg-icon slot="graphic" .path=${mdiRedo}></ha-svg-icon>
@@ -520,6 +518,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
@value-changed=${this._valueChanged}
@save-automation=${this._handleSaveAutomation}
@editor-save=${this._handleSaveAutomation}
@undo-paste=${this.undo}
>
<div class="alert-wrapper" slot="alerts">
${this._errors || stateObj?.state === UNAVAILABLE
@@ -792,7 +791,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
ev.stopPropagation();
if (this._config) {
this._undoRedoController.commit(this._config);
this.pushToUndo(this._config);
}
this._config = ev.detail.value;
@@ -1203,9 +1202,9 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
x: () => this._cutSelectedRow(),
Delete: () => this._deleteSelectedRow(),
Backspace: () => this._deleteSelectedRow(),
z: () => this._undo(),
Z: () => this._redo(),
y: () => this._redo(),
z: () => this.undo(),
Z: () => this.redo(),
y: () => this.redo(),
};
}
@@ -1239,20 +1238,16 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
this._manualEditor?.deleteSelectedRow();
}
private _applyUndoRedo(config: AutomationConfig) {
protected get currentConfig() {
return this._config;
}
protected applyUndoRedo(config: AutomationConfig) {
this._manualEditor?.triggerCloseSidebar();
this._config = config;
this._dirty = true;
}
private _undo() {
this._undoRedoController.undo();
}
private _redo() {
this._undoRedoController.redo();
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -616,7 +616,7 @@ export class HaManualAutomationEditor extends LitElement {
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(this, "undo-change");
fireEvent(this, "undo-paste");
this._pastedConfig = undefined;
},
@@ -742,5 +742,6 @@ declare global {
"open-sidebar": SidebarConfig;
"request-close-sidebar": undefined;
"close-sidebar": undefined;
"undo-paste": undefined;
}
}

View File

@@ -33,7 +33,10 @@ import { describeCondition } from "../../../../data/automation_i18n";
import { fullEntitiesContext } from "../../../../data/context";
import type { EntityRegistryEntry } from "../../../../data/entity_registry";
import type { Action, Option } from "../../../../data/script";
import { showPromptDialog } from "../../../../dialogs/generic/show-dialog-box";
import {
showConfirmationDialog,
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import "../action/ha-automation-action";
@@ -46,7 +49,6 @@ import {
overflowStyles,
rowStyles,
} from "../styles";
import { showToast } from "../../../../util/toast";
@customElement("ha-automation-option-row")
export default class HaAutomationOptionRow extends LitElement {
@@ -363,21 +365,23 @@ export default class HaAutomationOptionRow extends LitElement {
private _removeOption = () => {
if (this.option) {
fireEvent(this, "value-changed", {
value: null,
});
if (this._selected) {
fireEvent(this, "close-sidebar");
}
showToast(this, {
message: this.hass.localize("ui.common.successfully_deleted"),
duration: 4000,
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(window, "undo-change");
},
showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.delete_confirm_title"
),
text: this.hass.localize(
"ui.panel.config.automation.editor.actions.delete_confirm_text"
),
dismissText: this.hass.localize("ui.common.cancel"),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
confirm: () => {
fireEvent(this, "value-changed", {
value: null,
});
if (this._selected) {
fireEvent(this, "close-sidebar");
}
},
});
}

View File

@@ -53,6 +53,7 @@ import type { EntityRegistryEntry } from "../../../../data/entity_registry";
import { TRIGGER_ICONS, isTriggerList } from "../../../../data/trigger";
import {
showAlertDialog,
showConfirmationDialog,
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
@@ -602,20 +603,22 @@ export default class HaAutomationTriggerRow extends LitElement {
}
private _onDelete = () => {
fireEvent(this, "value-changed", { value: null });
showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.automation.editor.triggers.delete_confirm_title"
),
text: this.hass.localize(
"ui.panel.config.automation.editor.triggers.delete_confirm_text"
),
dismissText: this.hass.localize("ui.common.cancel"),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
confirm: () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected) {
fireEvent(this, "close-sidebar");
}
showToast(this, {
message: this.hass.localize("ui.common.successfully_deleted"),
duration: 4000,
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(window, "undo-change");
},
if (this._selected) {
fireEvent(this, "close-sidebar");
}
},
});
};

View File

@@ -68,7 +68,7 @@ class HaConfigBlueprint extends HassRouterPage {
(!changedProps || changedProps.has("route")) &&
this._currentPage === "edit"
) {
const blueprintId = this.routeTail.path.slice(1);
const blueprintId = this.routeTail.path.substr(1);
pageEl.blueprintId = blueprintId === "new" ? null : blueprintId;
}
}

View File

@@ -18,6 +18,7 @@ import type { HomeAssistant } from "../../../../types";
import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];
@customElement("dialog-energy-battery-settings")
export class DialogEnergyBatterySettings
@@ -32,10 +33,14 @@ export class DialogEnergyBatterySettings
@state() private _energy_units?: string[];
@state() private _power_units?: string[];
@state() private _error?: string;
private _excludeList?: string[];
private _excludeListPower?: string[];
public async showDialog(
params: EnergySettingsBatteryDialogParams
): Promise<void> {
@@ -46,6 +51,9 @@ export class DialogEnergyBatterySettings
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
const allSources: string[] = [];
this._params.battery_sources.forEach((entry) => {
allSources.push(entry.stat_energy_from);
@@ -56,6 +64,16 @@ export class DialogEnergyBatterySettings
id !== this._source?.stat_energy_from &&
id !== this._source?.stat_energy_to
);
const allPowerSources: string[] = [];
this._params.battery_sources.forEach((entry) => {
if (entry.stat_power_from) allPowerSources.push(entry.stat_power_from);
if (entry.stat_power_to) allPowerSources.push(entry.stat_power_to);
});
this._excludeListPower = allPowerSources.filter(
(id) =>
id !== this._source?.stat_power_from &&
id !== this._source?.stat_power_to
);
}
public closeDialog() {
@@ -72,8 +90,6 @@ export class DialogEnergyBatterySettings
return nothing;
}
const pickableUnit = this._energy_units?.join(", ") || "";
return html`
<ha-dialog
open
@@ -85,12 +101,6 @@ export class DialogEnergyBatterySettings
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
${this.hass.localize(
"ui.panel.config.energy.battery.dialog.entity_para",
{ unit: pickableUnit }
)}
</div>
<ha-statistic-picker
.hass=${this.hass}
@@ -105,6 +115,10 @@ export class DialogEnergyBatterySettings
this._source.stat_energy_from,
]}
@value-changed=${this._statisticToChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.entity_para",
{ unit: this._energy_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>
@@ -121,6 +135,40 @@ export class DialogEnergyBatterySettings
this._source.stat_energy_to,
]}
@value-changed=${this._statisticFromChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.entity_para",
{ unit: this._energy_units?.join(", ") || "" }
)}
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._source.stat_power_to}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_into_battery"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerToChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.entity_para",
{ unit: this._power_units?.join(", ") || "" }
)}
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._source.stat_power_from}
.label=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.power_out_of_battery"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerFromChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.battery.dialog.entity_para",
{ unit: this._power_units?.join(", ") || "" }
)}
></ha-statistic-picker>
<ha-button
@@ -150,6 +198,14 @@ export class DialogEnergyBatterySettings
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
}
private _powerToChanged(ev: CustomEvent<{ value: string }>) {
this._source = { ...this._source!, stat_power_to: ev.detail.value };
}
private _powerFromChanged(ev: CustomEvent<{ value: string }>) {
this._source = { ...this._source!, stat_power_from: ev.detail.value };
}
private async _save() {
try {
await this._params!.saveCallback(this._source!);
@@ -168,7 +224,11 @@ export class DialogEnergyBatterySettings
--mdc-dialog-max-width: 430px;
}
ha-statistic-picker {
width: 100%;
display: block;
margin-bottom: var(--ha-space-4);
}
ha-statistic-picker:last-of-type {
margin-bottom: 0;
}
`,
];

View File

@@ -21,6 +21,7 @@ import type { HomeAssistant } from "../../../../types";
import type { EnergySettingsDeviceDialogParams } from "./show-dialogs-energy";
const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];
@customElement("dialog-energy-device-settings")
export class DialogEnergyDeviceSettings
@@ -35,10 +36,14 @@ export class DialogEnergyDeviceSettings
@state() private _energy_units?: string[];
@state() private _power_units?: string[];
@state() private _error?: string;
private _excludeList?: string[];
private _excludeListPower?: string[];
private _possibleParents: DeviceConsumptionEnergyPreference[] = [];
public async showDialog(
@@ -50,9 +55,15 @@ export class DialogEnergyDeviceSettings
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
this._excludeList = this._params.device_consumptions
.map((entry) => entry.stat_consumption)
.filter((id) => id !== this._device?.stat_consumption);
this._excludeListPower = this._params.device_consumptions
.map((entry) => entry.stat_power)
.filter((id) => id && id !== this._device?.stat_power) as string[];
}
private _computePossibleParents() {
@@ -93,8 +104,6 @@ export class DialogEnergyDeviceSettings
return nothing;
}
const pickableUnit = this._energy_units?.join(", ") || "";
return html`
<ha-dialog
open
@@ -108,12 +117,6 @@ export class DialogEnergyDeviceSettings
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
${this.hass.localize(
"ui.panel.config.energy.device_consumption.dialog.selected_stat_intro",
{ unit: pickableUnit }
)}
</div>
<ha-statistic-picker
.hass=${this.hass}
@@ -125,9 +128,28 @@ export class DialogEnergyDeviceSettings
)}
.excludeStatistics=${this._excludeList}
@value-changed=${this._statisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.device_consumption.dialog.selected_stat_intro",
{ unit: this._energy_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._device?.stat_power}
.label=${this.hass.localize(
"ui.panel.config.energy.device_consumption.dialog.device_consumption_power"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerStatisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.device_consumption.dialog.device_consumption_power_helper",
{ unit: this._power_units?.join(", ") || "" }
)}
></ha-statistic-picker>
<ha-textfield
.label=${this.hass.localize(
"ui.panel.config.energy.device_consumption.dialog.display_name"
@@ -210,6 +232,20 @@ export class DialogEnergyDeviceSettings
this._computePossibleParents();
}
private _powerStatisticChanged(ev: CustomEvent<{ value: string }>) {
if (!this._device) {
return;
}
const newDevice = {
...this._device,
stat_power: ev.detail.value,
} as DeviceConsumptionEnergyPreference;
if (!newDevice.stat_power) {
delete newDevice.stat_power;
}
this._device = newDevice;
}
private _nameChanged(ev) {
const newDevice = {
...this._device!,
@@ -245,15 +281,19 @@ export class DialogEnergyDeviceSettings
return [
haStyleDialog,
css`
ha-statistic-picker {
display: block;
margin-bottom: var(--ha-space-2);
}
ha-statistic-picker {
width: 100%;
}
ha-select {
margin-top: 16px;
margin-top: var(--ha-space-4);
width: 100%;
}
ha-textfield {
margin-top: 16px;
margin-top: var(--ha-space-4);
width: 100%;
}
`,

View File

@@ -31,6 +31,7 @@ import type { HomeAssistant } from "../../../../types";
import type { EnergySettingsGridFlowDialogParams } from "./show-dialogs-energy";
const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];
@customElement("dialog-energy-grid-flow-settings")
export class DialogEnergyGridFlowSettings
@@ -51,10 +52,14 @@ export class DialogEnergyGridFlowSettings
@state() private _energy_units?: string[];
@state() private _power_units?: string[];
@state() private _error?: string;
private _excludeList?: string[];
private _excludeListPower?: string[];
public async showDialog(
params: EnergySettingsGridFlowDialogParams
): Promise<void> {
@@ -80,6 +85,10 @@ export class DialogEnergyGridFlowSettings
? "stat_energy_from"
: "stat_energy_to"
];
const initialSourceIdPower =
this._source[
this._params.direction === "from" ? "stat_power_from" : "stat_power_to"
];
this._pickedDisplayUnit = getDisplayUnit(
this.hass,
@@ -89,6 +98,9 @@ export class DialogEnergyGridFlowSettings
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
this._excludeList = [
...(this._params.grid_source?.flow_from?.map(
@@ -98,6 +110,15 @@ export class DialogEnergyGridFlowSettings
(entry) => entry.stat_energy_to
) || []),
].filter((id) => id !== initialSourceId);
this._excludeListPower = [
...(this._params.grid_source?.flow_from?.map(
(entry) => entry.stat_power_from
) || []),
...(this._params.grid_source?.flow_to?.map(
(entry) => entry.stat_power_to
) || []),
].filter((id) => id && id !== initialSourceIdPower) as string[];
}
public closeDialog() {
@@ -115,8 +136,6 @@ export class DialogEnergyGridFlowSettings
return nothing;
}
const pickableUnit = this._energy_units?.join(", ") || "";
const unitPriceSensor = this._pickedDisplayUnit
? `${this.hass.config.currency}/${this._pickedDisplayUnit}`
: undefined;
@@ -150,19 +169,11 @@ export class DialogEnergyGridFlowSettings
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
<p>
${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.paragraph`
)}
</p>
<p>
${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.entity_para`,
{ unit: pickableUnit }
)}
</p>
</div>
<p>
${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.paragraph`
)}
</p>
<ha-statistic-picker
.hass=${this.hass}
@@ -178,6 +189,30 @@ export class DialogEnergyGridFlowSettings
)}
.excludeStatistics=${this._excludeList}
@value-changed=${this._statisticChanged}
.helper=${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.entity_para`,
{ unit: this._energy_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._source[
this._params.direction === "from"
? "stat_power_from"
: "stat_power_to"
]}
.label=${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.power_stat`
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerStatisticChanged}
.helper=${this.hass.localize(
`ui.panel.config.energy.grid.flow_dialog.${this._params.direction}.entity_para`,
{ unit: this._power_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>
@@ -340,6 +375,15 @@ export class DialogEnergyGridFlowSettings
};
}
private _powerStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._source = {
...this._source!,
[this._params!.direction === "from"
? "stat_power_from"
: "stat_power_to"]: ev.detail.value,
};
}
private async _statisticChanged(ev: CustomEvent<{ value: string }>) {
if (ev.detail.value) {
const metadata = await getStatisticMetadata(this.hass, [ev.detail.value]);
@@ -380,6 +424,10 @@ export class DialogEnergyGridFlowSettings
ha-dialog {
--mdc-dialog-max-width: 430px;
}
ha-statistic-picker {
display: block;
margin: var(--ha-space-4) 0;
}
ha-formfield {
display: block;
}

View File

@@ -28,6 +28,7 @@ import { brandsUrl } from "../../../../util/brands-url";
import type { EnergySettingsSolarDialogParams } from "./show-dialogs-energy";
const energyUnitClasses = ["energy"];
const powerUnitClasses = ["power"];
@customElement("dialog-energy-solar-settings")
export class DialogEnergySolarSettings
@@ -46,10 +47,14 @@ export class DialogEnergySolarSettings
@state() private _energy_units?: string[];
@state() private _power_units?: string[];
@state() private _error?: string;
private _excludeList?: string[];
private _excludeListPower?: string[];
public async showDialog(
params: EnergySettingsSolarDialogParams
): Promise<void> {
@@ -62,9 +67,15 @@ export class DialogEnergySolarSettings
this._energy_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "energy")
).units;
this._power_units = (
await getSensorDeviceClassConvertibleUnits(this.hass, "power")
).units;
this._excludeList = this._params.solar_sources
.map((entry) => entry.stat_energy_from)
.filter((id) => id !== this._source?.stat_energy_from);
this._excludeListPower = this._params.solar_sources
.map((entry) => entry.stat_power_from)
.filter((id) => id && id !== this._source?.stat_power_from) as string[];
}
public closeDialog() {
@@ -81,8 +92,6 @@ export class DialogEnergySolarSettings
return nothing;
}
const pickableUnit = this._energy_units?.join(", ") || "";
return html`
<ha-dialog
open
@@ -94,12 +103,6 @@ export class DialogEnergySolarSettings
@closed=${this.closeDialog}
>
${this._error ? html`<p class="error">${this._error}</p>` : ""}
<div>
${this.hass.localize(
"ui.panel.config.energy.solar.dialog.entity_para",
{ unit: pickableUnit }
)}
</div>
<ha-statistic-picker
.hass=${this.hass}
@@ -111,9 +114,28 @@ export class DialogEnergySolarSettings
)}
.excludeStatistics=${this._excludeList}
@value-changed=${this._statisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.solar.dialog.entity_para",
{ unit: this._energy_units?.join(", ") || "" }
)}
dialogInitialFocus
></ha-statistic-picker>
<ha-statistic-picker
.hass=${this.hass}
.includeUnitClass=${powerUnitClasses}
.value=${this._source.stat_power_from}
.label=${this.hass.localize(
"ui.panel.config.energy.solar.dialog.solar_production_power"
)}
.excludeStatistics=${this._excludeListPower}
@value-changed=${this._powerStatisticChanged}
.helper=${this.hass.localize(
"ui.panel.config.energy.solar.dialog.entity_para",
{ unit: this._power_units?.join(", ") || "" }
)}
></ha-statistic-picker>
<h3>
${this.hass.localize(
"ui.panel.config.energy.solar.dialog.solar_production_forecast"
@@ -267,6 +289,10 @@ export class DialogEnergySolarSettings
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
}
private _powerStatisticChanged(ev: CustomEvent<{ value: string }>) {
this._source = { ...this._source!, stat_power_from: ev.detail.value };
}
private async _save() {
try {
if (!this._forecast) {
@@ -287,6 +313,10 @@ export class DialogEnergySolarSettings
ha-dialog {
--mdc-dialog-max-width: 430px;
}
ha-statistic-picker {
display: block;
margin-bottom: var(--ha-space-4);
}
img {
height: 24px;
margin-right: 16px;

View File

@@ -442,7 +442,9 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
: nothing}
${this._manifest?.is_built_in &&
this._manifest.quality_scale &&
this._manifest.quality_scale in QUALITY_SCALE_MAP
Object.keys(QUALITY_SCALE_MAP).includes(
this._manifest.quality_scale
)
? html`
<div class="integration-info">
<a

View File

@@ -70,7 +70,7 @@ export class ZHAClusterCommands extends LitElement {
${this._commands.map(
(entry) => html`
<ha-list-item .value=${String(entry.id)}>
${entry.name} (id: ${formatAsPaddedHex(entry.id)})
${entry.name + " (id: " + formatAsPaddedHex(entry.id) + ")"}
</ha-list-item>
`
)}

View File

@@ -74,7 +74,7 @@ class HaConfigScene extends HassRouterPage {
this._currentPage === "edit"
) {
pageEl.creatingNew = undefined;
const sceneId = this.routeTail.path.slice(1);
const sceneId = this.routeTail.path.substr(1);
pageEl.sceneId = sceneId === "new" ? null : sceneId;
}
}

View File

@@ -98,7 +98,7 @@ class HaConfigScript extends HassRouterPage {
this._currentPage === "show"
) {
pageEl.creatingNew = undefined;
const scriptId = this.routeTail.path.slice(1);
const scriptId = this.routeTail.path.substr(1);
pageEl.entityId = scriptId === "new" ? null : scriptId;
return;
}
@@ -108,7 +108,7 @@ class HaConfigScript extends HassRouterPage {
this._currentPage !== "dashboard"
) {
pageEl.creatingNew = undefined;
const scriptId = this.routeTail.path.slice(1);
const scriptId = this.routeTail.path.substr(1);
pageEl.scriptId = scriptId === "new" ? null : scriptId;
}
}

View File

@@ -65,7 +65,7 @@ import "../../../layouts/hass-subpage";
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { UndoRedoMixin } from "../../../mixins/undo-redo-mixin";
import { haStyle } from "../../../resources/styles";
import type { Entries, HomeAssistant, Route } from "../../../types";
import { isMac } from "../../../util/is_mac";
@@ -78,9 +78,14 @@ import "./blueprint-script-editor";
import "./manual-script-editor";
import type { HaManualScriptEditor } from "./manual-script-editor";
export class HaScriptEditor extends SubscribeMixin(
const baseEditorMixins = SubscribeMixin(
PreventUnsavedMixin(KeyboardShortcutMixin(LitElement))
) {
);
export class HaScriptEditor extends UndoRedoMixin<
typeof baseEditorMixins,
ScriptConfig
>(baseEditorMixins) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public scriptId: string | null = null;
@@ -136,11 +141,6 @@ export class HaScriptEditor extends SubscribeMixin(
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
) => void;
private _undoRedoController = new UndoRedoController<ScriptConfig>(this, {
apply: (config) => this._applyUndoRedo(config),
currentConfig: () => this._config!,
});
protected willUpdate(changedProps) {
super.willUpdate(changedProps);
@@ -188,8 +188,8 @@ export class HaScriptEditor extends SubscribeMixin(
slot="toolbar-icon"
.label=${this.hass.localize("ui.common.undo")}
.path=${mdiUndo}
@click=${this._undo}
.disabled=${!this._undoRedoController.canUndo}
@click=${this.undo}
.disabled=${!this.canUndo}
id="button-undo"
>
</ha-icon-button>
@@ -205,8 +205,8 @@ export class HaScriptEditor extends SubscribeMixin(
slot="toolbar-icon"
.label=${this.hass.localize("ui.common.redo")}
.path=${mdiRedo}
@click=${this._redo}
.disabled=${!this._undoRedoController.canRedo}
@click=${this.redo}
.disabled=${!this.canRedo}
id="button-redo"
>
</ha-icon-button>
@@ -249,16 +249,16 @@ export class HaScriptEditor extends SubscribeMixin(
${this._mode === "gui" && this.narrow
? html`<ha-list-item
graphic="icon"
@click=${this._undo}
.disabled=${!this._undoRedoController.canUndo}
@click=${this.undo}
.disabled=${!this.canUndo}
>
${this.hass.localize("ui.common.undo")}
<ha-svg-icon slot="graphic" .path=${mdiUndo}></ha-svg-icon>
</ha-list-item>
<ha-list-item
graphic="icon"
@click=${this._redo}
.disabled=${!this._undoRedoController.canRedo}
@click=${this.redo}
.disabled=${!this.canRedo}
>
${this.hass.localize("ui.common.redo")}
<ha-svg-icon slot="graphic" .path=${mdiRedo}></ha-svg-icon>
@@ -463,6 +463,7 @@ export class HaScriptEditor extends SubscribeMixin(
@value-changed=${this._valueChanged}
@editor-save=${this._handleSaveScript}
@save-script=${this._handleSaveScript}
@undo-paste=${this.undo}
>
<div class="alert-wrapper" slot="alerts">
${this._errors || stateObj?.state === UNAVAILABLE
@@ -678,7 +679,7 @@ export class HaScriptEditor extends SubscribeMixin(
private _valueChanged(ev) {
if (this._config) {
this._undoRedoController.commit(this._config);
this.pushToUndo(this._config);
}
this._config = ev.detail.value;
@@ -775,7 +776,7 @@ export class HaScriptEditor extends SubscribeMixin(
}
if (this._config) {
this._undoRedoController.commit(this._config);
this.pushToUndo(this._config);
}
this._manualEditor?.addFields();
@@ -1109,9 +1110,9 @@ export class HaScriptEditor extends SubscribeMixin(
x: () => this._cutSelectedRow(),
Delete: () => this._deleteSelectedRow(),
Backspace: () => this._deleteSelectedRow(),
z: () => this._undo(),
Z: () => this._redo(),
y: () => this._redo(),
z: () => this.undo(),
Z: () => this.redo(),
y: () => this.redo(),
};
}
@@ -1145,20 +1146,16 @@ export class HaScriptEditor extends SubscribeMixin(
this._manualEditor?.deleteSelectedRow();
}
private _applyUndoRedo(config: ScriptConfig) {
protected get currentConfig() {
return this._config;
}
protected applyUndoRedo(config: ScriptConfig) {
this._manualEditor?.triggerCloseSidebar();
this._config = config;
this._dirty = true;
}
private _undo() {
this._undoRedoController.undo();
}
private _redo() {
this._undoRedoController.redo();
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -20,13 +20,13 @@ import "../../../components/ha-md-menu-item";
import type { ScriptFieldSidebarConfig } from "../../../data/automation";
import type { Field } from "../../../data/script";
import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { isMac } from "../../../util/is_mac";
import { indentStyle, overflowStyles } from "../automation/styles";
import "./ha-script-field-selector-editor";
import type HaScriptFieldSelectorEditor from "./ha-script-field-selector-editor";
import { showToast } from "../../../util/toast";
@customElement("ha-script-field-row")
export default class HaScriptFieldRow extends LitElement {
@@ -386,19 +386,21 @@ export default class HaScriptFieldRow extends LitElement {
};
private _onDelete = () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected || this._selectorRowSelected) {
fireEvent(this, "close-sidebar");
}
showToast(this, {
message: this.hass.localize("ui.common.successfully_deleted"),
duration: 4000,
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(window, "undo-change");
},
showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.script.editor.field_delete_confirm_title"
),
text: this.hass.localize(
"ui.panel.config.script.editor.field_delete_confirm_text"
),
dismissText: this.hass.localize("ui.common.cancel"),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
confirm: () => {
fireEvent(this, "value-changed", { value: null });
if (this._selected || this._selectorRowSelected) {
fireEvent(this, "close-sidebar");
}
},
});
};

View File

@@ -491,7 +491,7 @@ export class HaManualScriptEditor extends LitElement {
action: {
text: this.hass.localize("ui.common.undo"),
action: () => {
fireEvent(this, "undo-change");
fireEvent(this, "undo-paste");
this._pastedConfig = undefined;
},

View File

@@ -222,9 +222,9 @@ export class HuiCreateDialogBadge
private _handleBadgePicked(ev) {
const config = ev.detail.config;
if (this._params!.entities && this._params!.entities.length) {
if ("entities" in config) {
if (Object.keys(config).includes("entities")) {
config.entities = this._params!.entities;
} else if ("entity" in config) {
} else if (Object.keys(config).includes("entity")) {
config.entity = this._params!.entities[0];
}
}

View File

@@ -244,9 +244,9 @@ export class HuiCreateDialogCard
private _handleCardPicked(ev) {
const config = ev.detail.config;
if (this._params!.entities && this._params!.entities.length) {
if ("entities" in config) {
if (Object.keys(config).includes("entities")) {
config.entities = this._params!.entities;
} else if ("entity" in config) {
} else if (Object.keys(config).includes("entity")) {
config.entity = this._params!.entities[0];
}
}

View File

@@ -129,7 +129,8 @@ export class HuiStatisticCardEditor
name: "period",
required: true,
selector:
selectedPeriodKey && selectedPeriodKey in periods
selectedPeriodKey &&
Object.keys(periods).includes(selectedPeriodKey)
? {
select: {
multiple: false,

View File

@@ -1,67 +0,0 @@
import { css } from "lit";
/**
* Shared styles for state control toggle components
* Used by: cover, valve, lock, fan, light toggle controls
*/
export const stateControlToggleStyle = css`
ha-control-switch {
height: 45vh;
max-height: 320px;
min-height: 200px;
--control-switch-thickness: 130px;
--control-switch-border-radius: var(--ha-border-radius-6xl);
--control-switch-padding: 6px;
--mdc-icon-size: 24px;
}
.buttons {
display: flex;
flex-direction: column;
width: 130px;
height: 45vh;
max-height: 320px;
min-height: 200px;
padding: 6px;
box-sizing: border-box;
}
ha-control-button {
flex: 1;
width: 100%;
--control-button-border-radius: var(--ha-border-radius-6xl);
--mdc-icon-size: 24px;
}
ha-control-button.active {
--control-button-icon-color: white;
--control-button-background-color: var(--color);
--control-button-focus-color: var(--color);
--control-button-background-opacity: 1;
}
ha-control-button:not(:last-child) {
margin-bottom: 6px;
}
`;
/**
* Additional styles for components with pulse animation (like lock toggle)
*/
export const stateControlPulseStyle = css`
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.pulse {
animation: pulse 1s infinite;
}
`;

View File

@@ -1,6 +1,6 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { html, LitElement } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
@@ -10,7 +10,6 @@ import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { stateControlToggleStyle } from "../../resources/state-control-styles";
import type { HomeAssistant } from "../../types";
@customElement("ha-state-control-cover-toggle")
@@ -138,7 +137,41 @@ export class HaStateControlCoverToggle extends LitElement {
`;
}
static styles = [stateControlToggleStyle];
static styles = css`
ha-control-switch {
height: 45vh;
max-height: 320px;
min-height: 200px;
--control-switch-thickness: 130px;
--control-switch-border-radius: var(--ha-border-radius-6xl);
--control-switch-padding: 6px;
--mdc-icon-size: 24px;
}
.buttons {
display: flex;
flex-direction: column;
width: 130px;
height: 45vh;
max-height: 320px;
min-height: 200px;
padding: 6px;
box-sizing: border-box;
}
ha-control-button {
flex: 1;
width: 100%;
--control-button-border-radius: var(--ha-border-radius-6xl);
--mdc-icon-size: 24px;
}
ha-control-button.active {
--control-button-icon-color: white;
--control-button-background-color: var(--color);
--control-button-background-opacity: 1;
}
ha-control-button:not(:last-child) {
margin-bottom: 6px;
}
`;
}
declare global {

View File

@@ -1,7 +1,7 @@
import { mdiFlash, mdiFlashOff } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { LitElement, html } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
@@ -12,7 +12,6 @@ import "../components/ha-control-button";
import "../components/ha-control-switch";
import { UNAVAILABLE, UNKNOWN } from "../data/entity";
import { forwardHaptic } from "../data/haptics";
import { stateControlToggleStyle } from "../resources/state-control-styles";
import type { HomeAssistant } from "../types";
@customElement("ha-state-control-toggle")
@@ -129,7 +128,42 @@ export class HaStateControlToggle extends LitElement {
`;
}
static styles = [stateControlToggleStyle];
static styles = css`
ha-control-switch {
height: 45vh;
max-height: 320px;
min-height: 200px;
--control-switch-thickness: 130px;
--control-switch-border-radius: var(--ha-border-radius-6xl);
--control-switch-padding: 6px;
--mdc-icon-size: 24px;
}
.buttons {
display: flex;
flex-direction: column;
width: 130px;
height: 45vh;
max-height: 320px;
min-height: 200px;
padding: 6px;
box-sizing: border-box;
}
ha-control-button {
flex: 1;
width: 100%;
--control-button-border-radius: var(--ha-border-radius-6xl);
--mdc-icon-size: 24px;
}
ha-control-button.active {
--control-button-icon-color: white;
--control-button-background-color: var(--color);
--control-button-focus-color: var(--color);
--control-button-background-opacity: 1;
}
ha-control-button:not(:last-child) {
margin-bottom: 6px;
}
`;
}
declare global {

View File

@@ -1,5 +1,5 @@
import type { PropertyValues, TemplateResult } from "lit";
import { html, LitElement } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
@@ -12,10 +12,6 @@ import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import type { LockEntity } from "../../data/lock";
import { callProtectedLockService } from "../../data/lock";
import {
stateControlToggleStyle,
stateControlPulseStyle,
} from "../../resources/state-control-styles";
import type { HomeAssistant } from "../../types";
declare global {
@@ -149,7 +145,56 @@ export class HaStateControlLockToggle extends LitElement {
`;
}
static styles = [stateControlToggleStyle, stateControlPulseStyle];
static styles = css`
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
ha-control-switch {
height: 45vh;
max-height: 320px;
min-height: 200px;
--control-switch-thickness: 130px;
--control-switch-border-radius: var(--ha-border-radius-6xl);
--control-switch-padding: 6px;
--mdc-icon-size: 24px;
}
.pulse {
animation: pulse 1s infinite;
}
.buttons {
display: flex;
flex-direction: column;
width: 130px;
height: 45vh;
max-height: 320px;
min-height: 200px;
padding: 6px;
box-sizing: border-box;
}
ha-control-button {
flex: 1;
width: 100%;
--control-button-border-radius: var(--ha-border-radius-6xl);
--mdc-icon-size: 24px;
}
ha-control-button.active {
--control-button-icon-color: white;
--control-button-background-color: var(--color);
--control-button-focus-color: var(--color);
--control-button-background-opacity: 1;
}
ha-control-button:not(:last-child) {
margin-bottom: 6px;
}
`;
}
declare global {

View File

@@ -1,6 +1,6 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { html, LitElement } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
@@ -10,7 +10,6 @@ import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { stateControlToggleStyle } from "../../resources/state-control-styles";
import type { HomeAssistant } from "../../types";
@customElement("ha-state-control-valve-toggle")
@@ -138,7 +137,42 @@ export class HaStateControlValveToggle extends LitElement {
`;
}
static styles = [stateControlToggleStyle];
static styles = css`
ha-control-switch {
height: 45vh;
max-height: 320px;
min-height: 200px;
--control-switch-thickness: 130px;
--control-switch-border-radius: var(--ha-border-radius-6xl);
--control-switch-padding: 6px;
--mdc-icon-size: 24px;
}
.buttons {
display: flex;
flex-direction: column;
width: 130px;
height: 45vh;
max-height: 320px;
min-height: 200px;
padding: 6px;
box-sizing: border-box;
}
ha-control-button {
flex: 1;
width: 100%;
--control-button-border-radius: var(--ha-border-radius-6xl);
--mdc-icon-size: 24px;
}
ha-control-button.active {
--control-button-icon-color: white;
--control-button-background-color: var(--color);
--control-button-focus-color: var(--color);
--control-button-background-opacity: 1;
}
ha-control-button:not(:last-child) {
margin-bottom: 6px;
}
`;
}
declare global {

View File

@@ -3031,6 +3031,7 @@
"paragraph": "Grid consumption is the energy that flows from the energy grid to your home.",
"entity_para": "Pick a sensor which measures grid consumption in either of {unit}.",
"energy_stat": "Consumed energy",
"power_stat": "Current power consumption",
"cost_para": "Select how Home Assistant should keep track of the costs of the consumed energy.",
"no_cost": "Do not track costs",
"cost_stat": "Use an entity tracking the total costs",
@@ -3045,6 +3046,7 @@
"paragraph": "Grid production is the energy that flows from your solar panels to the grid.",
"entity_para": "Pick a sensor which measures grid production in either of {unit}.",
"energy_stat": "Energy returned to the grid",
"power_stat": "Current power returned to the grid",
"cost_para": "Do you get money back when you return energy to the grid?",
"no_cost": "I do not get money back",
"cost_stat": "Use an entity tracking the total received money",
@@ -3071,6 +3073,7 @@
"header": "Configure solar panels",
"entity_para": "Pick a sensor which measures solar energy production in either of {unit}.",
"solar_production_energy": "Solar production energy",
"solar_production_power": "Solar production power",
"solar_production_forecast": "Solar production forecast",
"solar_production_forecast_description": "Adding solar production forecast information will allow you to quickly see your expected production for today.",
"dont_forecast_production": "Don't forecast production",
@@ -3088,9 +3091,11 @@
"add_battery_system": "Add battery system",
"dialog": {
"header": "Configure battery system",
"entity_para": "Pick sensors which measure energy going into and coming out of the battery in either of {unit}.",
"energy_into_battery": "Energy going into the battery",
"energy_out_of_battery": "Energy coming out of the battery"
"entity_para": "Pick sensors that measure the electricity flowing in and out of the battery in either of {unit}.",
"energy_into_battery": "Energy charged into the battery",
"energy_out_of_battery": "Energy discharged from the battery",
"power_into_battery": "Power charging the battery",
"power_out_of_battery": "Power discharging the battery"
}
},
"gas": {
@@ -3152,10 +3157,12 @@
"header": "Add a device",
"display_name": "Display name",
"device_consumption_energy": "Device energy consumption",
"selected_stat_intro": "Select the energy sensor that measures the device's energy usage in either of {unit}.",
"device_consumption_power": "Device power consumption",
"selected_stat_intro": "Select the sensor that measures the device's energy usage in either of {unit}.",
"included_in_device": "Upstream device",
"included_in_device_helper": "If this device is already counted by another device (such as a smart switch measured by a smart breaker), selecting the upstream device prevents duplicate energy tracking.",
"no_upstream_devices": "No eligible upstream devices"
"no_upstream_devices": "No eligible upstream devices",
"device_consumption_power_helper": "Select the sensor that measures the device's power usage in either of {unit}."
}
}
},
@@ -3907,6 +3914,8 @@
"change_alias": "Rename trigger",
"alias": "Trigger name",
"delete": "[%key:ui::common::delete%]",
"delete_confirm_title": "Delete trigger?",
"delete_confirm_text": "It will be permanently deleted.",
"unsupported_platform": "No visual editor support for platform: {platform}",
"type_select": "Trigger type",
"unknown_trigger": "[%key:ui::panel::config::devices::automation::triggers::unknown_trigger%]",
@@ -4170,6 +4179,8 @@
"change_alias": "Rename condition",
"alias": "Condition name",
"delete": "[%key:ui::common::delete%]",
"delete_confirm_title": "Delete condition?",
"delete_confirm_text": "[%key:ui::panel::config::automation::editor::triggers::delete_confirm_text%]",
"unsupported_condition": "No visual editor support for condition: {condition}",
"type_select": "Condition type",
"unknown_condition": "[%key:ui::panel::config::devices::automation::conditions::unknown_condition%]",
@@ -4339,6 +4350,8 @@
"disable": "Disable",
"disabled": "Disabled",
"delete": "[%key:ui::common::delete%]",
"delete_confirm_title": "Delete action?",
"delete_confirm_text": "[%key:ui::panel::config::automation::editor::triggers::delete_confirm_text%]",
"unsupported_action": "No visual editor support for this action",
"type_select": "Action type",
"continue_on_error": "Continue on error",
@@ -4800,6 +4813,8 @@
"label": "Field",
"field_selector": "Field selector"
},
"field_delete_confirm_title": "Delete field?",
"field_delete_confirm_text": "[%key:ui::panel::config::automation::editor::triggers::delete_confirm_text%]",
"header": "Script: {name}",
"default_name": "New script",
"modes": {

170
yarn.lock
View File

@@ -5080,131 +5080,131 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/a11y-base@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/a11y-base@npm:24.9.2"
"@vaadin/a11y-base@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/a11y-base@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/3e49b03daf1a1f16c4592364d8ddd0be574589779302f6cca10a242aab8a6052d69475eb60c77473267539ec2f741acd4a3794cd24aee5fa424dacfa3871668b
checksum: 10/f8789d0ff11f2c3aa3e8b5bcf4f1af32af1dcd7eb671c2fb4cae63331840c6a79f070bc637e6762f8bbd15ec0d6e4d9cb378507fb2a78cc7f876934914c4ea32
languageName: node
linkType: hard
"@vaadin/combo-box@npm:24.9.2":
version: 24.9.2
resolution: "@vaadin/combo-box@npm:24.9.2"
"@vaadin/combo-box@npm:24.9.1":
version: 24.9.1
resolution: "@vaadin/combo-box@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/field-base": "npm:~24.9.2"
"@vaadin/input-container": "npm:~24.9.2"
"@vaadin/item": "npm:~24.9.2"
"@vaadin/lit-renderer": "npm:~24.9.2"
"@vaadin/overlay": "npm:~24.9.2"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.2"
"@vaadin/vaadin-material-styles": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
"@vaadin/a11y-base": "npm:~24.9.1"
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/field-base": "npm:~24.9.1"
"@vaadin/input-container": "npm:~24.9.1"
"@vaadin/item": "npm:~24.9.1"
"@vaadin/lit-renderer": "npm:~24.9.1"
"@vaadin/overlay": "npm:~24.9.1"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.1"
"@vaadin/vaadin-material-styles": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/6931a185b4bf3854fae224e79eafc97b46fd0078f1757f458e5b5ddbc91b6dcbb80cdc27d8c4e7e20a75bb95e32da867f285a7c116eed23282bc9662b5b841f3
checksum: 10/422fd0d2e47678e759526097d128aba13f2e70147631baf43a0328cadb95c1bdc4ce0ab459a5a8710882568194ff79e3c0d73c3c4ebf3ffcac72a43dfbfe6ade
languageName: node
linkType: hard
"@vaadin/component-base@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/component-base@npm:24.9.2"
"@vaadin/component-base@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/component-base@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/vaadin-development-mode-detector": "npm:^2.0.0"
"@vaadin/vaadin-usage-statistics": "npm:^2.1.0"
lit: "npm:^3.0.0"
checksum: 10/782c8186a69ae51ac0e07af643a5d0cdfa9d281a3bda25ed8df0f3bd24210489e5f8fb60a5aec7e242d6d986fc16d54343dbc3725fc022da8890c9734f10e561
checksum: 10/5cb4870a0e0581bbb275c0addb144e0a3823fe4d86826d8fa2bff5c61105a5b6a34d7f65d13686a3b5f6e9e585105caa5b45716b9574ae7a0f323c1a6aa79535
languageName: node
linkType: hard
"@vaadin/field-base@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/field-base@npm:24.9.2"
"@vaadin/field-base@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/field-base@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/a11y-base": "npm:~24.9.1"
"@vaadin/component-base": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/456670e9fa69374e53cc3bd69a2a7bccfc447eec40756db1a3b6ea2ee2af39c529e0ae77d2b7977f65d26bcd323d448f9788794b67cb3e20027988e63c3a3d77
checksum: 10/47440fa611ad1bab1f996a6e1471959d156d9bed88f0671ffb07f32d9fee0fea267c71c6f35fe207dba919bddf43488552a0bdf5cbe64387a00256f22b4f1948
languageName: node
linkType: hard
"@vaadin/icon@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/icon@npm:24.9.2"
"@vaadin/icon@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/icon@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/86581231e2d46292152e7010852276a870700fdd5f0cce3ab234fcd5fa57827120163e0c9f6e34f436b5d43b20c741e6b51a40f9f2148cc77087f1b15d17e016
checksum: 10/0574f83fe14d5ffc5c8cf40a5fb38b80373d3ec590bedd1046800cda70f3d5d9337e4f062cdd2c79f917f71b6a71e850c4127da2cb8f7b863f0dd86a7e8d851b
languageName: node
linkType: hard
"@vaadin/input-container@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/input-container@npm:24.9.2"
"@vaadin/input-container@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/input-container@npm:24.9.1"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.2"
"@vaadin/vaadin-material-styles": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.1"
"@vaadin/vaadin-material-styles": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/fd8ff7458dddd01cf7d2bb4cf6a969473ccad4dec6292897698aa3a51db3b74e30e1ae4077aa092e324041734f4829febf9f81345ee6b142138cfe4436a8a0ba
checksum: 10/f8e2420fd3c0187eb2d1b96a53685e6ac053ce390ab5ab0c9cb9a7be42c66fe500828c0b0e3ef270ba3802b5c6dc667646906d8db3a7a8a0bef4b24decf1ffc7
languageName: node
linkType: hard
"@vaadin/item@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/item@npm:24.9.2"
"@vaadin/item@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/item@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.2"
"@vaadin/vaadin-material-styles": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
"@vaadin/a11y-base": "npm:~24.9.1"
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.1"
"@vaadin/vaadin-material-styles": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/1173fa0b147acfe66cb817ce518e8d7b2a4189e3386c98e8eebee7c15767d51b35d2b60a7d0ab165431dbe09061a492da96414755c936621e68cddaefa5c9301
checksum: 10/2f7c1cdeedd38aa80a8a8756690ca4d73415d801a37156d0f6e78e7dbebf470f3db090c7a7511e6f47d0ff6189447d4a452285622a8edd9364ab5cd5477649ab
languageName: node
linkType: hard
"@vaadin/lit-renderer@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/lit-renderer@npm:24.9.2"
"@vaadin/lit-renderer@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/lit-renderer@npm:24.9.1"
dependencies:
lit: "npm:^3.0.0"
checksum: 10/a33d22a26ae4d66c371e620a19da67ee1aab2cdb75dbcbf5dd4dc885368b9fc90a7063112dba7b58eee8cf3d7b69a6640941aa50106db1a287eca5c8188bbf76
checksum: 10/bdaaa2354352155e8b500e6c207881ec73be66acdccd98346375b1139d97d3acaec3b908e61db6cbde78b9f0b0aa94921144e3090d6bfaa5bb39961923b6f7db
languageName: node
linkType: hard
"@vaadin/overlay@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/overlay@npm:24.9.2"
"@vaadin/overlay@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/overlay@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.9.2"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.2"
"@vaadin/vaadin-material-styles": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
"@vaadin/a11y-base": "npm:~24.9.1"
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.1"
"@vaadin/vaadin-material-styles": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
lit: "npm:^3.0.0"
checksum: 10/48d52a1038c3ee033d56a819cd67da171b2f640bdfdbc1d1bb9091401a0a661f817862587efa0a5eda0ad5119ed0014edb1fd9f96b31b0724399c935d33133c0
checksum: 10/3d84412fe98c43b8e9487a5426f72dbc09fcad964d9f792bc7daab944776f106dfc27b0242642effb77e45a3314eccf646c3cd0cfc1852646f69fe1eab5bca32
languageName: node
linkType: hard
@@ -5215,37 +5215,37 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/vaadin-lumo-styles@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/vaadin-lumo-styles@npm:24.9.2"
"@vaadin/vaadin-lumo-styles@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/vaadin-lumo-styles@npm:24.9.1"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/icon": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
checksum: 10/ea0f008ccc4cabe1ae40f5fb78fb59b0b0d6996694ba054df1b634296563f75abeb0c1cbcde5adac8cc9e455e341f2b8fe13b132aa393e5a94804f1b4e6c8c43
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/icon": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
checksum: 10/6318b68ccee1ca3527d6aa503d3a57d5a9920a00b459057fa7a98336d071a63e905dfd1e29c965f740c7b409ea5a9cc5bd99f769633803b3d485f765741e43ee
languageName: node
linkType: hard
"@vaadin/vaadin-material-styles@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/vaadin-material-styles@npm:24.9.2"
"@vaadin/vaadin-material-styles@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/vaadin-material-styles@npm:24.9.1"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.2"
checksum: 10/bbe07aa29a8e9ea36f62cf1e17c497e38207850743be450d05976febb5b9d751766abf1a56d116410c09e91e6b390164f7fdb47714fac981c323cc75d00fa084
"@vaadin/component-base": "npm:~24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.1"
checksum: 10/e3cb4a5de4d28bcd43b82a94d25880af5b22116f15b0f711d5b66aaaf5116e144fe6f05143fee9e65ecc6d6ea8a3b734864667c20135e3047e79c3aab9a03f00
languageName: node
linkType: hard
"@vaadin/vaadin-themable-mixin@npm:24.9.2, @vaadin/vaadin-themable-mixin@npm:~24.9.2":
version: 24.9.2
resolution: "@vaadin/vaadin-themable-mixin@npm:24.9.2"
"@vaadin/vaadin-themable-mixin@npm:24.9.1, @vaadin/vaadin-themable-mixin@npm:~24.9.1":
version: 24.9.1
resolution: "@vaadin/vaadin-themable-mixin@npm:24.9.1"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
lit: "npm:^3.0.0"
style-observer: "npm:^0.0.8"
checksum: 10/80e06db3dc145ea28c43b58829eb298524dd44732e419ebd99e562053a7b7bcb4dec121e12bcba96610b63b328250dc4b09776d9d2dae94b3cca7f0414d5590c
checksum: 10/90139de617724f01b116a52388319d9e9d752215b98bf5a7ee10eebf4b0d21583c1ac8a238a921bfe83665c3becd5586d322a4d463cdf3e9bfa493331c68a604
languageName: node
linkType: hard
@@ -9267,8 +9267,8 @@ __metadata:
"@types/tar": "npm:6.1.13"
"@types/ua-parser-js": "npm:0.7.39"
"@types/webspeechapi": "npm:0.0.29"
"@vaadin/combo-box": "npm:24.9.2"
"@vaadin/vaadin-themable-mixin": "npm:24.9.2"
"@vaadin/combo-box": "npm:24.9.1"
"@vaadin/vaadin-themable-mixin": "npm:24.9.1"
"@vibrant/color": "npm:4.0.0"
"@vitest/coverage-v8": "npm:3.2.4"
"@vue/web-component-wrapper": "npm:1.3.0"