mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-23 00:17:27 +00:00
Compare commits
2 Commits
show-proto
...
improve-co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdf53cfcdd | ||
|
|
3194fe9a30 |
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
})}`;
|
||||
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user