mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-27 11:47:20 +00:00
Compare commits
27 Commits
number-ent
...
panel-ener
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f57db13fe8 | ||
|
|
53a144c0b7 | ||
|
|
21f41055ae | ||
|
|
c8f5910d98 | ||
|
|
0ae49c7c3e | ||
|
|
d961aaace4 | ||
|
|
bd6bc25874 | ||
|
|
a45b07ea23 | ||
|
|
f7c446b257 | ||
|
|
71a29aa97d | ||
|
|
ae3a405a7b | ||
|
|
ebbcad812a | ||
|
|
d35a12d7e8 | ||
|
|
67e6dba85c | ||
|
|
fb666a7553 | ||
|
|
d767afb1e1 | ||
|
|
eb6191ab3a | ||
|
|
7fe9ae22f0 | ||
|
|
e3a1e5e0e3 | ||
|
|
01b8a5e01a | ||
|
|
a8ab035793 | ||
|
|
b36795ad3d | ||
|
|
ff0e173cfd | ||
|
|
11883525c2 | ||
|
|
f89f364add | ||
|
|
56391e32f2 | ||
|
|
b7f0f62949 |
28
package.json
28
package.json
@@ -28,13 +28,13 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.4",
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@codemirror/autocomplete": "6.19.1",
|
||||
"@codemirror/autocomplete": "6.20.0",
|
||||
"@codemirror/commands": "6.10.0",
|
||||
"@codemirror/language": "6.11.3",
|
||||
"@codemirror/legacy-modes": "6.5.2",
|
||||
"@codemirror/search": "6.5.11",
|
||||
"@codemirror/state": "6.5.2",
|
||||
"@codemirror/view": "6.38.6",
|
||||
"@codemirror/view": "6.38.8",
|
||||
"@date-fns/tz": "1.4.1",
|
||||
"@egjs/hammerjs": "2.0.17",
|
||||
"@formatjs/intl-datetimeformat": "6.18.2",
|
||||
@@ -96,10 +96,10 @@
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
"app-datepicker": "5.1.1",
|
||||
"barcode-detector": "3.0.6",
|
||||
"color-name": "2.0.2",
|
||||
"barcode-detector": "3.0.8",
|
||||
"color-name": "2.1.0",
|
||||
"comlink": "4.4.2",
|
||||
"core-js": "3.46.0",
|
||||
"core-js": "3.47.0",
|
||||
"cropperjs": "1.6.2",
|
||||
"culori": "4.0.2",
|
||||
"date-fns": "4.1.0",
|
||||
@@ -111,7 +111,7 @@
|
||||
"fuse.js": "7.1.0",
|
||||
"google-timezones-json": "1.2.0",
|
||||
"gulp-zopfli-green": "6.0.2",
|
||||
"hls.js": "1.6.14",
|
||||
"hls.js": "1.6.15",
|
||||
"home-assistant-js-websocket": "9.6.0",
|
||||
"idb-keyval": "6.2.2",
|
||||
"intl-messageformat": "10.7.18",
|
||||
@@ -122,7 +122,7 @@
|
||||
"lit": "3.3.1",
|
||||
"lit-html": "3.3.1",
|
||||
"luxon": "3.7.2",
|
||||
"marked": "17.0.0",
|
||||
"marked": "17.0.1",
|
||||
"memoize-one": "6.0.0",
|
||||
"node-vibrant": "4.0.3",
|
||||
"object-hash": "3.0.0",
|
||||
@@ -153,7 +153,7 @@
|
||||
"@babel/plugin-transform-runtime": "7.28.5",
|
||||
"@babel/preset-env": "7.28.5",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.21.6",
|
||||
"@lokalise/node-api": "15.3.1",
|
||||
"@lokalise/node-api": "15.4.0",
|
||||
"@octokit/auth-oauth-device": "8.0.3",
|
||||
"@octokit/plugin-retry": "8.0.3",
|
||||
"@octokit/rest": "22.0.1",
|
||||
@@ -178,7 +178,7 @@
|
||||
"@types/tar": "6.1.13",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@types/webspeechapi": "0.0.29",
|
||||
"@vitest/coverage-v8": "4.0.8",
|
||||
"@vitest/coverage-v8": "4.0.13",
|
||||
"babel-loader": "10.0.0",
|
||||
"babel-plugin-template-html-minifier": "4.1.0",
|
||||
"browserslist-useragent-regexp": "4.1.3",
|
||||
@@ -201,25 +201,25 @@
|
||||
"gulp-rename": "2.1.0",
|
||||
"html-minifier-terser": "7.2.0",
|
||||
"husky": "9.1.7",
|
||||
"jsdom": "27.1.0",
|
||||
"jsdom": "27.2.0",
|
||||
"jszip": "3.10.1",
|
||||
"lint-staged": "16.2.6",
|
||||
"lint-staged": "16.2.7",
|
||||
"lit-analyzer": "2.0.3",
|
||||
"lodash.merge": "4.6.2",
|
||||
"lodash.template": "4.5.0",
|
||||
"map-stream": "0.0.7",
|
||||
"pinst": "3.0.0",
|
||||
"prettier": "3.6.2",
|
||||
"rspack-manifest-plugin": "5.1.0",
|
||||
"rspack-manifest-plugin": "5.2.0",
|
||||
"serve": "14.2.5",
|
||||
"sinon": "21.0.0",
|
||||
"tar": "7.5.2",
|
||||
"terser-webpack-plugin": "5.3.14",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.46.3",
|
||||
"typescript-eslint": "8.47.0",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "4.0.8",
|
||||
"vitest": "4.0.13",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
"webpackbar": "7.0.0",
|
||||
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"
|
||||
|
||||
@@ -1,64 +1,16 @@
|
||||
import memoizeOne from "memoize-one";
|
||||
import { theme2hex } from "./convert-color";
|
||||
|
||||
export const COLORS = [
|
||||
"#4269d0",
|
||||
"#f4bd4a",
|
||||
"#ff725c",
|
||||
"#6cc5b0",
|
||||
"#a463f2",
|
||||
"#ff8ab7",
|
||||
"#9c6b4e",
|
||||
"#97bbf5",
|
||||
"#01ab63",
|
||||
"#094bad",
|
||||
"#c99000",
|
||||
"#d84f3e",
|
||||
"#49a28f",
|
||||
"#048732",
|
||||
"#d96895",
|
||||
"#8043ce",
|
||||
"#7599d1",
|
||||
"#7a4c31",
|
||||
"#6989f4",
|
||||
"#ffd444",
|
||||
"#ff957c",
|
||||
"#8fe9d3",
|
||||
"#62cc71",
|
||||
"#ffadda",
|
||||
"#c884ff",
|
||||
"#badeff",
|
||||
"#bf8b6d",
|
||||
"#927acc",
|
||||
"#97ee3f",
|
||||
"#bf3947",
|
||||
"#9f5b00",
|
||||
"#f48758",
|
||||
"#8caed6",
|
||||
"#f2b94f",
|
||||
"#eff26e",
|
||||
"#e43872",
|
||||
"#d9b100",
|
||||
"#9d7a00",
|
||||
"#698cff",
|
||||
"#00d27e",
|
||||
"#d06800",
|
||||
"#009f82",
|
||||
"#c49200",
|
||||
"#cbe8ff",
|
||||
"#fecddf",
|
||||
"#c27eb6",
|
||||
"#8cd2ce",
|
||||
"#c4b8d9",
|
||||
"#f883b0",
|
||||
"#a49100",
|
||||
"#f48800",
|
||||
"#27d0df",
|
||||
"#a04a9b",
|
||||
];
|
||||
// Total number of colors defined in CSS variables (--color-1 through --color-54)
|
||||
export const COLORS_COUNT = 54;
|
||||
|
||||
export function getColorByIndex(index: number) {
|
||||
return COLORS[index % COLORS.length];
|
||||
export function getColorByIndex(
|
||||
index: number,
|
||||
style: CSSStyleDeclaration
|
||||
): string {
|
||||
// Wrap around using modulo to support unlimited indices
|
||||
const colorIndex = (index % COLORS_COUNT) + 1;
|
||||
return style.getPropertyValue(`--color-${colorIndex}`);
|
||||
}
|
||||
|
||||
export function getGraphColorByIndex(
|
||||
@@ -68,15 +20,19 @@ export function getGraphColorByIndex(
|
||||
// The CSS vars for the colors use range 1..n, so we need to adjust the index from the internal 0..n color index range.
|
||||
const themeColor =
|
||||
style.getPropertyValue(`--graph-color-${index + 1}`) ||
|
||||
getColorByIndex(index);
|
||||
getColorByIndex(index, style);
|
||||
return theme2hex(themeColor);
|
||||
}
|
||||
|
||||
export const getAllGraphColors = memoizeOne(
|
||||
(style: CSSStyleDeclaration) =>
|
||||
COLORS.map((_color, index) => getGraphColorByIndex(index, style)),
|
||||
Array.from({ length: COLORS_COUNT }, (_, index) =>
|
||||
getGraphColorByIndex(index, style)
|
||||
),
|
||||
(newArgs: [CSSStyleDeclaration], lastArgs: [CSSStyleDeclaration]) =>
|
||||
// this is not ideal, but we need to memoize the colors
|
||||
newArgs[0].getPropertyValue("--graph-color-1") ===
|
||||
lastArgs[0].getPropertyValue("--graph-color-1")
|
||||
lastArgs[0].getPropertyValue("--graph-color-1") &&
|
||||
newArgs[0].getPropertyValue("--color-1") ===
|
||||
lastArgs[0].getPropertyValue("--color-1")
|
||||
);
|
||||
|
||||
@@ -81,6 +81,7 @@ class HaLabel extends LitElement {
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 0 16px;
|
||||
|
||||
@@ -465,10 +465,16 @@ export class HaServiceControl extends LitElement {
|
||||
? computeObjectId(this._value.action)
|
||||
: undefined;
|
||||
|
||||
const descriptionPlaceholders =
|
||||
domain && serviceName
|
||||
? this.hass.services[domain][serviceName].description_placeholders
|
||||
: undefined;
|
||||
|
||||
const description =
|
||||
(serviceName &&
|
||||
this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.description`
|
||||
`component.${domain}.services.${serviceName}.description`,
|
||||
descriptionPlaceholders
|
||||
)) ||
|
||||
serviceData?.description;
|
||||
|
||||
@@ -537,7 +543,8 @@ export class HaServiceControl extends LitElement {
|
||||
.disabled=${this.disabled}
|
||||
.value=${this._value?.data?.entity_id}
|
||||
.label=${this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.fields.entity_id.description`
|
||||
`component.${domain}.services.${serviceName}.fields.entity_id.description`,
|
||||
descriptionPlaceholders
|
||||
) || entityId.description}
|
||||
@value-changed=${this._entityPicked}
|
||||
allow-custom-entity
|
||||
@@ -575,7 +582,8 @@ export class HaServiceControl extends LitElement {
|
||||
left-chevron
|
||||
.expanded=${!dataField.collapsed}
|
||||
.header=${this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.sections.${dataField.key}.name`
|
||||
`component.${domain}.services.${serviceName}.sections.${dataField.key}.name`,
|
||||
descriptionPlaceholders
|
||||
) ||
|
||||
dataField.name ||
|
||||
dataField.key}
|
||||
@@ -611,7 +619,10 @@ export class HaServiceControl extends LitElement {
|
||||
serviceName: string | undefined
|
||||
) {
|
||||
return this.hass!.localize(
|
||||
`component.${domain}.services.${serviceName}.sections.${dataField.key}.description`
|
||||
`component.${domain}.services.${serviceName}.sections.${dataField.key}.description`,
|
||||
domain && serviceName
|
||||
? this.hass.services[domain][serviceName].description_placeholders
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
|
||||
@@ -658,6 +669,10 @@ export class HaServiceControl extends LitElement {
|
||||
}
|
||||
|
||||
const showOptional = showOptionalToggle(dataField);
|
||||
const descriptionPlaceholders =
|
||||
domain && serviceName
|
||||
? this.hass.services[domain][serviceName].description_placeholders
|
||||
: undefined;
|
||||
|
||||
return dataField.selector &&
|
||||
(!dataField.advanced ||
|
||||
@@ -679,7 +694,8 @@ export class HaServiceControl extends LitElement {
|
||||
></ha-checkbox>`}
|
||||
<span slot="heading"
|
||||
>${this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.fields.${dataField.key}.name`
|
||||
`component.${domain}.services.${serviceName}.fields.${dataField.key}.name`,
|
||||
descriptionPlaceholders
|
||||
) ||
|
||||
dataField.name ||
|
||||
dataField.key}</span
|
||||
@@ -689,7 +705,8 @@ export class HaServiceControl extends LitElement {
|
||||
breaks
|
||||
allow-svg
|
||||
.content=${this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.fields.${dataField.key}.description`
|
||||
`component.${domain}.services.${serviceName}.fields.${dataField.key}.description`,
|
||||
descriptionPlaceholders
|
||||
) || dataField?.description}
|
||||
></ha-markdown>
|
||||
</span>
|
||||
|
||||
@@ -92,8 +92,14 @@ class HaServicePicker extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
const descriptionPlaceholders =
|
||||
this.hass.services[domain][service].description_placeholders;
|
||||
|
||||
const serviceName =
|
||||
localize(`component.${domain}.services.${service}.name`) ||
|
||||
localize(
|
||||
`component.${domain}.services.${service}.name`,
|
||||
descriptionPlaceholders
|
||||
) ||
|
||||
services[domain][service].name ||
|
||||
service;
|
||||
|
||||
@@ -163,16 +169,21 @@ class HaServicePicker extends LitElement {
|
||||
const serviceId = `${domain}.${service}`;
|
||||
const domainName = domainToName(localize, domain);
|
||||
|
||||
const descriptionPlaceholders =
|
||||
this.hass.services[domain][service].description_placeholders;
|
||||
|
||||
const name =
|
||||
this.hass.localize(
|
||||
`component.${domain}.services.${service}.name`
|
||||
`component.${domain}.services.${service}.name`,
|
||||
descriptionPlaceholders
|
||||
) ||
|
||||
services[domain][service].name ||
|
||||
service;
|
||||
|
||||
const description =
|
||||
this.hass.localize(
|
||||
`component.${domain}.services.${service}.description`
|
||||
`component.${domain}.services.${service}.description`,
|
||||
descriptionPlaceholders
|
||||
) ||
|
||||
services[domain][service].description ||
|
||||
"";
|
||||
|
||||
@@ -137,8 +137,12 @@ const getCalendarDate = (dateObj: any): string | undefined => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const getCalendars = (hass: HomeAssistant): Calendar[] =>
|
||||
Object.keys(hass.states)
|
||||
export const getCalendars = (
|
||||
hass: HomeAssistant,
|
||||
element: Element
|
||||
): Calendar[] => {
|
||||
const computedStyles = getComputedStyle(element);
|
||||
return Object.keys(hass.states)
|
||||
.filter(
|
||||
(eid) =>
|
||||
computeDomain(eid) === "calendar" &&
|
||||
@@ -149,8 +153,9 @@ export const getCalendars = (hass: HomeAssistant): Calendar[] =>
|
||||
.map((eid, idx) => ({
|
||||
...hass.states[eid],
|
||||
name: computeStateName(hass.states[eid]),
|
||||
backgroundColor: getColorByIndex(idx),
|
||||
backgroundColor: getColorByIndex(idx, computedStyles),
|
||||
}));
|
||||
};
|
||||
|
||||
export const createCalendarEvent = (
|
||||
hass: HomeAssistant,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import type { MediaSelectorValue } from "../../selector";
|
||||
import type { LovelaceBadgeConfig } from "./badge";
|
||||
import type { LovelaceCardConfig } from "./card";
|
||||
import type { LovelaceSectionRawConfig } from "./section";
|
||||
import type {
|
||||
LovelaceSectionConfig,
|
||||
LovelaceSectionRawConfig,
|
||||
} from "./section";
|
||||
import type { LovelaceStrategyConfig } from "./strategy";
|
||||
|
||||
export interface ShowViewConfig {
|
||||
@@ -33,6 +36,12 @@ export interface LovelaceViewHeaderConfig {
|
||||
badges_wrap?: "wrap" | "scroll";
|
||||
}
|
||||
|
||||
export interface LovelaceViewSidebarConfig {
|
||||
sections?: LovelaceSectionConfig[];
|
||||
content_label?: string;
|
||||
sidebar_label?: string;
|
||||
}
|
||||
|
||||
export interface LovelaceBaseViewConfig {
|
||||
index?: number;
|
||||
title?: string;
|
||||
@@ -56,6 +65,8 @@ export interface LovelaceViewConfig extends LovelaceBaseViewConfig {
|
||||
cards?: LovelaceCardConfig[];
|
||||
sections?: LovelaceSectionRawConfig[];
|
||||
header?: LovelaceViewHeaderConfig;
|
||||
// Only used for section view, it should move to a section view config type when the views will have dedicated editor.
|
||||
sidebar?: LovelaceViewSidebarConfig;
|
||||
}
|
||||
|
||||
export interface LovelaceStrategyViewConfig extends LovelaceBaseViewConfig {
|
||||
|
||||
@@ -219,9 +219,13 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
|
||||
if (config.action) {
|
||||
const [domain, serviceName] = config.action.split(".", 2);
|
||||
const descriptionPlaceholders =
|
||||
hass.services[domain][serviceName].description_placeholders;
|
||||
const service =
|
||||
hass.localize(`component.${domain}.services.${serviceName}.name`) ||
|
||||
hass.services[domain][serviceName]?.name;
|
||||
hass.localize(
|
||||
`component.${domain}.services.${serviceName}.name`,
|
||||
descriptionPlaceholders
|
||||
) || hass.services[domain][serviceName]?.name;
|
||||
|
||||
if (config.metadata) {
|
||||
return hass.localize(
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { mdiAlertOutline } from "@mdi/js";
|
||||
import { mdiAlertOutline, mdiClose } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../../components/ha-button";
|
||||
import "../../components/ha-dialog-footer";
|
||||
import "../../components/ha-dialog-header";
|
||||
import "../../components/ha-md-dialog";
|
||||
import type { HaMdDialog } from "../../components/ha-md-dialog";
|
||||
import "../../components/ha-svg-icon";
|
||||
import "../../components/ha-textfield";
|
||||
import type { HaTextField } from "../../components/ha-textfield";
|
||||
import "../../components/ha-wa-dialog";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import type { DialogBoxParams } from "./show-dialog-box";
|
||||
|
||||
@@ -19,12 +19,12 @@ class DialogBox extends LitElement {
|
||||
|
||||
@state() private _params?: DialogBoxParams;
|
||||
|
||||
@state() private _open = false;
|
||||
|
||||
@state() private _closeState?: "canceled" | "confirmed";
|
||||
|
||||
@query("ha-textfield") private _textField?: HaTextField;
|
||||
|
||||
@query("ha-md-dialog") private _dialog?: HaMdDialog;
|
||||
|
||||
private _closePromise?: Promise<void>;
|
||||
|
||||
private _closeResolve?: () => void;
|
||||
@@ -34,6 +34,7 @@ class DialogBox extends LitElement {
|
||||
await this._closePromise;
|
||||
}
|
||||
this._params = params;
|
||||
this._open = true;
|
||||
}
|
||||
|
||||
public closeDialog(): boolean {
|
||||
@@ -60,16 +61,25 @@ class DialogBox extends LitElement {
|
||||
this.hass.localize("ui.dialogs.generic.default_confirmation_title"));
|
||||
|
||||
return html`
|
||||
<ha-md-dialog
|
||||
open
|
||||
.disableCancelAction=${confirmPrompt}
|
||||
<ha-wa-dialog
|
||||
.hass=${this.hass}
|
||||
.open=${this._open}
|
||||
?prevent-scrim-close=${confirmPrompt}
|
||||
@closed=${this._dialogClosed}
|
||||
type="alert"
|
||||
aria-labelledby="dialog-box-title"
|
||||
aria-describedby="dialog-box-description"
|
||||
>
|
||||
<div slot="headline">
|
||||
<span .title=${dialogTitle} id="dialog-box-title">
|
||||
<ha-dialog-header slot="header">
|
||||
${!confirmPrompt
|
||||
? html`<slot name="headerNavigationIcon" slot="navigationIcon">
|
||||
<ha-icon-button
|
||||
data-dialog="close"
|
||||
.label=${this.hass?.localize("ui.common.close") ?? "Close"}
|
||||
.path=${mdiClose}
|
||||
></ha-icon-button
|
||||
></slot>`
|
||||
: nothing}
|
||||
<span slot="title" id="dialog-box-title">
|
||||
${this._params.warning
|
||||
? html`<ha-svg-icon
|
||||
.path=${mdiAlertOutline}
|
||||
@@ -78,13 +88,13 @@ class DialogBox extends LitElement {
|
||||
: nothing}
|
||||
${dialogTitle}
|
||||
</span>
|
||||
</div>
|
||||
<div slot="content" id="dialog-box-description">
|
||||
</ha-dialog-header>
|
||||
<div id="dialog-box-description">
|
||||
${this._params.text ? html` <p>${this._params.text}</p> ` : ""}
|
||||
${this._params.prompt
|
||||
? html`
|
||||
<ha-textfield
|
||||
dialogInitialFocus
|
||||
autofocus
|
||||
value=${ifDefined(this._params.defaultValue)}
|
||||
.placeholder=${this._params.placeholder}
|
||||
.label=${this._params.inputLabel
|
||||
@@ -99,10 +109,11 @@ class DialogBox extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<div slot="actions">
|
||||
<ha-dialog-footer slot="footer">
|
||||
${confirmPrompt
|
||||
? html`
|
||||
<ha-button
|
||||
slot="secondaryAction"
|
||||
@click=${this._dismiss}
|
||||
?autofocus=${!this._params.prompt && this._params.destructive}
|
||||
appearance="plain"
|
||||
@@ -114,6 +125,7 @@ class DialogBox extends LitElement {
|
||||
`
|
||||
: nothing}
|
||||
<ha-button
|
||||
slot="primaryAction"
|
||||
@click=${this._confirm}
|
||||
?autofocus=${!this._params.prompt && !this._params.destructive}
|
||||
variant=${this._params.destructive ? "danger" : "brand"}
|
||||
@@ -122,8 +134,8 @@ class DialogBox extends LitElement {
|
||||
? this._params.confirmText
|
||||
: this.hass.localize("ui.common.ok")}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-md-dialog>
|
||||
</ha-dialog-footer>
|
||||
</ha-wa-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -148,20 +160,20 @@ class DialogBox extends LitElement {
|
||||
}
|
||||
|
||||
private _closeDialog() {
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
this._dialog?.close();
|
||||
this._open = false;
|
||||
this._closePromise = new Promise((resolve) => {
|
||||
this._closeResolve = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
private _dialogClosed() {
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
if (!this._closeState) {
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
this._cancel();
|
||||
}
|
||||
this._closeState = undefined;
|
||||
this._params = undefined;
|
||||
this._open = false;
|
||||
this._closeResolve?.();
|
||||
this._closeResolve = undefined;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class PanelCalendar extends LitElement {
|
||||
public willUpdate(changedProps: PropertyValues): void {
|
||||
super.willUpdate(changedProps);
|
||||
if (!this.hasUpdated) {
|
||||
this._calendars = getCalendars(this.hass);
|
||||
this._calendars = getCalendars(this.hass, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ class PanelCalendar extends LitElement {
|
||||
manifest: await fetchIntegrationManifest(this.hass, "local_calendar"),
|
||||
dialogClosedCallback: ({ flowFinished }) => {
|
||||
if (flowFinished) {
|
||||
this._calendars = getCalendars(this.hass);
|
||||
this._calendars = getCalendars(this.hass, this);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -871,13 +871,17 @@ class DialogAddAutomationElement
|
||||
`,
|
||||
key: `${DYNAMIC_PREFIX}${dmn}.${service}`,
|
||||
name: `${domain ? "" : `${domainToName(localize, dmn)}: `}${
|
||||
this.hass.localize(`component.${dmn}.services.${service}.name`) ||
|
||||
this.hass.localize(
|
||||
`component.${dmn}.services.${service}.name`,
|
||||
this.hass.services[dmn][service].description_placeholders
|
||||
) ||
|
||||
services[dmn][service]?.name ||
|
||||
service
|
||||
}`,
|
||||
description:
|
||||
this.hass.localize(
|
||||
`component.${dmn}.services.${service}.description`
|
||||
`component.${dmn}.services.${service}.description`,
|
||||
this.hass.services[dmn][service].description_placeholders
|
||||
) ||
|
||||
services[dmn][service]?.description ||
|
||||
"",
|
||||
|
||||
@@ -93,8 +93,12 @@ export default class HaAutomationSidebarAction extends LitElement {
|
||||
".",
|
||||
2
|
||||
);
|
||||
|
||||
title = `${domainToName(this.hass.localize, domain)}: ${
|
||||
this.hass.localize(`component.${domain}.services.${service}.name`) ||
|
||||
this.hass.localize(
|
||||
`component.${domain}.services.${service}.name`,
|
||||
this.hass.services[domain][service].description_placeholders
|
||||
) ||
|
||||
this.hass.services[domain][service]?.name ||
|
||||
title
|
||||
}`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type { AssistPipeline } from "../../../../data/assist_pipeline";
|
||||
@@ -78,6 +79,18 @@ export class AssistPipelineDetailSTT extends LitElement {
|
||||
|
||||
private _supportedLanguagesChanged(ev) {
|
||||
this._supportedLanguages = ev.detail.value;
|
||||
|
||||
if (
|
||||
!this.data?.stt_language ||
|
||||
!this._supportedLanguages?.includes(this.data.stt_language)
|
||||
) {
|
||||
// wait for update of conversation_engine
|
||||
setTimeout(() => {
|
||||
const value = { ...this.data };
|
||||
value.stt_language = this._supportedLanguages?.[0] ?? null;
|
||||
fireEvent(this, "value-changed", { value });
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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 type { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
@@ -122,6 +123,18 @@ export class AssistPipelineDetailTTS extends LitElement {
|
||||
|
||||
private _supportedLanguagesChanged(ev) {
|
||||
this._supportedLanguages = ev.detail.value;
|
||||
|
||||
if (
|
||||
!this.data?.tts_language ||
|
||||
!this._supportedLanguages?.includes(this.data?.tts_language)
|
||||
) {
|
||||
// wait for update of conversation_engine
|
||||
setTimeout(() => {
|
||||
const value = { ...this.data };
|
||||
value.tts_language = this._supportedLanguages?.[0] ?? null;
|
||||
fireEvent(this, "value-changed", { value });
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
||||
@@ -135,6 +135,11 @@ class HaPanelDevAction extends LitElement {
|
||||
? computeObjectId(this._serviceData?.action)
|
||||
: undefined;
|
||||
|
||||
const descriptionPlaceholders =
|
||||
domain && serviceName
|
||||
? this.hass.services[domain][serviceName].description_placeholders
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<div class="content">
|
||||
<p>
|
||||
@@ -307,12 +312,14 @@ class HaPanelDevAction extends LitElement {
|
||||
<td><pre>${field.key}</pre></td>
|
||||
<td>
|
||||
${this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.fields.${field.key}.description`
|
||||
`component.${domain}.services.${serviceName}.fields.${field.key}.description`,
|
||||
descriptionPlaceholders
|
||||
) || field.description}
|
||||
</td>
|
||||
<td>
|
||||
${this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.fields.${field.key}.example`
|
||||
`component.${domain}.services.${serviceName}.fields.${field.key}.example`,
|
||||
descriptionPlaceholders
|
||||
) || field.example}
|
||||
</td>
|
||||
</tr>`
|
||||
@@ -643,7 +650,11 @@ class HaPanelDevAction extends LitElement {
|
||||
} catch (_err: any) {
|
||||
value =
|
||||
this.hass.localize(
|
||||
`component.${domain}.services.${serviceName}.fields.${field.key}.example`
|
||||
`component.${domain}.services.${serviceName}.fields.${field.key}.example`,
|
||||
domain && serviceName
|
||||
? this.hass.services[domain][serviceName]
|
||||
.description_placeholders
|
||||
: undefined
|
||||
) || field.example;
|
||||
}
|
||||
example[field.key] = value;
|
||||
|
||||
@@ -1,60 +1,77 @@
|
||||
import { mdiDownload, mdiPencil } from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { mdiPencil, mdiDownload } from "@mdi/js";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../components/ha-menu-button";
|
||||
import { goBack, navigate } from "../../common/navigate";
|
||||
import "../../components/ha-alert";
|
||||
import "../../components/ha-icon-button-arrow-prev";
|
||||
import "../../components/ha-list-item";
|
||||
import "../../components/ha-menu-button";
|
||||
import "../../components/ha-top-app-bar-fixed";
|
||||
import "../../components/ha-alert";
|
||||
import type { LovelaceConfig } from "../../data/lovelace/config/types";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../lovelace/components/hui-energy-period-selector";
|
||||
import type { Lovelace } from "../lovelace/types";
|
||||
import "../lovelace/views/hui-view";
|
||||
import "../lovelace/views/hui-view-container";
|
||||
import { goBack, navigate } from "../../common/navigate";
|
||||
import type {
|
||||
BatterySourceTypeEnergyPreference,
|
||||
DeviceConsumptionEnergyPreference,
|
||||
EnergyPreferences,
|
||||
GasSourceTypeEnergyPreference,
|
||||
GridSourceTypeEnergyPreference,
|
||||
SolarSourceTypeEnergyPreference,
|
||||
BatterySourceTypeEnergyPreference,
|
||||
GasSourceTypeEnergyPreference,
|
||||
WaterSourceTypeEnergyPreference,
|
||||
DeviceConsumptionEnergyPreference,
|
||||
EnergyCollection,
|
||||
} from "../../data/energy";
|
||||
import {
|
||||
computeConsumptionData,
|
||||
getEnergyDataCollection,
|
||||
getSummedData,
|
||||
} from "../../data/energy";
|
||||
import { fileDownload } from "../../util/file_download";
|
||||
import type { LovelaceConfig } from "../../data/lovelace/config/types";
|
||||
import type { LovelaceViewConfig } from "../../data/lovelace/config/view";
|
||||
import type { StatisticValue } from "../../data/recorder";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant, PanelInfo } from "../../types";
|
||||
import { fileDownload } from "../../util/file_download";
|
||||
import "../lovelace/components/hui-energy-period-selector";
|
||||
import "../lovelace/hui-root";
|
||||
import type { Lovelace } from "../lovelace/types";
|
||||
import "../lovelace/views/hui-view";
|
||||
import "../lovelace/views/hui-view-container";
|
||||
|
||||
export const DEFAULT_ENERGY_COLLECTION_KEY = "energy_dashboard";
|
||||
|
||||
const ENERGY_LOVELACE_CONFIG: LovelaceConfig = {
|
||||
views: [
|
||||
{
|
||||
strategy: {
|
||||
type: "energy-overview",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
},
|
||||
},
|
||||
{
|
||||
strategy: {
|
||||
type: "energy-electricity",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
},
|
||||
path: "electricity",
|
||||
},
|
||||
{
|
||||
type: "panel",
|
||||
path: "setup",
|
||||
cards: [{ type: "custom:energy-setup-wizard-card" }],
|
||||
},
|
||||
],
|
||||
const EMPTY_PREFERENCES: EnergyPreferences = {
|
||||
energy_sources: [],
|
||||
device_consumption: [],
|
||||
device_consumption_water: [],
|
||||
};
|
||||
|
||||
const OVERVIEW_VIEW = {
|
||||
path: "overview",
|
||||
strategy: {
|
||||
type: "energy-overview",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
const ELECTRICITY_VIEW = {
|
||||
path: "electricity",
|
||||
back_path: "/energy",
|
||||
strategy: {
|
||||
type: "energy-electricity",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
const WATER_VIEW = {
|
||||
back_path: "/energy",
|
||||
path: "water",
|
||||
strategy: {
|
||||
type: "energy-water",
|
||||
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
},
|
||||
} as LovelaceViewConfig;
|
||||
|
||||
const WIZARD_VIEW = {
|
||||
type: "panel",
|
||||
path: "setup",
|
||||
cards: [{ type: "custom:energy-setup-wizard-card" }],
|
||||
};
|
||||
|
||||
@customElement("ha-panel-energy")
|
||||
@@ -63,70 +80,96 @@ class PanelEnergy extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public panel?: PanelInfo;
|
||||
|
||||
@state() private _lovelace?: Lovelace;
|
||||
|
||||
@state() private _searchParms = new URLSearchParams(window.location.search);
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
@property({ attribute: false }) public route?: {
|
||||
path: string;
|
||||
prefix: string;
|
||||
};
|
||||
|
||||
private _energyCollection?: EnergyCollection;
|
||||
@state()
|
||||
private _prefs?: EnergyPreferences;
|
||||
|
||||
get _viewPath(): string | undefined {
|
||||
const viewPath: string | undefined = this.route!.path.split("/")[1];
|
||||
return viewPath ? decodeURI(viewPath) : undefined;
|
||||
}
|
||||
@state()
|
||||
private _error?: string;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._loadPrefs();
|
||||
}
|
||||
|
||||
public async willUpdate(changedProps: PropertyValues) {
|
||||
public willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
// Initial setup
|
||||
if (!this.hasUpdated) {
|
||||
this.hass.loadFragmentTranslation("lovelace");
|
||||
this._loadConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!changedProps.has("hass")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldHass = changedProps.get("hass") as this["hass"];
|
||||
if (oldHass?.locale !== this.hass.locale) {
|
||||
if (oldHass && oldHass.localize !== this.hass.localize) {
|
||||
this._setLovelace();
|
||||
} else if (oldHass && oldHass.localize !== this.hass.localize) {
|
||||
this._reloadView();
|
||||
}
|
||||
}
|
||||
|
||||
private async _loadPrefs() {
|
||||
if (this._viewPath === "setup") {
|
||||
await import("./cards/energy-setup-wizard-card");
|
||||
} else {
|
||||
this._energyCollection = getEnergyDataCollection(this.hass, {
|
||||
key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
});
|
||||
try {
|
||||
// Have to manually refresh here as we don't want to subscribe yet
|
||||
await this._energyCollection.refresh();
|
||||
} catch (err: any) {
|
||||
if (err.code === "not_found") {
|
||||
navigate("/energy/setup");
|
||||
}
|
||||
this._error = err.message;
|
||||
return;
|
||||
}
|
||||
const prefs = this._energyCollection.prefs!;
|
||||
if (
|
||||
prefs.device_consumption.length === 0 &&
|
||||
prefs.energy_sources.length === 0
|
||||
) {
|
||||
// No energy sources available, start from scratch
|
||||
navigate("/energy/setup");
|
||||
private _fetchEnergyPrefs = async (): Promise<
|
||||
EnergyPreferences | undefined
|
||||
> => {
|
||||
const collection = getEnergyDataCollection(this.hass, {
|
||||
key: DEFAULT_ENERGY_COLLECTION_KEY,
|
||||
});
|
||||
try {
|
||||
await collection.refresh();
|
||||
} catch (err: any) {
|
||||
if (err.code === "not_found") {
|
||||
return undefined;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
return collection.prefs;
|
||||
};
|
||||
|
||||
private async _loadConfig() {
|
||||
try {
|
||||
this._error = undefined;
|
||||
const prefs = await this._fetchEnergyPrefs();
|
||||
this._prefs = prefs || EMPTY_PREFERENCES;
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Failed to load prefs:", err);
|
||||
this._prefs = EMPTY_PREFERENCES;
|
||||
this._error = (err as Error).message || "Unknown error";
|
||||
}
|
||||
await this._setLovelace();
|
||||
|
||||
// Navigate to first view if not there yet
|
||||
const firstPath = this._lovelace!.config?.views?.[0]?.path;
|
||||
const viewPath: string | undefined = this.route!.path.split("/")[1];
|
||||
if (viewPath !== firstPath) {
|
||||
navigate(`${this.route!.prefix}/${firstPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async _setLovelace() {
|
||||
const config = await this._generateLovelaceConfig();
|
||||
|
||||
this._lovelace = {
|
||||
config: config,
|
||||
rawConfig: config,
|
||||
editMode: false,
|
||||
urlPath: "energy",
|
||||
mode: "generated",
|
||||
locale: this.hass.locale,
|
||||
enableFullEditMode: () => undefined,
|
||||
saveConfig: async () => undefined,
|
||||
deleteConfig: async () => undefined,
|
||||
setEditMode: () => undefined,
|
||||
showToast: () => undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private _back(ev) {
|
||||
@@ -135,31 +178,49 @@ class PanelEnergy extends LitElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._energyCollection?.prefs) {
|
||||
if (this._error) {
|
||||
return html`
|
||||
<div class="centered">
|
||||
<ha-alert alert-type="error">
|
||||
An error occurred loading energy preferences: ${this._error}
|
||||
</ha-alert>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (!this._prefs) {
|
||||
// Still loading
|
||||
return html`<div class="centered">
|
||||
<ha-spinner size="large"></ha-spinner>
|
||||
</div>`;
|
||||
return html`
|
||||
<div class="centered">
|
||||
<ha-spinner size="large"></ha-spinner>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
const { prefs } = this._energyCollection;
|
||||
const isSingleView = prefs.energy_sources.every((source) =>
|
||||
["grid", "solar", "battery"].includes(source.type)
|
||||
);
|
||||
let viewPath = this._viewPath;
|
||||
if (isSingleView) {
|
||||
// if only electricity sources, show electricity view directly
|
||||
viewPath = "electricity";
|
||||
|
||||
if (!this._lovelace) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const viewPath: string | undefined = this.route!.path.split("/")[1];
|
||||
|
||||
const views = this._lovelace.config?.views || [];
|
||||
const viewIndex = Math.max(
|
||||
ENERGY_LOVELACE_CONFIG.views.findIndex((view) => view.path === viewPath),
|
||||
views.findIndex((view) => view.path === viewPath),
|
||||
0
|
||||
);
|
||||
const showBack =
|
||||
this._searchParms.has("historyBack") || (!isSingleView && viewIndex > 0);
|
||||
|
||||
const showBack = this._searchParms.has("historyBack") || viewIndex > 0;
|
||||
|
||||
return html`
|
||||
<div class="header">
|
||||
<div class="toolbar">
|
||||
<hui-root
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.lovelace=${this._lovelace}
|
||||
.route=${this.route}
|
||||
.panel=${this.panel}
|
||||
@reload-energy-panel=${this._reloadConfig}
|
||||
>
|
||||
<div class="toolbar" slot="toolbar">
|
||||
${showBack
|
||||
? html`
|
||||
<ha-icon-button-arrow-prev
|
||||
@@ -185,14 +246,17 @@ class PanelEnergy extends LitElement {
|
||||
.collectionKey=${DEFAULT_ENERGY_COLLECTION_KEY}
|
||||
>
|
||||
${this.hass.user?.is_admin
|
||||
? html` <ha-list-item
|
||||
slot="overflow-menu"
|
||||
graphic="icon"
|
||||
@request-selected=${this._navigateConfig}
|
||||
>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPencil}> </ha-svg-icon>
|
||||
${this.hass!.localize("ui.panel.energy.configure")}
|
||||
</ha-list-item>`
|
||||
? html`
|
||||
<ha-list-item
|
||||
slot="overflow-menu"
|
||||
graphic="icon"
|
||||
@request-selected=${this._navigateConfig}
|
||||
>
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPencil}>
|
||||
</ha-svg-icon>
|
||||
${this.hass!.localize("ui.panel.energy.configure")}
|
||||
</ha-list-item>
|
||||
`
|
||||
: nothing}
|
||||
<ha-list-item
|
||||
slot="overflow-menu"
|
||||
@@ -204,45 +268,40 @@ class PanelEnergy extends LitElement {
|
||||
</ha-list-item>
|
||||
</hui-energy-period-selector>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hui-view-container
|
||||
.hass=${this.hass}
|
||||
@reload-energy-panel=${this._reloadView}
|
||||
>
|
||||
${this._error
|
||||
? html`<div class="centered">
|
||||
<ha-alert alert-type="error">
|
||||
An error occurred while fetching your energy preferences:
|
||||
${this._error}
|
||||
</ha-alert>
|
||||
</div>`
|
||||
: this._lovelace
|
||||
? html`<hui-view
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.lovelace=${this._lovelace}
|
||||
.index=${viewIndex}
|
||||
></hui-view>`
|
||||
: nothing}
|
||||
</hui-view-container>
|
||||
</hui-root>
|
||||
`;
|
||||
}
|
||||
|
||||
private _setLovelace() {
|
||||
this._lovelace = {
|
||||
config: ENERGY_LOVELACE_CONFIG,
|
||||
rawConfig: ENERGY_LOVELACE_CONFIG,
|
||||
editMode: false,
|
||||
urlPath: "energy",
|
||||
mode: "generated",
|
||||
locale: this.hass.locale,
|
||||
enableFullEditMode: () => undefined,
|
||||
saveConfig: async () => undefined,
|
||||
deleteConfig: async () => undefined,
|
||||
setEditMode: () => undefined,
|
||||
showToast: () => undefined,
|
||||
};
|
||||
private async _generateLovelaceConfig(): Promise<LovelaceConfig> {
|
||||
if (
|
||||
!this._prefs ||
|
||||
(this._prefs.device_consumption.length === 0 &&
|
||||
this._prefs.energy_sources.length === 0)
|
||||
) {
|
||||
await import("./cards/energy-setup-wizard-card");
|
||||
return {
|
||||
views: [WIZARD_VIEW],
|
||||
};
|
||||
}
|
||||
|
||||
const isElectricityOnly = this._prefs.energy_sources.every((source) =>
|
||||
["grid", "solar", "battery"].includes(source.type)
|
||||
);
|
||||
if (isElectricityOnly) {
|
||||
return {
|
||||
views: [ELECTRICITY_VIEW],
|
||||
};
|
||||
}
|
||||
|
||||
const hasWater =
|
||||
this._prefs.energy_sources.some((source) => source.type === "water") ||
|
||||
this._prefs.device_consumption_water?.length > 0;
|
||||
|
||||
const views: LovelaceViewConfig[] = [OVERVIEW_VIEW, ELECTRICITY_VIEW];
|
||||
if (hasWater) {
|
||||
views.push(WATER_VIEW);
|
||||
}
|
||||
return { views };
|
||||
}
|
||||
|
||||
private _navigateConfig(ev) {
|
||||
@@ -252,7 +311,9 @@ class PanelEnergy extends LitElement {
|
||||
|
||||
private async _dumpCSV(ev) {
|
||||
ev.stopPropagation();
|
||||
const energyData = this._energyCollection!;
|
||||
const energyData = getEnergyDataCollection(this.hass, {
|
||||
key: "energy_dashboard",
|
||||
});
|
||||
|
||||
if (!energyData.prefs || !energyData.state.stats) {
|
||||
return;
|
||||
@@ -548,13 +609,8 @@ class PanelEnergy extends LitElement {
|
||||
fileDownload(url, "energy.csv");
|
||||
}
|
||||
|
||||
private _reloadView() {
|
||||
// Force strategy to be re-run by making a copy of the view
|
||||
const config = this._lovelace!.config;
|
||||
this._lovelace = {
|
||||
...this._lovelace!,
|
||||
config: { ...config, views: config.views.map((view) => ({ ...view })) },
|
||||
};
|
||||
private _reloadConfig() {
|
||||
this._loadConfig();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
@@ -580,45 +636,6 @@ class PanelEnergy extends LitElement {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
.header {
|
||||
background-color: var(--app-header-background-color);
|
||||
color: var(--app-header-text-color, white);
|
||||
border-bottom: var(--app-header-border-bottom, none);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: calc(
|
||||
var(--mdc-top-app-bar-width, 100%) - var(
|
||||
--safe-area-inset-right,
|
||||
0px
|
||||
)
|
||||
);
|
||||
padding-top: var(--safe-area-inset-top);
|
||||
z-index: 4;
|
||||
transition: box-shadow 200ms linear;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
-webkit-backdrop-filter: var(--app-header-backdrop-filter, none);
|
||||
backdrop-filter: var(--app-header-backdrop-filter, none);
|
||||
padding-top: var(--safe-area-inset-top);
|
||||
padding-right: var(--safe-area-inset-right);
|
||||
}
|
||||
:host([narrow]) .header {
|
||||
width: calc(
|
||||
var(--mdc-top-app-bar-width, 100%) - var(
|
||||
--safe-area-inset-left,
|
||||
0px
|
||||
) - var(--safe-area-inset-right, 0px)
|
||||
);
|
||||
padding-left: var(--safe-area-inset-left);
|
||||
}
|
||||
:host([scrolled]) .header {
|
||||
box-shadow: var(
|
||||
--mdc-top-app-bar-fixed-box-shadow,
|
||||
0px 2px 4px -1px rgba(0, 0, 0, 0.2),
|
||||
0px 4px 5px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 10px 0px rgba(0, 0, 0, 0.12)
|
||||
);
|
||||
}
|
||||
.toolbar {
|
||||
height: var(--header-height);
|
||||
display: flex;
|
||||
@@ -637,24 +654,6 @@ class PanelEnergy extends LitElement {
|
||||
line-height: var(--ha-line-height-normal);
|
||||
flex-grow: 1;
|
||||
}
|
||||
hui-view-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
padding-top: calc(var(--header-height) + var(--safe-area-inset-top));
|
||||
padding-right: var(--safe-area-inset-right);
|
||||
padding-inline-end: var(--safe-area-inset-right);
|
||||
padding-bottom: var(--safe-area-inset-bottom);
|
||||
}
|
||||
:host([narrow]) hui-view-container {
|
||||
padding-left: var(--safe-area-inset-left);
|
||||
padding-inline-start: var(--safe-area-inset-left);
|
||||
}
|
||||
hui-view {
|
||||
flex: 1 1 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
.centered {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -9,6 +9,14 @@ import type { LovelaceSectionConfig } from "../../../data/lovelace/config/sectio
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy";
|
||||
|
||||
const sourceHasCost = (source: Record<string, any>): boolean =>
|
||||
Boolean(
|
||||
source.stat_cost ||
|
||||
source.stat_compensation ||
|
||||
source.entity_energy_price ||
|
||||
source.number_energy_price
|
||||
);
|
||||
|
||||
@customElement("energy-overview-view-strategy")
|
||||
export class EnergyViewStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
@@ -64,6 +72,13 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
const hasPowerDevices = prefs.device_consumption.find(
|
||||
(device) => device.stat_rate
|
||||
);
|
||||
const hasCost = prefs.energy_sources.some(
|
||||
(source) =>
|
||||
sourceHasCost(source) ||
|
||||
(source.type === "grid" &&
|
||||
(source.flow_from?.some(sourceHasCost) ||
|
||||
source.flow_to?.some(sourceHasCost)))
|
||||
);
|
||||
|
||||
const overviewSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
@@ -88,7 +103,7 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
if (hasGrid || hasSolar || hasBattery || hasGas || hasWater) {
|
||||
if (hasCost) {
|
||||
overviewSection.cards!.push({
|
||||
type: "energy-sources-table",
|
||||
collection_key: collectionKey,
|
||||
@@ -195,6 +210,10 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
{
|
||||
type: "heading",
|
||||
heading: hass.localize("ui.panel.energy.overview.water"),
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "/energy/water",
|
||||
},
|
||||
},
|
||||
{
|
||||
title: hass.localize(
|
||||
|
||||
86
src/panels/energy/strategies/energy-water-view-strategy.ts
Normal file
86
src/panels/energy/strategies/energy-water-view-strategy.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { getEnergyDataCollection } from "../../../data/energy";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||
import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy";
|
||||
import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy";
|
||||
|
||||
@customElement("energy-water-view-strategy")
|
||||
export class EnergyWaterViewStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const view: LovelaceViewConfig = { cards: [] };
|
||||
|
||||
const collectionKey =
|
||||
_config.collection_key || DEFAULT_ENERGY_COLLECTION_KEY;
|
||||
|
||||
const energyCollection = getEnergyDataCollection(hass, {
|
||||
key: collectionKey,
|
||||
});
|
||||
const prefs = energyCollection.prefs;
|
||||
|
||||
// No water sources available
|
||||
if (
|
||||
!prefs ||
|
||||
(!prefs.device_consumption_water?.length &&
|
||||
!prefs.energy_sources.some((source) => source.type === "water"))
|
||||
) {
|
||||
return view;
|
||||
}
|
||||
|
||||
view.type = "sidebar";
|
||||
|
||||
const hasWater = prefs.energy_sources.some(
|
||||
(source) => source.type === "water"
|
||||
);
|
||||
|
||||
view.cards!.push({
|
||||
type: "energy-compare",
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
|
||||
if (hasWater) {
|
||||
view.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.energy_water_graph_title"),
|
||||
type: "energy-water-graph",
|
||||
collection_key: collectionKey,
|
||||
});
|
||||
}
|
||||
|
||||
if (hasWater) {
|
||||
view.cards!.push({
|
||||
title: hass.localize(
|
||||
"ui.panel.energy.cards.energy_sources_table_title"
|
||||
),
|
||||
type: "energy-sources-table",
|
||||
collection_key: collectionKey,
|
||||
types: ["water"],
|
||||
});
|
||||
}
|
||||
|
||||
// Only include if we have at least 1 water device in the config.
|
||||
if (prefs.device_consumption_water?.length) {
|
||||
const showFloorsNAreas = !prefs.device_consumption_water.some(
|
||||
(d) => d.included_in_stat
|
||||
);
|
||||
view.cards!.push({
|
||||
title: hass.localize("ui.panel.energy.cards.water_sankey_title"),
|
||||
type: "water-sankey",
|
||||
collection_key: collectionKey,
|
||||
group_by_floor: showFloorsNAreas,
|
||||
group_by_area: showFloorsNAreas,
|
||||
});
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"energy-water-view-strategy": EnergyWaterViewStrategy;
|
||||
}
|
||||
}
|
||||
@@ -400,7 +400,9 @@ class HaLogbookRenderer extends LitElement {
|
||||
? `${domainToName(this.hass.localize, item.context_domain)}:
|
||||
${
|
||||
this.hass.localize(
|
||||
`component.${item.context_domain}.services.${item.context_service}.name`
|
||||
`component.${item.context_domain}.services.${item.context_service}.name`,
|
||||
this.hass.services[item.context_domain][item.context_service]
|
||||
.description_placeholders
|
||||
) ||
|
||||
this.hass.services[item.context_domain]?.[item.context_service]?.name ||
|
||||
item.context_service
|
||||
|
||||
@@ -80,9 +80,10 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
|
||||
throw new Error("Entities need to be an array");
|
||||
}
|
||||
|
||||
const computedStyles = getComputedStyle(this);
|
||||
this._calendars = config!.entities.map((entity, idx) => ({
|
||||
entity_id: entity,
|
||||
backgroundColor: getColorByIndex(idx),
|
||||
backgroundColor: getColorByIndex(idx, computedStyles),
|
||||
}));
|
||||
|
||||
if (this._config?.entities !== config.entities) {
|
||||
|
||||
@@ -394,7 +394,8 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
||||
if (color) {
|
||||
return color;
|
||||
}
|
||||
color = getColorByIndex(this._colorIndex);
|
||||
const computedStyles = getComputedStyle(this);
|
||||
color = getColorByIndex(this._colorIndex, computedStyles);
|
||||
this._colorIndex++;
|
||||
this._colorDict[entityId] = color;
|
||||
return color;
|
||||
|
||||
@@ -67,7 +67,10 @@ export const handleAction = async (
|
||||
await hass.loadBackendTranslation("title");
|
||||
const localize = await hass.loadBackendTranslation("services");
|
||||
serviceName = `${domainToName(localize, domain)}: ${
|
||||
localize(`component.${domain}.services.${service}.name`) ||
|
||||
localize(
|
||||
`component.${domain}.services.${service}.name`,
|
||||
hass.services[domain][service].description_placeholders
|
||||
) ||
|
||||
serviceDomains[domain][service].name ||
|
||||
service
|
||||
}`;
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
removeSearchParam,
|
||||
} from "../../common/url/search-params";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import { isMobileClient } from "../../util/is_mobile";
|
||||
import { afterNextRender } from "../../common/util/render-status";
|
||||
import "../../components/ha-button";
|
||||
import "../../components/ha-button-menu";
|
||||
@@ -126,7 +127,7 @@ interface UndoStackItem {
|
||||
|
||||
@customElement("hui-root")
|
||||
class HUIRoot extends LitElement {
|
||||
@property({ attribute: false }) public panel?: PanelInfo<LovelacePanelConfig>;
|
||||
@property({ attribute: false }) public panel?: PanelInfo;
|
||||
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -294,7 +295,8 @@ class HUIRoot extends LitElement {
|
||||
overflowAction: this._handleShowQuickBar,
|
||||
visible: !this._editMode,
|
||||
overflow: this.narrow,
|
||||
suffix: this.hass.enableShortcuts ? "(E)" : undefined,
|
||||
suffix:
|
||||
this.hass.enableShortcuts && !isMobileClient ? "(E)" : undefined,
|
||||
},
|
||||
{
|
||||
icon: mdiCommentProcessingOutline,
|
||||
@@ -304,7 +306,8 @@ class HUIRoot extends LitElement {
|
||||
visible:
|
||||
!this._editMode && this._conversation(this.hass.config.components),
|
||||
overflow: this.narrow,
|
||||
suffix: this.hass.enableShortcuts ? "(A)" : undefined,
|
||||
suffix:
|
||||
this.hass.enableShortcuts && !isMobileClient ? "(A)" : undefined,
|
||||
},
|
||||
{
|
||||
icon: mdiRefresh,
|
||||
@@ -540,68 +543,72 @@ class HUIRoot extends LitElement {
|
||||
})}
|
||||
>
|
||||
<div class="header">
|
||||
<div class="toolbar">
|
||||
<slot name="toolbar">
|
||||
<div class="toolbar">
|
||||
${this._editMode
|
||||
? html`
|
||||
<div class="main-title">
|
||||
${dashboardTitle ||
|
||||
this.hass!.localize("ui.panel.lovelace.editor.header")}
|
||||
<ha-icon-button
|
||||
slot="actionItems"
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_lovelace.edit_title"
|
||||
)}
|
||||
.path=${mdiPencil}
|
||||
class="edit-icon"
|
||||
@click=${this._editDashboard}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`
|
||||
: html`
|
||||
${isSubview
|
||||
? html`
|
||||
<ha-icon-button-arrow-prev
|
||||
.hass=${this.hass}
|
||||
slot="navigationIcon"
|
||||
@click=${this._goBack}
|
||||
></ha-icon-button-arrow-prev>
|
||||
`
|
||||
: html`
|
||||
<ha-menu-button
|
||||
slot="navigationIcon"
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
`}
|
||||
${isSubview
|
||||
? html`
|
||||
<div class="main-title">${curViewConfig.title}</div>
|
||||
`
|
||||
: hasTabViews
|
||||
? tabs
|
||||
: html`
|
||||
<div class="main-title">
|
||||
${views[0]?.title ?? dashboardTitle}
|
||||
</div>
|
||||
`}
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`}
|
||||
</div>
|
||||
${this._editMode
|
||||
? html`
|
||||
<div class="main-title">
|
||||
${dashboardTitle ||
|
||||
this.hass!.localize("ui.panel.lovelace.editor.header")}
|
||||
<div class="tab-bar">
|
||||
${tabs}
|
||||
<ha-icon-button
|
||||
slot="actionItems"
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_lovelace.edit_title"
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPencil}
|
||||
class="edit-icon"
|
||||
@click=${this._editDashboard}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`
|
||||
: html`
|
||||
${isSubview
|
||||
? html`
|
||||
<ha-icon-button-arrow-prev
|
||||
.hass=${this.hass}
|
||||
slot="navigationIcon"
|
||||
@click=${this._goBack}
|
||||
></ha-icon-button-arrow-prev>
|
||||
`
|
||||
: html`
|
||||
<ha-menu-button
|
||||
slot="navigationIcon"
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
`}
|
||||
${isSubview
|
||||
? html`<div class="main-title">${curViewConfig.title}</div>`
|
||||
: hasTabViews
|
||||
? tabs
|
||||
: html`
|
||||
<div class="main-title">
|
||||
${views[0]?.title ?? dashboardTitle}
|
||||
</div>
|
||||
`}
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`}
|
||||
</div>
|
||||
${this._editMode
|
||||
? html`
|
||||
<div class="tab-bar">
|
||||
${tabs}
|
||||
<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
: nothing}
|
||||
</slot>
|
||||
</div>
|
||||
<hui-view-container
|
||||
class=${this._editMode ? "has-tab-bar" : ""}
|
||||
|
||||
@@ -42,6 +42,8 @@ const STRATEGIES: Record<LovelaceStrategyConfigType, Record<string, any>> = {
|
||||
import("../../energy/strategies/energy-overview-view-strategy"),
|
||||
"energy-electricity": () =>
|
||||
import("../../energy/strategies/energy-electricity-view-strategy"),
|
||||
"energy-water": () =>
|
||||
import("../../energy/strategies/energy-water-view-strategy"),
|
||||
map: () => import("./map/map-view-strategy"),
|
||||
iframe: () => import("./iframe/iframe-view-strategy"),
|
||||
area: () => import("./areas/area-view-strategy"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { getAreasFloorHierarchy } from "../../../../common/areas/areas-floor-hierarchy";
|
||||
import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
|
||||
import {
|
||||
findEntities,
|
||||
@@ -23,8 +24,8 @@ import type {
|
||||
WeatherForecastCardConfig,
|
||||
} from "../../cards/types";
|
||||
import type { CommonControlSectionStrategyConfig } from "../usage_prediction/common-controls-section-strategy";
|
||||
import { getAreasFloorHierarchy } from "../../../../common/areas/areas-floor-hierarchy";
|
||||
import { HOME_SUMMARIES_FILTERS } from "./helpers/home-summaries";
|
||||
import type { Condition } from "../../common/validate-condition";
|
||||
|
||||
export interface HomeOverviewViewStrategyConfig {
|
||||
type: "home-overview";
|
||||
@@ -70,8 +71,12 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
||||
|
||||
const floorCount = home.floors.length + (home.areas.length ? 1 : 0);
|
||||
|
||||
// Allow between 2 and 3 columns (the max should be set to define the width of the header)
|
||||
const maxColumns = 2;
|
||||
const maxColumns = 3;
|
||||
|
||||
const largeScreenCondition: Condition = {
|
||||
condition: "screen",
|
||||
media_query: "(min-width: 871px)",
|
||||
};
|
||||
|
||||
const floorsSections: LovelaceSectionConfig[] = [];
|
||||
for (const floorStructure of home.floors) {
|
||||
@@ -126,12 +131,6 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
||||
});
|
||||
}
|
||||
|
||||
const favoriteSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
column_span: maxColumns,
|
||||
cards: [],
|
||||
};
|
||||
|
||||
const favoriteEntities = (config.favorite_entities || []).filter(
|
||||
(entityId) => hass.states[entityId] !== undefined
|
||||
);
|
||||
@@ -176,74 +175,70 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
||||
({
|
||||
type: "home-summary",
|
||||
summary: "light",
|
||||
vertical: true,
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "/light?historyBack=1",
|
||||
},
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
columns: 12,
|
||||
},
|
||||
} satisfies HomeSummaryCard),
|
||||
hasClimate &&
|
||||
({
|
||||
type: "home-summary",
|
||||
summary: "climate",
|
||||
vertical: true,
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "/climate?historyBack=1",
|
||||
},
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
columns: 12,
|
||||
},
|
||||
} satisfies HomeSummaryCard),
|
||||
hasSecurity &&
|
||||
({
|
||||
type: "home-summary",
|
||||
summary: "security",
|
||||
vertical: true,
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "/security?historyBack=1",
|
||||
},
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
columns: 12,
|
||||
},
|
||||
} satisfies HomeSummaryCard),
|
||||
hasMediaPlayers &&
|
||||
({
|
||||
type: "home-summary",
|
||||
summary: "media_players",
|
||||
vertical: true,
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
navigation_path: "media-players",
|
||||
},
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
columns: 12,
|
||||
},
|
||||
} satisfies HomeSummaryCard),
|
||||
].filter(Boolean) as LovelaceCardConfig[];
|
||||
|
||||
const summarySection: LovelaceSectionConfig = {
|
||||
const forYouSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
column_span: maxColumns,
|
||||
cards: [
|
||||
{
|
||||
type: "heading",
|
||||
heading: hass.localize("ui.panel.lovelace.strategy.home.for_you"),
|
||||
heading_style: "title",
|
||||
visibility: [largeScreenCondition],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const widgetSection: LovelaceSectionConfig = {
|
||||
cards: [],
|
||||
};
|
||||
|
||||
if (summaryCards.length) {
|
||||
summarySection.cards!.push(
|
||||
{
|
||||
type: "heading",
|
||||
heading: hass.localize("ui.panel.lovelace.strategy.home.summaries"),
|
||||
},
|
||||
...summaryCards
|
||||
);
|
||||
widgetSection.cards!.push(...summaryCards);
|
||||
}
|
||||
|
||||
const weatherFilter = generateEntityFilter(hass, {
|
||||
@@ -251,28 +246,16 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
||||
entity_category: "none",
|
||||
});
|
||||
|
||||
const widgetSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
column_span: maxColumns,
|
||||
cards: [],
|
||||
};
|
||||
const weatherEntity = Object.keys(hass.states)
|
||||
.filter(weatherFilter)
|
||||
.sort()[0];
|
||||
|
||||
if (weatherEntity) {
|
||||
widgetSection.cards!.push(
|
||||
{
|
||||
type: "heading",
|
||||
heading: "",
|
||||
heading_style: "subtitle",
|
||||
},
|
||||
{
|
||||
type: "weather-forecast",
|
||||
entity: weatherEntity,
|
||||
forecast_type: "daily",
|
||||
} as WeatherForecastCardConfig
|
||||
);
|
||||
widgetSection.cards!.push({
|
||||
type: "weather-forecast",
|
||||
entity: weatherEntity,
|
||||
forecast_type: "daily",
|
||||
} as WeatherForecastCardConfig);
|
||||
}
|
||||
|
||||
const energyPrefs = isComponentLoaded(hass, "energy")
|
||||
@@ -299,11 +282,19 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
||||
|
||||
const sections = (
|
||||
[
|
||||
favoriteSection.cards && favoriteSection,
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
// Heading to add some spacing on large screens
|
||||
{
|
||||
type: "heading",
|
||||
heading_style: "subtitle",
|
||||
visibility: [largeScreenCondition],
|
||||
},
|
||||
],
|
||||
},
|
||||
commonControlsSection,
|
||||
summarySection.cards && summarySection,
|
||||
...floorsSections,
|
||||
widgetSection.cards && widgetSection,
|
||||
] satisfies (LovelaceSectionRawConfig | undefined)[]
|
||||
).filter(Boolean) as LovelaceSectionRawConfig[];
|
||||
|
||||
@@ -319,6 +310,11 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
||||
content: `## ${hass.localize("ui.panel.lovelace.strategy.home.welcome_user", { user: "{{ user }}" })}`,
|
||||
} satisfies MarkdownCardConfig,
|
||||
},
|
||||
sidebar: {
|
||||
sections: [forYouSection, widgetSection],
|
||||
content_label: hass.localize("ui.panel.lovelace.strategy.home.home"),
|
||||
sidebar_label: hass.localize("ui.panel.lovelace.strategy.home.for_you"),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
import type { HuiSection } from "../sections/hui-section";
|
||||
import type { Lovelace } from "../types";
|
||||
import "./hui-view-header";
|
||||
import "./hui-view-sidebar";
|
||||
|
||||
export const DEFAULT_MAX_COLUMNS = 4;
|
||||
|
||||
@@ -46,6 +47,8 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
@property({ attribute: false }) public isStrategy = false;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public sections: HuiSection[] = [];
|
||||
|
||||
@property({ attribute: false }) public cards: HuiCard[] = [];
|
||||
@@ -58,6 +61,12 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
@state() _dragging = false;
|
||||
|
||||
@state() private _showSidebar = false;
|
||||
|
||||
private _contentScrollTop = 0;
|
||||
|
||||
private _sidebarScrollTop = 0;
|
||||
|
||||
private _columnsController = new ResizeController(this, {
|
||||
callback: (entries) => {
|
||||
const totalWidth = entries[0]?.contentRect.width;
|
||||
@@ -135,16 +144,31 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
const sections = this.sections;
|
||||
const totalSectionCount =
|
||||
this._sectionColumnCount + (this.lovelace?.editMode ? 1 : 0);
|
||||
this._sectionColumnCount +
|
||||
(this.lovelace?.editMode ? 1 : 0) +
|
||||
(this._config?.sidebar ? 1 : 0);
|
||||
const editMode = this.lovelace.editMode;
|
||||
|
||||
const maxColumnCount = this._columnsController.value ?? 1;
|
||||
|
||||
const columnCount = Math.min(maxColumnCount, totalSectionCount);
|
||||
// On mobile with sidebar, use full width for whichever view is active
|
||||
const contentColumnCount =
|
||||
this._config?.sidebar && !this.narrow
|
||||
? Math.max(1, columnCount - 1)
|
||||
: columnCount;
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="wrapper ${classMap({
|
||||
"top-margin": Boolean(this._config?.top_margin),
|
||||
"has-sidebar": Boolean(this._config?.sidebar),
|
||||
narrow: this.narrow,
|
||||
})}"
|
||||
style=${styleMap({
|
||||
"--column-count": columnCount,
|
||||
"--content-column-count": contentColumnCount,
|
||||
})}
|
||||
>
|
||||
<hui-view-header
|
||||
.hass=${this.hass}
|
||||
@@ -152,38 +176,54 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
.lovelace=${this.lovelace}
|
||||
.viewIndex=${this.index}
|
||||
.config=${this._config?.header}
|
||||
style=${styleMap({
|
||||
"--max-column-count": maxColumnCount,
|
||||
})}
|
||||
></hui-view-header>
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
@item-moved=${this._sectionMoved}
|
||||
group="section"
|
||||
handle-selector=".handle"
|
||||
draggable-selector=".section"
|
||||
.rollback=${false}
|
||||
>
|
||||
<div
|
||||
class="container ${classMap({
|
||||
dense: Boolean(this._config?.dense_section_placement),
|
||||
})}"
|
||||
style=${styleMap({
|
||||
"--total-section-count": totalSectionCount,
|
||||
"--max-column-count": maxColumnCount,
|
||||
})}
|
||||
${this.narrow && this._config?.sidebar
|
||||
? html`
|
||||
<div class="mobile-tabs">
|
||||
<ha-control-select
|
||||
.value=${this._showSidebar ? "sidebar" : "content"}
|
||||
@value-changed=${this._viewChanged}
|
||||
.options=${[
|
||||
{
|
||||
value: "content",
|
||||
label: this._config.sidebar.content_label,
|
||||
},
|
||||
{
|
||||
value: "sidebar",
|
||||
label: this._config.sidebar.sidebar_label,
|
||||
},
|
||||
]}
|
||||
>
|
||||
</ha-control-select>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
<div class="container">
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
@item-moved=${this._sectionMoved}
|
||||
group="section"
|
||||
handle-selector=".handle"
|
||||
draggable-selector=".section"
|
||||
.rollback=${false}
|
||||
>
|
||||
${repeat(
|
||||
sections,
|
||||
(section) => this._getSectionKey(section),
|
||||
(section, idx) => {
|
||||
const columnSpan = Math.min(
|
||||
section.config.column_span || 1,
|
||||
maxColumnCount
|
||||
);
|
||||
const rowSpan = section.config.row_span || 1;
|
||||
<div
|
||||
class="content ${classMap({
|
||||
dense: Boolean(this._config?.dense_section_placement),
|
||||
"mobile-hidden": this.narrow && this._showSidebar,
|
||||
})}"
|
||||
>
|
||||
${repeat(
|
||||
sections,
|
||||
(section) => this._getSectionKey(section),
|
||||
(section, idx) => {
|
||||
const columnSpan = Math.min(
|
||||
section.config.column_span || 1,
|
||||
contentColumnCount
|
||||
);
|
||||
const rowSpan = section.config.row_span || 1;
|
||||
|
||||
return html`
|
||||
return html`
|
||||
<div
|
||||
class="section"
|
||||
style=${styleMap({
|
||||
@@ -208,72 +248,89 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
)}
|
||||
${editMode
|
||||
? html`
|
||||
<ha-sortable
|
||||
group="card"
|
||||
@item-added=${this._handleCardAdded}
|
||||
draggable-selector=".card"
|
||||
.rollback=${false}
|
||||
>
|
||||
<div class="create-section-container">
|
||||
<div class="drop-helper" aria-hidden="true">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.drop_card_create_section"
|
||||
}
|
||||
)}
|
||||
${editMode
|
||||
? html`
|
||||
<ha-sortable
|
||||
group="card"
|
||||
@item-added=${this._handleCardAdded}
|
||||
draggable-selector=".card"
|
||||
.rollback=${false}
|
||||
>
|
||||
<div class="create-section-container">
|
||||
<div class="drop-helper" aria-hidden="true">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.drop_card_create_section"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="create-section"
|
||||
@click=${this._createSection}
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.create_section"
|
||||
)}
|
||||
</p>
|
||||
.title=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.create_section"
|
||||
)}
|
||||
>
|
||||
<ha-ripple></ha-ripple>
|
||||
<ha-svg-icon .path=${mdiViewGridPlus}></ha-svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="create-section"
|
||||
@click=${this._createSection}
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.create_section"
|
||||
)}
|
||||
.title=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.create_section"
|
||||
)}
|
||||
>
|
||||
<ha-ripple></ha-ripple>
|
||||
<ha-svg-icon .path=${mdiViewGridPlus}></ha-svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ha-sortable>
|
||||
`
|
||||
: nothing}
|
||||
${editMode && this._config?.cards?.length
|
||||
? html`
|
||||
<div class="section imported-cards">
|
||||
<div class="imported-card-header">
|
||||
<p class="title">
|
||||
<ha-svg-icon .path=${mdiEyeOff}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.imported_cards_title"
|
||||
)}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.imported_cards_description"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<hui-section
|
||||
.lovelace=${this.lovelace}
|
||||
.hass=${this.hass}
|
||||
.config=${this._importedCardSectionConfig(
|
||||
this._config.cards
|
||||
</ha-sortable>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</ha-sortable>
|
||||
${this._config?.sidebar
|
||||
? html`
|
||||
<hui-view-sidebar
|
||||
class=${classMap({
|
||||
"mobile-hidden": this.narrow && !this._showSidebar,
|
||||
})}
|
||||
.hass=${this.hass}
|
||||
.badges=${this.badges}
|
||||
.lovelace=${this.lovelace}
|
||||
.viewIndex=${this.index}
|
||||
.config=${this._config.sidebar}
|
||||
></hui-view-sidebar>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<div class="imported-cards-section">
|
||||
${editMode && this._config?.cards?.length
|
||||
? html`
|
||||
<div class="section imported-cards">
|
||||
<div class="imported-card-header">
|
||||
<p class="title">
|
||||
<ha-svg-icon .path=${mdiEyeOff}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.imported_cards_title"
|
||||
)}
|
||||
.viewIndex=${this.index}
|
||||
preview
|
||||
import-only
|
||||
></hui-section>
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.imported_cards_description"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</ha-sortable>
|
||||
<hui-section
|
||||
.lovelace=${this.lovelace}
|
||||
.hass=${this.hass}
|
||||
.config=${this._importedCardSectionConfig(
|
||||
this._config.cards
|
||||
)}
|
||||
.viewIndex=${this.index}
|
||||
preview
|
||||
import-only
|
||||
></hui-section>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -352,6 +409,34 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private _viewChanged(ev: CustomEvent) {
|
||||
const newValue = ev.detail.value;
|
||||
const shouldShowSidebar = newValue === "sidebar";
|
||||
|
||||
if (shouldShowSidebar !== this._showSidebar) {
|
||||
this._toggleView();
|
||||
}
|
||||
}
|
||||
|
||||
private _toggleView() {
|
||||
// Save current scroll position
|
||||
if (this._showSidebar) {
|
||||
this._sidebarScrollTop = window.scrollY;
|
||||
} else {
|
||||
this._contentScrollTop = window.scrollY;
|
||||
}
|
||||
|
||||
this._showSidebar = !this._showSidebar;
|
||||
|
||||
// Restore scroll position after view updates
|
||||
this.updateComplete.then(() => {
|
||||
const scrollY = this._showSidebar
|
||||
? this._sidebarScrollTop
|
||||
: this._contentScrollTop;
|
||||
window.scrollTo(0, scrollY);
|
||||
});
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
--row-height: var(--ha-view-sections-row-height, 56px);
|
||||
@@ -369,14 +454,19 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper.top-margin {
|
||||
.wrapper {
|
||||
display: block;
|
||||
margin-top: var(--top-margin);
|
||||
padding: var(--row-gap) var(--column-gap);
|
||||
box-sizing: content-box;
|
||||
margin: 0 auto;
|
||||
max-width: calc(
|
||||
var(--column-count) * var(--column-max-width) +
|
||||
(var(--column-count) - 1) * var(--column-gap)
|
||||
);
|
||||
}
|
||||
|
||||
.container > * {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
.wrapper.top-margin {
|
||||
margin-top: var(--top-margin);
|
||||
}
|
||||
|
||||
.section {
|
||||
@@ -390,22 +480,92 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
}
|
||||
|
||||
.container {
|
||||
--column-count: min(var(--max-column-count), var(--total-section-count));
|
||||
display: grid;
|
||||
grid-template-columns: [content-start] repeat(
|
||||
var(--content-column-count),
|
||||
1fr
|
||||
);
|
||||
gap: var(--row-gap) var(--column-gap);
|
||||
padding: var(--row-gap) 0;
|
||||
}
|
||||
|
||||
.wrapper.has-sidebar .container {
|
||||
grid-template-columns:
|
||||
[content-start] repeat(var(--content-column-count), 1fr)
|
||||
[sidebar-start] 1fr;
|
||||
}
|
||||
|
||||
/* On mobile with sidebar, content and sidebar both take full width */
|
||||
.wrapper.narrow.has-sidebar .container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
hui-view-sidebar {
|
||||
grid-column: sidebar-start / -1;
|
||||
}
|
||||
|
||||
.wrapper.narrow hui-view-sidebar {
|
||||
grid-column: 1 / -1;
|
||||
padding-bottom: calc(
|
||||
var(--ha-space-4) + 56px + var(--ha-space-4) +
|
||||
env(safe-area-inset-bottom)
|
||||
);
|
||||
}
|
||||
|
||||
.mobile-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-tabs {
|
||||
position: fixed;
|
||||
bottom: calc(var(--ha-space-4) + env(safe-area-inset-bottom));
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0;
|
||||
z-index: 1;
|
||||
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.15))
|
||||
drop-shadow(0 4px 16px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.mobile-tabs ha-control-select {
|
||||
width: max-content;
|
||||
min-width: 280px;
|
||||
max-width: 90%;
|
||||
--control-select-thickness: 56px;
|
||||
--control-select-border-radius: var(--ha-border-radius-6xl);
|
||||
--control-select-background: var(--card-background-color);
|
||||
--control-select-background-opacity: 1;
|
||||
--control-select-color: var(--primary-color);
|
||||
--control-select-padding: 6px;
|
||||
}
|
||||
|
||||
ha-sortable {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-column: content-start / sidebar-start;
|
||||
grid-row: 1 / -1;
|
||||
display: grid;
|
||||
align-items: start;
|
||||
justify-content: center;
|
||||
grid-template-columns: repeat(var(--column-count), 1fr);
|
||||
grid-template-columns: repeat(var(--content-column-count), 1fr);
|
||||
grid-auto-flow: row;
|
||||
gap: var(--row-gap) var(--column-gap);
|
||||
padding: var(--row-gap) var(--column-gap);
|
||||
box-sizing: content-box;
|
||||
margin: 0 auto;
|
||||
max-width: calc(
|
||||
var(--column-count) * var(--column-max-width) +
|
||||
(var(--column-count) - 1) * var(--column-gap)
|
||||
}
|
||||
|
||||
.wrapper.narrow .content {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.wrapper.narrow.has-sidebar .content {
|
||||
padding-bottom: calc(
|
||||
var(--ha-space-4) + 56px + var(--ha-space-4) +
|
||||
env(safe-area-inset-bottom)
|
||||
);
|
||||
}
|
||||
.container.dense {
|
||||
|
||||
.content.dense {
|
||||
grid-auto-flow: row dense;
|
||||
}
|
||||
|
||||
@@ -483,13 +643,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
hui-view-header {
|
||||
display: block;
|
||||
padding: 0 var(--column-gap);
|
||||
padding-top: var(--row-gap);
|
||||
margin: auto;
|
||||
max-width: calc(
|
||||
var(--max-column-count) * var(--column-max-width) +
|
||||
(var(--max-column-count) - 1) * var(--column-gap)
|
||||
);
|
||||
}
|
||||
|
||||
.imported-cards {
|
||||
|
||||
57
src/panels/lovelace/views/hui-view-sidebar.ts
Normal file
57
src/panels/lovelace/views/hui-view-sidebar.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
import type { LovelaceViewSidebarConfig } from "../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "../sections/hui-section";
|
||||
import type { Lovelace } from "../types";
|
||||
|
||||
export const DEFAULT_VIEW_SIDEBAR_LAYOUT = "start";
|
||||
|
||||
@customElement("hui-view-sidebar")
|
||||
export class HuiViewSidebar extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelace!: Lovelace;
|
||||
|
||||
@property({ attribute: false }) public config?: LovelaceViewSidebarConfig;
|
||||
|
||||
@property({ attribute: false }) public viewIndex!: number;
|
||||
|
||||
render() {
|
||||
if (!this.lovelace) return nothing;
|
||||
|
||||
// Use preview mode instead of setting lovelace to avoid the sections to be
|
||||
// editable as it is not yet supported
|
||||
return html`
|
||||
<div class="container">
|
||||
${repeat(
|
||||
this.config?.sections || [],
|
||||
(section) => html`
|
||||
<hui-section
|
||||
.config=${section}
|
||||
.hass=${this.hass}
|
||||
.preview=${this.lovelace.editMode}
|
||||
.viewIndex=${this.viewIndex}
|
||||
></hui-section>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--row-gap, 8px);
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-view-sidebar": HuiViewSidebar;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ interface PassThroughNode {
|
||||
id: string;
|
||||
value: number;
|
||||
depth: number;
|
||||
sourceId: string;
|
||||
targetId: string;
|
||||
}
|
||||
|
||||
interface GraphLink extends GraphEdge {
|
||||
@@ -152,6 +154,8 @@ export function createPassThroughNode(
|
||||
id: `${sourceId}-${targetId}-${depth}`,
|
||||
value,
|
||||
depth,
|
||||
sourceId,
|
||||
targetId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -237,6 +241,79 @@ export function groupNodesBySection(
|
||||
return nodesPerSection;
|
||||
}
|
||||
|
||||
export function sortNodesInSections(
|
||||
nodesPerSection: Record<number, Node[]>,
|
||||
depths: number[]
|
||||
): Record<number, Node[]> {
|
||||
const sortedSections: Record<number, Node[]> = {};
|
||||
|
||||
depths.forEach((depth, depthIndex) => {
|
||||
const sectionNodes = nodesPerSection[depth] || [];
|
||||
|
||||
// Sort nodes to minimize crossings
|
||||
const sortedNodes = [...sectionNodes].sort((a, b) => {
|
||||
const aIsPassthrough = isPassThroughNode(a);
|
||||
const bIsPassthrough = isPassThroughNode(b);
|
||||
|
||||
// Both are passthrough nodes - sort by source position
|
||||
if (aIsPassthrough && bIsPassthrough) {
|
||||
// Find positions of source nodes in previous section (use already sorted section)
|
||||
if (depthIndex > 0) {
|
||||
const prevDepth = depths[depthIndex - 1];
|
||||
const prevSection =
|
||||
sortedSections[prevDepth] || nodesPerSection[prevDepth] || [];
|
||||
|
||||
const aSourceIndex = prevSection.findIndex((n) => {
|
||||
const nodeId = isPassThroughNode(n) ? n.id : (n as GraphNode).id;
|
||||
return nodeId === a.sourceId;
|
||||
});
|
||||
const bSourceIndex = prevSection.findIndex((n) => {
|
||||
const nodeId = isPassThroughNode(n) ? n.id : (n as GraphNode).id;
|
||||
return nodeId === b.sourceId;
|
||||
});
|
||||
|
||||
if (
|
||||
aSourceIndex !== bSourceIndex &&
|
||||
aSourceIndex !== -1 &&
|
||||
bSourceIndex !== -1
|
||||
) {
|
||||
return aSourceIndex - bSourceIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to target node positions in next section (not sorted yet, use original)
|
||||
if (depthIndex < depths.length - 1) {
|
||||
const nextDepth = depths[depthIndex + 1];
|
||||
const nextSection = nodesPerSection[nextDepth] || [];
|
||||
|
||||
const aTargetIndex = nextSection.findIndex((n) => {
|
||||
const nodeId = isPassThroughNode(n) ? n.id : (n as GraphNode).id;
|
||||
return nodeId === a.targetId;
|
||||
});
|
||||
const bTargetIndex = nextSection.findIndex((n) => {
|
||||
const nodeId = isPassThroughNode(n) ? n.id : (n as GraphNode).id;
|
||||
return nodeId === b.targetId;
|
||||
});
|
||||
|
||||
if (
|
||||
aTargetIndex !== bTargetIndex &&
|
||||
aTargetIndex !== -1 &&
|
||||
bTargetIndex !== -1
|
||||
) {
|
||||
return aTargetIndex - bTargetIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
sortedSections[depth] = sortedNodes;
|
||||
});
|
||||
|
||||
return sortedSections;
|
||||
}
|
||||
|
||||
export function createSectionNodes(nodes: Node[]): SectionNode[] {
|
||||
return nodes.map(
|
||||
(node: Node): SectionNode => ({
|
||||
@@ -337,10 +414,11 @@ function processNodes(
|
||||
);
|
||||
|
||||
const nodesPerSection = groupNodesBySection(nodes, passThroughNodes);
|
||||
const sortedNodesPerSection = sortNodesInSections(nodesPerSection, depths);
|
||||
let globalValueToSizeRatio = 0;
|
||||
|
||||
const sections = depths.map((depth) => {
|
||||
const sectionNodes = createSectionNodes(nodesPerSection[depth] || []);
|
||||
const sectionNodes = createSectionNodes(sortedNodesPerSection[depth] || []);
|
||||
const availableSpace = sectionSize - (sectionNodes.length + 1) * nodeGap;
|
||||
const totalValue = sectionNodes.reduce(
|
||||
(acc: number, node: SectionNode) => acc + node.value,
|
||||
|
||||
@@ -92,6 +92,62 @@ export const colorStyles = css`
|
||||
--black-color: #000000;
|
||||
--white-color: #ffffff;
|
||||
|
||||
/* colors - used for graphs, calendars, maps, etc */
|
||||
--color-1: #4269d0;
|
||||
--color-2: #f4bd4a;
|
||||
--color-3: #ff725c;
|
||||
--color-4: #6cc5b0;
|
||||
--color-5: #a463f2;
|
||||
--color-6: #ff8ab7;
|
||||
--color-7: #9c6b4e;
|
||||
--color-8: #97bbf5;
|
||||
--color-9: #01ab63;
|
||||
--color-10: #094bad;
|
||||
--color-11: #c99000;
|
||||
--color-12: #d84f3e;
|
||||
--color-13: #49a28f;
|
||||
--color-14: #048732;
|
||||
--color-15: #d96895;
|
||||
--color-16: #8043ce;
|
||||
--color-17: #7599d1;
|
||||
--color-18: #7a4c31;
|
||||
--color-19: #6989f4;
|
||||
--color-20: #ffd444;
|
||||
--color-21: #ff957c;
|
||||
--color-22: #8fe9d3;
|
||||
--color-23: #62cc71;
|
||||
--color-24: #ffadda;
|
||||
--color-25: #c884ff;
|
||||
--color-26: #badeff;
|
||||
--color-27: #bf8b6d;
|
||||
--color-28: #927acc;
|
||||
--color-29: #97ee3f;
|
||||
--color-30: #bf3947;
|
||||
--color-31: #9f5b00;
|
||||
--color-32: #f48758;
|
||||
--color-33: #8caed6;
|
||||
--color-34: #f2b94f;
|
||||
--color-35: #eff26e;
|
||||
--color-36: #e43872;
|
||||
--color-37: #d9b100;
|
||||
--color-38: #9d7a00;
|
||||
--color-39: #698cff;
|
||||
--color-40: #00d27e;
|
||||
--color-41: #d06800;
|
||||
--color-42: #009f82;
|
||||
--color-43: #c49200;
|
||||
--color-44: #cbe8ff;
|
||||
--color-45: #fecddf;
|
||||
--color-46: #c27eb6;
|
||||
--color-47: #8cd2ce;
|
||||
--color-48: #c4b8d9;
|
||||
--color-49: #f883b0;
|
||||
--color-50: #a49100;
|
||||
--color-51: #f48800;
|
||||
--color-52: #27d0df;
|
||||
--color-53: #a04a9b;
|
||||
--color-54: #4269d0;
|
||||
|
||||
/* history colors */
|
||||
--history-unavailable-color: transparent;
|
||||
|
||||
|
||||
@@ -7088,7 +7088,9 @@
|
||||
"unamed_device": "Unnamed device",
|
||||
"others": "Others",
|
||||
"scenes": "Scenes",
|
||||
"automations": "Automations"
|
||||
"automations": "Automations",
|
||||
"for_you": "For you",
|
||||
"home": "Home"
|
||||
},
|
||||
"common_controls": {
|
||||
"not_loaded": "Usage Prediction integration is not loaded.",
|
||||
|
||||
@@ -2,34 +2,63 @@ import { describe, test, expect } from "vitest";
|
||||
import {
|
||||
getColorByIndex,
|
||||
getGraphColorByIndex,
|
||||
COLORS,
|
||||
COLORS_COUNT,
|
||||
} from "../../../src/common/color/colors";
|
||||
import { theme2hex } from "../../../src/common/color/convert-color";
|
||||
|
||||
describe("getColorByIndex", () => {
|
||||
test("return the correct color for a given index", () => {
|
||||
expect(getColorByIndex(0)).toBe(COLORS[0]);
|
||||
expect(getColorByIndex(10)).toBe(COLORS[10]);
|
||||
test("return the correct color from CSS variable", () => {
|
||||
const style = {
|
||||
getPropertyValue: (prop) => {
|
||||
if (prop === "--color-1") return "#4269d0";
|
||||
if (prop === "--color-11") return "#c99000";
|
||||
return "";
|
||||
},
|
||||
} as CSSStyleDeclaration;
|
||||
expect(getColorByIndex(0, style)).toBe(theme2hex("#4269d0"));
|
||||
expect(getColorByIndex(10, style)).toBe(theme2hex("#c99000"));
|
||||
});
|
||||
|
||||
test("wrap around if the index is greater than the length of COLORS", () => {
|
||||
expect(getColorByIndex(COLORS.length)).toBe(COLORS[0]);
|
||||
expect(getColorByIndex(COLORS.length + 4)).toBe(COLORS[4]);
|
||||
test("wrap around if the index is greater than the total count", () => {
|
||||
const style = {
|
||||
getPropertyValue: (prop) => {
|
||||
if (prop === "--color-1") return "#4269d0";
|
||||
if (prop === "--color-5") return "#a463f2";
|
||||
return "";
|
||||
},
|
||||
} as CSSStyleDeclaration;
|
||||
// Index 54 should wrap to color 1
|
||||
expect(getColorByIndex(COLORS_COUNT, style)).toBe(theme2hex("#4269d0"));
|
||||
// Index 58 should wrap to color 5
|
||||
expect(getColorByIndex(COLORS_COUNT + 4, style)).toBe(theme2hex("#a463f2"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("getGraphColorByIndex", () => {
|
||||
test("return the correct theme color if it exists", () => {
|
||||
test("return color from --graph-color variable when it exists", () => {
|
||||
const style = {
|
||||
getPropertyValue: (prop) => (prop === "--graph-color-1" ? "#123456" : ""),
|
||||
} as CSSStyleDeclaration;
|
||||
expect(getGraphColorByIndex(0, style)).toBe(theme2hex("#123456"));
|
||||
});
|
||||
|
||||
test("return the default color if the theme color does not exist", () => {
|
||||
test("fallback to --color variable when --graph-color does not exist", () => {
|
||||
const style = {
|
||||
getPropertyValue: () => "",
|
||||
} as unknown as CSSStyleDeclaration;
|
||||
expect(getGraphColorByIndex(0, style)).toBe(theme2hex(COLORS[0]));
|
||||
getPropertyValue: (prop) => (prop === "--color-5" ? "#abcdef" : ""),
|
||||
} as CSSStyleDeclaration;
|
||||
// Index 4 should try --graph-color-5, then fallback to --color-5
|
||||
expect(getGraphColorByIndex(4, style)).toBe(theme2hex("#abcdef"));
|
||||
});
|
||||
|
||||
test("prefer --graph-color over --color when both exist", () => {
|
||||
const style = {
|
||||
getPropertyValue: (prop) => {
|
||||
if (prop === "--graph-color-1") return "#111111";
|
||||
if (prop === "--color-1") return "#222222";
|
||||
return "";
|
||||
},
|
||||
} as CSSStyleDeclaration;
|
||||
// Should prefer --graph-color-1
|
||||
expect(getGraphColorByIndex(0, style)).toBe(theme2hex("#111111"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,6 +67,8 @@ describe("Sankey Layout Functions", () => {
|
||||
id: "test",
|
||||
value: 10,
|
||||
depth: 1,
|
||||
sourceId: "source",
|
||||
targetId: "target",
|
||||
};
|
||||
expect(isPassThroughNode(passThroughNode)).toBe(true);
|
||||
});
|
||||
@@ -142,7 +144,14 @@ describe("Sankey Layout Functions", () => {
|
||||
];
|
||||
|
||||
const passThroughNodes = [
|
||||
{ id: "pt1", depth: 1, passThrough: true, value: 5 },
|
||||
{
|
||||
id: "pt1",
|
||||
depth: 1,
|
||||
passThrough: true,
|
||||
value: 5,
|
||||
sourceId: "node1",
|
||||
targetId: "node2",
|
||||
},
|
||||
];
|
||||
|
||||
const result = groupNodesBySection(
|
||||
@@ -195,6 +204,8 @@ describe("Sankey Layout Functions", () => {
|
||||
passThrough: true,
|
||||
value: 5,
|
||||
depth: 1,
|
||||
sourceId: "source",
|
||||
targetId: "target",
|
||||
};
|
||||
|
||||
const result = createSectionNodes([passThroughNode]);
|
||||
@@ -316,13 +327,15 @@ describe("Sankey Layout Functions", () => {
|
||||
|
||||
describe("createPassThroughNode", () => {
|
||||
it("should create a pass-through node", () => {
|
||||
const result = createPassThroughNode("source-target", "section1", 2, 15);
|
||||
const result = createPassThroughNode("source", "target", 2, 15);
|
||||
|
||||
expect(result).toEqual({
|
||||
passThrough: true,
|
||||
id: "source-target-section1-2",
|
||||
id: "source-target-2",
|
||||
value: 15,
|
||||
depth: 2,
|
||||
sourceId: "source",
|
||||
targetId: "target",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
449
yarn.lock
449
yarn.lock
@@ -5,10 +5,10 @@ __metadata:
|
||||
version: 8
|
||||
cacheKey: 10
|
||||
|
||||
"@acemir/cssom@npm:^0.9.19":
|
||||
version: 0.9.19
|
||||
resolution: "@acemir/cssom@npm:0.9.19"
|
||||
checksum: 10/1c7066c002c170d5a775533cb83ff7eb7415a8cc514995325c3d135803fa4a3feffccf21ba0b520b804cdc5fccef8476d7ef83d0e4876dd7bd007ab64d535588
|
||||
"@acemir/cssom@npm:^0.9.23":
|
||||
version: 0.9.23
|
||||
resolution: "@acemir/cssom@npm:0.9.23"
|
||||
checksum: 10/752294359ddf691f402bf871f347c1d5ea8532ead5e197cf60eeb7ab25bdd6f6e98fc7fad74042f2e423bb45fe7e4a049db645e01fa0781a0ed4ea2cec911047
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -38,7 +38,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@asamuzakjp/dom-selector@npm:^6.7.3":
|
||||
"@asamuzakjp/dom-selector@npm:^6.7.4":
|
||||
version: 6.7.4
|
||||
resolution: "@asamuzakjp/dom-selector@npm:6.7.4"
|
||||
dependencies:
|
||||
@@ -1215,15 +1215,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@codemirror/autocomplete@npm:6.19.1":
|
||||
version: 6.19.1
|
||||
resolution: "@codemirror/autocomplete@npm:6.19.1"
|
||||
"@codemirror/autocomplete@npm:6.20.0":
|
||||
version: 6.20.0
|
||||
resolution: "@codemirror/autocomplete@npm:6.20.0"
|
||||
dependencies:
|
||||
"@codemirror/language": "npm:^6.0.0"
|
||||
"@codemirror/state": "npm:^6.0.0"
|
||||
"@codemirror/view": "npm:^6.17.0"
|
||||
"@lezer/common": "npm:^1.0.0"
|
||||
checksum: 10/6b5a6f3eb869057696c8e1e601eec97f4c68eebb6ca3890d0aea264b2e7888c555a57c74ae53731d3bc2cc98466be1778cc64b0f7f591ba90b61cd334e7095a8
|
||||
checksum: 10/ba3603b860c30dd4f8b7c20085680d2f491022db95fe1f3aa6a58363c64678efb3ba795d715755c8a02121631317cf7fbe44cfa3b4cdb01ebca2b4ed36ea5d8a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1282,15 +1282,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@codemirror/view@npm:6.38.6, @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.38.6
|
||||
resolution: "@codemirror/view@npm:6.38.6"
|
||||
"@codemirror/view@npm:6.38.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.38.8
|
||||
resolution: "@codemirror/view@npm:6.38.8"
|
||||
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/5a047337a98de111817ce8c8d39e6429c90ca0b0a4d2678d6e161e9e5961b1d476a891f447ab7a05cac395d4a93530e7c68bedd93191285265f0742a308ad00b
|
||||
checksum: 10/81b1508015a378e4719d0239254173f0c5cd340c2abf96eb488fe5fb474bdb37ec1f010b9890ced774accd7aeb9443e7337cb6a89544b954273e5ddabece7cea
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2365,10 +2365,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lokalise/node-api@npm:15.3.1":
|
||||
version: 15.3.1
|
||||
resolution: "@lokalise/node-api@npm:15.3.1"
|
||||
checksum: 10/9175559660cfbde3f6451ee0ade96ca5ccf6686f3a8f07a23ae6abf3a58db5b5dc71683cdb7f19252765250df7b77dc67539a80e24c3b44a1a97bb2f2d9cd090
|
||||
"@lokalise/node-api@npm:15.4.0":
|
||||
version: 15.4.0
|
||||
resolution: "@lokalise/node-api@npm:15.4.0"
|
||||
checksum: 10/fe7e36bb137310244079fba9978a10fdf65ca6566e075e8e25ed0fd461e7168649ca43929a0a3a0eaf2df72055996ef4d8a72302e7b502863feb9f9a6471aff1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4520,10 +4520,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/emscripten@npm:^1.41.2":
|
||||
version: 1.41.2
|
||||
resolution: "@types/emscripten@npm:1.41.2"
|
||||
checksum: 10/95bc5acddaab2155a1fbe0c816717a2552b8d4df484d4bb8b6962b9f2e65c7a8d81872d6e80d706384608e9ea0cde07f852b3069e12921c2b445c6fb48bd985b
|
||||
"@types/emscripten@npm:^1.41.5":
|
||||
version: 1.41.5
|
||||
resolution: "@types/emscripten@npm:1.41.5"
|
||||
checksum: 10/60dfcced39b2d0c94f31907c5cf5d97fe06ed35ed6cb134650a1a96bae861302722d4a6f459b484ea09588cde70cbcc034974454a746be3ce9688b52398d2953
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4945,106 +4945,106 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.46.3"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.47.0"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.10.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.46.3"
|
||||
"@typescript-eslint/type-utils": "npm:8.46.3"
|
||||
"@typescript-eslint/utils": "npm:8.46.3"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.46.3"
|
||||
"@typescript-eslint/scope-manager": "npm:8.47.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.47.0"
|
||||
"@typescript-eslint/utils": "npm:8.47.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.47.0"
|
||||
graphemer: "npm:^1.4.0"
|
||||
ignore: "npm:^7.0.0"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.46.3
|
||||
"@typescript-eslint/parser": ^8.47.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/0c1eb81a43f1d04fdd79c4e59f9f0687b86735ae6c98d94fe5eb021da2f83e0e2426a2922fe94296fb0a9ab131d53fe4cde8b54d0948d7b23e01e648a318bd1c
|
||||
checksum: 10/53d86116a39429c0cdde5969f9ea2cf712f7c7cb2ed023088a876686a4771df131dbefda7645ba0724e2a5a0532e14bdffcb92c708060a46a8607dc5243083d1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/parser@npm:8.46.3"
|
||||
"@typescript-eslint/parser@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.46.3"
|
||||
"@typescript-eslint/types": "npm:8.46.3"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.46.3"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.46.3"
|
||||
"@typescript-eslint/scope-manager": "npm:8.47.0"
|
||||
"@typescript-eslint/types": "npm:8.47.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.47.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.47.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/d36edeba9ce37d219115fb101a4496bca2685969b217d0f64c0c255867a8793a8b41a95b86e26775a09b3abbb7c5b93ef712ea9a0fba3d055dcf385b17825075
|
||||
checksum: 10/e7213296a27b78511b8c9b2627ff6530d0eb31e6b076eef6f34f11ca7fbcb7e998a2fa079bfc1563a53f9d88326aa4af995241bcdf08a15c3e5be0d13fdff2d7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/project-service@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/project-service@npm:8.46.3"
|
||||
"@typescript-eslint/project-service@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.46.3"
|
||||
"@typescript-eslint/types": "npm:^8.46.3"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.47.0"
|
||||
"@typescript-eslint/types": "npm:^8.47.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/2f041dfc664209b6a213cf585df28d0913ddf81916b83119c897a10dd9ad20dcd0ee3c523ee95440f498da6ba9d6e50cf08852418c0a2ebddd92c7a7cd295736
|
||||
checksum: 10/e2f935dae66ce27e6c0cce8b750da0e8fe84b6e0fa248bf8210b84eec3c4d2e2679a878185f445ce507d132215a676dcf8a21d47ab70c547da47ede000a128e1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.46.3"
|
||||
"@typescript-eslint/scope-manager@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.46.3"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.46.3"
|
||||
checksum: 10/6bb6c3210bfcca59cf60860b51bfae8d28b01d074a8608b6f24b3290952ff74103e08d390d11cbf613812fca04aa55ad14ad9da04c3041e23acdca235ab1ff78
|
||||
"@typescript-eslint/types": "npm:8.47.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.47.0"
|
||||
checksum: 10/e97ae0f746f6bb5706181a973bcc0c1268706ef7e8c18594b37168bb0b41b1673d3f0ba1a2575ee3bd121066500fdc75af313f6ad283198942a5cdb65ade7621
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.46.3, @typescript-eslint/tsconfig-utils@npm:^8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.46.3"
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.47.0, @typescript-eslint/tsconfig-utils@npm:^8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.47.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/e7a16eadf79483d4b61dee56a08d032bafe26d44d634e7863a5875dbb44393570896641272a4e9810f4eac76a4109f59ad667b036d7627ef1647dc672ea19c5e
|
||||
checksum: 10/7f44441da3778928937419f8ebc62939538cf30087e56c0ca56f599ce98111b82f496902a9e15d713822b9cd14b17937d57b722468450a48748f8e50fd7161af
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.46.3"
|
||||
"@typescript-eslint/type-utils@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.46.3"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.46.3"
|
||||
"@typescript-eslint/utils": "npm:8.46.3"
|
||||
"@typescript-eslint/types": "npm:8.47.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.47.0"
|
||||
"@typescript-eslint/utils": "npm:8.47.0"
|
||||
debug: "npm:^4.3.4"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/b29cd001c715033ec9cd5fdf2723915f1b4c6c9342283ed00d20e4b942117625facba9a2cf3914b06633c2af9a167430f8f134323627adb0be85f73da4e89d72
|
||||
checksum: 10/07dcdd1ac071bbaf87b6b320d107129787a62cc403ce78e081cbe5e2ed0c576d660654e4117e6224c4c23d46919d7130b70801835d2fc41d9344c47ff946ce81
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.46.3, @typescript-eslint/types@npm:^8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/types@npm:8.46.3"
|
||||
checksum: 10/3de35df2ec2f2937c8f6eb262cd49f34500a18d01e0d8da6f348afd621f6c222c41d4ea15203ebbf0bd59814aa2b4c83fde7eb6d4aad1fa1514ee7a742887c6a
|
||||
"@typescript-eslint/types@npm:8.47.0, @typescript-eslint/types@npm:^8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/types@npm:8.47.0"
|
||||
checksum: 10/fc42416c01c512cfe1533bdf521925bca999adc68ffefa246e48552783f1fe9d22487d912611c5cb35fca481604aae3cab88279a53ce76c7cd7510b76775c078
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.46.3"
|
||||
"@typescript-eslint/typescript-estree@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service": "npm:8.46.3"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.46.3"
|
||||
"@typescript-eslint/types": "npm:8.46.3"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.46.3"
|
||||
"@typescript-eslint/project-service": "npm:8.47.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.47.0"
|
||||
"@typescript-eslint/types": "npm:8.47.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.47.0"
|
||||
debug: "npm:^4.3.4"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
is-glob: "npm:^4.0.3"
|
||||
@@ -5053,32 +5053,32 @@ __metadata:
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/b55cf72fe3dff0b9bdf9b1793e43fdb2789fa6d706ba7d69fb94801bea82041056a95659bd8fe1e6f026787b2e8d0f8d060149841095a0a82044e3469b8d82cd
|
||||
checksum: 10/a480e83f1fca8a389642cbb18855ef25214c4765694b1d4a74051d2653a4fbbbf3a3cc4e544d1ecb79d49958fbf819246043c0d823d4384aa1c7b5ff79d02fcc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/utils@npm:8.46.3"
|
||||
"@typescript-eslint/utils@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.47.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.7.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.46.3"
|
||||
"@typescript-eslint/types": "npm:8.46.3"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.46.3"
|
||||
"@typescript-eslint/scope-manager": "npm:8.47.0"
|
||||
"@typescript-eslint/types": "npm:8.47.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.47.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/369c962bc20a2a6022ef4533ad55ab4e3d2403e7e200505b29fae6f0b8fc99be8fe149d929781f5ead0d3f88f2c74904f60aaa3771e6773e2b7dd8f61f07a534
|
||||
checksum: 10/e165bbcaaafb88761f12272bc4b3be1631d8a8ea319765c80cfe5bf7a5858f437486eeae177643baa213570a664f0254b41bf0541e9238b57080bb30d1a2c8ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.46.3"
|
||||
"@typescript-eslint/visitor-keys@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.46.3"
|
||||
"@typescript-eslint/types": "npm:8.47.0"
|
||||
eslint-visitor-keys: "npm:^4.2.1"
|
||||
checksum: 10/02659a4cc4780d677907ed7e356e18b941e0ed18883acfda0d74d3e388144f90aa098b8fcdc2f4c01e9e6b60ac6154d1afb009feb6169c483260a5c8b4891171
|
||||
checksum: 10/1e184cdebc4ab15da8a46ae2624ba4543c6bea83ced80a1602da99b72c00b5f6ea913ae021823c555a35a65bb9a9df09d119713998c44b00eba25e1407844294
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5368,12 +5368,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/coverage-v8@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/coverage-v8@npm:4.0.8"
|
||||
"@vitest/coverage-v8@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/coverage-v8@npm:4.0.13"
|
||||
dependencies:
|
||||
"@bcoe/v8-coverage": "npm:^1.0.2"
|
||||
"@vitest/utils": "npm:4.0.8"
|
||||
"@vitest/utils": "npm:4.0.13"
|
||||
ast-v8-to-istanbul: "npm:^0.3.8"
|
||||
debug: "npm:^4.4.3"
|
||||
istanbul-lib-coverage: "npm:^3.2.2"
|
||||
@@ -5384,34 +5384,34 @@ __metadata:
|
||||
std-env: "npm:^3.10.0"
|
||||
tinyrainbow: "npm:^3.0.3"
|
||||
peerDependencies:
|
||||
"@vitest/browser": 4.0.8
|
||||
vitest: 4.0.8
|
||||
"@vitest/browser": 4.0.13
|
||||
vitest: 4.0.13
|
||||
peerDependenciesMeta:
|
||||
"@vitest/browser":
|
||||
optional: true
|
||||
checksum: 10/f97d933c7a776eccbd293fd3f77c0dcdc683e528094ce802b2b309e282c01cca0e8ad51a03b61ec623da7034527879824df2e30f70062d7ca587db40bfa5ffd2
|
||||
checksum: 10/5bbbf72f8da7931c120636b12feb655ae102b4f1ef67481c03fd9a007727fe9d707653896798ff6c477fff3a0f260151ae753e0b69a2493522b5007c84bf9a43
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/expect@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/expect@npm:4.0.8"
|
||||
"@vitest/expect@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/expect@npm:4.0.13"
|
||||
dependencies:
|
||||
"@standard-schema/spec": "npm:^1.0.0"
|
||||
"@types/chai": "npm:^5.2.2"
|
||||
"@vitest/spy": "npm:4.0.8"
|
||||
"@vitest/utils": "npm:4.0.8"
|
||||
chai: "npm:^6.2.0"
|
||||
"@vitest/spy": "npm:4.0.13"
|
||||
"@vitest/utils": "npm:4.0.13"
|
||||
chai: "npm:^6.2.1"
|
||||
tinyrainbow: "npm:^3.0.3"
|
||||
checksum: 10/342934870fb2b11b7a47db4df2a9df2b711087fe48118568ac013386cd659b9bff8f8252bef643e9519a88d018d54e6758a733c9dedf907e9d5dc53040aa0dc3
|
||||
checksum: 10/13c0e66e4eeaf56bbf1c57aeabe271a186966de97bd273266910aa45391479167cf3749f18b404035bde5f1822ce4a370b1a1e9101c8f8ef658c885b687b4e50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/mocker@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/mocker@npm:4.0.8"
|
||||
"@vitest/mocker@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/mocker@npm:4.0.13"
|
||||
dependencies:
|
||||
"@vitest/spy": "npm:4.0.8"
|
||||
"@vitest/spy": "npm:4.0.13"
|
||||
estree-walker: "npm:^3.0.3"
|
||||
magic-string: "npm:^0.30.21"
|
||||
peerDependencies:
|
||||
@@ -5422,54 +5422,54 @@ __metadata:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
checksum: 10/6a624e04a6fa78cc45205961bd0638486674d1cbf4589599772fdd49f58f433c821bcb1eea013ac772171fb9c81154e6f9ffcf1704f27e245860e982c3988cd4
|
||||
checksum: 10/339f86523bfca84fc9b7efa10f0b4362078c4d5137556d026cc4c163bb13f878412769bbbffeb7772c27c8360bd75a50a8acf7e9fc8b237236dffed4a07f95b7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/pretty-format@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/pretty-format@npm:4.0.8"
|
||||
"@vitest/pretty-format@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/pretty-format@npm:4.0.13"
|
||||
dependencies:
|
||||
tinyrainbow: "npm:^3.0.3"
|
||||
checksum: 10/7e438ba6875a72b58cfe429dedc1de3025c8f87f523db24c687b2ad298e0c1a3e171e7e22ab938518a52c44383acff58d3e9936620dc45f4e97f1669e3e275da
|
||||
checksum: 10/734c6a4d1f7c567bbff7a7855aa90360a46d4f0c221db66d9d63ff7a690a4fd89e36e9eb8db9acf5647bcab9eb3c6625e8d06cc7e1b46321bf7d514375524c8d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/runner@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/runner@npm:4.0.8"
|
||||
"@vitest/runner@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/runner@npm:4.0.13"
|
||||
dependencies:
|
||||
"@vitest/utils": "npm:4.0.8"
|
||||
"@vitest/utils": "npm:4.0.13"
|
||||
pathe: "npm:^2.0.3"
|
||||
checksum: 10/cb66c1121c2701bb2400fb0969b7504aee34b400278d03f1ed19d78f8180adb88dbbd0f3f5d4ff1db49a5ae50f0e139964ff7ae32aa1d99f6e9d91d6a57c1ffe
|
||||
checksum: 10/f6d92620653b18ff7e897c7e9e74d52603a4ffecb5bedde28f2ad763584728a2581de75b19de0da896fac5f68b5e5c1dce3f4fc71fc616c31e90a9823dcf6ebf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/snapshot@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/snapshot@npm:4.0.8"
|
||||
"@vitest/snapshot@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/snapshot@npm:4.0.13"
|
||||
dependencies:
|
||||
"@vitest/pretty-format": "npm:4.0.8"
|
||||
"@vitest/pretty-format": "npm:4.0.13"
|
||||
magic-string: "npm:^0.30.21"
|
||||
pathe: "npm:^2.0.3"
|
||||
checksum: 10/d703a4bb4979f94cc9b3c8ecaf5ce9c4741066772f1d4414db7faa1d1ed209ad5da9c85a98118e340f5f5652d680a1895efa39c060b6e3700a95806eefdf40a7
|
||||
checksum: 10/1d7337389432cb02ab42650d32e4c09af2ac45cfb5880c85fca089c901d236252b71e849bc45a992ad371834e84308f2b723c741ea090f50675a1509a1d29d7c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/spy@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/spy@npm:4.0.8"
|
||||
checksum: 10/944223ffef7d64299d92c94ab895209b27a307ef59d2ef6f5c6c006fc1e85612c9547069b0fde7b2d93adfa484b3770b459a716f6b82f8839226132767fb661c
|
||||
"@vitest/spy@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/spy@npm:4.0.13"
|
||||
checksum: 10/55fce93d47b0812726a213ca96265661a3b64267a392ff5d6fc8270f57492653e1bfab62c0fd0c5788b859d91219b6b43ad932d7921bdc80b47da3cf6dea9dd9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/utils@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "@vitest/utils@npm:4.0.8"
|
||||
"@vitest/utils@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "@vitest/utils@npm:4.0.13"
|
||||
dependencies:
|
||||
"@vitest/pretty-format": "npm:4.0.8"
|
||||
"@vitest/pretty-format": "npm:4.0.13"
|
||||
tinyrainbow: "npm:^3.0.3"
|
||||
checksum: 10/9f241a8aafbd81caec766143c8c99b8e1e76671460ff6bd1fc0921ea968c2f0d3d8305551b52509c0fb427d436ec9e2f75cafdc273d2f23c1ccaea504269a160
|
||||
checksum: 10/0b0a5d4cc23a4b1cb481f1b31e51fe0f8021bc67478b494f08490f6690d866dedc026275850ce3104c34462ee7b415afb35a3692ced642dfa8339890fa88649e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6108,12 +6108,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"barcode-detector@npm:3.0.6":
|
||||
version: 3.0.6
|
||||
resolution: "barcode-detector@npm:3.0.6"
|
||||
"barcode-detector@npm:3.0.8":
|
||||
version: 3.0.8
|
||||
resolution: "barcode-detector@npm:3.0.8"
|
||||
dependencies:
|
||||
zxing-wasm: "npm:2.2.2"
|
||||
checksum: 10/c1d4fbeecbb0be8f91e15c2bfdaaf3b27e3fd6fe224e60c4c25793a3bf90bab844702956de2f596a8e3229d2b4e0d88b42fb629472efc0b36a3751c3b01b7151
|
||||
zxing-wasm: "npm:2.2.4"
|
||||
checksum: 10/7de6225f659c69a0f4101d080a9e0812f2404c485fa2406424b8b13eaff274f6e7405c94de24827a09def52c32a63b19b9c9fba61c5274b074d558f696ec1684
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6479,10 +6479,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chai@npm:^6.2.0":
|
||||
version: 6.2.0
|
||||
resolution: "chai@npm:6.2.0"
|
||||
checksum: 10/199422854e253d8711ea3f220365c6a850c450abf68b31131d2a0f703cbfc5cb48e6c81567e0adbe80e83cdcae6dba82d069a41a77c16bdf6703329c5c3447ef
|
||||
"chai@npm:^6.2.1":
|
||||
version: 6.2.1
|
||||
resolution: "chai@npm:6.2.1"
|
||||
checksum: 10/f7917749e2468bd3a17ee4769b680e440002960c1294dd11c6d3ad102b5db9ea1a43e3ad9462b7b0f1502e5c845a6e39ce63db9de1def782e44652018c48acb7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6699,10 +6699,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"color-name@npm:2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "color-name@npm:2.0.2"
|
||||
checksum: 10/58e5fa3853a0dac813179e75a1fe07ff362abacb9fd456fcaae702b74d4ed5f6de2cbaee07ff2660f3495c7a6ceabc4ef0420165db0018e7150a6d4045f6539e
|
||||
"color-name@npm:2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "color-name@npm:2.1.0"
|
||||
checksum: 10/eb014f71d87408e318e95d3f554f188370d354ba8e0ffa4341d0fd19de391bfe2bc96e563d4f6614644d676bc24f475560dffee3fe310c2d6865d007410a9a2b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6743,10 +6743,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"commander@npm:^14.0.1":
|
||||
version: 14.0.1
|
||||
resolution: "commander@npm:14.0.1"
|
||||
checksum: 10/783115e9403caeca29c0fcbd4e0358f70c67760e4e4933f3453fcdd5ddba2ec44173c8da5213d7ce5e404f51c7e71203a42c548164dbe27b668b32a8981577f1
|
||||
"commander@npm:^14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "commander@npm:14.0.2"
|
||||
checksum: 10/2d202db5e5f9bb770112a3c1579b893d17ac6f6d932183077308bdd96d0f87f0bbe6a68b5b9ed2cf3b2514be6bb7de637480703c0e2db9741ee1b383237deb26
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6902,10 +6902,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"core-js@npm:3.46.0":
|
||||
version: 3.46.0
|
||||
resolution: "core-js@npm:3.46.0"
|
||||
checksum: 10/82993ca487c6cbbf8bbf00e45eeb9705eb63dc2f9c90d7f35696733efbc3f4b52426e1f8dbef0f0b68ea16caa21e4f44cc5490e08120e1cad4a72b031ed8adaa
|
||||
"core-js@npm:3.47.0":
|
||||
version: 3.47.0
|
||||
resolution: "core-js@npm:3.47.0"
|
||||
checksum: 10/c02dc6a091c7e6799e3527dc06a428c44bbcff7f8f6ee700ff818b90aa2ebaf1f17b0234146e692811da97cda5a39a6095ecadec9fd1a74b1135103eb0e96cb1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6975,14 +6975,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssstyle@npm:^5.3.2":
|
||||
version: 5.3.2
|
||||
resolution: "cssstyle@npm:5.3.2"
|
||||
"cssstyle@npm:^5.3.3":
|
||||
version: 5.3.3
|
||||
resolution: "cssstyle@npm:5.3.3"
|
||||
dependencies:
|
||||
"@asamuzakjp/css-color": "npm:^4.0.3"
|
||||
"@csstools/css-syntax-patches-for-csstree": "npm:^1.0.14"
|
||||
css-tree: "npm:^3.1.0"
|
||||
checksum: 10/2f628254c738556c6394dbe705d7cadd8a8867767feb00bc8a4980a43b405fc891f72687cc2f04a8b15185009e9713f0f96bc9311e7781d848b0d145056b9f1f
|
||||
checksum: 10/8c6133761395f03d50e74ff4c05473b4835b79013efed3f4b79dc452d94a7122082887d89c3c1164bba0e8919be209b75e4f4706197c086fc9f4b50182ab03d6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9184,10 +9184,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hls.js@npm:1.6.14":
|
||||
version: 1.6.14
|
||||
resolution: "hls.js@npm:1.6.14"
|
||||
checksum: 10/56eedf163912abf72bd5ca0eac44dbaa442cff59bb8d1ff3303614bf18d21dfa3ec7b85db5b71449986c52c63b7efb6bd5392b048bf22c61549f71a001fa94cd
|
||||
"hls.js@npm:1.6.15":
|
||||
version: 1.6.15
|
||||
resolution: "hls.js@npm:1.6.15"
|
||||
checksum: 10/c385f8b5ed541d658d2c7f8616d6aef6064855f6d70ad4e1d0e9696d35820394e4d170e53891530098d648108ce68af948d726a4fad73c99fda274c9e68aa49c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9202,13 +9202,13 @@ __metadata:
|
||||
"@babel/runtime": "npm:7.28.4"
|
||||
"@braintree/sanitize-url": "npm:7.1.1"
|
||||
"@bundle-stats/plugin-webpack-filter": "npm:4.21.6"
|
||||
"@codemirror/autocomplete": "npm:6.19.1"
|
||||
"@codemirror/autocomplete": "npm:6.20.0"
|
||||
"@codemirror/commands": "npm:6.10.0"
|
||||
"@codemirror/language": "npm:6.11.3"
|
||||
"@codemirror/legacy-modes": "npm:6.5.2"
|
||||
"@codemirror/search": "npm:6.5.11"
|
||||
"@codemirror/state": "npm:6.5.2"
|
||||
"@codemirror/view": "npm:6.38.6"
|
||||
"@codemirror/view": "npm:6.38.8"
|
||||
"@date-fns/tz": "npm:1.4.1"
|
||||
"@egjs/hammerjs": "npm:2.0.17"
|
||||
"@formatjs/intl-datetimeformat": "npm:6.18.2"
|
||||
@@ -9233,7 +9233,7 @@ __metadata:
|
||||
"@lit-labs/virtualizer": "npm:2.1.1"
|
||||
"@lit/context": "npm:1.1.6"
|
||||
"@lit/reactive-element": "npm:2.1.1"
|
||||
"@lokalise/node-api": "npm:15.3.1"
|
||||
"@lokalise/node-api": "npm:15.4.0"
|
||||
"@material/chips": "npm:=14.0.0-canary.53b3cad2f.0"
|
||||
"@material/data-table": "npm:=14.0.0-canary.53b3cad2f.0"
|
||||
"@material/mwc-base": "npm:0.27.0"
|
||||
@@ -9291,18 +9291,18 @@ __metadata:
|
||||
"@vaadin/combo-box": "npm:24.9.5"
|
||||
"@vaadin/vaadin-themable-mixin": "npm:24.9.5"
|
||||
"@vibrant/color": "npm:4.0.0"
|
||||
"@vitest/coverage-v8": "npm:4.0.8"
|
||||
"@vitest/coverage-v8": "npm:4.0.13"
|
||||
"@vue/web-component-wrapper": "npm:1.3.0"
|
||||
"@webcomponents/scoped-custom-element-registry": "npm:0.0.10"
|
||||
"@webcomponents/webcomponentsjs": "npm:2.8.0"
|
||||
app-datepicker: "npm:5.1.1"
|
||||
babel-loader: "npm:10.0.0"
|
||||
babel-plugin-template-html-minifier: "npm:4.1.0"
|
||||
barcode-detector: "npm:3.0.6"
|
||||
barcode-detector: "npm:3.0.8"
|
||||
browserslist-useragent-regexp: "npm:4.1.3"
|
||||
color-name: "npm:2.0.2"
|
||||
color-name: "npm:2.1.0"
|
||||
comlink: "npm:4.4.2"
|
||||
core-js: "npm:3.46.0"
|
||||
core-js: "npm:3.47.0"
|
||||
cropperjs: "npm:1.6.2"
|
||||
culori: "npm:4.0.2"
|
||||
date-fns: "npm:4.1.0"
|
||||
@@ -9331,19 +9331,19 @@ __metadata:
|
||||
gulp-json-transform: "npm:0.5.0"
|
||||
gulp-rename: "npm:2.1.0"
|
||||
gulp-zopfli-green: "npm:6.0.2"
|
||||
hls.js: "npm:1.6.14"
|
||||
hls.js: "npm:1.6.15"
|
||||
home-assistant-js-websocket: "npm:9.6.0"
|
||||
html-minifier-terser: "npm:7.2.0"
|
||||
husky: "npm:9.1.7"
|
||||
idb-keyval: "npm:6.2.2"
|
||||
intl-messageformat: "npm:10.7.18"
|
||||
js-yaml: "npm:4.1.1"
|
||||
jsdom: "npm:27.1.0"
|
||||
jsdom: "npm:27.2.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"
|
||||
leaflet.markercluster: "npm:1.5.3"
|
||||
lint-staged: "npm:16.2.6"
|
||||
lint-staged: "npm:16.2.7"
|
||||
lit: "npm:3.3.1"
|
||||
lit-analyzer: "npm:2.0.3"
|
||||
lit-html: "npm:3.3.1"
|
||||
@@ -9351,7 +9351,7 @@ __metadata:
|
||||
lodash.template: "npm:4.5.0"
|
||||
luxon: "npm:3.7.2"
|
||||
map-stream: "npm:0.0.7"
|
||||
marked: "npm:17.0.0"
|
||||
marked: "npm:17.0.1"
|
||||
memoize-one: "npm:6.0.0"
|
||||
node-vibrant: "npm:4.0.3"
|
||||
object-hash: "npm:3.0.0"
|
||||
@@ -9362,7 +9362,7 @@ __metadata:
|
||||
qrcode: "npm:1.5.4"
|
||||
roboto-fontface: "npm:0.10.0"
|
||||
rrule: "npm:2.8.1"
|
||||
rspack-manifest-plugin: "npm:5.1.0"
|
||||
rspack-manifest-plugin: "npm:5.2.0"
|
||||
serve: "npm:14.2.5"
|
||||
sinon: "npm:21.0.0"
|
||||
sortablejs: "patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch"
|
||||
@@ -9373,10 +9373,10 @@ __metadata:
|
||||
tinykeys: "npm:3.0.0"
|
||||
ts-lit-plugin: "npm:2.0.2"
|
||||
typescript: "npm:5.9.3"
|
||||
typescript-eslint: "npm:8.46.3"
|
||||
typescript-eslint: "npm:8.47.0"
|
||||
ua-parser-js: "npm:2.0.6"
|
||||
vite-tsconfig-paths: "npm:5.1.4"
|
||||
vitest: "npm:4.0.8"
|
||||
vitest: "npm:4.0.13"
|
||||
vue: "npm:2.7.16"
|
||||
vue2-daterange-picker: "npm:0.6.8"
|
||||
webpack-stats-plugin: "npm:1.1.3"
|
||||
@@ -10418,13 +10418,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jsdom@npm:27.1.0":
|
||||
version: 27.1.0
|
||||
resolution: "jsdom@npm:27.1.0"
|
||||
"jsdom@npm:27.2.0":
|
||||
version: 27.2.0
|
||||
resolution: "jsdom@npm:27.2.0"
|
||||
dependencies:
|
||||
"@acemir/cssom": "npm:^0.9.19"
|
||||
"@asamuzakjp/dom-selector": "npm:^6.7.3"
|
||||
cssstyle: "npm:^5.3.2"
|
||||
"@acemir/cssom": "npm:^0.9.23"
|
||||
"@asamuzakjp/dom-selector": "npm:^6.7.4"
|
||||
cssstyle: "npm:^5.3.3"
|
||||
data-urls: "npm:^6.0.0"
|
||||
decimal.js: "npm:^10.6.0"
|
||||
html-encoding-sniffer: "npm:^4.0.0"
|
||||
@@ -10447,7 +10447,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
canvas:
|
||||
optional: true
|
||||
checksum: 10/9e2bd9824abed594da64fc58f1bdb817c7f82ba3025cef4817e6709807f886ac71b7b6a0f4f69ba604e9137bbcd6b7246b98dec53bde95500f5ac4b39a8ebb00
|
||||
checksum: 10/78458e0230fd18ceef1e8753ab44eadf436654540a3d1dc5068f49b87c2bd1752b8fff25c9e1f30ee406ae3e80cc3f81668f778b8220a7bf9386a0a826dee088
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10690,11 +10690,11 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lint-staged@npm:16.2.6":
|
||||
version: 16.2.6
|
||||
resolution: "lint-staged@npm:16.2.6"
|
||||
"lint-staged@npm:16.2.7":
|
||||
version: 16.2.7
|
||||
resolution: "lint-staged@npm:16.2.7"
|
||||
dependencies:
|
||||
commander: "npm:^14.0.1"
|
||||
commander: "npm:^14.0.2"
|
||||
listr2: "npm:^9.0.5"
|
||||
micromatch: "npm:^4.0.8"
|
||||
nano-spawn: "npm:^2.0.0"
|
||||
@@ -10703,7 +10703,7 @@ __metadata:
|
||||
yaml: "npm:^2.8.1"
|
||||
bin:
|
||||
lint-staged: bin/lint-staged.js
|
||||
checksum: 10/c419f1347166ddd06746d4a3e4ce6441f3d0e82dcdcbc3d3615ddf7b82b36c603df2e43dbb1edad5ed00ae29857479e1f880bcca271f8bf4b0db7d0f77861d21
|
||||
checksum: 10/c1fd7685300800ea6d3f073cb450f9e3d2a83966e7c6785ea9608a08e77e1e8e5f1958f77b98ccd7d423daa53bb36016d6fd96a98d22234d0f7f56d7b3f360f2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10984,12 +10984,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"marked@npm:17.0.0":
|
||||
version: 17.0.0
|
||||
resolution: "marked@npm:17.0.0"
|
||||
"marked@npm:17.0.1":
|
||||
version: 17.0.1
|
||||
resolution: "marked@npm:17.0.1"
|
||||
bin:
|
||||
marked: bin/marked.js
|
||||
checksum: 10/5544d27547851986c4e994a3f5739ea30bfe2616a9e1d5d5c8ced0fd561b5e971b3c7ee62b4fea1ea530e9886b89102d5c3b3bf962756494ced021f1accd6854
|
||||
checksum: 10/8d39cf5a1eb97288d09d47dba57a613b8c45a212287b27aa16b4bc41baaebb147340c359d379da1bc6d351474d169aa3a63f981770b67f7663ed0a479dd950c2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -12780,9 +12780,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rspack-manifest-plugin@npm:5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "rspack-manifest-plugin@npm:5.1.0"
|
||||
"rspack-manifest-plugin@npm:5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "rspack-manifest-plugin@npm:5.2.0"
|
||||
dependencies:
|
||||
"@rspack/lite-tapable": "npm:^1.0.1"
|
||||
peerDependencies:
|
||||
@@ -12790,7 +12790,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@rspack/core":
|
||||
optional: true
|
||||
checksum: 10/672de1eb405b48c7a50f03d1813048b1a6711afd1e7f6829471c020bc16de96ecbf8d8a10c3f8cdb6bfcaa6e93461bd22cef92203f17d8494a53e285d21a16ad
|
||||
checksum: 10/661774e2f3d41db615b2fb2d14800c85524b33f3fd0b67e4161ca775f9ccbba3ecc8db21cd6e1f878e65a13cd6d718c6d66ad55614137cecb615cfd8d8f1cac9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14223,12 +14223,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"type-fest@npm:^5.0.1":
|
||||
version: 5.0.1
|
||||
resolution: "type-fest@npm:5.0.1"
|
||||
"type-fest@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "type-fest@npm:5.2.0"
|
||||
dependencies:
|
||||
tagged-tag: "npm:^1.0.0"
|
||||
checksum: 10/5ec4def4ce82e6a33cf2e1a50f7ef512226fbe85314e402155aaedd70d4aa7ccea4224a72234d5351b1b4a730b36243d5b011c147e91795d2eee0dba291c6e51
|
||||
checksum: 10/4ce526139c05e92a1d92fa905840ff9ae725b8058df5a5571380bca1827db1f2e4e204c9d561fd63e972d45591dd4d38eab5f5529c0af93d6cfb5f99109aa74a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14295,18 +14295,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:8.46.3":
|
||||
version: 8.46.3
|
||||
resolution: "typescript-eslint@npm:8.46.3"
|
||||
"typescript-eslint@npm:8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "typescript-eslint@npm:8.47.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.46.3"
|
||||
"@typescript-eslint/parser": "npm:8.46.3"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.46.3"
|
||||
"@typescript-eslint/utils": "npm:8.46.3"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.47.0"
|
||||
"@typescript-eslint/parser": "npm:8.47.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.47.0"
|
||||
"@typescript-eslint/utils": "npm:8.47.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/2f77eb70c8fd6ec4920d5abf828ef28007df8ff94605246a4ca918fadb996a83f7fb82510a1de69fad7f0159ee8f15246d467ebc42df20a4585919cb6b401715
|
||||
checksum: 10/159dad98535dafd68c6228fae4aaf9e02d65d9ac3b02ddf0356b56ce72651dd9860e8bf9e0ee22532d77dd382d7f810e1bf1dd41c3fab381f627a08580c5117e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14751,17 +14751,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vitest@npm:4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "vitest@npm:4.0.8"
|
||||
"vitest@npm:4.0.13":
|
||||
version: 4.0.13
|
||||
resolution: "vitest@npm:4.0.13"
|
||||
dependencies:
|
||||
"@vitest/expect": "npm:4.0.8"
|
||||
"@vitest/mocker": "npm:4.0.8"
|
||||
"@vitest/pretty-format": "npm:4.0.8"
|
||||
"@vitest/runner": "npm:4.0.8"
|
||||
"@vitest/snapshot": "npm:4.0.8"
|
||||
"@vitest/spy": "npm:4.0.8"
|
||||
"@vitest/utils": "npm:4.0.8"
|
||||
"@vitest/expect": "npm:4.0.13"
|
||||
"@vitest/mocker": "npm:4.0.13"
|
||||
"@vitest/pretty-format": "npm:4.0.13"
|
||||
"@vitest/runner": "npm:4.0.13"
|
||||
"@vitest/snapshot": "npm:4.0.13"
|
||||
"@vitest/spy": "npm:4.0.13"
|
||||
"@vitest/utils": "npm:4.0.13"
|
||||
debug: "npm:^4.4.3"
|
||||
es-module-lexer: "npm:^1.7.0"
|
||||
expect-type: "npm:^1.2.2"
|
||||
@@ -14777,17 +14777,20 @@ __metadata:
|
||||
why-is-node-running: "npm:^2.3.0"
|
||||
peerDependencies:
|
||||
"@edge-runtime/vm": "*"
|
||||
"@opentelemetry/api": ^1.9.0
|
||||
"@types/debug": ^4.1.12
|
||||
"@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0
|
||||
"@vitest/browser-playwright": 4.0.8
|
||||
"@vitest/browser-preview": 4.0.8
|
||||
"@vitest/browser-webdriverio": 4.0.8
|
||||
"@vitest/ui": 4.0.8
|
||||
"@vitest/browser-playwright": 4.0.13
|
||||
"@vitest/browser-preview": 4.0.13
|
||||
"@vitest/browser-webdriverio": 4.0.13
|
||||
"@vitest/ui": 4.0.13
|
||||
happy-dom: "*"
|
||||
jsdom: "*"
|
||||
peerDependenciesMeta:
|
||||
"@edge-runtime/vm":
|
||||
optional: true
|
||||
"@opentelemetry/api":
|
||||
optional: true
|
||||
"@types/debug":
|
||||
optional: true
|
||||
"@types/node":
|
||||
@@ -14806,7 +14809,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vitest: vitest.mjs
|
||||
checksum: 10/b2fd9e2bb0740860f998f1ecfb948da330cc2e8dc15376669ef742420ad77fedea491731dfaefff17379457d21f06740afaa725952cbcbdcd499a532b95e5717
|
||||
checksum: 10/5842ee10e8509adc225602ec9f186ccbfb6c9733c23ab1587eaaa5406adf626d60d910fcd574223f0d0fe2393eb2af8a97fb3163029becd4c9894d95e4361585
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -15803,14 +15806,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"zxing-wasm@npm:2.2.2":
|
||||
version: 2.2.2
|
||||
resolution: "zxing-wasm@npm:2.2.2"
|
||||
"zxing-wasm@npm:2.2.4":
|
||||
version: 2.2.4
|
||||
resolution: "zxing-wasm@npm:2.2.4"
|
||||
dependencies:
|
||||
"@types/emscripten": "npm:^1.41.2"
|
||||
type-fest: "npm:^5.0.1"
|
||||
"@types/emscripten": "npm:^1.41.5"
|
||||
type-fest: "npm:^5.2.0"
|
||||
peerDependencies:
|
||||
"@types/emscripten": ">=1.39.6"
|
||||
checksum: 10/c542a3a56d30961cd221535fa82fef7fe49abff896339e23236b6a13297e0eba2dc9d51fb0808544321950b51a8f554d57a7859ddb7f8c236cdf66e2509a8b02
|
||||
checksum: 10/e5928cbb066c854c970cbf724e978e502c3469d69de2469bd37d1f6ab8f5d2a2acdbaa9dea32d35cfc058e2b482e29a9c4f12161d9df3e1e952c30dda3a96d8c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
Reference in New Issue
Block a user