Compare commits

..

39 Commits

Author SHA1 Message Date
Bram Kragten
905435db3e Bumped version to 20260107.1 2026-01-09 23:26:47 +01:00
Yosi Levy
ea73fd3f01 Fix for volume scroll in media player (#28891) 2026-01-09 23:26:22 +01:00
Yosi Levy
e519a0203e Arrow fixes in media browser (#28890) 2026-01-09 23:26:21 +01:00
Bram Kragten
d98ee7e0b5 Add support for choose selector to initial form data (#28876)
* Add support for choose selector to initial form data

* Update compute-initial-ha-form-data.ts
2026-01-09 23:26:20 +01:00
Bram Kragten
6fc8c17909 Fix color palette creation (#28867) 2026-01-09 23:26:19 +01:00
dcapslock
201169c3d8 Fix choose selector active_choice when card editor config changes (#28858) 2026-01-09 23:26:18 +01:00
DAccord
303538ac21 Handling empty history (#28852)
Co-authored-by: DAccord <11232265+DAccord@users.noreply.github.com>
2026-01-09 23:26:17 +01:00
Bram Kragten
3c5a6193d0 Bumped version to 20260107.0 2026-01-07 16:32:09 +01:00
Wendelin
5ee4bd63f8 Fix logs provider picker mobile width (#28847) 2026-01-07 16:31:52 +01:00
Wendelin
b193929bd9 Throttle unknown value checks in ha-generic-picker (#28842) 2026-01-07 16:31:51 +01:00
Paul Bottein
3bee5c8cd4 Remove ha-combo-box-textfield (#28841) 2026-01-07 16:31:50 +01:00
Paul Bottein
976c74b8da Prefill the field with current value when editing a custom text item (#28840) 2026-01-07 16:31:49 +01:00
Wendelin
3a4a13db21 Improve device picker performance (#28835) 2026-01-07 16:31:48 +01:00
Paul Bottein
a2f033dd88 Reduce shadow effect for scrollable fade mixin (#28832) 2026-01-07 16:31:46 +01:00
Bram Kragten
a44b94c8df Prevent showing error during loading of statistics picker (#28823) 2026-01-07 16:31:45 +01:00
Bram Kragten
8796830ff9 Bumped version to 20251229.1 2026-01-06 17:18:45 +01:00
Bram Kragten
bdff13d5e1 Use target selector to filter references entities (#28822)
* Use target selector to filter references entities

* Update ha-selector-state.ts
2026-01-06 17:18:20 +01:00
Bram Kragten
4346484afc Use single path for thread icon, add KNX, simplify (#28819)
* Use single path for thread icon, simplify

* Add custom path for KNX
2026-01-06 17:18:19 +01:00
Bram Kragten
533694391e Remove iOS focus handling from dialogs (#28818) 2026-01-06 17:18:18 +01:00
Bram Kragten
3adba7aa1f Fix translation loading of choose selector (#28817) 2026-01-06 17:18:17 +01:00
karwosts
b60552c025 Fix statistic-graph-card cutoff w/ energy date picker (#28810)
* Fix statistics-graph energy-date mode end-time with 5min statistics

* don't modify date/hour for 5minute graph

* suggestedMax use period instead of days

* go back to string types
2026-01-06 17:18:16 +01:00
Paul Bottein
3011d56101 Show close button when zwave firmware update is finished (#28805) 2026-01-06 17:18:15 +01:00
Aidan Timson
c903c0d734 Add option for any state and show translated label for entity state values (#28803)
* Add option for any state

* Use translated labels for value
2026-01-06 17:18:14 +01:00
Aidan Timson
14be390994 Remove duplicate custom items, remove "no matching ..." when allow-custom-value set (#28801)
* Remove duplicate custom items, allow default from picker

* Memoize

* Memoize

* Memoize func

* Don't show no matching item when custom value is allowed

* Remove no items found label now unused

* Cleanup unused translations

* Restore used value

* Remove no items found label now unused

* Remove redundant comment

* Remove searchFn

* Ensure custom value isnt identical

* Fix duplicated value

* Fix duplicated value

* Use additional items for entity state content

* Fix duplicate values

---------

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
2026-01-06 17:18:12 +01:00
Paul Bottein
d48019a48e Remove custom value for unknown icon in icon picker (#28800) 2026-01-06 17:18:11 +01:00
Copilot
7b5cbb76ef Display template targets with neutral badge instead of "Unknown area" error (#28799)
* Initial plan

* Add template target display with neutral badge

- Import mdiCodeBraces icon and isTemplate function
- Check if target ID is a template before checking if it exists
- Display grey {} icon with "Template" text for templated targets
- Add "template" translation key to target_summary
- Prevents misleading red "Unknown area" badge for template targets

Co-authored-by: piitaya <5878303+piitaya@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: piitaya <5878303+piitaya@users.noreply.github.com>
2026-01-06 17:18:10 +01:00
Paul Bottein
c75fab025f Use regular item for bottom padding in combobox (#28798) 2026-01-06 17:18:09 +01:00
karwosts
c007206fa0 Fix statistic names w/ energy_date_selection (#28787) 2026-01-06 17:18:08 +01:00
Norbert Rittel
ab5b5a4276 A few small spelling fixes in user-facing strings (#28786)
- use correct spelling for "Wi-Fi" trademark
- capitalize "PIN" as abbreviation
- fix spelling of "set up" as verb
- fix sentence-casing
2026-01-06 17:18:07 +01:00
Paulus Schoutsen
9eb40f8470 Bluetooth panel to support multi adapter (#28763)
* Support multiple adapters in bluetooth panel

* Move connection allocations up

* Make it tabs

* Add icons

* Revert "Add icons"

This reverts commit e338b6e578.

* Revert "Make it tabs"

This reverts commit d1b19d5c3e.

* Fix scanner matching and no active connection slot support

* Update src/panels/config/integrations/integration-panels/bluetooth/bluetooth-config-dashboard.ts

---------

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2026-01-06 17:18:06 +01:00
dependabot[bot]
bc827d9bf1 Bump qs from 6.14.0 to 6.14.1 (#28760)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-06 17:18:05 +01:00
Simon Lamon
24f5d58691 Make cancel a secondary action in blueprint import (#28754) 2026-01-06 17:18:04 +01:00
Simon Lamon
13505a9104 Fix matter translations (#28752) 2026-01-06 17:18:03 +01:00
Simon Lamon
c1d135aa16 Revert lit update (#28751) 2026-01-06 17:18:02 +01:00
Paulus Schoutsen
16d13c3202 Verify bluetooth config entries exist before showing entry (#28745) 2026-01-06 17:18:01 +01:00
Paulus Schoutsen
46b3c34ba1 Hide dashboard controls in kiosk mode (#28742) 2026-01-06 17:18:00 +01:00
Paulus Schoutsen
57a81b9de4 Add config entry picker for Z-Wave JS panel (#28741) 2026-01-06 17:17:58 +01:00
Simon Lamon
69f4f1dbed Provide kioskmode in demo (#28739) 2026-01-06 17:17:57 +01:00
Paulus Schoutsen
355a1aff3f Protocol link updates (#28736)
* Update icons Thread & Insteon

* Remove matter link

* Remove back path from ZHA

* Fix ZHA dashboard config entry
2026-01-06 17:17:56 +01:00
43 changed files with 919 additions and 881 deletions

View File

@@ -22,13 +22,11 @@ You are an assistant helping with development of the Home Assistant frontend. Th
```bash
yarn lint # ESLint + Prettier + TypeScript + Lit
yarn format # Auto-fix ESLint + Prettier
yarn lint:types # TypeScript compiler (run WITHOUT file arguments)
yarn lint:types # TypeScript compiler
yarn test # Vitest
script/develop # Development server
```
> **WARNING:** Never run `tsc` or `yarn lint:types` with file arguments (e.g., `yarn lint:types src/file.ts`). When `tsc` receives file arguments, it ignores `tsconfig.json` and emits `.js` files into `src/`, polluting the codebase. Always run `yarn lint:types` without arguments. For individual file type checking, rely on IDE diagnostics. If `.js` files are accidentally generated, clean up with `git clean -fd src/`.
### Component Prefixes
- `ha-` - Home Assistant components

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send bundle stats and build information to RelativeCI
uses: relative-ci/agent-action@3c681926017930047fc03acaa35cd6a44efcbfc3 # v3.2.2
uses: relative-ci/agent-action@c45aaa919ef85620af54242a241ac17a8fa35983 # v3.2.1
with:
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
token: ${{ github.token }}

View File

@@ -187,11 +187,5 @@ export default tseslint.config(
],
"no-use-before-define": "off",
},
},
{
files: ["src/util/recorder-worklet.js"],
languageOptions: {
globals: globals.audioWorklet,
},
}
);

View File

@@ -34,18 +34,18 @@
"@codemirror/legacy-modes": "6.5.2",
"@codemirror/search": "6.5.11",
"@codemirror/state": "6.5.3",
"@codemirror/view": "6.39.8",
"@codemirror/view": "6.39.7",
"@date-fns/tz": "1.4.1",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "7.1.1",
"@formatjs/intl-displaynames": "7.1.1",
"@formatjs/intl-durationformat": "0.9.1",
"@formatjs/intl-getcanonicallocales": "3.1.1",
"@formatjs/intl-listformat": "8.1.1",
"@formatjs/intl-locale": "5.1.1",
"@formatjs/intl-numberformat": "9.1.1",
"@formatjs/intl-pluralrules": "6.1.1",
"@formatjs/intl-relativetimeformat": "12.1.1",
"@formatjs/intl-datetimeformat": "7.1.0",
"@formatjs/intl-displaynames": "7.1.0",
"@formatjs/intl-durationformat": "0.9.0",
"@formatjs/intl-getcanonicallocales": "3.1.0",
"@formatjs/intl-listformat": "8.1.0",
"@formatjs/intl-locale": "5.1.0",
"@formatjs/intl-numberformat": "9.1.0",
"@formatjs/intl-pluralrules": "6.1.0",
"@formatjs/intl-relativetimeformat": "12.1.0",
"@fullcalendar/core": "6.1.20",
"@fullcalendar/daygrid": "6.1.20",
"@fullcalendar/interaction": "6.1.20",
@@ -112,7 +112,7 @@
"hls.js": "1.6.15",
"home-assistant-js-websocket": "9.6.0",
"idb-keyval": "6.2.2",
"intl-messageformat": "11.0.8",
"intl-messageformat": "11.0.7",
"js-yaml": "4.1.1",
"leaflet": "1.9.4",
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
@@ -156,8 +156,8 @@
"@octokit/plugin-retry": "8.0.3",
"@octokit/rest": "22.0.1",
"@rsdoctor/rspack-plugin": "1.4.0",
"@rspack/core": "1.7.0",
"@rspack/dev-server": "1.1.5",
"@rspack/core": "1.6.8",
"@rspack/dev-server": "1.1.4",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.25",
"@types/chromecast-caf-sender": "1.0.11",
@@ -199,7 +199,7 @@
"gulp-rename": "2.1.0",
"html-minifier-terser": "7.2.0",
"husky": "9.1.7",
"jsdom": "27.4.0",
"jsdom": "27.3.0",
"jszip": "3.10.1",
"lint-staged": "16.2.7",
"lit-analyzer": "2.0.3",
@@ -215,7 +215,7 @@
"terser-webpack-plugin": "5.3.16",
"ts-lit-plugin": "2.0.2",
"typescript": "5.9.3",
"typescript-eslint": "8.51.0",
"typescript-eslint": "8.50.1",
"vite-tsconfig-paths": "6.0.3",
"vitest": "4.0.16",
"webpack-stats-plugin": "1.1.3",
@@ -229,7 +229,7 @@
"clean-css": "5.3.3",
"@lit/reactive-element": "2.1.2",
"@fullcalendar/daygrid": "6.1.20",
"globals": "17.0.0",
"globals": "16.5.0",
"tslib": "2.8.1",
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
"glob@^10.2.2": "^10.5.0"

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20251229.0"
version = "20260107.1"
license = "Apache-2.0"
license-files = ["LICENSE*"]
description = "The Home Assistant frontend"

View File

@@ -79,7 +79,7 @@ export const generateColorPalette = (
}
return steps.map((step) => {
const name = `color-${label}-${step}`;
const name = `ha-color-${label}-${step}`;
// Base color at 50%
if (step === 50) {

View File

@@ -18,6 +18,7 @@ import type { HomeAssistant } from "../../types";
import { brandsUrl } from "../../util/brands-url";
import "../ha-generic-picker";
import type { HaGenericPicker } from "../ha-generic-picker";
import type { HaEntityPickerEntityFilterFunc } from "../../data/entity/entity";
export type HaDevicePickerDeviceFilterFunc = (
device: DeviceRegistryEntry
@@ -94,7 +95,30 @@ export class HaDevicePicker extends LitElement {
@state() private _configEntryLookup: Record<string, ConfigEntry> = {};
private _getDevicesMemoized = memoizeOne(getDevices);
private _getDevicesMemoized = memoizeOne(
(
_devices: HomeAssistant["devices"],
configEntryLookup: Record<string, ConfigEntry>,
includeDomains?: string[],
excludeDomains?: string[],
includeDeviceClasses?: string[],
deviceFilter?: HaDevicePickerDeviceFilterFunc,
entityFilter?: HaEntityPickerEntityFilterFunc,
excludeDevices?: string[],
value?: string
) =>
getDevices(
this.hass,
configEntryLookup,
includeDomains,
excludeDomains,
includeDeviceClasses,
deviceFilter,
entityFilter,
excludeDevices,
value
)
);
protected firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);
@@ -110,7 +134,7 @@ export class HaDevicePicker extends LitElement {
private _getItems = () =>
this._getDevicesMemoized(
this.hass,
this.hass.devices,
this._configEntryLookup,
this.includeDomains,
this.excludeDomains,

View File

@@ -18,10 +18,7 @@ import "../ha-combo-box-item";
import "../ha-generic-picker";
import type { HaGenericPicker } from "../ha-generic-picker";
import "../ha-input-helper-text";
import {
NO_ITEMS_AVAILABLE_ID,
type PickerComboBoxItem,
} from "../ha-picker-combo-box";
import type { PickerComboBoxItem } from "../ha-picker-combo-box";
import "../ha-sortable";
const rowRenderer: RenderItemFunction<PickerComboBoxItem> = (item) => html`
@@ -184,18 +181,17 @@ export class HaEntityNamePicker extends LitElement {
.disabled=${this.disabled}
.required=${this.required && !value.length}
.getItems=${this._getFilteredItems}
.getAdditionalItems=${this._getAdditionalItems}
.rowRenderer=${rowRenderer}
.searchFn=${this._searchFn}
.notFoundLabel=${this.hass.localize(
"ui.components.entity.entity-name-picker.no_match"
)}
.value=${this._getPickerValue()}
allow-custom-value
.customValueLabel=${this.hass.localize(
"ui.components.entity.entity-name-picker.custom_name"
)}
@value-changed=${this._pickerValueChanged}
.searchFn=${this._searchFn}
.searchLabel=${this.hass.localize(
"ui.components.entity.entity-name-picker.search"
)}
>
<div slot="field" class="container">
<ha-sortable
@@ -279,6 +275,11 @@ export class HaEntityNamePicker extends LitElement {
this._editIndex = idx;
await this.updateComplete;
await this._picker?.open();
const value = this._items[idx];
// Pre-fill the field value when editing a text item
if (value.type === "text" && value.text) {
this._picker?.setFieldValue(value.text);
}
}
private get _items(): EntityNameItem[] {
@@ -316,10 +317,7 @@ export class HaEntityNamePicker extends LitElement {
return undefined;
}
private _getFilteredItems = (
searchString?: string,
_section?: string
): PickerComboBoxItem[] => {
private _getFilteredItems = (): PickerComboBoxItem[] => {
const items = this._getItems(this.entityId);
const currentItem =
this._editIndex != null ? this._items[this._editIndex] : undefined;
@@ -336,49 +334,27 @@ export class HaEntityNamePicker extends LitElement {
);
// When editing an existing text item, include it in the base items
if (currentItem?.type === "text" && currentItem.text && !searchString) {
if (currentItem?.type === "text" && currentItem.text) {
filteredItems.push(this._customNameOption(currentItem.text));
}
return filteredItems;
};
private _getAdditionalItems = (
searchString?: string
private _searchFn = (
searchString: string,
filteredItems: PickerComboBoxItem[]
): PickerComboBoxItem[] => {
if (!searchString) {
return [];
}
const currentItem =
this._editIndex != null ? this._items[this._editIndex] : undefined;
const currentId =
currentItem?.type === "text" && currentItem.text
? this._customNameOption(currentItem.text).id
: undefined;
// Don't add if it's the same as the current item being edited
if (
currentItem?.type === "text" &&
currentItem.text &&
currentItem.text === searchString
) {
return [];
}
// Always return custom name option when there's a search string
// This prevents "No matching items found" from showing
return [this._customNameOption(searchString)];
};
private _searchFn = (
search: string,
filteredItems: PickerComboBoxItem[],
_allItems: PickerComboBoxItem[]
): PickerComboBoxItem[] => {
// Remove NO_ITEMS_AVAILABLE_ID if we have additional items (custom name option)
// This prevents "No matching items found" from showing when custom values are allowed
const hasAdditionalItems = this._getAdditionalItems(search).length > 0;
if (hasAdditionalItems) {
return filteredItems.filter(
(item) => typeof item !== "string" || item !== NO_ITEMS_AVAILABLE_ID
);
// Remove custom name option if search string is present to avoid duplicates
if (searchString && currentId) {
return filteredItems.filter((item) => item.id !== currentId);
}
return filteredItems;
};

View File

@@ -19,7 +19,10 @@ import "../ha-combo-box-item";
import "../ha-generic-picker";
import type { HaGenericPicker } from "../ha-generic-picker";
import "../ha-input-helper-text";
import type { PickerComboBoxItem } from "../ha-picker-combo-box";
import {
NO_ITEMS_AVAILABLE_ID,
type PickerComboBoxItem,
} from "../ha-picker-combo-box";
import "../ha-sortable";
const HIDDEN_ATTRIBUTES = [
@@ -199,11 +202,7 @@ export class HaStateContentPicker extends LitElement {
.value=${this._getPickerValue()}
.getItems=${this._getFilteredItems}
.getAdditionalItems=${this._getAdditionalItems}
.notFoundLabel=${this.hass.localize("ui.components.combo-box.no_match")}
allow-custom-value
.customValueLabel=${this.hass.localize(
"ui.components.entity.entity-state-content-picker.custom_state"
)}
.searchFn=${this._searchFn}
@value-changed=${this._pickerValueChanged}
>
<div slot="field" class="container">
@@ -328,7 +327,7 @@ export class HaStateContentPicker extends LitElement {
(text: string): PickerComboBoxItem => ({
id: text,
primary: this.hass.localize(
"ui.components.entity.entity-state-content-picker.custom_state"
"ui.components.entity.entity-state-content-picker.custom_attribute"
),
secondary: `"${text}"`,
search_labels: {
@@ -340,10 +339,7 @@ export class HaStateContentPicker extends LitElement {
})
);
private _getFilteredItems = (
searchString?: string,
_section?: string
): PickerComboBoxItem[] => {
private _getFilteredItems = (): PickerComboBoxItem[] => {
const stateObj = this.entityId
? this.hass.states[this.entityId]
: undefined;
@@ -358,11 +354,7 @@ export class HaStateContentPicker extends LitElement {
);
// When editing an existing custom value, include it in the base items
if (
currentValue &&
!items.find((item) => item.id === currentValue) &&
!searchString
) {
if (currentValue && !items.find((item) => item.id === currentValue)) {
filteredItems.push(this._customValueOption(currentValue));
}
@@ -372,33 +364,34 @@ export class HaStateContentPicker extends LitElement {
private _getAdditionalItems = (
searchString?: string
): PickerComboBoxItem[] => {
if (!searchString) {
return [];
}
const currentValue =
this._editIndex != null ? this._value[this._editIndex] : undefined;
// Don't add if it's the same as the current item being edited
if (currentValue && currentValue === searchString) {
return [];
}
// Check if the search string matches an existing item
const stateObj = this.entityId
? this.hass.states[this.entityId]
: undefined;
const items = this._getItems(this.entityId, stateObj, this.allowName);
const existingItem = items.find((item) => item.id === searchString);
// Only return custom value option if it doesn't match an existing item
if (!existingItem) {
// If the search string does not match with the id of any of the items,
// offer to add it as a custom attribute
const existingItem = items.find((item) => item.id === searchString);
if (searchString && !existingItem) {
return [this._customValueOption(searchString)];
}
return [];
};
private _searchFn = (
search: string,
filteredItems: PickerComboBoxItem[],
_allItems: PickerComboBoxItem[]
): PickerComboBoxItem[] => {
if (!search) {
return filteredItems;
}
// Always exclude NO_ITEMS_AVAILABLE_ID (since custom values are allowed) and currentValue (the custom value being edited)
return filteredItems.filter((item) => item.id !== NO_ITEMS_AVAILABLE_ID);
};
private async _moveItem(ev: CustomEvent) {
ev.stopPropagation();
const { oldIndex, newIndex } = ev.detail;

View File

@@ -7,6 +7,7 @@ import { getStates } from "../../common/entity/get_states";
import type { HomeAssistant, ValueChangedEvent } from "../../types";
import "../ha-generic-picker";
import type { PickerComboBoxItem } from "../ha-picker-combo-box";
import type { PickerValueRenderer } from "../ha-picker-field";
@customElement("ha-entity-state-picker")
export class HaEntityStatePicker extends LitElement {
@@ -108,6 +109,12 @@ export class HaEntityStatePicker extends LitElement {
this.extraOptions
);
private _valueRenderer: PickerValueRenderer = (value: string) => {
const items = this._getFilteredItems();
const item = items.find((option) => option.id === value);
return html`<span slot="headline">${item?.primary ?? value}</span>`;
};
protected render() {
if (!this.hass) {
return nothing;
@@ -125,6 +132,7 @@ export class HaEntityStatePicker extends LitElement {
.helper=${this.helper}
.value=${this.value}
.getItems=${this._getFilteredItems}
.valueRenderer=${this._valueRenderer}
.notFoundLabel=${this.hass.localize("ui.components.combo-box.no_match")}
.customValueLabel=${this.hass.localize(
"ui.components.entity.entity-state-picker.add_custom_state"

View File

@@ -141,6 +141,7 @@ export class HaStatisticPicker extends LitElement {
private async _getStatisticIds() {
this.statisticIds = await getStatisticIds(this.hass, this.statisticTypes);
this._picker?.requestUpdate();
}
private _getItems = () =>
@@ -177,9 +178,9 @@ export class HaStatisticPicker extends LitElement {
entitiesOnly?: boolean,
excludeStatistics?: string[],
value?: string
): StatisticComboBoxItem[] => {
): StatisticComboBoxItem[] | undefined => {
if (!statisticIds) {
return [];
return undefined;
}
if (includeStatisticsUnitOfMeasurement) {

View File

@@ -1,24 +0,0 @@
import type { PropertyValues } from "lit";
import { customElement, property } from "lit/decorators";
import { HaTextField } from "./ha-textfield";
@customElement("ha-combo-box-textfield")
export class HaComboBoxTextField extends HaTextField {
@property({ type: Boolean, attribute: "force-blank-value" })
public forceBlankValue = false;
protected willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps);
if (changedProps.has("value") || changedProps.has("forceBlankValue")) {
if (this.forceBlankValue && this.value) {
this.value = "";
}
}
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-combo-box-textfield": HaComboBoxTextField;
}
}

View File

@@ -1,5 +1,21 @@
import type { Selector } from "../../data/selector";
import type { HaFormSchema } from "./types";
import type { HaFormData, HaFormSchema } from "./types";
const setDefaultValue = (
field: HaFormSchema,
value: HaFormData | undefined
) => {
if ("selector" in field && "choose" in field.selector) {
const firstChoice = Object.keys(field.selector.choose.choices)[0];
if (firstChoice) {
return {
active_choice: firstChoice,
[firstChoice]: value,
};
}
}
return value;
};
export const computeInitialHaFormData = (
schema: HaFormSchema[] | readonly HaFormSchema[]
@@ -10,9 +26,12 @@ export const computeInitialHaFormData = (
field.description?.suggested_value !== undefined &&
field.description?.suggested_value !== null
) {
data[field.name] = field.description.suggested_value;
data[field.name] = setDefaultValue(
field,
field.description.suggested_value
);
} else if ("default" in field) {
data[field.name] = field.default;
data[field.name] = setDefaultValue(field, field.default);
} else if (field.type === "expandable") {
const expandableData = computeInitialHaFormData(field.schema);
if (field.required || Object.keys(expandableData).length) {
@@ -108,6 +127,21 @@ export const computeInitialHaFormData = (
data[field.name] = {};
} else if ("state" in selector) {
data[field.name] = selector.state?.multiple ? [] : "";
} else if ("choose" in selector) {
const firstChoice = Object.keys(selector.choose.choices)[0];
if (!firstChoice) {
data[field.name] = {};
} else {
data[field.name] = {
active_choice: firstChoice,
[firstChoice]: computeInitialHaFormData([
{
name: firstChoice,
selector: selector.choose.choices[firstChoice].selector,
},
])[firstChoice],
};
}
} else {
throw new Error(
`Selector ${Object.keys(selector)[0]} not supported in initial form data`

View File

@@ -1,12 +1,19 @@
import "@home-assistant/webawesome/dist/components/popover/popover";
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
import { mdiPlaylistPlus } from "@mdi/js";
import { css, html, LitElement, nothing, type CSSResultGroup } from "lit";
import {
css,
html,
LitElement,
nothing,
type CSSResultGroup,
type PropertyValues,
} from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { tinykeys } from "tinykeys";
import { fireEvent } from "../common/dom/fire_event";
import { throttle } from "../common/util/throttle";
import { PickerMixin } from "../mixins/picker-mixin";
import type { FuseWeightedKey } from "../resources/fuseMultiTerm";
import type { HomeAssistant } from "../types";
@@ -39,7 +46,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
public getItems!: (
searchString?: string,
section?: string
) => (PickerComboBoxItem | string)[];
) => (PickerComboBoxItem | string)[] | undefined;
@property({ attribute: false, type: Array })
public getAdditionalItems?: (searchString?: string) => PickerComboBoxItem[];
@@ -114,6 +121,8 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
@state() private _openedNarrow = false;
@state() private _unknownValue = false;
static shadowRootOptions = {
...LitElement.shadowRootOptions,
delegatesFocus: true,
@@ -130,6 +139,25 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
private _unsubscribeTinyKeys?: () => void;
protected willUpdate(changedProperties: PropertyValues) {
if (changedProperties.has("value")) {
this._setUnknownValue();
return;
}
if (changedProperties.has("hass")) {
this._throttleUnknownValue();
}
}
public setFieldValue(value: string) {
if (this._comboBox) {
this._comboBox.setFieldValue(value);
return;
}
// Store initial value to set when opened
this._initialFieldValue = value;
}
protected render() {
// Only show label if it's not a top label and there is a value.
const label = this.useTopLabel && this.value ? undefined : this.label;
@@ -157,11 +185,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
type="button"
class=${this._opened ? "opened" : ""}
compact
.unknown=${this._unknownValue(
this.allowCustomValue,
this.value,
this.getItems()
)}
.unknown=${this._unknownValue}
.unknownItemText=${this.unknownItemText}
aria-label=${ifDefined(this.label)}
@click=${this.open}
@@ -182,40 +206,42 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
</ha-picker-field>`}
</slot>
</div>
${!this._openedNarrow && (this._pickerWrapperOpen || this._opened)
? html`
<wa-popover
.open=${this._pickerWrapperOpen}
style="--body-width: ${this._popoverWidth}px;"
without-arrow
distance="-4"
.placement=${this.popoverPlacement}
for="picker"
auto-size="vertical"
auto-size-padding="16"
@wa-after-show=${this._dialogOpened}
@wa-after-hide=${this._hidePicker}
trap-focus
role="dialog"
aria-modal="true"
aria-label=${this.label || "Select option"}
>
${this._renderComboBox()}
</wa-popover>
`
: this._pickerWrapperOpen || this._opened
? html`<ha-bottom-sheet
flexcontent
.open=${this._pickerWrapperOpen}
@wa-after-show=${this._dialogOpened}
@closed=${this._hidePicker}
role="dialog"
aria-modal="true"
aria-label=${this.label || "Select option"}
>
${this._renderComboBox(true)}
</ha-bottom-sheet>`
: nothing}
${this._pickerWrapperOpen || this._opened
? this._openedNarrow
? html`
<ha-bottom-sheet
flexcontent
.open=${this._pickerWrapperOpen}
@wa-after-show=${this._dialogOpened}
@closed=${this._hidePicker}
role="dialog"
aria-modal="true"
aria-label=${this.label || "Select option"}
>
${this._renderComboBox(true)}
</ha-bottom-sheet>
`
: html`
<wa-popover
.open=${this._pickerWrapperOpen}
style="--body-width: ${this._popoverWidth}px;"
without-arrow
distance="-4"
.placement=${this.popoverPlacement}
for="picker"
auto-size="vertical"
auto-size-padding="16"
@wa-after-show=${this._dialogOpened}
@wa-after-hide=${this._hidePicker}
trap-focus
role="dialog"
aria-modal="true"
aria-label=${this.label || "Select option"}
>
${this._renderComboBox()}
</wa-popover>
`
: nothing}
</div>
${this._renderHelper()}`;
}
@@ -248,26 +274,29 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
`;
}
private _unknownValue = memoizeOne(
(
allowCustomValue: boolean,
value?: string,
items?: (PickerComboBoxItem | string)[]
) => {
if (
allowCustomValue ||
value === undefined ||
value === null ||
value === "" ||
!items
) {
return false;
}
return !items.some(
(item) => typeof item !== "string" && item.id === value
);
private _setUnknownValue = () => {
const items = this.getItems();
if (
this.allowCustomValue ||
this.value === undefined ||
this.value === null ||
this.value === "" ||
!items
) {
this._unknownValue = false;
return;
}
this._unknownValue = !items.some(
(item) => typeof item !== "string" && item.id === this.value
);
};
private _throttleUnknownValue = throttle(
this._setUnknownValue,
1000,
true,
false
);
private _renderHelper() {
@@ -283,9 +312,16 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
</ha-input-helper-text>`;
}
private _initialFieldValue?: string;
private _dialogOpened = () => {
this._opened = true;
requestAnimationFrame(() => {
// Set initial field value if needed
if (this._initialFieldValue) {
this._comboBox?.setFieldValue(this._initialFieldValue);
this._initialFieldValue = undefined;
}
if (this.hass && isIosApp(this.hass)) {
this.hass.auth.external!.fireMessage({
type: "focus_element",
@@ -295,6 +331,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
});
return;
}
this._comboBox?.focus();
});
};
@@ -376,6 +413,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
.container {
position: relative;
display: block;
max-width: 100%;
}
label[disabled] {
color: var(--mdc-text-field-disabled-ink-color, rgba(0, 0, 0, 0.6));

View File

@@ -124,9 +124,6 @@ export class HaIconPicker extends LitElement {
.label=${this.label}
.value=${this._value}
.searchFn=${this._filterIcons}
.notFoundLabel=${this.hass?.localize(
"ui.components.icon-picker.no_match"
)}
popover-placement="bottom-start"
@value-changed=${this._valueChanged}
>
@@ -173,20 +170,6 @@ export class HaIconPicker extends LitElement {
}
}
// Allow preview for custom icon not in list
if (rankedItems.length === 0) {
rankedItems.push({
item: {
id: filter,
primary: filter,
icon: filter,
search_labels: { keyword: filter },
sorting_label: filter,
},
rank: 0,
});
}
return rankedItems
.sort((itemA, itemB) => itemA.rank - itemB.rank)
.map((item) => item.item);

View File

@@ -109,7 +109,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
public getItems!: (
searchString?: string,
section?: string
) => PickerComboBoxItem[];
) => PickerComboBoxItem[] | undefined;
@property({ attribute: false, type: Array })
public getAdditionalItems?: (searchString?: string) => PickerComboBoxItem[];
@@ -153,6 +153,12 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
@state() private _items: PickerComboBoxItem[] = [];
public setFieldValue(value: string) {
if (this._searchFieldElement) {
this._searchFieldElement.value = value;
}
}
protected get scrollableElement(): HTMLElement | null {
return this._virtualizerElement as HTMLElement | null;
}
@@ -295,7 +301,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
this.getAdditionalItems?.(searchString) || [];
private _getItems = () => {
let items = [...this.getItems(this._search, this.selectedSection)];
let items = [...(this.getItems(this._search, this.selectedSection) || [])];
if (!this.sections?.length) {
items = items.sort((entityA, entityB) => {
@@ -324,7 +330,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
});
}
if (!items.length) {
if (!items.length && !this.allowCustomValue) {
items.push({ id: NO_ITEMS_AVAILABLE_ID, primary: "" });
}
@@ -430,7 +436,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
index
);
if (!filteredItems.length) {
if (!filteredItems.length && !this.allowCustomValue) {
filteredItems.push({ id: NO_ITEMS_AVAILABLE_ID, primary: "" });
}

View File

@@ -38,6 +38,13 @@ export class HaChooseSelector extends LitElement {
) {
this._setActiveChoice();
}
if (
changedProperties.has("value") &&
changedProperties.get("value")?.active_choice &&
changedProperties.get("value")?.active_choice !== this._activeChoice
) {
this._setActiveChoice();
}
}
protected render() {
@@ -54,7 +61,8 @@ export class HaChooseSelector extends LitElement {
size="small"
.buttons=${this._toggleButtons(
this.selector.choose.choices,
this.selector.choose.translation_key
this.selector.choose.translation_key,
this.hass.localize
)}
.active=${this._activeChoice}
@value-changed=${this._choiceChanged}
@@ -72,7 +80,11 @@ export class HaChooseSelector extends LitElement {
}
private _toggleButtons = memoizeOne(
(choices: ChooseSelector["choose"]["choices"], translationKey?: string) =>
(
choices: ChooseSelector["choose"]["choices"],
translationKey?: string,
_localize?: HomeAssistant["localize"]
) =>
Object.keys(choices).map((choice) => ({
label:
this.localizeValue && translationKey

View File

@@ -1,12 +1,17 @@
import type { HassServiceTarget } from "home-assistant-js-websocket";
import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import type { StateSelector } from "../../data/selector";
import { extractFromTarget } from "../../data/target";
import memoizeOne from "memoize-one";
import {
resolveEntityIDs,
type StateSelector,
type TargetSelector,
} from "../../data/selector";
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import type { HomeAssistant } from "../../types";
import "../entity/ha-entity-state-picker";
import "../entity/ha-entity-states-picker";
import type { PickerComboBoxItem } from "../ha-picker-combo-box";
@customElement("ha-selector-state")
export class HaSelectorState extends SubscribeMixin(LitElement) {
@@ -28,16 +33,33 @@ export class HaSelectorState extends SubscribeMixin(LitElement) {
filter_attribute?: string;
filter_entity?: string | string[];
filter_target?: HassServiceTarget;
target_selector?: TargetSelector;
};
@state() private _entityIds?: string | string[];
private _convertExtraOptions = memoizeOne(
(
extraOptions?: { label: string; value: any }[]
): PickerComboBoxItem[] | undefined => {
if (!extraOptions) {
return undefined;
}
return extraOptions.map((option) => ({
id: option.value,
primary: option.label,
sorting_label: option.label,
}));
}
);
willUpdate(changedProps) {
if (changedProps.has("selector") || changedProps.has("context")) {
this._resolveEntityIds(
this.selector.state?.entity_id,
this.context?.filter_entity,
this.context?.filter_target
this.context?.filter_target,
this.context?.target_selector
).then((entityIds) => {
this._entityIds = entityIds;
});
@@ -45,6 +67,9 @@ export class HaSelectorState extends SubscribeMixin(LitElement) {
}
protected render() {
const extraOptions = this._convertExtraOptions(
this.selector.state?.extra_options
);
if (this.selector.state?.multiple) {
return html`
<ha-entity-states-picker
@@ -52,7 +77,7 @@ export class HaSelectorState extends SubscribeMixin(LitElement) {
.entityId=${this._entityIds}
.attribute=${this.selector.state?.attribute ||
this.context?.filter_attribute}
.extraOptions=${this.selector.state?.extra_options}
.extraOptions=${extraOptions}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
@@ -69,7 +94,7 @@ export class HaSelectorState extends SubscribeMixin(LitElement) {
.entityId=${this._entityIds}
.attribute=${this.selector.state?.attribute ||
this.context?.filter_attribute}
.extraOptions=${this.selector.state?.extra_options}
.extraOptions=${extraOptions}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
@@ -84,7 +109,8 @@ export class HaSelectorState extends SubscribeMixin(LitElement) {
private async _resolveEntityIds(
selectorEntityId: string | string[] | undefined,
contextFilterEntity: string | string[] | undefined,
contextFilterTarget: HassServiceTarget | undefined
contextFilterTarget: HassServiceTarget | undefined,
contextTargetSelector: TargetSelector | undefined
): Promise<string | string[] | undefined> {
if (selectorEntityId !== undefined) {
return selectorEntityId;
@@ -93,8 +119,14 @@ export class HaSelectorState extends SubscribeMixin(LitElement) {
return contextFilterEntity;
}
if (contextFilterTarget !== undefined) {
const result = await extractFromTarget(this.hass, contextFilterTarget);
return result.referenced_entities;
return resolveEntityIDs(
this.hass,
contextFilterTarget,
this.hass.entities,
this.hass.devices,
this.hass.areas,
contextTargetSelector
);
}
return undefined;
}

View File

@@ -57,6 +57,7 @@ export class HaSlider extends Slider {
#thumb {
border: none;
background-color: var(--ha-slider-thumb-color, var(--primary-color));
overflow: hidden;
}
#thumb:after {

View File

@@ -13,7 +13,6 @@ import { fireEvent } from "../common/dom/fire_event";
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import { isIosApp } from "../util/is_ios";
import "./ha-dialog-header";
import "./ha-icon-button";
@@ -185,21 +184,22 @@ export class HaWaDialog extends ScrollableFadeMixin(LitElement) {
await this.updateComplete;
requestAnimationFrame(() => {
if (isIosApp(this.hass)) {
const element = this.querySelector("[autofocus]");
if (element !== null) {
if (!element.id) {
element.id = "ha-wa-dialog-autofocus";
}
this.hass.auth.external!.fireMessage({
type: "focus_element",
payload: {
element_id: element.id,
},
});
}
return;
}
// temporary disabled because of issues with focus in iOS app, can be reenabled in 2026.2.0
// if (isIosApp(this.hass)) {
// const element = this.querySelector("[autofocus]");
// if (element !== null) {
// if (!element.id) {
// element.id = "ha-wa-dialog-autofocus";
// }
// this.hass.auth.external!.fireMessage({
// type: "focus_element",
// payload: {
// element_id: element.id,
// },
// });
// }
// return;
// }
(this.querySelector("[autofocus]") as HTMLElement | null)?.focus();
});
};

View File

@@ -1,7 +1,6 @@
import type { ActionDetail } from "@material/mwc-list";
import {
mdiAlphaABoxOutline,
mdiArrowLeft,
mdiClose,
mdiDotsVertical,
mdiGrid,
@@ -24,6 +23,7 @@ import type { HomeAssistant } from "../../types";
import "../ha-dialog";
import "../ha-dialog-header";
import "../ha-list-item";
import "../ha-icon-button-arrow-prev";
import "./ha-media-manage-button";
import "./ha-media-player-browse";
import type {
@@ -88,11 +88,10 @@ class DialogMediaPlayerBrowse extends LitElement {
<ha-dialog-header show-border slot="heading">
${this._navigateIds.length > (this._params.minimumNavigateLevel ?? 1)
? html`
<ha-icon-button
<ha-icon-button-arrow-prev
slot="navigationIcon"
.path=${mdiArrowLeft}
@click=${this._goBack}
></ha-icon-button>
></ha-icon-button-arrow-prev>
`
: nothing}
<span slot="title">

View File

@@ -16,6 +16,8 @@ export interface RecorderInfo {
export type StatisticType = "change" | "state" | "sum" | "min" | "max" | "mean";
export type StatisticPeriod = "5minute" | "hour" | "day" | "week" | "month";
export type Statistics = Record<string, StatisticValue[]>;
export interface StatisticValue {
@@ -174,7 +176,7 @@ export const fetchStatistics = (
startTime: Date,
endTime?: Date,
statistic_ids?: string[],
period: "5minute" | "hour" | "day" | "week" | "month" = "hour",
period: StatisticPeriod = "hour",
units?: StatisticsUnitConfiguration,
types?: StatisticsTypes
) =>

View File

@@ -929,13 +929,13 @@ export const resolveEntityIDs = (
targetPickerValue: HassServiceTarget,
entities: HomeAssistant["entities"],
devices: HomeAssistant["devices"],
areas: HomeAssistant["areas"]
areas: HomeAssistant["areas"],
targetSelector: TargetSelector = { target: {} }
): string[] => {
if (!targetPickerValue) {
return [];
}
const targetSelector = { target: {} };
const targetEntities = new Set(ensureArray(targetPickerValue.entity_id));
const targetDevices = new Set(ensureArray(targetPickerValue.device_id));
const targetAreas = new Set(ensureArray(targetPickerValue.area_id));

View File

@@ -766,7 +766,10 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
}
.content-wrapper.settings-view .fade-bottom {
bottom: var(--ha-space-18);
bottom: calc(
var(--ha-space-14) +
max(var(--safe-area-inset-bottom), var(--ha-space-4))
);
}
.child-view {

View File

@@ -50,7 +50,7 @@ export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
/**
* Safe area padding in pixels for the scrollable element.
*/
protected scrollFadeSafeAreaPadding = 16;
protected scrollFadeSafeAreaPadding = 4;
/**
* Scroll threshold in pixels for showing the fades.
@@ -73,6 +73,9 @@ export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated?.(changedProperties);
if (this.scrollableElement) {
this._updateScrollableState(this.scrollableElement);
}
this._attachScrollableElement();
}
@@ -83,6 +86,8 @@ export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
disconnectedCallback() {
this._detachScrollableElement();
this._contentScrolled = false;
this._contentScrollable = false;
super.disconnectedCallback();
}
@@ -125,16 +130,16 @@ export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
position: absolute;
left: 0;
right: 0;
height: var(--ha-space-4);
height: var(--ha-space-2);
pointer-events: none;
transition: opacity 180ms ease-in-out;
background: linear-gradient(
to bottom,
var(--shadow-color),
transparent
);
border-radius: var(--ha-border-radius-square);
opacity: 0;
background: linear-gradient(
to bottom,
var(--ha-color-shadow-scrollable-fade),
transparent
);
}
.fade-top {
top: 0;

View File

@@ -50,7 +50,6 @@ import {
import "../../../layouts/hass-tabs-subpage";
import type { HomeAssistant, Route } from "../../../types";
import { showToast } from "../../../util/toast";
import "../ha-config-section";
import { configSections } from "../ha-panel-config";
import {
loadAreaRegistryDetailDialog,

View File

@@ -4,7 +4,6 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { computeDomain } from "../../../../../common/entity/compute_domain";
import "../../../../../components/ha-checkbox";
import "../../../../../components/ha-selector/ha-selector";
import "../../../../../components/ha-settings-row";
@@ -269,8 +268,11 @@ export class HaPlatformCondition extends LitElement {
return undefined;
}
const context = {};
const context: Record<string, any> = {};
for (const [context_key, data_key] of Object.entries(field.context)) {
if (data_key === "target" && this.description?.target) {
context.target_selector = this._targetSelector(this.description.target);
}
context[context_key] =
data_key === "target"
? this.condition.target
@@ -378,7 +380,7 @@ export class HaPlatformCondition extends LitElement {
return "";
}
return this.hass.localize(
`component.${computeDomain(this.condition.condition)}.selector.${key}`
`component.${getConditionDomain(this.condition.condition)}.selector.${key}`
);
};

View File

@@ -82,7 +82,6 @@ import type { Entries, HomeAssistant, Route } from "../../../types";
import { isMac } from "../../../util/is_mac";
import { showToast } from "../../../util/toast";
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
import "../ha-config-section";
import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-automation-mode";
import {
type EntityRegistryUpdate,

View File

@@ -1,10 +1,16 @@
import { consume } from "@lit/context";
import { mdiAlert, mdiFormatListBulleted, mdiShape } from "@mdi/js";
import {
mdiAlert,
mdiCodeBraces,
mdiFormatListBulleted,
mdiShape,
} from "@mdi/js";
import type { HassServiceTarget } from "home-assistant-js-websocket";
import { css, html, LitElement, type nothing, type TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ensureArray } from "../../../../common/array/ensure-array";
import { transform } from "../../../../common/decorators/transform";
import { isTemplate } from "../../../../common/string/has-template";
import "../../../../components/ha-svg-icon";
import type { ConfigEntry } from "../../../../data/config_entries";
import {
@@ -167,6 +173,16 @@ export class HaAutomationRowTargets extends LitElement {
);
}
// Check if the target is a template
if (isTemplate(targetId)) {
return this._renderTargetBadge(
html`<ha-svg-icon .path=${mdiCodeBraces}></ha-svg-icon>`,
this.localize(
"ui.panel.config.automation.editor.target_summary.template"
)
);
}
const exists = this._checkTargetExists(targetType, targetId);
if (!exists) {
return this._renderTargetBadge(

View File

@@ -4,7 +4,6 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { computeDomain } from "../../../../../common/entity/compute_domain";
import "../../../../../components/ha-checkbox";
import "../../../../../components/ha-selector/ha-selector";
import "../../../../../components/ha-settings-row";
@@ -305,8 +304,11 @@ export class HaPlatformTrigger extends LitElement {
return undefined;
}
const context = {};
const context: Record<string, any> = {};
for (const [context_key, data_key] of Object.entries(field.context)) {
if (data_key === "target" && this.description?.target) {
context.target_selector = this._targetSelector(this.description.target);
}
context[context_key] =
data_key === "target"
? this.trigger.target
@@ -414,7 +416,7 @@ export class HaPlatformTrigger extends LitElement {
return "";
}
return this.hass.localize(
`component.${computeDomain(this.trigger.trigger)}.selector.${key}`
`component.${getTriggerDomain(this.trigger.trigger)}.selector.${key}`
);
};

View File

@@ -26,7 +26,6 @@ import {
mdiScrewdriver,
mdiScriptText,
mdiShape,
mdiLan,
mdiSofa,
mdiTools,
mdiUpdate,
@@ -126,7 +125,8 @@ export const configSections: Record<string, PageNavigation[]> = {
{
path: "/knx",
name: "KNX",
iconPath: mdiLan,
iconPath:
"M 3.9861338,14.261456 3.7267552,13.934877 6.3179131,11.306266 H 4.466374 l -2.6385205,2.68258 V 11.312882 H 0.00440574 L 0,17.679803 l 1.8278535,5.43e-4 v -1.818482 l 0.7225444,-0.732459 2.1373588,2.543782 2.1869324,-5.44e-4 M 24,17.680369 21.809238,17.669359 19.885559,15.375598 17.640262,17.68037 h -1.828407 l 3.236048,-3.302138 -2.574075,-3.067547 2.135161,0.0016 1.610309,1.87687 1.866403,-1.87687 h 1.828429 l -2.857742,2.87478 m -10.589867,-2.924898 2.829625,3.990552 -0.01489,-3.977887 1.811889,-0.0044 0.0011,6.357564 -2.093314,-5.44e-4 -2.922133,-3.947594 -0.0314,3.947594 H 8.2581097 V 11.261677 M 11.971203,6.3517488 c 0,0 2.800714,-0.093203 6.172001,1.0812045 3.462393,1.0898845 5.770926,3.4695627 5.770926,3.4695627 l -1.823898,-5.43e-4 C 22.088532,10.900273 20.577938,9.4271528 17.660223,8.5024618 15.139256,7.703366 12.723057,7.645835 12.111178,7.6449876 l -9.71e-4,0.0011 c 0,0 -0.0259,-6.4e-4 -0.07527,-9.714e-4 -0.04726,3.33e-4 -0.07201,9.714e-4 -0.07201,9.714e-4 v -0.00113 C 11.337007,7.6453728 8.8132091,7.7001736 6.2821829,8.5024618 3.3627914,9.4276738 1.8521646,10.901973 1.8521646,10.901973 l -1.82398708,5.43e-4 C 0.03128403,10.899322 2.339143,8.5221038 5.799224,7.4329533 9.170444,6.2585642 11.971203,6.3517488 11.971203,6.3517488 Z",
iconColor: "#4EAA66",
component: "knx",
translationKey: "knx",
@@ -135,10 +135,7 @@ export const configSections: Record<string, PageNavigation[]> = {
path: "/config/thread",
name: "Thread",
iconPath:
"M82.498,0C37.008,0,0,37.008,0,82.496c0,45.181,36.51,81.977,81.573,82.476V82.569l-27.002-0.002 c-8.023,0-14.554,6.53-14.554,14.561c0,8.023,6.531,14.551,14.554,14.551v17.98c-17.939,0-32.534-14.595-32.534-32.531 c0-17.944,14.595-32.543,32.534-32.543l27.002,0.004v-9.096c0-14.932,12.146-27.08,27.075-27.08 c14.932,0,27.082,12.148,27.082,27.08c0,14.931-12.15,27.08-27.082,27.08l-9.097-0.001v80.641 C136.889,155.333,165,122.14,165,82.496C165,37.008,127.99,0,82.498,0z",
iconSecondaryPath:
"M117.748 55.493C117.748 50.477 113.666 46.395 108.648 46.395C103.633 46.395 99.551 50.477 99.551 55.493V64.59L108.648 64.591C113.666 64.591 117.748 60.51 117.748 55.493Z",
iconViewBox: "0 0 165 165",
"m 17.126982,8.0730792 c 0,-0.7297242 -0.593746,-1.32357 -1.323637,-1.32357 -0.729454,0 -1.323199,0.5938458 -1.323199,1.32357 v 1.3234242 l 1.323199,1.458e-4 c 0.729891,0 1.323637,-0.5937006 1.323637,-1.32357 z M 11.999709,0 C 5.3829818,0 0,5.3838955 0,12.001455 0,18.574352 5.3105455,23.927406 11.865164,24 V 12.012075 l -3.9275642,-2.91e-4 c -1.1669814,0 -2.1169453,0.949979 -2.1169453,2.118323 0,1.16718 0.9499639,2.116868 2.1169453,2.116868 v 2.615717 c -2.6093089,0 -4.732218,-2.12327 -4.732218,-4.732585 0,-2.61048 2.1229091,-4.7343308 4.732218,-4.7343308 l 3.9275642,5.82e-4 v -1.323279 c 0,-2.172296 1.766691,-3.9395777 3.938181,-3.9395777 2.171928,0 3.9392,1.7672817 3.9392,3.9395777 0,2.1721498 -1.767272,3.9395768 -3.9392,3.9395768 l -1.323199,-1.45e-4 V 23.744102 C 19.911127,22.597726 24,17.768833 24,12.001455 24,5.3838955 18.616727,0 11.999709,0 Z",
iconColor: "#ED7744",
component: "thread",
translationKey: "thread",
@@ -155,8 +152,7 @@ export const configSections: Record<string, PageNavigation[]> = {
path: "/insteon",
name: "Insteon",
iconPath:
"M82.5108 43.8917H82.7152C107.824 43.8917 129.241 28.1166 137.629 5.95738L105.802 0L82.5108 43.8917ZM82.5108 43.8917H82.3065C57.1975 43.8917 35.7811 28.1352 27.3928 5.95738H27.3742L59.2015 0L82.5108 43.8917ZM43.8903 82.4951V82.2908C43.8903 57.1805 28.1158 35.7636 5.95718 27.3751L0 59.2037L43.8903 82.4951ZM43.8903 82.4951V82.6989C43.8903 107.809 28.1343 129.226 5.95718 137.615V137.633L0 105.805L43.8903 82.4951ZM165 59.2037L159.043 27.3751V27.3936C136.865 35.7822 121.11 57.1991 121.11 82.3094V82.5133V82.7176V82.7363C121.11 107.846 136.884 129.263 159.043 137.652L165 105.823L121.11 82.5133L165 59.2037ZM137.628 159.043L105.8 165L82.4912 121.108H82.695C107.804 121.108 129.221 136.865 137.609 159.043H137.628ZM82.4912 121.108L59.1818 165L27.3545 159.043C35.7428 136.884 57.1592 121.108 82.2682 121.108H82.2868H82.4912Z",
iconViewBox: "0 0 165 165",
"m 12.001571,6.3842473 h 0.02973 c 3.652189,0 6.767389,-2.29456 7.987462,-5.5177193 L 15.389382,0 Z m 0,0 h -0.02972 c -3.6522186,0 -6.7673314,-2.2918546 -7.9874477,-5.5177193 h -0.00271 L 8.6111273,0 Z M 6.3840436,11.999287 v -0.02972 c 0,-3.6524074 -2.2944727,-6.7675928 -5.51754469,-7.9877383 L 0,8.6114473 Z m 0,0 v 0.02964 c 0,3.652378 -2.2917818,6.767578 -5.51754469,7.987796 v 0.0026 L 0,15.389818 Z M 24,8.6114473 23.133527,3.9818327 v 0.00269 C 19.907636,5.2046836 17.616,8.3198691 17.616,11.972276 v 0.02966 0.02972 0.0027 c 0,3.65232 2.2944,6.76752 5.517527,7.987738 L 24,15.392436 17.616,12.001935 Z M 20.018618,23.133527 15.389091,24 11.99872,17.615709 h 0.02964 c 3.652218,0 6.767418,2.291927 7.987491,5.517818 z M 11.99872,17.615709 8.6082618,24 3.9788364,23.133527 C 5.1989527,19.9104 8.3140655,17.615709 11.966284,17.615709 h 0.0027 z",
iconColor: "#E4002C",
component: "insteon",
translationKey: "insteon",

View File

@@ -1,21 +1,14 @@
import { mdiCogOutline } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../../../components/ha-card";
import "../../../../../components/ha-code-editor";
import "../../../../../components/ha-formfield";
import "../../../../../components/ha-switch";
import "../../../../../components/ha-alert";
import "../../../../../components/ha-button";
import { getConfigEntries } from "../../../../../data/config_entries";
import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-options-flow";
import "../../../../../layouts/hass-subpage";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
import {
subscribeBluetoothConnectionAllocations,
subscribeBluetoothScannerState,
subscribeBluetoothScannersDetails,
} from "../../../../../data/bluetooth";
import "../../../../../components/ha-card";
import "../../../../../components/ha-icon-button";
import "../../../../../components/ha-list";
import "../../../../../components/ha-list-item";
import type {
BluetoothAllocationsData,
BluetoothScannerState,
@@ -23,10 +16,17 @@ import type {
HaScannerType,
} from "../../../../../data/bluetooth";
import {
getValueInPercentage,
roundWithOneDecimal,
} from "../../../../../util/calculate";
import "../../../../../components/ha-metric";
subscribeBluetoothConnectionAllocations,
subscribeBluetoothScannerState,
subscribeBluetoothScannersDetails,
} from "../../../../../data/bluetooth";
import type { ConfigEntry } from "../../../../../data/config_entries";
import { getConfigEntries } from "../../../../../data/config_entries";
import type { DeviceRegistryEntry } from "../../../../../data/device/device_registry";
import { showOptionsFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-options-flow";
import "../../../../../layouts/hass-subpage";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
@customElement("bluetooth-config-dashboard")
export class BluetoothConfigDashboard extends LitElement {
@@ -34,18 +34,14 @@ export class BluetoothConfigDashboard extends LitElement {
@property({ type: Boolean }) public narrow = false;
@state() private _configEntries: ConfigEntry[] = [];
@state() private _connectionAllocationData: BluetoothAllocationsData[] = [];
@state() private _connectionAllocationsError?: string;
@state() private _scannerState?: BluetoothScannerState;
@state() private _scannerStates: Record<string, BluetoothScannerState> = {};
@state() private _scannerDetails?: BluetoothScannersDetails;
private _configEntry = new URLSearchParams(window.location.search).get(
"config_entry"
);
private _unsubConnectionAllocations?: (() => Promise<void>) | undefined;
private _unsubScannerState?: (() => Promise<void>) | undefined;
@@ -55,41 +51,44 @@ export class BluetoothConfigDashboard extends LitElement {
public connectedCallback(): void {
super.connectedCallback();
if (this.hass) {
this._loadConfigEntries();
this._subscribeBluetoothConnectionAllocations();
this._subscribeBluetoothScannerState();
this._subscribeScannerDetails();
}
}
private async _loadConfigEntries(): Promise<void> {
this._configEntries = await getConfigEntries(this.hass, {
domain: "bluetooth",
});
}
private async _subscribeBluetoothConnectionAllocations(): Promise<void> {
if (this._unsubConnectionAllocations || !this._configEntry) {
if (this._unsubConnectionAllocations) {
return;
}
try {
this._unsubConnectionAllocations =
await subscribeBluetoothConnectionAllocations(
this.hass.connection,
(data) => {
this._connectionAllocationData = data;
},
this._configEntry
);
} catch (err: any) {
this._unsubConnectionAllocations = undefined;
this._connectionAllocationsError = err.message;
}
this._unsubConnectionAllocations =
await subscribeBluetoothConnectionAllocations(
this.hass.connection,
(data) => {
this._connectionAllocationData = data;
}
);
}
private async _subscribeBluetoothScannerState(): Promise<void> {
if (this._unsubScannerState || !this._configEntry) {
if (this._unsubScannerState) {
return;
}
this._unsubScannerState = await subscribeBluetoothScannerState(
this.hass.connection,
(scannerState) => {
this._scannerState = scannerState;
},
this._configEntry
this._scannerStates = {
...this._scannerStates,
[scannerState.source]: scannerState,
};
}
);
}
@@ -122,31 +121,19 @@ export class BluetoothConfigDashboard extends LitElement {
}
protected render(): TemplateResult {
// Get scanner type to determine if options button should be shown
const scannerDetails =
this._scannerState && this._scannerDetails?.[this._scannerState.source];
const scannerType: HaScannerType =
scannerDetails?.scanner_type ?? "unknown";
const isRemoteScanner = scannerType === "remote";
return html`
<hass-subpage .narrow=${this.narrow} .hass=${this.hass}>
<hass-subpage
header=${this.hass.localize("ui.panel.config.bluetooth.title")}
.narrow=${this.narrow}
.hass=${this.hass}
>
<div class="content">
<ha-card
.header=${this.hass.localize(
"ui.panel.config.bluetooth.settings_title"
)}
>
<div class="card-content">${this._renderScannerState()}</div>
${!isRemoteScanner
? html`<div class="card-actions">
<ha-button @click=${this._openOptionFlow}
>${this.hass.localize(
"ui.panel.config.bluetooth.option_flow"
)}</ha-button
>
</div>`
: nothing}
<ha-list>${this._renderAdaptersList()}</ha-list>
</ha-card>
<ha-card
.header=${this.hass.localize(
@@ -183,7 +170,11 @@ export class BluetoothConfigDashboard extends LitElement {
)}
>
<div class="card-content">
${this._renderConnectionAllocations()}
<p>
${this.hass.localize(
"ui.panel.config.bluetooth.connection_slot_allocations_monitor_description"
)}
</p>
</div>
<div class="card-actions">
<ha-button
@@ -201,13 +192,90 @@ export class BluetoothConfigDashboard extends LitElement {
`;
}
private _getUsedAllocations = (used: number, total: number) =>
roundWithOneDecimal(getValueInPercentage(used, 0, total));
private _renderAdaptersList() {
if (this._configEntries.length === 0) {
return html`<ha-list-item noninteractive>
${this.hass.localize(
"ui.panel.config.bluetooth.no_scanner_state_available"
)}
</ha-list-item>`;
}
// Build source to device mapping (same as visualization)
const sourceDevices: Record<string, DeviceRegistryEntry> = {};
Object.values(this.hass.devices).forEach((device) => {
const btConnection = device.connections.find(
(connection) => connection[0] === "bluetooth"
);
if (btConnection) {
sourceDevices[btConnection[1]] = device;
}
});
return this._configEntries.map((entry) => {
// Find scanner by matching device's config_entries to this entry
const scannerDetails = this._scannerDetails
? Object.values(this._scannerDetails).find((d) => {
const device = sourceDevices[d.source];
return device?.config_entries.includes(entry.entry_id);
})
: undefined;
const scannerState = scannerDetails
? this._scannerStates[scannerDetails.source]
: undefined;
const scannerType: HaScannerType =
scannerDetails?.scanner_type ?? "unknown";
const isRemoteScanner = scannerType === "remote";
const hasMismatch =
scannerState &&
scannerState.current_mode !== scannerState.requested_mode;
// Find allocation data for this scanner
const allocations = scannerDetails
? this._connectionAllocationData.find(
(a) => a.source === scannerDetails.source
)
: undefined;
const secondaryText = this._formatScannerModeText(scannerState);
return html`
<ha-list-item twoline hasMeta noninteractive>
<span>${entry.title}</span>
<span slot="secondary">
${secondaryText}${allocations
? allocations.slots > 0
? ` · ${allocations.slots - allocations.free}/${allocations.slots} ${this.hass.localize("ui.panel.config.bluetooth.active_connections")}`
: ` · ${this.hass.localize("ui.panel.config.bluetooth.no_connection_slots")}`
: nothing}
</span>
${!isRemoteScanner
? html`<ha-icon-button
slot="meta"
.path=${mdiCogOutline}
.entry=${entry}
@click=${this._openOptionFlow}
.label=${this.hass.localize(
"ui.panel.config.bluetooth.option_flow"
)}
></ha-icon-button>`
: nothing}
</ha-list-item>
${hasMismatch && scannerDetails
? this._renderScannerMismatchWarning(
entry.title,
scannerState,
scannerType
)
: nothing}
`;
});
}
private _renderScannerMismatchWarning(
name: string,
scannerState: BluetoothScannerState,
scannerType: HaScannerType,
formatMode: (mode: string | null) => string
scannerType: HaScannerType
) {
const instructions: string[] = [];
@@ -238,8 +306,9 @@ export class BluetoothConfigDashboard extends LitElement {
${this.hass.localize(
"ui.panel.config.bluetooth.scanner_mode_mismatch",
{
requested: formatMode(scannerState.requested_mode),
current: formatMode(scannerState.current_mode),
name: name,
requested: this._formatMode(scannerState.requested_mode),
current: this._formatMode(scannerState.current_mode),
}
)}
</div>
@@ -249,127 +318,59 @@ export class BluetoothConfigDashboard extends LitElement {
</ha-alert>`;
}
private _renderScannerState() {
if (!this._configEntry || !this._scannerState) {
return html`<div>
${this.hass.localize(
"ui.panel.config.bluetooth.no_scanner_state_available"
)}
</div>`;
private _formatMode(mode: string | null): string {
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;
}
const scannerState = this._scannerState;
// Find the scanner details for this source
const scannerDetails = this._scannerDetails?.[scannerState.source];
const scannerType: HaScannerType =
scannerDetails?.scanner_type ?? "unknown";
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
? this._renderScannerMismatchWarning(
scannerState,
scannerType,
formatMode
)
: nothing}
</div>
`;
}
private _renderConnectionAllocations() {
if (this._connectionAllocationsError) {
return html`<ha-alert alert-type="error"
>${this._connectionAllocationsError}</ha-alert
>`;
private _formatModeLabel(mode: string | null): string {
switch (mode) {
case null:
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_none_label"
);
case "active":
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_active_label"
);
case "passive":
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_passive_label"
);
default:
return mode;
}
if (this._connectionAllocationData.length === 0) {
return html`<div>
${this.hass.localize(
"ui.panel.config.bluetooth.no_connection_slot_allocations"
)}
</div>`;
}
const allocations = this._connectionAllocationData[0];
const allocationsUsed = allocations.slots - allocations.free;
const allocationsTotal = allocations.slots;
if (allocationsTotal === 0) {
return html`<div>
${this.hass.localize(
"ui.panel.config.bluetooth.no_active_connection_support"
)}
</div>`;
}
return html`
<p>
${this.hass.localize(
"ui.panel.config.bluetooth.connection_slot_allocations_monitor_details",
{ slots: allocationsTotal }
)}
</p>
<ha-metric
.heading=${this.hass.localize(
"ui.panel.config.bluetooth.used_connection_slot_allocations"
)}
.value=${this._getUsedAllocations(allocationsUsed, allocationsTotal)}
.tooltip=${allocations.allocated.length > 0
? `${allocationsUsed}/${allocationsTotal} (${allocations.allocated.join(", ")})`
: `${allocationsUsed}/${allocationsTotal}`}
></ha-metric>
`;
}
private async _openOptionFlow() {
const configEntryId = this._configEntry;
if (!configEntryId) {
return;
private _formatScannerModeText(
scannerState: BluetoothScannerState | undefined
): string {
if (!scannerState) {
return this.hass.localize(
"ui.panel.config.bluetooth.scanner_state_unknown"
);
}
const configEntries = await getConfigEntries(this.hass, {
domain: "bluetooth",
});
const configEntry = configEntries.find(
(entry) => entry.entry_id === configEntryId
);
showOptionsFlowDialog(this, configEntry!);
return this._formatModeLabel(scannerState.current_mode);
}
private _openOptionFlow(ev: Event) {
const button = ev.currentTarget as HTMLElement & { entry: ConfigEntry };
showOptionsFlowDialog(this, button.entry);
}
static get styles(): CSSResultGroup {
@@ -394,17 +395,9 @@ 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;
ha-list-item {
--mdc-list-item-meta-display: flex;
--mdc-list-item-meta-size: 48px;
}
`,
];

View File

@@ -302,10 +302,11 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
</div>
${this._updateFinishedMessage!.success
? html`<p>
${this.hass.localize(
`ui.panel.config.zwave_js.update_firmware.finished_status.done${localizationKeySuffix}`
)}
</p>`
${this.hass.localize(
`ui.panel.config.zwave_js.update_firmware.finished_status.done${localizationKeySuffix}`
)}
</p>
${closeButton}`
: html`<p>
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.finished_status.try_again"

View File

@@ -372,7 +372,7 @@ export class HaConfigLogs extends LitElement {
@media all and (max-width: 870px) {
ha-generic-picker {
max-width: 50%;
max-width: max(30%, 160px);
}
ha-button {
max-width: 100%;

View File

@@ -30,35 +30,33 @@ import {
import { formatTime } from "../../../../../common/datetime/format_time";
import type { ECOption } from "../../../../../resources/echarts/echarts";
import { filterXSS } from "../../../../../common/util/xss";
import type { StatisticPeriod } from "../../../../../data/recorder";
export function getSuggestedMax(
dayDifference: number,
end: Date,
detailedDailyData = false
): number {
export function getSuggestedMax(period: StatisticPeriod, end: Date): number {
let suggestedMax = new Date(end);
if (period === "5minute") {
return suggestedMax.getTime();
}
suggestedMax.setMinutes(0, 0, 0);
if (period === "hour") {
return suggestedMax.getTime();
}
// Sometimes around DST we get a time of 0:59 instead of 23:59 as expected.
// Correct for this when showing days/months so we don't get an extra day.
if (dayDifference > 2 && suggestedMax.getHours() === 0) {
if (suggestedMax.getHours() === 0) {
suggestedMax = subHours(suggestedMax, 1);
}
if (!detailedDailyData) {
suggestedMax.setMinutes(0, 0, 0);
}
if (dayDifference > 35) {
suggestedMax.setDate(1);
}
if (dayDifference > 2) {
suggestedMax.setHours(0);
suggestedMax.setHours(0);
if (period === "day" || period === "week") {
return suggestedMax.getTime();
}
// period === month
suggestedMax.setDate(1);
return suggestedMax.getTime();
}
export function getSuggestedPeriod(
dayDifference: number
): "month" | "day" | "hour" {
export function getSuggestedPeriod(dayDifference: number): StatisticPeriod {
return dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour";
}
@@ -96,7 +94,10 @@ export function getCommonOptions(
xAxis: {
type: "time",
min: start,
max: getSuggestedMax(dayDifference, end, detailedDailyData),
max: getSuggestedMax(
detailedDailyData ? "5minute" : getSuggestedPeriod(dayDifference),
end
),
},
yAxis: {
type: "value",

View File

@@ -186,7 +186,7 @@ export class HuiEnergyDevicesGraphCard
params.value[0] as number,
this.hass.locale,
params.value < 0.1 ? { maximumFractionDigits: 3 } : undefined
)} kWh ${params.percent ? `(${params.percent} %)` : ""}`;
)} kWh`;
return `${title}${params.marker} ${params.seriesName}: <div style="direction:ltr; display: inline;">${value}</div>`;
}

View File

@@ -334,10 +334,7 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard {
.maxYAxis=${this._config.max_y_axis}
.startTime=${this._energyStart}
.endTime=${this._energyEnd && this._energyStart
? getSuggestedMax(
differenceInDays(this._energyEnd, this._energyStart),
this._energyEnd
)
? getSuggestedMax(this._period!, this._energyEnd)
: undefined}
.fitYData=${this._config.fit_y_data || false}
.hideLegend=${this._config.hide_legend || false}

View File

@@ -7,6 +7,11 @@ const calcPoints = (
height: number,
limits?: { minX?: number; maxX?: number; minY?: number; maxY?: number }
) => {
// handling empty history (for example unavailable for long time)
if (history.length === 0) {
return { points: [], yAxisOrigin: height };
}
let yAxisOrigin = height;
let minY = limits?.minY ?? history[0][1];
let maxY = limits?.maxY ?? history[0][1];

View File

@@ -28,16 +28,11 @@ import type { HomeAssistant, ValueChangedEvent } from "../../../../types";
import { DEFAULT_HOURS_TO_SHOW, DEFAULT_ZOOM } from "../../cards/hui-map-card";
import type { MapCardConfig, MapEntityConfig } from "../../cards/types";
import "../../components/hui-entity-editor";
import "../hui-sub-element-editor";
import type {
EditDetailElementEvent,
SubElementEditorConfig,
EntitiesEditorEvent,
} from "../types";
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
import type { EntityConfig } from "../../entity-rows/types";
import type { LovelaceCardEditor } from "../../types";
import { processEditorEntities } from "../process-editor-entities";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import type { EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
export const mapEntitiesConfigStruct = union([
@@ -81,20 +76,13 @@ const cardConfigStruct = assign(
const themeModes = ["auto", "light", "dark"] as const;
const SUB_SCHEMA = [
{ name: "entity", selector: { entity: {} }, required: true },
{ name: "name", selector: { text: {} } },
] as const;
@customElement("hui-map-card-editor")
export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
@property({ attribute: false }) public hass?: HomeAssistant;
@state() private _config?: MapCardConfig;
@state() private _subElementEditorConfig?: SubElementEditorConfig;
@state() private _configEntities?: MapEntityConfig[];
@state() private _configEntities?: EntityConfig[];
@state() private _possibleGeoSources?: { value: string; label?: string }[];
@@ -162,7 +150,7 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
this._config = config;
this._configEntities = config.entities
? (processEditorEntities(config.entities) as MapEntityConfig[])
? processEditorEntities(config.entities)
: [];
}
@@ -179,19 +167,6 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
return nothing;
}
if (this._subElementEditorConfig) {
return html`
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.schema=${SUB_SCHEMA}
@go-back=${this._goBack}
@config-changed=${this._handleSubEntityChanged}
>
</hui-sub-element-editor>
`;
}
return html`
<ha-form
.hass=${this.hass}
@@ -205,9 +180,7 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
.hass=${this.hass}
.entities=${this._configEntities}
.entityFilter=${hasLocation}
can-edit
@entities-changed=${this._entitiesValueChanged}
@edit-detail-element=${this._editDetailElement}
></hui-entity-editor>
<h3>
@@ -230,36 +203,6 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
`;
}
private _goBack(): void {
this._subElementEditorConfig = undefined;
}
private _editDetailElement(ev: HASSDomEvent<EditDetailElementEvent>): void {
this._subElementEditorConfig = ev.detail.subElementConfig;
}
private _handleSubEntityChanged(ev: CustomEvent): void {
ev.stopPropagation();
const index = this._subElementEditorConfig!.index!;
const newEntities = this._configEntities!.concat();
const newConfig = ev.detail.config as MapEntityConfig;
this._subElementEditorConfig = {
...this._subElementEditorConfig!,
elementConfig: newConfig,
};
newEntities[index] = newConfig;
let config = this._config!;
config = { ...config, entities: newEntities };
this._config = config;
this._configEntities = processEditorEntities(
config.entities as any[]
) as MapEntityConfig[];
fireEvent(this, "config-changed", { config });
}
private _selectSchema = memoizeOne(
(options, localize: LocalizeFunc): SelectSelector => ({
select: {
@@ -286,9 +229,7 @@ export class HuiMapCardEditor extends LitElement implements LovelaceCardEditor {
if (ev.detail && ev.detail.entities) {
this._config = { ...this._config!, entities: ev.detail.entities };
this._configEntities = processEditorEntities(
this._config.entities || []
) as MapEntityConfig[];
this._configEntities = processEditorEntities(this._config.entities || []);
fireEvent(this, "config-changed", { config: this._config! });
}
}

View File

@@ -1,7 +1,6 @@
import type { ActionDetail } from "@material/mwc-list";
import {
mdiAlphaABoxOutline,
mdiArrowLeft,
mdiDotsVertical,
mdiGrid,
mdiListBoxOutline,
@@ -97,7 +96,6 @@ class PanelMediaBrowser extends LitElement {
? html`
<ha-icon-button-arrow-prev
slot="navigationIcon"
.path=${mdiArrowLeft}
@click=${this._goBack}
></ha-icon-button-arrow-prev>
`

View File

@@ -156,6 +156,9 @@ export const semanticColorStyles = css`
/* Surfaces */
--ha-color-surface-default: var(--ha-color-neutral-95);
--ha-color-on-surface-default: var(--ha-color-neutral-05);
/* Scrollable fade */
--ha-color-shadow-scrollable-fade: rgba(0, 0, 0, 0.08);
}
`;

View File

@@ -672,8 +672,8 @@
"device_missing": "No related device"
},
"add": "Add",
"custom_name": "Custom name",
"no_match": "No entities found"
"search": "Search or enter custom name",
"custom_name": "Custom name"
},
"entity-attribute-picker": {
"attribute": "Attribute",
@@ -685,7 +685,7 @@
},
"entity-state-content-picker": {
"add": "Add",
"custom_state": "Custom state"
"custom_attribute": "Custom attribute"
}
},
"target-picker": {
@@ -772,9 +772,6 @@
"no_match": "No languages found for {term}",
"no_languages": "No languages available"
},
"icon-picker": {
"no_match": "No matching icons found"
},
"tts-picker": {
"tts": "Text-to-speech",
"none": "None"
@@ -4119,7 +4116,8 @@
"targets": "{count} {count, plural,\n one {target}\n other {targets}\n}",
"invalid": "Invalid target",
"all_entities": "All entities",
"none_entities": "No entities"
"none_entities": "No entities",
"template": "Template"
},
"triggers": {
"name": "Triggers",
@@ -6013,26 +6011,31 @@
},
"bluetooth": {
"title": "Bluetooth",
"settings_title": "Bluetooth settings",
"settings_title": "Bluetooth adapters",
"option_flow": "Configure Bluetooth options",
"advertisement_monitor": "Advertisement monitor",
"advertisement_monitor_details": "The advertisement monitor listens for Bluetooth advertisements and displays the data in a structured format.",
"connection_slot_allocations_monitor": "Connection slot allocations monitor",
"connection_slot_allocations_monitor_details": "The connection slot allocations monitor displays the (GATT) connection slot allocations for the adapter. This adapter supports up to {slots} simultaneous connections. Each remote Bluetooth device that requires an active connection will use one connection slot while the Bluetooth device is connecting or connected.",
"connection_slot_allocations_monitor_description": "The connection slot allocations monitor displays the (GATT) connection slot allocations for each adapter. Each remote Bluetooth device that requires an active connection will use one connection slot while the Bluetooth device is connecting or connected.",
"connection_monitor": "Connection monitor",
"visualization": "Visualization",
"used_connection_slot_allocations": "Used connection slot allocations",
"no_connections": "No active connections",
"active_connections": "connections",
"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_connection_slots": "No connection slots",
"no_scanner_state_available": "No scanner state available",
"scanner_state_unknown": "State unknown",
"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.",
"scanning_mode_active_label": "Active scanning",
"scanning_mode_passive_label": "Passive scanning",
"scanning_mode_none_label": "No scanning",
"scanner_mode_mismatch": "{name} 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_remote": "For proxies: reboot the device",
"scanner_mode_mismatch_usb": "For USB adapters: unplug and plug back in",
"scanner_mode_mismatch_uart": "For UART/onboard adapters: power down the system completely and power it back up",

605
yarn.lock
View File

@@ -1282,15 +1282,15 @@ __metadata:
languageName: node
linkType: hard
"@codemirror/view@npm:6.39.8, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
version: 6.39.8
resolution: "@codemirror/view@npm:6.39.8"
"@codemirror/view@npm:6.39.7, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
version: 6.39.7
resolution: "@codemirror/view@npm:6.39.7"
dependencies:
"@codemirror/state": "npm:^6.5.0"
crelt: "npm:^1.0.6"
style-mod: "npm:^4.1.0"
w3c-keyname: "npm:^2.2.4"
checksum: 10/a15941940fabc9b595da00a7760947cf7ce83f3f819be31250a73d2a1de5d1b5528a5803aa19c74656d2d7cbc39f47daec4962190ffc0849f4f359e45b4f1c3a
checksum: 10/46057d484ece18e01a5d6423063a151b7ac646bf122f19cba8ddc4cdff6e99b1ac5d7fe923ffe829e3c34b669382251c0a130cdbcb8e681edebbe920e9ee11d5
languageName: node
linkType: hard
@@ -1670,18 +1670,6 @@ __metadata:
languageName: node
linkType: hard
"@exodus/bytes@npm:^1.6.0":
version: 1.6.0
resolution: "@exodus/bytes@npm:1.6.0"
peerDependencies:
"@exodus/crypto": ^1.0.0-rc.4
peerDependenciesMeta:
"@exodus/crypto":
optional: true
checksum: 10/4066bc5f2b7782fabdad4cac707031cbe7c3491bcd38f28e3b5144d687f858e834aaa9b0bcbe9685f1ccfaf4dc747172e82f28cf361e9623448ec80ab755b198
languageName: node
linkType: hard
"@floating-ui/core@npm:^1.7.3":
version: 1.7.3
resolution: "@floating-ui/core@npm:1.7.3"
@@ -1708,166 +1696,166 @@ __metadata:
languageName: node
linkType: hard
"@formatjs/ecma402-abstract@npm:3.0.7":
version: 3.0.7
resolution: "@formatjs/ecma402-abstract@npm:3.0.7"
"@formatjs/ecma402-abstract@npm:3.0.6":
version: 3.0.6
resolution: "@formatjs/ecma402-abstract@npm:3.0.6"
dependencies:
"@formatjs/fast-memoize": "npm:3.0.2"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/fast-memoize": "npm:3.0.1"
"@formatjs/intl-localematcher": "npm:0.7.3"
decimal.js: "npm:^10.4.3"
tslib: "npm:^2.8.0"
checksum: 10/a79f43d3c3e5301722d3288806e6910d8598e2f0c849775398f6e20bac78b568db9c03b6605c9db8eb3aa80dff4fc260cb153e67b167924a547e0d29a1b2d8c3
checksum: 10/d1747a4a1f1b3b749727f226c94f9f698e1761a9c486fe9091ada3010886a85410a5230772bc19cd468fc8af55809e90d2cbb3e045460d3488ae5d9bc391e5a5
languageName: node
linkType: hard
"@formatjs/fast-memoize@npm:3.0.2":
version: 3.0.2
resolution: "@formatjs/fast-memoize@npm:3.0.2"
"@formatjs/fast-memoize@npm:3.0.1":
version: 3.0.1
resolution: "@formatjs/fast-memoize@npm:3.0.1"
dependencies:
tslib: "npm:^2.8.0"
checksum: 10/381afd816ca67d7e3e333247f1115ede11420226d72f109c54e8300741212b9bb08a6bacec17d0f0f2172789e39d0cef61fcae0a484e1dff2e9c33eee930694e
checksum: 10/9c152fbb3725a0ba759f75658107504b33cd7d232380cdce5afeea320be3c71762de0af9b1dc3b8f03c652c6db9b7453ad57ab1e82762dd9a1713990988f84b8
languageName: node
linkType: hard
"@formatjs/icu-messageformat-parser@npm:3.2.1":
version: 3.2.1
resolution: "@formatjs/icu-messageformat-parser@npm:3.2.1"
"@formatjs/icu-messageformat-parser@npm:3.2.0":
version: 3.2.0
resolution: "@formatjs/icu-messageformat-parser@npm:3.2.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/icu-skeleton-parser": "npm:2.0.7"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/icu-skeleton-parser": "npm:2.0.6"
tslib: "npm:^2.8.0"
checksum: 10/4e853881ad10472547e893648474841f7943b16c0262c9db7e92fd29d49214da0b5723e48f53872ad3673b3f4a9d11c6683e102f6a864efc78d3a4203a451dff
checksum: 10/0b381dfa74b1a31490b18ec1325155d308d229c3dc1105496c4b0f7e501ea14ff3780a6e437fd47d2b57cd2591a8341823a83c95a4b1c92f0a12cedfafcceeb9
languageName: node
linkType: hard
"@formatjs/icu-skeleton-parser@npm:2.0.7":
version: 2.0.7
resolution: "@formatjs/icu-skeleton-parser@npm:2.0.7"
"@formatjs/icu-skeleton-parser@npm:2.0.6":
version: 2.0.6
resolution: "@formatjs/icu-skeleton-parser@npm:2.0.6"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/ecma402-abstract": "npm:3.0.6"
tslib: "npm:^2.8.0"
checksum: 10/4a496854f877af04f87ac9bcf36593bfe4ec949a58a695c40c87dcbfff4a15473941448d6812644ab6fc832fc96408d6374015de74d3842cb03654f136b783d1
checksum: 10/f1504406691eacfaab95eb88a4360f9dbddb991a919f8f9fe8d7cbf0cae85072c159b7198e159c5eaf8c4797d1e97f1c6a27300bd19f35241b5ee9aa089418af
languageName: node
linkType: hard
"@formatjs/intl-datetimeformat@npm:7.1.1":
version: 7.1.1
resolution: "@formatjs/intl-datetimeformat@npm:7.1.1"
"@formatjs/intl-datetimeformat@npm:7.1.0":
version: 7.1.0
resolution: "@formatjs/intl-datetimeformat@npm:7.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
decimal.js: "npm:^10.4.3"
tslib: "npm:^2.8.0"
checksum: 10/cda6fd9d6244ad11f9ed2d780971388643eba514397417d63de48a8aaac2ccc43ecc2a4331e4458f0ccc16d29516ae1d1addd5b790edbea49432d58ccdf4e10e
checksum: 10/0230f22155dbfdc246bd668135134bc612808d88c46450b7f0a57959f7cb7945f5333051e95f101979411e5658380c511b8047642e7befde7a36efa32a6d5dfa
languageName: node
linkType: hard
"@formatjs/intl-displaynames@npm:7.1.1":
version: 7.1.1
resolution: "@formatjs/intl-displaynames@npm:7.1.1"
"@formatjs/intl-displaynames@npm:7.1.0":
version: 7.1.0
resolution: "@formatjs/intl-displaynames@npm:7.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
tslib: "npm:^2.8.0"
checksum: 10/f7b44c546b26cdd50b60983f5a8cfa672ac5b0a03f9f3c85caac98bc20b6768721e67fde62b977cfa98c3720f9cb1dadfa5448be88a3ee5616f48b1f84b1474f
checksum: 10/6069ab76045c3ae765c888f636ddacf2617effc8826cc33589339b0e512629db66dd24c6f8bf2c3723fa5aa64a9d66b8e82acd0cb3327134e77abf400619c25a
languageName: node
linkType: hard
"@formatjs/intl-durationformat@npm:0.9.1":
version: 0.9.1
resolution: "@formatjs/intl-durationformat@npm:0.9.1"
"@formatjs/intl-durationformat@npm:0.9.0":
version: 0.9.0
resolution: "@formatjs/intl-durationformat@npm:0.9.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
tslib: "npm:^2.8.0"
checksum: 10/b9fae713b39238c4658102b0edbb684e786007e2c95b8135435009b5c7c64c4a5d8cd50b92326f9d2c4e2b1fbbb61f49ee0709daad82dbf90636cd79713596d5
checksum: 10/f656e634d1b33fd9cf810c60187e34655c3c6cfd119dc1c6d00b9fdf46ab9edf550179effd49f5bee908ad7a20943cac463e426fa3bb557ee1a43f8301d12b55
languageName: node
linkType: hard
"@formatjs/intl-enumerator@npm:2.1.1":
version: 2.1.1
resolution: "@formatjs/intl-enumerator@npm:2.1.1"
"@formatjs/intl-enumerator@npm:2.1.0":
version: 2.1.0
resolution: "@formatjs/intl-enumerator@npm:2.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/ecma402-abstract": "npm:3.0.6"
tslib: "npm:^2.8.0"
checksum: 10/cabc2387bead8498c32e3068b98557a3e217777bbccf46ee2eb4918decab15ae750cf20f4b6186deecb3e0242873c0aba40e2294665683dabe1f1f67333b5195
checksum: 10/5a3392d14fd010d2aa400e08870d50a3099dc20e96fb827bb1e9391aec51319a5c6a06ea8ea516c164f1e3a552202b52cd67ec0b61af15eef64f7ca6bf4b965b
languageName: node
linkType: hard
"@formatjs/intl-getcanonicallocales@npm:3.1.1":
version: 3.1.1
resolution: "@formatjs/intl-getcanonicallocales@npm:3.1.1"
"@formatjs/intl-getcanonicallocales@npm:3.1.0":
version: 3.1.0
resolution: "@formatjs/intl-getcanonicallocales@npm:3.1.0"
dependencies:
tslib: "npm:^2.8.0"
checksum: 10/23e6a3c1cf42257f130fd6b1cc080ecaf7b267743e3990ea7eb9f6cc981c649f2c18c935d1f581593ec241095a982c248441ac10d0e871575463dbfebf942f5c
checksum: 10/4a99a8153b12b526a3115b614c8d7c0126c161d48dabb1a4938dd03c2aafb36db056a9ea5c2e160ee5449bce0a11b1e50a86bd5f548f93c73377c6b184b8bc4d
languageName: node
linkType: hard
"@formatjs/intl-listformat@npm:8.1.1":
version: 8.1.1
resolution: "@formatjs/intl-listformat@npm:8.1.1"
"@formatjs/intl-listformat@npm:8.1.0":
version: 8.1.0
resolution: "@formatjs/intl-listformat@npm:8.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
tslib: "npm:^2.8.0"
checksum: 10/29daf29492f396a6266324196af764123b9bbd19fcd25ed02dfccbc4f31dcc592be47e02c39d8b5c1f8b8411f22ca961f82b4c66a98e7e44dd8cfa3459ec42f3
checksum: 10/b63bf22c79cb7108a32da10737bd11f00e61ed6a37ec9f16656578d51ce8411005e95d5eaba243e90670259b2ab067a654e8f9c7739e07eff980eb7433618e94
languageName: node
linkType: hard
"@formatjs/intl-locale@npm:5.1.1":
version: 5.1.1
resolution: "@formatjs/intl-locale@npm:5.1.1"
"@formatjs/intl-locale@npm:5.1.0":
version: 5.1.0
resolution: "@formatjs/intl-locale@npm:5.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-enumerator": "npm:2.1.1"
"@formatjs/intl-getcanonicallocales": "npm:3.1.1"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-enumerator": "npm:2.1.0"
"@formatjs/intl-getcanonicallocales": "npm:3.1.0"
tslib: "npm:^2.8.0"
checksum: 10/02be5269e4ef1d058d5be8a0fe580f775e6a760ed4417ebf43a651bc6f0234833528ab76d64df276857d53d90ca7fcd022d0f5d667df3be485c85ae7a9bee617
checksum: 10/833b2624d64801078704df577a94c7326d68bc77f838faec68c7db66313a525bf46604472263ef6554a10aa076148253c29ddc161e9dffc9773218b2b20e4673
languageName: node
linkType: hard
"@formatjs/intl-localematcher@npm:0.7.4":
version: 0.7.4
resolution: "@formatjs/intl-localematcher@npm:0.7.4"
"@formatjs/intl-localematcher@npm:0.7.3":
version: 0.7.3
resolution: "@formatjs/intl-localematcher@npm:0.7.3"
dependencies:
"@formatjs/fast-memoize": "npm:3.0.2"
"@formatjs/fast-memoize": "npm:3.0.1"
tslib: "npm:^2.8.0"
checksum: 10/e2eb759628b35b45d95bddfc33bc8e985afd5d17c3d22bd243ea537fcb3b22eba2bbd8ce9e0f5cd6e29c3b514fe077ba99f5e7e5a1730983c9bfad649dc76985
checksum: 10/31386f8ca3a190a457a5969a3da76f2cb66b6c0b07ad98e9b6f42cc0ca2cd0242639a3efd2148c7e6d06f3b5e25267931c53a35ed2cb3c326cd2a34a5edda4e0
languageName: node
linkType: hard
"@formatjs/intl-numberformat@npm:9.1.1":
version: 9.1.1
resolution: "@formatjs/intl-numberformat@npm:9.1.1"
"@formatjs/intl-numberformat@npm:9.1.0":
version: 9.1.0
resolution: "@formatjs/intl-numberformat@npm:9.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
decimal.js: "npm:^10.4.3"
tslib: "npm:^2.8.0"
checksum: 10/dd2e0e331162f7d4253dcaebbfcead2e5a13669348890b042fe80d109088e930d08f09a6c74969ccd5e3fd3a3190a5d0c6013645e2cde289d8dc425ae1b3ea3a
checksum: 10/85e78885cc8d7324fd2cfe6aba50d88fb2eee9058692faa304aaa2fe742d304a7ed02b0f4b4503004335bfb0d1d0110e42f18341225fac59ba6416b8efd654c1
languageName: node
linkType: hard
"@formatjs/intl-pluralrules@npm:6.1.1":
version: 6.1.1
resolution: "@formatjs/intl-pluralrules@npm:6.1.1"
"@formatjs/intl-pluralrules@npm:6.1.0":
version: 6.1.0
resolution: "@formatjs/intl-pluralrules@npm:6.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
decimal.js: "npm:^10.4.3"
tslib: "npm:^2.8.0"
checksum: 10/94b900a5396bb066e61fc76af01e4634b60935a66ae27e57d148210dacc5ba7d95ee1dd2158ece1b240da50a9f88d44929af9bae95db6839f025f6ed03625dc9
checksum: 10/c6e66e1e1236d09518208805392b834a35708fe15e45269f9ab2af916c7c43da9e5046e55f908f3531b3ced9ad293b9ca8151d91e648d318f438d542077e3c6b
languageName: node
linkType: hard
"@formatjs/intl-relativetimeformat@npm:12.1.1":
version: 12.1.1
resolution: "@formatjs/intl-relativetimeformat@npm:12.1.1"
"@formatjs/intl-relativetimeformat@npm:12.1.0":
version: 12.1.0
resolution: "@formatjs/intl-relativetimeformat@npm:12.1.0"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/intl-localematcher": "npm:0.7.4"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/intl-localematcher": "npm:0.7.3"
tslib: "npm:^2.8.0"
checksum: 10/102a694f7b9764aa3e43702af4a2e47e6c9df7116815810a3210d80919ffe4b60e8a2098ebd424d3074df052b5fc3b5846ff6691a09f53103186253a006e5354
checksum: 10/0ef13a7544d01bf2aaffd91ab766f11c98516128ff6eaec718471599ab482a068b82be96c06770ac4b34ddddccc1f7631662eef9999744468c0cedec229b267e
languageName: node
linkType: hard
@@ -3312,58 +3300,58 @@ __metadata:
languageName: node
linkType: hard
"@module-federation/error-codes@npm:0.22.0":
version: 0.22.0
resolution: "@module-federation/error-codes@npm:0.22.0"
checksum: 10/4edb269e9f3039899f879788c84d2bfecff94ca8e87ffcd80dbf8589d8543ec32558b3fa05c8549a8abd3ac33e856ff2aacf458dea5c0d7bea608bf12bb13359
"@module-federation/error-codes@npm:0.21.6":
version: 0.21.6
resolution: "@module-federation/error-codes@npm:0.21.6"
checksum: 10/6ded1ecab780f1f9ec46a59adb200e75cdf11580d70aa79dd75d71fbbf276615690da277ea67aa1ceb5bc88386f5708cc1d2ba5526be5c9ff02397a6123e36bf
languageName: node
linkType: hard
"@module-federation/runtime-core@npm:0.22.0":
version: 0.22.0
resolution: "@module-federation/runtime-core@npm:0.22.0"
"@module-federation/runtime-core@npm:0.21.6":
version: 0.21.6
resolution: "@module-federation/runtime-core@npm:0.21.6"
dependencies:
"@module-federation/error-codes": "npm:0.22.0"
"@module-federation/sdk": "npm:0.22.0"
checksum: 10/d21969198322b6f79e0513b702d0af5097613d47819724c849b6c677c163cd10fb8c89e3ff62b798bec498ee4d8e95dec71861071bc4ed74bd86a7e43193bc05
"@module-federation/error-codes": "npm:0.21.6"
"@module-federation/sdk": "npm:0.21.6"
checksum: 10/85efa2042d6f3a7cf0e4971b991472d4339d88f6f15684afb6d451f19ed934e225b2510c86b7bb4d2c5f64253ed7b0175f08c17f95bfc2b9929930a8a03fff1e
languageName: node
linkType: hard
"@module-federation/runtime-tools@npm:0.22.0":
version: 0.22.0
resolution: "@module-federation/runtime-tools@npm:0.22.0"
"@module-federation/runtime-tools@npm:0.21.6":
version: 0.21.6
resolution: "@module-federation/runtime-tools@npm:0.21.6"
dependencies:
"@module-federation/runtime": "npm:0.22.0"
"@module-federation/webpack-bundler-runtime": "npm:0.22.0"
checksum: 10/0e7693c1ec02fc5bef770b478c8757cad9cfefb2310d1943151d0ad079b72472d9b2c8a087299e9124dfcd6b649c83290c7fdfa333865baab4ba193f39e7b6bd
"@module-federation/runtime": "npm:0.21.6"
"@module-federation/webpack-bundler-runtime": "npm:0.21.6"
checksum: 10/36e7ccab948e11f310e87397a1a2185b56064e5691e553b34173686e2bc7372ec710e5ad48c026eb28c85b168765788b743aa2111513f3b57118b47636312dd1
languageName: node
linkType: hard
"@module-federation/runtime@npm:0.22.0":
version: 0.22.0
resolution: "@module-federation/runtime@npm:0.22.0"
"@module-federation/runtime@npm:0.21.6":
version: 0.21.6
resolution: "@module-federation/runtime@npm:0.21.6"
dependencies:
"@module-federation/error-codes": "npm:0.22.0"
"@module-federation/runtime-core": "npm:0.22.0"
"@module-federation/sdk": "npm:0.22.0"
checksum: 10/eca608be999d7d2e83abc1169643c2f795a5ed950f9e2bdf7000400a30b3e1e0ca4bdaa5daa09f55e44868383d444707e40236cec1aaa7b40432b0cce800b7f3
"@module-federation/error-codes": "npm:0.21.6"
"@module-federation/runtime-core": "npm:0.21.6"
"@module-federation/sdk": "npm:0.21.6"
checksum: 10/93fd9bb284630933cab7e4bc070d648b56272f3636038c05eec7d1e3eeb189be3ccebe5f8ecc450197ee992d2616ed282d54e673ec0acd63adee4faddf80b144
languageName: node
linkType: hard
"@module-federation/sdk@npm:0.22.0":
version: 0.22.0
resolution: "@module-federation/sdk@npm:0.22.0"
checksum: 10/d7085d883730a33145052520787a7e59cf9c54b51b2946bebc7c63a6bb668bcc6cbdc27fa0b7354a62f5a7ee4e8829a66b84e644607498f2e37cfd5eb4ded0da
"@module-federation/sdk@npm:0.21.6":
version: 0.21.6
resolution: "@module-federation/sdk@npm:0.21.6"
checksum: 10/effc4aa932e2f06742bda8f02aaec84e138f5512b50f18c38b051490020b20d3d8edf7ece853fccffc1f78a0b43dec78e69bf02150e7e2801d5ce03c3ee367b9
languageName: node
linkType: hard
"@module-federation/webpack-bundler-runtime@npm:0.22.0":
version: 0.22.0
resolution: "@module-federation/webpack-bundler-runtime@npm:0.22.0"
"@module-federation/webpack-bundler-runtime@npm:0.21.6":
version: 0.21.6
resolution: "@module-federation/webpack-bundler-runtime@npm:0.21.6"
dependencies:
"@module-federation/runtime": "npm:0.22.0"
"@module-federation/sdk": "npm:0.22.0"
checksum: 10/afd24406817dfc6474ebcf5be714ccf26690eb3f6f5172bda711c8f23dba149fe47293f7aa2d0733dfed0334c98d4d3d9e7c2da2be78750cae5a72d72f32ce93
"@module-federation/runtime": "npm:0.21.6"
"@module-federation/sdk": "npm:0.21.6"
checksum: 10/a5ceb72ee3867acad5d7d3c654eb568068b1d5288f60ce9301bdc9f56effa5a4c26a732a2cec7176a81b87139566cd51dd8dfbc6112da05d47b870fa3ad3ba1f
languageName: node
linkType: hard
@@ -3993,92 +3981,92 @@ __metadata:
languageName: node
linkType: hard
"@rspack/binding-darwin-arm64@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-darwin-arm64@npm:1.7.0"
"@rspack/binding-darwin-arm64@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-darwin-arm64@npm:1.6.8"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-darwin-x64@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-darwin-x64@npm:1.7.0"
"@rspack/binding-darwin-x64@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-darwin-x64@npm:1.6.8"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-gnu@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-linux-arm64-gnu@npm:1.7.0"
"@rspack/binding-linux-arm64-gnu@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-linux-arm64-gnu@npm:1.6.8"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-musl@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-linux-arm64-musl@npm:1.7.0"
"@rspack/binding-linux-arm64-musl@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-linux-arm64-musl@npm:1.6.8"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-linux-x64-gnu@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-linux-x64-gnu@npm:1.7.0"
"@rspack/binding-linux-x64-gnu@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-linux-x64-gnu@npm:1.6.8"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-x64-musl@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-linux-x64-musl@npm:1.7.0"
"@rspack/binding-linux-x64-musl@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-linux-x64-musl@npm:1.6.8"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-wasm32-wasi@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-wasm32-wasi@npm:1.7.0"
"@rspack/binding-wasm32-wasi@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-wasm32-wasi@npm:1.6.8"
dependencies:
"@napi-rs/wasm-runtime": "npm:1.0.7"
conditions: cpu=wasm32
languageName: node
linkType: hard
"@rspack/binding-win32-arm64-msvc@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-win32-arm64-msvc@npm:1.7.0"
"@rspack/binding-win32-arm64-msvc@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-win32-arm64-msvc@npm:1.6.8"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-win32-ia32-msvc@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-win32-ia32-msvc@npm:1.7.0"
"@rspack/binding-win32-ia32-msvc@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-win32-ia32-msvc@npm:1.6.8"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@rspack/binding-win32-x64-msvc@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding-win32-x64-msvc@npm:1.7.0"
"@rspack/binding-win32-x64-msvc@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding-win32-x64-msvc@npm:1.6.8"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@rspack/binding@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/binding@npm:1.7.0"
"@rspack/binding@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/binding@npm:1.6.8"
dependencies:
"@rspack/binding-darwin-arm64": "npm:1.7.0"
"@rspack/binding-darwin-x64": "npm:1.7.0"
"@rspack/binding-linux-arm64-gnu": "npm:1.7.0"
"@rspack/binding-linux-arm64-musl": "npm:1.7.0"
"@rspack/binding-linux-x64-gnu": "npm:1.7.0"
"@rspack/binding-linux-x64-musl": "npm:1.7.0"
"@rspack/binding-wasm32-wasi": "npm:1.7.0"
"@rspack/binding-win32-arm64-msvc": "npm:1.7.0"
"@rspack/binding-win32-ia32-msvc": "npm:1.7.0"
"@rspack/binding-win32-x64-msvc": "npm:1.7.0"
"@rspack/binding-darwin-arm64": "npm:1.6.8"
"@rspack/binding-darwin-x64": "npm:1.6.8"
"@rspack/binding-linux-arm64-gnu": "npm:1.6.8"
"@rspack/binding-linux-arm64-musl": "npm:1.6.8"
"@rspack/binding-linux-x64-gnu": "npm:1.6.8"
"@rspack/binding-linux-x64-musl": "npm:1.6.8"
"@rspack/binding-wasm32-wasi": "npm:1.6.8"
"@rspack/binding-win32-arm64-msvc": "npm:1.6.8"
"@rspack/binding-win32-ia32-msvc": "npm:1.6.8"
"@rspack/binding-win32-x64-msvc": "npm:1.6.8"
dependenciesMeta:
"@rspack/binding-darwin-arm64":
optional: true
@@ -4100,29 +4088,29 @@ __metadata:
optional: true
"@rspack/binding-win32-x64-msvc":
optional: true
checksum: 10/152155585fe2b31c68efc1ddaa3272bcff04f483220d6b5c1ac4e35d69622261233657d66e3e0d73f28c08ccfe31742e4c284a9e35da82ee2cf32f896a6bd87b
checksum: 10/ca8b64987f05b970c08ad6bd4068bebe843824468535cc523c543f234eab8d728bbe1da2482b32675a472208639a3fd89d14013724fa612c285dfa33cc0c0c90
languageName: node
linkType: hard
"@rspack/core@npm:1.7.0":
version: 1.7.0
resolution: "@rspack/core@npm:1.7.0"
"@rspack/core@npm:1.6.8":
version: 1.6.8
resolution: "@rspack/core@npm:1.6.8"
dependencies:
"@module-federation/runtime-tools": "npm:0.22.0"
"@rspack/binding": "npm:1.7.0"
"@module-federation/runtime-tools": "npm:0.21.6"
"@rspack/binding": "npm:1.6.8"
"@rspack/lite-tapable": "npm:1.1.0"
peerDependencies:
"@swc/helpers": ">=0.5.1"
peerDependenciesMeta:
"@swc/helpers":
optional: true
checksum: 10/79786219475e74ef2e8bb418b33e6fa39eb152639e64a83ee3887427c536d3eac4a09fda1b589f5806d62fda96b4b0350ae1bc8b26e93049be97eaae21dd6a02
checksum: 10/3c10608dd1e07d340bedd9ed8e520f5e8ad4401475f12ae204ac4cd1d5ad1d57250b0ea8ffc8595bbf8d7d211a4c5408c7c2ee161b0402b7ba7a3e6f692d4423
languageName: node
linkType: hard
"@rspack/dev-server@npm:1.1.5":
version: 1.1.5
resolution: "@rspack/dev-server@npm:1.1.5"
"@rspack/dev-server@npm:1.1.4":
version: 1.1.4
resolution: "@rspack/dev-server@npm:1.1.4"
dependencies:
chokidar: "npm:^3.6.0"
http-proxy-middleware: "npm:^2.0.9"
@@ -4131,7 +4119,7 @@ __metadata:
ws: "npm:^8.18.0"
peerDependencies:
"@rspack/core": "*"
checksum: 10/67a747d998f9a2449cb1c6c5791ffc812c9d99a7219595359ce960063f344fde9f8f2000bbc9633dc490082f69b74a20b8f319697bd19beca65bd108f5dff5e5
checksum: 10/9409af5b9cd6f3de70caea7f82595a5e99e39ec203ef93fc9973fefdcacf6b7d264d07e927a2331d73d7d606f211865d82386bdde410f6be506ff91a1af89d99
languageName: node
linkType: hard
@@ -4949,138 +4937,138 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/eslint-plugin@npm:8.51.0"
"@typescript-eslint/eslint-plugin@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/eslint-plugin@npm:8.50.1"
dependencies:
"@eslint-community/regexpp": "npm:^4.10.0"
"@typescript-eslint/scope-manager": "npm:8.51.0"
"@typescript-eslint/type-utils": "npm:8.51.0"
"@typescript-eslint/utils": "npm:8.51.0"
"@typescript-eslint/visitor-keys": "npm:8.51.0"
"@typescript-eslint/scope-manager": "npm:8.50.1"
"@typescript-eslint/type-utils": "npm:8.50.1"
"@typescript-eslint/utils": "npm:8.50.1"
"@typescript-eslint/visitor-keys": "npm:8.50.1"
ignore: "npm:^7.0.0"
natural-compare: "npm:^1.4.0"
ts-api-utils: "npm:^2.2.0"
ts-api-utils: "npm:^2.1.0"
peerDependencies:
"@typescript-eslint/parser": ^8.51.0
"@typescript-eslint/parser": ^8.50.1
eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0"
checksum: 10/cb6c129a9f7e723218458ec86acb86176f7cddc1b41924416478a31fd633c2991849be56e21dca8df0ce535ea2014b361073b043085e39795816de528747c80b
checksum: 10/d4351575f8a2a7ac509681e22ef6773f13085b8c01a549e5316311c5757571d65692d60c1cd1a8d6872005adcc2ecfc4a605770a4dce2cc438da02e5bda505bd
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/parser@npm:8.51.0"
"@typescript-eslint/parser@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/parser@npm:8.50.1"
dependencies:
"@typescript-eslint/scope-manager": "npm:8.51.0"
"@typescript-eslint/types": "npm:8.51.0"
"@typescript-eslint/typescript-estree": "npm:8.51.0"
"@typescript-eslint/visitor-keys": "npm:8.51.0"
"@typescript-eslint/scope-manager": "npm:8.50.1"
"@typescript-eslint/types": "npm:8.50.1"
"@typescript-eslint/typescript-estree": "npm:8.50.1"
"@typescript-eslint/visitor-keys": "npm:8.50.1"
debug: "npm:^4.3.4"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0"
checksum: 10/ad2cb5d9cea5749fca712699ef971d68506f6170766d465ecc5864b5b5a15401c85d4042231df9edcc200f14b2579e6d4b2fbe66db824d925193004cde02ba79
checksum: 10/444c799c34edc5bc3cb7178d3b3bb3c5526d8b4662f575a687c9fc65868c6f965bed3df07507769284cb0f20822a656d192049d77e717c3f34b8154f13ce481a
languageName: node
linkType: hard
"@typescript-eslint/project-service@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/project-service@npm:8.51.0"
"@typescript-eslint/project-service@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/project-service@npm:8.50.1"
dependencies:
"@typescript-eslint/tsconfig-utils": "npm:^8.51.0"
"@typescript-eslint/types": "npm:^8.51.0"
"@typescript-eslint/tsconfig-utils": "npm:^8.50.1"
"@typescript-eslint/types": "npm:^8.50.1"
debug: "npm:^4.3.4"
peerDependencies:
typescript: ">=4.8.4 <6.0.0"
checksum: 10/f8b38bf1c92c3a5d33ae0304fc920b8ac20b24c308c056ea70fb5b257f9447be62fe54e9595260fd8611b36c8a66229e4ca7ef859edad42e1321434986132aac
checksum: 10/9e97bdb3485215a4ada558f4c02d39b0b629a649a1b21dd22e56712dc8cdafe827ab664f6168367a3c4461e6787b8d8a2c7dc2b2e83c5a5634bd2ef2ac286931
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/scope-manager@npm:8.51.0"
"@typescript-eslint/scope-manager@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/scope-manager@npm:8.50.1"
dependencies:
"@typescript-eslint/types": "npm:8.51.0"
"@typescript-eslint/visitor-keys": "npm:8.51.0"
checksum: 10/3d873589cd5b39f2bdc1e5b4f0052095f2cc5b2d59115ceea99533346839539ad7123ab0ba43ff4dd28c6afd4e8ae77798beb3618c93f24010104d38dedad6ad
"@typescript-eslint/types": "npm:8.50.1"
"@typescript-eslint/visitor-keys": "npm:8.50.1"
checksum: 10/fae4ccf2c474fe44b6c5b729dc957f547755e537748bf912135bd0b57cdcea31e27f2aa722fb9a2b3e01e01208c5f1c992c4ccbe63415c9c568ef51f1ab28835
languageName: node
linkType: hard
"@typescript-eslint/tsconfig-utils@npm:8.51.0, @typescript-eslint/tsconfig-utils@npm:^8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/tsconfig-utils@npm:8.51.0"
"@typescript-eslint/tsconfig-utils@npm:8.50.1, @typescript-eslint/tsconfig-utils@npm:^8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/tsconfig-utils@npm:8.50.1"
peerDependencies:
typescript: ">=4.8.4 <6.0.0"
checksum: 10/1a423e2b8bb6900e86f54ef78e967f17e6f51a528c64d78460338b916fda4e44bb8c73a7aba6b129295c59c3f364edbf27b34580f525df700674afbf0fc034df
checksum: 10/e05f27ef76d0b69c4bb563e5fc5432f884fc2fbc9d7035f7350d67e5fc32a1dad9a07310755c52d9fce5cba2b509a42ffbf899fb11e6fd8469c1d6ca6c3cd423
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/type-utils@npm:8.51.0"
"@typescript-eslint/type-utils@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/type-utils@npm:8.50.1"
dependencies:
"@typescript-eslint/types": "npm:8.51.0"
"@typescript-eslint/typescript-estree": "npm:8.51.0"
"@typescript-eslint/utils": "npm:8.51.0"
"@typescript-eslint/types": "npm:8.50.1"
"@typescript-eslint/typescript-estree": "npm:8.50.1"
"@typescript-eslint/utils": "npm:8.50.1"
debug: "npm:^4.3.4"
ts-api-utils: "npm:^2.2.0"
ts-api-utils: "npm:^2.1.0"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0"
checksum: 10/1dd5b72e4c7d6ffeafff1c24f745c335dc4073ec2a5c7e40f1a05be3be91097246c96be8d927389d8e4ccfa15db946a45ac85dbfd0c788d6cf003dced1830c7d
checksum: 10/0985a4594c523cf6040e8244fa59e0c28837e29cf8a68a74cec76c411506ae3637621135f9517a2e67abef15231708ece89ab7bdfa08b8c7d8ea59d2c103d1cc
languageName: node
linkType: hard
"@typescript-eslint/types@npm:8.51.0, @typescript-eslint/types@npm:^8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/types@npm:8.51.0"
checksum: 10/34c4b602d2f07edb72879e8af5359b0d54d3787030ae0a8325691972b07f2c6429bef9586938d18ff7df03a2be858064c7890a42136514ff0f2b7847c1432193
"@typescript-eslint/types@npm:8.50.1, @typescript-eslint/types@npm:^8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/types@npm:8.50.1"
checksum: 10/fb5f89790bfaae8af09c835d2735c3162821d5e1e37b643cd317684f412bcf67282625b29f62b59619abd07ee36158c96cc958c2c5ce75f268cf13cb154b3125
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/typescript-estree@npm:8.51.0"
"@typescript-eslint/typescript-estree@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/typescript-estree@npm:8.50.1"
dependencies:
"@typescript-eslint/project-service": "npm:8.51.0"
"@typescript-eslint/tsconfig-utils": "npm:8.51.0"
"@typescript-eslint/types": "npm:8.51.0"
"@typescript-eslint/visitor-keys": "npm:8.51.0"
"@typescript-eslint/project-service": "npm:8.50.1"
"@typescript-eslint/tsconfig-utils": "npm:8.50.1"
"@typescript-eslint/types": "npm:8.50.1"
"@typescript-eslint/visitor-keys": "npm:8.50.1"
debug: "npm:^4.3.4"
minimatch: "npm:^9.0.4"
semver: "npm:^7.6.0"
tinyglobby: "npm:^0.2.15"
ts-api-utils: "npm:^2.2.0"
ts-api-utils: "npm:^2.1.0"
peerDependencies:
typescript: ">=4.8.4 <6.0.0"
checksum: 10/4f9f82b18b9a62e3ffe1253e7914a396ec1c550fec36f862eff9d3d49be4bf01349eb2540be68ecc35b245aab7f72843d2b5cd1e73c8e820db5cf6f3c6542916
checksum: 10/3da56bb297c2e7e237f99dc853138075dd01839c695f392bf8395b4013e1236e588925a0fe347a011cfcc3bfa5377bf0d69a2b03ca2b03926bfa9f303c36d030
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/utils@npm:8.51.0"
"@typescript-eslint/utils@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/utils@npm:8.50.1"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.7.0"
"@typescript-eslint/scope-manager": "npm:8.51.0"
"@typescript-eslint/types": "npm:8.51.0"
"@typescript-eslint/typescript-estree": "npm:8.51.0"
"@typescript-eslint/scope-manager": "npm:8.50.1"
"@typescript-eslint/types": "npm:8.50.1"
"@typescript-eslint/typescript-estree": "npm:8.50.1"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0"
checksum: 10/e5ced67d08129e62fd6866a72b94fa685cd33aa7f5d1fc3bb9a34187d0fc0b469062ec8dfd44cd8c06494af070a050a314a6db672dda392fbc907b64b1ecc57f
checksum: 10/71fe0bc1c9f0676b67842275d611b90f5874164a275663e026673df3cb4dba0c8d27c27b2e6f556d37e19a31e3462e35a80d6f37eb6fe5ffd28aae0bdcb0beca
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:8.51.0":
version: 8.51.0
resolution: "@typescript-eslint/visitor-keys@npm:8.51.0"
"@typescript-eslint/visitor-keys@npm:8.50.1":
version: 8.50.1
resolution: "@typescript-eslint/visitor-keys@npm:8.50.1"
dependencies:
"@typescript-eslint/types": "npm:8.51.0"
"@typescript-eslint/types": "npm:8.50.1"
eslint-visitor-keys: "npm:^4.2.1"
checksum: 10/922fb3d2e59f6e8a9583a1bc7b13e66d4ec7bd7df3256602810465a7017549b890cd1a7897efc71ed64cc287c718be5dddbc8071b74e8ee41fe441f6d5251d3d
checksum: 10/59616dd2d5fc1a5b722c6812d23ed95bb896523daacfa58a15095aefb7ee393749765709b2fbdfe0a2968636f21879b9e847246eb00aa05281df084014698ced
languageName: node
linkType: hard
@@ -8748,10 +8736,10 @@ __metadata:
languageName: node
linkType: hard
"globals@npm:17.0.0":
version: 17.0.0
resolution: "globals@npm:17.0.0"
checksum: 10/af6213db9bf5f599b8a609061984c4d5fedb23db336228b866eba70819fe13ea3d11ca507b4799e8afc888331d0f7e5760d01507e38cb988fff9ad3a9635b312
"globals@npm:16.5.0":
version: 16.5.0
resolution: "globals@npm:16.5.0"
checksum: 10/f9e8a2a13f50222c127030a619e283e7bbfe32966316bdde0715af1d15a7e40cb9c24ff52cad59671f97762ed8b515353c2f8674f560c63d9385f19ee26735a6
languageName: node
linkType: hard
@@ -9010,18 +8998,18 @@ __metadata:
"@codemirror/legacy-modes": "npm:6.5.2"
"@codemirror/search": "npm:6.5.11"
"@codemirror/state": "npm:6.5.3"
"@codemirror/view": "npm:6.39.8"
"@codemirror/view": "npm:6.39.7"
"@date-fns/tz": "npm:1.4.1"
"@egjs/hammerjs": "npm:2.0.17"
"@formatjs/intl-datetimeformat": "npm:7.1.1"
"@formatjs/intl-displaynames": "npm:7.1.1"
"@formatjs/intl-durationformat": "npm:0.9.1"
"@formatjs/intl-getcanonicallocales": "npm:3.1.1"
"@formatjs/intl-listformat": "npm:8.1.1"
"@formatjs/intl-locale": "npm:5.1.1"
"@formatjs/intl-numberformat": "npm:9.1.1"
"@formatjs/intl-pluralrules": "npm:6.1.1"
"@formatjs/intl-relativetimeformat": "npm:12.1.1"
"@formatjs/intl-datetimeformat": "npm:7.1.0"
"@formatjs/intl-displaynames": "npm:7.1.0"
"@formatjs/intl-durationformat": "npm:0.9.0"
"@formatjs/intl-getcanonicallocales": "npm:3.1.0"
"@formatjs/intl-listformat": "npm:8.1.0"
"@formatjs/intl-locale": "npm:5.1.0"
"@formatjs/intl-numberformat": "npm:9.1.0"
"@formatjs/intl-pluralrules": "npm:6.1.0"
"@formatjs/intl-relativetimeformat": "npm:12.1.0"
"@fullcalendar/core": "npm:6.1.20"
"@fullcalendar/daygrid": "npm:6.1.20"
"@fullcalendar/interaction": "npm:6.1.20"
@@ -9066,8 +9054,8 @@ __metadata:
"@octokit/rest": "npm:22.0.1"
"@replit/codemirror-indentation-markers": "npm:6.5.3"
"@rsdoctor/rspack-plugin": "npm:1.4.0"
"@rspack/core": "npm:1.7.0"
"@rspack/dev-server": "npm:1.1.5"
"@rspack/core": "npm:1.6.8"
"@rspack/dev-server": "npm:1.1.4"
"@swc/helpers": "npm:0.5.18"
"@thomasloven/round-slider": "npm:0.6.0"
"@tsparticles/engine": "npm:3.9.1"
@@ -9136,9 +9124,9 @@ __metadata:
html-minifier-terser: "npm:7.2.0"
husky: "npm:9.1.7"
idb-keyval: "npm:6.2.2"
intl-messageformat: "npm:11.0.8"
intl-messageformat: "npm:11.0.7"
js-yaml: "npm:4.1.1"
jsdom: "npm:27.4.0"
jsdom: "npm:27.3.0"
jszip: "npm:3.10.1"
leaflet: "npm:1.9.4"
leaflet-draw: "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
@@ -9173,7 +9161,7 @@ __metadata:
tinykeys: "npm:3.0.0"
ts-lit-plugin: "npm:2.0.2"
typescript: "npm:5.9.3"
typescript-eslint: "npm:8.51.0"
typescript-eslint: "npm:8.50.1"
ua-parser-js: "npm:2.0.7"
vite-tsconfig-paths: "npm:6.0.3"
vitest: "npm:4.0.16"
@@ -9221,12 +9209,12 @@ __metadata:
languageName: node
linkType: hard
"html-encoding-sniffer@npm:^6.0.0":
version: 6.0.0
resolution: "html-encoding-sniffer@npm:6.0.0"
"html-encoding-sniffer@npm:^4.0.0":
version: 4.0.0
resolution: "html-encoding-sniffer@npm:4.0.0"
dependencies:
"@exodus/bytes": "npm:^1.6.0"
checksum: 10/97392e45d8aff57f180f62a1b12e62201c8451af68424b8bc3196f78e273891f2df285e5be43a3f28c7ba4badf9524ef305db65c4e4935a9e796afc86d9654b8
whatwg-encoding: "npm:^3.1.1"
checksum: 10/e86efd493293a5671b8239bd099d42128433bb3c7b0fdc7819282ef8e118a21f5dead0ad6f358e024a4e5c84f17ebb7a9b36075220fac0a6222b207248bede6f
languageName: node
linkType: hard
@@ -9401,7 +9389,7 @@ __metadata:
languageName: node
linkType: hard
"iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3":
"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3":
version: 0.6.3
resolution: "iconv-lite@npm:0.6.3"
dependencies:
@@ -9543,15 +9531,15 @@ __metadata:
languageName: node
linkType: hard
"intl-messageformat@npm:11.0.8":
version: 11.0.8
resolution: "intl-messageformat@npm:11.0.8"
"intl-messageformat@npm:11.0.7":
version: 11.0.7
resolution: "intl-messageformat@npm:11.0.7"
dependencies:
"@formatjs/ecma402-abstract": "npm:3.0.7"
"@formatjs/fast-memoize": "npm:3.0.2"
"@formatjs/icu-messageformat-parser": "npm:3.2.1"
"@formatjs/ecma402-abstract": "npm:3.0.6"
"@formatjs/fast-memoize": "npm:3.0.1"
"@formatjs/icu-messageformat-parser": "npm:3.2.0"
tslib: "npm:^2.8.0"
checksum: 10/e6b1317c683732c5c9677d897e049669b89569422f96edd8160d11ae252a5795ba62f27812b3ec2be57ca88e49ac336be6608642edbd2c2b36515f55b13385e9
checksum: 10/e0f7c93db02a24aaa66c56cea8838abbbc20aa0dc08a0db784d9f575c6440a7b05bf40294678d4216b0d6dad1264b037096308d1a06f11e2052b4455d6cb8ea5
languageName: node
linkType: hard
@@ -10197,17 +10185,16 @@ __metadata:
languageName: node
linkType: hard
"jsdom@npm:27.4.0":
version: 27.4.0
resolution: "jsdom@npm:27.4.0"
"jsdom@npm:27.3.0":
version: 27.3.0
resolution: "jsdom@npm:27.3.0"
dependencies:
"@acemir/cssom": "npm:^0.9.28"
"@asamuzakjp/dom-selector": "npm:^6.7.6"
"@exodus/bytes": "npm:^1.6.0"
cssstyle: "npm:^5.3.4"
data-urls: "npm:^6.0.0"
decimal.js: "npm:^10.6.0"
html-encoding-sniffer: "npm:^6.0.0"
html-encoding-sniffer: "npm:^4.0.0"
http-proxy-agent: "npm:^7.0.2"
https-proxy-agent: "npm:^7.0.6"
is-potential-custom-element-name: "npm:^1.0.1"
@@ -10217,6 +10204,7 @@ __metadata:
tough-cookie: "npm:^6.0.0"
w3c-xmlserializer: "npm:^5.0.0"
webidl-conversions: "npm:^8.0.0"
whatwg-encoding: "npm:^3.1.1"
whatwg-mimetype: "npm:^4.0.0"
whatwg-url: "npm:^15.1.0"
ws: "npm:^8.18.3"
@@ -10226,7 +10214,7 @@ __metadata:
peerDependenciesMeta:
canvas:
optional: true
checksum: 10/7c6db85ab91183b95204648e086cfc09ecee36d9e8fee0bb5d68e27543eca632de0af6d43de461176a7823820543d5c53561778af5f712b1a1cd28bfac084d51
checksum: 10/c650e954df04a80e7309984450ce764ae2a840810b9575b20204194dee3c5cff42e65526519cb58b946ffe66a058b7b763bad4814b3903a9c86a2c1651b8b74b
languageName: node
linkType: hard
@@ -13873,12 +13861,12 @@ __metadata:
languageName: node
linkType: hard
"ts-api-utils@npm:^2.2.0":
version: 2.3.0
resolution: "ts-api-utils@npm:2.3.0"
"ts-api-utils@npm:^2.1.0":
version: 2.1.0
resolution: "ts-api-utils@npm:2.1.0"
peerDependencies:
typescript: ">=4.8.4"
checksum: 10/33472e0aa22222947512bcbdad37f078a6a4fb8f79e5ce271267f3520e7303ab204067cc7eaa508b2e4f91539b0bb9ecb9254f5f62397d27cf52dc5e73540a8f
checksum: 10/02e55b49d9617c6eebf8aadfa08d3ca03ca0cd2f0586ad34117fdfc7aa3cd25d95051843fde9df86665ad907f99baed179e7a117b11021417f379e4d2614eacd
languageName: node
linkType: hard
@@ -14041,18 +14029,18 @@ __metadata:
languageName: node
linkType: hard
"typescript-eslint@npm:8.51.0":
version: 8.51.0
resolution: "typescript-eslint@npm:8.51.0"
"typescript-eslint@npm:8.50.1":
version: 8.50.1
resolution: "typescript-eslint@npm:8.50.1"
dependencies:
"@typescript-eslint/eslint-plugin": "npm:8.51.0"
"@typescript-eslint/parser": "npm:8.51.0"
"@typescript-eslint/typescript-estree": "npm:8.51.0"
"@typescript-eslint/utils": "npm:8.51.0"
"@typescript-eslint/eslint-plugin": "npm:8.50.1"
"@typescript-eslint/parser": "npm:8.50.1"
"@typescript-eslint/typescript-estree": "npm:8.50.1"
"@typescript-eslint/utils": "npm:8.50.1"
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: ">=4.8.4 <6.0.0"
checksum: 10/491dc8b6fb56f69c94515c31f6ff1db961d79c06e647f5db55647cca34dacedff4bab879a211559fc46e925a7a85ff60a1a68b7eac1e8a5db37828c57a65c718
checksum: 10/4cd6d67fcea16c5b766b4d60492618825f1e8ca92dcdb036b40e86fa7cebd1b0549e8d6de74215516b719edb326fd26763aa5750d2b39ec52c45b4a08e1ef78d
languageName: node
linkType: hard
@@ -14813,6 +14801,15 @@ __metadata:
languageName: node
linkType: hard
"whatwg-encoding@npm:^3.1.1":
version: 3.1.1
resolution: "whatwg-encoding@npm:3.1.1"
dependencies:
iconv-lite: "npm:0.6.3"
checksum: 10/bbef815eb67f91487c7f2ef96329743f5fd8357d7d62b1119237d25d41c7e452dff8197235b2d3c031365a17f61d3bb73ca49d0ed1582475aa4a670815e79534
languageName: node
linkType: hard
"whatwg-fetch@npm:^3.4.1":
version: 3.6.20
resolution: "whatwg-fetch@npm:3.6.20"