Compare commits

...

8 Commits

Author SHA1 Message Date
Aidan Timson
099b38de73 D (Contextual dashboards - areas, climate, lights, energy etc., not fully working) 2026-01-21 15:27:57 +00:00
Aidan Timson
db442a4b09 C (Fix for device not showing on more info) 2026-01-21 15:15:28 +00:00
Aidan Timson
4daab5e9e2 B (Fix more info context passing, messy but working) 2026-01-21 15:15:28 +00:00
Aidan Timson
205122eaac A (Everything #1) 2026-01-21 15:15:08 +00:00
Aidan Timson
eef5ff5e67 Prefetch and pass related result to dialog instead of loading on show (load on event call) 2026-01-21 14:37:38 +00:00
Aidan Timson
3192e09c0a Use interface 2026-01-21 14:24:36 +00:00
Aidan Timson
078cc5cf0d Send context from device page 2026-01-21 14:06:52 +00:00
Aidan Timson
a751bd40b4 Add support for context in quick bar 2026-01-21 14:06:52 +00:00
19 changed files with 465 additions and 22 deletions

View File

@@ -54,6 +54,7 @@ export interface PickerComboBoxItem {
sorting_label?: string;
icon_path?: string;
icon?: string;
isRelated?: boolean;
}
export const NO_ITEMS_AVAILABLE_ID = "___no_items_available___";

View File

@@ -148,6 +148,7 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
this._initialView = params.view || DEFAULT_VIEW;
this._childView = undefined;
this.large = false;
this._setQuickBarContext();
this._loadEntityRegistryEntry();
}
@@ -163,6 +164,8 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
} catch (_e) {
this._entry = null;
}
this._setQuickBarContext();
}
public closeDialog() {
@@ -215,6 +218,53 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
return !!this.hass.auth.external?.config.hasEntityAddTo;
}
private _setQuickBarContext(): void {
if (!this._entityId) {
return;
}
const stateObj = this.hass.states[this._entityId] as HassEntity | undefined;
const context = stateObj
? getEntityContext(
stateObj,
this.hass.entities,
this.hass.devices,
this.hass.areas,
this.hass.floors
)
: this._entry
? getEntityEntryContext(
this._entry,
this.hass.entities,
this.hass.devices,
this.hass.areas,
this.hass.floors
)
: undefined;
const domain = computeDomain(this._entityId);
let itemType: ItemType = SearchableDomains.has(domain)
? (domain as ItemType)
: "entity";
let itemId = this._entityId;
if (context?.device) {
itemType = "device";
itemId = context.device.id;
} else if (context?.area) {
itemType = "area";
itemId = context.area.area_id;
} else if (context?.floor) {
itemType = "floor";
itemId = context.floor.floor_id;
}
fireEvent(this, "hass-quick-bar-context", {
itemType,
itemId,
});
}
private _getDeviceId(): string | null {
const entity = this.hass.entities[this._entityId!] as
| EntityRegistryEntry

View File

@@ -4,6 +4,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { computeDomain } from "../../common/entity/compute_domain";
import { fireEvent } from "../../common/dom/fire_event";
import { navigate } from "../../common/navigate";
import { caseInsensitiveStringCompare } from "../../common/string/compare";
@@ -44,6 +45,7 @@ import {
type ActionCommandComboBoxItem,
type NavigationComboBoxItem,
} from "../../data/quick_bar";
import type { RelatedResult } from "../../data/search";
import {
multiTermSortedSearch,
type FuseWeightedKey,
@@ -52,7 +54,11 @@ import type { HomeAssistant } from "../../types";
import { isIosApp } from "../../util/is_ios";
import { showConfirmationDialog } from "../generic/show-dialog-box";
import { showShortcutsDialog } from "../shortcuts/show-shortcuts-dialog";
import type { QuickBarParams, QuickBarSection } from "./show-dialog-quick-bar";
import type {
QuickBarContextItem,
QuickBarParams,
QuickBarSection,
} from "./show-dialog-quick-bar";
const SEPARATOR = "________";
@@ -70,6 +76,10 @@ export class QuickBar extends LitElement {
@state() private _opened = false;
@state() private _relatedResult?: RelatedResult;
@state() private _contextItem?: QuickBarContextItem;
@query("ha-picker-combo-box") private _comboBox?: HaPickerComboBox;
private get _showEntityId() {
@@ -91,6 +101,15 @@ export class QuickBar extends LitElement {
this._initialize();
this._selectedSection = params.mode;
this._hint = params.hint;
this._contextItem = params.contextItem;
this._relatedResult = params.related;
if (!params.contextItem) {
this._contextItem = undefined;
this._relatedResult = undefined;
}
this._open = true;
}
@@ -377,6 +396,8 @@ export class QuickBar extends LitElement {
this._selectedSection = section as QuickBarSection | undefined;
return this._getItemsMemoized(
this._configEntryLookup,
this._contextItem,
this._relatedResult,
searchString,
this._selectedSection
);
@@ -385,10 +406,13 @@ export class QuickBar extends LitElement {
private _getItemsMemoized = memoizeOne(
(
configEntryLookup: Record<string, ConfigEntry>,
contextItem: QuickBarContextItem | undefined,
relatedResult: RelatedResult | undefined,
filter?: string,
section?: QuickBarSection
) => {
const items: (string | PickerComboBoxItem)[] = [];
const relatedIdSets = this._getRelatedIdSets(contextItem, relatedResult);
if (!section || section === "navigate") {
let navigateItems = this._generateNavigationCommandsMemoized(
@@ -436,17 +460,29 @@ export class QuickBar extends LitElement {
}
if (!section || section === "entity") {
let entityItems = this._getEntitiesMemoized(this.hass).sort(
this._sortBySortingLabel
);
let entityItems = this._getEntitiesMemoized(this.hass);
// Mark related items
if (relatedIdSets.entities.size > 0) {
entityItems = entityItems.map((item) => ({
...item,
isRelated: relatedIdSets.entities.has(
(item as EntityComboBoxItem).stateObj?.entity_id || ""
),
}));
}
if (filter) {
entityItems = this._filterGroup(
"entity",
entityItems,
filter,
entityComboBoxKeys
) as EntityComboBoxItem[];
entityItems = this._sortRelatedFirst(
this._filterGroup(
"entity",
entityItems,
filter,
entityComboBoxKeys
) as EntityComboBoxItem[]
);
} else {
entityItems = this._sortRelatedByLabel(entityItems);
}
if (!section && entityItems.length) {
@@ -463,15 +499,25 @@ export class QuickBar extends LitElement {
let deviceItems = this._getDevicesMemoized(
this.hass,
configEntryLookup
).sort(this._sortBySortingLabel);
);
// Mark related items
if (relatedIdSets.devices.size > 0) {
deviceItems = deviceItems.map((item) => {
const deviceId = item.id.split(SEPARATOR)[1];
return {
...item,
isRelated: relatedIdSets.devices.has(deviceId || ""),
};
});
}
if (filter) {
deviceItems = this._filterGroup(
"device",
deviceItems,
filter,
deviceComboBoxKeys
deviceItems = this._sortRelatedFirst(
this._filterGroup("device", deviceItems, filter, deviceComboBoxKeys)
);
} else {
deviceItems = this._sortRelatedByLabel(deviceItems);
}
if (!section && deviceItems.length) {
@@ -487,13 +533,23 @@ export class QuickBar extends LitElement {
if (this.hass.user?.is_admin && (!section || section === "area")) {
let areaItems = this._getAreasMemoized(this.hass);
// Mark related items
if (relatedIdSets.areas.size > 0) {
areaItems = areaItems.map((item) => {
const areaId = item.id.split(SEPARATOR)[1];
return {
...item,
isRelated: relatedIdSets.areas.has(areaId || ""),
};
});
}
if (filter) {
areaItems = this._filterGroup(
"area",
areaItems,
filter,
areaComboBoxKeys
areaItems = this._sortRelatedFirst(
this._filterGroup("area", areaItems, filter, areaComboBoxKeys)
);
} else {
areaItems = this._sortRelatedByLabel(areaItems);
}
if (!section && areaItems.length) {
@@ -510,6 +566,108 @@ export class QuickBar extends LitElement {
}
);
private _getRelatedIdSets = memoizeOne(
(contextItem?: QuickBarContextItem, related?: RelatedResult) => {
const entities = new Set(related?.entity || []);
const devices = new Set(related?.device || []);
const areas = new Set(related?.area || []);
if (contextItem) {
switch (contextItem.itemType) {
case "domain":
this._getDomainEntities(contextItem.itemId).forEach((entityId) =>
entities.add(entityId)
);
break;
case "entity":
entities.add(contextItem.itemId);
break;
case "device":
devices.add(contextItem.itemId);
break;
case "area":
areas.add(contextItem.itemId);
break;
}
}
return { entities, devices, areas };
}
);
private _getDomainEntities(domain: string): string[] {
const states = Object.values(this.hass.states);
if (domain === "energy") {
return states
.filter((stateObj) => {
if (computeDomain(stateObj.entity_id) !== "sensor") {
return false;
}
const deviceClass = stateObj.attributes.device_class;
return (
typeof deviceClass === "string" &&
["energy", "power", "gas", "water"].includes(deviceClass)
);
})
.map((stateObj) => stateObj.entity_id);
}
if (domain === "security") {
const coverClasses = new Set(["door", "garage", "gate"]);
const binarySensorClasses = new Set([
"lock",
"door",
"window",
"garage_door",
"opening",
"carbon_monoxide",
"gas",
"moisture",
"safety",
"smoke",
]);
return states
.filter((stateObj) => {
const stateDomain = computeDomain(stateObj.entity_id);
if (
stateDomain === "camera" ||
stateDomain === "alarm_control_panel" ||
stateDomain === "lock"
) {
return true;
}
const deviceClass = stateObj.attributes.device_class;
if (stateDomain === "cover") {
return (
typeof deviceClass === "string" && coverClasses.has(deviceClass)
);
}
if (stateDomain === "binary_sensor") {
if (typeof deviceClass !== "string") {
return false;
}
if (binarySensorClasses.has(deviceClass)) {
return true;
}
return (
deviceClass === "tamper" &&
stateObj.attributes.entity_category === "diagnostic"
);
}
return false;
})
.map((stateObj) => stateObj.entity_id);
}
return states
.filter((stateObj) => computeDomain(stateObj.entity_id) === domain)
.map((stateObj) => stateObj.entity_id);
}
private _getEntitiesMemoized = memoizeOne((hass: HomeAssistant) =>
getEntities(
hass,
@@ -609,6 +767,23 @@ export class QuickBar extends LitElement {
this.hass.locale.language
);
private _sortRelatedByLabel = (items: PickerComboBoxItem[]) =>
[...items].sort((a, b) => {
if (a.isRelated && !b.isRelated) return -1;
if (!a.isRelated && b.isRelated) return 1;
return this._sortBySortingLabel(a, b);
});
private _sortRelatedFirst = (items: PickerComboBoxItem[]) =>
[...items].sort((a, b) => {
const aRelated = Boolean(a.isRelated);
const bRelated = Boolean(b.isRelated);
if (aRelated === bRelated) {
return 0;
}
return aRelated ? -1 : 1;
});
// #endregion data
// #region interaction

View File

@@ -1,4 +1,5 @@
import { fireEvent } from "../../common/dom/fire_event";
import type { ItemType, RelatedResult } from "../../data/search";
export type QuickBarSection =
| "entity"
@@ -7,10 +8,19 @@ export type QuickBarSection =
| "navigate"
| "command";
export type QuickBarContextItemType = ItemType | "domain";
export interface QuickBarContextItem {
itemType: QuickBarContextItemType;
itemId: string;
}
export interface QuickBarParams {
entityFilter?: string;
mode?: QuickBarSection;
hint?: string;
contextItem?: QuickBarContextItem;
related?: RelatedResult;
}
export const loadQuickBar = () => import("./ha-quick-bar");

View File

@@ -1,6 +1,7 @@
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { goBack } from "../../common/navigate";
import { debounce } from "../../common/util/debounce";
import { deepEqual } from "../../common/util/deep-equal";
@@ -45,6 +46,8 @@ class PanelClimate extends LitElement {
return;
}
this._setQuickBarContext();
const oldHass = changedProps.get("hass") as this["hass"];
if (oldHass && oldHass.localize !== this.hass.localize) {
this._setLovelace();
@@ -76,6 +79,7 @@ class PanelClimate extends LitElement {
private async _setup() {
await this.hass.loadFragmentTranslation("lovelace");
this._setQuickBarContext();
this._setLovelace();
}
@@ -163,6 +167,13 @@ class PanelClimate extends LitElement {
};
}
private _setQuickBarContext() {
fireEvent(this, "hass-quick-bar-context", {
itemType: "domain",
itemId: "climate",
});
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -80,6 +80,12 @@ class DialogAreaDetail
): Promise<void> {
this._params = params;
this._error = undefined;
if (this._params.entry) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "area",
itemId: this._params.entry.area_id,
});
}
if (this._params.entry) {
this._name = this._params.entry.name;
this._aliases = this._params.entry.aliases;

View File

@@ -55,6 +55,12 @@ class DialogFloorDetail extends LitElement {
public showDialog(params: FloorRegistryDetailDialogParams): void {
this._params = params;
this._error = undefined;
if (this._params.entry) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "floor",
itemId: this._params.entry.floor_id,
});
}
this._name = this._params.entry
? this._params.entry.name
: this._params.suggestedName || "";

View File

@@ -10,6 +10,7 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { fireEvent } from "../../../common/dom/fire_event";
import { goBack } from "../../../common/navigate";
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import { slugify } from "../../../common/string/slugify";
@@ -137,6 +138,12 @@ class HaConfigAreaPage extends LitElement {
super.updated(changedProps);
if (changedProps.has("areaId")) {
this._findRelated();
if (this.areaId) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "area",
itemId: this.areaId,
});
}
}
}

View File

@@ -682,6 +682,16 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
sub(this._config)
);
}
if (changedProps.has("_entityId") || changedProps.has("entityId")) {
const automationEntityId = this._entityId ?? this.entityId;
if (automationEntityId) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "automation",
itemId: automationEntityId,
});
}
}
}
private _setEntityId() {

View File

@@ -41,6 +41,10 @@ class DialogDeviceRegistryDetail extends LitElement {
): Promise<void> {
this._params = params;
this._error = undefined;
fireEvent(this, "hass-quick-bar-context", {
itemType: "device",
itemId: this._params.device.id,
});
this._nameByUser = this._params.device.name_by_user || "";
this._areaId = this._params.device.area_id || "";
this._labels = this._params.device.labels || [];

View File

@@ -20,6 +20,7 @@ import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { ASSIST_ENTITIES, SENSOR_ENTITIES } from "../../../common/const";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeEntityEntryName } from "../../../common/entity/compute_entity_name";
@@ -302,6 +303,11 @@ export class HaConfigDevicePage extends LitElement {
super.updated(changedProps);
if (changedProps.has("deviceId")) {
this._findRelated();
// Broadcast device context for quick bar
fireEvent(this, "hass-quick-bar-context", {
itemType: "device",
itemId: this.deviceId,
});
}
}

View File

@@ -43,6 +43,12 @@ class DialogLabelDetail
public showDialog(params: LabelDetailDialogParams): void {
this._params = params;
this._error = undefined;
if (this._params.entry) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "label",
itemId: this._params.entry.label_id,
});
}
if (this._params.entry) {
this._name = this._params.entry.name || "";
this._icon = this._params.entry.icon || "";

View File

@@ -652,6 +652,13 @@ export class HaSceneEditor extends PreventUnsavedMixin(
);
}
}
if (changedProps.has("_scene") && this._scene?.entity_id) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "scene",
itemId: this._scene.entity_id,
});
}
}
private _handleMenuAction(ev: CustomEvent<{ item: HaDropdownItem }>) {

View File

@@ -583,6 +583,13 @@ export class HaScriptEditor extends SubscribeMixin(
this._dirty = false;
this._readOnly = true;
}
if (changedProps.has("_entityId") && this._entityId) {
fireEvent(this, "hass-quick-bar-context", {
itemType: "script",
itemId: this._entityId,
});
}
}
private async _checkValidation() {

View File

@@ -3,6 +3,7 @@ import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../common/dom/fire_event";
import { navigate } from "../../common/navigate";
import type { LocalizeKeys } from "../../common/translations/localize";
import "../../components/ha-alert";
@@ -133,6 +134,7 @@ class PanelEnergy extends LitElement {
// Initial setup
if (!this.hasUpdated) {
this.hass.loadFragmentTranslation("lovelace");
this._setQuickBarContext();
this._loadConfig();
return;
}
@@ -141,6 +143,8 @@ class PanelEnergy extends LitElement {
return;
}
this._setQuickBarContext();
const oldHass = changedProps.get("hass") as this["hass"];
if (oldHass && oldHass.localize !== this.hass.localize) {
this._setLovelace();
@@ -207,6 +211,13 @@ class PanelEnergy extends LitElement {
};
}
private _setQuickBarContext() {
fireEvent(this, "hass-quick-bar-context", {
itemType: "domain",
itemId: "energy",
});
}
protected render() {
if (this._error) {
return html`

View File

@@ -1,6 +1,7 @@
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { goBack } from "../../common/navigate";
import { debounce } from "../../common/util/debounce";
import { deepEqual } from "../../common/util/deep-equal";
@@ -45,6 +46,8 @@ class PanelLight extends LitElement {
return;
}
this._setQuickBarContext();
const oldHass = changedProps.get("hass") as this["hass"];
if (oldHass && oldHass.localize !== this.hass.localize) {
this._setLovelace();
@@ -76,6 +79,7 @@ class PanelLight extends LitElement {
private async _setup() {
await this.hass.loadFragmentTranslation("lovelace");
this._setQuickBarContext();
this._setLovelace();
}
@@ -163,6 +167,13 @@ class PanelLight extends LitElement {
};
}
private _setQuickBarContext() {
fireEvent(this, "hass-quick-bar-context", {
itemType: "domain",
itemId: "light",
});
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -72,6 +72,7 @@ import {
} from "../../dialogs/generic/show-dialog-box";
import { showMoreInfoDialog } from "../../dialogs/more-info/show-ha-more-info-dialog";
import { showQuickBar } from "../../dialogs/quick-bar/show-dialog-quick-bar";
import type { QuickBarContextItem } from "../../dialogs/quick-bar/show-dialog-quick-bar";
import { showShortcutsDialog } from "../../dialogs/shortcuts/show-shortcuts-dialog";
import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import { haStyle } from "../../resources/styles";
@@ -841,6 +842,34 @@ class HUIRoot extends LitElement {
fireEvent(this, "config-refresh");
}
private _setQuickBarContext(viewConfig?: LovelaceViewConfig) {
if (!this.lovelace || !isStrategyDashboard(this.lovelace.rawConfig)) {
return;
}
if (this.lovelace.rawConfig.strategy.type !== "home") {
return;
}
let contextItem: QuickBarContextItem = {
itemType: "entity",
itemId: "zone.home",
};
const viewPath = viewConfig?.path;
if (viewPath?.startsWith("areas-")) {
const areaId = viewPath.slice("areas-".length);
if (areaId) {
contextItem = {
itemType: "area",
itemId: areaId,
};
}
}
fireEvent(this, "hass-quick-bar-context", contextItem);
}
private _handleReloadResources(): void {
this.hass.callService("lovelace", "reload_resources");
showConfirmationDialog(this, {
@@ -1213,6 +1242,8 @@ class HUIRoot extends LitElement {
return;
}
this._setQuickBarContext(viewConfig);
if (!force && this._viewCache![viewIndex]) {
view = this._viewCache![viewIndex];
} else {

View File

@@ -1,6 +1,7 @@
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { goBack } from "../../common/navigate";
import { debounce } from "../../common/util/debounce";
import { deepEqual } from "../../common/util/deep-equal";
@@ -45,6 +46,8 @@ class PanelSecurity extends LitElement {
return;
}
this._setQuickBarContext();
const oldHass = changedProps.get("hass") as this["hass"];
if (oldHass && oldHass.localize !== this.hass.localize) {
this._setLovelace();
@@ -76,6 +79,7 @@ class PanelSecurity extends LitElement {
private async _setup() {
await this.hass.loadFragmentTranslation("lovelace");
this._setQuickBarContext();
this._setLovelace();
}
@@ -163,6 +167,13 @@ class PanelSecurity extends LitElement {
};
}
private _setQuickBarContext() {
fireEvent(this, "hass-quick-bar-context", {
itemType: "domain",
itemId: "security",
});
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -6,10 +6,12 @@ import { mainWindow } from "../common/dom/get_main_window";
import { ShortcutManager } from "../common/keyboard/shortcuts";
import { extractSearchParamsObject } from "../common/url/search-params";
import type {
QuickBarContextItem,
QuickBarParams,
QuickBarSection,
} from "../dialogs/quick-bar/show-dialog-quick-bar";
import { showQuickBar } from "../dialogs/quick-bar/show-dialog-quick-bar";
import { findRelated, type ItemType, type RelatedResult } from "../data/search";
import { showShortcutsDialog } from "../dialogs/shortcuts/show-shortcuts-dialog";
import { showVoiceCommandDialog } from "../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import type { Redirects } from "../panels/my/ha-panel-my";
@@ -23,11 +25,55 @@ declare global {
"hass-quick-bar": QuickBarParams;
"hass-quick-bar-trigger": KeyboardEvent;
"hass-enable-shortcuts": HomeAssistant["enableShortcuts"];
"hass-quick-bar-context": QuickBarContextItem | undefined;
}
}
export default <T extends Constructor<HassElement>>(superClass: T) =>
class extends superClass {
private _quickBarContext?: QuickBarContextItem;
private _quickBarContextRelated?: RelatedResult;
private _fetchRelatedMemoized = memoizeOne(
(itemType: ItemType, itemId: string) =>
findRelated(this.hass!, itemType, itemId)
);
private _clearQuickBarContext = () => {
this._quickBarContext = undefined;
this._quickBarContextRelated = undefined;
};
private _contextMatches = (context?: QuickBarContextItem) =>
context?.itemType === this._quickBarContext?.itemType &&
context?.itemId === this._quickBarContext?.itemId;
private _prefetchQuickBarContext = async (
context?: QuickBarContextItem
) => {
this._quickBarContextRelated = undefined;
if (!context || context.itemType === "domain") {
return;
}
try {
const related = await this._fetchRelatedMemoized(
context.itemType,
context.itemId
);
if (this._contextMatches(context)) {
this._quickBarContextRelated = related;
}
} catch {
if (this._contextMatches(context)) {
this._quickBarContextRelated = undefined;
}
}
};
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
@@ -36,6 +82,20 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
storeState(this.hass!);
});
this.addEventListener("hass-quick-bar-context", (ev) => {
this._quickBarContext =
ev.detail && "itemType" in ev.detail && "itemId" in ev.detail
? ev.detail
: undefined;
this._prefetchQuickBarContext(this._quickBarContext);
});
mainWindow.addEventListener(
"location-changed",
this._clearQuickBarContext
);
mainWindow.addEventListener("popstate", this._clearQuickBarContext);
mainWindow.addEventListener("hass-quick-bar-trigger", (ev) => {
switch (ev.detail.key) {
case "e":
@@ -61,6 +121,15 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
this._registerShortcut();
}
public disconnectedCallback() {
super.disconnectedCallback();
mainWindow.removeEventListener(
"location-changed",
this._clearQuickBarContext
);
mainWindow.removeEventListener("popstate", this._clearQuickBarContext);
}
private _registerShortcut() {
const shortcutManager = new ShortcutManager();
shortcutManager.add({
@@ -114,7 +183,11 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
}
e.preventDefault();
showQuickBar(this, { mode });
showQuickBar(this, {
mode,
contextItem: this._quickBarContext,
related: this._quickBarContextRelated,
});
}
private _showShortcutDialog(e: KeyboardEvent) {