Compare commits

...

12 Commits

Author SHA1 Message Date
Petar Petrov
59b0b964ff Type fix 2026-04-21 11:47:21 +03:00
Paul Bottein
ebf4b0d000 Merge branch 'dev' into claude/security-dashboard-activity-log-Rqwej 2026-04-21 10:06:41 +02:00
MikeDev96
c8459eb781 Add paste above/below buttons in automation editor (#51495)
* Add paste above/below buttons in automation editor

* Removed paste above option and renamed paste below to paste

* Added shortcut hint to paste options
2026-04-21 09:27:11 +02:00
Aidan Timson
74fd7b61f1 Add missing actions permission to stale workflow (#51638)
* Add missing actions permission to stale workflow

* Prioritise oldest updated items

* Don't change ordering
2026-04-21 08:45:10 +03:00
renovate[bot]
5d32bf338b Update dependency eslint to v10.2.1 (#51648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-21 08:44:10 +03:00
Stefan Agner
4848e939b4 Fix supervisor My redirects for Container installs (#51645)
The supervisor_* My redirects (supervisor_store, supervisor_addons,
supervisor_app, supervisor_addon, supervisor_add_addon_repository) had
no component gate, so on Container installations they silently
navigated to broken pages. Gate them on the hassio component and route
the missing-hassio case through the existing no_supervisor error
message, which now links directly to the installation docs.

Also remove the unreachable /hassio/_my_redirect/ fallback that was
left behind by the standalone hassio panel removal (#29132), and
update the no_supervisor string: Home Assistant Supervised is no
longer a supported installation method (see architecture discussion
home-assistant/architecture#1198), only Home Assistant OS.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 18:32:30 +02:00
Stefan Agner
23acfc729c Remove dead /hassio URL references (#51643)
The standalone hassio panel at /hassio was removed in #29132 and
replaced by the apps panel under /config/apps in #28245. A couple of
references to the old URL path were missed: a dead branch in the
quick-bar My-link builder and a /hassio/ startsWith check that kept
the configuration sidebar item highlighted.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 18:13:06 +02:00
Paul Bottein
93110b1d70 Fix section config not propagating to layout element (#51640) 2026-04-20 15:29:16 +02:00
Paul Bottein
730fdd3931 Set max column to 3 and fix title margin 2026-03-02 15:07:31 +01:00
Petar Petrov
0bd7b242b7 remove import 2026-03-02 15:47:51 +02:00
Petar Petrov
b17774ff3d Update src/panels/security/strategies/security-view-strategy.ts 2026-03-02 11:46:50 +02:00
Claude
e037a83ed2 Add activity log sidebar to security dashboard
Add a sidebar with a logbook card to the security domain dashboard,
filtered by security entities (cameras, locks, alarm panels, covers,
binary sensors) and person entities. The sidebar uses the sections view
sidebar layout with mobile tab support for switching between devices
and activity views on narrow screens.

https://claude.ai/code/session_01MCjuARQfuyowAbJ9fwiEnH
2026-02-26 12:22:16 +00:00
21 changed files with 363 additions and 54 deletions

View File

@@ -6,6 +6,7 @@ on:
- cron: "0 * * * *"
permissions:
actions: write
issues: write
pull-requests: write

View File

@@ -167,7 +167,7 @@
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.4",
"del": "8.0.1",
"eslint": "10.2.0",
"eslint": "10.2.1",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-webpack": "0.13.11",

View File

@@ -454,8 +454,7 @@ class HaSidebar extends SubscribeMixin(ScrollableFadeMixin(LitElement)) {
if (!this.hass.user?.is_admin) {
return nothing;
}
const isSelected =
selectedPanel === "config" || this.route.path?.startsWith("/hassio/");
const isSelected = selectedPanel === "config";
return html`
<ha-md-list-item
class="configuration ${classMap({ selected: isSelected })}"

View File

@@ -607,6 +607,8 @@ export interface TriggerSidebarConfig extends BaseSidebarConfig {
description?: TriggerDescription;
yamlMode: boolean;
uiSupported: boolean;
paste: () => void;
pasteAvailable: () => boolean;
}
export interface ConditionSidebarConfig extends BaseSidebarConfig {
@@ -623,6 +625,8 @@ export interface ConditionSidebarConfig extends BaseSidebarConfig {
description?: ConditionDescription;
yamlMode: boolean;
uiSupported: boolean;
paste: () => void;
pasteAvailable: () => boolean;
}
export interface ActionSidebarConfig extends BaseSidebarConfig {
@@ -641,6 +645,8 @@ export interface ActionSidebarConfig extends BaseSidebarConfig {
};
yamlMode: boolean;
uiSupported: boolean;
paste: () => void;
pasteAvailable: () => boolean;
}
export interface OptionSidebarConfig extends BaseSidebarConfig {

View File

@@ -10,6 +10,7 @@ import {
mdiCheckboxOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
mdiDelete,
mdiDotsVertical,
mdiPlay,
@@ -385,6 +386,31 @@ export default class HaAutomationActionRow extends LitElement {
)}
</ha-dropdown-item>
${this._pasteAvailable()
? html`
<ha-dropdown-item value="paste">
<ha-svg-icon slot="icon" .path=${mdiContentPaste}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.paste"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>V</span>
</span>`
)}
</ha-dropdown-item>
`
: nothing}
${!this.optionsInSidebar
? html`
<ha-dropdown-item
@@ -769,6 +795,9 @@ export default class HaAutomationActionRow extends LitElement {
private _copyAction = () => {
this._setClipboard();
if (this._selected && this.optionsInSidebar) {
this.openSidebar(); // refresh sidebar
}
showEditorToast(this, {
message: this.hass.localize(
"ui.panel.config.automation.editor.actions.copied_to_clipboard"
@@ -791,6 +820,15 @@ export default class HaAutomationActionRow extends LitElement {
});
};
private _pasteAction = () => {
const action = this._clipboard?.action;
if (!action) return;
fireEvent(this, "paste", { item: action });
};
private _pasteAvailable = () => !!this._clipboard?.action;
private _moveUp = () => {
fireEvent(this, "move-up");
};
@@ -868,6 +906,8 @@ export default class HaAutomationActionRow extends LitElement {
delete: this._onDelete,
copy: this._copyAction,
cut: this._cutAction,
paste: this._pasteAction,
pasteAvailable: this._pasteAvailable,
duplicate: this._duplicateAction,
insertAfter: this._insertAfter,
run: this._runAction,
@@ -961,6 +1001,9 @@ export default class HaAutomationActionRow extends LitElement {
case "cut":
this._cutAction();
break;
case "paste":
this._pasteAction();
break;
case "move_up":
this._moveUp();
break;

View File

@@ -80,6 +80,7 @@ export default class HaAutomationAction extends AutomationSortableListMixin<Acti
.narrow=${this.narrow}
.disabled=${this.disabled}
@duplicate=${this.duplicateItem}
@paste=${this.pasteItem}
@insert-after=${this.insertAfter}
@move-down=${this.moveDown}
@move-up=${this.moveUp}

View File

@@ -6,6 +6,7 @@ import {
mdiArrowUp,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
mdiDelete,
mdiDotsVertical,
mdiFlask,
@@ -278,6 +279,31 @@ export default class HaAutomationConditionRow extends LitElement {
)}
</ha-dropdown-item>
${this._pasteAvailable()
? html`
<ha-dropdown-item value="paste">
<ha-svg-icon slot="icon" .path=${mdiContentPaste}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.paste"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>V</span>
</span>`
)}
</ha-dropdown-item>
`
: nothing}
${!this.optionsInSidebar
? html`
<ha-dropdown-item
@@ -665,6 +691,9 @@ export default class HaAutomationConditionRow extends LitElement {
private _copyCondition = () => {
this._setClipboard();
if (this._selected && this.optionsInSidebar) {
this.openSidebar(); // refresh sidebar
}
showEditorToast(this, {
message: this.hass.localize(
"ui.panel.config.automation.editor.conditions.copied_to_clipboard"
@@ -687,6 +716,15 @@ export default class HaAutomationConditionRow extends LitElement {
});
};
private _pasteCondition = () => {
const condition = this._clipboard?.condition;
if (!condition) return;
fireEvent(this, "paste", { item: condition });
};
private _pasteAvailable = () => !!this._clipboard?.condition;
private _moveUp = () => {
fireEvent(this, "move-up");
};
@@ -790,6 +828,8 @@ export default class HaAutomationConditionRow extends LitElement {
insertAfter: this._insertAfter,
copy: this._copyCondition,
cut: this._cutCondition,
paste: this._pasteCondition,
pasteAvailable: this._pasteAvailable,
test: this._testCondition,
config: sidebarCondition,
uiSupported: this._uiSupported(
@@ -858,6 +898,9 @@ export default class HaAutomationConditionRow extends LitElement {
case "cut":
this._cutCondition();
break;
case "paste":
this._pasteCondition();
break;
case "move_up":
this._moveUp();
break;

View File

@@ -226,6 +226,7 @@ export default class HaAutomationCondition extends AutomationSortableListMixin<C
.disabled=${this.disabled}
.narrow=${this.narrow}
@duplicate=${this.duplicateItem}
@paste=${this.pasteItem}
@insert-after=${this.insertAfter}
@move-down=${this.moveDown}
@move-up=${this.moveUp}

View File

@@ -104,6 +104,9 @@ declare global {
value: Trigger | Condition | Action | Trigger[] | Condition[] | Action[];
};
"save-automation": undefined;
paste: {
item: Trigger | Condition | Action;
};
}
}

View File

@@ -165,6 +165,21 @@ export const AutomationSortableListMixin = <T extends object>(
});
}
protected pasteItem(ev: CustomEvent) {
ev.stopPropagation();
if (!ev.detail.item) return;
const index = (ev.target as any).index;
const clonedItem = deepClone(ev.detail.item);
this.setHighlightedItems(ensureArray(clonedItem));
fireEvent(this, "value-changed", {
// @ts-expect-error Requires library bump to ES2023
value: this.items.toSpliced(index + 1, 0, clonedItem),
});
}
protected insertAfter(ev: CustomEvent) {
ev.stopPropagation();
const index = (ev.target as any).index;

View File

@@ -5,6 +5,7 @@ import {
mdiCheckboxOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
mdiDelete,
mdiPlay,
mdiPlayCircleOutline,
@@ -228,6 +229,37 @@ export default class HaAutomationSidebarAction extends LitElement {
: nothing}
</div>
</ha-dropdown-item>
${this.config.pasteAvailable()
? html`
<ha-dropdown-item
slot="menu-items"
value="paste"
.disabled=${this.disabled}
>
<ha-svg-icon slot="icon" .path=${mdiContentPaste}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.paste"
)}
${!this.narrow
? html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>V</span>
</span>`
: nothing}
</div>
</ha-dropdown-item>
`
: nothing}
<ha-dropdown-item
slot="menu-items"
value="toggle_yaml_mode"
@@ -391,6 +423,9 @@ export default class HaAutomationSidebarAction extends LitElement {
case "cut":
this.config.cut();
break;
case "paste":
this.config.paste();
break;
case "toggle_yaml_mode":
this._toggleYamlMode();
break;

View File

@@ -3,6 +3,7 @@ import {
mdiAppleKeyboardCommand,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
mdiDelete,
mdiFlask,
mdiPlayCircleOutline,
@@ -221,6 +222,37 @@ export default class HaAutomationSidebarCondition extends LitElement {
: nothing}
</div>
</ha-dropdown-item>
${this.config.pasteAvailable()
? html`
<ha-dropdown-item
slot="menu-items"
value="paste"
.disabled=${this.disabled}
>
<ha-svg-icon slot="icon" .path=${mdiContentPaste}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.paste"
)}
${!this.narrow
? html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>V</span>
</span>`
: nothing}
</div>
</ha-dropdown-item>
`
: nothing}
<ha-dropdown-item
slot="menu-items"
value="toggle_yaml_mode"
@@ -436,6 +468,9 @@ export default class HaAutomationSidebarCondition extends LitElement {
case "cut":
this.config.cut();
break;
case "paste":
this.config.paste();
break;
case "toggle_yaml_mode":
this._toggleYamlMode();
break;

View File

@@ -3,6 +3,7 @@ import {
mdiAppleKeyboardCommand,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
mdiDelete,
mdiIdentifier,
mdiPlayCircleOutline,
@@ -209,6 +210,37 @@ export default class HaAutomationSidebarTrigger extends LitElement {
: nothing}
</div>
</ha-dropdown-item>
${this.config.pasteAvailable()
? html`
<ha-dropdown-item
slot="menu-items"
value="paste"
.disabled=${this.disabled}
>
<ha-svg-icon slot="icon" .path=${mdiContentPaste}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.paste"
)}
${!this.narrow
? html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>V</span>
</span>`
: nothing}
</div>
</ha-dropdown-item>
`
: nothing}
<ha-dropdown-item
slot="menu-items"
value="toggle_yaml_mode"
@@ -351,6 +383,9 @@ export default class HaAutomationSidebarTrigger extends LitElement {
case "cut":
this.config.cut();
break;
case "paste":
this.config.paste();
break;
case "toggle_yaml_mode":
this._toggleYamlMode();
break;

View File

@@ -6,6 +6,7 @@ import {
mdiArrowUp,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
mdiDelete,
mdiDotsVertical,
mdiInformationOutline,
@@ -314,6 +315,31 @@ export default class HaAutomationTriggerRow extends LitElement {
)}
</ha-dropdown-item>
${this._pasteAvailable()
? html`
<ha-dropdown-item value="paste">
<ha-svg-icon slot="icon" .path=${mdiContentPaste}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.paste"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>V</span>
</span>`
)}
</ha-dropdown-item>
`
: nothing}
${!this.optionsInSidebar
? html`
<ha-dropdown-item
@@ -622,6 +648,8 @@ export default class HaAutomationTriggerRow extends LitElement {
copy: this._copyTrigger,
duplicate: this._duplicateTrigger,
cut: this._cutTrigger,
paste: this._pasteTrigger,
pasteAvailable: this._pasteAvailable,
insertAfter: this._insertAfter,
config: trigger,
uiSupported: this._uiSupported(
@@ -762,6 +790,9 @@ export default class HaAutomationTriggerRow extends LitElement {
private _copyTrigger = () => {
this._setClipboard();
if (this._selected && this.optionsInSidebar) {
this.openSidebar(); // refresh sidebar
}
showEditorToast(this, {
message: this.hass.localize(
"ui.panel.config.automation.editor.triggers.copied_to_clipboard"
@@ -784,6 +815,15 @@ export default class HaAutomationTriggerRow extends LitElement {
});
};
private _pasteTrigger = () => {
const trigger = this._clipboard?.trigger;
if (!trigger) return;
fireEvent(this, "paste", { item: trigger });
};
private _pasteAvailable = () => !!this._clipboard?.trigger;
private _moveUp = () => {
fireEvent(this, "move-up");
};
@@ -856,6 +896,9 @@ export default class HaAutomationTriggerRow extends LitElement {
case "cut":
this._cutTrigger();
break;
case "paste":
this._pasteTrigger();
break;
case "move_up":
this._moveUp();
break;

View File

@@ -137,6 +137,7 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
.trigger=${trg}
.triggerDescriptions=${this._triggerDescriptions}
@duplicate=${this.duplicateItem}
@paste=${this.pasteItem}
@insert-after=${this.insertAfter}
@move-down=${this.moveDown}
@move-up=${this.moveUp}

View File

@@ -210,6 +210,8 @@ export class HuiSection extends ConditionalListenerMixin<LovelaceSectionConfig>(
) {
addLayoutElement = true;
this._createLayoutElement(this._config);
} else {
this._layoutElement.setConfig(sectionConfig);
}
this._createCards(sectionConfig);

View File

@@ -336,12 +336,15 @@ export const getMyRedirects = (): Redirects => ({
redirect: "/config/info",
},
supervisor_store: {
component: "hassio",
redirect: "/config/apps/available",
},
supervisor_addons: {
component: "hassio",
redirect: "/config/apps",
},
supervisor_app: {
component: "hassio",
redirect: "/config/app",
params: {
app: "string",
@@ -351,6 +354,7 @@ export const getMyRedirects = (): Redirects => ({
},
},
supervisor_addon: {
component: "hassio",
redirect: "/config/app",
params: {
addon: "string",
@@ -360,6 +364,7 @@ export const getMyRedirects = (): Redirects => ({
},
},
supervisor_add_addon_repository: {
component: "hassio",
redirect: "/config/apps/available",
params: {
repository_url: "url",
@@ -410,21 +415,9 @@ class HaPanelMy extends LitElement {
1,
this.route.path.endsWith("/") ? this.route.path.length - 1 : undefined
);
const hasSupervisor = isComponentLoaded(this.hass.config, "hassio");
this._redirect = getRedirect(path);
if (path.startsWith("supervisor") && this._redirect === undefined) {
if (!hasSupervisor) {
this._error = "no_supervisor";
return;
}
navigate(`/hassio/_my_redirect/${path}${window.location.search}`, {
replace: true,
});
return;
}
if (!this._redirect) {
this._error = "not_supported";
return;
@@ -444,7 +437,10 @@ class HaPanelMy extends LitElement {
!isComponentLoaded(this.hass.config, this._redirect.component)
) {
this.hass.loadBackendTranslation("title", this._redirect.component);
this._error = "no_component";
this._error =
this._redirect.component === "hassio"
? "no_supervisor"
: "no_component";
const component = this._redirect.component;
if ((PROTOCOL_INTEGRATIONS as readonly string[]).includes(component)) {
const params = extractSearchParamsObject();

View File

@@ -1,16 +1,22 @@
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,
generateEntityFilter,
type EntityFilter,
} from "../../../common/entity/entity_filter";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { floorDefaultIcon } from "../../../components/ha-floor-icon";
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
import type { LovelaceSectionRawConfig } from "../../../data/lovelace/config/section";
import type {
LovelaceSectionConfig,
LovelaceSectionRawConfig,
} from "../../../data/lovelace/config/section";
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
import type { HomeAssistant } from "../../../types";
import type { LogbookCardConfig } from "../../lovelace/cards/types";
import { computeAreaTileCardConfig } from "../../lovelace/strategies/areas/helpers/areas-strategy-helper";
export interface SecurityViewStrategyConfig {
@@ -226,10 +232,55 @@ export class SecurityViewStrategy extends ReactiveElement {
sections.push(section);
}
// Build sidebar with activity log
const hasLogbook = isComponentLoaded(hass.config, "logbook");
// Collect person entity IDs
const personEntities = Object.keys(hass.states).filter(
(entityId) => computeStateDomain(hass.states[entityId]) === "person"
);
const logbookEntityIds = [...entities, ...personEntities];
const sidebarSection: LovelaceSectionConfig | undefined =
hasLogbook && logbookEntityIds.length > 0
? {
type: "grid",
cards: [
{
type: "heading",
heading: hass.localize(
"ui.panel.lovelace.strategy.security.activity"
),
heading_style: "title",
} as LovelaceCardConfig,
{
type: "logbook",
target: {
entity_id: logbookEntityIds,
},
hours_to_show: 24,
grid_options: { columns: 12 },
} satisfies LogbookCardConfig,
],
}
: undefined;
return {
type: "sections",
max_columns: 2,
max_columns: 3,
sections: sections,
...(sidebarSection && {
sidebar: {
sections: [sidebarSection],
content_label: hass.localize(
"ui.panel.lovelace.strategy.security.devices"
),
sidebar_label: hass.localize(
"ui.panel.lovelace.strategy.security.activity"
),
},
}),
};
}
}

View File

@@ -340,8 +340,6 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
if (repo && repo.source !== "local") {
myParams.append("repository_url", repo.source);
}
} else if (redirect.redirect === "/hassio/addon") {
myParams.append("addon", targetPath.split("/")[3]);
}
window.open(
`https://my.home-assistant.io/create-link/?${myParams.toString()}`,

View File

@@ -2526,7 +2526,7 @@
"my": {
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
"component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.",
"no_supervisor": "This redirect is not supported by your Home Assistant installation. It needs either the Home Assistant OS or Home Assistant Supervised installation method. For more information, see the {docs_link}.",
"no_supervisor": "This redirect is not supported by your Home Assistant installation. It needs the Home Assistant OS installation method. For more information, see the {docs_link}.",
"not_app": "This redirect only works from a mobile device that has the Home Assistant Companion app installed. {link}.",
"url_error": "The provided URL is invalid.",
"documentation": "documentation",
@@ -8348,7 +8348,8 @@
},
"security": {
"devices": "Devices",
"other_devices": "Other devices"
"other_devices": "Other devices",
"activity": "Activity"
},
"climate": {
"devices": "Devices",

View File

@@ -1501,23 +1501,23 @@ __metadata:
languageName: node
linkType: hard
"@eslint/config-array@npm:^0.23.4":
version: 0.23.4
resolution: "@eslint/config-array@npm:0.23.4"
"@eslint/config-array@npm:^0.23.5":
version: 0.23.5
resolution: "@eslint/config-array@npm:0.23.5"
dependencies:
"@eslint/object-schema": "npm:^3.0.4"
"@eslint/object-schema": "npm:^3.0.5"
debug: "npm:^4.3.1"
minimatch: "npm:^10.2.4"
checksum: 10/a42bdf8d66d52703596d5a791eedb1ad79e232dad58e0450b65d8ad48c2fdf50ee62d26fe0e823092384e93378c39adeea30eb1cd12af7ee207a142f9e1996eb
checksum: 10/0e05be2b5c8b9f9fb8094948fd2d35591a32091b9d39205181f2ed9bec0e2c8b2969f019f40a0388755a025408b98929e2d0beccb4fbd6609c1c0d6c9e9a14f0
languageName: node
linkType: hard
"@eslint/config-helpers@npm:^0.5.4":
version: 0.5.4
resolution: "@eslint/config-helpers@npm:0.5.4"
"@eslint/config-helpers@npm:^0.5.5":
version: 0.5.5
resolution: "@eslint/config-helpers@npm:0.5.5"
dependencies:
"@eslint/core": "npm:^1.2.0"
checksum: 10/277c951ac82b28e2f56adae3cf64ddcfa4e0fb07e8beaa853c2070e07fcb6062fc48a257ddfa12027aaead698f031bc81c343e0c9ddf7a8f59b724e119552897
"@eslint/core": "npm:^1.2.1"
checksum: 10/19072449502b928a716df87b2d9b13c7befb21974b0f93fdbea705ddba098792142808105170ef2183c28ce13ac9fa1713ef0599749f8469434ac2b914fc8f4d
languageName: node
linkType: hard
@@ -1530,12 +1530,12 @@ __metadata:
languageName: node
linkType: hard
"@eslint/core@npm:^1.2.0":
version: 1.2.0
resolution: "@eslint/core@npm:1.2.0"
"@eslint/core@npm:^1.2.1":
version: 1.2.1
resolution: "@eslint/core@npm:1.2.1"
dependencies:
"@types/json-schema": "npm:^7.0.15"
checksum: 10/b4e459ea69935cbed0b99f2160631fcabb3489d950dde86989b1da395f7649bedb14c702afc82e7cb64b6d7c62a6a10f8dae8dcf4c92dc3035bcbe531e65603e
checksum: 10/e1f9f5534f495b74a4c13c372e8f2feaf0c67f5dd666111c849c97c221d4ba730c98333a2ca94dd28cd7c24e3b1016bd868ca03c42e070732c047053f854cb13
languageName: node
linkType: hard
@@ -1568,10 +1568,10 @@ __metadata:
languageName: node
linkType: hard
"@eslint/object-schema@npm:^3.0.4":
version: 3.0.4
resolution: "@eslint/object-schema@npm:3.0.4"
checksum: 10/16daaf207aea472852465619fd29db29e0ab897353347020c52d526e27d8ceb44516506d4da61ff0a89cb8bd5ad935b882aca255ff1bc44ea9a59b1bd8de75bb
"@eslint/object-schema@npm:^3.0.5":
version: 3.0.5
resolution: "@eslint/object-schema@npm:3.0.5"
checksum: 10/42e9ec2551d7cafe1825f20494576c9a867dfd26e728b66620f55d954cd5c4c9c4987755d147893985b8d39b49dace31117e59e7bc9564eb411b397e579a50e7
languageName: node
linkType: hard
@@ -1585,13 +1585,13 @@ __metadata:
languageName: node
linkType: hard
"@eslint/plugin-kit@npm:^0.7.0":
version: 0.7.0
resolution: "@eslint/plugin-kit@npm:0.7.0"
"@eslint/plugin-kit@npm:^0.7.1":
version: 0.7.1
resolution: "@eslint/plugin-kit@npm:0.7.1"
dependencies:
"@eslint/core": "npm:^1.2.0"
"@eslint/core": "npm:^1.2.1"
levn: "npm:^0.4.1"
checksum: 10/3e435cc19db205f4a70ecba060e22b9b7efa2809426c0b020347b3aea0ae5e3507628486c1bc1a18a32fbad1e8cf0fd2ec11ca6ca6a6b958d141291426257c15
checksum: 10/8f923f4cdadadd215e0c2028e6a53101bb148a7780cdb4dc8cd69b0c77fc88496742e87e0605b12905ff715e2c7ad6cbd2d92c5653cdbf91cca1e229b5022c1f
languageName: node
linkType: hard
@@ -7748,16 +7748,16 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:10.2.0":
version: 10.2.0
resolution: "eslint@npm:10.2.0"
"eslint@npm:10.2.1":
version: 10.2.1
resolution: "eslint@npm:10.2.1"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.8.0"
"@eslint-community/regexpp": "npm:^4.12.2"
"@eslint/config-array": "npm:^0.23.4"
"@eslint/config-helpers": "npm:^0.5.4"
"@eslint/core": "npm:^1.2.0"
"@eslint/plugin-kit": "npm:^0.7.0"
"@eslint/config-array": "npm:^0.23.5"
"@eslint/config-helpers": "npm:^0.5.5"
"@eslint/core": "npm:^1.2.1"
"@eslint/plugin-kit": "npm:^0.7.1"
"@humanfs/node": "npm:^0.16.6"
"@humanwhocodes/module-importer": "npm:^1.0.1"
"@humanwhocodes/retry": "npm:^0.4.2"
@@ -7789,7 +7789,7 @@ __metadata:
optional: true
bin:
eslint: bin/eslint.js
checksum: 10/583589ed96922aad9507c94339e843c8929c297d505ae7d70579cef56b435a10d8a48d24616eb4fb53fbe75d8655adb8e44add5d5b2bca100148d31d890ab3a4
checksum: 10/954658c846696dc501a2b8e5fb268713e231dd81375dc25d76cd2fb4a1c73094ea73c64197634ece6fca8a54536e89eb44548a11be672544522e7a50eb8aae95
languageName: node
linkType: hard
@@ -8995,7 +8995,7 @@ __metadata:
dialog-polyfill: "npm:0.5.6"
echarts: "npm:6.0.0"
element-internals-polyfill: "npm:3.0.2"
eslint: "npm:10.2.0"
eslint: "npm:10.2.1"
eslint-config-airbnb-base: "npm:15.0.0"
eslint-config-prettier: "npm:10.1.8"
eslint-import-resolver-webpack: "npm:0.13.11"