From 9c250b99f0029284bda36a519b39c549952163ee Mon Sep 17 00:00:00 2001 From: Huakun Shen Date: Mon, 4 Nov 2024 17:07:27 -0500 Subject: [PATCH] feat: Add a bunch of builtin commands for app internal control --- apps/desktop/package.json | 2 + apps/desktop/src/lib/cmds/builtin.ts | 172 ++++++++++++++------------ apps/desktop/src/lib/utils/updater.ts | 88 +++++++++++++ apps/desktop/tailwind.config.ts | 2 +- pnpm-lock.yaml | 6 + 5 files changed, 191 insertions(+), 79 deletions(-) create mode 100644 apps/desktop/src/lib/utils/updater.ts diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 717ed17..ff6075a 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -27,6 +27,7 @@ "lucide-svelte": "^0.454.0", "lz-string": "^1.5.0", "mode-watcher": "^0.4.1", + "semver": "^7.6.3", "svelte-radix": "^2.0.1", "svelte-sonner": "^0.3.28", "sveltekit-superforms": "^2.20.0" @@ -42,6 +43,7 @@ "@tailwindcss/typography": "^0.5.15", "@tauri-apps/cli": "^2.0.4", "@types/bun": "latest", + "@types/semver": "^7.5.8", "autoprefixer": "^10.4.20", "clsx": "^2.1.1", "embla-carousel-svelte": "^8.3.1", diff --git a/apps/desktop/src/lib/cmds/builtin.ts b/apps/desktop/src/lib/cmds/builtin.ts index e6ee94e..9c9033c 100644 --- a/apps/desktop/src/lib/cmds/builtin.ts +++ b/apps/desktop/src/lib/cmds/builtin.ts @@ -1,7 +1,11 @@ -import { appState } from "@/stores" +import { appConfig, appState } from "@/stores" +import { checkUpdateAndInstall } from "@/utils/updater" import type { BuiltinCmd } from "@kksh/ui/types" +import { getVersion } from "@tauri-apps/api/app" +import { exit } from "@tauri-apps/plugin-process" import { dev } from "$app/environment" import { goto } from "$app/navigation" +import { toast } from "svelte-sonner" export const builtinCmds: BuiltinCmd[] = [ { @@ -30,23 +34,23 @@ export const builtinCmds: BuiltinCmd[] = [ // supabase.auth.signOut() // } // }, - // { - // name: "Show Draggable Area", - // iconifyIcon: "mingcute:move-fill", - // description: "", - // function: async () => { - // // select all html elements with attribute data-tauri-drag-region - // const elements = document.querySelectorAll("[data-tauri-drag-region]") - // elements.forEach((el) => { - // el.classList.add("bg-red-500/30") - // }) - // setTimeout(() => { - // elements.forEach((el) => { - // el.classList.remove("bg-red-500/30") - // }) - // }, 2_000) - // } - // }, + { + name: "Show Draggable Area", + iconifyIcon: "mingcute:move-fill", + description: "", + function: async () => { + // select all html elements with attribute data-tauri-drag-region + const elements = document.querySelectorAll("[data-tauri-drag-region]") + elements.forEach((el) => { + el.classList.add("bg-red-500/30") + }) + setTimeout(() => { + elements.forEach((el) => { + el.classList.remove("bg-red-500/30") + }) + }, 2_000) + } + }, // { // name: "Add Dev Extension", // iconifyIcon: "lineicons:dev", @@ -57,14 +61,14 @@ export const builtinCmds: BuiltinCmd[] = [ // goto("/add-dev-ext") // } // }, - // { - // name: "Kunkun Version", - // iconifyIcon: "stash:version-solid", - // description: "", - // function: async () => { - // toast.success(`Kunkun Version: ${await getVersion()}`) - // } - // }, + { + name: "Kunkun Version", + iconifyIcon: "stash:version-solid", + description: "", + function: async () => { + toast.success(`Kunkun Version: ${await getVersion()}`) + } + }, { name: "Set Dev Extension Path", iconifyIcon: "lineicons:dev", @@ -143,30 +147,32 @@ export const builtinCmds: BuiltinCmd[] = [ // appStateStore.setSearchTermSync("") // } // }, - // { - // name: "Check Update", - // iconifyIcon: "material-symbols:update", - // description: "Check for updates", - // function: async () => { - // checkUpdateAndInstall() - // } - // }, - // { - // name: "Check Beta Update", - // iconifyIcon: "material-symbols:update", - // description: "Check for Beta updates", - // function: async () => { - // checkUpdateAndInstall(true) - // } - // }, - // { - // name: "Reload", - // iconifyIcon: "tabler:reload", - // description: "Reload this page", - // function: async () => { - // location.reload() - // } - // }, + { + name: "Check Update", + iconifyIcon: "material-symbols:update", + description: "Check for updates", + function: async () => { + checkUpdateAndInstall() + appState.clearSearchTerm() + } + }, + { + name: "Check Beta Update", + iconifyIcon: "material-symbols:update", + description: "Check for Beta updates", + function: async () => { + checkUpdateAndInstall({ beta: true }) + appState.clearSearchTerm() + } + }, + { + name: "Reload", + iconifyIcon: "tabler:reload", + description: "Reload this page", + function: async () => { + location.reload() + } + }, { name: "Dance", iconifyIcon: "mdi:dance-pole", @@ -174,33 +180,43 @@ export const builtinCmds: BuiltinCmd[] = [ function: async () => { goto("/dance") } + }, + { + name: "Quit Kunkun", + iconifyIcon: "emojione:cross-mark-button", + description: "Quit Kunkun", + function: async () => { + exit(0) + } + }, + { + name: "Toggle Dev Extension HMR", + iconifyIcon: "ri:toggle-line", + description: "Load dev extensions from their dev server URLs", + function: async () => { + appConfig.update((config) => { + toast.success(`Dev Extension HMR toggled to: ${!config.hmr}`) + return { + ...config, + hmr: !config.hmr + } + }) + appState.clearSearchTerm() + } + }, + { + name: "Toggle Hide On Blur", + iconifyIcon: "ri:toggle-line", + description: "Toggle Hide On Blur", + function: async () => { + appConfig.update((config) => { + toast.success(`"Hide on Blur" toggled to: ${!config.hideOnBlur}`) + return { + ...config, + hideOnBlur: !config.hideOnBlur + } + }) + appState.clearSearchTerm() + } } - // { - // name: "Quit Kunkun", - // iconifyIcon: "emojione:cross-mark-button", - // description: "Quit Kunkun", - // function: async () => { - // exit(0) - // } - // }, - // { - // name: "Toggle Dev Extension Live Load Mode", - // iconifyIcon: "ri:toggle-line", - // description: "Load dev extensions from their dev server URLs", - // function: async () => { - // toggleDevExtensionLiveLoadMode() - // } - // }, - // { - // name: "Toggle Hide On Blur", - // iconifyIcon: "ri:toggle-line", - // description: "Toggle Hide On Blur", - // function: async () => { - // const appConfig = useAppConfigStore() - // appConfig.setHideOnBlur(!appConfig.hideOnBlur) - // const appStateStore = useAppStateStore() - // appStateStore.setSearchTermSync("") - // toast.success(`"Hide on Blur" toggled to: ${appConfig.hideOnBlur}`) - // } - // } ] diff --git a/apps/desktop/src/lib/utils/updater.ts b/apps/desktop/src/lib/utils/updater.ts new file mode 100644 index 0000000..17705b0 --- /dev/null +++ b/apps/desktop/src/lib/utils/updater.ts @@ -0,0 +1,88 @@ +import { extensions } from "@/stores" +import { supabaseAPI } from "@/supabase" +import { isCompatible } from "@kksh/api" +import type { ExtPackageJsonExtra } from "@kksh/api/models" +import { greaterThan } from "@std/semver" +import { relaunch } from "@tauri-apps/plugin-process" +import { check } from "@tauri-apps/plugin-updater" +import { gt } from "semver" +import { toast } from "svelte-sonner" +import { get } from "svelte/store" + +export async function checkUpdateAndInstall({ beta }: { beta?: boolean } = {}) { + const update = await check({ + headers: { + "kk-updater-mode": beta ? "beta" : "stable" + } + }) + if (update?.available) { + const confirmUpdate = await confirm( + `A new version ${update.version} is available. Do you want to install and relaunch?` + ) + if (confirmUpdate) { + await update.downloadAndInstall() + await relaunch() + } + } else { + toast.info("You are on the latest version") + } +} + +export async function checkSingleExtensionUpdate( + installedExt: ExtPackageJsonExtra, + autoupgrade: boolean +) { + const { data: sbExt, error } = await supabaseAPI.getLatestExtPublish( + installedExt.kunkun.identifier + ) + if (error) { + return toast.error(`Failed to check update for ${installedExt.kunkun.identifier}: ${error}`) + } + + if (!sbExt) { + return null + } + + if ( + gt(sbExt.version, installedExt.version) && + (sbExt.api_version ? isCompatible(sbExt.api_version) : true) + ) { + if (autoupgrade) { + await extensions + .upgradeStoreExtension( + sbExt.identifier, + supabaseAPI.translateExtensionFilePathToUrl(sbExt.tarball_path) + ) + .then(() => { + toast.success(`${sbExt.name} upgraded`, { + description: `From ${installedExt.version} to ${sbExt.version}` + }) + }) + .catch((err) => { + toast.error(`Failed to upgrade ${sbExt.name}`, { description: err }) + }) + return true + } else { + console.log(`new version available ${installedExt.kunkun.identifier} ${sbExt.version}`) + toast.info( + `Extension ${installedExt.kunkun.identifier} has a new version ${sbExt.version}, you can upgrade in Store.`, + { duration: 10_000 } + ) + } + } + return false +} + +export async function checkExtensionUpdate(autoupgrade: boolean = false) { + let upgradedCount = 0 + for (const ext of get(extensions)) { + const upgraded = await checkSingleExtensionUpdate(ext, autoupgrade) + if (upgraded) { + upgradedCount++ + } + } + + if (upgradedCount > 0) { + toast.info(`${upgradedCount} extensions have been upgraded`) + } +} diff --git a/apps/desktop/tailwind.config.ts b/apps/desktop/tailwind.config.ts index fbc57f7..12ab766 100644 --- a/apps/desktop/tailwind.config.ts +++ b/apps/desktop/tailwind.config.ts @@ -9,7 +9,7 @@ const config: Config = { "./node_modules/@kksh/ui/src/**/*.{html,js,svelte,ts}", "../../node_modules/@kksh/svelte5/src/**/*.{html,js,svelte,ts}" ], - safelist: ["dark"], + safelist: ["dark", "bg-red-500/30"], theme: { container: { center: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 010c4eb..db384ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -153,6 +153,9 @@ importers: mode-watcher: specifier: ^0.4.1 version: 0.4.1(svelte@5.1.9) + semver: + specifier: ^7.6.3 + version: 7.6.3 svelte-radix: specifier: ^2.0.1 version: 2.0.1(svelte@5.1.9) @@ -193,6 +196,9 @@ importers: '@types/bun': specifier: latest version: 1.1.13 + '@types/semver': + specifier: ^7.5.8 + version: 7.5.8 autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47)