mirror of
https://github.com/kunkunsh/kunkun.git
synced 2025-04-04 14:46:42 +00:00
feat: implement extensions management in settings, to allow uninstallation
This commit is contained in:
parent
3b888351cf
commit
836a92cf14
@ -1,6 +1,6 @@
|
||||
import { getExtensionsFolder } from "@/constants"
|
||||
import { db } from "@kksh/api/commands"
|
||||
import type { ExtPackageJsonExtra } from "@kksh/api/models"
|
||||
import type { ExtPackageJson, ExtPackageJsonExtra } from "@kksh/api/models"
|
||||
import * as extAPI from "@kksh/extension"
|
||||
import * as path from "@tauri-apps/api/path"
|
||||
import * as fs from "@tauri-apps/plugin-fs"
|
||||
@ -21,22 +21,44 @@ function createExtensionsStore(): Writable<ExtPackageJsonExtra[]> & {
|
||||
findStoreExtensionByIdentifier: (identifier: string) => ExtPackageJsonExtra | undefined
|
||||
registerNewExtensionByPath: (extPath: string) => Promise<ExtPackageJsonExtra>
|
||||
uninstallStoreExtensionByIdentifier: (identifier: string) => Promise<ExtPackageJsonExtra>
|
||||
uninstallDevExtensionByIdentifier: (identifier: string) => Promise<ExtPackageJsonExtra>
|
||||
upgradeStoreExtension: (identifier: string, tarballUrl: string) => Promise<ExtPackageJsonExtra>
|
||||
} {
|
||||
const store = writable<ExtPackageJsonExtra[]>([])
|
||||
|
||||
/**
|
||||
* Load all extensions from the database and disk, all extensions manifest will be stored in the store
|
||||
* @returns loaded extensions
|
||||
*/
|
||||
function init() {
|
||||
return extAPI.loadAllExtensionsFromDb().then((exts) => {
|
||||
store.set(exts)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all extensions installed from the store (non-dev extensions)
|
||||
*/
|
||||
function getExtensionsFromStore(): ExtPackageJsonExtra[] {
|
||||
const extContainerPath = get(appConfig).extensionsInstallDir
|
||||
if (!extContainerPath) return []
|
||||
return get(extensions).filter((ext) => !extAPI.isExtPathInDev(extContainerPath, ext.extPath))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dev extensions
|
||||
*/
|
||||
function getDevExtensions(): ExtPackageJsonExtra[] {
|
||||
const extContainerPath = get(appConfig).extensionsInstallDir
|
||||
if (!extContainerPath) return []
|
||||
return get(extensions).filter((ext) => extAPI.isExtPathInDev(extContainerPath, ext.extPath))
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by its identifier
|
||||
* @param identifier extension identifier
|
||||
* @returns found extension or undefined
|
||||
*/
|
||||
function findStoreExtensionByIdentifier(identifier: string): ExtPackageJsonExtra | undefined {
|
||||
return get(extensions).find((ext) => ext.kunkun.identifier === identifier)
|
||||
}
|
||||
@ -106,7 +128,12 @@ function createExtensionsStore(): Writable<ExtPackageJsonExtra[]> & {
|
||||
})
|
||||
}
|
||||
|
||||
async function uninstallExtensionByPath(targetPath: string) {
|
||||
/**
|
||||
* Uninstall an extension by its path
|
||||
* @param targetPath absolute path to the extension folder
|
||||
* @returns uninstalled extension
|
||||
*/
|
||||
async function uninstallExtensionByPath(targetPath: string): Promise<ExtPackageJsonExtra> {
|
||||
const targetExt = get(extensions).find((ext) => ext.extPath === targetPath)
|
||||
if (!targetExt) throw new Error(`Extension ${targetPath} not registered in DB`)
|
||||
return extAPI
|
||||
@ -115,7 +142,33 @@ function createExtensionsStore(): Writable<ExtPackageJsonExtra[]> & {
|
||||
.then(() => targetExt)
|
||||
}
|
||||
|
||||
async function uninstallStoreExtensionByIdentifier(identifier: string) {
|
||||
/**
|
||||
* Uninstall a dev extension by its path
|
||||
* Files will not be removed from disk, only unregistered from the DB
|
||||
* @param targetPath absolute path to the extension folder
|
||||
* @returns uninstalled extension
|
||||
*/
|
||||
async function uninstallDevExtensionByPath(targetPath: string): Promise<ExtPackageJsonExtra> {
|
||||
const targetExt = get(extensions).find((ext) => ext.extPath === targetPath)
|
||||
if (!targetExt) throw new Error(`Extension ${targetPath} not registered in DB`)
|
||||
// remove from DB
|
||||
return db
|
||||
.deleteExtensionByPath(targetPath)
|
||||
.then(() => store.update((exts) => exts.filter((ext) => ext.extPath !== targetExt.extPath)))
|
||||
.then(() => targetExt)
|
||||
}
|
||||
|
||||
async function uninstallDevExtensionByIdentifier(
|
||||
identifier: string
|
||||
): Promise<ExtPackageJsonExtra> {
|
||||
const targetExt = getDevExtensions().find((ext) => ext.kunkun.identifier === identifier)
|
||||
if (!targetExt) throw new Error(`Extension ${identifier} not found`)
|
||||
return uninstallDevExtensionByPath(targetExt.extPath)
|
||||
}
|
||||
|
||||
async function uninstallStoreExtensionByIdentifier(
|
||||
identifier: string
|
||||
): Promise<ExtPackageJsonExtra> {
|
||||
const targetExt = getExtensionsFromStore().find((ext) => ext.kunkun.identifier === identifier)
|
||||
if (!targetExt) throw new Error(`Extension ${identifier} not found`)
|
||||
return uninstallExtensionByPath(targetExt.extPath)
|
||||
@ -143,6 +196,7 @@ function createExtensionsStore(): Writable<ExtPackageJsonExtra[]> & {
|
||||
installFromTarballUrl,
|
||||
installFromNpmPackageName,
|
||||
uninstallStoreExtensionByIdentifier,
|
||||
uninstallDevExtensionByIdentifier,
|
||||
upgradeStoreExtension
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import { appConfig, devStoreExts, extensions, installedStoreExts } from "@/stores"
|
||||
import { ExtPackageJsonExtra } from "@kksh/api/models"
|
||||
import * as extAPI from "@kksh/extension"
|
||||
import { Button, Table } from "@kksh/svelte5"
|
||||
import { error } from "@tauri-apps/plugin-log"
|
||||
import { TrashIcon } from "lucide-svelte"
|
||||
import { toast } from "svelte-sonner"
|
||||
import { derived, get } from "svelte/store"
|
||||
|
||||
function onUninstall(ext: ExtPackageJsonExtra) {
|
||||
const extContainerPath = get(appConfig).extensionsInstallDir
|
||||
const isDev = extContainerPath && extAPI.isExtPathInDev(extContainerPath, ext.extPath)
|
||||
console.log("uninstall extension (isDev): ", isDev)
|
||||
|
||||
const uninstallFunc = isDev
|
||||
? extensions.uninstallDevExtensionByIdentifier
|
||||
: extensions.uninstallStoreExtensionByIdentifier
|
||||
|
||||
return uninstallFunc(ext.kunkun.identifier)
|
||||
.then((uninstalledExt) => {
|
||||
toast.success(`${uninstalledExt.name} Uninstalled`)
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error("Fail to uninstall extension", { description: err })
|
||||
error(`Fail to uninstall store extension (${ext.kunkun.identifier}): ${err}`)
|
||||
})
|
||||
.finally(() => {})
|
||||
}
|
||||
</script>
|
||||
|
||||
{#snippet extRow(ext: ExtPackageJsonExtra, type: "Dev Extension" | "Extension")}
|
||||
<Table.Row>
|
||||
<Table.Cell class="font-medium">{ext.kunkun.name}</Table.Cell>
|
||||
<Table.Cell class="">{ext.kunkun.identifier}</Table.Cell>
|
||||
<Table.Cell>{type}</Table.Cell>
|
||||
<Table.Cell>{ext.version}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button variant="destructive" size="icon" onclick={() => onUninstall(ext)}>
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/snippet}
|
||||
<main class="container">
|
||||
<h1 class="text-2xl font-bold">Your Extensions</h1>
|
||||
<Table.Root>
|
||||
<Table.Caption>Your Extensions</Table.Caption>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head>Name</Table.Head>
|
||||
<Table.Head>Identifier</Table.Head>
|
||||
<Table.Head>Type</Table.Head>
|
||||
<Table.Head>Version</Table.Head>
|
||||
<Table.Head>Uninstall</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each $devStoreExts as ext, i (i)}
|
||||
{@render extRow(ext, "Dev Extension")}
|
||||
{/each}
|
||||
{#each $installedStoreExts as ext, i (i)}
|
||||
{@render extRow(ext, "Extension")}
|
||||
{/each}
|
||||
</Table.Body>
|
||||
<!-- <Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={3}>Total</Table.Cell>
|
||||
<Table.Cell class="text-right">$2,500.00</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Footer> -->
|
||||
</Table.Root>
|
||||
</main>
|
@ -214,6 +214,7 @@ impl JarvisDB {
|
||||
// }
|
||||
|
||||
pub fn delete_extension_by_path(&self, path: &str) -> Result<()> {
|
||||
println!("DB deleting extension by path: {}", path);
|
||||
self.conn
|
||||
.execute("DELETE FROM extensions WHERE path = ?1", params![path])?;
|
||||
Ok(())
|
||||
|
@ -54,10 +54,14 @@ export function loadAllExtensionsFromDisk(
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all extensions from the database
|
||||
* Then load the manifest from the disk
|
||||
* If a extension is in database but cannot be loaded from disk, it will be skipped
|
||||
* @returns loaded extensions
|
||||
*/
|
||||
export async function loadAllExtensionsFromDb(): Promise<ExtPackageJsonExtra[]> {
|
||||
console.log("loadAllExtensionsFromDb start")
|
||||
const allDbExts = await (await db.getAllExtensions()).filter((ext) => ext.path)
|
||||
console.log("allDbExts", allDbExts)
|
||||
const results: ExtPackageJsonExtra[] = []
|
||||
for (const ext of allDbExts) {
|
||||
if (!ext.path) continue
|
||||
|
Loading…
x
Reference in New Issue
Block a user