From 4ad49ef07f65431d047094dda7eb6359fe4d8809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Wed, 8 Jun 2022 15:28:40 +0200 Subject: [PATCH] Move to supervisor store API (#12911) * Move to supervisor store API * Add supervisorApiCall helper to simplify functions * Do not consider ESPHome as custom repository * Home Assistant Community Add-ons is not custom --- .../addon-store/hassio-addon-repository.ts | 22 ++++------- hassio/src/addon-store/hassio-addon-store.ts | 12 +++--- hassio/src/components/hassio-filter-addons.ts | 6 +-- .../dialog-hassio-repositories.ts | 39 +++++++------------ src/data/supervisor/common.ts | 34 ++++++++++++++++ src/data/supervisor/store.ts | 36 ++++++++++------- 6 files changed, 88 insertions(+), 61 deletions(-) create mode 100644 src/data/supervisor/common.ts diff --git a/hassio/src/addon-store/hassio-addon-repository.ts b/hassio/src/addon-store/hassio-addon-repository.ts index 8d55dbcb8c..56c9ecaadf 100644 --- a/hassio/src/addon-store/hassio-addon-repository.ts +++ b/hassio/src/addon-store/hassio-addon-repository.ts @@ -6,10 +6,8 @@ import { atLeastVersion } from "../../../src/common/config/version"; import { navigate } from "../../../src/common/navigate"; import { caseInsensitiveStringCompare } from "../../../src/common/string/compare"; import "../../../src/components/ha-card"; -import { - HassioAddonInfo, - HassioAddonRepository, -} from "../../../src/data/hassio/addon"; +import { HassioAddonRepository } from "../../../src/data/hassio/addon"; +import { StoreAddon } from "../../../src/data/supervisor/store"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { HomeAssistant } from "../../../src/types"; import "../components/hassio-card-content"; @@ -23,20 +21,16 @@ class HassioAddonRepositoryEl extends LitElement { @property({ attribute: false }) public repo!: HassioAddonRepository; - @property({ attribute: false }) public addons!: HassioAddonInfo[]; + @property({ attribute: false }) public addons!: StoreAddon[]; @property() public filter!: string; - private _getAddons = memoizeOne( - (addons: HassioAddonInfo[], filter?: string) => { - if (filter) { - return filterAndSort(addons, filter); - } - return addons.sort((a, b) => - caseInsensitiveStringCompare(a.name, b.name) - ); + private _getAddons = memoizeOne((addons: StoreAddon[], filter?: string) => { + if (filter) { + return filterAndSort(addons, filter); } - ); + return addons.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name)); + }); protected render(): TemplateResult { const repo = this.repo; diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts index 4d1f5ba1bf..2c373a4e9f 100644 --- a/hassio/src/addon-store/hassio-addon-store.ts +++ b/hassio/src/addon-store/hassio-addon-store.ts @@ -14,15 +14,15 @@ import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; import { navigate } from "../../../src/common/navigate"; -import "../../../src/components/search-input"; import { extractSearchParam } from "../../../src/common/url/search-params"; import "../../../src/components/ha-button-menu"; import "../../../src/components/ha-icon-button"; +import "../../../src/components/search-input"; import { - HassioAddonInfo, HassioAddonRepository, reloadHassioAddons, } from "../../../src/data/hassio/addon"; +import { StoreAddon } from "../../../src/data/supervisor/store"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import "../../../src/layouts/hass-loading-screen"; import "../../../src/layouts/hass-subpage"; @@ -66,10 +66,10 @@ class HassioAddonStore extends LitElement { protected render(): TemplateResult { let repos: TemplateResult[] = []; - if (this.supervisor.addon.repositories) { + if (this.supervisor.store.repositories) { repos = this.addonRepositories( - this.supervisor.addon.repositories, - this.supervisor.addon.addons, + this.supervisor.store.repositories, + this.supervisor.store.addons, this._filter ); } @@ -145,7 +145,7 @@ class HassioAddonStore extends LitElement { private addonRepositories = memoizeOne( ( repositories: HassioAddonRepository[], - addons: HassioAddonInfo[], + addons: StoreAddon[], filter?: string ) => repositories.sort(sortRepos).map((repo) => { diff --git a/hassio/src/components/hassio-filter-addons.ts b/hassio/src/components/hassio-filter-addons.ts index ddb56188aa..6daa1ddbad 100644 --- a/hassio/src/components/hassio-filter-addons.ts +++ b/hassio/src/components/hassio-filter-addons.ts @@ -1,8 +1,8 @@ import Fuse from "fuse.js"; -import { HassioAddonInfo } from "../../../src/data/hassio/addon"; +import { StoreAddon } from "../../../src/data/supervisor/store"; -export function filterAndSort(addons: HassioAddonInfo[], filter: string) { - const options: Fuse.IFuseOptions = { +export function filterAndSort(addons: StoreAddon[], filter: string) { + const options: Fuse.IFuseOptions = { keys: ["name", "description", "slug"], isCaseSensitive: false, minMatchCharLength: 2, diff --git a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts index d42cb05a4b..e701640923 100644 --- a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts +++ b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts @@ -15,15 +15,18 @@ import "../../../../src/components/ha-circular-progress"; import { createCloseHeading } from "../../../../src/components/ha-dialog"; import "../../../../src/components/ha-icon-button"; import { - fetchHassioAddonsInfo, HassioAddonInfo, HassioAddonRepository, } from "../../../../src/data/hassio/addon"; import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import { setSupervisorOption } from "../../../../src/data/hassio/supervisor"; import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; import type { HomeAssistant } from "../../../../src/types"; import { HassioRepositoryDialogParams } from "./show-dialog-repositories"; +import { + addStoreRepository, + fetchStoreRepositories, + removeStoreRepository, +} from "../../../../src/data/supervisor/store"; @customElement("dialog-hassio-repositories") class HassioRepositoriesDialog extends LitElement { @@ -58,7 +61,13 @@ class HassioRepositoriesDialog extends LitElement { private _filteredRepositories = memoizeOne((repos: HassioAddonRepository[]) => repos - .filter((repo) => repo.slug !== "core" && repo.slug !== "local") + .filter( + (repo) => + repo.slug !== "core" && // The core add-ons repository + repo.slug !== "local" && // Locally managed add-ons + repo.slug !== "a0d7b954" && // Home Assistant Community Add-ons + repo.slug !== "5c53de3b" // The ESPHome repository + ) .sort((a, b) => caseInsensitiveStringCompare(a.name, b.name)) ); @@ -215,9 +224,7 @@ class HassioRepositoriesDialog extends LitElement { private async _loadData(): Promise { try { - const addonsinfo = await fetchHassioAddonsInfo(this.hass); - - this._repositories = addonsinfo.repositories; + this._repositories = await fetchStoreRepositories(this.hass); fireEvent(this, "supervisor-collection-refresh", { collection: "addon" }); } catch (err: any) { @@ -231,14 +238,9 @@ class HassioRepositoriesDialog extends LitElement { return; } this._processing = true; - const repositories = this._filteredRepositories(this._repositories!); - const newRepositories = repositories.map((repo) => repo.source); - newRepositories.push(input.value); try { - await setSupervisorOption(this.hass, { - addons_repositories: newRepositories, - }); + await addStoreRepository(this.hass, input.value); await this._loadData(); input.value = ""; @@ -250,19 +252,8 @@ class HassioRepositoriesDialog extends LitElement { private async _removeRepository(ev: Event) { const slug = (ev.currentTarget as any).slug; - const repositories = this._filteredRepositories(this._repositories!); - const repository = repositories.find((repo) => repo.slug === slug); - if (!repository) { - return; - } - const newRepositories = repositories - .map((repo) => repo.source) - .filter((repo) => repo !== repository.source); - try { - await setSupervisorOption(this.hass, { - addons_repositories: newRepositories, - }); + await removeStoreRepository(this.hass, slug); await this._loadData(); } catch (err: any) { this._error = extractApiErrorMessage(err); diff --git a/src/data/supervisor/common.ts b/src/data/supervisor/common.ts new file mode 100644 index 0000000000..b47f76bc4d --- /dev/null +++ b/src/data/supervisor/common.ts @@ -0,0 +1,34 @@ +import { atLeastVersion } from "../../common/config/version"; +import { HomeAssistant } from "../../types"; +import { hassioApiResultExtractor, HassioResponse } from "../hassio/common"; + +export interface SupervisorApiCallOptions { + method?: "get" | "post" | "delete"; + data?: Record; + timeout?: number; +} + +export const supervisorApiCall = async ( + hass: HomeAssistant, + endpoint: string, + options?: SupervisorApiCallOptions +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + // Websockets was added in 2021.2.4 + return hass.callWS({ + type: "supervisor/api", + endpoint, + method: options?.method || "get", + timeout: options?.timeout ?? null, + data: options?.data, + }); + } + return hassioApiResultExtractor( + await hass.callApi>( + // @ts-ignore + (options.method || "get").toUpperCase(), + `hassio${endpoint}`, + options?.data + ) + ); +}; diff --git a/src/data/supervisor/store.ts b/src/data/supervisor/store.ts index e9e2fbe57f..e02b46b56f 100644 --- a/src/data/supervisor/store.ts +++ b/src/data/supervisor/store.ts @@ -1,7 +1,6 @@ -import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { AddonRepository, AddonStage } from "../hassio/addon"; -import { hassioApiResultExtractor, HassioResponse } from "../hassio/common"; +import { supervisorApiCall } from "./common"; export interface StoreAddon { advanced: boolean; @@ -36,16 +35,25 @@ export interface SupervisorStore { export const fetchSupervisorStore = async ( hass: HomeAssistant -): Promise => { - if (atLeastVersion(hass.config.version, 2021, 2, 4)) { - return hass.callWS({ - type: "supervisor/api", - endpoint: "/store", - method: "get", - }); - } +): Promise => supervisorApiCall(hass, "/store"); - return hassioApiResultExtractor( - await hass.callApi>("GET", `hassio/store`) - ); -}; +export const fetchStoreRepositories = async ( + hass: HomeAssistant +): Promise => supervisorApiCall(hass, "/store/repositories"); + +export const addStoreRepository = async ( + hass: HomeAssistant, + repository: string +): Promise => + supervisorApiCall(hass, "/store/repositories", { + method: "post", + data: { repository }, + }); + +export const removeStoreRepository = async ( + hass: HomeAssistant, + repository: string +): Promise => + supervisorApiCall(hass, `/store/repositories/${repository}`, { + method: "delete", + });