From b729c8ebbe66d71316b40e46442061416beb213a Mon Sep 17 00:00:00 2001 From: Martin Drechsel Date: Tue, 6 May 2025 11:09:56 +0200 Subject: [PATCH] zwischenstand --- README.md | 82 +++- nuxt.config.ts | 3 +- package.json | 1 + pnpm-lock.yaml | 391 +++++++++++++++++- src-tauri/Cargo.lock | 37 +- src-tauri/Cargo.toml | 8 +- src-tauri/capabilities/default.json | 53 +-- src-tauri/database/index.ts | 23 ++ .../migrations/0001_wealthy_thaddeus_ross.sql | 7 + .../migrations/meta/0001_snapshot.json | 223 ++++++++++ .../database/migrations/meta/_journal.json | 7 + src-tauri/database/schemas/vault.ts | 64 ++- src-tauri/database/vault.db | Bin 40960 -> 49152 bytes src-tauri/src/database/core.rs | 175 +++++++- src-tauri/src/database/mod.rs | 79 +++- src-tauri/src/extension/core.rs | 181 ++++++++ src-tauri/src/extension/database/mod.rs | 16 +- src-tauri/src/extension/mod.rs | 7 + src-tauri/src/lib.rs | 28 +- src-tauri/tauri.conf.json | 6 +- .../haex/extension/manifest/confirm.vue | 102 +++++ .../manifest/permissions/database.vue | 63 +++ .../manifest/permissions/filesystem.vue | 65 +++ .../extension/manifest/permissions/http.vue | 43 ++ .../extension/manifest/permissions/title.vue | 5 + src/components/ui/accordion/index.vue | 43 ++ src/components/ui/dialog/index.vue | 41 +- src/components/ui/sidebar/link/extension.vue | 49 +++ .../ui/sidebar/{link.vue => link/index.vue} | 0 src/components/vault/button/open.vue | 9 +- src/components/vault/card/index.vue | 32 +- src/composables/helper.ts | 30 +- src/layouts/app.vue | 115 +++--- src/pages/vault.vue | 14 +- .../[vaultId]/extensions/[extensionId].vue | 28 +- .../vault/[vaultId]/extensions/index.vue | 87 +++- src/pages/vault/[vaultId]/index.vue | 10 +- src/stores/extensions/index.ts | 321 +++++++++++--- src/stores/ui/sidebar.ts | 51 +-- src/stores/vault/index.ts | 129 +++--- 40 files changed, 2252 insertions(+), 376 deletions(-) create mode 100644 src-tauri/database/index.ts create mode 100644 src-tauri/database/migrations/0001_wealthy_thaddeus_ross.sql create mode 100644 src-tauri/database/migrations/meta/0001_snapshot.json create mode 100644 src-tauri/src/extension/core.rs create mode 100644 src/components/haex/extension/manifest/confirm.vue create mode 100644 src/components/haex/extension/manifest/permissions/database.vue create mode 100644 src/components/haex/extension/manifest/permissions/filesystem.vue create mode 100644 src/components/haex/extension/manifest/permissions/http.vue create mode 100644 src/components/haex/extension/manifest/permissions/title.vue create mode 100644 src/components/ui/accordion/index.vue create mode 100644 src/components/ui/sidebar/link/extension.vue rename src/components/ui/sidebar/{link.vue => link/index.vue} (100%) diff --git a/README.md b/README.md index 5047afc..eae0082 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,80 @@ -# Tauri + Vue + TypeScript +# HaexHub - The European "Everything App" -This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + +{ + "de": { + "title": "Erweiterung hinzufügen", + "question": "Möchtest du die Erweiterung {extension} hinzufügen?", + "confirm": "Bestätigen", + "deny": "Ablehnen", + + "permission": { + "read": "Lesen", + "write": "Schreiben" + }, + + "database": { + "title": "Datenbank Berechtigungen" + }, + "http": { + "title": "Internet Berechtigungen" + }, + "filesystem": { + "title": "Dateisystem Berechtigungen" + } + }, + "en": { "title": "Confirm Permission" } +} + diff --git a/src/components/haex/extension/manifest/permissions/database.vue b/src/components/haex/extension/manifest/permissions/database.vue new file mode 100644 index 0000000..a421beb --- /dev/null +++ b/src/components/haex/extension/manifest/permissions/database.vue @@ -0,0 +1,63 @@ + + + + + +{ + "de": { + "permission": { + "read": "Lesen", + "write": "Schreiben" + }, + + "database": { + "title": "Datenbank Berechtigungen" + } + }, + "en": { "title": "Confirm Permission" } +} + diff --git a/src/components/haex/extension/manifest/permissions/filesystem.vue b/src/components/haex/extension/manifest/permissions/filesystem.vue new file mode 100644 index 0000000..3cf336a --- /dev/null +++ b/src/components/haex/extension/manifest/permissions/filesystem.vue @@ -0,0 +1,65 @@ + + + + + +{ + "de": { + "permission": { + "read": "Lesen", + "write": "Schreiben" + }, + + "filesystem": { + "title": "Dateisystem Berechtigungen" + } + }, + "en": { "title": "Confirm Permission" } +} + diff --git a/src/components/haex/extension/manifest/permissions/http.vue b/src/components/haex/extension/manifest/permissions/http.vue new file mode 100644 index 0000000..079f7eb --- /dev/null +++ b/src/components/haex/extension/manifest/permissions/http.vue @@ -0,0 +1,43 @@ + + + + + +{ + "de": { + "permission": { + "access": "Zugriff" + }, + + "http": { + "title": "Internet Berechtigungen" + } + }, + "en": { "title": "Confirm Permission" } +} + diff --git a/src/components/haex/extension/manifest/permissions/title.vue b/src/components/haex/extension/manifest/permissions/title.vue new file mode 100644 index 0000000..d90875a --- /dev/null +++ b/src/components/haex/extension/manifest/permissions/title.vue @@ -0,0 +1,5 @@ + diff --git a/src/components/ui/accordion/index.vue b/src/components/ui/accordion/index.vue new file mode 100644 index 0000000..051f42e --- /dev/null +++ b/src/components/ui/accordion/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/ui/dialog/index.vue b/src/components/ui/dialog/index.vue index 1d24dfb..31bbc48 100644 --- a/src/components/ui/dialog/index.vue +++ b/src/components/ui/dialog/index.vue @@ -1,9 +1,5 @@ diff --git a/src/components/ui/sidebar/link.vue b/src/components/ui/sidebar/link/index.vue similarity index 100% rename from src/components/ui/sidebar/link.vue rename to src/components/ui/sidebar/link/index.vue diff --git a/src/components/vault/button/open.vue b/src/components/vault/button/open.vue index cee4e88..643532a 100644 --- a/src/components/vault/button/open.vue +++ b/src/components/vault/button/open.vue @@ -71,7 +71,8 @@ const { add } = useSnackbar(); const handleError = (error: unknown) => { isOpen.value = false; - add({ type: "error", text: JSON.stringify(error) }); + console.log("handleError", error, typeof error); + add({ type: "error", text: "Passwort falsch" }); //console.error(error); }; @@ -100,6 +101,7 @@ const onLoadDatabase = async () => { }; const localePath = useLocalePath(); + const onOpenDatabase = async () => { try { check.value = true; @@ -120,7 +122,10 @@ const onOpenDatabase = async () => { }); if (!vaultId) { - add({ type: "error", text: "Vault konnte nicht geöffnet werden" }); + add({ + type: "error", + text: "Vault konnte nicht geöffnet werden. \n Vermutlich ist das Passwort falsch", + }); return; } diff --git a/src/components/vault/card/index.vue b/src/components/vault/card/index.vue index 4dc09ba..d141b99 100644 --- a/src/components/vault/card/index.vue +++ b/src/components/vault/card/index.vue @@ -1,14 +1,27 @@ diff --git a/src/composables/helper.ts b/src/composables/helper.ts index 2d1cfb2..3589515 100644 --- a/src/composables/helper.ts +++ b/src/composables/helper.ts @@ -1,21 +1,21 @@ -import { H3Error } from 'h3'; +import { H3Error } from "h3"; export const bytesToBase64DataUrlAsync = async ( bytes: Uint8Array, - type = 'application/octet-stream' + type = "application/octet-stream" ) => { return await new Promise((resolve, reject) => { const reader = Object.assign(new FileReader(), { onload: () => resolve(reader.result), onerror: () => reject(reader.error), }); - reader.readAsDataURL(new File([new Blob([bytes])], '', { type })); + reader.readAsDataURL(new File([new Blob([bytes])], "", { type })); }); }; export const blobToImageAsync = (blob: Blob): Promise => { return new Promise((resolve) => { - console.log('transform blob', blob); + console.log("transform blob", blob); const url = URL.createObjectURL(blob); let img = new Image(); img.onload = () => { @@ -34,7 +34,7 @@ export const deepToRaw = >(sourceObj: T): T => { if (isRef(input) || isReactive(input) || isProxy(input)) { return objectIterator(toRaw(input)); } - if (input && typeof input === 'object') { + if (input && typeof input === "object") { return Object.keys(input).reduce((acc, key) => { acc[key as keyof typeof acc] = objectIterator(input[key]); return acc; @@ -48,10 +48,9 @@ export const deepToRaw = >(sourceObj: T): T => { export const readableFileSize = (sizeInByte: number | string = 0) => { if (!sizeInByte) { - return '0 KB'; + return "0 KB"; } - const size = - typeof sizeInByte === 'string' ? parseInt(sizeInByte) : sizeInByte; + const size = typeof sizeInByte === "string" ? parseInt(sizeInByte) : sizeInByte; const sizeInKb = size / 1024; const sizeInMb = sizeInKb / 1024; const sizeInGb = sizeInMb / 1024; @@ -64,20 +63,17 @@ export const readableFileSize = (sizeInByte: number | string = 0) => { return `${sizeInKb.toFixed(2)} KB`; }; -import type { LocationQueryValue, RouteLocationRawI18n } from 'vue-router'; +import type { LocationQueryValue, RouteLocationRawI18n } from "vue-router"; export const getSingleRouteParam = ( param: string | string[] | LocationQueryValue | LocationQueryValue[] ): string => { - const _param = Array.isArray(param) ? param.at(0) ?? '' : param ?? ''; + const _param = Array.isArray(param) ? param.at(0) ?? "" : param ?? ""; //console.log('found param', _param, param); - return _param; + return decodeURIComponent(_param); }; -export const isRouteActive = ( - to: RouteLocationRawI18n, - exact: boolean = false -) => +export const isRouteActive = (to: RouteLocationRawI18n, exact: boolean = false) => computed(() => { const found = useRouter() .getRoutes() @@ -86,9 +82,7 @@ export const isRouteActive = ( return exact ? found?.name === useRouter().currentRoute.value.name : found?.name === useRouter().currentRoute.value.name || - found?.children.some( - (child) => child.name === useRouter().currentRoute.value.name - ); + found?.children.some((child) => child.name === useRouter().currentRoute.value.name); }); export const isKey = (x: T, k: PropertyKey): k is keyof T => { diff --git a/src/layouts/app.vue b/src/layouts/app.vue index 0a8baf7..bd191a0 100644 --- a/src/layouts/app.vue +++ b/src/layouts/app.vue @@ -1,32 +1,27 @@ + diff --git a/src/pages/vault/[vaultId]/extensions/[extensionId].vue b/src/pages/vault/[vaultId]/extensions/[extensionId].vue index b98330b..6e3ed13 100644 --- a/src/pages/vault/[vaultId]/extensions/[extensionId].vue +++ b/src/pages/vault/[vaultId]/extensions/[extensionId].vue @@ -1,7 +1,16 @@ @@ -10,8 +19,21 @@ definePageMeta({ name: "haexExtension", }); -const iframeRef = useTemplateRef("iFrameRef"); const { t } = useI18n(); +const iframeRef = useTemplateRef("iFrameRef"); + +const { extensionEntry: iframeSrc, currentExtension } = storeToRefs(useExtensionsStore()); +const extensionStore = useExtensionsStore(); + +watch(iframeSrc, () => console.log("iframeSrc", iframeSrc.value), { immediate: true }); + +onMounted(async () => { + const minfest = await extensionStore.readManifestFileAsync( + currentExtension.value!.id, + currentExtension.value!.version + ); + console.log("manifest", minfest, extensionStore.extensionEntry); +}); diff --git a/src/pages/vault/[vaultId]/extensions/index.vue b/src/pages/vault/[vaultId]/extensions/index.vue index faacbad..e92f02a 100644 --- a/src/pages/vault/[vaultId]/extensions/index.vue +++ b/src/pages/vault/[vaultId]/extensions/index.vue @@ -1,9 +1,92 @@ + + +{ + "de": { + "title": "Erweiterung installieren", + "extension": { + "add": "Erweiterung hinzufügen", + "success": { + "title": "{extension} hinzugefügt", + "text": "Die Erweiterung wurde erfolgreich hinzugefügt" + } + } + }, + "en": { + "title": "Install extension" + } +} + diff --git a/src/pages/vault/[vaultId]/index.vue b/src/pages/vault/[vaultId]/index.vue index 4ff6c64..5a14fde 100644 --- a/src/pages/vault/[vaultId]/index.vue +++ b/src/pages/vault/[vaultId]/index.vue @@ -1,9 +1,15 @@ diff --git a/src/stores/extensions/index.ts b/src/stores/extensions/index.ts index 75f76d9..43d4948 100644 --- a/src/stores/extensions/index.ts +++ b/src/stores/extensions/index.ts @@ -2,19 +2,29 @@ import { invoke } from "@tauri-apps/api/core"; import { join, resourceDir } from "@tauri-apps/api/path"; import { readTextFile, readDir } from "@tauri-apps/plugin-fs"; import { convertFileSrc } from "@tauri-apps/api/core"; +import { haexExtensions } from "~~/src-tauri/database/schemas/vault"; +import { eq } from "drizzle-orm"; const manifestFileName = "manifest.json"; +const logoFileName = "logo.svg"; export interface IHaexHubExtensionLink { name: string; icon: string; tooltip?: string; id: string; + version: string; + manifest?: IHaexHubExtensionManifest; } export interface IHaexHubExtensionManifest { name: string; + id: string; entry: string; + author: string; + url: string; + version: string; + icon: string; permissions: { database?: { read?: string[]; @@ -30,80 +40,142 @@ export interface IHaexHubExtensionManifest { } export const useExtensionsStore = defineStore("extensionsStore", () => { - const availableExtensions = ref([ - { - id: "haex-browser", - name: "Haex Browser", - icon: "solar:global-outline", - }, - - { - id: "extensions", - name: "sidebar.extensions", - icon: "gg:extension", - }, - - { - id: "settings", - name: "sidebar.settings", - icon: "ph:gear-six", - }, - ]); + const availableExtensions = ref([]); const currentRoute = useRouter().currentRoute; const isActive = (id: string) => computed( - () => - currentRoute.value.name === "extension" && - currentRoute.value.params.extensionId === id + () => currentRoute.value.name === "extension" && currentRoute.value.params.extensionId === id ); const currentExtension = computed(() => { - if (currentRoute.value.name !== "haexExtension") return; - - const extensionId = getSingleRouteParam( - currentRoute.value.params.extensionId - ); + console.log("computed currentExtension", currentRoute.value.params); + if (currentRoute.value.meta.name !== "haexExtension") return; + const extensionId = getSingleRouteParam(currentRoute.value.params.extensionId); + console.log("extensionId from param", extensionId); if (!extensionId) return; - return availableExtensions.value.find( - (extension) => extension.id === extensionId - ); + const extension = availableExtensions.value.find((extension) => extension.id === extensionId); + console.log("currentExtension", extension); + return extension; }); - const checkExtensionDirectoryAsync = async (extensionDirectory: string) => { + const getExtensionPathAsync = async (extensionId?: string, version?: string) => { + if (!extensionId || !version) return ""; + return await join(await resourceDir(), "extensions", extensionId, version); + }; + + const checkSourceExtensionDirectoryAsync = async (extensionDirectory: string) => { try { const dir = await readDir(extensionDirectory); - const manifest = dir.find( - (entry) => entry.name === manifestFileName && entry.isFile - ); + const manifest = dir.find((entry) => entry.name === manifestFileName && entry.isFile); if (!manifest) throw new Error("Kein Manifest für Erweiterung gefunden"); + + const logo = dir.find((item) => item.isFile && item.name === logoFileName); + if (!logo) throw new Error("Logo fehlt"); + return true; } catch (error) { - throw new Error( - `Keine Leseberechtigung für Ordner ${extensionDirectory}` - ); + throw new Error(`Keine Leseberechtigung für Ordner ${extensionDirectory}`); } }; - const installAsync = async ( - extensionDirectory: string | null, - global: boolean = true - ): Promise => { + const checkManifest = (manifestFile: unknown): manifestFile is IHaexHubExtensionManifest => { + const errors = []; + + if (typeof manifestFile !== "object" || manifestFile === null) { + errors.push("Manifest ist falsch"); + return false; + } + + if (!("id" in manifestFile) || typeof manifestFile.id !== "string") + errors.push("Keine ID vergeben"); + + if (!("name" in manifestFile) || typeof manifestFile.name !== "string") + errors.push("Name fehlt"); + + if (!("entry" in manifestFile) || typeof manifestFile.entry !== "string") + errors.push("Entry fehlerhaft"); + + if (!("author" in manifestFile) || typeof manifestFile.author !== "string") + errors.push("Author fehlt"); + + if (!("url" in manifestFile) || typeof manifestFile.url !== "string") errors.push("Url fehlt"); + + if (!("version" in manifestFile) || typeof manifestFile.version !== "string") + errors.push("Version fehlt"); + + if ( + !("permissions" in manifestFile) || + typeof manifestFile.permissions !== "object" || + manifestFile.permissions === null + ) { + errors.push("Berechtigungen fehlen"); + } + + if (errors.length) throw errors; + + /* const permissions = manifestFile.permissions as Partial; + if ( + ("database" in permissions && + (typeof permissions.database !== "object" || permissions.database === null)) || + ("filesystem" in permissions && typeof permissions.filesystem !== "object") || + permissions.filesystem === null + ) { + return false; + } */ + + return true; + }; + + const readManifestFileAsync = async (extensionId: string, version: string | number) => { try { - if (!extensionDirectory) - throw new Error("Kein Ordner für Erweiterung angegeben"); - const checkDirectory = await checkExtensionDirectoryAsync( - extensionDirectory - ); + const extensionPath = await getExtensionPathAsync(extensionId, `${version}`); + const manifestPath = await join(extensionPath, manifestFileName); + const manifest = (await JSON.parse( + await readTextFile(manifestPath) + )) as IHaexHubExtensionManifest; - const manifestPath = await join(extensionDirectory, "manifest.json"); - const manifest = await JSON.parse(await readTextFile(manifestPath)); + /* + TODO implement await checkManifets(manifest); + */ + return manifest; + } catch (error) { + console.error("ERROR readManifestFileAsync", error); + } + }; - console.log("manifest", manifest); - return; + const installAsync = async (extensionDirectory: string | null, global: boolean = true) => { + try { + if (!extensionDirectory) throw new Error("Kein Ordner für Erweiterung angegeben"); + const manifestPath = await join(extensionDirectory, manifestFileName); + const manifest = (await JSON.parse( + await readTextFile(manifestPath) + )) as IHaexHubExtensionManifest; + + const destination = await getExtensionPathAsync(manifest.id, manifest.version); + + await checkSourceExtensionDirectoryAsync(extensionDirectory); + + await invoke("copy_directory", { source: extensionDirectory, destination }); + + const logoFilePath = await join(destination, "logo.svg"); + const logoSvg = await readTextFile(logoFilePath); + + const { currentVault } = storeToRefs(useVaultStore()); + const res = await currentVault.value?.drizzle.insert(haexExtensions).values({ + id: manifest.id, + name: manifest.name, + author: manifest.author, + enabled: true, + url: manifest.url, + version: manifest.version, + icon: logoSvg, + }); + + console.log("insert extensions", res); } catch (error) { throw error; /* @@ -213,9 +285,158 @@ export const useExtensionsStore = defineStore("extensionsStore", () => { } }; + const extensionEntry = computedAsync( + async () => { + console.log("extensionEntry start", currentExtension.value); + const regex = /((href|src)=["'])([^"']+)(["'])/g; + if (!currentExtension.value?.id || !currentExtension.value.version) { + console.log("extension id or entry missing", currentExtension.value); + return "no mani: " + currentExtension.value; + } + //return "wadahadedzdz"; + + const extensionPath = await getExtensionPathAsync( + currentExtension.value?.id, + currentExtension.value?.version + ); //await join(await resourceDir(), currentExtension.value.. extensionDir, entryFileName); + + console.log("extensionEntry extensionPath", extensionPath); + const manifest = await readManifestFileAsync( + currentExtension.value.id, + currentExtension.value.version + ); + + if (!manifest) return "no manifest readable"; + + const entryPath = await join(extensionPath, manifest.entry); + + return `asset://localhost/${entryPath}`; + let entryHtml = await readTextFile(entryPath); + + console.log("entryHtml", entryHtml); + const replacements = []; + let match; + while ((match = regex.exec(entryHtml)) !== null) { + const [fullMatch, prefix, attr, resource, suffix] = match; + if (!resource.startsWith("http")) { + replacements.push({ match: fullMatch, resource, prefix, suffix }); + } + } + + for (const { match, resource, prefix, suffix } of replacements) { + const fileContent = await readTextFile(await join(extensionPath, resource)); + const blob = new Blob([fileContent], { type: getMimeType(resource) }); + const blobUrl = URL.createObjectURL(blob); + console.log("blob", resource, blobUrl); + entryHtml = entryHtml.replace(match, `${prefix}${blobUrl}${suffix}`); + } + + console.log("entryHtml", entryHtml); + + const blob = new Blob([entryHtml], { type: "text/html" }); + const iframeSrc = URL.createObjectURL(blob); + + console.log("iframeSrc", iframeSrc); + + /* const path = convertFileSrc(extensionDir, manifest.entry); + console.log("final path", path); */ + //manifest.entry = iframeSrc; + return iframeSrc; + /* await join( + path, //`file:/${extensionDirectory}`, + manifest.entry + ); */ + // Modul-Datei laden + //const modulePathFull = await join(basePath, manifest.main); + /* const manifest: PluginManifest = await invoke('load_plugin', { + manifestPath, + }); */ + /* const iframe = document.createElement('iframe'); + iframe.src = manifest.entry; + iframe.setAttribute('sandbox', 'allow-scripts'); + iframe.style.width = '100%'; + iframe.style.height = '100%'; + iframe.style.border = 'none'; */ + /* const addonApi = { + db_execute: async (sql: string, params: string[] = []) => { + return invoke('db_execute', { + addonId: manifest.name, + sql, + params, + }); + }, + db_select: async (sql: string, params: string[] = []) => { + return invoke('db_select', { + addonId: manifest.name, + sql, + params, + }); + }, + }; */ + /* iframe.onload = () => { + iframe.contentWindow?.postMessage( + { type: 'init', payload: addonApi }, + '*' + ); + }; + + window.addEventListener('message', (event) => { + if (event.source === iframe.contentWindow) { + const { type } = event.data; + if (type === 'ready') { + console.log(`Plugin ${manifest.name} ist bereit`); + } + } + }); */ + /* plugins.value.push({ name: manifest.name, entry: manifest.entry }); + + console.log(`Plugin ${manifest.name} geladen.`); */ + }, + null, + { lazy: true } + ); + + const loadExtensionsAsync = async () => { + const { currentVault } = storeToRefs(useVaultStore()); + + /* const query = db + .select() + .from(haexExtensions) + //.where(sql`${haexExtensions.enabled} = "1"`); + .where(eq(haexExtensions.enabled, true)); */ + const extensions = await currentVault.value?.drizzle + .select() + .from(haexExtensions) + .where(eq(haexExtensions.enabled, true)); + + //const manifest = readTextFile(manifestFileName) + //const { sql, params } = query.toSQL(); + //const extensions = await invoke("sql_select", { sql, params }); + console.log("loadExtensionsAsync ", extensions); + availableExtensions.value = + extensions?.map((extension) => ({ + id: extension.id, + name: extension.name ?? "", + icon: extension.icon ?? "", + tooltip: extension.name ?? "", + version: extension.version ?? "", + })) ?? []; + }; + return { availableExtensions, + checkManifest, currentExtension, + extensionEntry, + installAsync, isActive, + loadExtensionsAsync, + readManifestFileAsync, }; }); + +const getMimeType = (file: string) => { + if (file.endsWith(".css")) return "text/css"; + if (file.endsWith(".js")) return "text/javascript"; + return "text/plain"; +}; diff --git a/src/stores/ui/sidebar.ts b/src/stores/ui/sidebar.ts index 0c32f3c..3722cc4 100644 --- a/src/stores/ui/sidebar.ts +++ b/src/stores/ui/sidebar.ts @@ -2,31 +2,33 @@ import { getSingleRouteParam } from "~/composables/helper"; import type { RouteLocationRaw, RouteLocationAsRelativeGeneric } from "vue-router"; export interface ISidebarItem { - name: string; - icon: string; - tooltip?: string; - id: string; - to?: RouteLocationAsRelativeGeneric; + name: string; + icon: string; + tooltip?: string; + id: string; + to?: RouteLocationAsRelativeGeneric; } export const useSidebarStore = defineStore("sidebarStore", () => { - const menu = ref([ - { - id: "haex-browser", - name: "Haex Browser", - icon: "solar:global-outline", - to: { name: "haexBrowser" }, - }, + const isVisible = ref(true); - { - id: "haex-extensions-add", - name: "Haex Extensions", - icon: "gg:extension", - to: { name: "haexExtensionAdd" }, - }, - ]); + const menu = ref([ + { + id: "haex-browser", + name: "Haex Browser", + icon: "solar:global-outline", + to: { name: "haexBrowser" }, + }, - /* const loadAsync = async (id: string) => { + { + id: "haex-extensions-add", + name: "Haex Extensions", + icon: "gg:extension", + to: { name: "extensionOverview" }, + }, + ]); + + /* const loadAsync = async (id: string) => { extensions.value.some(async (extension) => { if (extension.id === id) { await navigateTo( @@ -37,8 +39,9 @@ export const useSidebarStore = defineStore("sidebarStore", () => { }); }; */ - return { - menu, - //loadAsync, - }; + return { + menu, + isVisible, + //loadAsync, + }; }); diff --git a/src/stores/vault/index.ts b/src/stores/vault/index.ts index 276371e..97d1193 100644 --- a/src/stores/vault/index.ts +++ b/src/stores/vault/index.ts @@ -57,85 +57,83 @@ export const useVaultStore = defineStore("vaultStore", () => { ); const openAsync = async ({ path = "", password }: { path: string; password: string }) => { - const sqlitePath = path?.startsWith("sqlite:") ? path : `sqlite:${path}`; + try { + console.log("try to open db", path, password); - console.log("try to open db", path, password); - - const result = await invoke("open_encrypted_database", { - path, - key: password, - }); - - console.log("open vault from store", result); - if (!(await testDatabaseReadAsync())) throw new Error("Passwort falsch"); - //const db = await Database.load(sqlitePath); - - const vaultId = await getVaultIdAsync(path); - const seperator = platform() === "windows" ? "\\" : "/"; - const fileName = path.split(seperator).pop(); - console.log("opened db fileName", fileName, vaultId); - - openVaults.value = { - ...openVaults.value, - [vaultId]: { - //database: db, + const result = await invoke("open_encrypted_database", { path, - password, - name: fileName ?? path, - drizzle: drizzle( - async (sql, params, method) => { - let rows: any = []; - let results = []; + key: password, + }); - // If the query is a SELECT, use the select method - if (isSelectQuery(sql)) { - rows = await invoke("db_select", { sql, params }).catch((e) => { - console.error("SQL Error:", e); - return []; - }); - } else { - // Otherwise, use the execute method - rows = await invoke("db_execute", { sql, params }).catch((e) => { - console.error("SQL Error:", e); - return []; - }); - return { rows: [] }; - } + console.log("open vault from store", result); + //const db = await Database.load(sqlitePath); - rows = rows.map((row: any) => { - return Object.values(row); - }); + const vaultId = await getVaultIdAsync(path); + const seperator = platform() === "windows" ? "\\" : "/"; + const fileName = path.split(seperator).pop(); + console.log("opened db fileName", fileName, vaultId); - // If the method is "all", return all rows - results = method === "all" ? rows : rows[0]; + openVaults.value = { + ...openVaults.value, + [vaultId]: { + //database: db, + path, + password, + name: fileName ?? path, + drizzle: drizzle( + async (sql, params: unknown[], method) => { + let rows: any = []; + let results = []; - return { rows: results }; - }, - // Pass the schema to the drizzle instance - { schema: schema, logger: true } - ), - }, - }; + // If the query is a SELECT, use the select method + if (isSelectQuery(sql)) { + console.log("sql_select", sql, params); + rows = await invoke("sql_select", { sql, params }).catch((e) => { + console.error("SQL select Error:", e, sql, params); + return []; + }); + console.log("select", rows); + } else { + // Otherwise, use the execute method + rows = await invoke("sql_execute", { sql, params }).catch((e) => { + console.error("SQL execute Error:", e, sql, params); + return []; + }); + return { rows: [] }; + } - const { addVaultAsync } = useLastVaultStore(); - await addVaultAsync({ path }); + /* rows = rows.map((row: any) => { + return Object.values(row); + }); */ - return vaultId; - }; + console.log("select after map", rows); + // If the method is "all", return all rows + results = method === "all" ? rows : rows[0]; - const createTable = () => { - console.log("ddd", schema.testTable.getSQL().queryChunks); + return { rows: results }; + }, + // Pass the schema to the drizzle instance + { schema: schema, logger: true } + ), + }, + }; - schema.testTable.getSQL().queryChunks.forEach((chunk) => { - const res = currentVault.value?.drizzle.run(chunk); - console.log("create table", res); - }); + //if (!(await testDatabaseReadAsync())) throw new Error("Passwort falsch"); + + const { addVaultAsync } = useLastVaultStore(); + await addVaultAsync({ path }); + + return vaultId; + } catch (error) { + console.error("Error openAsync ", error); + return false; + //if (error === "file is not a database") throw new Error("Passwort falsch"); + } }; const testDatabaseReadAsync = async () => { try { - currentVault.value?.drizzle.select({ count: count() }).from(schema.haexExtensions); - return true; + return currentVault.value?.drizzle.select({ count: count() }).from(schema.haexExtensions); } catch (error) { return false; } @@ -186,7 +184,6 @@ export const useVaultStore = defineStore("vaultStore", () => { openVaults, refreshDatabaseAsync, read_only, - createTable, }; });