Compare commits

..

2 Commits

9 changed files with 126 additions and 157 deletions

View File

@@ -206,3 +206,29 @@ export const sortConfigEntries = (
);
return [primaryEntry, ...otherEntries];
};
export const handleConfigEntrySubscriptionMessages = (
currentEntries: ConfigEntry[],
messages: ConfigEntryUpdate[]
): ConfigEntry[] => {
let entries = [...currentEntries];
messages.forEach((message) => {
if (message.type === null || message.type === "added") {
entries.push(message.entry);
return;
}
if (message.type === "removed") {
entries = entries.filter(
(entry) => entry.entry_id !== message.entry.entry_id
);
return;
}
if (message.type === "updated") {
const newEntry = message.entry;
entries = entries.map((entry) =>
entry.entry_id === newEntry.entry_id ? newEntry : entry
);
}
});
return entries;
};

View File

@@ -3,6 +3,7 @@ import type { HassConfig } from "home-assistant-js-websocket";
import type { HomeAssistant } from "../types";
import type { EntityRegistryEntry } from "./entity/entity_registry";
import type { LabelRegistryEntry } from "./label/label_registry";
import type { ConfigEntry } from "./config_entries";
export const connectionContext =
createContext<HomeAssistant["connection"]>("connection");
@@ -30,3 +31,5 @@ export const fullEntitiesContext =
export const floorsContext = createContext<HomeAssistant["floors"]>("floors");
export const labelsContext = createContext<LabelRegistryEntry[]>("labels");
export const configEntries = createContext<ConfigEntry[]>("configEntries");

View File

@@ -1,5 +1,6 @@
import { ContextProvider } from "@lit/context";
import { mdiContentSave, mdiHelpCircle } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import { load } from "js-yaml";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@@ -46,7 +47,13 @@ import {
isTrigger,
normalizeAutomationConfig,
} from "../../../data/automation";
import {
handleConfigEntrySubscriptionMessages,
subscribeConfigEntries,
} from "../../../data/config_entries";
import { configEntries } from "../../../data/context";
import { getActionType, type Action } from "../../../data/script";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { showToast } from "../../../util/toast";
@@ -80,7 +87,7 @@ const automationConfigStruct = union([
export const SIDEBAR_DEFAULT_WIDTH = 500;
@customElement("manual-automation-editor")
export class HaManualAutomationEditor extends LitElement {
export class HaManualAutomationEditor extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
@@ -117,6 +124,11 @@ export class HaManualAutomationEditor extends LitElement {
HaAutomationAction | HaAutomationCondition
>;
private _configEntries = new ContextProvider(this, {
context: configEntries,
initialValue: [],
});
private _prevSidebarWidthPx?: number;
public connectedCallback() {
@@ -124,6 +136,19 @@ export class HaManualAutomationEditor extends LitElement {
window.addEventListener("paste", this._handlePaste);
}
public hassSubscribe(): Promise<UnsubscribeFunc>[] {
return [
subscribeConfigEntries(this.hass, (messages) => {
this._configEntries.setValue(
handleConfigEntrySubscriptionMessages(
this._configEntries.value,
messages
)
);
}),
];
}
public disconnectedCallback() {
window.removeEventListener("paste", this._handlePaste);
super.disconnectedCallback();

View File

@@ -1,17 +1,15 @@
import { consume } from "@lit/context";
import { mdiAlert, mdiFormatListBulleted, mdiShape } from "@mdi/js";
import type { HassServiceTarget } from "home-assistant-js-websocket";
import { LitElement, css, html, nothing, type TemplateResult } from "lit";
import { css, html, LitElement, type nothing, type TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { until } from "lit/directives/until";
import { ensureArray } from "../../../../common/array/ensure-array";
import { transform } from "../../../../common/decorators/transform";
import "../../../../components/ha-svg-icon";
import {
getConfigEntries,
type ConfigEntry,
} from "../../../../data/config_entries";
import type { ConfigEntry } from "../../../../data/config_entries";
import {
areasContext,
configEntries,
devicesContext,
floorsContext,
labelsContext,
@@ -55,6 +53,13 @@ export class HaAutomationRowTargets extends LitElement {
@consume({ context: labelsContext, subscribe: true })
private _labelRegistry!: LabelRegistryEntry[];
@state()
@consume({ context: configEntries, subscribe: true })
@transform<ConfigEntry[], Record<string, ConfigEntry>>({
transformer: function (value) {
return Object.fromEntries(value.map((entry) => [entry.entry_id, entry]));
},
})
private _configEntryLookup?: Record<string, ConfigEntry>;
protected render() {
@@ -149,13 +154,6 @@ export class HaAutomationRowTargets extends LitElement {
</div>`;
}
private async _loadConfigEntries() {
const configEntries = await getConfigEntries(this.hass);
this._configEntryLookup = Object.fromEntries(
configEntries.map((entry) => [entry.entry_id, entry])
);
}
private _renderTarget(
targetType: "floor" | "area" | "device" | "entity" | "label",
targetId: string
@@ -178,22 +176,6 @@ export class HaAutomationRowTargets extends LitElement {
);
}
if (targetType === "device" && !this._configEntryLookup) {
const loadConfigEntries = this._loadConfigEntries().then(() =>
this._renderTargetBadge(
getTargetIcon(
this.hass,
targetType,
targetId,
this._configEntryLookup!
),
getTargetText(this.hass, targetType, targetId)
)
);
return html`${until(loadConfigEntries, nothing)}`;
}
return this._renderTargetBadge(
getTargetIcon(
this.hass,

View File

@@ -8,7 +8,7 @@ import {
} from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
@@ -39,6 +39,7 @@ import {
} from "../../../dialogs/quick-bar/show-dialog-quick-bar";
import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart";
import { showShortcutsDialog } from "../../../dialogs/shortcuts/show-shortcuts-dialog";
import type { PageNavigation } from "../../../layouts/hass-tabs-subpage";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
@@ -154,6 +155,8 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public cloudStatus?: CloudStatus;
@property({ attribute: false }) public showAdvanced = false;
@state() private _tip?: string;
@state() private _repairsIssues: { issues: RepairsIssue[]; total: number } = {
@@ -161,24 +164,21 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
total: 0,
};
private _pages = memoizeOne((cloudStatus, isCloudLoaded) => [
isCloudLoaded
? [
{
component: "cloud",
path: "/config/cloud",
name: "Home Assistant Cloud",
info: cloudStatus,
iconPath: mdiCloudLock,
iconColor: "#3B808E",
translationKey: "cloud",
},
...configSections.dashboard,
]
: configSections.dashboard,
configSections.dashboard_2,
configSections.dashboard_3,
]);
private _pages = memoizeOne((cloudStatus, isCloudLoaded) => {
const pages: PageNavigation[] = [];
if (isCloudLoaded) {
pages.push({
component: "cloud",
path: "/config/cloud",
name: "Home Assistant Cloud",
info: cloudStatus,
iconPath: mdiCloudLock,
iconColor: "#3B808E",
translationKey: "cloud",
});
}
return [...pages, ...configSections.dashboard];
});
public hassSubscribe(): UnsubscribeFunc[] {
return [
@@ -308,22 +308,18 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
: ""}
</ha-card>`
: ""}
${this._pages(
this.cloudStatus,
isComponentLoaded(this.hass, "cloud")
).map((categoryPages) =>
categoryPages.length === 0
? nothing
: html`
<ha-card outlined>
<ha-config-navigation
.hass=${this.hass}
.narrow=${this.narrow}
.pages=${categoryPages}
></ha-config-navigation>
</ha-card>
`
)}
<ha-card outlined>
<ha-config-navigation
.hass=${this.hass}
.narrow=${this.narrow}
.showAdvanced=${this.showAdvanced}
.pages=${this._pages(
this.cloudStatus,
isComponentLoaded(this.hass, "cloud")
)}
></ha-config-navigation>
</ha-card>
<ha-tip .hass=${this.hass}>${this._tip}</ha-tip>
</ha-config-section>
</ha-top-app-bar-fixed>

View File

@@ -3,7 +3,6 @@ import {
mdiAccount,
mdiBackupRestore,
mdiBadgeAccountHorizontal,
mdiBluetooth,
mdiCellphoneCog,
mdiCog,
mdiDatabase,
@@ -26,14 +25,10 @@ import {
mdiScrewdriver,
mdiScriptText,
mdiShape,
mdiLan,
mdiSofa,
mdiTools,
mdiUpdate,
mdiViewDashboard,
mdiZigbee,
mdiZWave,
mdiRouterWireless,
} from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
@@ -106,65 +101,6 @@ export const configSections: Record<string, PageNavigation[]> = {
iconPath: mdiMicrophone,
iconColor: "#3263C3",
},
],
dashboard_2: [
{
path: "/config/matter",
name: "Matter",
iconPath:
"M7.228375 6.41685c0.98855 0.80195 2.16365 1.3412 3.416275 1.56765V1.30093l1.3612 -0.7854275 1.360125 0.7854275V7.9845c1.252875 -0.226675 2.4283 -0.765875 3.41735 -1.56765l2.471225 1.4293c-4.019075 3.976275 -10.490025 3.976275 -14.5091 0l2.482925 -1.4293Zm3.00335 17.067575c1.43325 -5.47035 -1.8052 -11.074775 -7.2604 -12.564675v2.859675c1.189125 0.455 2.244125 1.202875 3.0672 2.174275L0.25 19.2955v1.5719l1.3611925 0.781175L7.39865 18.3068c0.430175 1.19825 0.550625 2.48575 0.35015 3.743l2.482925 1.434625ZM21.034 10.91975c-5.452225 1.4932 -8.6871 7.09635 -7.254025 12.564675l2.47655 -1.43035c-0.200025 -1.257275 -0.079575 -2.544675 0.35015 -3.743025l5.7832 3.337525L23.75 20.86315V19.2955L17.961475 15.9537c0.8233 -0.97115 1.878225 -1.718975 3.0672 -2.174275l0.005325 -2.859675Z",
iconColor: "#2458B3",
component: "matter",
translationKey: "matter",
},
{
path: "/config/zha",
name: "Zigbee",
iconPath: mdiZigbee,
iconColor: "#E74011",
component: "zha",
translationKey: "zha",
},
{
path: "/config/zwave_js",
name: "Z-Wave",
iconPath: mdiZWave,
iconColor: "#153163",
component: "zwave_js",
translationKey: "zwave_js",
},
{
path: "/config/thread",
name: "Thread",
iconPath: mdiRouterWireless,
iconColor: "#ED7744",
component: "thread",
translationKey: "thread",
},
{
path: "/config/bluetooth",
name: "Bluetooth",
iconPath: mdiBluetooth,
iconColor: "#0082FC",
component: "bluetooth",
translationKey: "bluetooth",
},
{
path: "/knx",
name: "KNX",
iconPath: mdiLan,
iconColor: "#4EAA66",
component: "knx",
translationKey: "knx",
},
{
path: "/insteon",
name: "Insteon",
iconPath: mdiLan,
iconColor: "#E4002C",
component: "insteon",
translationKey: "insteon",
},
{
path: "/config/tags",
translationKey: "tags",
@@ -172,8 +108,6 @@ export const configSections: Record<string, PageNavigation[]> = {
iconColor: "#616161",
component: "tag",
},
],
dashboard_3: [
{
path: "/config/person",
translationKey: "people",

View File

@@ -1,4 +1,6 @@
import { ContextProvider } from "@lit/context";
import { mdiContentSave, mdiHelpCircle } from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import { load } from "js-yaml";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@@ -35,6 +37,11 @@ import type {
ActionSidebarConfig,
SidebarConfig,
} from "../../../data/automation";
import {
handleConfigEntrySubscriptionMessages,
subscribeConfigEntries,
} from "../../../data/config_entries";
import { configEntries } from "../../../data/context";
import type {
Action,
Fields,
@@ -46,6 +53,7 @@ import {
MODES,
normalizeScriptConfig,
} from "../../../data/script";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { showToast } from "../../../util/toast";
@@ -70,7 +78,7 @@ const scriptConfigStruct = object({
});
@customElement("manual-script-editor")
export class HaManualScriptEditor extends LitElement {
export class HaManualScriptEditor extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
@@ -108,6 +116,11 @@ export class HaManualScriptEditor extends LitElement {
HaAutomationAction | HaScriptFields
>;
private _configEntries = new ContextProvider(this, {
context: configEntries,
initialValue: [],
});
private _openFields = false;
private _prevSidebarWidthPx?: number;
@@ -129,6 +142,19 @@ export class HaManualScriptEditor extends LitElement {
});
}
public hassSubscribe(): Promise<UnsubscribeFunc>[] {
return [
subscribeConfigEntries(this.hass, (messages) => {
this._configEntries.setValue(
handleConfigEntrySubscriptionMessages(
this._configEntries.value,
messages
)
);
}),
];
}
protected updated(changedProps) {
if (this._openFields && changedProps.has("config")) {
this._openFields = false;

View File

@@ -268,6 +268,7 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
now.setHours(now.getHours() - this._hoursToShow);
const configUrl = `/history?${createSearchParam({
entity_id: this._entityIds.join(","),
back: "1",
start_date: now.toISOString(),
})}`;

View File

@@ -2329,30 +2329,6 @@
},
"cloud": {
"secondary": "Loading..."
},
"zwave_js": {
"secondary": "Manage your Z-Wave network"
},
"zha": {
"secondary": "Manage your Zigbee network"
},
"matter": {
"secondary": "Manage your Matter network"
},
"thread": {
"secondary": "Manage your Thread network"
},
"bluetooth": {
"secondary": "Manage your Bluetooth devices"
},
"knx": {
"secondary": "Manage your KNX network"
},
"insteon": {
"secondary": "Manage your Insteon network"
},
"hacs": {
"secondary": "Manage community integrations and frontend modules"
}
},
"common": {