mirror of
https://github.com/home-assistant/frontend.git
synced 2026-01-23 16:07:57 +00:00
Compare commits
4 Commits
dev
...
quickbar-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eef5ff5e67 | ||
|
|
3192e09c0a | ||
|
|
078cc5cf0d | ||
|
|
a751bd40b4 |
@@ -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___";
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
type ActionCommandComboBoxItem,
|
||||
type NavigationComboBoxItem,
|
||||
} from "../../data/quick_bar";
|
||||
import type { RelatedResult } from "../../data/search";
|
||||
import {
|
||||
multiTermSortedSearch,
|
||||
type FuseWeightedKey,
|
||||
@@ -70,6 +71,8 @@ export class QuickBar extends LitElement {
|
||||
|
||||
@state() private _opened = false;
|
||||
|
||||
@state() private _relatedResult?: RelatedResult;
|
||||
|
||||
@query("ha-picker-combo-box") private _comboBox?: HaPickerComboBox;
|
||||
|
||||
private get _showEntityId() {
|
||||
@@ -91,6 +94,13 @@ export class QuickBar extends LitElement {
|
||||
this._initialize();
|
||||
this._selectedSection = params.mode;
|
||||
this._hint = params.hint;
|
||||
|
||||
this._relatedResult = params.related;
|
||||
|
||||
if (!params.contextItem) {
|
||||
this._relatedResult = undefined;
|
||||
}
|
||||
|
||||
this._open = true;
|
||||
}
|
||||
|
||||
@@ -377,6 +387,7 @@ export class QuickBar extends LitElement {
|
||||
this._selectedSection = section as QuickBarSection | undefined;
|
||||
return this._getItemsMemoized(
|
||||
this._configEntryLookup,
|
||||
this._relatedResult,
|
||||
searchString,
|
||||
this._selectedSection
|
||||
);
|
||||
@@ -385,10 +396,12 @@ export class QuickBar extends LitElement {
|
||||
private _getItemsMemoized = memoizeOne(
|
||||
(
|
||||
configEntryLookup: Record<string, ConfigEntry>,
|
||||
relatedResult: RelatedResult | undefined,
|
||||
filter?: string,
|
||||
section?: QuickBarSection
|
||||
) => {
|
||||
const items: (string | PickerComboBoxItem)[] = [];
|
||||
const relatedIdSets = this._getRelatedIdSets(relatedResult);
|
||||
|
||||
if (!section || section === "navigate") {
|
||||
let navigateItems = this._generateNavigationCommandsMemoized(
|
||||
@@ -436,17 +449,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 +488,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 +522,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 +555,12 @@ export class QuickBar extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
private _getRelatedIdSets = memoizeOne((related?: RelatedResult) => ({
|
||||
entities: new Set(related?.entity || []),
|
||||
devices: new Set(related?.device || []),
|
||||
areas: new Set(related?.area || []),
|
||||
}));
|
||||
|
||||
private _getEntitiesMemoized = memoizeOne((hass: HomeAssistant) =>
|
||||
getEntities(
|
||||
hass,
|
||||
@@ -609,6 +660,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
|
||||
|
||||
@@ -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,17 @@ export type QuickBarSection =
|
||||
| "navigate"
|
||||
| "command";
|
||||
|
||||
export interface QuickBarContextItem {
|
||||
itemType: ItemType;
|
||||
itemId: string;
|
||||
}
|
||||
|
||||
export interface QuickBarParams {
|
||||
entityFilter?: string;
|
||||
mode?: QuickBarSection;
|
||||
hint?: string;
|
||||
contextItem?: QuickBarContextItem;
|
||||
related?: RelatedResult;
|
||||
}
|
||||
|
||||
export const loadQuickBar = () => import("./ha-quick-bar");
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 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: QuickBarContextItem["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) {
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user