Add navigation commands to quick bar commands (#7380)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Donnie 2020-11-11 02:46:53 -08:00 committed by GitHub
parent 216fce74f8
commit 2a57ffa615
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 205 additions and 40 deletions

View 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);

View File

@ -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;
};

View File

@ -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;
}
`,
];

View File

@ -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}`}

View File

@ -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"