mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-23 16:19:25 +00:00
Compare commits
4 Commits
dev
...
automation
Author | SHA1 | Date | |
---|---|---|---|
![]() |
14932f754f | ||
![]() |
2e629aefec | ||
![]() |
777ede87d6 | ||
![]() |
367907d62c |
@@ -158,7 +158,7 @@
|
||||
"@octokit/auth-oauth-device": "8.0.1",
|
||||
"@octokit/plugin-retry": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@rsdoctor/rspack-plugin": "1.2.3",
|
||||
"@rsdoctor/rspack-plugin": "1.2.2",
|
||||
"@rspack/cli": "1.4.11",
|
||||
"@rspack/core": "1.4.11",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
@@ -191,7 +191,7 @@
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-lit": "2.1.1",
|
||||
"eslint-plugin-lit-a11y": "5.1.1",
|
||||
"eslint-plugin-unused-imports": "4.2.0",
|
||||
"eslint-plugin-unused-imports": "4.1.4",
|
||||
"eslint-plugin-wc": "3.0.1",
|
||||
"fancy-log": "2.0.0",
|
||||
"fs-extra": "11.3.1",
|
||||
@@ -218,7 +218,7 @@
|
||||
"terser-webpack-plugin": "5.3.14",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.40.0",
|
||||
"typescript-eslint": "8.39.1",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "3.2.4",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
|
@@ -101,7 +101,7 @@ export class StateHistoryChartTimeline extends LitElement {
|
||||
fill: api.value(4) as string,
|
||||
},
|
||||
};
|
||||
const text = (api.value(3) as string).replaceAll("\n", " ");
|
||||
const text = api.value(3) as string;
|
||||
const textWidth = measureTextWidth(text, 12);
|
||||
const LABEL_PADDING = 4;
|
||||
if (textWidth < rectShape.width - LABEL_PADDING * 2) {
|
||||
|
243
src/components/ha-bottom-sheet.ts
Normal file
243
src/components/ha-bottom-sheet.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
import { css, html, LitElement, type PropertyValues } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
|
||||
const ANIMATION_DURATION_MS = 300;
|
||||
|
||||
@customElement("ha-bottom-sheet")
|
||||
export class HaBottomSheet extends LitElement {
|
||||
@query("dialog") private _dialog!: HTMLDialogElement;
|
||||
|
||||
@property({ attribute: false }) public contentHash?: string;
|
||||
|
||||
private _dragging = false;
|
||||
|
||||
private _dragStartY = 0;
|
||||
|
||||
private _initialSize = 0;
|
||||
|
||||
private _open = false;
|
||||
|
||||
render() {
|
||||
return html`<dialog open>
|
||||
<div class="handle-wrapper">
|
||||
<div
|
||||
@mousedown=${this._handleMouseDown}
|
||||
@touchstart=${this._handleTouchStart}
|
||||
class="handle"
|
||||
></div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</dialog>`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this._openSheet();
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("contentHash") && this._open) {
|
||||
fireEvent(this, "bottom-sheet-opened");
|
||||
}
|
||||
}
|
||||
|
||||
private _openSheet() {
|
||||
requestAnimationFrame(async () => {
|
||||
this._dialog.classList.add("show");
|
||||
|
||||
setTimeout(() => {
|
||||
this._dialog.style.setProperty(
|
||||
"height",
|
||||
`${(this._dialog.offsetHeight / window.innerHeight) * 100}vh`
|
||||
);
|
||||
this._dialog.style.setProperty("max-height", "90vh");
|
||||
this._open = true;
|
||||
fireEvent(this, "bottom-sheet-opened");
|
||||
}, ANIMATION_DURATION_MS);
|
||||
});
|
||||
}
|
||||
|
||||
public closeSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
this._dialog.classList.remove("show");
|
||||
setTimeout(() => {
|
||||
this._dialog.close();
|
||||
fireEvent(this, "bottom-sheet-closed");
|
||||
}, ANIMATION_DURATION_MS);
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener("mousemove", this._handleMouseMove);
|
||||
document.addEventListener("mouseup", this._handleMouseUp);
|
||||
// Use non-passive listeners so we can call preventDefault to block
|
||||
// browser pull-to-refresh and page scrolling while dragging.
|
||||
document.addEventListener("touchmove", this._handleTouchMove, {
|
||||
passive: false,
|
||||
});
|
||||
document.addEventListener("touchend", this._handleTouchEnd);
|
||||
document.addEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener("mousemove", this._handleMouseMove);
|
||||
document.removeEventListener("mouseup", this._handleMouseUp);
|
||||
document.removeEventListener("touchmove", this._handleTouchMove);
|
||||
document.removeEventListener("touchend", this._handleTouchEnd);
|
||||
document.removeEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
private _handleMouseDown = (ev: MouseEvent) => {
|
||||
this._startDrag(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchStart = (ev: TouchEvent) => {
|
||||
// Prevent the browser from interpreting this as a scroll/PTR gesture.
|
||||
ev.preventDefault();
|
||||
this._startDrag(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _startDrag(clientY: number) {
|
||||
this._dragging = true;
|
||||
this._dragStartY = clientY;
|
||||
this._initialSize = (this._dialog.offsetHeight / window.innerHeight) * 100;
|
||||
document.body.style.cursor = "grabbing";
|
||||
}
|
||||
|
||||
private _handleMouseMove = (ev: MouseEvent) => {
|
||||
if (!this._dragging) return;
|
||||
this._updateSize(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchMove = (ev: TouchEvent) => {
|
||||
if (!this._dragging) return;
|
||||
ev.preventDefault(); // Prevent scrolling
|
||||
this._updateSize(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _updateSize(clientY: number) {
|
||||
const deltaY = this._dragStartY - clientY;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const deltaVh = (deltaY / viewportHeight) * 100;
|
||||
|
||||
// Calculate new size and clamp between 10vh and 90vh
|
||||
let newSize = this._initialSize + deltaVh;
|
||||
newSize = Math.max(10, Math.min(90, newSize));
|
||||
|
||||
// on drag down and below 20vh
|
||||
if (newSize < 20 && deltaY < 0) {
|
||||
this.closeSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
this._dialog.style.setProperty("height", `${newSize}vh`);
|
||||
}
|
||||
|
||||
private _handleMouseUp = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _handleTouchEnd = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _endDrag() {
|
||||
if (!this._dragging) return;
|
||||
this._dragging = false;
|
||||
document.body.style.cursor = "";
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.handle-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
padding-bottom: 2px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
}
|
||||
.handle-wrapper .handle {
|
||||
height: 20px;
|
||||
width: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 20;
|
||||
}
|
||||
.handle-wrapper .handle::after {
|
||||
content: "";
|
||||
border-radius: 8px;
|
||||
height: 4px;
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
width: 80px;
|
||||
}
|
||||
.handle-wrapper .handle:active::after {
|
||||
cursor: grabbing;
|
||||
}
|
||||
dialog {
|
||||
height: auto;
|
||||
max-height: 70vh;
|
||||
min-height: 30vh;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
position: fixed;
|
||||
width: calc(100% - 4px);
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
top: auto;
|
||||
inset-inline-end: auto;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
box-shadow: 0px -8px 16px rgba(0, 0, 0, 0.2);
|
||||
border-top-left-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
border-top-right-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
transform: translateY(100%);
|
||||
transition: transform ${ANIMATION_DURATION_MS}ms ease;
|
||||
border-top-width: var(--ha-bottom-sheet-border-width);
|
||||
border-right-width: var(--ha-bottom-sheet-border-width);
|
||||
border-left-width: var(--ha-bottom-sheet-border-width);
|
||||
border-bottom-width: 0;
|
||||
border-style: var(--ha-bottom-sheet-border-style);
|
||||
border-color: var(--ha-bottom-sheet-border-color);
|
||||
}
|
||||
|
||||
dialog.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-bottom-sheet": HaBottomSheet;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"bottom-sheet-closed": undefined;
|
||||
"bottom-sheet-opened": undefined;
|
||||
}
|
||||
}
|
@@ -15,6 +15,16 @@ import { migrateAutomationAction } from "./script";
|
||||
export const AUTOMATION_DEFAULT_MODE: (typeof MODES)[number] = "single";
|
||||
export const AUTOMATION_DEFAULT_MAX = 10;
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
/**
|
||||
* Dispatched to open the automation editor.
|
||||
* Used by custom cards/panels to trigger the editor view.
|
||||
*/
|
||||
"show-automation-editor": ShowAutomationEditorParams;
|
||||
}
|
||||
}
|
||||
|
||||
export interface AutomationEntity extends HassEntityBase {
|
||||
attributes: HassEntityAttributeBase & {
|
||||
id?: string;
|
||||
@@ -558,6 +568,7 @@ export interface AutomationClipboard {
|
||||
export interface BaseSidebarConfig {
|
||||
toggleYamlMode: () => boolean;
|
||||
delete: () => void;
|
||||
scrollIntoView: () => void;
|
||||
}
|
||||
|
||||
export interface TriggerSidebarConfig extends BaseSidebarConfig {
|
||||
|
@@ -2,16 +2,10 @@ import type { Condition } from "../../../panels/lovelace/common/validate-conditi
|
||||
import type { LovelaceCardConfig } from "./card";
|
||||
import type { LovelaceStrategyConfig } from "./strategy";
|
||||
|
||||
export interface LovelaceSectionStyleConfig {
|
||||
background_color?: string;
|
||||
background_opacity?: number;
|
||||
}
|
||||
|
||||
export interface LovelaceBaseSectionConfig {
|
||||
visibility?: Condition[];
|
||||
column_span?: number;
|
||||
row_span?: number;
|
||||
style?: LovelaceSectionStyleConfig;
|
||||
/**
|
||||
* @deprecated Use heading card instead.
|
||||
*/
|
||||
|
@@ -12,7 +12,6 @@ export interface Zone {
|
||||
}
|
||||
|
||||
export interface HomeZoneMutableParams {
|
||||
name?: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
radius: number;
|
||||
|
@@ -856,9 +856,7 @@ export class QuickBar extends LitElement {
|
||||
|
||||
private _generateNavigationPanelCommands(): BaseNavigationCommand[] {
|
||||
return Object.keys(this.hass.panels)
|
||||
.filter(
|
||||
(panelKey) => panelKey !== "_my_redirect" && panelKey !== "hassio"
|
||||
)
|
||||
.filter((panelKey) => panelKey !== "_my_redirect")
|
||||
.map((panelKey) => {
|
||||
const panel = this.hass.panels[panelKey];
|
||||
const translationKey = getPanelNameTranslationKey(panel);
|
||||
|
@@ -112,9 +112,7 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
|
||||
this.assistConfiguration.available_wake_words.length > 1
|
||||
? html`<div class="row">
|
||||
<ha-select
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.assistants.pipeline.detail.form.wake_word_id"
|
||||
)}
|
||||
.label=${"Wake word"}
|
||||
@closed=${stopPropagation}
|
||||
fixedMenuPosition
|
||||
naturalMenuWidth
|
||||
@@ -146,9 +144,7 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
|
||||
${pipelineEntity
|
||||
? html`<div class="row">
|
||||
<ha-select
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.assistants.pipeline.devices.pipeline"
|
||||
)}
|
||||
.label=${"Assistant"}
|
||||
@closed=${stopPropagation}
|
||||
.value=${pipelineEntity?.state}
|
||||
fixedMenuPosition
|
||||
|
@@ -641,10 +641,14 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
this.openSidebar();
|
||||
}
|
||||
|
||||
private _scrollIntoView = () => {
|
||||
this.scrollIntoView({
|
||||
block: "start",
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
public openSidebar(action?: Action): void {
|
||||
if (this.narrow) {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
const sidebarAction = action ?? this.action;
|
||||
const actionType = getAutomationActionType(sidebarAction);
|
||||
|
||||
@@ -668,6 +672,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
config: sidebarAction,
|
||||
uiSupported: actionType ? this._uiSupported(actionType) : false,
|
||||
yamlMode: this._yamlMode,
|
||||
scrollIntoView: this._scrollIntoView,
|
||||
} satisfies ActionSidebarConfig);
|
||||
this._selected = true;
|
||||
}
|
||||
|
@@ -167,9 +167,6 @@ export default class HaAutomationAction extends LitElement {
|
||||
} else if (!this.optionsInSidebar) {
|
||||
row.expand();
|
||||
}
|
||||
if (this.narrow) {
|
||||
row.scrollIntoView();
|
||||
}
|
||||
row.focus();
|
||||
});
|
||||
}
|
||||
|
@@ -598,11 +598,14 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
this.openSidebar();
|
||||
}
|
||||
|
||||
public openSidebar(condition?: Condition): void {
|
||||
if (this.narrow) {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
private _scrollIntoView = () => {
|
||||
this.scrollIntoView({
|
||||
block: "start",
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
public openSidebar(condition?: Condition): void {
|
||||
const sidebarCondition = condition || this.condition;
|
||||
fireEvent(this, "open-sidebar", {
|
||||
save: (value) => {
|
||||
@@ -624,6 +627,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
config: sidebarCondition,
|
||||
uiSupported: this._uiSupported(sidebarCondition.condition),
|
||||
yamlMode: this._yamlMode,
|
||||
scrollIntoView: this._scrollIntoView,
|
||||
} satisfies ConditionSidebarConfig);
|
||||
this._selected = true;
|
||||
}
|
||||
|
@@ -111,9 +111,6 @@ export default class HaAutomationCondition extends LitElement {
|
||||
} else if (!this.optionsInSidebar) {
|
||||
row.expand();
|
||||
}
|
||||
if (this.narrow) {
|
||||
row.scrollIntoView();
|
||||
}
|
||||
row.focus();
|
||||
});
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-bottom-sheet";
|
||||
import type { HaBottomSheet } from "../../../components/ha-bottom-sheet";
|
||||
import {
|
||||
isCondition,
|
||||
isScriptField,
|
||||
@@ -13,14 +15,12 @@ import {
|
||||
} from "../../../data/automation";
|
||||
import { isTriggerList } from "../../../data/trigger";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type HaAutomationConditionEditor from "./condition/ha-automation-condition-editor";
|
||||
import "./sidebar/ha-automation-sidebar-action";
|
||||
import "./sidebar/ha-automation-sidebar-condition";
|
||||
import "./sidebar/ha-automation-sidebar-option";
|
||||
import "./sidebar/ha-automation-sidebar-script-field";
|
||||
import "./sidebar/ha-automation-sidebar-script-field-selector";
|
||||
import "./sidebar/ha-automation-sidebar-trigger";
|
||||
import type HaAutomationTriggerEditor from "./trigger/ha-automation-trigger-editor";
|
||||
|
||||
@customElement("ha-automation-sidebar")
|
||||
export default class HaAutomationSidebar extends LitElement {
|
||||
@@ -32,92 +32,95 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _yamlMode = false;
|
||||
|
||||
@query(".sidebar-editor")
|
||||
public editor?: HaAutomationTriggerEditor | HaAutomationConditionEditor;
|
||||
|
||||
protected render() {
|
||||
if (!this.config) {
|
||||
return nothing;
|
||||
}
|
||||
@query("ha-bottom-sheet") private _bottomSheetElement?: HaBottomSheet;
|
||||
|
||||
private _renderContent() {
|
||||
// get config type
|
||||
const type = this._getType();
|
||||
|
||||
if (type === "trigger") {
|
||||
return html`
|
||||
<ha-automation-sidebar-trigger
|
||||
class="sidebar-content"
|
||||
.hass=${this.hass}
|
||||
.config=${this.config}
|
||||
.isWide=${this.isWide}
|
||||
.disabled=${this.disabled}
|
||||
.yamlMode=${this._yamlMode}
|
||||
@toggle-yaml-mode=${this._toggleYamlMode}
|
||||
@close-sidebar=${this._closeSidebar}
|
||||
@close-sidebar=${this._handleCloseSidebar}
|
||||
></ha-automation-sidebar-trigger>
|
||||
`;
|
||||
}
|
||||
if (type === "condition") {
|
||||
return html`
|
||||
<ha-automation-sidebar-condition
|
||||
class="sidebar-content"
|
||||
.hass=${this.hass}
|
||||
.config=${this.config}
|
||||
.isWide=${this.isWide}
|
||||
.disabled=${this.disabled}
|
||||
.yamlMode=${this._yamlMode}
|
||||
@toggle-yaml-mode=${this._toggleYamlMode}
|
||||
@close-sidebar=${this._closeSidebar}
|
||||
@close-sidebar=${this._handleCloseSidebar}
|
||||
></ha-automation-sidebar-condition>
|
||||
`;
|
||||
}
|
||||
if (type === "action") {
|
||||
return html`
|
||||
<ha-automation-sidebar-action
|
||||
class="sidebar-content"
|
||||
.hass=${this.hass}
|
||||
.config=${this.config}
|
||||
.isWide=${this.isWide}
|
||||
.disabled=${this.disabled}
|
||||
.yamlMode=${this._yamlMode}
|
||||
@toggle-yaml-mode=${this._toggleYamlMode}
|
||||
@close-sidebar=${this._closeSidebar}
|
||||
@close-sidebar=${this._handleCloseSidebar}
|
||||
></ha-automation-sidebar-action>
|
||||
`;
|
||||
}
|
||||
if (type === "option") {
|
||||
return html`
|
||||
<ha-automation-sidebar-option
|
||||
class="sidebar-content"
|
||||
.hass=${this.hass}
|
||||
.config=${this.config}
|
||||
.isWide=${this.isWide}
|
||||
.disabled=${this.disabled}
|
||||
@close-sidebar=${this._closeSidebar}
|
||||
@close-sidebar=${this._handleCloseSidebar}
|
||||
></ha-automation-sidebar-option>
|
||||
`;
|
||||
}
|
||||
if (type === "script-field-selector") {
|
||||
return html`
|
||||
<ha-automation-sidebar-script-field-selector
|
||||
class="sidebar-content"
|
||||
.hass=${this.hass}
|
||||
.config=${this.config}
|
||||
.isWide=${this.isWide}
|
||||
.disabled=${this.disabled}
|
||||
.yamlMode=${this._yamlMode}
|
||||
@toggle-yaml-mode=${this._toggleYamlMode}
|
||||
@close-sidebar=${this._closeSidebar}
|
||||
@close-sidebar=${this._handleCloseSidebar}
|
||||
></ha-automation-sidebar-script-field-selector>
|
||||
`;
|
||||
}
|
||||
if (type === "script-field") {
|
||||
return html`
|
||||
<ha-automation-sidebar-script-field
|
||||
class="sidebar-content"
|
||||
.hass=${this.hass}
|
||||
.config=${this.config}
|
||||
.isWide=${this.isWide}
|
||||
.disabled=${this.disabled}
|
||||
.yamlMode=${this._yamlMode}
|
||||
@toggle-yaml-mode=${this._toggleYamlMode}
|
||||
@close-sidebar=${this._closeSidebar}
|
||||
@close-sidebar=${this._handleCloseSidebar}
|
||||
></ha-automation-sidebar-script-field>
|
||||
`;
|
||||
}
|
||||
@@ -125,6 +128,26 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.config) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
if (this.narrow) {
|
||||
return html`
|
||||
<ha-bottom-sheet
|
||||
.contentHash=${JSON.stringify(this.config)}
|
||||
@bottom-sheet-closed=${this._closeSidebar}
|
||||
@bottom-sheet-opened=${this._scrollRowIntoView}
|
||||
>
|
||||
${this._renderContent()}
|
||||
</ha-bottom-sheet>
|
||||
`;
|
||||
}
|
||||
|
||||
return this._renderContent();
|
||||
}
|
||||
|
||||
private _getType() {
|
||||
if (
|
||||
(this.config as TriggerSidebarConfig)?.config &&
|
||||
@@ -157,8 +180,17 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _closeSidebar(ev: CustomEvent) {
|
||||
private _handleCloseSidebar(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (this.narrow) {
|
||||
this._bottomSheetElement?.closeSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
this._closeSidebar();
|
||||
}
|
||||
|
||||
private _closeSidebar() {
|
||||
this.config?.close();
|
||||
}
|
||||
|
||||
@@ -172,6 +204,10 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
});
|
||||
};
|
||||
|
||||
private _scrollRowIntoView = () => {
|
||||
this.config?.scrollIntoView();
|
||||
};
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
height: 100%;
|
||||
@@ -180,6 +216,15 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
border-radius: var(--ha-card-border-radius);
|
||||
--ha-bottom-sheet-border-width: 2px;
|
||||
--ha-bottom-sheet-border-style: solid;
|
||||
--ha-bottom-sheet-border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
.sidebar-content {
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -273,10 +273,11 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
class=${classMap({
|
||||
sidebar: true,
|
||||
hidden: !this._sidebarConfig,
|
||||
overlay: !this.isWide,
|
||||
overlay: !this.isWide && !this.narrow,
|
||||
})}
|
||||
.isWide=${this.isWide}
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.config=${this._sidebarConfig}
|
||||
@value-changed=${this._sidebarConfigChanged}
|
||||
.disabled=${this.disabled}
|
||||
@@ -612,26 +613,23 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
|
||||
.sidebar.overlay {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: calc(100% - 64px);
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
height: calc(100% - 70px);
|
||||
padding: 0;
|
||||
z-index: 5;
|
||||
box-shadow: -8px 0 16px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
.sidebar.overlay {
|
||||
max-height: 70vh;
|
||||
max-height: 70dvh;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
box-shadow: 0px -8px 16px rgba(0, 0, 0, 0.2);
|
||||
.split-view {
|
||||
gap: 0;
|
||||
margin-right: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
.sidebar.overlay.hidden {
|
||||
.sidebar {
|
||||
height: 0;
|
||||
width: 0;
|
||||
flex: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -342,11 +342,14 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
this.openSidebar();
|
||||
}
|
||||
|
||||
public openSidebar(): void {
|
||||
if (this.narrow) {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
private _scrollIntoView = () => {
|
||||
this.scrollIntoView({
|
||||
block: "start",
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
public openSidebar(): void {
|
||||
fireEvent(this, "open-sidebar", {
|
||||
close: () => {
|
||||
this._selected = false;
|
||||
@@ -357,6 +360,7 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
},
|
||||
toggleYamlMode: () => false, // no yaml mode for options
|
||||
delete: this._removeOption,
|
||||
scrollIntoView: this._scrollIntoView,
|
||||
} satisfies OptionSidebarConfig);
|
||||
this._selected = true;
|
||||
}
|
||||
|
@@ -133,10 +133,6 @@ export default class HaAutomationOption extends LitElement {
|
||||
if (!this.optionsInSidebar) {
|
||||
row.expand();
|
||||
}
|
||||
|
||||
if (this.narrow) {
|
||||
row.scrollIntoView();
|
||||
}
|
||||
row.focus();
|
||||
});
|
||||
}
|
||||
|
@@ -0,0 +1,220 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
const ANIMATION_DURATION_MS = 300;
|
||||
|
||||
@customElement("ha-automation-sidebar-bottom-sheet")
|
||||
export class HaAutomationSidebarBottomSheet extends LitElement {
|
||||
@state() private _size = 30;
|
||||
|
||||
@query("dialog") private _dialog!: HTMLDialogElement;
|
||||
|
||||
private _dragging = false;
|
||||
|
||||
private _dragStartY = 0;
|
||||
|
||||
private _initialSize = 0;
|
||||
|
||||
public showDialog(): void {
|
||||
this._openSheet();
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.closeSheet();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<dialog open style=${`--size: ${this._size}vh;`}>
|
||||
<div
|
||||
class="handle-wrapper"
|
||||
@mousedown=${this._handleMouseDown}
|
||||
@touchstart=${this._handleTouchStart}
|
||||
>
|
||||
<div class="handle"></div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</dialog>`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this._openSheet();
|
||||
}
|
||||
|
||||
private _openSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
this._dialog.classList.add("show");
|
||||
});
|
||||
}
|
||||
|
||||
public closeSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
this._dialog.classList.remove("show");
|
||||
setTimeout(() => {
|
||||
this._dialog.close();
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}, ANIMATION_DURATION_MS);
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener("mousemove", this._handleMouseMove);
|
||||
document.addEventListener("mouseup", this._handleMouseUp);
|
||||
// Use non-passive listeners so we can call preventDefault to block
|
||||
// browser pull-to-refresh and page scrolling while dragging.
|
||||
document.addEventListener("touchmove", this._handleTouchMove, {
|
||||
passive: false,
|
||||
});
|
||||
document.addEventListener("touchend", this._handleTouchEnd);
|
||||
document.addEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener("mousemove", this._handleMouseMove);
|
||||
document.removeEventListener("mouseup", this._handleMouseUp);
|
||||
document.removeEventListener("touchmove", this._handleTouchMove);
|
||||
document.removeEventListener("touchend", this._handleTouchEnd);
|
||||
document.removeEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
private _handleMouseDown = (ev: MouseEvent) => {
|
||||
this._startDrag(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchStart = (ev: TouchEvent) => {
|
||||
// Prevent the browser from interpreting this as a scroll/PTR gesture.
|
||||
ev.preventDefault();
|
||||
this._startDrag(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _startDrag(clientY: number) {
|
||||
this._dragging = true;
|
||||
this._dragStartY = clientY;
|
||||
this._initialSize = this._size;
|
||||
document.body.style.cursor = "grabbing";
|
||||
}
|
||||
|
||||
private _handleMouseMove = (ev: MouseEvent) => {
|
||||
if (!this._dragging) return;
|
||||
this._updateSize(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchMove = (ev: TouchEvent) => {
|
||||
if (!this._dragging) return;
|
||||
ev.preventDefault(); // Prevent scrolling
|
||||
this._updateSize(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _updateSize(clientY: number) {
|
||||
const deltaY = this._dragStartY - clientY;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const deltaVh = (deltaY / viewportHeight) * 100;
|
||||
|
||||
// Calculate new size and clamp between 10vh and 90vh
|
||||
let newSize = this._initialSize + deltaVh;
|
||||
newSize = Math.max(10, Math.min(90, newSize));
|
||||
|
||||
this._size = newSize;
|
||||
|
||||
if (newSize < 20) {
|
||||
this.closeSheet();
|
||||
}
|
||||
}
|
||||
|
||||
private _handleMouseUp = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _handleTouchEnd = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _endDrag() {
|
||||
if (!this._dragging) return;
|
||||
this._dragging = false;
|
||||
document.body.style.cursor = "";
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
--size: 30vh;
|
||||
--size: 30dvh;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
.handle-wrapper {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding-bottom: 2px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
}
|
||||
.handle-wrapper:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
.handle-wrapper .handle {
|
||||
border-radius: 8px;
|
||||
height: 4px;
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
width: 80px;
|
||||
transition: background-color 0.2s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
dialog {
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
top: auto;
|
||||
inset-inline-end: auto;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
height: var(--size);
|
||||
box-shadow: 0px -8px 16px rgba(0, 0, 0, 0.2);
|
||||
border-top-left-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
border-top-right-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
transform: translateY(100%);
|
||||
transition: transform ${ANIMATION_DURATION_MS}ms ease;
|
||||
}
|
||||
|
||||
dialog.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-sidebar-bottom-sheet": HaAutomationSidebarBottomSheet;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"bottom-sheet-closed": undefined;
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import { mdiClose, mdiDotsVertical } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
@@ -33,6 +33,12 @@ export default class HaAutomationSidebarCard extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public warnings?: string[];
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _contentScrolled = false;
|
||||
|
||||
@query(".card-content") private _contentElement?: HTMLDivElement;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<ha-card
|
||||
@@ -42,7 +48,9 @@ export default class HaAutomationSidebarCard extends LitElement {
|
||||
yaml: this.yamlMode,
|
||||
})}
|
||||
>
|
||||
<ha-dialog-header>
|
||||
<ha-dialog-header
|
||||
class=${classMap({ scrolled: this._contentScrolled })}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="navigationIcon"
|
||||
.label=${this.hass.localize("ui.common.close")}
|
||||
@@ -81,6 +89,25 @@ export default class HaAutomationSidebarCard extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._contentElement?.addEventListener("scroll", this._onScroll, {
|
||||
passive: true,
|
||||
});
|
||||
|
||||
this._onScroll();
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._contentElement?.removeEventListener("scroll", this._onScroll);
|
||||
}
|
||||
|
||||
private _onScroll = () => {
|
||||
const top = this._contentElement?.scrollTop ?? 0;
|
||||
this._contentScrolled = top > 0;
|
||||
};
|
||||
|
||||
private _closeSidebar() {
|
||||
fireEvent(this, "close-sidebar");
|
||||
}
|
||||
@@ -98,25 +125,33 @@ export default class HaAutomationSidebarCard extends LitElement {
|
||||
border-width: 2px;
|
||||
display: block;
|
||||
}
|
||||
ha-card.mobile {
|
||||
border-bottom-right-radius: var(--ha-border-radius-square);
|
||||
border-bottom-left-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
ha-card.mobile {
|
||||
max-height: 70vh;
|
||||
max-height: 70dvh;
|
||||
border-width: 2px 2px 0;
|
||||
border: none;
|
||||
}
|
||||
ha-card.mobile.yaml {
|
||||
height: 70vh;
|
||||
height: 70dvh;
|
||||
ha-card.mobile {
|
||||
border-bottom-right-radius: var(--ha-border-radius-square);
|
||||
border-bottom-left-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
}
|
||||
|
||||
ha-dialog-header {
|
||||
border-radius: var(--ha-card-border-radius);
|
||||
box-shadow: none;
|
||||
transition: box-shadow 180ms ease-in-out;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
}
|
||||
|
||||
ha-dialog-header.scrolled {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
@@ -130,17 +165,6 @@ export default class HaAutomationSidebarCard extends LitElement {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
ha-card.mobile .card-content {
|
||||
max-height: calc(
|
||||
70vh - 88px - max(var(--safe-area-inset-bottom), 16px)
|
||||
);
|
||||
max-height: calc(
|
||||
70dvh - 88px - max(var(--safe-area-inset-bottom), 16px)
|
||||
);
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,12 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "./ha-automation-sidebar-bottom-sheet";
|
||||
|
||||
export const showAutomationSidebarBottomSheet = (
|
||||
element: HTMLElement
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "ha-automation-sidebar-bottom-sheet",
|
||||
dialogImport: () => import("./ha-automation-sidebar-bottom-sheet"),
|
||||
dialogParams: {},
|
||||
});
|
||||
};
|
@@ -468,10 +468,14 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
this.openSidebar();
|
||||
}
|
||||
|
||||
private _scrollIntoView = () => {
|
||||
this.scrollIntoView({
|
||||
block: "start",
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
public openSidebar(trigger?: Trigger): void {
|
||||
if (this.narrow) {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
fireEvent(this, "open-sidebar", {
|
||||
save: (value) => {
|
||||
fireEvent(this, "value-changed", { value });
|
||||
@@ -492,6 +496,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
config: trigger || this.trigger,
|
||||
uiSupported: this._uiSupported(this._getType(trigger || this.trigger)),
|
||||
yamlMode: this._yamlMode,
|
||||
scrollIntoView: this._scrollIntoView,
|
||||
} satisfies TriggerSidebarConfig);
|
||||
this._selected = true;
|
||||
}
|
||||
|
@@ -180,9 +180,6 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
} else {
|
||||
row.expand();
|
||||
}
|
||||
if (this.narrow) {
|
||||
row.scrollIntoView();
|
||||
}
|
||||
row.focus();
|
||||
});
|
||||
}
|
||||
|
@@ -15,6 +15,8 @@ import type { CloudStatus } from "../../../data/cloud";
|
||||
import { fetchCloudStatus } from "../../../data/cloud";
|
||||
import type { HardwareInfo } from "../../../data/hardware";
|
||||
import { BOARD_NAMES } from "../../../data/hardware";
|
||||
import type { HassioBackup } from "../../../data/hassio/backup";
|
||||
import { fetchHassioBackups } from "../../../data/hassio/backup";
|
||||
import type {
|
||||
HassioHassOSInfo,
|
||||
HassioHostInfo,
|
||||
@@ -42,7 +44,7 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public showAdvanced = false;
|
||||
|
||||
@state() private _latestBackupDate?: Date;
|
||||
@state() private _latestBackupDate?: string;
|
||||
|
||||
@state() private _boardName?: string;
|
||||
|
||||
@@ -61,7 +63,7 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
description = this._latestBackupDate
|
||||
? this.hass.localize("ui.panel.config.backup.description", {
|
||||
relative_time: relativeTime(
|
||||
this._latestBackupDate,
|
||||
new Date(this._latestBackupDate),
|
||||
this.hass.locale
|
||||
),
|
||||
})
|
||||
@@ -153,24 +155,26 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
|
||||
this._fetchNetworkStatus();
|
||||
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
||||
this._fetchBackupInfo();
|
||||
this._fetchBackupInfo(isHassioLoaded);
|
||||
this._fetchHardwareInfo(isHassioLoaded);
|
||||
if (isHassioLoaded) {
|
||||
this._fetchStorageInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchBackupInfo() {
|
||||
const backups: BackupContent[] = isComponentLoaded(this.hass, "backup")
|
||||
? await fetchBackupInfo(this.hass).then(
|
||||
(backupData) => backupData.backups
|
||||
)
|
||||
: [];
|
||||
private async _fetchBackupInfo(isHassioLoaded: boolean) {
|
||||
const backups: BackupContent[] | HassioBackup[] = isHassioLoaded
|
||||
? await fetchHassioBackups(this.hass)
|
||||
: isComponentLoaded(this.hass, "backup")
|
||||
? await fetchBackupInfo(this.hass).then(
|
||||
(backupData) => backupData.backups
|
||||
)
|
||||
: [];
|
||||
|
||||
if (backups.length > 0) {
|
||||
this._latestBackupDate = backups
|
||||
.map((backup) => new Date(backup.date))
|
||||
.reduce((a, b) => (a > b ? a : b));
|
||||
this._latestBackupDate = (backups as any[]).reduce((a, b) =>
|
||||
a.date > b.date ? a : b
|
||||
).date;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -85,7 +85,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
this._deviceTrackers = this._params.entry.device_trackers || [];
|
||||
this._picture = this._params.entry.picture || null;
|
||||
this._user = this._userId
|
||||
? this._params.users?.find((user) => user.id === this._userId)
|
||||
? this._params.users.find((user) => user.id === this._userId)
|
||||
: undefined;
|
||||
this._isAdmin = this._user?.group_ids.includes(SYSTEM_GROUP_ID_ADMIN);
|
||||
this._localOnly = this._user?.local_only;
|
||||
@@ -372,10 +372,10 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
userAddedCallback: async (user?: User) => {
|
||||
if (user) {
|
||||
target.checked = true;
|
||||
if (this._params!.entry && this._params!.updateEntry) {
|
||||
if (this._params!.entry) {
|
||||
await this._params!.updateEntry({ user_id: user.id });
|
||||
}
|
||||
this._params?.refreshUsers?.();
|
||||
this._params?.refreshUsers();
|
||||
this._user = user;
|
||||
this._userId = user.id;
|
||||
this._isAdmin = user.group_ids.includes(SYSTEM_GROUP_ID_ADMIN);
|
||||
@@ -403,7 +403,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
return;
|
||||
}
|
||||
await deleteUser(this.hass, this._userId);
|
||||
this._params?.refreshUsers?.();
|
||||
this._params?.refreshUsers();
|
||||
this._userId = undefined;
|
||||
this._user = undefined;
|
||||
this._isAdmin = undefined;
|
||||
@@ -466,7 +466,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
if (newUsername) {
|
||||
try {
|
||||
await adminChangeUsername(this.hass, this._user.id, newUsername);
|
||||
this._params?.refreshUsers?.();
|
||||
this._params?.refreshUsers();
|
||||
this._user = { ...this._user, username: newUsername };
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@@ -500,7 +500,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
],
|
||||
local_only: this._localOnly,
|
||||
});
|
||||
this._params?.refreshUsers?.();
|
||||
this._params?.refreshUsers();
|
||||
}
|
||||
const values: PersonMutableParams = {
|
||||
name: this._name.trim(),
|
||||
@@ -509,9 +509,9 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
picture: this._picture,
|
||||
};
|
||||
if (this._params!.entry) {
|
||||
await this._params!.updateEntry?.(values);
|
||||
await this._params!.updateEntry(values);
|
||||
} else {
|
||||
await this._params!.createEntry?.(values);
|
||||
await this._params!.createEntry(values);
|
||||
this._personExists = true;
|
||||
}
|
||||
this.closeDialog();
|
||||
@@ -525,7 +525,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
private async _deleteEntry() {
|
||||
this._submitting = true;
|
||||
try {
|
||||
if (await this._params!.removeEntry?.()) {
|
||||
if (await this._params!.removeEntry()) {
|
||||
if (this._params!.entry!.user_id) {
|
||||
deleteUser(this.hass, this._params!.entry!.user_id);
|
||||
}
|
||||
|
@@ -4,22 +4,22 @@ import type { User } from "../../../data/user";
|
||||
|
||||
export interface PersonDetailDialogParams {
|
||||
entry?: Person;
|
||||
users?: User[];
|
||||
refreshUsers?: () => void;
|
||||
createEntry?: (values: PersonMutableParams) => Promise<unknown>;
|
||||
updateEntry?: (updates: Partial<PersonMutableParams>) => Promise<unknown>;
|
||||
removeEntry?: () => Promise<boolean>;
|
||||
users: User[];
|
||||
refreshUsers: () => void;
|
||||
createEntry: (values: PersonMutableParams) => Promise<unknown>;
|
||||
updateEntry: (updates: Partial<PersonMutableParams>) => Promise<unknown>;
|
||||
removeEntry: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
export const loadPersonDetailDialog = () => import("./dialog-person-detail");
|
||||
|
||||
export const showPersonDetailDialog = (
|
||||
element: HTMLElement,
|
||||
params: PersonDetailDialogParams
|
||||
systemLogDetailParams: PersonDetailDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-person-detail",
|
||||
dialogImport: loadPersonDetailDialog,
|
||||
dialogParams: params,
|
||||
dialogParams: systemLogDetailParams,
|
||||
});
|
||||
};
|
||||
|
@@ -183,13 +183,17 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _scrollIntoView = () => {
|
||||
this.scrollIntoView({
|
||||
block: "start",
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
public openSidebar(selectorEditor = false): void {
|
||||
if (!selectorEditor) {
|
||||
this._selected = true;
|
||||
}
|
||||
if (this.narrow) {
|
||||
this.scrollIntoView();
|
||||
}
|
||||
|
||||
fireEvent(this, "open-sidebar", {
|
||||
save: (value) => {
|
||||
@@ -215,6 +219,7 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
excludeKeys: this.excludeKeys,
|
||||
},
|
||||
yamlMode: this._yamlMode,
|
||||
scrollIntoView: this._scrollIntoView,
|
||||
} satisfies ScriptFieldSidebarConfig);
|
||||
}
|
||||
|
||||
|
@@ -75,10 +75,6 @@ export default class HaScriptFields extends LitElement {
|
||||
)!;
|
||||
row.updateComplete.then(() => {
|
||||
row.openSidebar();
|
||||
|
||||
if (this.narrow) {
|
||||
row.scrollIntoView();
|
||||
}
|
||||
row.focus();
|
||||
});
|
||||
}
|
||||
|
@@ -34,7 +34,6 @@ class DialogHomeZoneDetail extends LitElement {
|
||||
this._params = params;
|
||||
this._error = undefined;
|
||||
this._data = {
|
||||
name: this.hass.config.location_name,
|
||||
latitude: this.hass.config.latitude,
|
||||
longitude: this.hass.config.longitude,
|
||||
radius: this.hass.config.radius,
|
||||
@@ -64,7 +63,7 @@ class DialogHomeZoneDetail extends LitElement {
|
||||
escapeKeyAction
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass!.localize("ui.common.edit_item", { name: this._data.name })
|
||||
this.hass!.localize("ui.panel.config.zone.edit_home")
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
|
@@ -85,9 +85,7 @@ class DialogZoneDetail extends LitElement {
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this._params.entry
|
||||
? this.hass!.localize("ui.common.edit_item", {
|
||||
name: this._params.entry.name,
|
||||
})
|
||||
? this._params.entry.name
|
||||
: this.hass!.localize("ui.panel.config.zone.detail.new_zone")
|
||||
)}
|
||||
>
|
||||
|
@@ -165,9 +165,9 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
.entry=${entry}
|
||||
@click=${this._openEditEntry}
|
||||
.path=${mdiPencil}
|
||||
.label=${hass.localize("ui.common.edit_item", {
|
||||
name: entry.name,
|
||||
})}
|
||||
.label=${hass.localize(
|
||||
"ui.panel.config.zone.edit_zone"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`
|
||||
@@ -218,9 +218,9 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
this._canEditCore
|
||||
? mdiPencil
|
||||
: mdiPencilOff}
|
||||
.label=${hass.localize("ui.common.edit_item", {
|
||||
name: hass.config.location_name,
|
||||
})}
|
||||
.label=${stateObject.entity_id === "zone.home"
|
||||
? hass.localize("ui.panel.config.zone.edit_home")
|
||||
: hass.localize("ui.panel.config.zone.edit_zone")}
|
||||
@click=${this._editHomeZone}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>`}
|
||||
|
@@ -1,323 +0,0 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
mdiPause,
|
||||
mdiPlay,
|
||||
mdiPlayPause,
|
||||
mdiPower,
|
||||
mdiSkipNext,
|
||||
mdiSkipPrevious,
|
||||
mdiStop,
|
||||
} from "@mdi/js";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
LovelaceCardFeatureContext,
|
||||
MediaPlayerPlaybackCardFeatureConfig,
|
||||
} from "./types";
|
||||
import type {
|
||||
ControlButton,
|
||||
MediaPlayerEntity,
|
||||
} from "../../../data/media-player";
|
||||
import { MediaPlayerEntityFeature } from "../../../data/media-player";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { isUnavailableState } from "../../../data/entity";
|
||||
import { hasConfigChanged } from "../common/has-changed";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon";
|
||||
|
||||
export const supportsMediaPlayerPlaybackCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
) => {
|
||||
const stateObj = context.entity_id
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "media_player";
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-playback-card-feature")
|
||||
class HuiMediaPlayerPlaybackCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state() private _config?: MediaPlayerPlaybackCardFeatureConfig;
|
||||
|
||||
@state() private _narrow?: boolean = false;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as
|
||||
| MediaPlayerEntity
|
||||
| undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): MediaPlayerPlaybackCardFeatureConfig {
|
||||
return {
|
||||
type: "media-player-playback",
|
||||
};
|
||||
}
|
||||
|
||||
public setConfig(config: MediaPlayerPlaybackCardFeatureConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public willUpdate(): void {
|
||||
if (!this.hasUpdated) {
|
||||
this._measureCard();
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
const entityId = this.context?.entity_id;
|
||||
return (
|
||||
hasConfigChanged(this, changedProps) ||
|
||||
(changedProps.has("hass") &&
|
||||
(!oldHass ||
|
||||
!entityId ||
|
||||
oldHass.states[entityId] !== this.hass!.states[entityId]))
|
||||
);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!supportsMediaPlayerPlaybackCardFeature(this.hass, this.context) ||
|
||||
!this._stateObj
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const buttons = this._computeButtons(this._stateObj);
|
||||
|
||||
return html`
|
||||
<ha-control-button-group>
|
||||
${supportsFeature(this._stateObj, MediaPlayerEntityFeature.TURN_OFF) &&
|
||||
stateActive(this._stateObj)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.media_player.turn_off")}
|
||||
@click=${this._togglePower}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
`
|
||||
: ""}
|
||||
${supportsFeature(this._stateObj, MediaPlayerEntityFeature.TURN_ON) &&
|
||||
!stateActive(this._stateObj) &&
|
||||
!isUnavailableState(this._stateObj.state)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.media_player.turn_on")}
|
||||
@click=${this._togglePower}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
`
|
||||
: buttons.map(
|
||||
(button) => html`
|
||||
<ha-control-button
|
||||
key=${button.action}
|
||||
.label=${this.hass?.localize(
|
||||
`ui.card.media_player.${button.action}`
|
||||
)}
|
||||
@click=${this._action}
|
||||
>
|
||||
<ha-svg-icon .path=${button.icon}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
`
|
||||
)}
|
||||
</ha-control-button-group>
|
||||
`;
|
||||
}
|
||||
|
||||
private _measureCard() {
|
||||
if (!this.isConnected) {
|
||||
return;
|
||||
}
|
||||
const host = (this.getRootNode() as ShadowRoot).host as
|
||||
| HTMLElement
|
||||
| undefined;
|
||||
const width = host?.clientWidth ?? this.clientWidth ?? 0;
|
||||
this._narrow = width < 300;
|
||||
}
|
||||
|
||||
private _computeControlButton(stateObj: MediaPlayerEntity): ControlButton {
|
||||
return stateObj.state === "on"
|
||||
? { icon: mdiPlayPause, action: "media_play_pause" }
|
||||
: stateObj.state !== "playing"
|
||||
? { icon: mdiPlay, action: "media_play" }
|
||||
: supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE)
|
||||
? { icon: mdiPause, action: "media_pause" }
|
||||
: { icon: mdiStop, action: "media_stop" };
|
||||
}
|
||||
|
||||
private _computeButtons(stateObj: MediaPlayerEntity): ControlButton[] {
|
||||
const controlButton = this._computeControlButton(stateObj);
|
||||
const assumedState = stateObj.attributes.assumed_state === true;
|
||||
|
||||
const controls: ControlButton[] = [];
|
||||
|
||||
if (
|
||||
!this._narrow &&
|
||||
(stateObj.state === "playing" || assumedState) &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.PREVIOUS_TRACK)
|
||||
) {
|
||||
controls.push({ icon: mdiSkipPrevious, action: "media_previous_track" });
|
||||
}
|
||||
|
||||
if (
|
||||
!assumedState &&
|
||||
((stateObj.state === "playing" &&
|
||||
(supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE) ||
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.STOP))) ||
|
||||
((stateObj.state === "paused" || stateObj.state === "idle") &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.PLAY)) ||
|
||||
(stateObj.state === "on" &&
|
||||
(supportsFeature(stateObj, MediaPlayerEntityFeature.PLAY) ||
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE))))
|
||||
) {
|
||||
controls.push({ icon: controlButton.icon, action: controlButton.action });
|
||||
}
|
||||
|
||||
if (assumedState) {
|
||||
if (supportsFeature(stateObj, MediaPlayerEntityFeature.PLAY)) {
|
||||
controls.push({ icon: mdiPlay, action: "media_play" });
|
||||
}
|
||||
|
||||
if (supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE)) {
|
||||
controls.push({ icon: mdiPause, action: "media_pause" });
|
||||
}
|
||||
|
||||
if (supportsFeature(stateObj, MediaPlayerEntityFeature.STOP)) {
|
||||
controls.push({ icon: mdiStop, action: "media_stop" });
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(stateObj.state === "playing" || assumedState) &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.NEXT_TRACK)
|
||||
) {
|
||||
controls.push({ icon: mdiSkipNext, action: "media_next_track" });
|
||||
}
|
||||
|
||||
return controls;
|
||||
}
|
||||
|
||||
private _togglePower(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService(
|
||||
"media_player",
|
||||
stateActive(this._stateObj) ? "turn_off" : "turn_on",
|
||||
{
|
||||
entity_id: this._stateObj.entity_id,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _action(e: Event): void {
|
||||
const action = (e.currentTarget as HTMLElement).getAttribute("key");
|
||||
if (!action) return;
|
||||
|
||||
switch (action) {
|
||||
case "media_play_pause":
|
||||
this._playPauseStop();
|
||||
break;
|
||||
case "media_play":
|
||||
this._play();
|
||||
break;
|
||||
case "media_pause":
|
||||
this._pause();
|
||||
break;
|
||||
case "media_stop":
|
||||
this._stop();
|
||||
break;
|
||||
case "media_previous_track":
|
||||
this._previousTrack();
|
||||
break;
|
||||
case "media_next_track":
|
||||
this._nextTrack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _playPauseStop(): void {
|
||||
if (!this._stateObj) return;
|
||||
|
||||
const service =
|
||||
this._stateObj.state !== "playing"
|
||||
? "media_play"
|
||||
: supportsFeature(this._stateObj, MediaPlayerEntityFeature.PAUSE)
|
||||
? "media_pause"
|
||||
: "media_stop";
|
||||
|
||||
this.hass!.callService("media_player", service, {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _play(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_play", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _pause(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_pause", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _stop(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_stop", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _previousTrack(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_previous_track", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _nextTrack(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_next_track", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
static styles = cardFeatureStyles;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-media-player-playback-card-feature": HuiMediaPlayerPlaybackCardFeature;
|
||||
}
|
||||
}
|
@@ -39,10 +39,6 @@ export interface LockOpenDoorCardFeatureConfig {
|
||||
type: "lock-open-door";
|
||||
}
|
||||
|
||||
export interface MediaPlayerPlaybackCardFeatureConfig {
|
||||
type: "media-player-playback";
|
||||
}
|
||||
|
||||
export interface MediaPlayerVolumeSliderCardFeatureConfig {
|
||||
type: "media-player-volume-slider";
|
||||
}
|
||||
@@ -246,7 +242,6 @@ export type LovelaceCardFeatureConfig =
|
||||
| LightColorTempCardFeatureConfig
|
||||
| LockCommandsCardFeatureConfig
|
||||
| LockOpenDoorCardFeatureConfig
|
||||
| MediaPlayerPlaybackCardFeatureConfig
|
||||
| MediaPlayerVolumeSliderCardFeatureConfig
|
||||
| NumericInputCardFeatureConfig
|
||||
| SelectOptionsCardFeatureConfig
|
||||
|
@@ -9,7 +9,6 @@ import {
|
||||
type TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
@@ -85,10 +84,8 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
|
||||
const displayType =
|
||||
config.display_type || (config.show_camera ? "camera" : "picture");
|
||||
const vertical = displayType === "compact" ? config.vertical : false;
|
||||
this._config = {
|
||||
...config,
|
||||
vertical,
|
||||
display_type: displayType,
|
||||
};
|
||||
|
||||
@@ -112,7 +109,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
const featuresCount = this._config?.features?.length || 0;
|
||||
return (
|
||||
1 +
|
||||
(displayType === "compact" ? (this._config?.vertical ? 1 : 0) : 2) +
|
||||
(displayType === "compact" ? 0 : 2) +
|
||||
(featuresPosition === "inline" ? 0 : featuresCount)
|
||||
);
|
||||
}
|
||||
@@ -136,11 +133,6 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
|
||||
const displayType = this._config?.display_type || "picture";
|
||||
|
||||
if (this._config?.vertical) {
|
||||
rows++;
|
||||
min_columns = 3;
|
||||
}
|
||||
|
||||
if (displayType !== "compact") {
|
||||
if (featurePosition === "inline" && featuresCount > 0) {
|
||||
rows += 3;
|
||||
@@ -405,12 +397,9 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
return sensorStates;
|
||||
}
|
||||
|
||||
private _featurePosition = memoizeOne((config: AreaCardConfig) => {
|
||||
if (config.vertical) {
|
||||
return "bottom";
|
||||
}
|
||||
return config.features_position || "bottom";
|
||||
});
|
||||
private _featurePosition = memoizeOne(
|
||||
(config: AreaCardConfig) => config.features_position || "bottom"
|
||||
);
|
||||
|
||||
private _displayedFeatures = memoizeOne((config: AreaCardConfig) => {
|
||||
const features = config.features || [];
|
||||
@@ -450,8 +439,6 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
const contentClasses = { vertical: Boolean(this._config.vertical) };
|
||||
|
||||
const icon = area.icon;
|
||||
|
||||
const name = this._config.name || computeAreaName(area);
|
||||
@@ -531,7 +518,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
</div>
|
||||
`}
|
||||
<div class="container ${containerOrientationClass}">
|
||||
<div class="content ${classMap(contentClasses)}">
|
||||
<div class="content">
|
||||
<ha-tile-icon>
|
||||
${displayType === "compact"
|
||||
? this._renderAlertSensorBadge()
|
||||
@@ -669,16 +656,6 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.vertical {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.vertical ha-tile-info {
|
||||
width: 100%;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
ha-tile-icon {
|
||||
--tile-icon-color: var(--tile-color);
|
||||
position: relative;
|
||||
|
@@ -251,6 +251,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
const entityId = this._config.entity;
|
||||
const stateObj = entityId ? this.hass.states[entityId] : undefined;
|
||||
|
||||
const contentClasses = { vertical: Boolean(this._config.vertical) };
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning .hass=${this.hass}>
|
||||
@@ -259,8 +261,6 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
const contentClasses = { vertical: Boolean(this._config.vertical) };
|
||||
|
||||
const name = this._config.name || computeStateName(stateObj);
|
||||
const active = stateActive(stateObj);
|
||||
const color = this._computeStateColor(stateObj, this._config.color);
|
||||
|
@@ -104,13 +104,12 @@ export interface EntitiesCardConfig extends LovelaceCardConfig {
|
||||
state_color?: boolean;
|
||||
}
|
||||
|
||||
export type AreaCardDisplayType = "compact" | "icon" | "picture" | "camera";
|
||||
export interface AreaCardConfig extends LovelaceCardConfig {
|
||||
area?: string;
|
||||
name?: string;
|
||||
color?: string;
|
||||
navigation_path?: string;
|
||||
display_type?: AreaCardDisplayType;
|
||||
display_type?: "compact" | "icon" | "picture" | "camera";
|
||||
/** @deprecated Use `display_type` instead */
|
||||
show_camera?: boolean;
|
||||
camera_view?: HuiImage["cameraView"];
|
||||
|
@@ -22,7 +22,6 @@ import "../card-features/hui-light-brightness-card-feature";
|
||||
import "../card-features/hui-light-color-temp-card-feature";
|
||||
import "../card-features/hui-lock-commands-card-feature";
|
||||
import "../card-features/hui-lock-open-door-card-feature";
|
||||
import "../card-features/hui-media-player-playback-card-feature";
|
||||
import "../card-features/hui-media-player-volume-slider-card-feature";
|
||||
import "../card-features/hui-numeric-input-card-feature";
|
||||
import "../card-features/hui-select-options-card-feature";
|
||||
@@ -71,7 +70,6 @@ const TYPES = new Set<LovelaceCardFeatureConfig["type"]>([
|
||||
"light-color-temp",
|
||||
"lock-commands",
|
||||
"lock-open-door",
|
||||
"media-player-playback",
|
||||
"media-player-volume-slider",
|
||||
"numeric-input",
|
||||
"select-options",
|
||||
|
@@ -36,7 +36,7 @@ import {
|
||||
DEVICE_CLASSES,
|
||||
type AreaCardFeatureContext,
|
||||
} from "../../cards/hui-area-card";
|
||||
import type { AreaCardConfig, AreaCardDisplayType } from "../../cards/types";
|
||||
import type { AreaCardConfig } from "../../cards/types";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||
import type { EditDetailElementEvent, EditSubElementEvent } from "../types";
|
||||
@@ -52,7 +52,6 @@ const cardConfigStruct = assign(
|
||||
navigation_path: optional(string()),
|
||||
show_camera: optional(boolean()),
|
||||
display_type: optional(enums(["compact", "icon", "picture", "camera"])),
|
||||
vertical: optional(boolean()),
|
||||
camera_view: optional(string()),
|
||||
alert_classes: optional(array(string())),
|
||||
sensor_classes: optional(array(string())),
|
||||
@@ -79,7 +78,7 @@ export class HuiAreaCardEditor
|
||||
private _schema = memoizeOne(
|
||||
(
|
||||
localize: LocalizeFunc,
|
||||
displayType: AreaCardDisplayType,
|
||||
showCamera: boolean,
|
||||
binaryClasses: SelectOption[],
|
||||
sensorClasses: SelectOption[]
|
||||
) =>
|
||||
@@ -114,28 +113,7 @@ export class HuiAreaCardEditor
|
||||
},
|
||||
},
|
||||
},
|
||||
...(displayType === "compact"
|
||||
? ([
|
||||
{
|
||||
name: "content_layout",
|
||||
required: true,
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: ["horizontal", "vertical"].map(
|
||||
(value) => ({
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.card.area.content_layout_options.${value}`
|
||||
),
|
||||
value,
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const satisfies readonly HaFormSchema[])
|
||||
: []),
|
||||
...(displayType === "camera"
|
||||
...(showCamera
|
||||
? ([
|
||||
{
|
||||
name: "camera_view",
|
||||
@@ -304,7 +282,7 @@ export class HuiAreaCardEditor
|
||||
}
|
||||
|
||||
private _featuresSchema = memoizeOne(
|
||||
(localize: LocalizeFunc, vertical: boolean) =>
|
||||
(localize: LocalizeFunc) =>
|
||||
[
|
||||
{
|
||||
name: "features_position",
|
||||
@@ -325,7 +303,6 @@ export class HuiAreaCardEditor
|
||||
src_dark: `/static/images/form/tile_features_position_${value}_dark.svg`,
|
||||
flip_rtl: true,
|
||||
},
|
||||
disabled: vertical && value === "inline",
|
||||
})),
|
||||
},
|
||||
},
|
||||
@@ -361,35 +338,31 @@ export class HuiAreaCardEditor
|
||||
this._config.sensor_classes || DEVICE_CLASSES.sensor
|
||||
);
|
||||
|
||||
const showCamera = this._config.display_type === "camera";
|
||||
|
||||
const displayType =
|
||||
this._config.display_type ||
|
||||
(this._config.show_camera ? "camera" : "picture");
|
||||
this._config.display_type || this._config.show_camera
|
||||
? "camera"
|
||||
: "picture";
|
||||
|
||||
const schema = this._schema(
|
||||
this.hass.localize,
|
||||
displayType,
|
||||
showCamera,
|
||||
binarySelectOptions,
|
||||
sensorSelectOptions
|
||||
);
|
||||
|
||||
const vertical = this._config.vertical && displayType === "compact";
|
||||
|
||||
const featuresSchema = this._featuresSchema(this.hass.localize, vertical);
|
||||
const featuresSchema = this._featuresSchema(this.hass.localize);
|
||||
|
||||
const data = {
|
||||
camera_view: "auto",
|
||||
alert_classes: DEVICE_CLASSES.binary_sensor,
|
||||
sensor_classes: DEVICE_CLASSES.sensor,
|
||||
features_position: "bottom",
|
||||
display_type: displayType,
|
||||
content_layout: vertical ? "vertical" : "horizontal",
|
||||
...this._config,
|
||||
};
|
||||
|
||||
// Default features position to bottom and force it to bottom in vertical mode
|
||||
if (!data.features_position || vertical) {
|
||||
data.features_position = "bottom";
|
||||
}
|
||||
|
||||
const hasCompatibleFeatures = this._hasCompatibleFeatures(
|
||||
this._featureContext
|
||||
);
|
||||
@@ -447,12 +420,6 @@ export class HuiAreaCardEditor
|
||||
delete config.camera_view;
|
||||
}
|
||||
|
||||
// Convert content_layout to vertical
|
||||
if (config.content_layout) {
|
||||
config.vertical = config.content_layout === "vertical";
|
||||
delete config.content_layout;
|
||||
}
|
||||
|
||||
fireEvent(this, "config-changed", { config });
|
||||
}
|
||||
|
||||
|
@@ -42,7 +42,6 @@ import { supportsLightBrightnessCardFeature } from "../../card-features/hui-ligh
|
||||
import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature";
|
||||
import { supportsLockCommandsCardFeature } from "../../card-features/hui-lock-commands-card-feature";
|
||||
import { supportsLockOpenDoorCardFeature } from "../../card-features/hui-lock-open-door-card-feature";
|
||||
import { supportsMediaPlayerPlaybackCardFeature } from "../../card-features/hui-media-player-playback-card-feature";
|
||||
import { supportsMediaPlayerVolumeSliderCardFeature } from "../../card-features/hui-media-player-volume-slider-card-feature";
|
||||
import { supportsNumericInputCardFeature } from "../../card-features/hui-numeric-input-card-feature";
|
||||
import { supportsSelectOptionsCardFeature } from "../../card-features/hui-select-options-card-feature";
|
||||
@@ -96,7 +95,6 @@ const UI_FEATURE_TYPES = [
|
||||
"light-color-temp",
|
||||
"lock-commands",
|
||||
"lock-open-door",
|
||||
"media-player-playback",
|
||||
"media-player-volume-slider",
|
||||
"numeric-input",
|
||||
"select-options",
|
||||
@@ -164,7 +162,6 @@ const SUPPORTS_FEATURE_TYPES: Record<
|
||||
"light-color-temp": supportsLightColorTempCardFeature,
|
||||
"lock-commands": supportsLockCommandsCardFeature,
|
||||
"lock-open-door": supportsLockOpenDoorCardFeature,
|
||||
"media-player-playback": supportsMediaPlayerPlaybackCardFeature,
|
||||
"media-player-volume-slider": supportsMediaPlayerVolumeSliderCardFeature,
|
||||
"numeric-input": supportsNumericInputCardFeature,
|
||||
"select-options": supportsSelectOptionsCardFeature,
|
||||
|
@@ -261,17 +261,18 @@ export class HuiTileCardEditor
|
||||
this._config.hide_state ?? false
|
||||
);
|
||||
|
||||
const vertical = this._config.vertical ?? false;
|
||||
|
||||
const featuresSchema = this._featuresSchema(this.hass.localize, vertical);
|
||||
const featuresSchema = this._featuresSchema(
|
||||
this.hass.localize,
|
||||
this._config.vertical ?? false
|
||||
);
|
||||
|
||||
const data = {
|
||||
...this._config,
|
||||
content_layout: vertical ? "vertical" : "horizontal",
|
||||
content_layout: this._config.vertical ? "vertical" : "horizontal",
|
||||
};
|
||||
|
||||
// Default features position to bottom and force it to bottom in vertical mode
|
||||
if (!data.features_position || vertical) {
|
||||
if (!data.features_position || data.vertical) {
|
||||
data.features_position = "bottom";
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,5 @@
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import {
|
||||
mdiClose,
|
||||
mdiDotsVertical,
|
||||
mdiFileMoveOutline,
|
||||
mdiPlaylistEdit,
|
||||
} from "@mdi/js";
|
||||
import { mdiClose, mdiDotsVertical, mdiPlaylistEdit } from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
@@ -21,10 +16,7 @@ import "../../../../components/ha-yaml-editor";
|
||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
import "../../../../components/sl-tab-group";
|
||||
import type { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
|
||||
import {
|
||||
isStrategyView,
|
||||
type LovelaceViewConfig,
|
||||
} from "../../../../data/lovelace/config/view";
|
||||
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
@@ -35,12 +27,6 @@ import {
|
||||
import "./hui-section-settings-editor";
|
||||
import "./hui-section-visibility-editor";
|
||||
import type { EditSectionDialogParams } from "./show-edit-section-dialog";
|
||||
import { showSelectViewDialog } from "../select-view/show-select-view-dialog";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import { saveConfig } from "../../../../data/lovelace/config/types";
|
||||
import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { addSection, deleteSection, moveSection } from "../config-util";
|
||||
import type { Lovelace } from "../../types";
|
||||
|
||||
const TABS = ["tab-settings", "tab-visibility"] as const;
|
||||
|
||||
@@ -51,8 +37,6 @@ export class HuiDialogEditSection
|
||||
{
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelace?: Lovelace;
|
||||
|
||||
@state() private _params?: EditSectionDialogParams;
|
||||
|
||||
@state() private _config?: LovelaceSectionRawConfig;
|
||||
@@ -77,8 +61,6 @@ export class HuiDialogEditSection
|
||||
public async showDialog(params: EditSectionDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
|
||||
this.lovelace = params.lovelace;
|
||||
|
||||
this._config = findLovelaceContainer(this._params.lovelaceConfig, [
|
||||
this._params.viewIndex,
|
||||
this._params.sectionIndex,
|
||||
@@ -183,15 +165,6 @@ export class HuiDialogEditSection
|
||||
.path=${mdiPlaylistEdit}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.move_to_view"
|
||||
)}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiFileMoveOutline}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
${!this._yamlMode
|
||||
? html`
|
||||
@@ -249,138 +222,9 @@ export class HuiDialogEditSection
|
||||
case 0:
|
||||
this._yamlMode = !this._yamlMode;
|
||||
break;
|
||||
case 1:
|
||||
this._openSelectView();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _openSelectView(): void {
|
||||
if (!this._params || !this.lovelace) {
|
||||
return;
|
||||
}
|
||||
|
||||
showSelectViewDialog(this, {
|
||||
lovelaceConfig: this._params.lovelaceConfig,
|
||||
urlPath: this.lovelace.urlPath,
|
||||
allowDashboardChange: true,
|
||||
header: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.header"
|
||||
),
|
||||
viewSelectedCallback: this._moveSectionToView,
|
||||
});
|
||||
}
|
||||
|
||||
private _moveSectionToView = async (
|
||||
urlPath: string | null,
|
||||
selectedDashConfig: LovelaceConfig,
|
||||
viewIndex: number
|
||||
) => {
|
||||
if (!this._params || !this.lovelace) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toView = selectedDashConfig.views[viewIndex];
|
||||
|
||||
if (isStrategyView(toView)) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.error_title"
|
||||
),
|
||||
text: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.error_text_strategy"
|
||||
),
|
||||
warning: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const fromViewIndex = this._params.viewIndex;
|
||||
const fromSectionIndex = this._params.sectionIndex;
|
||||
|
||||
// Same dashboard
|
||||
if (urlPath === this.lovelace.urlPath) {
|
||||
const oldConfig = this.lovelace.config;
|
||||
const toIndex = toView.sections?.length ?? 0;
|
||||
try {
|
||||
await this.lovelace.saveConfig(
|
||||
moveSection(
|
||||
oldConfig,
|
||||
[fromViewIndex, fromSectionIndex],
|
||||
[viewIndex, toIndex]
|
||||
)
|
||||
);
|
||||
this.lovelace.showToast({
|
||||
message: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.success"
|
||||
),
|
||||
duration: 4000,
|
||||
action: {
|
||||
action: async () => {
|
||||
await this.lovelace!.saveConfig(oldConfig);
|
||||
},
|
||||
text: this.hass!.localize("ui.common.undo"),
|
||||
},
|
||||
});
|
||||
|
||||
this.closeDialog();
|
||||
} catch (err: any) {
|
||||
this.lovelace.showToast({
|
||||
message: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.error"
|
||||
),
|
||||
});
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Cross dashboard
|
||||
const oldFromConfig = this.lovelace.config;
|
||||
const oldToConfig = selectedDashConfig;
|
||||
try {
|
||||
const section = findLovelaceContainer(oldFromConfig, [
|
||||
fromViewIndex,
|
||||
fromSectionIndex,
|
||||
]) as LovelaceSectionRawConfig;
|
||||
|
||||
await saveConfig(
|
||||
this.hass!,
|
||||
urlPath,
|
||||
addSection(oldToConfig, viewIndex, section)
|
||||
);
|
||||
|
||||
await this.lovelace.saveConfig(
|
||||
deleteSection(oldFromConfig, fromViewIndex, fromSectionIndex)
|
||||
);
|
||||
|
||||
this.lovelace.showToast({
|
||||
message: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.success"
|
||||
),
|
||||
duration: 4000,
|
||||
action: {
|
||||
action: async () => {
|
||||
await saveConfig(this.hass!, urlPath, oldToConfig);
|
||||
await this.lovelace!.saveConfig(oldFromConfig);
|
||||
},
|
||||
text: this.hass!.localize("ui.common.undo"),
|
||||
},
|
||||
});
|
||||
|
||||
this.closeDialog();
|
||||
} catch (err: any) {
|
||||
this.lovelace.showToast({
|
||||
message: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_section.error"
|
||||
),
|
||||
});
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
private _viewYamlChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (!ev.detail.isValid) {
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { mdiFormatColorFill } from "@mdi/js";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type {
|
||||
HaFormSchema,
|
||||
@@ -12,13 +10,9 @@ import "../../../../components/ha-form/ha-form";
|
||||
import type { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
|
||||
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { hex2rgb, rgb2hex } from "../../../../common/color/convert-color";
|
||||
|
||||
interface SettingsData {
|
||||
column_span?: number;
|
||||
background_type: "none" | "color";
|
||||
background_color?: number[];
|
||||
background_opacity?: number;
|
||||
}
|
||||
|
||||
@customElement("hui-section-settings-editor")
|
||||
@@ -29,10 +23,8 @@ export class HuiDialogEditSection extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public viewConfig!: LovelaceViewConfig;
|
||||
|
||||
@state() private _selectorBackgroundType: "none" | "color" = "none";
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(maxColumns: number, enableBackground: boolean) =>
|
||||
(maxColumns: number) =>
|
||||
[
|
||||
{
|
||||
name: "column_span",
|
||||
@@ -44,91 +36,15 @@ export class HuiDialogEditSection extends LitElement {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "styling",
|
||||
type: "expandable",
|
||||
flatten: true,
|
||||
iconPath: mdiFormatColorFill,
|
||||
schema: [
|
||||
{
|
||||
name: "background_settings",
|
||||
flatten: true,
|
||||
type: "grid",
|
||||
schema: [
|
||||
{
|
||||
name: "background_type",
|
||||
required: true,
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: [
|
||||
{
|
||||
value: "none",
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_section.settings.background_type_none_option"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "color",
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_section.settings.background_type_color_option"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "background_color",
|
||||
selector: {
|
||||
color_rgb: {},
|
||||
},
|
||||
disabled: !enableBackground,
|
||||
},
|
||||
{
|
||||
name: "background_opacity",
|
||||
selector: {
|
||||
number: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
disabled: !enableBackground,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
] as const satisfies HaFormSchema[]
|
||||
);
|
||||
|
||||
protected firstUpdated(_changedProperties: PropertyValues) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
|
||||
if (this.config.style?.background_color) {
|
||||
this._selectorBackgroundType = "color";
|
||||
} else {
|
||||
this._selectorBackgroundType = "none";
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const data: SettingsData = {
|
||||
column_span: this.config.column_span || 1,
|
||||
background_type: this._selectorBackgroundType,
|
||||
background_color: this.config.style?.background_color
|
||||
? hex2rgb(this.config.style?.background_color as any)
|
||||
: [],
|
||||
background_opacity: this.config.style?.background_opacity || 100,
|
||||
};
|
||||
|
||||
const schema = this._schema(
|
||||
this.viewConfig.max_columns || 4,
|
||||
this._selectorBackgroundType === "color"
|
||||
);
|
||||
const schema = this._schema(this.viewConfig.max_columns || 4);
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
@@ -160,27 +76,11 @@ export class HuiDialogEditSection extends LitElement {
|
||||
ev.stopPropagation();
|
||||
const newData = ev.detail.value as SettingsData;
|
||||
|
||||
this._selectorBackgroundType = newData.background_type;
|
||||
|
||||
const newConfig: LovelaceSectionRawConfig = {
|
||||
...this.config,
|
||||
column_span: newData.column_span,
|
||||
};
|
||||
|
||||
if (newData.background_type === "color") {
|
||||
newConfig.style = {
|
||||
...newConfig.style,
|
||||
background_color: rgb2hex(newData.background_color as any),
|
||||
background_opacity: newData.background_opacity,
|
||||
};
|
||||
} else {
|
||||
newConfig.style = {
|
||||
...newConfig.style,
|
||||
background_color: undefined,
|
||||
background_opacity: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,7 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||
import type { Lovelace } from "../../types";
|
||||
|
||||
export interface EditSectionDialogParams {
|
||||
lovelace: Lovelace;
|
||||
lovelaceConfig: LovelaceConfig;
|
||||
saveConfig: (config: LovelaceConfig) => void;
|
||||
viewIndex: number;
|
||||
|
@@ -1,9 +1,7 @@
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiCodeBraces,
|
||||
mdiCommentProcessingOutline,
|
||||
mdiDevices,
|
||||
mdiDotsVertical,
|
||||
mdiFileMultiple,
|
||||
mdiFormatListBulletedTriangle,
|
||||
@@ -12,9 +10,7 @@ import {
|
||||
mdiPencil,
|
||||
mdiPlus,
|
||||
mdiRefresh,
|
||||
mdiRobot,
|
||||
mdiShape,
|
||||
mdiSofa,
|
||||
mdiViewDashboard,
|
||||
} from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
@@ -56,7 +52,6 @@ import {
|
||||
updateDashboard,
|
||||
} from "../../data/lovelace/dashboard";
|
||||
import { getPanelTitle } from "../../data/panel";
|
||||
import { createPerson } from "../../data/person";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
@@ -71,10 +66,7 @@ import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant, PanelInfo } from "../../types";
|
||||
import { documentationUrl } from "../../util/documentation-url";
|
||||
import { showNewAutomationDialog } from "../config/automation/show-dialog-new-automation";
|
||||
import { showAddIntegrationDialog } from "../config/integrations/show-add-integration-dialog";
|
||||
import { showDashboardDetailDialog } from "../config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail";
|
||||
import { showPersonDetailDialog } from "../config/person/show-dialog-person-detail";
|
||||
import { swapView } from "./editor/config-util";
|
||||
import { showDashboardStrategyEditorDialog } from "./editor/dashboard-strategy-editor/dialogs/show-dialog-dashboard-strategy-editor";
|
||||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||
@@ -86,28 +78,6 @@ import "./views/hui-view";
|
||||
import type { HUIView } from "./views/hui-view";
|
||||
import "./views/hui-view-background";
|
||||
import "./views/hui-view-container";
|
||||
import { showAreaRegistryDetailDialog } from "../config/areas/show-dialog-area-registry-detail";
|
||||
import { createAreaRegistryEntry } from "../../data/area_registry";
|
||||
import { showToast } from "../../util/toast";
|
||||
|
||||
interface ActionItem {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
overflowAction?: any;
|
||||
buttonAction?: any;
|
||||
visible: boolean | undefined;
|
||||
overflow: boolean;
|
||||
overflow_can_promote?: boolean;
|
||||
suffix?: string;
|
||||
subItems?: SubActionItem[];
|
||||
}
|
||||
|
||||
interface SubActionItem {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
action?: any;
|
||||
visible: boolean | undefined;
|
||||
}
|
||||
|
||||
@customElement("hui-root")
|
||||
class HUIRoot extends LitElement {
|
||||
@@ -175,7 +145,16 @@ class HUIRoot extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
const items: ActionItem[] = [
|
||||
const items: {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
overflowAction?: any;
|
||||
buttonAction?: any;
|
||||
visible: boolean | undefined;
|
||||
overflow: boolean;
|
||||
overflow_can_promote?: boolean;
|
||||
suffix?: string;
|
||||
}[] = [
|
||||
{
|
||||
icon: mdiFormatListBulletedTriangle,
|
||||
key: "ui.panel.lovelace.unused_entities.title",
|
||||
@@ -204,45 +183,13 @@ class HUIRoot extends LitElement {
|
||||
visible: this._editMode && this.hass.userData?.showAdvanced,
|
||||
overflow: true,
|
||||
},
|
||||
{
|
||||
icon: mdiPlus,
|
||||
key: "ui.panel.lovelace.menu.add",
|
||||
visible: !this._editMode && this.hass.user?.is_admin,
|
||||
overflow: false,
|
||||
subItems: [
|
||||
{
|
||||
icon: mdiDevices,
|
||||
key: "ui.panel.lovelace.menu.add_device",
|
||||
visible: true,
|
||||
action: this._handleAddDevice,
|
||||
},
|
||||
{
|
||||
icon: mdiRobot,
|
||||
key: "ui.panel.lovelace.menu.create_automation",
|
||||
visible: true,
|
||||
action: this._handleACreateAutomation,
|
||||
},
|
||||
{
|
||||
icon: mdiSofa,
|
||||
key: "ui.panel.lovelace.menu.add_area",
|
||||
visible: true,
|
||||
action: this._handleAddArea,
|
||||
},
|
||||
{
|
||||
icon: mdiAccount,
|
||||
key: "ui.panel.lovelace.menu.invite_person",
|
||||
visible: true,
|
||||
action: this._handleInvitePerson,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: mdiMagnify,
|
||||
key: "ui.panel.lovelace.menu.search_entities",
|
||||
buttonAction: this._showQuickBar,
|
||||
overflowAction: this._handleShowQuickBar,
|
||||
visible: !this._editMode,
|
||||
overflow: false,
|
||||
overflow: this.narrow,
|
||||
suffix: this.hass.enableShortcuts ? "(E)" : undefined,
|
||||
},
|
||||
{
|
||||
@@ -252,7 +199,7 @@ class HUIRoot extends LitElement {
|
||||
overflowAction: this._handleShowVoiceCommandDialog,
|
||||
visible:
|
||||
!this._editMode && this._conversation(this.hass.config.components),
|
||||
overflow: false,
|
||||
overflow: this.narrow,
|
||||
suffix: this.hass.enableShortcuts ? "(A)" : undefined,
|
||||
},
|
||||
{
|
||||
@@ -300,50 +247,20 @@ class HUIRoot extends LitElement {
|
||||
(i) => i.visible && (!i.overflow || overflowCanPromote)
|
||||
);
|
||||
|
||||
buttonItems.forEach((item) => {
|
||||
const label = [this.hass!.localize(item.key), item.suffix].join(" ");
|
||||
const button = item.subItems
|
||||
? html`
|
||||
<ha-button-menu
|
||||
slot="actionItems"
|
||||
corner="BOTTOM_END"
|
||||
menu-corner="END"
|
||||
>
|
||||
<ha-icon-button
|
||||
.label=${label}
|
||||
.path=${item.icon}
|
||||
slot="trigger"
|
||||
></ha-icon-button>
|
||||
${item.subItems
|
||||
.filter((subItem) => subItem.visible)
|
||||
.map(
|
||||
(subItem) => html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.key=${subItem.key}
|
||||
@request-selected=${subItem.action}
|
||||
>
|
||||
${this.hass!.localize(subItem.key)}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${subItem.icon}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>
|
||||
`
|
||||
: html`
|
||||
<ha-tooltip slot="actionItems" placement="bottom" .content=${label}>
|
||||
<ha-icon-button
|
||||
.path=${item.icon}
|
||||
@click=${item.buttonAction}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
result.push(button);
|
||||
buttonItems.forEach((i) => {
|
||||
result.push(
|
||||
html`<ha-tooltip
|
||||
slot="actionItems"
|
||||
placement="bottom"
|
||||
.content=${[this.hass!.localize(i.key), i.suffix].join(" ")}
|
||||
>
|
||||
<ha-icon-button
|
||||
.path=${i.icon}
|
||||
@click=${i.buttonAction}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>`
|
||||
);
|
||||
});
|
||||
|
||||
if (overflowItems.length && !overflowCanPromote) {
|
||||
const listItems: TemplateResult[] = [];
|
||||
overflowItems.forEach((i) => {
|
||||
@@ -456,15 +373,10 @@ class HUIRoot extends LitElement {
|
||||
})}
|
||||
</sl-tab-group>`;
|
||||
|
||||
const isSubview = curViewConfig?.subview;
|
||||
const hasTabViews = views.filter((view) => !view.subview).length > 1;
|
||||
const showTabBar = this._editMode || (!isSubview && hasTabViews);
|
||||
|
||||
return html`
|
||||
<div
|
||||
class=${classMap({
|
||||
"edit-mode": this._editMode,
|
||||
narrow: this.narrow,
|
||||
})}
|
||||
>
|
||||
<div class="header">
|
||||
@@ -487,7 +399,7 @@ class HUIRoot extends LitElement {
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`
|
||||
: html`
|
||||
${isSubview
|
||||
${curViewConfig?.subview
|
||||
? html`
|
||||
<ha-icon-button-arrow-prev
|
||||
slot="navigationIcon"
|
||||
@@ -501,37 +413,34 @@ class HUIRoot extends LitElement {
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
`}
|
||||
${isSubview
|
||||
${curViewConfig?.subview
|
||||
? html`<div class="main-title">${curViewConfig.title}</div>`
|
||||
: hasTabViews && !showTabBar
|
||||
: views.filter((view) => !view.subview).length > 1
|
||||
? tabs
|
||||
: html`
|
||||
<div class="main-title">
|
||||
${curViewConfig?.title ?? dashboardTitle}
|
||||
${views[0]?.title ?? dashboardTitle}
|
||||
</div>
|
||||
`}
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`}
|
||||
</div>
|
||||
${showTabBar
|
||||
${this._editMode
|
||||
? html`<div class="edit-tab-bar">
|
||||
${tabs}
|
||||
${this._editMode
|
||||
? html`<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>`
|
||||
: nothing}
|
||||
<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>
|
||||
</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
<hui-view-container
|
||||
class=${showTabBar ? "has-tab-bar" : ""}
|
||||
.hass=${this.hass}
|
||||
.theme=${curViewConfig?.theme}
|
||||
id="view"
|
||||
@@ -787,79 +696,6 @@ class HUIRoot extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleAddDevice(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAddIntegrationDialog(this);
|
||||
}
|
||||
|
||||
private async _handleACreateAutomation(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showNewAutomationDialog(this, { mode: "automation" });
|
||||
}
|
||||
|
||||
private async _handleAddArea(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAreaRegistryDetailDialog(this, {
|
||||
createEntry: async (values) => {
|
||||
const area = await createAreaRegistryEntry(this.hass, values);
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_area_success"
|
||||
),
|
||||
action: {
|
||||
action: () => {
|
||||
navigate(`/config/areas/area/${area.area_id}`);
|
||||
},
|
||||
text: this.hass.localize("ui.panel.lovelace.menu.add_area_action"),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async _handleInvitePerson(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showPersonDetailDialog(this, {
|
||||
users: [],
|
||||
createEntry: async (values) => {
|
||||
await createPerson(this.hass!, values);
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_person_success"
|
||||
),
|
||||
action: {
|
||||
action: () => {
|
||||
navigate(`/config/person`);
|
||||
},
|
||||
text: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_person_action"
|
||||
),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _handleRawEditor(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
@@ -1214,14 +1050,6 @@ class HUIRoot extends LitElement {
|
||||
margin: var(--margin-title);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
flex-grow: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
.narrow .main-title {
|
||||
margin: 0;
|
||||
margin-inline-start: 8px;
|
||||
}
|
||||
.action-items {
|
||||
white-space: nowrap;
|
||||
@@ -1286,6 +1114,9 @@ class HUIRoot extends LitElement {
|
||||
--ha-tab-active-text-color: var(--app-header-edit-text-color, #fff);
|
||||
--ha-tab-indicator-color: var(--app-header-edit-text-color, #fff);
|
||||
}
|
||||
.edit-mode sl-tab {
|
||||
height: 54px;
|
||||
}
|
||||
sl-tab {
|
||||
height: calc(var(--header-height, 56px) - 2px);
|
||||
}
|
||||
@@ -1357,10 +1188,9 @@ class HUIRoot extends LitElement {
|
||||
/**
|
||||
* In edit mode we have the tab bar on a new line *
|
||||
*/
|
||||
hui-view-container.has-tab-bar {
|
||||
.edit-mode hui-view-container {
|
||||
padding-top: calc(
|
||||
var(--header-height) + calc(var(--header-height, 56px) - 2px) +
|
||||
var(--safe-area-inset-top)
|
||||
var(--header-height) + 48px + var(--safe-area-inset-top)
|
||||
);
|
||||
}
|
||||
.hide-tab {
|
||||
|
@@ -20,7 +20,6 @@ import "../components/hui-card-edit-mode";
|
||||
import { moveCard } from "../editor/config-util";
|
||||
import type { LovelaceCardPath } from "../editor/lovelace-path";
|
||||
import type { Lovelace } from "../types";
|
||||
import { hex2rgb } from "../../../common/color/convert-color";
|
||||
|
||||
const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
|
||||
delay: 100,
|
||||
@@ -87,12 +86,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
? IMPORT_MODE_CARD_SORTABLE_OPTIONS
|
||||
: CARD_SORTABLE_OPTIONS;
|
||||
|
||||
const backgroundOpacity =
|
||||
(this._config.style?.background_opacity || 100) / 100;
|
||||
const background = this._config.style?.background_color
|
||||
? `rgba(${hex2rgb(this._config.style.background_color)}, ${backgroundOpacity})`
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
@@ -110,11 +103,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
class="container ${classMap({
|
||||
"edit-mode": editMode,
|
||||
"import-only": this.importOnly,
|
||||
"has-background": Boolean(background),
|
||||
})}"
|
||||
style=${styleMap({
|
||||
background: background,
|
||||
})}
|
||||
>
|
||||
${repeat(
|
||||
cardsConfig,
|
||||
@@ -261,10 +250,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
border: none;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.container.has-background {
|
||||
padding: 8px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
|
@@ -3,7 +3,6 @@ import { customElement } from "lit/decorators";
|
||||
import { generateEntityFilter } from "../../../../common/entity/entity_filter";
|
||||
import { clamp } from "../../../../common/number/clamp";
|
||||
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 { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
@@ -12,11 +11,11 @@ import {
|
||||
getAreas,
|
||||
getFloors,
|
||||
} from "../areas/helpers/areas-strategy-helper";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
import {
|
||||
findEntities,
|
||||
OVERVIEW_SUMMARIES_FILTERS,
|
||||
} from "./helpers/overview-summaries";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
|
||||
export interface OverviewClimateViewStrategyConfig {
|
||||
type: "overview-climate";
|
||||
@@ -25,9 +24,10 @@ export interface OverviewClimateViewStrategyConfig {
|
||||
const processAreasForClimate = (
|
||||
areaIds: string[],
|
||||
hass: HomeAssistant,
|
||||
entities: string[]
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
entities: string[],
|
||||
computeTileCard: (entityId: string) => any
|
||||
): any[] => {
|
||||
const cards: any[] = [];
|
||||
|
||||
for (const areaId of areaIds) {
|
||||
const area = hass.areas[areaId];
|
||||
@@ -38,8 +38,6 @@ const processAreasForClimate = (
|
||||
});
|
||||
const areaEntities = entities.filter(areaFilter);
|
||||
|
||||
const computeTileCard = computeAreaTileCardConfig(hass, "", true);
|
||||
|
||||
if (areaEntities.length > 0) {
|
||||
cards.push({
|
||||
heading_style: "subtitle",
|
||||
@@ -83,6 +81,8 @@ export class OverviewClimateViewStrategy extends ReactiveElement {
|
||||
|
||||
const floorCount = home.floors.length + (home.areas.length ? 1 : 0);
|
||||
|
||||
const computeTileCard = computeAreaTileCardConfig(hass, "", true);
|
||||
|
||||
// Process floors
|
||||
for (const floorStructure of home.floors) {
|
||||
const floorId = floorStructure.id;
|
||||
@@ -100,7 +100,12 @@ export class OverviewClimateViewStrategy extends ReactiveElement {
|
||||
],
|
||||
};
|
||||
|
||||
const areaCards = processAreasForClimate(areaIds, hass, entities);
|
||||
const areaCards = processAreasForClimate(
|
||||
areaIds,
|
||||
hass,
|
||||
entities,
|
||||
computeTileCard
|
||||
);
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
section.cards!.push(...areaCards);
|
||||
@@ -121,7 +126,12 @@ export class OverviewClimateViewStrategy extends ReactiveElement {
|
||||
],
|
||||
};
|
||||
|
||||
const areaCards = processAreasForClimate(home.areas, hass, entities);
|
||||
const areaCards = processAreasForClimate(
|
||||
home.areas,
|
||||
hass,
|
||||
entities,
|
||||
computeTileCard
|
||||
);
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
section.cards!.push(...areaCards);
|
||||
|
@@ -1,16 +1,22 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { clamp } from "../../../../common/number/clamp";
|
||||
import { floorDefaultIcon } from "../../../../components/ha-floor-icon";
|
||||
import type { AreaRegistryEntry } from "../../../../data/area_registry";
|
||||
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { getAreaControlEntities } from "../../card-features/hui-area-controls-card-feature";
|
||||
import { AREA_CONTROLS, type AreaControl } from "../../card-features/types";
|
||||
import type {
|
||||
AreaCardConfig,
|
||||
ButtonCardConfig,
|
||||
HeadingCardConfig,
|
||||
MarkdownCardConfig,
|
||||
TileCardConfig,
|
||||
} from "../../cards/types";
|
||||
import { getAreas } from "../areas/helpers/areas-strategy-helper";
|
||||
import { getAreas, getFloors } from "../areas/helpers/areas-strategy-helper";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
import { OVERVIEW_SUMMARIES_ICONS } from "./helpers/overview-summaries";
|
||||
|
||||
export interface OverviewHomeViewStrategyConfig {
|
||||
@@ -25,22 +31,42 @@ const computeAreaCard = (
|
||||
const area = hass.areas[areaId] as AreaRegistryEntry | undefined;
|
||||
const path = `areas-${areaId}`;
|
||||
|
||||
const controls: AreaControl[] = AREA_CONTROLS.filter(
|
||||
(a) => a !== "switch" // Exclude switches control for areas as we don't know what the switches control
|
||||
);
|
||||
const controlEntities = getAreaControlEntities(controls, areaId, [], hass);
|
||||
|
||||
const filteredControls = controls.filter(
|
||||
(control) => controlEntities[control].length > 0
|
||||
);
|
||||
|
||||
const sensorClasses: string[] = [];
|
||||
if (area?.temperature_entity_id) {
|
||||
sensorClasses.push("temperature");
|
||||
}
|
||||
if (area?.humidity_entity_id) {
|
||||
sensorClasses.push("humidity");
|
||||
}
|
||||
|
||||
return {
|
||||
type: "area",
|
||||
area: areaId,
|
||||
display_type: "compact",
|
||||
sensor_classes: sensorClasses,
|
||||
navigation_path: path,
|
||||
vertical: true,
|
||||
features: filteredControls.length
|
||||
? [
|
||||
{
|
||||
type: "area-controls",
|
||||
controls: filteredControls,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
rows: 1,
|
||||
columns: 12,
|
||||
},
|
||||
features_position: "inline",
|
||||
navigation_path: path,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -50,25 +76,58 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
config: OverviewHomeViewStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const floors = getFloors(hass.floors);
|
||||
const areas = getAreas(hass.areas);
|
||||
|
||||
const areasSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
column_span: 2,
|
||||
cards: [
|
||||
{
|
||||
const home = getHomeStructure(floors, areas);
|
||||
|
||||
const floorCount = home.floors.length + (home.areas.length ? 1 : 0);
|
||||
|
||||
const floorsSections: LovelaceSectionConfig[] = home.floors.map(
|
||||
(floorStructure) => {
|
||||
const floorId = floorStructure.id;
|
||||
const areaIds = floorStructure.areas;
|
||||
const floor = hass.floors[floorId];
|
||||
|
||||
const headingCard: HeadingCardConfig = {
|
||||
type: "heading",
|
||||
heading_style: "title",
|
||||
heading: "Areas",
|
||||
},
|
||||
...areas.map<AreaCardConfig>((area) =>
|
||||
computeAreaCard(area.area_id, hass)
|
||||
),
|
||||
],
|
||||
};
|
||||
heading: floorCount > 1 ? floor.name : "Areas",
|
||||
icon: floor.icon || floorDefaultIcon(floor),
|
||||
};
|
||||
|
||||
const areasCards = areaIds.map<AreaCardConfig>((areaId) =>
|
||||
computeAreaCard(areaId, hass)
|
||||
);
|
||||
|
||||
return {
|
||||
max_columns: 3,
|
||||
type: "grid",
|
||||
cards: [headingCard, ...areasCards],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
if (home.areas.length > 0) {
|
||||
floorsSections.push({
|
||||
type: "grid",
|
||||
max_columns: 3,
|
||||
cards: [
|
||||
{
|
||||
type: "heading",
|
||||
heading_style: "title",
|
||||
icon: "mdi:home",
|
||||
heading: floorCount > 1 ? "Other areas" : "Areas",
|
||||
},
|
||||
...home.areas.map<AreaCardConfig>((areaId) =>
|
||||
computeAreaCard(areaId, hass)
|
||||
),
|
||||
],
|
||||
} as LovelaceSectionConfig);
|
||||
}
|
||||
|
||||
// Allow between 2 and 3 columns (the max should be set to define the width of the header)
|
||||
const maxColumns = 2;
|
||||
const maxColumns = clamp(floorsSections.length, 2, 3);
|
||||
|
||||
const favoriteSection: LovelaceSectionConfig = {
|
||||
type: "grid",
|
||||
@@ -84,8 +143,7 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
favoriteSection.cards!.push(
|
||||
{
|
||||
type: "heading",
|
||||
heading: "",
|
||||
heading_style: "subtitle",
|
||||
heading: "Quick actions",
|
||||
},
|
||||
...favoriteEntities.map(
|
||||
(entityId) =>
|
||||
@@ -109,7 +167,6 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
type: "button",
|
||||
icon: OVERVIEW_SUMMARIES_ICONS.lights,
|
||||
name: "Lights",
|
||||
icon_height: "24px",
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
@@ -123,7 +180,6 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
type: "button",
|
||||
icon: OVERVIEW_SUMMARIES_ICONS.climate,
|
||||
name: "Climate",
|
||||
icon_height: "30px",
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
@@ -137,7 +193,6 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
type: "button",
|
||||
icon: OVERVIEW_SUMMARIES_ICONS.security,
|
||||
name: "Security",
|
||||
icon_height: "30px",
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
@@ -151,7 +206,6 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
type: "button",
|
||||
icon: OVERVIEW_SUMMARIES_ICONS.media_players,
|
||||
name: "Media Players",
|
||||
icon_height: "30px",
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
@@ -165,7 +219,6 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
type: "button",
|
||||
icon: "mdi:lightning-bolt",
|
||||
name: "Energy",
|
||||
icon_height: "30px",
|
||||
grid_options: {
|
||||
rows: 2,
|
||||
columns: 4,
|
||||
@@ -181,7 +234,7 @@ export class OverviewHomeViewStrategy extends ReactiveElement {
|
||||
const sections = [
|
||||
...(favoriteSection.cards ? [favoriteSection] : []),
|
||||
summarySection,
|
||||
areasSection,
|
||||
...floorsSections,
|
||||
];
|
||||
return {
|
||||
type: "sections",
|
||||
|
@@ -3,7 +3,6 @@ import { customElement } from "lit/decorators";
|
||||
import { generateEntityFilter } from "../../../../common/entity/entity_filter";
|
||||
import { clamp } from "../../../../common/number/clamp";
|
||||
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 { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
@@ -12,11 +11,11 @@ import {
|
||||
getAreas,
|
||||
getFloors,
|
||||
} from "../areas/helpers/areas-strategy-helper";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
import {
|
||||
findEntities,
|
||||
OVERVIEW_SUMMARIES_FILTERS,
|
||||
} from "./helpers/overview-summaries";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
|
||||
export interface OverviewLightsViewStrategyConfig {
|
||||
type: "overview-lights";
|
||||
@@ -25,9 +24,10 @@ export interface OverviewLightsViewStrategyConfig {
|
||||
const processAreasForLights = (
|
||||
areaIds: string[],
|
||||
hass: HomeAssistant,
|
||||
entities: string[]
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
entities: string[],
|
||||
computeTileCard: (entityId: string) => any
|
||||
): any[] => {
|
||||
const cards: any[] = [];
|
||||
|
||||
for (const areaId of areaIds) {
|
||||
const area = hass.areas[areaId];
|
||||
@@ -38,8 +38,6 @@ const processAreasForLights = (
|
||||
});
|
||||
const areaLights = entities.filter(areaFilter);
|
||||
|
||||
const computeTileCard = computeAreaTileCardConfig(hass, "", false);
|
||||
|
||||
if (areaLights.length > 0) {
|
||||
cards.push({
|
||||
heading_style: "subtitle",
|
||||
@@ -83,6 +81,8 @@ export class OverviewLightsViewStrategy extends ReactiveElement {
|
||||
|
||||
const floorCount = home.floors.length + (home.areas.length ? 1 : 0);
|
||||
|
||||
const computeTileCard = computeAreaTileCardConfig(hass, "", true);
|
||||
|
||||
// Process floors
|
||||
for (const floorStructure of home.floors) {
|
||||
const floorId = floorStructure.id;
|
||||
@@ -100,7 +100,12 @@ export class OverviewLightsViewStrategy extends ReactiveElement {
|
||||
],
|
||||
};
|
||||
|
||||
const areaCards = processAreasForLights(areaIds, hass, entities);
|
||||
const areaCards = processAreasForLights(
|
||||
areaIds,
|
||||
hass,
|
||||
entities,
|
||||
computeTileCard
|
||||
);
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
section.cards!.push(...areaCards);
|
||||
@@ -121,7 +126,12 @@ export class OverviewLightsViewStrategy extends ReactiveElement {
|
||||
],
|
||||
};
|
||||
|
||||
const areaCards = processAreasForLights(home.areas, hass, entities);
|
||||
const areaCards = processAreasForLights(
|
||||
home.areas,
|
||||
hass,
|
||||
entities,
|
||||
computeTileCard
|
||||
);
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
section.cards!.push(...areaCards);
|
||||
|
@@ -3,17 +3,16 @@ import { customElement } from "lit/decorators";
|
||||
import { generateEntityFilter } from "../../../../common/entity/entity_filter";
|
||||
import { clamp } from "../../../../common/number/clamp";
|
||||
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 { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { MediaControlCardConfig } from "../../cards/types";
|
||||
import { getAreas, getFloors } from "../areas/helpers/areas-strategy-helper";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
import {
|
||||
findEntities,
|
||||
OVERVIEW_SUMMARIES_FILTERS,
|
||||
} from "./helpers/overview-summaries";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
|
||||
export interface OvervieMediaPlayersViewStrategyConfig {
|
||||
type: "overview-media-players";
|
||||
@@ -23,8 +22,8 @@ const processAreasForMediaPlayers = (
|
||||
areaIds: string[],
|
||||
hass: HomeAssistant,
|
||||
entities: string[]
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
): any[] => {
|
||||
const cards: any[] = [];
|
||||
|
||||
for (const areaId of areaIds) {
|
||||
const area = hass.areas[areaId];
|
||||
|
@@ -16,7 +16,6 @@ import {
|
||||
OVERVIEW_SUMMARIES_FILTERS,
|
||||
} from "./helpers/overview-summaries";
|
||||
import { getHomeStructure } from "./helpers/overview-home-structure";
|
||||
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||
|
||||
export interface OverviewSecurityViewStrategyConfig {
|
||||
type: "overview-security";
|
||||
@@ -25,9 +24,10 @@ export interface OverviewSecurityViewStrategyConfig {
|
||||
const processAreasForSecurity = (
|
||||
areaIds: string[],
|
||||
hass: HomeAssistant,
|
||||
entities: string[]
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
entities: string[],
|
||||
computeTileCard: (entityId: string) => any
|
||||
): any[] => {
|
||||
const cards: any[] = [];
|
||||
|
||||
for (const areaId of areaIds) {
|
||||
const area = hass.areas[areaId];
|
||||
@@ -38,8 +38,6 @@ const processAreasForSecurity = (
|
||||
});
|
||||
const areaEntities = entities.filter(areaFilter);
|
||||
|
||||
const computeTileCard = computeAreaTileCardConfig(hass, "", true);
|
||||
|
||||
if (areaEntities.length > 0) {
|
||||
cards.push({
|
||||
heading_style: "subtitle",
|
||||
@@ -83,6 +81,8 @@ export class OverviewSecurityViewStrategy extends ReactiveElement {
|
||||
|
||||
const floorCount = home.floors.length + (home.areas.length ? 1 : 0);
|
||||
|
||||
const computeTileCard = computeAreaTileCardConfig(hass, "", true);
|
||||
|
||||
// Process floors
|
||||
for (const floorStructure of home.floors) {
|
||||
const floorId = floorStructure.id;
|
||||
@@ -100,7 +100,12 @@ export class OverviewSecurityViewStrategy extends ReactiveElement {
|
||||
],
|
||||
};
|
||||
|
||||
const areaCards = processAreasForSecurity(areaIds, hass, entities);
|
||||
const areaCards = processAreasForSecurity(
|
||||
areaIds,
|
||||
hass,
|
||||
entities,
|
||||
computeTileCard
|
||||
);
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
section.cards!.push(...areaCards);
|
||||
@@ -121,7 +126,12 @@ export class OverviewSecurityViewStrategy extends ReactiveElement {
|
||||
],
|
||||
};
|
||||
|
||||
const areaCards = processAreasForSecurity(home.areas, hass, entities);
|
||||
const areaCards = processAreasForSecurity(
|
||||
home.areas,
|
||||
hass,
|
||||
entities,
|
||||
computeTileCard
|
||||
);
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
section.cards!.push(...areaCards);
|
||||
|
@@ -379,7 +379,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
const index = ev.currentTarget.index;
|
||||
|
||||
showEditSectionDialog(this, {
|
||||
lovelace: this.lovelace!,
|
||||
lovelaceConfig: this.lovelace!.config,
|
||||
saveConfig: (newConfig) => {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
|
@@ -8,6 +8,10 @@ export const waMainStyles = css`
|
||||
--wa-focus-ring-offset: 2px;
|
||||
--wa-focus-ring: var(--wa-focus-ring-style) var(--wa-focus-ring-width)
|
||||
var(--wa-focus-ring-color);
|
||||
|
||||
--wa-space-l: 24px;
|
||||
--wa-shadow-l: 0 8px 8px -4px rgba(0, 0, 0, 0.2);
|
||||
--wa-form-control-padding-block: 0.75em;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@@ -7,21 +7,11 @@ import {
|
||||
import type { Constructor } from "../types";
|
||||
import type { HassBaseEl } from "./hass-base-mixin";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
/**
|
||||
* Dispatched to open the automation editor.
|
||||
* Used by custom cards/panels to trigger the editor view.
|
||||
*/
|
||||
"hass-automation-editor": ShowAutomationEditorParams;
|
||||
}
|
||||
}
|
||||
|
||||
export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
class extends superClass {
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
this.addEventListener("hass-automation-editor", (ev) =>
|
||||
this.addEventListener("show-automation-editor", (ev) =>
|
||||
this._handleShowAutomationEditor(
|
||||
ev as HASSDomEvent<ShowAutomationEditorParams>
|
||||
)
|
||||
|
@@ -413,7 +413,6 @@
|
||||
"add": "Add",
|
||||
"create": "Create",
|
||||
"edit": "Edit",
|
||||
"edit_item": "Edit {name}",
|
||||
"submit": "Submit",
|
||||
"rename": "Rename",
|
||||
"search": "[%key:ui::components::data-table::search%]",
|
||||
@@ -440,8 +439,7 @@
|
||||
"replace": "Replace",
|
||||
"append": "Append",
|
||||
"supports_markdown": "Supports {markdown_help_link}",
|
||||
"markdown": "Markdown",
|
||||
"none": "None"
|
||||
"markdown": "Markdown"
|
||||
},
|
||||
"components": {
|
||||
"selectors": {
|
||||
@@ -5339,6 +5337,8 @@
|
||||
"introduction": "Zones allow you to specify certain regions on Earth. When a person is within a zone, the state will take the name from the zone. Zones can also be used as a trigger or condition inside automation setups.",
|
||||
"no_zones_created_yet": "Looks like you have not created any zones yet.",
|
||||
"create_zone": "Create zone",
|
||||
"edit_zone": "Edit zone",
|
||||
"edit_home": "Edit home",
|
||||
"confirm_delete": "Are you sure you want to delete this zone?",
|
||||
"can_not_edit": "Unable to edit zone",
|
||||
"configured_in_yaml": "Zones configured via configuration.yaml cannot be edited via the UI.",
|
||||
@@ -6968,16 +6968,7 @@
|
||||
"assist_tooltip": "Assist",
|
||||
"reload_resources": "Reload resources",
|
||||
"exit_edit_mode": "Done",
|
||||
"close": "Close",
|
||||
"add": "Add to Home Assistant",
|
||||
"add_device": "Add device",
|
||||
"create_automation": "Create automation",
|
||||
"add_area": "Add area",
|
||||
"add_area_success": "Area added",
|
||||
"add_area_action": "View area",
|
||||
"add_person_success": "Person added",
|
||||
"add_person_action": "View persons",
|
||||
"invite_person": "Invite person"
|
||||
"close": "Close"
|
||||
},
|
||||
"reload_resources": {
|
||||
"refresh_header": "Do you want to refresh?",
|
||||
@@ -7104,8 +7095,7 @@
|
||||
"error_same_url": "You cannot save a view with the same URL as a different existing view.",
|
||||
"error_invalid_path": "URL contains invalid/reserved characters. Please enter a simple string only for the path of this view.",
|
||||
"error_number": "URL may not be a number.",
|
||||
"move_to_dashboard": "Move to dashboard",
|
||||
"move_to_view": "Move to view"
|
||||
"move_to_dashboard": "Move to dashboard"
|
||||
},
|
||||
"edit_view_header": {
|
||||
"add_title": "Add title",
|
||||
@@ -7211,13 +7201,6 @@
|
||||
"header": "[%key:ui::panel::lovelace::editor::suggest_card::header%]",
|
||||
"add": "[%key:ui::panel::lovelace::editor::suggest_card::add%]"
|
||||
},
|
||||
"move_section": {
|
||||
"header": "Choose a view to move the section to",
|
||||
"strategy_error_title": "Impossible to move the section",
|
||||
"strategy_error_text_strategy": "Moving a section to an auto-generated view is not supported.",
|
||||
"success": "Section moved successfully",
|
||||
"error": "Error while moving section"
|
||||
},
|
||||
"move_card": {
|
||||
"header": "Choose a view to move the card to",
|
||||
"strategy_error_title": "Impossible to move the card",
|
||||
@@ -7266,13 +7249,7 @@
|
||||
"edit_yaml": "[%key:ui::panel::lovelace::editor::edit_view::edit_yaml%]",
|
||||
"settings": {
|
||||
"column_span": "Width",
|
||||
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)",
|
||||
"styling": "Styling",
|
||||
"background_type": "Background type",
|
||||
"background_type_none_option": "None",
|
||||
"background_type_color_option": "Color",
|
||||
"background_color": "Background color",
|
||||
"background_opacity": "Background opacity"
|
||||
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)"
|
||||
},
|
||||
"visibility": {
|
||||
"explanation": "The section will be shown when ALL conditions below are fulfilled. If no conditions are set, the section will always be shown."
|
||||
@@ -7386,11 +7363,6 @@
|
||||
"sensor_classes": "Sensor classes",
|
||||
"description": "The Area card automatically displays entities of a specific area.",
|
||||
"display_type": "Display type",
|
||||
"content_layout": "[%key:ui::panel::lovelace::editor::card::tile::content_layout%]",
|
||||
"content_layout_options": {
|
||||
"horizontal": "[%key:ui::panel::lovelace::editor::card::tile::content_layout_options::horizontal%]",
|
||||
"vertical": "[%key:ui::panel::lovelace::editor::card::tile::content_layout_options::vertical%]"
|
||||
},
|
||||
"display_type_options": {
|
||||
"compact": "Compact",
|
||||
"icon": "Area icon",
|
||||
@@ -7933,9 +7905,6 @@
|
||||
"lock-open-door": {
|
||||
"label": "Lock open door"
|
||||
},
|
||||
"media-player-playback": {
|
||||
"label": "Media player playback controls"
|
||||
},
|
||||
"media-player-volume-slider": {
|
||||
"label": "Media player volume slider"
|
||||
},
|
||||
|
253
yarn.lock
253
yarn.lock
@@ -3869,22 +3869,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/client@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/client@npm:1.2.3"
|
||||
checksum: 10/4e02c72ded9f7cfa5dc9e224513d4f0cb4d36908fbd62353170148516ad742cd4c9573e2ee90b335d243f8c56f33b2bbd0cc51a3b65000f1a166c2b4c8dd9bd7
|
||||
"@rsdoctor/client@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/client@npm:1.2.2"
|
||||
checksum: 10/ae2e8dbbf17522c63ab1042391514706116cce73e9435293c1cced593bcacc5034b85cb7b0bcc09cf36d6350ff21680cc4e14d08728a95d98119db07c163f2d4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/core@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/core@npm:1.2.3"
|
||||
"@rsdoctor/core@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/core@npm:1.2.2"
|
||||
dependencies:
|
||||
"@rsbuild/plugin-check-syntax": "npm:1.3.0"
|
||||
"@rsdoctor/graph": "npm:1.2.3"
|
||||
"@rsdoctor/sdk": "npm:1.2.3"
|
||||
"@rsdoctor/types": "npm:1.2.3"
|
||||
"@rsdoctor/utils": "npm:1.2.3"
|
||||
"@rsdoctor/graph": "npm:1.2.2"
|
||||
"@rsdoctor/sdk": "npm:1.2.2"
|
||||
"@rsdoctor/types": "npm:1.2.2"
|
||||
"@rsdoctor/utils": "npm:1.2.2"
|
||||
axios: "npm:^1.11.0"
|
||||
browserslist-load-config: "npm:^1.0.0"
|
||||
enhanced-resolve: "npm:5.12.0"
|
||||
@@ -3894,67 +3894,70 @@ __metadata:
|
||||
path-browserify: "npm:1.0.1"
|
||||
semver: "npm:^7.7.2"
|
||||
source-map: "npm:^0.7.4"
|
||||
checksum: 10/45c39b966fb879f8770ced60d47d16b42098fc6642064bc528c6b1a9cd0724210b0af5f17f031ae9738884c75b034ea402f34f3d2737e608ce3ebef08fb6909c
|
||||
source-map-js: "npm:^1.2.1"
|
||||
checksum: 10/85fe4ef72d1ca7223a6df638ae7b8ca491665d2df37b115dc229569b3a6fe9b6855f7895e4975c48f3a8056ccc66e4cc941c1b2c5c58f3bb7c1061434e24983a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/graph@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/graph@npm:1.2.3"
|
||||
"@rsdoctor/graph@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/graph@npm:1.2.2"
|
||||
dependencies:
|
||||
"@rsdoctor/types": "npm:1.2.3"
|
||||
"@rsdoctor/utils": "npm:1.2.3"
|
||||
"@rsdoctor/types": "npm:1.2.2"
|
||||
"@rsdoctor/utils": "npm:1.2.2"
|
||||
lodash.unionby: "npm:^4.8.0"
|
||||
socket.io: "npm:4.8.1"
|
||||
source-map: "npm:^0.7.4"
|
||||
checksum: 10/fea12dfdad880f440ea2c3a06c95a92dcbcd78efac6ff03af50c56e40007239b63303ae267ca00e1360e2af559513173cdd0743c7635721cb8ac16e19cda170d
|
||||
checksum: 10/e17b30fb96e8fb5f9344fe08edcfc7a8a37dd4d8e111cbd1fe5ee0f5748143beb1c77a98d90b9fa1a50eb636c8a427e35560a548ec8a55cacea8ec79a58d3852
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/rspack-plugin@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/rspack-plugin@npm:1.2.3"
|
||||
"@rsdoctor/rspack-plugin@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/rspack-plugin@npm:1.2.2"
|
||||
dependencies:
|
||||
"@rsdoctor/core": "npm:1.2.3"
|
||||
"@rsdoctor/graph": "npm:1.2.3"
|
||||
"@rsdoctor/sdk": "npm:1.2.3"
|
||||
"@rsdoctor/types": "npm:1.2.3"
|
||||
"@rsdoctor/utils": "npm:1.2.3"
|
||||
"@rsdoctor/core": "npm:1.2.2"
|
||||
"@rsdoctor/graph": "npm:1.2.2"
|
||||
"@rsdoctor/sdk": "npm:1.2.2"
|
||||
"@rsdoctor/types": "npm:1.2.2"
|
||||
"@rsdoctor/utils": "npm:1.2.2"
|
||||
lodash: "npm:^4.17.21"
|
||||
peerDependencies:
|
||||
"@rspack/core": "*"
|
||||
peerDependenciesMeta:
|
||||
"@rspack/core":
|
||||
optional: true
|
||||
checksum: 10/59abb902046fb791a754e02b0eff5e1674417cfc3f6556d164fc6bed0af0eb0aa52bc087c0b0e8d1c42659d4cbaffd497550376799cbedbae4f4f76882b26924
|
||||
checksum: 10/040cd21f9c9382edbbea6b1e9b9c621956a8a56271321a7de55fff138ab49f3eb75e1dd26414487bca7d2034c975ecc9ecb1b394b1466c97f6592721ae76fb4e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/sdk@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/sdk@npm:1.2.3"
|
||||
"@rsdoctor/sdk@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/sdk@npm:1.2.2"
|
||||
dependencies:
|
||||
"@rsdoctor/client": "npm:1.2.3"
|
||||
"@rsdoctor/graph": "npm:1.2.3"
|
||||
"@rsdoctor/types": "npm:1.2.3"
|
||||
"@rsdoctor/utils": "npm:1.2.3"
|
||||
"@rsdoctor/client": "npm:1.2.2"
|
||||
"@rsdoctor/graph": "npm:1.2.2"
|
||||
"@rsdoctor/types": "npm:1.2.2"
|
||||
"@rsdoctor/utils": "npm:1.2.2"
|
||||
"@types/fs-extra": "npm:^11.0.4"
|
||||
body-parser: "npm:1.20.3"
|
||||
cors: "npm:2.8.5"
|
||||
dayjs: "npm:1.11.13"
|
||||
fs-extra: "npm:^11.1.1"
|
||||
json-cycle: "npm:^1.5.0"
|
||||
lodash: "npm:^4.17.21"
|
||||
open: "npm:^8.4.2"
|
||||
sirv: "npm:2.0.4"
|
||||
socket.io: "npm:4.8.1"
|
||||
source-map: "npm:^0.7.4"
|
||||
tapable: "npm:2.2.2"
|
||||
checksum: 10/3d39ff6a4cd074080b517a6daccf480d88b4f75bd0148748b64f5bd074a05e30a1de74c526d1d6e764a7b7763abc83e53e9ac717eb09cf786eb721b411609a5c
|
||||
checksum: 10/15aa9298c01747dce5732698ec646b7db54df3a7753db417b14c2eaaaf55c769080334db07598039d0dda97017f7c127277ca69531de4756c24e8c8049486262
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/types@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/types@npm:1.2.3"
|
||||
"@rsdoctor/types@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/types@npm:1.2.2"
|
||||
dependencies:
|
||||
"@types/connect": "npm:3.4.38"
|
||||
"@types/estree": "npm:1.0.5"
|
||||
@@ -3968,16 +3971,16 @@ __metadata:
|
||||
optional: true
|
||||
webpack:
|
||||
optional: true
|
||||
checksum: 10/e2971d683ee0b138387e383f7d171c573e97ad2b91a906dc7a2e091a3b17cf83a4d5c921f69de6929d408c1c87cc9b2b409235ad5b02d7b8a15506137b04e568
|
||||
checksum: 10/67d340e25fcc060eacff632ac5c5556df646f91853d423776ae3a1ee677e2a6a14a17e5838e6e9487256646efbabb168ca96acfb27f4a4d147f4a3fdd0f31ef4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rsdoctor/utils@npm:1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@rsdoctor/utils@npm:1.2.3"
|
||||
"@rsdoctor/utils@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@rsdoctor/utils@npm:1.2.2"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:7.26.2"
|
||||
"@rsdoctor/types": "npm:1.2.3"
|
||||
"@rsdoctor/types": "npm:1.2.2"
|
||||
"@types/estree": "npm:1.0.5"
|
||||
acorn: "npm:^8.10.0"
|
||||
acorn-import-attributes: "npm:^1.9.5"
|
||||
@@ -3993,7 +3996,7 @@ __metadata:
|
||||
picocolors: "npm:^1.1.1"
|
||||
rslog: "npm:^1.2.9"
|
||||
strip-ansi: "npm:^6.0.1"
|
||||
checksum: 10/4e6bcce13fd81872766e18eea97439d9bd117b2aba275e2a5a9ff7ec4d65c3ad44b8535ee3adcec70d16969865f4a53144dc692af6f66aaacedd656f63b2da57
|
||||
checksum: 10/7290b2239a3bba1207171b4942c3598ac19ced09667cf6ca682af2e96b3e578b6611a36861f68a186a74e2a983087c1b3436bf5dbfdd0edbc43d5042c6a08d1e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4991,67 +4994,76 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.40.0"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.39.1"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.10.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.40.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.40.0"
|
||||
"@typescript-eslint/utils": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.39.1"
|
||||
"@typescript-eslint/type-utils": "npm:8.39.1"
|
||||
"@typescript-eslint/utils": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
graphemer: "npm:^1.4.0"
|
||||
ignore: "npm:^7.0.0"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.40.0
|
||||
"@typescript-eslint/parser": ^8.39.1
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/9df4d4ac58734a34964b791622dcb94ffc6c49c1d0f4fd0480b3fc0e026527df7167ff78a4f8bbd29089d605756c28c1a90b2f0653df34b40ac8b969bc6c92e9
|
||||
checksum: 10/446050aa43d54c0107c7c927ae1f68a4384c2bba514d5c22edabbe355426cb37bd5bb5a3faf240a6be8ef06f68de6099c2a53d9cbb1849ed35a152fb156171e2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.40.0"
|
||||
"@typescript-eslint/parser@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/parser@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/1e60f70e9d02f930553db7f4684c27c376fadf345db155414a22d1a32cd21def7d36496bd63c1acbf3afbec9fb8794947e880f88c1143b83e1d3c45146cec41a
|
||||
checksum: 10/ff45ce76353ed564e0f9db47b02b4b20895c96182b3693c610ef3dbceda373c476037a99f90d9f28633c192f301e5d554c89e1ba72da216763f960648ddf1f34
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/project-service@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.40.0"
|
||||
"@typescript-eslint/project-service@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/project-service@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.40.0"
|
||||
"@typescript-eslint/types": "npm:^8.40.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.39.1"
|
||||
"@typescript-eslint/types": "npm:^8.39.1"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/86491aa65c1dd78c9784dddd8467601aef8be652c5fb3a901e8b1995cf07c1dbe11d0ab4610d770e3f4063c0c254a6c6aa5fb7cf724bf12fa4ee56f47f3a2955
|
||||
checksum: 10/1970633d1a338190f0125e186beaa39b3ef912f287e4815934faf64b72f140e87fdf7d861962683635a450d270dd76faf0c865d72bfd57b471a36739f943676b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.40.0"
|
||||
"@typescript-eslint/scope-manager@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
checksum: 10/0c5aa10208bfbb506bf3925a420c3de667298064bde400f03ee52c19cd0785dd05c2c820e05724d005737e2920d925aff0318ec3308156f9b81c84736a1fe46b
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
checksum: 10/8874f7479043b3fc878f2c04b2c565051deceb7e425a8e4e79a7f40f1ee696bb979bd91fff619e016fe6793f537b30609c0ee8a5c40911c4829fa264863f7a70
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.40.0, @typescript-eslint/tsconfig-utils@npm:^8.40.0":
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.39.1"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/38c1e1982504e606e525ad0ce47fdb4c7acc686a28a94c2b30fe988c439977e991ce69cb88a1724a41a8096fc2d18d7ced7fe8725e42879d841515ff36a37ecf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:^8.39.1":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.40.0"
|
||||
peerDependencies:
|
||||
@@ -5060,37 +5072,44 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.40.0"
|
||||
"@typescript-eslint/type-utils@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/utils": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/utils": "npm:8.39.1"
|
||||
debug: "npm:^4.3.4"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/296c718330b2ac4408840258c30c01072de01ffe1c009be00c5049be1b19a71cbb2e258363ae349150760bcd2d34799df305b4cfc4d7f3b2fa9760ac8ffb3f75
|
||||
checksum: 10/1195d65970f79f820558810f7e1edf0ea360bbeee55841fdbb71b5b40c09f1a65741b67a70b85c2834ae1f9a027b82da4234d01f42ab4e85dceef3eea84bfdaa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.40.0, @typescript-eslint/types@npm:^8.40.0":
|
||||
"@typescript-eslint/types@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/types@npm:8.39.1"
|
||||
checksum: 10/8013f4f48a98da0de270d5fef1ff28b35407de82fce5acf3efa212fce60bc92a81bbb15b4b358d9facf4f161e49feec856fbf1a6d96f5027d013b542f2fe1bcc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:^8.39.1":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/types@npm:8.40.0"
|
||||
checksum: 10/f3931d0920a42b3bc69e9cdeb67a0c710597271cdd9d7c736302bdc52d21df1c962082df7cd712eeabd2c47658415d0a4b7d72f819cb38f82f4e234b48dbaa57
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service": "npm:8.40.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
"@typescript-eslint/project-service": "npm:8.39.1"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
debug: "npm:^4.3.4"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
is-glob: "npm:^4.0.3"
|
||||
@@ -5099,32 +5118,32 @@ __metadata:
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/2e61ecfecb933f644799a7c11e4c7a730df57290c8d0482082cff7739b2401b0cf3b1ebef7b08a54a90285978957a49850d1a53061e8770164da651172ebee32
|
||||
checksum: 10/07ed9d7ab4d146ee3ce6cf82ffebf947e045a9289b01522e11b3985b64f590c00cac0ca10366df828ca213bf08216a67c7b2b76e7c8be650df2511a7e6385425
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.40.0"
|
||||
"@typescript-eslint/utils@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/utils@npm:8.39.1"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.7.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/b4cd1e6a4f55cc6475189de12e6bd418080a227e794745a2af304ab21655b031c28dae6387d4e9b54dd2f420696cec4f77cca9c66db405ed2281e0e09c95ba1c
|
||||
checksum: 10/39bb105f26aa1ba234ad7d284c277cbd66df9d51e245094892db140aac80d3656d0480f133b2db54e87af3ef9c371a12973120c9cfbff71e8e85865f9e1d0077
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
eslint-visitor-keys: "npm:^4.2.1"
|
||||
checksum: 10/191f47998001a5e9cdde7491b0215d9c6c45c637aedd7d32cafd35ce2a4a0f4b8582edab015e09238f48e025a788b99efd8e70e4e3200e32143f91c95112abcd
|
||||
checksum: 10/6d4e4d0b19ebb3f21b692bbb0dcf9961876ca28cdf502296888a78eb4cd802a2ec8d3d5721d19970411edfd1c06f3e272e4057014c859ee1f0546804d07945e3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -8138,16 +8157,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-unused-imports@npm:4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "eslint-plugin-unused-imports@npm:4.2.0"
|
||||
"eslint-plugin-unused-imports@npm:4.1.4":
|
||||
version: 4.1.4
|
||||
resolution: "eslint-plugin-unused-imports@npm:4.1.4"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/eslint-plugin": ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0
|
||||
eslint: ^9.0.0 || ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
"@typescript-eslint/eslint-plugin":
|
||||
optional: true
|
||||
checksum: 10/99285bd61a46ad5eaacd54525c04564feed3529dc2ae7800c736b7f4f011daa370133adb481677ad840f020681c0f409f3edfe3bc8f9f234c42bf4674bc4b576
|
||||
checksum: 10/8e987028ad925ce1e04c01dcae70adbf44c2878a8b15c4327b33a2861e471d7fe00f6fe213fbd2b936f3fcefc8ccabb0d778aa1d6e0e0387a3dc7fe150cd4ed4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9440,7 +9459,7 @@ __metadata:
|
||||
"@octokit/plugin-retry": "npm:8.0.1"
|
||||
"@octokit/rest": "npm:22.0.0"
|
||||
"@replit/codemirror-indentation-markers": "npm:6.5.3"
|
||||
"@rsdoctor/rspack-plugin": "npm:1.2.3"
|
||||
"@rsdoctor/rspack-plugin": "npm:1.2.2"
|
||||
"@rspack/cli": "npm:1.4.11"
|
||||
"@rspack/core": "npm:1.4.11"
|
||||
"@shoelace-style/shoelace": "npm:2.20.1"
|
||||
@@ -9498,7 +9517,7 @@ __metadata:
|
||||
eslint-plugin-import: "npm:2.32.0"
|
||||
eslint-plugin-lit: "npm:2.1.1"
|
||||
eslint-plugin-lit-a11y: "npm:5.1.1"
|
||||
eslint-plugin-unused-imports: "npm:4.2.0"
|
||||
eslint-plugin-unused-imports: "npm:4.1.4"
|
||||
eslint-plugin-wc: "npm:3.0.1"
|
||||
fancy-log: "npm:2.0.0"
|
||||
fs-extra: "npm:11.3.1"
|
||||
@@ -9552,7 +9571,7 @@ __metadata:
|
||||
tinykeys: "npm:3.0.0"
|
||||
ts-lit-plugin: "npm:2.0.2"
|
||||
typescript: "npm:5.9.2"
|
||||
typescript-eslint: "npm:8.40.0"
|
||||
typescript-eslint: "npm:8.39.1"
|
||||
ua-parser-js: "npm:2.0.4"
|
||||
vite-tsconfig-paths: "npm:5.1.4"
|
||||
vitest: "npm:3.2.4"
|
||||
@@ -14600,18 +14619,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "typescript-eslint@npm:8.40.0"
|
||||
"typescript-eslint@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "typescript-eslint@npm:8.39.1"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.40.0"
|
||||
"@typescript-eslint/parser": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/utils": "npm:8.40.0"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.39.1"
|
||||
"@typescript-eslint/parser": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/utils": "npm:8.39.1"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/b96dc4e70bd551e5399b928e946957cce622cba89f0ff87521f9e93f223acbe406930a1ebee845b158f586959cb7d85f15ea2250b97341aa87f50a3c987d068a
|
||||
checksum: 10/1c29c18f2e93b8b74d019590196b158006d7c65be87a56a4c953e52a9c4c40280a42f8ff1464fea870b3a1a4d54925b5cb7d54b4dc86b23cdf65a9b7787585b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Reference in New Issue
Block a user