mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-21 18:13:04 +00:00
Compare commits
12 Commits
card_picke
...
claude/sec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59b0b964ff | ||
|
|
ebf4b0d000 | ||
|
|
c8459eb781 | ||
|
|
74fd7b61f1 | ||
|
|
5d32bf338b | ||
|
|
4848e939b4 | ||
|
|
23acfc729c | ||
|
|
93110b1d70 | ||
|
|
730fdd3931 | ||
|
|
0bd7b242b7 | ||
|
|
b17774ff3d | ||
|
|
e037a83ed2 |
1
.github/workflows/stale.yml
vendored
1
.github/workflows/stale.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
- cron: "0 * * * *"
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 })}"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -104,6 +104,9 @@ declare global {
|
||||
value: Trigger | Condition | Action | Trigger[] | Condition[] | Action[];
|
||||
};
|
||||
"save-automation": undefined;
|
||||
paste: {
|
||||
item: Trigger | Condition | Action;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -210,6 +210,8 @@ export class HuiSection extends ConditionalListenerMixin<LovelaceSectionConfig>(
|
||||
) {
|
||||
addLayoutElement = true;
|
||||
this._createLayoutElement(this._config);
|
||||
} else {
|
||||
this._layoutElement.setConfig(sectionConfig);
|
||||
}
|
||||
|
||||
this._createCards(sectionConfig);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
),
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()}`,
|
||||
|
||||
@@ -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",
|
||||
|
||||
64
yarn.lock
64
yarn.lock
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user