From abf68afefbc9a3aeae1cc224ccf48dcf61aabf51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= <ludeeus@ludeeus.dev> Date: Sun, 16 Oct 2022 16:27:03 +0200 Subject: [PATCH] Add icon and overflow (#622) --- .../hacs-repository-owerflow-menu.ts | 186 ++++++++++++++++++ src/localize/languages/en.json | 1 + src/panels/hacs-experimental-panel.ts | 41 +++- src/panels/hacs-repository-panel.ts | 154 +-------------- 4 files changed, 230 insertions(+), 152 deletions(-) create mode 100644 src/components/hacs-repository-owerflow-menu.ts diff --git a/src/components/hacs-repository-owerflow-menu.ts b/src/components/hacs-repository-owerflow-menu.ts new file mode 100644 index 00000000..ca5ea256 --- /dev/null +++ b/src/components/hacs-repository-owerflow-menu.ts @@ -0,0 +1,186 @@ +import { + mdiAlert, + mdiAlertCircleOutline, + mdiArrowDownCircle, + mdiClose, + mdiGithub, + mdiInformation, + mdiLanguageJavascript, + mdiReload, +} from "@mdi/js"; +import memoizeOne from "memoize-one"; +import { mainWindow } from "../../homeassistant-frontend/src/common/dom/get_main_window"; +import { navigate } from "../../homeassistant-frontend/src/common/navigate"; +import "../../homeassistant-frontend/src/components/ha-icon-overflow-menu"; +import { getConfigEntries } from "../../homeassistant-frontend/src/data/config_entries"; +import { showConfirmationDialog } from "../../homeassistant-frontend/src/dialogs/generic/show-dialog-box"; +import { RepositoryBase } from "../data/repository"; +import { + deleteResource, + fetchResources, + repositoryUninstall, + repositoryUpdate, +} from "../data/websocket"; +import { HacsExperimentalPanel } from "../panels/hacs-experimental-panel"; +import { HacsRepositoryPanel } from "../panels/hacs-repository-panel"; + +export const repositoryMenuItems = memoizeOne( + (element: HacsRepositoryPanel | HacsExperimentalPanel, repository: RepositoryBase) => [ + ...(element.nodeName === "HACS-EXPERIMENTAL-PANEL" + ? [ + { + path: mdiInformation, + label: element.hacs.localize("common.show"), + action: () => navigate(`/hacs/repository/${repository.id}`), + }, + ] + : []), + { + path: mdiGithub, + label: element.hacs.localize("common.repository"), + action: () => + mainWindow.open(`https://github.com/${repository.full_name}`, "_blank", "noreferrer=true"), + }, + { + path: mdiArrowDownCircle, + label: element.hacs.localize("repository_card.update_information"), + action: async () => { + await repositoryUpdate(element.hass, String(repository.id)); + }, + }, + + ...(repository.installed_version + ? [ + { + path: mdiReload, + label: element.hacs.localize("repository_card.redownload"), + action: () => _downloadRepositoryDialog(element, repository.id), + hideForUninstalled: true, + }, + ] + : []), + ...(repository.category === "plugin" && repository.installed_version + ? [ + { + path: mdiLanguageJavascript, + label: element.hacs.localize("repository_card.open_source"), + action: () => + mainWindow.open( + `/hacsfiles/${repository.local_path.split("/").pop()}/${repository.file_name}`, + "_blank", + "noreferrer=true" + ), + }, + ] + : []), + { divider: true }, + { + path: mdiAlertCircleOutline, + label: element.hacs.localize("repository_card.open_issue"), + action: () => + mainWindow.open( + `https://github.com/${repository.full_name}/issues`, + "_blank", + "noreferrer=true" + ), + }, + ...(repository.id !== "172733314" && repository.installed_version + ? [ + { + path: mdiAlert, + label: element.hacs.localize("repository_card.report"), + action: () => + mainWindow.open( + `https://github.com/hacs/integration/issues/new?assignees=ludeeus&labels=flag&template=removal.yml&repo=${repository.full_name}&title=Request for removal of ${repository.full_name}`, + "_blank", + "noreferrer=true" + ), + warning: true, + }, + { + path: mdiClose, + label: element.hacs.localize("common.remove"), + action: async () => { + if (repository.category === "integration" && repository.config_flow) { + const configFlows = (await getConfigEntries(element.hass)).some( + (entry) => entry.domain === repository.domain + ); + if (configFlows) { + const ignore = await showConfirmationDialog(element, { + title: element.hacs.localize("dialog.configured.title"), + text: element.hacs.localize("dialog.configured.message", { + name: repository.name, + }), + dismissText: element.hacs.localize("common.ignore"), + confirmText: element.hacs.localize("common.navigate"), + confirm: () => { + navigate("/config/integrations", { replace: true }); + }, + }); + if (ignore) { + return; + } + } + } + element.dispatchEvent( + new CustomEvent("hacs-dialog", { + detail: { + type: "progress", + title: element.hacs.localize("dialog.remove.title"), + confirmText: element.hacs.localize("dialog.remove.title"), + content: element.hacs.localize("dialog.remove.message", { + name: repository.name, + }), + confirm: async () => { + await _repositoryRemove(element, repository); + }, + }, + bubbles: true, + composed: true, + }) + ); + }, + warning: true, + }, + ] + : []), + ] +); + +const _downloadRepositoryDialog = ( + element: HacsRepositoryPanel | HacsExperimentalPanel, + repositoryId: string +) => { + element.dispatchEvent( + new CustomEvent("hacs-dialog", { + detail: { + type: "download", + repository: repositoryId, + }, + bubbles: true, + composed: true, + }) + ); +}; + +const _repositoryRemove = async ( + element: HacsRepositoryPanel | HacsExperimentalPanel, + repository: RepositoryBase +) => { + if (repository.category === "plugin" && element.hacs.info?.lovelace_mode !== "yaml") { + const resources = await fetchResources(element.hass); + resources + .filter((resource) => + resource.url.startsWith( + `/hacsfiles/${repository.full_name.split("/")[1]}/${repository.file_name}` + ) + ) + .forEach(async (resource) => { + await deleteResource(element.hass, String(resource.id)); + }); + } + await repositoryUninstall(element.hass, String(repository.id)); + if (element.nodeName === "HACS-REPOSITORY-PANEL") { + history.back(); + } +}; diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 8ff9a899..b6633c32 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -5,6 +5,7 @@ "cancel": "Cancel", "close": "Close", "download": "Download", + "explore": "Explore & download repositories", "ignore": "Ignore", "integration_plural": "Integrations", "integration": "Integration", diff --git a/src/panels/hacs-experimental-panel.ts b/src/panels/hacs-experimental-panel.ts index 2dd134ba..988cba9f 100644 --- a/src/panels/hacs-experimental-panel.ts +++ b/src/panels/hacs-experimental-panel.ts @@ -26,14 +26,15 @@ import type { import "../../homeassistant-frontend/src/components/ha-button-menu"; import "../../homeassistant-frontend/src/components/ha-check-list-item"; -import "../../homeassistant-frontend/src/components/ha-chip"; import "../../homeassistant-frontend/src/components/ha-fab"; import "../../homeassistant-frontend/src/components/ha-menu-button"; import "../../homeassistant-frontend/src/components/ha-svg-icon"; import { haStyle } from "../../homeassistant-frontend/src/resources/styles"; import type { HomeAssistant, Route } from "../../homeassistant-frontend/src/types"; +import { brandsUrl } from "../../homeassistant-frontend/src/util/brands-url"; import { showDialogAbout } from "../components/dialogs/hacs-about-dialog"; import { hacsIcon } from "../components/hacs-icon"; +import { repositoryMenuItems } from "../components/hacs-repository-owerflow-menu"; import "../components/hacs-tabs-subpage-data-table"; import type { Hacs } from "../data/hacs"; import type { RepositoryBase } from "../data/repository"; @@ -206,7 +207,7 @@ export class HacsExperimentalPanel extends LitElement { ${this.section === "entry" ? html` <a href="/hacs/explore" slot="fab"> - <ha-fab .label=${this.hacs.localize("store.explore")} .extended=${!this.narrow}> + <ha-fab .label=${this.hacs.localize("common.explore")} .extended=${!this.narrow}> <ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon> </ha-fab ></a> ` @@ -234,6 +235,26 @@ export class HacsExperimentalPanel extends LitElement { narrow: boolean, tableColumnsOptions: TableColumnsOptions ): DataTableColumnContainer<RepositoryBase> => ({ + icon: { + title: "", + label: this.hass.localize("ui.panel.config.lovelace.dashboards.picker.headers.icon"), + hidden: this.narrow || this.section !== "entry", + type: "icon", + template: (_, repository: RepositoryBase) => + html` + <img + style="height: 32px; width: 32px" + slot="item-icon" + src=${brandsUrl({ + domain: repository.domain || "github", + type: "icon", + useFallback: true, + darkOptimized: this.hass.themes?.darkMode, + })} + referrerpolicy="no-referrer" + /> + `, + }, name: { ...defaultKeyData, title: this.hacs.localize("column.name"), @@ -282,6 +303,7 @@ export class HacsExperimentalPanel extends LitElement { hidden: narrow || !tableColumnsOptions[this.section].category, sortable: true, width: "10%", + template: (category: string) => this.hacs.localize(`common.${category}`), }, authors: defaultKeyData, description: defaultKeyData, @@ -289,6 +311,21 @@ export class HacsExperimentalPanel extends LitElement { full_name: defaultKeyData, id: defaultKeyData, topics: defaultKeyData, + actions: { + title: "", + width: this.narrow ? undefined : "10%", + hidden: this.section !== "entry", + type: "overflow-menu", + template: (_, repository: RepositoryBase) => + html` + <ha-icon-overflow-menu + .hass=${this.hass} + narrow + .items=${repositoryMenuItems(this, repository)} + > + </ha-icon-overflow-menu> + `, + }, }) ); diff --git a/src/panels/hacs-repository-panel.ts b/src/panels/hacs-repository-panel.ts index 7537aaeb..83561d0e 100644 --- a/src/panels/hacs-repository-panel.ts +++ b/src/panels/hacs-repository-panel.ts @@ -1,44 +1,28 @@ import { mdiAccount, - mdiAlert, - mdiAlertCircleOutline, mdiArrowDownBold, - mdiArrowDownCircle, - mdiClose, mdiCube, mdiDownload, mdiExclamationThick, - mdiGithub, - mdiLanguageJavascript, - mdiReload, mdiStar, } from "@mdi/js"; import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { mainWindow } from "../../homeassistant-frontend/src/common/dom/get_main_window"; -import { navigate } from "../../homeassistant-frontend/src/common/navigate"; import { extractSearchParamsObject } from "../../homeassistant-frontend/src/common/url/search-params"; import "../../homeassistant-frontend/src/components/ha-chip"; import "../../homeassistant-frontend/src/components/ha-fab"; -import "../../homeassistant-frontend/src/components/ha-icon-overflow-menu"; -import { getConfigEntries } from "../../homeassistant-frontend/src/data/config_entries"; import { showConfirmationDialog } from "../../homeassistant-frontend/src/dialogs/generic/show-dialog-box"; import "../../homeassistant-frontend/src/layouts/hass-error-screen"; import "../../homeassistant-frontend/src/layouts/hass-loading-screen"; import "../../homeassistant-frontend/src/layouts/hass-subpage"; import { HomeAssistant, Route } from "../../homeassistant-frontend/src/types"; import "../components/hacs-link"; +import { repositoryMenuItems } from "../components/hacs-repository-owerflow-menu"; import { Hacs } from "../data/hacs"; import { fetchRepositoryInformation, RepositoryBase, RepositoryInfo } from "../data/repository"; -import { - deleteResource, - fetchResources, - getRepositories, - repositoryAdd, - repositoryUninstall, - repositoryUpdate, -} from "../data/websocket"; +import { getRepositories, repositoryAdd } from "../data/websocket"; import { HacsStyles } from "../styles/hacs-common-style"; import { markdown } from "../tools/markdown/markdown"; @@ -198,82 +182,10 @@ export class HacsRepositoryPanel extends LitElement { hasFab > <ha-icon-overflow-menu + .hass=${this.hass} slot="toolbar-icon" narrow - .hass=${this.hass} - .items=${[ - { - path: mdiGithub, - label: this.hacs.localize("common.repository"), - action: () => - mainWindow.open( - `https://github.com/${this._repository!.full_name}`, - "_blank", - "noreferrer=true" - ), - }, - { - path: mdiArrowDownCircle, - label: this.hacs.localize("repository_card.update_information"), - action: () => this._refreshReopsitoryInfo(), - }, - { - path: mdiReload, - label: this.hacs.localize("repository_card.redownload"), - action: () => this._downloadRepositoryDialog(), - hideForUninstalled: true, - }, - { - category: "plugin", - hideForUninstalled: true, - path: mdiLanguageJavascript, - label: this.hacs.localize("repository_card.open_source"), - action: () => - mainWindow.open( - `/hacsfiles/${this._repository!.local_path.split("/").pop()}/${ - this._repository!.file_name - }`, - "_blank", - "noreferrer=true" - ), - }, - { - path: mdiAlertCircleOutline, - label: this.hacs.localize("repository_card.open_issue"), - action: () => - mainWindow.open( - `https://github.com/${this._repository!.full_name}/issues`, - "_blank", - "noreferrer=true" - ), - }, - { - hideForId: "172733314", - path: mdiAlert, - label: this.hacs.localize("repository_card.report"), - hideForUninstalled: true, - action: () => - mainWindow.open( - `https://github.com/hacs/integration/issues/new?assignees=ludeeus&labels=flag&template=removal.yml&repo=${ - this._repository!.full_name - }&title=Request for removal of ${this._repository!.full_name}`, - "_blank", - "noreferrer=true" - ), - }, - { - hideForId: "172733314", - hideForUninstalled: true, - path: mdiClose, - label: this.hacs.localize("common.remove"), - action: () => this._removeRepositoryDialog(), - }, - ].filter( - (entry) => - (!entry.category || this._repository!.category === entry.category) && - (!entry.hideForId || String(this._repository!.id) !== entry.hideForId) && - (!entry.hideForUninstalled || this._repository!.installed_version) - )} + .items=${repositoryMenuItems(this, this._repository)} > </ha-icon-overflow-menu> <div class="content"> @@ -344,64 +256,6 @@ export class HacsRepositoryPanel extends LitElement { ); } - private async _removeRepositoryDialog() { - if (this._repository!.category === "integration" && this._repository!.config_flow) { - const configFlows = (await getConfigEntries(this.hass)).some( - (entry) => entry.domain === this._repository!.domain - ); - if (configFlows) { - const ignore = await showConfirmationDialog(this, { - title: this.hacs.localize("dialog.configured.title"), - text: this.hacs.localize("dialog.configured.message", { name: this._repository!.name }), - dismissText: this.hacs.localize("common.ignore"), - confirmText: this.hacs.localize("common.navigate"), - confirm: () => { - navigate("/config/integrations", { replace: true }); - }, - }); - if (ignore) { - return; - } - } - } - this.dispatchEvent( - new CustomEvent("hacs-dialog", { - detail: { - type: "progress", - title: this.hacs.localize("dialog.remove.title"), - confirmText: this.hacs.localize("dialog.remove.title"), - content: this.hacs.localize("dialog.remove.message", { name: this._repository!.name }), - confirm: async () => { - await this._repositoryRemove(); - }, - }, - bubbles: true, - composed: true, - }) - ); - } - - private async _repositoryRemove() { - if (this._repository!.category === "plugin" && this.hacs.info?.lovelace_mode !== "yaml") { - const resources = await fetchResources(this.hass); - resources - .filter((resource) => - resource.url.startsWith( - `/hacsfiles/${this._repository!.full_name.split("/")[1]}/${this._repository!.file_name}` - ) - ) - .forEach(async (resource) => { - await deleteResource(this.hass, String(resource.id)); - }); - } - await repositoryUninstall(this.hass, String(this._repository!.id)); - history.back(); - } - - private async _refreshReopsitoryInfo() { - await repositoryUpdate(this.hass, String(this._repository!.id)); - } - static get styles() { return [ HacsStyles,