mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-25 13:57:21 +00:00
Add navigation commands to quick bar commands (#7380)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
216fce74f8
commit
2a57ffa615
18
src/common/config/can_show_page.ts
Normal file
18
src/common/config/can_show_page.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { isComponentLoaded } from "./is_component_loaded";
|
||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) => {
|
||||
return (
|
||||
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
||||
!hideAdvancedPage(hass, page)
|
||||
);
|
||||
};
|
||||
|
||||
const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
!page.component || isComponentLoaded(hass, page.component);
|
||||
const isCore = (page: PageNavigation) => page.core;
|
||||
const isAdvancedPage = (page: PageNavigation) => page.advancedOnly;
|
||||
const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced;
|
||||
const hideAdvancedPage = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
isAdvancedPage(page) && !userWantsAdvanced(hass);
|
@ -21,6 +21,18 @@ export const getDefaultPanel = (hass: HomeAssistant): PanelInfo =>
|
||||
? hass.panels[hass.defaultPanel]
|
||||
: hass.panels[DEFAULT_PANEL];
|
||||
|
||||
export const getPanelNameTranslationKey = (panel: PanelInfo): string => {
|
||||
if (panel.url_path === "lovelace") {
|
||||
return "panel.states";
|
||||
}
|
||||
|
||||
if (panel.url_path === "profile") {
|
||||
return "panel.profile";
|
||||
}
|
||||
|
||||
return `panel.${panel.title}`;
|
||||
};
|
||||
|
||||
export const getPanelTitle = (hass: HomeAssistant): string | undefined => {
|
||||
if (!hass.panels) {
|
||||
return undefined;
|
||||
@ -34,13 +46,20 @@ export const getPanelTitle = (hass: HomeAssistant): string | undefined => {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (panel.url_path === "lovelace") {
|
||||
return hass.localize("panel.states");
|
||||
}
|
||||
const translationKey = getPanelNameTranslationKey(panel);
|
||||
|
||||
if (panel.url_path === "profile") {
|
||||
return hass.localize("panel.profile");
|
||||
}
|
||||
|
||||
return hass.localize(`panel.${panel.title}`) || panel.title || undefined;
|
||||
return hass.localize(translationKey) || panel.title || undefined;
|
||||
};
|
||||
|
||||
export const getPanelIcon = (panel: PanelInfo): string | null => {
|
||||
if (!panel.icon) {
|
||||
switch (panel.component_name) {
|
||||
case "profile":
|
||||
return "hass:account";
|
||||
case "lovelace":
|
||||
return "hass:view-dashboard";
|
||||
}
|
||||
}
|
||||
|
||||
return panel.icon;
|
||||
};
|
||||
|
@ -41,19 +41,36 @@ import {
|
||||
showConfirmationDialog,
|
||||
} from "../generic/show-dialog-box";
|
||||
import { QuickBarParams } from "./show-dialog-quick-bar";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import { configSections } from "../../panels/config/ha-panel-config";
|
||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||
import { canShowPage } from "../../common/config/can_show_page";
|
||||
import { getPanelIcon, getPanelNameTranslationKey } from "../../data/panel";
|
||||
|
||||
const DEFAULT_NAVIGATION_ICON = "hass:arrow-right-circle";
|
||||
const DEFAULT_SERVER_ICON = "hass:server";
|
||||
|
||||
interface QuickBarItem extends ScorableTextItem {
|
||||
icon: string;
|
||||
icon?: string;
|
||||
iconPath?: string;
|
||||
action(data?: any): void;
|
||||
}
|
||||
|
||||
interface QuickBarNavigationItem extends QuickBarItem {
|
||||
path: string;
|
||||
}
|
||||
|
||||
interface NavigationInfo extends PageNavigation {
|
||||
text: string;
|
||||
}
|
||||
|
||||
@customElement("ha-quick-bar")
|
||||
export class QuickBar extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@internalProperty() private _commandItems: QuickBarItem[] = [];
|
||||
@internalProperty() private _commandItems?: QuickBarItem[];
|
||||
|
||||
@internalProperty() private _entityItems: QuickBarItem[] = [];
|
||||
@internalProperty() private _entityItems?: QuickBarItem[];
|
||||
|
||||
@internalProperty() private _items?: QuickBarItem[] = [];
|
||||
|
||||
@ -73,8 +90,7 @@ export class QuickBar extends LitElement {
|
||||
|
||||
public async showDialog(params: QuickBarParams) {
|
||||
this._commandMode = params.commandMode || this._toggleIfAlreadyOpened();
|
||||
this._commandItems = this._generateCommandItems();
|
||||
this._entityItems = this._generateEntityItems();
|
||||
this._initializeItemsIfNeeded();
|
||||
this._opened = true;
|
||||
}
|
||||
|
||||
@ -158,6 +174,14 @@ export class QuickBar extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _initializeItemsIfNeeded() {
|
||||
if (this._commandMode) {
|
||||
this._commandItems = this._commandItems || this._generateCommandItems();
|
||||
} else {
|
||||
this._entityItems = this._entityItems || this._generateEntityItems();
|
||||
}
|
||||
}
|
||||
|
||||
private _handleOpened() {
|
||||
this._setFilteredItems();
|
||||
this.updateComplete.then(() => {
|
||||
@ -182,10 +206,15 @@ export class QuickBar extends LitElement {
|
||||
.twoline=${Boolean(item.altText)}
|
||||
.item=${item}
|
||||
index=${ifDefined(index)}
|
||||
graphic="avatar"
|
||||
graphic="icon"
|
||||
>
|
||||
<ha-icon .icon=${item.icon} slot="graphic"></ha-icon>
|
||||
<span class="item-text">${item.text}</span>
|
||||
${item.iconPath
|
||||
? html`<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
slot="graphic"
|
||||
></ha-svg-icon>`
|
||||
: html`<ha-icon .icon=${item.icon} slot="graphic"></ha-icon>`}
|
||||
${item.text}
|
||||
${item.altText
|
||||
? html`
|
||||
<span slot="secondary" class="item-text secondary"
|
||||
@ -253,6 +282,8 @@ export class QuickBar extends LitElement {
|
||||
if (oldCommandMode !== this._commandMode) {
|
||||
this._items = undefined;
|
||||
this._focusSet = false;
|
||||
|
||||
this._initializeItemsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,10 +311,22 @@ export class QuickBar extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _generateEntityItems(): QuickBarItem[] {
|
||||
return Object.keys(this.hass.states)
|
||||
.map((entityId) => ({
|
||||
text: computeStateName(this.hass.states[entityId]),
|
||||
altText: entityId,
|
||||
icon: domainIcon(computeDomain(entityId), this.hass.states[entityId]),
|
||||
action: () => fireEvent(this, "hass-more-info", { entityId }),
|
||||
}))
|
||||
.sort((a, b) => compare(a.text.toLowerCase(), b.text.toLowerCase()));
|
||||
}
|
||||
|
||||
private _generateCommandItems(): QuickBarItem[] {
|
||||
return [
|
||||
...this._generateReloadCommands(),
|
||||
...this._generateServerControlCommands(),
|
||||
...this._generateNavigationCommands(),
|
||||
].sort((a, b) => compare(a.text.toLowerCase(), b.text.toLowerCase()));
|
||||
}
|
||||
|
||||
@ -316,7 +359,7 @@ export class QuickBar extends LitElement {
|
||||
`ui.dialogs.quick-bar.commands.server_control.${action}`
|
||||
)
|
||||
),
|
||||
icon: "hass:server",
|
||||
icon: DEFAULT_SERVER_ICON,
|
||||
action: () => this.hass.callService("homeassistant", action),
|
||||
},
|
||||
this.hass.localize("ui.dialogs.generic.ok")
|
||||
@ -324,6 +367,79 @@ export class QuickBar extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
private _generateNavigationCommands(): QuickBarItem[] {
|
||||
const panelItems = this._generateNavigationPanelCommands();
|
||||
const sectionItems = this._generateNavigationConfigSectionCommands();
|
||||
|
||||
return this._withNavigationActions([...panelItems, ...sectionItems]);
|
||||
}
|
||||
|
||||
private _generateNavigationPanelCommands(): Omit<
|
||||
QuickBarNavigationItem,
|
||||
"action"
|
||||
>[] {
|
||||
return Object.keys(this.hass.panels).map((panelKey) => {
|
||||
const panel = this.hass.panels[panelKey];
|
||||
const translationKey = getPanelNameTranslationKey(panel);
|
||||
|
||||
const text = this.hass.localize(
|
||||
"ui.dialogs.quick-bar.commands.navigation.navigate_to",
|
||||
"panel",
|
||||
this.hass.localize(translationKey) || panel.title || panel.url_path
|
||||
);
|
||||
|
||||
return {
|
||||
text,
|
||||
icon: getPanelIcon(panel) || DEFAULT_NAVIGATION_ICON,
|
||||
path: `/${panel.url_path}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private _generateNavigationConfigSectionCommands(): Partial<
|
||||
QuickBarNavigationItem
|
||||
>[] {
|
||||
const items: NavigationInfo[] = [];
|
||||
|
||||
for (const sectionKey of Object.keys(configSections)) {
|
||||
for (const page of configSections[sectionKey]) {
|
||||
if (canShowPage(this.hass, page)) {
|
||||
if (page.component) {
|
||||
const info = this._getNavigationInfoFromConfig(page);
|
||||
|
||||
if (info) {
|
||||
items.push(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private _getNavigationInfoFromConfig(
|
||||
page: PageNavigation
|
||||
): NavigationInfo | undefined {
|
||||
if (page.component) {
|
||||
const shortCaption = this.hass.localize(
|
||||
`ui.dialogs.quick-bar.commands.navigation.${page.component}`
|
||||
);
|
||||
|
||||
if (page.translationKey) {
|
||||
const caption = this.hass.localize(
|
||||
"ui.dialogs.quick-bar.commands.navigation.navigate_to_config",
|
||||
"panel",
|
||||
shortCaption
|
||||
);
|
||||
|
||||
return { ...page, text: caption };
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _generateConfirmationCommand(
|
||||
item: QuickBarItem,
|
||||
confirmText: ConfirmationDialogParams["confirmText"]
|
||||
@ -338,15 +454,13 @@ export class QuickBar extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
private _generateEntityItems(): QuickBarItem[] {
|
||||
return Object.keys(this.hass.states)
|
||||
.map((entityId) => ({
|
||||
text: computeStateName(this.hass.states[entityId]) || entityId,
|
||||
altText: entityId,
|
||||
icon: domainIcon(computeDomain(entityId), this.hass.states[entityId]),
|
||||
action: () => fireEvent(this, "hass-more-info", { entityId }),
|
||||
}))
|
||||
.sort((a, b) => compare(a.text.toLowerCase(), b.text.toLowerCase()));
|
||||
private _withNavigationActions(items) {
|
||||
return items.map(({ text, icon, iconPath, path }) => ({
|
||||
text,
|
||||
icon,
|
||||
iconPath,
|
||||
action: () => navigate(this, path),
|
||||
}));
|
||||
}
|
||||
|
||||
private _toggleIfAlreadyOpened() {
|
||||
@ -388,16 +502,14 @@ export class QuickBar extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
ha-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
ha-icon,
|
||||
ha-svg-icon {
|
||||
color: var(--primary-text-color);
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
ha-svg-icon.prefix {
|
||||
margin: 8px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.uni-virtualizer-host {
|
||||
@ -414,10 +526,7 @@ export class QuickBar extends LitElement {
|
||||
|
||||
mwc-list-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
margin-left: 16px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { canShowPage } from "../../../common/config/can_show_page";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-next";
|
||||
import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
|
||||
@ -27,10 +27,7 @@ class HaConfigNavigation extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
${this.pages.map((page) =>
|
||||
(!page.component ||
|
||||
page.core ||
|
||||
isComponentLoaded(this.hass, page.component)) &&
|
||||
(!page.advancedOnly || this.showAdvanced)
|
||||
canShowPage(this.hass, page)
|
||||
? html`
|
||||
<a
|
||||
href=${`/config/${page.component}`}
|
||||
|
@ -499,6 +499,28 @@
|
||||
"perform_action": "{action} Server",
|
||||
"restart": "[%key:ui::panel::config::server_control::section::server_management::restart%]",
|
||||
"stop": "[%key:ui::panel::config::server_control::section::server_management::stop%]"
|
||||
},
|
||||
"navigation": {
|
||||
"navigate_to": "Navigate to {panel}",
|
||||
"navigate_to_config": "Navigate to {panel} configuration",
|
||||
"logs": "[%key:ui::panel::config::logs::caption%]",
|
||||
"automation": "[%key:ui::panel::config::automation::caption%]",
|
||||
"script": "[%key:ui::panel::config::script::caption%]",
|
||||
"integrations": "[%key:ui::panel::config::integrations::caption%]",
|
||||
"areas": "[%key:ui::panel::config::areas::caption%]",
|
||||
"scene": "[%key:ui::panel::config::scene::caption%]",
|
||||
"helpers": "[%key:ui::panel::config::helpers::caption%]",
|
||||
"tags": "[%key:ui::panel::config::tags::caption%]",
|
||||
"person": "[%key:ui::panel::config::person::caption%]",
|
||||
"devices": "[%key:ui::panel::config::devices::caption%]",
|
||||
"entities": "[%key:ui::panel::config::entities::caption%]",
|
||||
"lovelace": "[%key:ui::panel::config::lovelace::caption%]",
|
||||
"core": "[%key:ui::panel::config::core::caption%]",
|
||||
"zone": "[%key:ui::panel::config::zone::caption%]",
|
||||
"users": "[%key:ui::panel::config::users::caption%]",
|
||||
"info": "[%key:ui::panel::config::info::caption%]",
|
||||
"customize": "[%key:ui::panel::config::customize::caption%]",
|
||||
"server_control": "[%key:ui::panel::config::server_control::caption%]"
|
||||
}
|
||||
},
|
||||
"filter_placeholder": "Entity Filter"
|
||||
|
Loading…
x
Reference in New Issue
Block a user