Merge branch 'dev'

This commit is contained in:
Bram Kragten 2024-11-04 19:04:13 +01:00
commit 452cfee2cd
57 changed files with 676 additions and 238 deletions

View File

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

View File

@ -55,7 +55,7 @@ jobs:
script/release
- name: Upload release assets
uses: softprops/action-gh-release@v2.0.8
uses: softprops/action-gh-release@v2.0.9
with:
files: |
dist/*.whl

View File

@ -223,7 +223,10 @@ class HassioAddonInfo extends LitElement {
<div class="description light-color">
${this.addon.version
? html`
Current version: ${this.addon.version}
${this.supervisor.localize(
"addon.dashboard.current_version",
{ version: this.addon.version }
)}
<div class="changelog" @click=${this._openChangelog}>
(<span class="changelog-link"
>${this.supervisor.localize(

View File

@ -27,11 +27,11 @@
"dependencies": {
"@babel/runtime": "7.26.0",
"@braintree/sanitize-url": "7.1.0",
"@codemirror/autocomplete": "6.18.1",
"@codemirror/autocomplete": "6.18.2",
"@codemirror/commands": "6.7.1",
"@codemirror/language": "6.10.3",
"@codemirror/legacy-modes": "6.4.1",
"@codemirror/search": "6.5.6",
"@codemirror/search": "6.5.7",
"@codemirror/state": "6.4.1",
"@codemirror/view": "6.34.1",
"@egjs/hammerjs": "2.0.17",
@ -101,7 +101,7 @@
"chart.js": "4.4.6",
"color-name": "2.0.0",
"comlink": "4.4.1",
"core-js": "3.38.1",
"core-js": "3.39.0",
"cropperjs": "1.6.2",
"date-fns": "4.1.0",
"date-fns-tz": "3.2.0",
@ -142,12 +142,12 @@
"vue": "2.7.16",
"vue2-daterange-picker": "0.6.8",
"weekstart": "2.0.0",
"workbox-cacheable-response": "7.1.0",
"workbox-core": "7.1.0",
"workbox-expiration": "7.1.0",
"workbox-precaching": "7.1.0",
"workbox-routing": "7.1.0",
"workbox-strategies": "7.1.0",
"workbox-cacheable-response": "7.3.0",
"workbox-core": "7.3.0",
"workbox-expiration": "7.3.0",
"workbox-precaching": "7.3.0",
"workbox-routing": "7.3.0",
"workbox-strategies": "7.3.0",
"xss": "1.0.15"
},
"devDependencies": {
@ -224,7 +224,7 @@
"lodash.template": "4.5.0",
"magic-string": "0.30.12",
"map-stream": "0.0.7",
"mocha": "10.7.3",
"mocha": "10.8.2",
"object-hash": "3.0.0",
"open": "10.1.0",
"pinst": "3.0.0",
@ -241,7 +241,7 @@
"transform-async-modules-webpack-plugin": "1.1.1",
"ts-lit-plugin": "2.0.2",
"typescript": "5.6.3",
"webpack": "5.95.0",
"webpack": "5.96.1",
"webpack-cli": "5.1.4",
"webpack-dev-server": "5.1.0",
"webpack-manifest-plugin": "5.0.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20241031.0"
version = "20241104.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@ -102,7 +102,9 @@ export class HaCameraStream extends LitElement {
.entityid=${this.stateObj.entity_id}
.posterUrl=${this._posterUrl}
@streams=${this._handleHlsStreams}
class=${!this._streamType && this._webRtcStreams ? "hidden" : ""}
class=${!this._streamType && this._webRtcStreams?.hasVideo
? "hidden"
: ""}
></ha-hls-player>`
: nothing}
${this._streamType === STREAM_TYPE_WEB_RTC ||

View File

@ -43,6 +43,7 @@ class HaDurationInput extends LitElement {
.label=${this.label}
.helper=${this.helper}
.required=${this.required}
.clearable=${!this.required && this.data !== undefined}
.autoValidate=${this.required}
.disabled=${this.disabled}
errorMessage="Required"
@ -67,28 +68,56 @@ class HaDurationInput extends LitElement {
}
private get _days() {
return this.data?.days ? Number(this.data.days) : 0;
return this.data?.days
? Number(this.data.days)
: this.required || this.data
? 0
: NaN;
}
private get _hours() {
return this.data?.hours ? Number(this.data.hours) : 0;
return this.data?.hours
? Number(this.data.hours)
: this.required || this.data
? 0
: NaN;
}
private get _minutes() {
return this.data?.minutes ? Number(this.data.minutes) : 0;
return this.data?.minutes
? Number(this.data.minutes)
: this.required || this.data
? 0
: NaN;
}
private get _seconds() {
return this.data?.seconds ? Number(this.data.seconds) : 0;
return this.data?.seconds
? Number(this.data.seconds)
: this.required || this.data
? 0
: NaN;
}
private get _milliseconds() {
return this.data?.milliseconds ? Number(this.data.milliseconds) : 0;
return this.data?.milliseconds
? Number(this.data.milliseconds)
: this.required || this.data
? 0
: NaN;
}
private _durationChanged(ev: CustomEvent<{ value: TimeChangedEvent }>) {
private _durationChanged(ev: CustomEvent<{ value?: TimeChangedEvent }>) {
ev.stopPropagation();
const value = { ...ev.detail.value };
const value = ev.detail.value ? { ...ev.detail.value } : undefined;
if (value) {
value.hours ||= 0;
value.minutes ||= 0;
value.seconds ||= 0;
if ("days" in value) value.days ||= 0;
if ("milliseconds" in value) value.milliseconds ||= 0;
if (!this.enableMillisecond && !value.milliseconds) {
// @ts-ignore
@ -112,6 +141,7 @@ class HaDurationInput extends LitElement {
value.days = (value.days ?? 0) + Math.floor(value.hours / 24);
value.hours %= 24;
}
}
fireEvent(this, "value-changed", {
value,

View File

@ -8,7 +8,6 @@ import { customIcons } from "../data/custom_icons";
import type { Chunks, Icons } from "../data/iconsets";
import {
MDI_PREFIXES,
checkCacheVersion,
findIconChunk,
getIcon,
writeCache,
@ -26,11 +25,6 @@ const mdiDeprecatedIcons: DeprecatedIcon = {};
const chunks: Chunks = {};
// Supervisor doesn't use icons, and should not update/downgrade the icon DB.
if (!__SUPERVISOR__) {
checkCacheVersion();
}
const debouncedWriteCache = debounce(() => writeCache(chunks), 2000);
const cachedIcons: Record<string, string> = {};

View File

@ -24,7 +24,7 @@ export class HaToast extends Snackbar {
max-width: 650px;
}
// Revert the default styles set by mwc-snackbar
/* Revert the default styles set by mwc-snackbar */
@media (max-width: 480px), (max-width: 344px) {
.mdc-snackbar__surface {
min-width: inherit;

View File

@ -86,6 +86,8 @@ export class HaMap extends ReactiveElement {
private _mapZones: Array<Marker | Circle> = [];
private _mapFocusZones: Array<Marker | Circle> = [];
private _mapPaths: Array<Polyline | CircleMarker> = [];
public connectedCallback(): void {
@ -201,7 +203,11 @@ export class HaMap extends ReactiveElement {
return;
}
if (!this._mapFocusItems.length && !this.layers?.length) {
if (
!this._mapFocusItems.length &&
!this._mapFocusZones.length &&
!this.layers?.length
) {
this.leafletMap.setView(
new this.Leaflet.LatLng(
this.hass.config.latitude,
@ -218,13 +224,9 @@ export class HaMap extends ReactiveElement {
: []
);
if (this.fitZones) {
this._mapZones?.forEach((zone) => {
bounds.extend(
"getBounds" in zone ? zone.getBounds() : zone.getLatLng()
);
this._mapFocusZones?.forEach((zone) => {
bounds.extend("getBounds" in zone ? zone.getBounds() : zone.getLatLng());
});
}
this.layers?.forEach((layer: any) => {
bounds.extend(
@ -395,6 +397,7 @@ export class HaMap extends ReactiveElement {
if (this._mapZones.length) {
this._mapZones.forEach((marker) => marker.remove());
this._mapZones = [];
this._mapFocusZones = [];
}
if (!this.entities) {
@ -466,13 +469,18 @@ export class HaMap extends ReactiveElement {
);
// create circle around it
this._mapZones.push(
Leaflet.circle([latitude, longitude], {
const circle = Leaflet.circle([latitude, longitude], {
interactive: false,
color: passive ? passiveZoneColor : zoneColor,
radius,
})
);
});
this._mapZones.push(circle);
if (
this.fitZones &&
(typeof entity === "string" || entity.focus !== false)
) {
this._mapFocusZones.push(circle);
}
continue;
}

View File

@ -193,7 +193,7 @@ export const fetchHassioLogs = async (
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs/boots/${boot}`,
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs${boot !== 0 ? `/boots/${boot}` : ""}`,
undefined,
range
? {
@ -203,20 +203,6 @@ export const fetchHassioLogs = async (
);
export const fetchHassioLogsFollow = async (
hass: HomeAssistant,
provider: string,
signal: AbortSignal,
lines = 100
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs/follow?lines=${lines}`,
undefined,
undefined,
signal
);
export const fetchHassioLogsBootFollow = async (
hass: HomeAssistant,
provider: string,
signal: AbortSignal,
@ -225,7 +211,7 @@ export const fetchHassioLogsBootFollow = async (
) =>
hass.callApiRaw(
"GET",
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs/boots/${boot}/follow?lines=${lines}`,
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs${boot !== 0 ? `/boots/${boot}` : ""}/follow?lines=${lines}`,
undefined,
undefined,
signal
@ -236,19 +222,14 @@ export const getHassioLogDownloadUrl = (provider: string) =>
provider.includes("_") ? `addons/${provider}` : provider
}/logs`;
export const getHassioLogDownloadLinesUrl = (provider: string, lines: number) =>
`/api/hassio/${
provider.includes("_") ? `addons/${provider}` : provider
}/logs?lines=${lines}`;
export const getHassioLogBootDownloadLinesUrl = (
export const getHassioLogDownloadLinesUrl = (
provider: string,
lines: number,
boot = 0
) =>
`/api/hassio/${
provider.includes("_") ? `addons/${provider}` : provider
}/logs/boots/${boot}?lines=${lines}`;
}/logs${boot !== 0 ? `/boots/${boot}` : ""}?lines=${lines}`;
export const setSupervisorOption = async (
hass: HomeAssistant,

View File

@ -1,4 +1,5 @@
import { clear, get, set, createStore, promisifyRequest } from "idb-keyval";
import memoizeOne from "memoize-one";
import { promiseTimeout } from "../common/util/promise-timeout";
import { iconMetadata } from "../resources/icon-metadata";
import type { IconMeta } from "../types";
@ -11,7 +12,23 @@ export interface Chunks {
[key: string]: Promise<Icons>;
}
export const iconStore = createStore("hass-icon-db", "mdi-icon-store");
const getStore = memoizeOne(async () => {
const iconStore = createStore("hass-icon-db", "mdi-icon-store");
// Supervisor doesn't use icons, and should not update/downgrade the icon DB.
if (!__SUPERVISOR__) {
const version = await get("_version", iconStore);
if (!version) {
set("_version", iconMetadata.version, iconStore);
} else if (version !== iconMetadata.version) {
await clear(iconStore);
set("_version", iconMetadata.version, iconStore);
}
}
return iconStore;
});
export const MDI_PREFIXES = ["mdi", "hass", "hassio", "hademo"];
@ -28,7 +45,10 @@ export const getIcon = (iconName: string) =>
return;
}
const readIcons = () =>
// Start initializing the store, so it's ready when we need it
const iconStoreProm = getStore();
const readIcons = async () => {
const iconStore = await iconStoreProm;
iconStore("readonly", (store) => {
for (const [iconName_, resolve_, reject_] of toRead) {
promisifyRequest<string | undefined>(store.get(iconName_))
@ -37,6 +57,7 @@ export const getIcon = (iconName: string) =>
}
toRead = [];
});
};
promiseTimeout(1000, readIcons()).catch((e) => {
// Firefox in private mode doesn't support IDB
@ -62,6 +83,7 @@ export const findIconChunk = (icon: string): string => {
export const writeCache = async (chunks: Chunks) => {
const keys = Object.keys(chunks);
const iconsSets: Icons[] = await Promise.all(Object.values(chunks));
const iconStore = await getStore();
// We do a batch opening the store just once, for (considerable) performance
iconStore("readwrite", (store) => {
iconsSets.forEach((icons, idx) => {
@ -72,14 +94,3 @@ export const writeCache = async (chunks: Chunks) => {
});
});
};
export const checkCacheVersion = async () => {
const version = await get("_version", iconStore);
if (!version) {
set("_version", iconMetadata.version, iconStore);
} else if (version !== iconMetadata.version) {
await clear(iconStore);
set("_version", iconMetadata.version, iconStore);
}
};

View File

@ -1,10 +1,24 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup } from "lit";
import type { CSSResultGroup, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { format } from "date-fns";
import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/ha-climate-state";
import "../../../components/ha-cover-controls";
import "../../../components/ha-cover-tilt-controls";
import "../../../components/ha-date-input";
import "../../../components/ha-humidifier-state";
import "../../../components/ha-select";
import "../../../components/ha-slider";
import "../../../components/ha-time-input";
import "../../../components/entity/ha-entity-toggle";
import "../../../components/entity/state-badge";
import { isTiltOnly } from "../../../data/cover";
import { isUnavailableState } from "../../../data/entity";
import type { ImageEntity } from "../../../data/image";
import { computeImageUrl } from "../../../data/image";
import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor";
import "../../../panels/lovelace/components/hui-timestamp-display";
import type { HomeAssistant } from "../../../types";
@ -28,18 +42,7 @@ class EntityPreviewRow extends LitElement {
<div class="name" .title=${computeStateName(stateObj)}>
${computeStateName(stateObj)}
</div>
<div class="value">
${stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP &&
!isUnavailableState(stateObj.state)
? html`
<hui-timestamp-display
.hass=${this.hass}
.ts=${new Date(stateObj.state)}
capitalize
></hui-timestamp-display>
`
: this.hass.formatEntityState(stateObj)}
</div>`;
<div class="value">${this.renderEntityState(stateObj)}</div>`;
}
static get styles(): CSSResultGroup {
@ -59,8 +62,308 @@ class EntityPreviewRow extends LitElement {
.value {
direction: ltr;
}
.numberflex {
display: flex;
align-items: center;
justify-content: flex-end;
flex-grow: 2;
}
.numberstate {
min-width: 45px;
text-align: end;
}
ha-textfield {
text-align: end;
direction: ltr !important;
}
ha-slider {
width: 100%;
max-width: 200px;
}
ha-time-input {
margin-left: 4px;
margin-inline-start: 4px;
margin-inline-end: initial;
direction: var(--direction);
}
.datetimeflex {
display: flex;
justify-content: flex-end;
width: 100%;
}
mwc-button {
margin-right: -0.57em;
margin-inline-end: -0.57em;
margin-inline-start: initial;
}
img {
display: block;
width: 100%;
}
`;
}
private renderEntityState(stateObj: HassEntity): TemplateResult | string {
const domain = stateObj.entity_id.split(".", 1)[0];
if (domain === "button") {
return html`
<mwc-button .disabled=${isUnavailableState(stateObj.state)}>
${this.hass.localize("ui.card.button.press")}
</mwc-button>
`;
}
const climateDomains = ["climate", "water_heater"];
if (climateDomains.includes(domain)) {
return html`
<ha-climate-state .hass=${this.hass} .stateObj=${stateObj}>
</ha-climate-state>
`;
}
if (domain === "cover") {
return html`
${isTiltOnly(stateObj)
? html`
<ha-cover-tilt-controls
.hass=${this.hass}
.stateObj=${stateObj}
></ha-cover-tilt-controls>
`
: html`
<ha-cover-controls
.hass=${this.hass}
.stateObj=${stateObj}
></ha-cover-controls>
`}
`;
}
if (domain === "date") {
return html`
<ha-date-input
.locale=${this.hass.locale}
.disabled=${isUnavailableState(stateObj.state)}
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
>
</ha-date-input>
`;
}
if (domain === "datetime") {
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
return html`
<div class="datetimeflex">
<ha-date-input
.label=${computeStateName(stateObj)}
.locale=${this.hass.locale}
.value=${date}
.disabled=${isUnavailableState(stateObj.state)}
>
</ha-date-input>
<ha-time-input
.value=${time}
.disabled=${isUnavailableState(stateObj.state)}
.locale=${this.hass.locale}
></ha-time-input>
</div>
`;
}
if (domain === "event") {
return html`
<div class="when">
${isUnavailableState(stateObj.state)
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
.ts=${new Date(stateObj.state)}
capitalize
></hui-timestamp-display>`}
</div>
<div class="what">
${isUnavailableState(stateObj.state)
? nothing
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
</div>
`;
}
const toggleDomains = ["fan", "light", "remote", "siren", "switch"];
if (toggleDomains.includes(domain)) {
const showToggle =
stateObj.state === "on" ||
stateObj.state === "off" ||
isUnavailableState(stateObj.state);
return html`
${showToggle
? html`
<ha-entity-toggle
.hass=${this.hass}
.stateObj=${stateObj}
></ha-entity-toggle>
`
: this.hass.formatEntityState(stateObj)}
`;
}
if (domain === "humidifier") {
return html`
<ha-humidifier-state .hass=${this.hass} .stateObj=${stateObj}>
</ha-humidifier-state>
`;
}
if (domain === "image") {
const image: string = computeImageUrl(stateObj as ImageEntity);
return html`
<img
alt=${ifDefined(stateObj?.attributes.friendly_name)}
src=${this.hass.hassUrl(image)}
/>
`;
}
if (domain === "lock") {
return html`
<mwc-button
.disabled=${isUnavailableState(stateObj.state)}
class="text-content"
>
${stateObj.state === "locked"
? this.hass!.localize("ui.card.lock.unlock")
: this.hass!.localize("ui.card.lock.lock")}
</mwc-button>
`;
}
if (domain === "number") {
const showNumberSlider =
stateObj.attributes.mode === "slider" ||
(stateObj.attributes.mode === "auto" &&
(Number(stateObj.attributes.max) - Number(stateObj.attributes.min)) /
Number(stateObj.attributes.step) <=
256);
return html`
${showNumberSlider
? html`
<div class="numberflex">
<ha-slider
labeled
.disabled=${isUnavailableState(stateObj.state)}
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
.max=${Number(stateObj.attributes.max)}
.value=${Number(stateObj.state)}
></ha-slider>
<span class="state">
${this.hass.formatEntityState(stateObj)}
</span>
</div>
`
: html` <div class="numberflex numberstate">
<ha-textfield
autoValidate
.disabled=${isUnavailableState(stateObj.state)}
pattern="[0-9]+([\\.][0-9]+)?"
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
.max=${Number(stateObj.attributes.max)}
.value=${stateObj.state}
.suffix=${stateObj.attributes.unit_of_measurement}
type="number"
></ha-textfield>
</div>`}
`;
}
if (domain === "select") {
return html`
<ha-select
.label=${computeStateName(stateObj)}
.value=${stateObj.state}
.disabled=${isUnavailableState(stateObj.state)}
naturalMenuWidth
>
${stateObj.attributes.options
? stateObj.attributes.options.map(
(option) => html`
<mwc-list-item .value=${option}>
${this.hass!.formatEntityState(stateObj, option)}
</mwc-list-item>
`
)
: ""}
</ha-select>
`;
}
if (domain === "sensor") {
const showSensor =
stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP &&
!isUnavailableState(stateObj.state);
return html`
${showSensor
? html`
<hui-timestamp-display
.hass=${this.hass}
.ts=${new Date(stateObj.state)}
capitalize
></hui-timestamp-display>
`
: this.hass.formatEntityState(stateObj)}
`;
}
if (domain === "text") {
return html`
<ha-textfield
.label=${computeStateName(stateObj)}
.disabled=${isUnavailableState(stateObj.state)}
.value=${stateObj.state}
.minlength=${stateObj.attributes.min}
.maxlength=${stateObj.attributes.max}
.autoValidate=${stateObj.attributes.pattern}
.pattern=${stateObj.attributes.pattern}
.type=${stateObj.attributes.mode}
placeholder=${this.hass!.localize("ui.card.text.emtpy_value")}
></ha-textfield>
`;
}
if (domain === "time") {
return html`
<ha-time-input
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.locale=${this.hass.locale}
.disabled=${isUnavailableState(stateObj.state)}
></ha-time-input>
`;
}
if (domain === "weather") {
return html`
<div>
${isUnavailableState(stateObj.state) ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
: this.hass.formatEntityAttributeValue(stateObj, "temperature")}
</div>
`;
}
return this.hass.formatEntityState(stateObj);
}
}
declare global {

View File

@ -143,7 +143,7 @@ class MoreInfoUpdate extends LitElement {
)}
</span>
<ha-switch
id="create_backup"
id="create-backup"
checked
.disabled=${updateIsInstalling(this.stateObj)}
></ha-switch>

View File

@ -66,6 +66,8 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
private _dialogClosed() {
this._params = undefined;
this._assistConfiguration = undefined;
this._previousSteps = [];
this._nextStep = undefined;
this._step = STEP.INIT;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}

View File

@ -17,7 +17,7 @@ export class HaVoiceAssistantSetupStepArea extends LitElement {
const device = this.hass.devices[this.deviceId];
return html`<div class="content">
<img src="/static/images/voice-assistant/area.gif" />
<img src="/static/images/voice-assistant/area.png" />
<h1>Select area</h1>
<p class="secondary">
When you voice assistant knows where it is, it can better control the

View File

@ -21,7 +21,7 @@ export class HaVoiceAssistantSetupStepChangeWakeWord extends LitElement {
protected override render() {
return html`<div class="padding content">
<img src="/static/images/voice-assistant/change-wake-word.gif" />
<img src="/static/images/voice-assistant/change-wake-word.png" />
<h1>Change wake word</h1>
<p class="secondary">
Some wake words are better for

View File

@ -6,6 +6,7 @@ import "../../components/ha-circular-progress";
import { testAssistSatelliteConnection } from "../../data/assist_satellite";
import type { HomeAssistant } from "../../types";
import { AssistantSetupStyles } from "./styles";
import { documentationUrl } from "../../util/documentation-url";
@customElement("ha-voice-assistant-setup-step-check")
export class HaVoiceAssistantSetupStepCheck extends LitElement {
@ -35,7 +36,7 @@ export class HaVoiceAssistantSetupStepCheck extends LitElement {
protected override render() {
return html`<div class="content">
${this._status === "timeout"
? html`<img src="/static/images/voice-assistant/error.gif" />
? html`<img src="/static/images/voice-assistant/error.png" />
<h1>The voice assistant is unable to connect to Home Assistant</h1>
<p class="secondary">
To play audio, the voice assistant device has to connect to Home
@ -44,12 +45,15 @@ export class HaVoiceAssistantSetupStepCheck extends LitElement {
</p>
<div class="footer">
<a
href="https://www.home-assistant.io/docs/configuration/remote/#adding-a-remote-url-to-home-assistant"
href=${documentationUrl(
this.hass,
"/voice_control/troubleshooting/#i-dont-get-a-voice-response"
)}
><ha-button>Help me</ha-button></a
>
<ha-button @click=${this._testConnection}>Retry</ha-button>
</div>`
: html`<img src="/static/images/voice-assistant/hi.gif" />
: html`<img src="/static/images/voice-assistant/hi.png" />
<h1>Hi</h1>
<p class="secondary">
Over the next couple steps we're going to personalize your voice

View File

@ -67,7 +67,7 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
: undefined;
return html`<div class="content">
<img src="/static/images/voice-assistant/heart.gif" />
<img src="/static/images/voice-assistant/heart.png" />
<h1>Ready to Assist!</h1>
<p class="secondary">
Make any final customizations here. You can always change these in the

View File

@ -65,7 +65,7 @@ export class HaVoiceAssistantSetupStepUpdate extends LitElement {
const progressIsNumeric = stateObj && updateUsesProgress(stateObj);
return html`<div class="content">
<img src="/static/images/voice-assistant/update.gif" />
<img src="/static/images/voice-assistant/update.png" />
<h1>
${stateObj &&
(stateObj.state === "unavailable" || updateIsInstalling(stateObj))

View File

@ -64,14 +64,14 @@ export class HaVoiceAssistantSetupStepWakeWord extends LitElement {
return html`<div class="content">
${!this._detected
? html`
<img src="/static/images/voice-assistant/sleep.gif" />
<img src="/static/images/voice-assistant/sleep.png" />
<h1>
Say ${this._activeWakeWord(this.assistConfiguration)} to wake the
device up
</h1>
<p class="secondary">Setup will continue once the device is awake.</p>
</div>`
: html`<img src="/static/images/voice-assistant/ok-nabu.gif" />
: html`<img src="/static/images/voice-assistant/ok-nabu.png" />
<h1>
Say ${this._activeWakeWord(this.assistConfiguration)} again
</h1>

View File

@ -16,6 +16,8 @@ import type { ValueChangedEvent } from "../types";
import { onBoardingStyles } from "./styles";
import { debounce } from "../common/util/debounce";
const CHECK_USERNAME_REGEX = /\s|[A-Z]/;
const CREATE_USER_SCHEMA: HaFormSchema[] = [
{
name: "name",
@ -121,6 +123,7 @@ class OnboardingCreateUser extends LitElement {
ev: ValueChangedEvent<HaFormDataContainer>
): void {
const nameChanged = ev.detail.value.name !== this._newUser.name;
const usernameChanged = ev.detail.value.username !== this._newUser.username;
const passwordChanged =
ev.detail.value.password !== this._newUser.password ||
ev.detail.value.password_confirm !== this._newUser.password_confirm;
@ -135,6 +138,9 @@ class OnboardingCreateUser extends LitElement {
this._debouncedCheckPasswordMatch();
}
}
if (usernameChanged) {
this._checkUsername();
}
}
private _debouncedCheckPasswordMatch = debounce(
@ -164,6 +170,21 @@ class OnboardingCreateUser extends LitElement {
const parts = String(this._newUser.name).split(" ");
if (parts.length) {
this._newUser.username = parts[0].toLowerCase();
this._checkUsername();
}
}
private _checkUsername(): void {
const old = this._formError.username;
if (CHECK_USERNAME_REGEX.test(this._newUser.username as string)) {
this._formError.username = this.localize(
"ui.panel.page-onboarding.user.error.username_not_normalized"
);
} else {
this._formError.username = "";
}
if (old !== this._formError.username) {
this.requestUpdate("_formError");
}
}

View File

@ -49,6 +49,7 @@ export class HaDelayAction extends LitElement implements ActionElement {
.disabled=${this.disabled}
.data=${this._timeData}
enableMillisecond
required
@value-changed=${this._valueChanged}
></ha-duration-input>`;
}

View File

@ -67,9 +67,6 @@ export class HaWaitForTriggerAction
private _timeoutChanged(ev: CustomEvent<{ value: TimeChangedEvent }>): void {
ev.stopPropagation();
const value = ev.detail.value;
if (!value) {
return;
}
fireEvent(this, "value-changed", {
value: { ...this.action, timeout: value },
});

View File

@ -712,8 +712,12 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
private async _duplicate() {
const result = this._readOnly
? await showConfirmationDialog(this, {
title: "Migrate automation?",
text: "You can migrate this automation, so it can be edited from the UI. After it is migrated and you have saved it, you will have to manually delete your old automation from your configuration. Do you want to migrate this automation?",
title: this.hass.localize(
"ui.panel.config.automation.picker.migrate_automation"
),
text: this.hass.localize(
"ui.panel.config.automation.picker.migrate_automation_description"
),
})
: await this.confirmUnsavedChanged();
if (result) {

View File

@ -46,7 +46,7 @@ export class HaCalendarTrigger extends LitElement implements TriggerElement {
],
],
},
{ name: "offset", selector: { duration: {} } },
{ name: "offset", required: true, selector: { duration: {} } },
{
name: "offset_type",
type: "select",

View File

@ -584,6 +584,10 @@ class AddIntegrationDialog extends LitElement {
});
if (configEntries.length > 0) {
this.closeDialog();
const localize = await this.hass.loadBackendTranslation(
"title",
integration.name
);
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_flow.single_config_entry_title"
@ -591,7 +595,7 @@ class AddIntegrationDialog extends LitElement {
text: this.hass.localize(
"ui.panel.config.integrations.config_flow.single_config_entry",
{
integration_name: integration.name,
integration_name: domainToName(localize, integration.name),
}
),
});

View File

@ -1387,6 +1387,10 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
this._extraConfigEntries || this.configEntries
);
if (entries.length > 0) {
const localize = await this.hass.loadBackendTranslation(
"title",
this._manifest.name
);
await showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_flow.single_config_entry_title"
@ -1394,7 +1398,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
text: this.hass.localize(
"ui.panel.config.integrations.config_flow.single_config_entry",
{
integration_name: this._manifest.name,
integration_name: domainToName(localize, this._manifest.name),
}
),
});

View File

@ -744,6 +744,10 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) {
if (integration.single_config_entry) {
const configEntries = await getConfigEntries(this.hass, { domain });
if (configEntries.length > 0) {
const localize = await this.hass.loadBackendTranslation(
"title",
integration.name
);
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.integrations.config_flow.single_config_entry_title"
@ -751,7 +755,7 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) {
text: this.hass.localize(
"ui.panel.config.integrations.config_flow.single_config_entry",
{
integration_name: integration.name,
integration_name: domainToName(localize, integration.name!),
}
),
});

View File

@ -44,7 +44,6 @@ class MatterAddDeviceGoogleHome extends LitElement {
home_assistant: html`<b>Home Assistant</b>`,
}
)}
<br />
<span
class="link"
type="button"
@ -57,13 +56,13 @@ class MatterAddDeviceGoogleHome extends LitElement {
)}
</span>
</li>
</ol>
<br />
<p>
<li>
${this.hass.localize(
`ui.dialogs.matter-add-device.google_home.redirect`
)}
</p>
</li>
</ol>
<br />
</div>
`;
}

View File

@ -14,10 +14,7 @@ import type { DownloadLogsDialogParams } from "./show-dialog-download-logs";
import "../../../components/ha-select";
import "../../../components/ha-list-item";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import {
getHassioLogDownloadLinesUrl,
getHassioLogBootDownloadLinesUrl,
} from "../../../data/hassio/supervisor";
import { getHassioLogDownloadLinesUrl } from "../../../data/hassio/supervisor";
import { getSignedPath } from "../../../data/auth";
import { fileDownload } from "../../../util/file_download";
@ -115,7 +112,7 @@ class DownloadLogsDialog extends LitElement {
const boot = this._dialogParams!.boot;
const timeString = new Date().toISOString().replace(/:/g, "-");
const downloadUrl = this._getDownloadUrlFunction()(
const downloadUrl = getHassioLogDownloadLinesUrl(
provider,
this._lineCount,
boot
@ -129,13 +126,6 @@ class DownloadLogsDialog extends LitElement {
this.closeDialog();
}
private _getDownloadUrlFunction() {
if (this._dialogParams!.boot === 0) {
return getHassioLogDownloadLinesUrl;
}
return getHassioLogBootDownloadLinesUrl;
}
private _setNumberOfLogs(ev) {
this._lineCount = Number(ev.target.value);
}

View File

@ -39,7 +39,6 @@ import { extractApiErrorMessage } from "../../../data/hassio/common";
import {
fetchHassioBoots,
fetchHassioLogs,
fetchHassioLogsBootFollow,
fetchHassioLogsFollow,
getHassioLogDownloadUrl,
} from "../../../data/hassio/supervisor";
@ -379,7 +378,7 @@ class ErrorLogCard extends LitElement {
isComponentLoaded(this.hass, "hassio") &&
this.provider
) {
const response = await this._fetchLogsFunction()(
const response = await fetchHassioLogsFollow(
this.hass,
this.provider,
this._logStreamAborter.signal,
@ -469,13 +468,6 @@ class ErrorLogCard extends LitElement {
}
}
private _fetchLogsFunction = () => {
if (this._boot === 0) {
return fetchHassioLogsFollow;
}
return fetchHassioLogsBootFollow;
};
private _debounceSearch = debounce(() => {
this._noSearchResults = !this._ansiToHtmlElement?.filterLines(this.filter);

View File

@ -681,8 +681,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
private async _duplicate() {
const result = this._readOnly
? await showConfirmationDialog(this, {
title: "Migrate script?",
text: "You can migrate this script, so it can be edited from the UI. After it is migrated and you have saved it, you will have to manually delete your old script from your configuration. Do you want to migrate this script?",
title: this.hass.localize(
"ui.panel.config.script.picker.migrate_script"
),
text: this.hass.localize(
"ui.panel.config.script.picker.migrate_script_description"
),
})
: await this.confirmUnsavedChanged();
if (result) {

View File

@ -59,18 +59,12 @@ export class HuiEnergyDateSelectionCard
static get styles(): CSSResultGroup {
return css`
:host {
ha-card {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
}
.padded {
padding-left: 16px !important;
padding-inline-start: 16px !important;
padding-inline-end: initial !important;
}
`;
}
}

View File

@ -28,6 +28,7 @@ export class HuiHorizontalStackCard extends HuiStackCard {
css`
#root {
display: flex;
height: 100%;
gap: var(--horizontal-stack-card-gap, var(--stack-card-gap, 8px));
}
#root > hui-card {

View File

@ -64,6 +64,7 @@ const cardConfigStruct = assign(
hours_to_show: optional(number()),
geo_location_sources: optional(array(geoSourcesConfigStruct)),
auto_fit: optional(boolean()),
fit_zones: optional(boolean()),
theme_mode: optional(string()),
})
);

View File

@ -242,8 +242,9 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
min-height: var(--row-height);
}
.container.edit-mode:not(.import-only) {
border-start-end-radius: 0px;
.container.import-only {
border: none;
padding: 0 !important;
}
.card {

View File

@ -1,5 +1,11 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import { mdiDelete, mdiDrag, mdiPencil, mdiViewGridPlus } from "@mdi/js";
import {
mdiDelete,
mdiDrag,
mdiEyeOff,
mdiPencil,
mdiViewGridPlus,
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
@ -245,6 +251,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
<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"
)}
@ -480,9 +487,9 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
}
.imported-card-header {
margin-top: 24px;
padding: 16px 8px;
border-top: 2px dashed var(--divider-color);
margin-top: 36px;
padding: 32px 0 16px 0;
border-top: 4px dotted var(--divider-color);
}
.imported-card-header .title {
@ -491,6 +498,11 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
font-size: 16px;
font-weight: 400;
line-height: 24px;
--mdc-icon-size: 18px;
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
}
.imported-card-header .subtitle {
margin: 0;

View File

@ -1745,8 +1745,8 @@
"answer_generic": "Other controllers"
},
"google_home": {
"header": "Link Matter app",
"step_1": "Find your device in Google Home. Tap the gear icon to open the device settings.",
"header": "Share from Google Home",
"step_1": "Find your device in the Google Home app. Tap the gear icon to open the device settings.",
"step_2": "Tap {linked_matter_apps_services}.",
"step_3": "Tap {link_apps_services} and choose {home_assistant} from the list.",
"linked_matter_apps_services": "Linked Matter apps and services",
@ -1776,8 +1776,8 @@
"code_instructions": "Paste the code you just received from the other controller."
},
"generic": {
"header": "Copy setup code",
"code_instructions": "Search for the sharing mode in the app of your controller, and activate it. You will get a sharing code, enter that below.",
"header": "Enter setup code",
"code_instructions": "Search for the sharing mode in the app of your controller, and activate it. You will get a setup code, enter that below.",
"setup_code": "Setup code"
}
}
@ -2792,7 +2792,9 @@
},
"empty_header": "Start automating",
"empty_text_1": "Automations make Home Assistant automatically respond to things happening in and around your home.",
"empty_text_2": "Automations connect triggers to actions in a ''when trigger then action'' fashion with optional conditions. For example: ''When the sun sets and if {user} is home, then turn on the lights''."
"empty_text_2": "Automations connect triggers to actions in a ''when trigger then action'' fashion with optional conditions. For example: ''When the sun sets and if {user} is home, then turn on the lights''.",
"migrate_automation": "Migrate automation?",
"migrate_automation_description": "You can migrate this automation, so it can be edited from the UI. After it is migrated and you have saved it, you will have to manually delete your old automation from your configuration. Do you want to migrate this automation?"
},
"dialog_new": {
"header": "Create automation",
@ -3215,7 +3217,7 @@
"description": {
"picker": "If an entity (or attribute) is in a specific state.",
"no_entity": "Confirm state",
"full": "If{hasAttribute, select, \n true { {attribute} of}\n other {}\n} {numberOfEntities, plural,\n zero {an entity is}\n one {{entities} is}\n other {{entities} are}\n} {numberOfStates, plural,\n zero {a state}\n other {{states}}\n}{hasDuration, select, \n true { for {duration}} \n other {}\n }"
"full": "If{hasAttribute, select, \n true { {attribute} of}\n other {}\n} {numberOfEntities, plural,\n =0 {an entity is}\n one {{entities} is}\n other {{entities} are}\n} {numberOfStates, plural,\n =0 {a state}\n other {{states}}\n}{hasDuration, select, \n true { for {duration}} \n other {}\n }"
}
},
"sun": {
@ -3676,7 +3678,9 @@
"duplicate": "[%key:ui::common::duplicate%]",
"empty_header": "Create your first script",
"empty_text": "A script is a sequence of actions that can be run from a dashboard, an automation, or be triggered by voice. For example, a ''Wake-up routine''' script that gradually turns on the light in the bedroom and opens the blinds after a delay.",
"search": "Search {number} scripts"
"search": "Search {number} scripts",
"migrate_script": "Migrate script?",
"migrate_script_description": "You can migrate this script, so it can be edited from the UI. After it is migrated and you have saved it, you will have to manually delete your old script from your configuration. Do you want to migrate this script?"
},
"dialog_new": {
"header": "Create script",
@ -4115,7 +4119,7 @@
"hidden": "Hidden"
},
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to manually edit them yourself to use the new entity IDs!",
"confirm_rename_entity_will_rename": "{count} {count, plural,\n one {entity ID}\n other {entity IDs}\n} will be renamed",
"confirm_rename_new": "New",
"confirm_rename_old": "Old",
@ -5306,7 +5310,7 @@
"share": "Share"
},
"mount_type": {
"nfs": "Network file share (NFS)",
"nfs": "Network File System (NFS)",
"cifs": "Samba/Windows (CIFS)"
},
"cifs_versions": {
@ -5884,7 +5888,7 @@
},
"entities": {
"name": "Entities",
"show_header_toggle": "Show header toggle?",
"show_header_toggle": "Show header toggle",
"toggle": "Toggle entities.",
"description": "The Entities card is the most common type of card. It groups items together into lists.",
"special_row": "special row",
@ -5931,9 +5935,9 @@
},
"gauge": {
"name": "Gauge",
"needle_gauge": "Display as needle gauge?",
"needle_gauge": "Display as needle gauge",
"severity": {
"define": "Define severity?",
"define": "Define severity",
"green": "Green",
"red": "Red",
"yellow": "Yellow"
@ -6067,7 +6071,7 @@
"state": "State",
"secondary_info_attribute": "Secondary info attribute",
"search": "Search",
"state_color": "Color icons based on state?",
"state_color": "Show state color",
"suggested_cards": "Suggested cards",
"other_cards": "Other cards",
"custom_cards": "Custom cards",
@ -6104,7 +6108,6 @@
"name": "Map",
"geo_location_sources": "Geolocation sources",
"no_geo_location_sources": "No geolocation sources available",
"dark_mode": "Dark mode?",
"appearance": "Appearance",
"theme_mode": "Theme Mode",
"theme_modes": {
@ -7203,6 +7206,7 @@
},
"create_account": "Create account",
"error": {
"username_not_normalized": "Username can only contain lowercase letters, and can not contain whitespace.",
"password_not_match": "Passwords don't match"
}
},
@ -7372,6 +7376,7 @@
},
"dashboard": {
"changelog": "Changelog",
"current_version": "Current version: {version}",
"cpu_usage": "Add-on CPU usage",
"ram_usage": "Add-on RAM usage",
"hostname": "Hostname",
@ -7472,7 +7477,7 @@
},
"watchdog": {
"title": "Watchdog",
"description": "This will start the add-on if it crashes"
"description": "This will restart the add-on if it crashes"
},
"auto_update": {
"title": "Auto update",

168
yarn.lock
View File

@ -1265,9 +1265,9 @@ __metadata:
languageName: node
linkType: hard
"@codemirror/autocomplete@npm:6.18.1":
version: 6.18.1
resolution: "@codemirror/autocomplete@npm:6.18.1"
"@codemirror/autocomplete@npm:6.18.2":
version: 6.18.2
resolution: "@codemirror/autocomplete@npm:6.18.2"
dependencies:
"@codemirror/language": "npm:^6.0.0"
"@codemirror/state": "npm:^6.0.0"
@ -1278,7 +1278,7 @@ __metadata:
"@codemirror/state": ^6.0.0
"@codemirror/view": ^6.0.0
"@lezer/common": ^1.0.0
checksum: 10/3b56ac6c57214e3e50c6ed79c12ac1822e3774afb033e0e4fb98dffd252f5ae64e5bed67dc2ad9cbd5d784373031be90995ddb1b36a10c16a2eef6af832041e2
checksum: 10/35bd17afb53e8c99b1342964616f0bcc13f5f06a5d4e2d9936afdaea61742b1c20b3856d513c5d5676e3a9b6fd95e997c842467d21dfa106845e65ab1720b2f4
languageName: node
linkType: hard
@ -1317,14 +1317,14 @@ __metadata:
languageName: node
linkType: hard
"@codemirror/search@npm:6.5.6":
version: 6.5.6
resolution: "@codemirror/search@npm:6.5.6"
"@codemirror/search@npm:6.5.7":
version: 6.5.7
resolution: "@codemirror/search@npm:6.5.7"
dependencies:
"@codemirror/state": "npm:^6.0.0"
"@codemirror/view": "npm:^6.0.0"
crelt: "npm:^1.0.5"
checksum: 10/6668a34b4617e909617d3d831627d74b7a7985e8cd86d396bfcb3e86262f2310fc029fd6c846f1b8f1e6768e75985c9f1b0b18b31e05341f06b5b75c1ffde38d
checksum: 10/0a4c5e23c42231ffb829513940ee43a630585b4277fa8cc919a947f3821c9c2dc095d334bb0e4d51b3ebb50739a34a81ddbcc39ca9c1f6f935fdaa51a86661bf
languageName: node
linkType: hard
@ -3944,7 +3944,27 @@ __metadata:
languageName: node
linkType: hard
"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5":
"@types/eslint-scope@npm:^3.7.7":
version: 3.7.7
resolution: "@types/eslint-scope@npm:3.7.7"
dependencies:
"@types/eslint": "npm:*"
"@types/estree": "npm:*"
checksum: 10/e2889a124aaab0b89af1bab5959847c5bec09809209255de0e63b9f54c629a94781daa04adb66bffcdd742f5e25a17614fb933965093c0eea64aacda4309380e
languageName: node
linkType: hard
"@types/eslint@npm:*":
version: 9.6.1
resolution: "@types/eslint@npm:9.6.1"
dependencies:
"@types/estree": "npm:*"
"@types/json-schema": "npm:*"
checksum: 10/719fcd255760168a43d0e306ef87548e1e15bffe361d5f4022b0f266575637acc0ecb85604ac97879ee8ae83c6a6d0613b0ed31d0209ddf22a0fe6d608fc56fe
languageName: node
linkType: hard
"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6":
version: 1.0.6
resolution: "@types/estree@npm:1.0.6"
checksum: 10/9d35d475095199c23e05b431bcdd1f6fec7380612aed068b14b2a08aa70494de8a9026765a5a91b1073f636fb0368f6d8973f518a31391d519e20c59388ed88d
@ -4090,7 +4110,7 @@ __metadata:
languageName: node
linkType: hard
"@types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
version: 7.0.15
resolution: "@types/json-schema@npm:7.0.15"
checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7
@ -5187,15 +5207,6 @@ __metadata:
languageName: node
linkType: hard
"acorn-import-attributes@npm:^1.9.5":
version: 1.9.5
resolution: "acorn-import-attributes@npm:1.9.5"
peerDependencies:
acorn: ^8
checksum: 10/8bfbfbb6e2467b9b47abb4d095df717ab64fce2525da65eabee073e85e7975fb3a176b6c8bba17c99a7d8ede283a10a590272304eb54a93c4aa1af9790d47a8b
languageName: node
linkType: hard
"acorn-jsx@npm:^5.3.2":
version: 5.3.2
resolution: "acorn-jsx@npm:5.3.2"
@ -5205,12 +5216,12 @@ __metadata:
languageName: node
linkType: hard
"acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0":
version: 8.13.0
resolution: "acorn@npm:8.13.0"
"acorn@npm:^8.14.0, acorn@npm:^8.5.0, acorn@npm:^8.8.2, acorn@npm:^8.9.0":
version: 8.14.0
resolution: "acorn@npm:8.14.0"
bin:
acorn: bin/acorn
checksum: 10/33e3a03114b02b3bc5009463b3d9549b31a90ee38ebccd5e66515830a02acf62a90edcc12abfb6c9fb3837b6c17a3ec9b72b3bf52ac31d8ad8248a4af871e0f5
checksum: 10/6df29c35556782ca9e632db461a7f97947772c6c1d5438a81f0c873a3da3a792487e83e404d1c6c25f70513e91aa18745f6eafb1fcc3a43ecd1920b21dd173d2
languageName: node
linkType: hard
@ -5881,7 +5892,7 @@ __metadata:
languageName: node
linkType: hard
"browserslist@npm:^4.21.10, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0":
"browserslist@npm:^4.23.3, browserslist@npm:^4.24.0":
version: 4.24.0
resolution: "browserslist@npm:4.24.0"
dependencies:
@ -6540,10 +6551,10 @@ __metadata:
languageName: node
linkType: hard
"core-js@npm:3.38.1":
version: 3.38.1
resolution: "core-js@npm:3.38.1"
checksum: 10/3c25fdf0b2595ed37ceb305213a61e2cf26185f628455e99d1c736dda5f69e2de4de7126e6a1da136f54260c4fcc982c4215e37b5a618790a597930f854c0a37
"core-js@npm:3.39.0":
version: 3.39.0
resolution: "core-js@npm:3.39.0"
checksum: 10/a3d34e669783dfc878e545f1983f60d9ff48a3867cd1d7ff8839b849e053002a208c7c14a5ca354b8e0b54982901e2f83dc87c3d9b95de0a94b4071d1c74e5f6
languageName: node
linkType: hard
@ -8716,11 +8727,11 @@ __metadata:
"@babel/runtime": "npm:7.26.0"
"@braintree/sanitize-url": "npm:7.1.0"
"@bundle-stats/plugin-webpack-filter": "npm:4.16.0"
"@codemirror/autocomplete": "npm:6.18.1"
"@codemirror/autocomplete": "npm:6.18.2"
"@codemirror/commands": "npm:6.7.1"
"@codemirror/language": "npm:6.10.3"
"@codemirror/legacy-modes": "npm:6.4.1"
"@codemirror/search": "npm:6.5.6"
"@codemirror/search": "npm:6.5.7"
"@codemirror/state": "npm:6.4.1"
"@codemirror/view": "npm:6.34.1"
"@egjs/hammerjs": "npm:2.0.17"
@ -8827,7 +8838,7 @@ __metadata:
chart.js: "npm:4.4.6"
color-name: "npm:2.0.0"
comlink: "npm:4.4.1"
core-js: "npm:3.38.1"
core-js: "npm:3.39.0"
cropperjs: "npm:1.6.2"
date-fns: "npm:4.1.0"
date-fns-tz: "npm:3.2.0"
@ -8877,7 +8888,7 @@ __metadata:
map-stream: "npm:0.0.7"
marked: "npm:14.1.3"
memoize-one: "npm:6.0.0"
mocha: "npm:10.7.3"
mocha: "npm:10.8.2"
node-vibrant: "npm:3.2.1-alpha.1"
object-hash: "npm:3.0.0"
open: "npm:10.1.0"
@ -8913,7 +8924,7 @@ __metadata:
vis-network: "npm:9.1.9"
vue: "npm:2.7.16"
vue2-daterange-picker: "npm:0.6.8"
webpack: "npm:5.95.0"
webpack: "npm:5.96.1"
webpack-cli: "npm:5.1.4"
webpack-dev-server: "npm:5.1.0"
webpack-manifest-plugin: "npm:5.0.0"
@ -8921,12 +8932,12 @@ __metadata:
webpackbar: "npm:6.0.1"
weekstart: "npm:2.0.0"
workbox-build: "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"
workbox-cacheable-response: "npm:7.1.0"
workbox-core: "npm:7.1.0"
workbox-expiration: "npm:7.1.0"
workbox-precaching: "npm:7.1.0"
workbox-routing: "npm:7.1.0"
workbox-strategies: "npm:7.1.0"
workbox-cacheable-response: "npm:7.3.0"
workbox-core: "npm:7.3.0"
workbox-expiration: "npm:7.3.0"
workbox-precaching: "npm:7.3.0"
workbox-routing: "npm:7.3.0"
workbox-strategies: "npm:7.3.0"
xss: "npm:1.0.15"
languageName: unknown
linkType: soft
@ -10966,9 +10977,9 @@ __metadata:
languageName: node
linkType: hard
"mocha@npm:10.7.3":
version: 10.7.3
resolution: "mocha@npm:10.7.3"
"mocha@npm:10.8.2":
version: 10.8.2
resolution: "mocha@npm:10.8.2"
dependencies:
ansi-colors: "npm:^4.1.3"
browser-stdout: "npm:^1.3.1"
@ -10993,7 +11004,7 @@ __metadata:
bin:
_mocha: bin/_mocha
mocha: bin/mocha.js
checksum: 10/5757aeb320df2507338bfba41731070ce16d27177c5876672fff4bcc4f7b7bcf1afe6ec761bfded43a5d28032d7b797b8b905b5b44c9420203f3ee71457732c1
checksum: 10/903bbffcb195ef9d36b27db54e3462c5486de1397289e0953735b3530397a139336c452bcf5188c663496c660d2285bbb6c7213290d36d536ad647b6145cb917
languageName: node
linkType: hard
@ -14678,17 +14689,17 @@ __metadata:
languageName: node
linkType: hard
"webpack@npm:5.95.0":
version: 5.95.0
resolution: "webpack@npm:5.95.0"
"webpack@npm:5.96.1":
version: 5.96.1
resolution: "webpack@npm:5.96.1"
dependencies:
"@types/estree": "npm:^1.0.5"
"@types/eslint-scope": "npm:^3.7.7"
"@types/estree": "npm:^1.0.6"
"@webassemblyjs/ast": "npm:^1.12.1"
"@webassemblyjs/wasm-edit": "npm:^1.12.1"
"@webassemblyjs/wasm-parser": "npm:^1.12.1"
acorn: "npm:^8.7.1"
acorn-import-attributes: "npm:^1.9.5"
browserslist: "npm:^4.21.10"
acorn: "npm:^8.14.0"
browserslist: "npm:^4.24.0"
chrome-trace-event: "npm:^1.0.2"
enhanced-resolve: "npm:^5.17.1"
es-module-lexer: "npm:^1.2.1"
@ -14710,7 +14721,7 @@ __metadata:
optional: true
bin:
webpack: bin/webpack.js
checksum: 10/0377ad3a550b041f26237c96fb55754625b0ce6bae83c1c2447e3262ad056b0b0ad770dcbb92b59f188e9a2bd56155ce910add17dcf023cfbe78bdec774380c1
checksum: 10/d3419ffd198252e1d0301bd0c072cee93172f3e47937c745aa8202691d2f5d529d4ba4a1965d1450ad89a1bcd3c1f70ae09e57232b0d01dd38d69c1060e964d5
languageName: node
linkType: hard
@ -14990,6 +15001,15 @@ __metadata:
languageName: node
linkType: hard
"workbox-cacheable-response@npm:7.3.0":
version: 7.3.0
resolution: "workbox-cacheable-response@npm:7.3.0"
dependencies:
workbox-core: "npm:7.3.0"
checksum: 10/44cd7bc26e509ca96b1b84e3ff5964296efa645853f114f39789d21c0a214ca5fc047259910b303e220bb4052155cddc5639993fcee076fac496b4895ff17a15
languageName: node
linkType: hard
"workbox-core@npm:7.1.0":
version: 7.1.0
resolution: "workbox-core@npm:7.1.0"
@ -14997,6 +15017,13 @@ __metadata:
languageName: node
linkType: hard
"workbox-core@npm:7.3.0":
version: 7.3.0
resolution: "workbox-core@npm:7.3.0"
checksum: 10/228fb7018a0568c329e21d47d84980f93ebfef9b1eb3f40ddc3516ca6ae58d51dc7ca4dddc829332775b59a3079e62d105c5e1c5c312805d177b963f8bf54393
languageName: node
linkType: hard
"workbox-expiration@npm:7.1.0":
version: 7.1.0
resolution: "workbox-expiration@npm:7.1.0"
@ -15007,6 +15034,16 @@ __metadata:
languageName: node
linkType: hard
"workbox-expiration@npm:7.3.0":
version: 7.3.0
resolution: "workbox-expiration@npm:7.3.0"
dependencies:
idb: "npm:^7.0.1"
workbox-core: "npm:7.3.0"
checksum: 10/83e021d700e521a65a89907679d1a580aacc0419428286910ec7c6b0a538326f71f05566434f666ebf6c9fbe819ef3ea81428df1d868f9ea92527afe5d11152d
languageName: node
linkType: hard
"workbox-google-analytics@npm:7.1.0":
version: 7.1.0
resolution: "workbox-google-analytics@npm:7.1.0"
@ -15039,6 +15076,17 @@ __metadata:
languageName: node
linkType: hard
"workbox-precaching@npm:7.3.0":
version: 7.3.0
resolution: "workbox-precaching@npm:7.3.0"
dependencies:
workbox-core: "npm:7.3.0"
workbox-routing: "npm:7.3.0"
workbox-strategies: "npm:7.3.0"
checksum: 10/d14135c471a45de36438c40eed7cb7157cdb336d4216a775486c6307d1ac316794d64231c2e2d0a4c313bb4a4fec623ab77e391cc458b4f2afa64e2487acb2e8
languageName: node
linkType: hard
"workbox-range-requests@npm:7.1.0":
version: 7.1.0
resolution: "workbox-range-requests@npm:7.1.0"
@ -15071,6 +15119,15 @@ __metadata:
languageName: node
linkType: hard
"workbox-routing@npm:7.3.0":
version: 7.3.0
resolution: "workbox-routing@npm:7.3.0"
dependencies:
workbox-core: "npm:7.3.0"
checksum: 10/0d729f9c5cfc5754404ac1f7b729c7740ddc806203792701ac642151fbec939b4aa0fb289eab2295e49180e8154ad9bb1380effb7e0f0362163b79db4291dba7
languageName: node
linkType: hard
"workbox-strategies@npm:7.1.0":
version: 7.1.0
resolution: "workbox-strategies@npm:7.1.0"
@ -15080,6 +15137,15 @@ __metadata:
languageName: node
linkType: hard
"workbox-strategies@npm:7.3.0":
version: 7.3.0
resolution: "workbox-strategies@npm:7.3.0"
dependencies:
workbox-core: "npm:7.3.0"
checksum: 10/61ba672075ef8aaa70ad9221460dab80a7d8920e324e14137460f26ebe8b137e5589fb75c664e0efeaf4402e3d8435a9b1818f9a9c61f88863c0e0315af337e7
languageName: node
linkType: hard
"workbox-streams@npm:7.1.0":
version: 7.1.0
resolution: "workbox-streams@npm:7.1.0"