mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-24 18:27:19 +00:00
Compare commits
6 Commits
reusable-f
...
renovate/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc12981581 | ||
|
|
4674384f7d | ||
|
|
2e7c95a8cc | ||
|
|
9630b175a1 | ||
|
|
be319503f7 | ||
|
|
9b1fe28018 |
@@ -11,7 +11,7 @@ A compact, accessible dropdown menu for choosing actions or settings. `ha-dropdo
|
||||
### Example usage (composition)
|
||||
|
||||
```html
|
||||
<ha-dropdown open>
|
||||
<ha-dropdown>
|
||||
<ha-button slot="trigger" with-caret>Dropdown</ha-button>
|
||||
|
||||
<ha-dropdown-item>
|
||||
|
||||
@@ -28,7 +28,7 @@ export class DemoHaDropdown extends LitElement {
|
||||
<div class=${mode}>
|
||||
<ha-card header="ha-button in ${mode}">
|
||||
<div class="card-content">
|
||||
<ha-dropdown open>
|
||||
<ha-dropdown>
|
||||
<ha-button slot="trigger" with-caret>Dropdown</ha-button>
|
||||
|
||||
<ha-dropdown-item>
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.4",
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@codemirror/autocomplete": "6.19.1",
|
||||
"@codemirror/autocomplete": "6.20.0",
|
||||
"@codemirror/commands": "6.10.0",
|
||||
"@codemirror/language": "6.11.3",
|
||||
"@codemirror/legacy-modes": "6.5.2",
|
||||
"@codemirror/search": "6.5.11",
|
||||
"@codemirror/state": "6.5.2",
|
||||
"@codemirror/view": "6.38.6",
|
||||
"@codemirror/view": "6.38.8",
|
||||
"@date-fns/tz": "1.4.1",
|
||||
"@egjs/hammerjs": "2.0.17",
|
||||
"@formatjs/intl-datetimeformat": "6.18.2",
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Connection } from "home-assistant-js-websocket";
|
||||
export interface CoreFrontendUserData {
|
||||
showAdvanced?: boolean;
|
||||
showEntityIdPicker?: boolean;
|
||||
defaultPanel?: string;
|
||||
default_panel?: string;
|
||||
}
|
||||
|
||||
export interface SidebarFrontendUserData {
|
||||
@@ -12,7 +12,7 @@ export interface SidebarFrontendUserData {
|
||||
}
|
||||
|
||||
export interface CoreFrontendSystemData {
|
||||
defaultPanel?: string;
|
||||
default_panel?: string;
|
||||
}
|
||||
|
||||
export interface HomeFrontendSystemData {
|
||||
|
||||
@@ -9,8 +9,8 @@ export const getLegacyDefaultPanelUrlPath = (): string | null => {
|
||||
};
|
||||
|
||||
export const getDefaultPanelUrlPath = (hass: HomeAssistant): string =>
|
||||
hass.userData?.defaultPanel ||
|
||||
hass.systemData?.defaultPanel ||
|
||||
hass.userData?.default_panel ||
|
||||
hass.systemData?.default_panel ||
|
||||
getLegacyDefaultPanelUrlPath() ||
|
||||
DEFAULT_PANEL;
|
||||
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { css, html } from "lit";
|
||||
import type {
|
||||
CSSResultGroup,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { state } from "lit/decorators";
|
||||
import type { Constructor } from "../types";
|
||||
|
||||
const stylesArray = (styles?: CSSResultGroup | CSSResultGroup[]) =>
|
||||
styles === undefined ? [] : Array.isArray(styles) ? styles : [styles];
|
||||
|
||||
export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
|
||||
superClass: T
|
||||
) => {
|
||||
class ScrollableFadeClass extends superClass {
|
||||
@state() protected _contentScrolled = false;
|
||||
|
||||
@state() protected _contentScrollable = false;
|
||||
|
||||
private _scrollTarget?: HTMLElement | null;
|
||||
|
||||
private _onScroll = (ev: Event) => {
|
||||
const target = ev.currentTarget as HTMLElement;
|
||||
this._contentScrolled = (target.scrollTop ?? 0) > 0;
|
||||
this._updateScrollableState(target);
|
||||
};
|
||||
|
||||
private _resize = new ResizeController(this, {
|
||||
target: null,
|
||||
callback: (entries) => {
|
||||
const target = entries[0]?.target as HTMLElement | undefined;
|
||||
if (target) {
|
||||
this._updateScrollableState(target);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
private static readonly DEFAULT_SAFE_AREA_PADDING = 16;
|
||||
|
||||
private static readonly DEFAULT_SCROLLABLE_ELEMENT: HTMLElement | null =
|
||||
null;
|
||||
|
||||
protected get scrollFadeSafeAreaPadding() {
|
||||
return ScrollableFadeClass.DEFAULT_SAFE_AREA_PADDING;
|
||||
}
|
||||
|
||||
protected get scrollableElement(): HTMLElement | null {
|
||||
return ScrollableFadeClass.DEFAULT_SCROLLABLE_ELEMENT;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues) {
|
||||
super.firstUpdated?.(changedProperties);
|
||||
this._attachScrollableElement();
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues) {
|
||||
super.updated?.(changedProperties);
|
||||
this._attachScrollableElement();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this._detachScrollableElement();
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
protected renderScrollableFades(rounded = false): TemplateResult {
|
||||
return html`
|
||||
<div
|
||||
class=${classMap({
|
||||
"fade-top": true,
|
||||
rounded,
|
||||
visible: this._contentScrolled,
|
||||
})}
|
||||
></div>
|
||||
<div
|
||||
class=${classMap({
|
||||
"fade-bottom": true,
|
||||
rounded,
|
||||
visible: this._contentScrollable,
|
||||
})}
|
||||
></div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
const superCtor = Object.getPrototypeOf(this) as
|
||||
| typeof LitElement
|
||||
| undefined;
|
||||
const inheritedStyles = stylesArray(
|
||||
(superCtor?.styles ?? []) as CSSResultGroup | CSSResultGroup[]
|
||||
);
|
||||
return [
|
||||
...inheritedStyles,
|
||||
css`
|
||||
.fade-top,
|
||||
.fade-bottom {
|
||||
position: absolute;
|
||||
left: var(--ha-space-0);
|
||||
right: var(--ha-space-0);
|
||||
height: var(--ha-space-4);
|
||||
pointer-events: none;
|
||||
transition: opacity 180ms ease-in-out;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
var(--shadow-color),
|
||||
transparent
|
||||
);
|
||||
border-radius: var(--ha-border-radius-square);
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
}
|
||||
.fade-top {
|
||||
top: var(--ha-space-0);
|
||||
}
|
||||
.fade-bottom {
|
||||
bottom: var(--ha-space-0);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.fade-top.visible,
|
||||
.fade-bottom.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fade-top.rounded,
|
||||
.fade-bottom.rounded {
|
||||
border-radius: var(
|
||||
--ha-card-border-radius,
|
||||
var(--ha-border-radius-lg)
|
||||
);
|
||||
border-bottom-left-radius: var(--ha-border-radius-square);
|
||||
border-bottom-right-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
.fade-top.rounded {
|
||||
border-top-left-radius: var(--ha-border-radius-square);
|
||||
border-top-right-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
.fade-bottom.rounded {
|
||||
border-bottom-left-radius: var(--ha-border-radius-square);
|
||||
border-bottom-right-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
private _attachScrollableElement() {
|
||||
const element = this.scrollableElement;
|
||||
if (element === this._scrollTarget) {
|
||||
return;
|
||||
}
|
||||
this._detachScrollableElement();
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
this._scrollTarget = element;
|
||||
element.addEventListener("scroll", this._onScroll, { passive: true });
|
||||
this._resize.observe(element);
|
||||
this._updateScrollableState(element);
|
||||
}
|
||||
|
||||
private _detachScrollableElement() {
|
||||
if (!this._scrollTarget) {
|
||||
return;
|
||||
}
|
||||
this._scrollTarget.removeEventListener("scroll", this._onScroll);
|
||||
this._resize.unobserve?.(this._scrollTarget);
|
||||
this._scrollTarget = undefined;
|
||||
}
|
||||
|
||||
private _updateScrollableState(element: HTMLElement) {
|
||||
const safeAreaInsetBottom =
|
||||
parseFloat(
|
||||
getComputedStyle(element).getPropertyValue("--safe-area-inset-bottom")
|
||||
) || 0;
|
||||
const { scrollHeight = 0, clientHeight = 0, scrollTop = 0 } = element;
|
||||
this._contentScrollable =
|
||||
scrollHeight - clientHeight >
|
||||
scrollTop + safeAreaInsetBottom + this.scrollFadeSafeAreaPadding;
|
||||
}
|
||||
}
|
||||
|
||||
return ScrollableFadeClass;
|
||||
};
|
||||
@@ -1,6 +1,14 @@
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { mdiClose, mdiDotsVertical } from "@mdi/js";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import {
|
||||
customElement,
|
||||
eventOptions,
|
||||
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";
|
||||
@@ -9,10 +17,8 @@ import "../../../../components/ha-dialog-header";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "../../../../components/ha-md-button-menu";
|
||||
import "../../../../components/ha-md-divider";
|
||||
import { haStyleScrollbar } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import "../ha-automation-editor-warning";
|
||||
import { ScrollableFadeMixin } from "../../../../mixins/scrollable-fade-mixin";
|
||||
|
||||
export interface SidebarOverflowMenuEntry {
|
||||
clickAction: () => void;
|
||||
@@ -25,9 +31,7 @@ export interface SidebarOverflowMenuEntry {
|
||||
export type SidebarOverflowMenu = (SidebarOverflowMenuEntry | "separator")[];
|
||||
|
||||
@customElement("ha-automation-sidebar-card")
|
||||
export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
|
||||
LitElement
|
||||
) {
|
||||
export default class HaAutomationSidebarCard extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean, attribute: "wide" }) public isWide = false;
|
||||
@@ -38,10 +42,23 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@state() private _contentScrolled = false;
|
||||
|
||||
@state() private _contentScrollable = false;
|
||||
|
||||
@query(".card-content") private _contentElement!: HTMLDivElement;
|
||||
|
||||
protected get scrollableElement(): HTMLElement | null {
|
||||
return this._contentElement;
|
||||
private _contentSize = new ResizeController(this, {
|
||||
target: null,
|
||||
callback: (entries) => {
|
||||
if (entries[0]?.target) {
|
||||
this._canScrollDown(entries[0].target);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
protected firstUpdated(_changedProperties: PropertyValues): void {
|
||||
this._contentSize.observe(this._contentElement);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
@@ -53,7 +70,9 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
|
||||
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")}
|
||||
@@ -88,14 +107,34 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
|
||||
>
|
||||
</ha-automation-editor-warning>`
|
||||
: nothing}
|
||||
<div class="card-content ha-scrollbar">
|
||||
<div class="card-content" @scroll=${this._onScroll}>
|
||||
<slot></slot>
|
||||
${this.renderScrollableFades(this.isWide)}
|
||||
</div>
|
||||
<div
|
||||
class=${classMap({ fade: true, scrollable: this._contentScrollable })}
|
||||
></div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
@eventOptions({ passive: true })
|
||||
private _onScroll(ev) {
|
||||
const top = ev.target.scrollTop ?? 0;
|
||||
this._contentScrolled = top > 0;
|
||||
|
||||
this._canScrollDown(ev.target);
|
||||
}
|
||||
|
||||
private _canScrollDown(element: HTMLElement) {
|
||||
const safeAreaInsetBottom =
|
||||
parseFloat(
|
||||
getComputedStyle(element).getPropertyValue("--safe-area-inset-bottom")
|
||||
) || 0;
|
||||
this._contentScrollable =
|
||||
(element.scrollHeight ?? 0) - (element.clientHeight ?? 0) >
|
||||
(element.scrollTop ?? 0) + safeAreaInsetBottom + 16;
|
||||
}
|
||||
|
||||
private _closeSidebar() {
|
||||
fireEvent(this, "close-sidebar");
|
||||
}
|
||||
@@ -105,63 +144,86 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
...super.styles,
|
||||
haStyleScrollbar,
|
||||
css`
|
||||
ha-card {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-color: var(--primary-color);
|
||||
border-width: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
static styles = css`
|
||||
ha-card {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-color: var(--primary-color);
|
||||
border-width: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
ha-card.mobile {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
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 {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
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);
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
position: relative;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
}
|
||||
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;
|
||||
position: relative;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
margin-top: 0;
|
||||
padding-bottom: max(var(--safe-area-inset-bottom, 0px), 32px);
|
||||
}
|
||||
ha-dialog-header.scrolled {
|
||||
box-shadow: var(--bar-box-shadow);
|
||||
}
|
||||
|
||||
.fade-top {
|
||||
top: var(--ha-space-17);
|
||||
}
|
||||
.fade {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
left: 1px;
|
||||
right: 1px;
|
||||
height: 16px;
|
||||
pointer-events: none;
|
||||
transition: box-shadow 180ms ease-in-out;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
transform: rotate(180deg);
|
||||
border-radius: var(--ha-card-border-radius);
|
||||
border-bottom-left-radius: var(--ha-border-radius-square);
|
||||
border-bottom-right-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
.card-content {
|
||||
padding-bottom: 42px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
.fade.scrollable {
|
||||
box-shadow: var(--bar-box-shadow);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
margin-top: 0;
|
||||
padding-bottom: max(var(--safe-area-inset-bottom, 0px), 32px);
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
.fade {
|
||||
bottom: 0;
|
||||
border-radius: var(--ha-border-radius-square);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding-bottom: 42px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
mdiCancel,
|
||||
mdiChevronRight,
|
||||
mdiCog,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiMenuDown,
|
||||
mdiPencilOff,
|
||||
@@ -109,10 +110,11 @@ import { configSections } from "../ha-panel-config";
|
||||
import "../integrations/ha-integration-overflow-menu";
|
||||
import { renderConfigEntryError } from "../integrations/ha-config-integration-page";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { isHelperDomain } from "./const";
|
||||
import { isHelperDomain, type HelperDomain } from "./const";
|
||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { HELPERS_CRUD } from "../../../data/helpers_crud";
|
||||
import {
|
||||
fetchDiagnosticHandlers,
|
||||
getConfigEntryDiagnosticsDownloadUrl,
|
||||
@@ -451,6 +453,19 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(helper.editable && helper.entity
|
||||
? [
|
||||
{
|
||||
divider: true,
|
||||
},
|
||||
{
|
||||
path: mdiDelete,
|
||||
label: this.hass.localize("ui.common.delete"),
|
||||
warning: true,
|
||||
action: () => this._deleteHelper(helper),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]}
|
||||
>
|
||||
</ha-icon-overflow-menu>
|
||||
@@ -1280,6 +1295,62 @@ ${rejected
|
||||
}
|
||||
}
|
||||
|
||||
private async _deleteHelper(helper: HelperItem) {
|
||||
if (!helper.entity_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.helpers.picker.delete_confirm_title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.helpers.picker.delete_confirm_text",
|
||||
{ name: helper.name }
|
||||
),
|
||||
confirmText: this.hass.localize("ui.common.delete"),
|
||||
dismissText: this.hass.localize("ui.common.cancel"),
|
||||
destructive: true,
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// For old-style helpers (input_boolean, etc.), use HELPERS_CRUD
|
||||
if (isHelperDomain(helper.type)) {
|
||||
const entityReg = this._entityReg.find(
|
||||
(e) => e.entity_id === helper.entity_id
|
||||
);
|
||||
if (
|
||||
!entityReg?.unique_id ||
|
||||
!isComponentLoaded(this.hass, helper.type)
|
||||
) {
|
||||
throw new Error(
|
||||
this.hass.localize("ui.panel.config.helpers.picker.delete_failed")
|
||||
);
|
||||
}
|
||||
await HELPERS_CRUD[helper.type as HelperDomain].delete(
|
||||
this.hass,
|
||||
entityReg.unique_id
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// For config entry-based helpers, delete the config entry
|
||||
if (helper.configEntry) {
|
||||
await deleteConfigEntry(this.hass, helper.configEntry.entry_id);
|
||||
}
|
||||
} catch (err: any) {
|
||||
showAlertDialog(this, {
|
||||
text:
|
||||
err.message ||
|
||||
this.hass.localize("ui.panel.config.helpers.picker.delete_failed"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _createHelper() {
|
||||
showHelperDetailDialog(this, {});
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
|
||||
color:
|
||||
route.route_status === "Active"
|
||||
? primaryColor
|
||||
: style.getPropertyValue("--disabled-color"),
|
||||
: style.getPropertyValue("--dark-primary-color"),
|
||||
type: ["Child", "Parent"].includes(neighbor.relationship)
|
||||
? "solid"
|
||||
: "dotted",
|
||||
@@ -335,7 +335,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
|
||||
symbolSize: 5,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: style.getPropertyValue("--disabled-color"),
|
||||
color: style.getPropertyValue("--dark-primary-color"),
|
||||
type: "dotted",
|
||||
},
|
||||
ignoreForceLayout: true,
|
||||
|
||||
@@ -62,7 +62,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
const defaultPanelUrlPath =
|
||||
this.hass.systemData?.defaultPanel || DEFAULT_PANEL;
|
||||
this.hass.systemData?.default_panel || DEFAULT_PANEL;
|
||||
const titleInvalid = !this._data.title || !this._data.title.trim();
|
||||
|
||||
return html`
|
||||
@@ -260,7 +260,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultPanel = this.hass.systemData?.defaultPanel || DEFAULT_PANEL;
|
||||
const defaultPanel = this.hass.systemData?.default_panel || DEFAULT_PANEL;
|
||||
// Add warning dialog to saying that this will change the default dashboard for all users
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
@@ -284,7 +284,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
||||
|
||||
saveFrontendSystemData(this.hass.connection, "core", {
|
||||
...this.hass.systemData,
|
||||
defaultPanel: urlPath === defaultPanel ? undefined : urlPath,
|
||||
default_panel: urlPath === defaultPanel ? undefined : urlPath,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -309,7 +309,20 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
||||
}
|
||||
this.closeDialog();
|
||||
} catch (err: any) {
|
||||
this._error = { base: err?.message || "Unknown error" };
|
||||
let localizedErrorMessage: string | undefined;
|
||||
if (err?.translation_domain && err?.translation_key) {
|
||||
const localize = await this.hass.loadBackendTranslation(
|
||||
"exceptions",
|
||||
err.translation_domain
|
||||
);
|
||||
localizedErrorMessage = localize(
|
||||
`component.${err.translation_domain}.exceptions.${err.translation_key}.message`,
|
||||
err.translation_placeholders
|
||||
);
|
||||
}
|
||||
this._error = {
|
||||
base: localizedErrorMessage || err?.message || "Unknown error",
|
||||
};
|
||||
} finally {
|
||||
this._submitting = false;
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
return html` <hass-loading-screen></hass-loading-screen> `;
|
||||
}
|
||||
|
||||
const defaultPanel = this.hass.systemData?.defaultPanel || DEFAULT_PANEL;
|
||||
const defaultPanel = this.hass.systemData?.default_panel || DEFAULT_PANEL;
|
||||
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
|
||||
@@ -25,7 +25,7 @@ class HaPickDashboardRow extends LitElement {
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const value = this.hass.userData?.defaultPanel || USE_SYSTEM_VALUE;
|
||||
const value = this.hass.userData?.default_panel || USE_SYSTEM_VALUE;
|
||||
return html`
|
||||
<ha-settings-row .narrow=${this.narrow}>
|
||||
<span slot="heading">
|
||||
@@ -84,12 +84,12 @@ class HaPickDashboardRow extends LitElement {
|
||||
return;
|
||||
}
|
||||
const urlPath = value === USE_SYSTEM_VALUE ? undefined : value;
|
||||
if (urlPath === this.hass.userData?.defaultPanel) {
|
||||
if (urlPath === this.hass.userData?.default_panel) {
|
||||
return;
|
||||
}
|
||||
saveFrontendUserData(this.hass.connection, "core", {
|
||||
...this.hass.userData,
|
||||
defaultPanel: urlPath,
|
||||
default_panel: urlPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ export const colorStyles = css`
|
||||
--divider-color: rgba(0, 0, 0, 0.12);
|
||||
--outline-color: rgba(0, 0, 0, 0.12);
|
||||
--outline-hover-color: rgba(0, 0, 0, 0.24);
|
||||
--shadow-color: rgba(0, 0, 0, 0.16);
|
||||
|
||||
/* rgb */
|
||||
--rgb-primary-color: 0, 154, 199;
|
||||
@@ -225,7 +224,7 @@ export const colorStyles = css`
|
||||
--table-row-alternative-background-color: var(--secondary-background-color);
|
||||
--data-table-background-color: var(--card-background-color);
|
||||
--markdown-code-background-color: var(--primary-background-color);
|
||||
--bar-box-shadow: 0 2px 12px var(--shadow-color);
|
||||
--bar-box-shadow: 0 2px 12px rgba(0, 0, 0, 0.16);
|
||||
|
||||
/* https://github.com/material-components/material-web/blob/master/docs/theming.md */
|
||||
--mdc-theme-primary: var(--primary-color);
|
||||
@@ -308,8 +307,6 @@ export const darkColorStyles = css`
|
||||
--divider-color: rgba(225, 225, 225, 0.12);
|
||||
--outline-color: rgba(225, 225, 225, 0.12);
|
||||
--outline-hover-color: rgba(225, 225, 225, 0.24);
|
||||
--shadow-color: rgba(0, 0, 0, 0.48);
|
||||
|
||||
--mdc-ripple-color: #aaaaaa;
|
||||
--mdc-linear-progress-buffer-color: rgba(255, 255, 255, 0.1);
|
||||
|
||||
@@ -353,7 +350,7 @@ export const darkColorStyles = css`
|
||||
--ha-button-neutral-color: #d9dae0;
|
||||
--ha-button-neutral-light-color: #6a7081;
|
||||
|
||||
--bar-box-shadow: 0 2px 12px var(--shadow-color);
|
||||
--bar-box-shadow: 0 2px 12px rgba(0, 0, 0, 0.48);
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -3265,7 +3265,10 @@
|
||||
"create_helper": "Create helper",
|
||||
"no_helpers": "Looks like you don't have any helpers yet!",
|
||||
"search": "Search {number} {number, plural,\n one {helper}\n other {helpers}\n}",
|
||||
"error_information": "Error information"
|
||||
"error_information": "Error information",
|
||||
"delete_confirm_title": "Delete helper?",
|
||||
"delete_confirm_text": "Are you sure you want to delete {name}?",
|
||||
"delete_failed": "Failed to delete helper"
|
||||
},
|
||||
"dialog": {
|
||||
"create": "Create",
|
||||
|
||||
20
yarn.lock
20
yarn.lock
@@ -1215,15 +1215,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@codemirror/autocomplete@npm:6.19.1":
|
||||
version: 6.19.1
|
||||
resolution: "@codemirror/autocomplete@npm:6.19.1"
|
||||
"@codemirror/autocomplete@npm:6.20.0":
|
||||
version: 6.20.0
|
||||
resolution: "@codemirror/autocomplete@npm:6.20.0"
|
||||
dependencies:
|
||||
"@codemirror/language": "npm:^6.0.0"
|
||||
"@codemirror/state": "npm:^6.0.0"
|
||||
"@codemirror/view": "npm:^6.17.0"
|
||||
"@lezer/common": "npm:^1.0.0"
|
||||
checksum: 10/6b5a6f3eb869057696c8e1e601eec97f4c68eebb6ca3890d0aea264b2e7888c555a57c74ae53731d3bc2cc98466be1778cc64b0f7f591ba90b61cd334e7095a8
|
||||
checksum: 10/ba3603b860c30dd4f8b7c20085680d2f491022db95fe1f3aa6a58363c64678efb3ba795d715755c8a02121631317cf7fbe44cfa3b4cdb01ebca2b4ed36ea5d8a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1282,15 +1282,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@codemirror/view@npm:6.38.6, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
|
||||
version: 6.38.6
|
||||
resolution: "@codemirror/view@npm:6.38.6"
|
||||
"@codemirror/view@npm:6.38.8, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0":
|
||||
version: 6.38.8
|
||||
resolution: "@codemirror/view@npm:6.38.8"
|
||||
dependencies:
|
||||
"@codemirror/state": "npm:^6.5.0"
|
||||
crelt: "npm:^1.0.6"
|
||||
style-mod: "npm:^4.1.0"
|
||||
w3c-keyname: "npm:^2.2.4"
|
||||
checksum: 10/5a047337a98de111817ce8c8d39e6429c90ca0b0a4d2678d6e161e9e5961b1d476a891f447ab7a05cac395d4a93530e7c68bedd93191285265f0742a308ad00b
|
||||
checksum: 10/81b1508015a378e4719d0239254173f0c5cd340c2abf96eb488fe5fb474bdb37ec1f010b9890ced774accd7aeb9443e7337cb6a89544b954273e5ddabece7cea
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9202,13 +9202,13 @@ __metadata:
|
||||
"@babel/runtime": "npm:7.28.4"
|
||||
"@braintree/sanitize-url": "npm:7.1.1"
|
||||
"@bundle-stats/plugin-webpack-filter": "npm:4.21.6"
|
||||
"@codemirror/autocomplete": "npm:6.19.1"
|
||||
"@codemirror/autocomplete": "npm:6.20.0"
|
||||
"@codemirror/commands": "npm:6.10.0"
|
||||
"@codemirror/language": "npm:6.11.3"
|
||||
"@codemirror/legacy-modes": "npm:6.5.2"
|
||||
"@codemirror/search": "npm:6.5.11"
|
||||
"@codemirror/state": "npm:6.5.2"
|
||||
"@codemirror/view": "npm:6.38.6"
|
||||
"@codemirror/view": "npm:6.38.8"
|
||||
"@date-fns/tz": "npm:1.4.1"
|
||||
"@egjs/hammerjs": "npm:2.0.17"
|
||||
"@formatjs/intl-datetimeformat": "npm:6.18.2"
|
||||
|
||||
Reference in New Issue
Block a user