From d95ca2801c19a89a2a845f43b6e0133bf4e9be50 Mon Sep 17 00:00:00 2001 From: 苏向夜 Date: Thu, 26 Feb 2026 18:30:57 +0800 Subject: refactor: migrate some invokes --- .changes/migrate-apis.md | 5 + .../ui/src/components/instance-creation-modal.tsx | 70 +++++------ .../ui/src/components/instance-editor-modal.tsx | 4 +- packages/ui/src/models/instance.ts | 131 ++++++++++++++++++++ packages/ui/src/models/instances.ts | 135 --------------------- packages/ui/src/pages/index.tsx | 5 +- packages/ui/src/pages/instances-view.tsx | 4 +- 7 files changed, 175 insertions(+), 179 deletions(-) create mode 100644 .changes/migrate-apis.md create mode 100644 packages/ui/src/models/instance.ts delete mode 100644 packages/ui/src/models/instances.ts diff --git a/.changes/migrate-apis.md b/.changes/migrate-apis.md new file mode 100644 index 0000000..54f1566 --- /dev/null +++ b/.changes/migrate-apis.md @@ -0,0 +1,5 @@ +--- +"@dropout/ui": "patch:refactor" +--- + +Migrate tauri invokes of instance creation modal to generated client. diff --git a/packages/ui/src/components/instance-creation-modal.tsx b/packages/ui/src/components/instance-creation-modal.tsx index 8a2b1b4..7c46d0f 100644 --- a/packages/ui/src/components/instance-creation-modal.tsx +++ b/packages/ui/src/components/instance-creation-modal.tsx @@ -1,7 +1,13 @@ -import { invoke } from "@tauri-apps/api/core"; import { Loader2, Search } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; +import { + getFabricLoadersForVersion, + getForgeVersionsForGame, + installFabric, + installForge, + installVersion, +} from "@/client"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -13,12 +19,13 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; -import { useInstancesStore } from "@/models/instances"; +import { useInstanceStore } from "@/models/instance"; import { useGameStore } from "@/stores/game-store"; -import type { Version } from "@/types/bindings/manifest"; -import type { FabricLoaderEntry } from "../types/bindings/fabric"; -import type { ForgeVersion as ForgeVersionEntry } from "../types/bindings/forge"; -import type { Instance } from "../types/bindings/instance"; +import type { + FabricLoaderEntry, + ForgeVersion as ForgeVersionEntry, + Version, +} from "@/types"; interface Props { open: boolean; @@ -27,7 +34,7 @@ interface Props { export function InstanceCreationModal({ open, onOpenChange }: Props) { const gameStore = useGameStore(); - const instancesStore = useInstancesStore(); + const instancesStore = useInstanceStore(); // Steps: 1 = name, 2 = version, 3 = mod loader const [step, setStep] = useState(1); @@ -61,12 +68,7 @@ export function InstanceCreationModal({ open, onOpenChange }: Props) { setForgeVersions([]); try { if (modLoaderType === "fabric") { - const loaders = await invoke( - "get_fabric_loaders_for_version", - { - gameVersion: selectedVersionUI.id, - }, - ); + const loaders = await getFabricLoadersForVersion(selectedVersionUI.id); setFabricLoaders(loaders || []); if (loaders && loaders.length > 0) { setSelectedFabricLoader(loaders[0].loader.version); @@ -74,12 +76,7 @@ export function InstanceCreationModal({ open, onOpenChange }: Props) { setSelectedFabricLoader(""); } } else if (modLoaderType === "forge") { - const versions = await invoke( - "get_forge_versions_for_game", - { - gameVersion: selectedVersionUI.id, - }, - ); + const versions = await getForgeVersionsForGame(selectedVersionUI.id); setForgeVersions(versions || []); if (versions && versions.length > 0) { // Binding `ForgeVersion` uses `version` (not `id`) — use `.version` here. @@ -182,17 +179,12 @@ export function InstanceCreationModal({ open, onOpenChange }: Props) { try { // Step 1: create instance - const instance = await invoke("create_instance", { - name: instanceName.trim(), - }); + const instance = await instancesStore.create(instanceName.trim()); // If selectedVersion provided, install it - if (selectedVersionUI) { + if (selectedVersionUI && instance) { try { - await invoke("install_version", { - instanceId: instance.id, - versionId: selectedVersionUI.id, - }); + await installVersion(instance?.id, selectedVersionUI.id); } catch (err) { console.error("Failed to install base version:", err); // continue - instance created but version install failed @@ -203,24 +195,24 @@ export function InstanceCreationModal({ open, onOpenChange }: Props) { } // If mod loader selected, install it - if (modLoaderType === "fabric" && selectedFabricLoader) { + if (modLoaderType === "fabric" && selectedFabricLoader && instance) { try { - await invoke("install_fabric", { - instanceId: instance.id, - gameVersion: selectedVersionUI?.id ?? "", - loaderVersion: selectedFabricLoader, - }); + await installFabric( + instance?.id, + selectedVersionUI?.id ?? "", + selectedFabricLoader, + ); } catch (err) { console.error("Failed to install Fabric:", err); toast.error(`Failed to install Fabric: ${String(err)}`); } - } else if (modLoaderType === "forge" && selectedForgeLoader) { + } else if (modLoaderType === "forge" && selectedForgeLoader && instance) { try { - await invoke("install_forge", { - instanceId: instance.id, - gameVersion: selectedVersionUI?.id ?? "", - installerVersion: selectedForgeLoader, - }); + await installForge( + instance?.id, + selectedVersionUI?.id ?? "", + selectedForgeLoader, + ); } catch (err) { console.error("Failed to install Forge:", err); toast.error(`Failed to install Forge: ${String(err)}`); diff --git a/packages/ui/src/components/instance-editor-modal.tsx b/packages/ui/src/components/instance-editor-modal.tsx index f880c20..d964185 100644 --- a/packages/ui/src/components/instance-editor-modal.tsx +++ b/packages/ui/src/components/instance-editor-modal.tsx @@ -16,7 +16,7 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { toNumber } from "@/lib/tsrs-utils"; -import { useInstancesStore } from "@/models/instances"; +import { useInstanceStore } from "@/models/instance"; import { useSettingsStore } from "@/models/settings"; import type { FileInfo } from "../types/bindings/core"; import type { Instance } from "../types/bindings/instance"; @@ -28,7 +28,7 @@ type Props = { }; export function InstanceEditorModal({ open, instance, onOpenChange }: Props) { - const instancesStore = useInstancesStore(); + const instancesStore = useInstanceStore(); const { config } = useSettingsStore(); const [activeTab, setActiveTab] = useState< diff --git a/packages/ui/src/models/instance.ts b/packages/ui/src/models/instance.ts new file mode 100644 index 0000000..a3fda3d --- /dev/null +++ b/packages/ui/src/models/instance.ts @@ -0,0 +1,131 @@ +import { toast } from "sonner"; +import { create } from "zustand"; +import { + createInstance, + deleteInstance, + duplicateInstance, + getActiveInstance, + getInstance, + listInstances, + setActiveInstance, + updateInstance, +} from "@/client"; +import type { Instance } from "@/types"; + +interface InstanceState { + instances: Instance[]; + activeInstance: Instance | null; + + refresh: () => Promise; + create: (name: string) => Promise; + delete: (id: string) => Promise; + update: (instance: Instance) => Promise; + setActiveInstance: (instance: Instance) => Promise; + duplicate: (id: string, newName: string) => Promise; + get: (id: string) => Promise; +} + +export const useInstanceStore = create((set, get) => ({ + instances: [], + activeInstance: null, + + refresh: async () => { + const { setActiveInstance } = get(); + try { + const instances = await listInstances(); + const activeInstance = await getActiveInstance(); + + if (!activeInstance && instances.length > 0) { + // If no active instance but instances exist, set the first one as active + await setActiveInstance(instances[0]); + } + + set({ instances, activeInstance }); + } catch (e) { + console.error("Failed to load instances:", e); + toast.error("Error loading instances"); + } + }, + + create: async (name) => { + const { refresh } = get(); + try { + const instance = await createInstance(name); + await refresh(); + toast.success(`Instance "${name}" created successfully`); + return instance; + } catch (e) { + console.error("Failed to create instance:", e); + toast.error("Error creating instance"); + return null; + } + }, + + delete: async (id) => { + const { refresh, instances, activeInstance, setActiveInstance } = get(); + try { + await deleteInstance(id); + await refresh(); + + // If deleted instance was active, set another as active + if (activeInstance?.id === id) { + if (instances.length > 0) { + await setActiveInstance(instances[0]); + } else { + set({ activeInstance: null }); + } + } + + toast.success("Instance deleted successfully"); + } catch (e) { + console.error("Failed to delete instance:", e); + toast.error("Error deleting instance"); + } + }, + + update: async (instance) => { + const { refresh } = get(); + try { + await updateInstance(instance); + await refresh(); + toast.success("Instance updated successfully"); + } catch (e) { + console.error("Failed to update instance:", e); + toast.error("Error updating instance"); + } + }, + + setActiveInstance: async (instance) => { + try { + await setActiveInstance(instance.id); + set({ activeInstance: instance }); + toast.success("Active instance changed"); + } catch (e) { + console.error("Failed to set active instance:", e); + toast.error("Error setting active instance"); + } + }, + + duplicate: async (id, newName) => { + const { refresh } = get(); + try { + const instance = await duplicateInstance(id, newName); + await refresh(); + toast.success(`Instance duplicated as "${newName}"`); + return instance; + } catch (e) { + console.error("Failed to duplicate instance:", e); + toast.error("Error duplicating instance"); + return null; + } + }, + + get: async (id) => { + try { + return await getInstance(id); + } catch (e) { + console.error("Failed to get instance:", e); + return null; + } + }, +})); diff --git a/packages/ui/src/models/instances.ts b/packages/ui/src/models/instances.ts deleted file mode 100644 index f434c7c..0000000 --- a/packages/ui/src/models/instances.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { toast } from "sonner"; -import { create } from "zustand"; -import { - createInstance, - deleteInstance, - duplicateInstance, - getActiveInstance, - getInstance, - listInstances, - setActiveInstance, - updateInstance, -} from "@/client"; -import type { Instance } from "@/types"; - -interface InstancesState { - // State - instances: Instance[]; - activeInstance: Instance | null; - - // Actions - refresh: () => Promise; - create: (name: string) => Promise; - delete: (id: string) => Promise; - update: (instance: Instance) => Promise; - setActiveInstance: (instance: Instance) => Promise; - duplicate: (id: string, newName: string) => Promise; - getInstance: (id: string) => Promise; -} - -export const useInstancesStore = create((set, get) => ({ - // Initial state - instances: [], - activeInstance: null, - - // Actions - refresh: async () => { - const { setActiveInstance } = get(); - try { - const instances = await listInstances(); - const active = await getActiveInstance(); - - if (!active && instances.length > 0) { - // If no active instance but instances exist, set the first one as active - await setActiveInstance(instances[0]); - } - - set({ instances }); - } catch (e) { - console.error("Failed to load instances:", e); - toast.error("Error loading instances"); - } - }, - - create: async (name) => { - const { refresh } = get(); - try { - const instance = await createInstance(name); - await refresh(); - toast.success(`Instance "${name}" created successfully`); - return instance; - } catch (e) { - console.error("Failed to create instance:", e); - toast.error("Error creating instance"); - return null; - } - }, - - delete: async (id) => { - const { refresh, instances, activeInstance, setActiveInstance } = get(); - try { - await deleteInstance(id); - await refresh(); - - // If deleted instance was active, set another as active - if (activeInstance?.id === id) { - if (instances.length > 0) { - await setActiveInstance(instances[0]); - } else { - set({ activeInstance: null }); - } - } - - toast.success("Instance deleted successfully"); - } catch (e) { - console.error("Failed to delete instance:", e); - toast.error("Error deleting instance"); - } - }, - - update: async (instance) => { - const { refresh } = get(); - try { - await updateInstance(instance); - await refresh(); - toast.success("Instance updated successfully"); - } catch (e) { - console.error("Failed to update instance:", e); - toast.error("Error updating instance"); - } - }, - - setActiveInstance: async (instance) => { - try { - await setActiveInstance(instance.id); - set({ activeInstance: instance }); - toast.success("Active instance changed"); - } catch (e) { - console.error("Failed to set active instance:", e); - toast.error("Error setting active instance"); - } - }, - - duplicate: async (id, newName) => { - const { refresh } = get(); - try { - const instance = await duplicateInstance(id, newName); - await refresh(); - toast.success(`Instance duplicated as "${newName}"`); - return instance; - } catch (e) { - console.error("Failed to duplicate instance:", e); - toast.error("Error duplicating instance"); - return null; - } - }, - - getInstance: async (id) => { - try { - return await getInstance(id); - } catch (e) { - console.error("Failed to get instance:", e); - return null; - } - }, -})); diff --git a/packages/ui/src/pages/index.tsx b/packages/ui/src/pages/index.tsx index 54cfc1e..093ccb2 100644 --- a/packages/ui/src/pages/index.tsx +++ b/packages/ui/src/pages/index.tsx @@ -3,18 +3,21 @@ import { Outlet, useLocation } from "react-router"; import { ParticleBackground } from "@/components/particle-background"; import { Sidebar } from "@/components/sidebar"; import { useAuthStore } from "@/models/auth"; +import { useInstanceStore } from "@/models/instance"; import { useSettingsStore } from "@/models/settings"; export function IndexPage() { const authStore = useAuthStore(); const settingsStore = useSettingsStore(); + const instanceStore = useInstanceStore(); const location = useLocation(); useEffect(() => { authStore.init(); settingsStore.refresh(); - }, [authStore.init, settingsStore.refresh]); + instanceStore.refresh(); + }, [authStore.init, settingsStore.refresh, instanceStore.refresh]); return (
diff --git a/packages/ui/src/pages/instances-view.tsx b/packages/ui/src/pages/instances-view.tsx index ad6bd38..1634905 100644 --- a/packages/ui/src/pages/instances-view.tsx +++ b/packages/ui/src/pages/instances-view.tsx @@ -13,11 +13,11 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { toNumber } from "@/lib/tsrs-utils"; -import { useInstancesStore } from "@/models/instances"; +import { useInstanceStore } from "@/models/instance"; import type { Instance } from "../types/bindings/instance"; export function InstancesView() { - const instancesStore = useInstancesStore(); + const instancesStore = useInstanceStore(); // Modal / UI state const [showCreateModal, setShowCreateModal] = useState(false); -- cgit v1.2.3-70-g09d2