diff --git a/console/package.json b/console/package.json index 90367fa..f52c0f2 100644 --- a/console/package.json +++ b/console/package.json @@ -17,6 +17,7 @@ "dayjs": "^1.11.9", "github-markdown-css": "^5.2.0", "pretty-bytes": "^6.1.1", + "qs": "^6.11.2", "semver": "^7.5.4", "vue": "^3.3.4", "vue-i18n": "^9.2.2" diff --git a/console/pnpm-lock.yaml b/console/pnpm-lock.yaml index d2c75ca..8ffe8ef 100644 --- a/console/pnpm-lock.yaml +++ b/console/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: pretty-bytes: specifier: ^6.1.1 version: 6.1.1 + qs: + specifier: ^6.11.2 + version: 6.11.2 semver: specifier: ^7.5.4 version: 7.5.4 @@ -1251,7 +1254,6 @@ packages: dependencies: function-bind: 1.1.1 get-intrinsic: 1.1.1 - dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -2155,7 +2157,6 @@ packages: /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} @@ -2181,7 +2182,6 @@ packages: function-bind: 1.1.1 has: 1.0.3 has-symbols: 1.0.3 - dev: true /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} @@ -2301,7 +2301,6 @@ packages: /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - dev: true /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} @@ -2315,7 +2314,6 @@ packages: engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 - dev: true /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} @@ -2871,7 +2869,6 @@ packages: /object-inspect@1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} - dev: true /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -3160,6 +3157,13 @@ packages: engines: {node: '>=6'} dev: true + /qs@6.11.2: + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -3332,7 +3336,6 @@ packages: call-bind: 1.0.2 get-intrinsic: 1.1.1 object-inspect: 1.12.2 - dev: true /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} diff --git a/console/src/composables/use-app-compare.ts b/console/src/composables/use-app-compare.ts index f6ffbce..aa84bb1 100644 --- a/console/src/composables/use-app-compare.ts +++ b/console/src/composables/use-app-compare.ts @@ -1,11 +1,10 @@ import { AppType, STORE_APP_ID } from "@/constant"; import type { ApplicationSearchResult } from "@/types"; -import type { Plugin, PluginList, Theme, ThemeList } from "@halo-dev/api-client"; -import { useQuery } from "@tanstack/vue-query"; -import axios from "axios"; import { computed, type Ref } from "vue"; import semver from "semver"; import { useHaloVersion } from "./use-halo-version"; +import { useFetchInstalledPlugins } from "./use-plugin"; +import { useFetchInstalledThemes } from "./use-theme"; export function useAppCompare(app: Ref) { const { haloVersion } = useHaloVersion(); @@ -14,23 +13,8 @@ export function useAppCompare(app: Ref) { return app.value?.application.spec.type; }); - const { data: installedPlugins } = useQuery({ - queryKey: ["plugins"], - queryFn: async () => { - const { data } = await axios.get(`/apis/api.console.halo.run/v1alpha1/plugins`); - return data.items; - }, - enabled: computed(() => appType.value === AppType.PLUGIN), - }); - - const { data: installedThemes } = useQuery({ - queryKey: ["themes"], - queryFn: async () => { - const { data } = await axios.get("/apis/api.console.halo.run/v1alpha1/themes?uninstalled=false"); - return data.items; - }, - enabled: computed(() => appType.value === AppType.THEME), - }); + const { installedPlugins } = useFetchInstalledPlugins(computed(() => appType.value === AppType.PLUGIN)); + const { installedThemes } = useFetchInstalledThemes(computed(() => appType.value === AppType.THEME)); const matchedPlugin = computed(() => { if (appType.value === AppType.PLUGIN) { diff --git a/console/src/composables/use-app-download.ts b/console/src/composables/use-app-download.ts index 6f1dc89..e09699c 100644 --- a/console/src/composables/use-app-download.ts +++ b/console/src/composables/use-app-download.ts @@ -262,12 +262,13 @@ export function useAppDownload(app: Ref) { function handleClearQueryCache() { if (appType.value === "THEME") { queryClient.invalidateQueries({ queryKey: ["installed-themes"] }); - queryClient.invalidateQueries({ queryKey: ["themes"] }); + queryClient.invalidateQueries({ queryKey: ["store-installed-themes"] }); return; } if (appType.value === "PLUGIN") { queryClient.invalidateQueries({ queryKey: ["plugins"] }); + queryClient.invalidateQueries({ queryKey: ["store-installed-plugins"] }); } } diff --git a/console/src/composables/use-plugin-version.ts b/console/src/composables/use-plugin-version.ts index b4c0153..564dc6f 100644 --- a/console/src/composables/use-plugin-version.ts +++ b/console/src/composables/use-plugin-version.ts @@ -2,29 +2,35 @@ import type { ApplicationSearchResult, ListResponse } from "@/types"; import storeApiClient from "@/utils/store-api-client"; import type { Plugin } from "@halo-dev/api-client"; import { useQuery } from "@tanstack/vue-query"; -import { computed, type Ref } from "vue"; +import { computed, ref, type Ref } from "vue"; import semver from "semver"; import { useHaloVersion } from "./use-halo-version"; import { STORE_APP_ID } from "@/constant"; +import { useFetchInstalledPlugins } from "./use-plugin"; export function usePluginVersion(plugin: Ref) { const { haloVersion } = useHaloVersion(); - // TODO: 可能需要专门的最新版本应用列表接口 + const { installedPlugins } = useFetchInstalledPlugins(ref(true)); + const { data: storePlugins } = useQuery>({ queryKey: ["plugin-apps"], queryFn: async () => { + const appIds = installedPlugins.value?.map((plugin) => plugin.metadata.annotations?.[STORE_APP_ID]) || []; + const { data } = await storeApiClient.get>( `/apis/api.store.halo.run/v1alpha1/applications`, { params: { type: "PLUGIN", + names: appIds, }, } ); return data; }, staleTime: 1000, + enabled: computed(() => !!installedPlugins.value?.length), }); const matchedApp = computed(() => { diff --git a/console/src/composables/use-plugin.ts b/console/src/composables/use-plugin.ts new file mode 100644 index 0000000..35b802f --- /dev/null +++ b/console/src/composables/use-plugin.ts @@ -0,0 +1,20 @@ +import { STORE_APP_ID } from "@/constant"; +import { apiClient } from "@/utils/api-client"; +import type { Plugin } from "@halo-dev/api-client"; +import { useQuery } from "@tanstack/vue-query"; +import type { Ref } from "vue"; + +export function useFetchInstalledPlugins(enabled: Ref) { + const { data: installedPlugins } = useQuery({ + queryKey: ["store-installed-plugins"], + queryFn: async () => { + const { data } = await apiClient.plugin.listPlugins(); + return data.items.filter((plugin) => { + return !!plugin.metadata.annotations?.[STORE_APP_ID]; + }); + }, + enabled, + staleTime: 1000, + }); + return { installedPlugins }; +} diff --git a/console/src/composables/use-theme-version.ts b/console/src/composables/use-theme-version.ts index cb06498..0aba4f3 100644 --- a/console/src/composables/use-theme-version.ts +++ b/console/src/composables/use-theme-version.ts @@ -2,29 +2,35 @@ import type { ApplicationSearchResult, ListResponse } from "@/types"; import storeApiClient from "@/utils/store-api-client"; import type { Theme } from "@halo-dev/api-client"; import { useQuery } from "@tanstack/vue-query"; -import { computed, type Ref } from "vue"; +import { computed, ref, type Ref } from "vue"; import semver from "semver"; import { useHaloVersion } from "./use-halo-version"; import { STORE_APP_ID } from "@/constant"; +import { useFetchInstalledThemes } from "./use-theme"; export function useThemeVersion(theme: Ref) { const { haloVersion } = useHaloVersion(); - // TODO: 可能需要专门的最新版本应用列表接口 + const { installedThemes } = useFetchInstalledThemes(ref(true)); + const { data: storeThemes } = useQuery>({ queryKey: ["theme-apps"], queryFn: async () => { + const appIds = installedThemes.value?.map((theme) => theme.metadata.annotations?.[STORE_APP_ID]) || []; + const { data } = await storeApiClient.get>( `/apis/api.store.halo.run/v1alpha1/applications`, { params: { type: "THEME", + names: appIds, }, } ); return data; }, staleTime: 1000, + enabled: computed(() => !!installedThemes.value?.length), }); const matchedApp = computed(() => { diff --git a/console/src/composables/use-theme.ts b/console/src/composables/use-theme.ts new file mode 100644 index 0000000..a8b7914 --- /dev/null +++ b/console/src/composables/use-theme.ts @@ -0,0 +1,21 @@ +import { STORE_APP_ID } from "@/constant"; +import { apiClient } from "@/utils/api-client"; +import type { Theme } from "@halo-dev/api-client"; +import { useQuery } from "@tanstack/vue-query"; +import type { Ref } from "vue"; + +export function useFetchInstalledThemes(enabled: Ref) { + const { data: installedThemes } = useQuery({ + queryKey: ["store-installed-themes"], + queryFn: async () => { + const { data } = await apiClient.theme.listThemes({ + uninstalled: false, + }); + return data.items.filter((theme) => { + return !!theme.metadata.annotations?.[STORE_APP_ID]; + }); + }, + enabled, + }); + return { installedThemes }; +} diff --git a/console/src/utils/store-api-client.ts b/console/src/utils/store-api-client.ts index c9c9e65..6e6d48b 100644 --- a/console/src/utils/store-api-client.ts +++ b/console/src/utils/store-api-client.ts @@ -1,7 +1,11 @@ import axios from "axios"; +import qs from "qs"; const storeApiClient = axios.create({ baseURL: import.meta.env.VITE_APP_STORE_BACKEND, + paramsSerializer: (params) => { + return qs.stringify(params, { arrayFormat: "repeat" }); + }, }); export default storeApiClient;