aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/packages/ui-new/src/pages/versions-view.tsx.bk
diff options
context:
space:
mode:
Diffstat (limited to 'packages/ui-new/src/pages/versions-view.tsx.bk')
-rw-r--r--packages/ui-new/src/pages/versions-view.tsx.bk662
1 files changed, 0 insertions, 662 deletions
diff --git a/packages/ui-new/src/pages/versions-view.tsx.bk b/packages/ui-new/src/pages/versions-view.tsx.bk
deleted file mode 100644
index d54596d..0000000
--- a/packages/ui-new/src/pages/versions-view.tsx.bk
+++ /dev/null
@@ -1,662 +0,0 @@
-import { invoke } from "@tauri-apps/api/core";
-import { listen, type UnlistenFn } from "@tauri-apps/api/event";
-import { Coffee, Loader2, Search, Trash2 } from "lucide-react";
-import { useCallback, useEffect, useState } from "react";
-import { toast } from "sonner";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Input } from "@/components/ui/input";
-import { ScrollArea } from "@/components/ui/scroll-area";
-import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
-import { useInstancesStore } from "../models/instances";
-import { useGameStore } from "../stores/game-store";
-import type { Version } from "../types/bindings/manifest";
-
-interface InstalledModdedVersion {
- id: string;
- javaVersion?: number;
-}
-
-type TypeFilter = "all" | "release" | "snapshot" | "installed";
-
-export function VersionsView() {
- const { versions, selectedVersion, loadVersions, setSelectedVersion } =
- useGameStore();
- const { activeInstance } = useInstancesStore();
-
- const [searchQuery, setSearchQuery] = useState("");
- const [typeFilter, setTypeFilter] = useState<TypeFilter>("all");
- const [installedModdedVersions, setInstalledModdedVersions] = useState<
- InstalledModdedVersion[]
- >([]);
- const [, setIsLoadingModded] = useState(false);
- const [showDeleteDialog, setShowDeleteDialog] = useState(false);
- const [versionToDelete, setVersionToDelete] = useState<string | null>(null);
- const [isDeleting, setIsDeleting] = useState(false);
- const [selectedVersionMetadata, setSelectedVersionMetadata] = useState<{
- id: string;
- javaVersion?: number;
- isInstalled: boolean;
- } | null>(null);
- const [isLoadingMetadata, setIsLoadingMetadata] = useState(false);
- const [showModLoaderSelector, setShowModLoaderSelector] = useState(false);
-
- const normalizedQuery = searchQuery.trim().toLowerCase().replace(/。/g, ".");
-
- // Load installed modded versions with Java version info
- const loadInstalledModdedVersions = useCallback(async () => {
- if (!activeInstance) {
- setInstalledModdedVersions([]);
- setIsLoadingModded(false);
- return;
- }
-
- setIsLoadingModded(true);
- try {
- const allInstalled = await invoke<Array<{ id: string; type: string }>>(
- "list_installed_versions",
- { instanceId: activeInstanceId },
- );
-
- const moddedIds = allInstalled
- .filter((v) => v.type === "fabric" || v.type === "forge")
- .map((v) => v.id);
-
- const versionsWithJava = await Promise.all(
- moddedIds.map(async (id) => {
- try {
- const javaVersion = await invoke<number | null>(
- "get_version_java_version",
- {
- instanceId: activeInstanceId,
- versionId: id,
- },
- );
- return {
- id,
- javaVersion: javaVersion ?? undefined,
- };
- } catch (e) {
- console.error(`Failed to get Java version for ${id}:`, e);
- return { id, javaVersion: undefined };
- }
- }),
- );
-
- setInstalledModdedVersions(versionsWithJava);
- } catch (e) {
- console.error("Failed to load installed modded versions:", e);
- toast.error("Error loading modded versions");
- } finally {
- setIsLoadingModded(false);
- }
- }, [activeInstanceId]);
-
- // Combined versions list (vanilla + modded)
- const allVersions = (() => {
- const moddedVersions: Version[] = installedModdedVersions.map((v) => {
- const versionType = v.id.startsWith("fabric-loader-")
- ? "fabric"
- : v.id.includes("-forge-")
- ? "forge"
- : "fabric";
- return {
- id: v.id,
- type: versionType,
- url: "",
- time: "",
- releaseTime: new Date().toISOString(),
- javaVersion: BigInt(v.javaVersion ?? 0),
- isInstalled: true,
- };
- });
- return [...moddedVersions, ...versions];
- })();
-
- // Filter versions based on search and type filter
- const filteredVersions = allVersions.filter((version) => {
- if (typeFilter === "release" && version.type !== "release") return false;
- if (typeFilter === "snapshot" && version.type !== "snapshot") return false;
- if (typeFilter === "installed" && !version.isInstalled) return false;
-
- if (
- normalizedQuery &&
- !version.id.toLowerCase().includes(normalizedQuery)
- ) {
- return false;
- }
-
- return true;
- });
-
- // Get version badge styling
- const getVersionBadge = (type: string) => {
- switch (type) {
- case "release":
- return {
- text: "Release",
- variant: "default" as const,
- className: "bg-emerald-500 hover:bg-emerald-600",
- };
- case "snapshot":
- return {
- text: "Snapshot",
- variant: "secondary" as const,
- className: "bg-amber-500 hover:bg-amber-600",
- };
- case "fabric":
- return {
- text: "Fabric",
- variant: "outline" as const,
- className: "border-indigo-500 text-indigo-700 dark:text-indigo-300",
- };
- case "forge":
- return {
- text: "Forge",
- variant: "outline" as const,
- className: "border-orange-500 text-orange-700 dark:text-orange-300",
- };
- case "modpack":
- return {
- text: "Modpack",
- variant: "outline" as const,
- className: "border-purple-500 text-purple-700 dark:text-purple-300",
- };
- default:
- return {
- text: type,
- variant: "outline" as const,
- className: "border-gray-500 text-gray-700 dark:text-gray-300",
- };
- }
- };
-
- // Load version metadata
- const loadVersionMetadata = useCallback(
- async (versionId: string) => {
- if (!versionId || !activeInstanceId) {
- setSelectedVersionMetadata(null);
- return;
- }
-
- setIsLoadingMetadata(true);
- try {
- const metadata = await invoke<{
- id: string;
- javaVersion?: number;
- isInstalled: boolean;
- }>("get_version_metadata", {
- instanceId: activeInstanceId,
- versionId,
- });
- setSelectedVersionMetadata(metadata);
- } catch (e) {
- console.error("Failed to load version metadata:", e);
- setSelectedVersionMetadata(null);
- } finally {
- setIsLoadingMetadata(false);
- }
- },
- [activeInstanceId],
- );
-
- // Get base version for mod loader selector
- const selectedBaseVersion = (() => {
- if (!selectedVersion) return "";
-
- if (selectedVersion.startsWith("fabric-loader-")) {
- const parts = selectedVersion.split("-");
- return parts[parts.length - 1];
- }
- if (selectedVersion.includes("-forge-")) {
- return selectedVersion.split("-forge-")[0];
- }
-
- const version = versions.find((v) => v.id === selectedVersion);
- return version ? selectedVersion : "";
- })();
-
- // Handle version deletion
- const handleDeleteVersion = async () => {
- if (!versionToDelete || !activeInstanceId) return;
-
- setIsDeleting(true);
- try {
- await invoke("delete_version", {
- instanceId: activeInstanceId,
- versionId: versionToDelete,
- });
-
- if (selectedVersion === versionToDelete) {
- setSelectedVersion("");
- }
-
- setShowDeleteDialog(false);
- setVersionToDelete(null);
- toast.success("Version deleted successfully");
-
- await loadVersions(activeInstanceId);
- await loadInstalledModdedVersions();
- } catch (e) {
- console.error("Failed to delete version:", e);
- toast.error(`Failed to delete version: ${e}`);
- } finally {
- setIsDeleting(false);
- }
- };
-
- // Show delete confirmation dialog
- const showDeleteConfirmation = (versionId: string, e: React.MouseEvent) => {
- e.stopPropagation();
- setVersionToDelete(versionId);
- setShowDeleteDialog(true);
- };
-
- // Setup event listeners for version updates
- useEffect(() => {
- let unlisteners: UnlistenFn[] = [];
-
- const setupEventListeners = async () => {
- try {
- const versionDeletedUnlisten = await listen(
- "version-deleted",
- async () => {
- await loadVersions(activeInstanceId ?? undefined);
- await loadInstalledModdedVersions();
- },
- );
-
- const downloadCompleteUnlisten = await listen(
- "download-complete",
- async () => {
- await loadVersions(activeInstanceId ?? undefined);
- await loadInstalledModdedVersions();
- },
- );
-
- const versionInstalledUnlisten = await listen(
- "version-installed",
- async () => {
- await loadVersions(activeInstanceId ?? undefined);
- await loadInstalledModdedVersions();
- },
- );
-
- const fabricInstalledUnlisten = await listen(
- "fabric-installed",
- async () => {
- await loadVersions(activeInstanceId ?? undefined);
- await loadInstalledModdedVersions();
- },
- );
-
- const forgeInstalledUnlisten = await listen(
- "forge-installed",
- async () => {
- await loadVersions(activeInstanceId ?? undefined);
- await loadInstalledModdedVersions();
- },
- );
-
- unlisteners = [
- versionDeletedUnlisten,
- downloadCompleteUnlisten,
- versionInstalledUnlisten,
- fabricInstalledUnlisten,
- forgeInstalledUnlisten,
- ];
- } catch (e) {
- console.error("Failed to setup event listeners:", e);
- }
- };
-
- setupEventListeners();
- loadInstalledModdedVersions();
-
- return () => {
- unlisteners.forEach((unlisten) => {
- unlisten();
- });
- };
- }, [activeInstanceId, loadVersions, loadInstalledModdedVersions]);
-
- // Load metadata when selected version changes
- useEffect(() => {
- if (selectedVersion) {
- loadVersionMetadata(selectedVersion);
- } else {
- setSelectedVersionMetadata(null);
- }
- }, [selectedVersion, loadVersionMetadata]);
-
- return (
- <div className="h-full flex flex-col p-6 overflow-hidden">
- <div className="flex items-center justify-between mb-6">
- <h2 className="text-3xl font-black bg-clip-text text-transparent bg-linear-to-r from-gray-900 to-gray-600 dark:from-white dark:to-white/60">
- Version Manager
- </h2>
- <div className="text-sm dark:text-white/40 text-black/50">
- Select a version to play or modify
- </div>
- </div>
-
- <div className="flex-1 grid grid-cols-1 lg:grid-cols-3 gap-6 overflow-hidden">
- {/* Left: Version List */}
- <div className="lg:col-span-2 flex flex-col gap-4 overflow-hidden">
- {/* Search and Filters */}
- <div className="flex gap-3">
- <div className="relative flex-1">
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
- <Input
- type="text"
- placeholder="Search versions..."
- className="pl-9 bg-white/60 dark:bg-black/20 border-black/10 dark:border-white/10 dark:text-white text-gray-900 placeholder-black/30 dark:placeholder-white/30 focus:border-indigo-500/50 dark:focus:bg-black/40 focus:bg-white/80 backdrop-blur-sm"
- value={searchQuery}
- onChange={(e) => setSearchQuery(e.target.value)}
- />
- </div>
- </div>
-
- {/* Type Filter Tabs */}
- <Tabs
- value={typeFilter}
- onValueChange={(v) => setTypeFilter(v as TypeFilter)}
- className="w-full"
- >
- <TabsList className="grid grid-cols-4 bg-white/60 dark:bg-black/20 border-black/5 dark:border-white/5">
- <TabsTrigger value="all">All</TabsTrigger>
- <TabsTrigger value="release">Release</TabsTrigger>
- <TabsTrigger value="snapshot">Snapshot</TabsTrigger>
- <TabsTrigger value="installed">Installed</TabsTrigger>
- </TabsList>
- </Tabs>
-
- {/* Version List */}
- <ScrollArea className="flex-1 pr-2">
- {versions.length === 0 ? (
- <div className="flex items-center justify-center h-40 dark:text-white/30 text-black/30 italic animate-pulse">
- Loading versions...
- </div>
- ) : filteredVersions.length === 0 ? (
- <div className="flex flex-col items-center justify-center h-40 dark:text-white/30 text-black/30 gap-2">
- <span className="text-2xl">👻</span>
- <span>No matching versions found</span>
- </div>
- ) : (
- <div className="space-y-2">
- {filteredVersions.map((version) => {
- const badge = getVersionBadge(version.type);
- const isSelected = selectedVersion === version.id;
-
- return (
- <Card
- key={version.id}
- className={`w-full cursor-pointer transition-all duration-200 relative overflow-hidden group ${
- isSelected
- ? "border-indigo-200 dark:border-indigo-500/50 bg-indigo-50 dark:bg-indigo-600/20 shadow-[0_0_20px_rgba(99,102,241,0.2)]"
- : "border-black/5 dark:border-white/5 bg-white/40 dark:bg-white/5 hover:bg-white/60 dark:hover:bg-white/10 hover:border-black/10 dark:hover:border-white/10 hover:translate-x-1"
- }`}
- onClick={() => setSelectedVersion(version.id)}
- >
- {isSelected && (
- <div className="absolute inset-0 bg-linear-to-r from-indigo-500/10 to-transparent pointer-events-none" />
- )}
-
- <CardContent className="p-4">
- <div className="flex items-center justify-between">
- <div className="flex items-center gap-4 flex-1">
- <Badge
- variant={badge.variant}
- className={badge.className}
- >
- {badge.text}
- </Badge>
- <div className="flex-1">
- <div
- className={`font-bold font-mono text-lg tracking-tight ${
- isSelected
- ? "text-black dark:text-white"
- : "text-gray-700 dark:text-zinc-300 group-hover:text-black dark:group-hover:text-white"
- }`}
- >
- {version.id}
- </div>
- <div className="flex items-center gap-2 mt-0.5">
- {version.releaseTime &&
- version.type !== "fabric" &&
- version.type !== "forge" && (
- <div className="text-xs dark:text-white/30 text-black/30">
- {new Date(
- version.releaseTime,
- ).toLocaleDateString()}
- </div>
- )}
- {version.javaVersion && (
- <div className="flex items-center gap-1 text-xs dark:text-white/40 text-black/40">
- <Coffee className="h-3 w-3 opacity-60" />
- <span className="font-medium">
- Java {version.javaVersion}
- </span>
- </div>
- )}
- </div>
- </div>
- </div>
-
- <div className="flex items-center gap-2">
- {version.isInstalled && (
- <Button
- variant="ghost"
- size="icon"
- className="opacity-0 group-hover:opacity-100 transition-opacity text-red-500 dark:text-red-400 hover:bg-red-500/10 dark:hover:bg-red-500/20"
- onClick={(e) =>
- showDeleteConfirmation(version.id, e)
- }
- title="Delete version"
- >
- <Trash2 className="h-4 w-4" />
- </Button>
- )}
- </div>
- </div>
- </CardContent>
- </Card>
- );
- })}
- </div>
- )}
- </ScrollArea>
- </div>
-
- {/* Right: Version Details */}
- <div className="flex flex-col gap-6">
- <Card className="border-black/5 dark:border-white/5 bg-white/40 dark:bg-white/5 backdrop-blur-sm">
- <CardHeader>
- <CardTitle className="text-lg">Version Details</CardTitle>
- </CardHeader>
- <CardContent className="space-y-4">
- {selectedVersion ? (
- <>
- <div>
- <div className="text-sm text-muted-foreground mb-1">
- Selected Version
- </div>
- <div className="font-mono text-xl font-bold">
- {selectedVersion}
- </div>
- </div>
-
- {isLoadingMetadata ? (
- <div className="flex items-center gap-2">
- <Loader2 className="h-4 w-4 animate-spin" />
- <span className="text-sm">Loading metadata...</span>
- </div>
- ) : selectedVersionMetadata ? (
- <div className="space-y-3">
- <div>
- <div className="text-sm text-muted-foreground mb-1">
- Installation Status
- </div>
- <Badge
- variant={
- selectedVersionMetadata.isInstalled
- ? "default"
- : "outline"
- }
- >
- {selectedVersionMetadata.isInstalled
- ? "Installed"
- : "Not Installed"}
- </Badge>
- </div>
-
- {selectedVersionMetadata.javaVersion && (
- <div>
- <div className="text-sm text-muted-foreground mb-1">
- Java Version
- </div>
- <div className="flex items-center gap-2">
- <Coffee className="h-4 w-4" />
- <span>
- Java {selectedVersionMetadata.javaVersion}
- </span>
- </div>
- </div>
- )}
-
- {!selectedVersionMetadata.isInstalled && (
- <Button
- className="w-full"
- onClick={() => setShowModLoaderSelector(true)}
- >
- Install with Mod Loader
- </Button>
- )}
- </div>
- ) : null}
- </>
- ) : (
- <div className="text-center py-8 text-muted-foreground">
- Select a version to view details
- </div>
- )}
- </CardContent>
- </Card>
-
- {/* Mod Loader Installation */}
- {showModLoaderSelector && selectedBaseVersion && (
- <Card className="border-black/5 dark:border-white/5 bg-white/40 dark:bg-white/5 backdrop-blur-sm">
- <CardHeader>
- <CardTitle className="text-lg">Install Mod Loader</CardTitle>
- </CardHeader>
- <CardContent className="space-y-4">
- <div className="text-sm text-muted-foreground">
- Install {selectedBaseVersion} with Fabric or Forge
- </div>
- <div className="flex gap-2">
- <Button
- variant="outline"
- className="flex-1"
- onClick={async () => {
- if (!activeInstanceId) return;
- try {
- await invoke("install_fabric", {
- instanceId: activeInstanceId,
- gameVersion: selectedBaseVersion,
- loaderVersion: "latest",
- });
- toast.success("Fabric installation started");
- setShowModLoaderSelector(false);
- } catch (e) {
- console.error("Failed to install Fabric:", e);
- toast.error(`Failed to install Fabric: ${e}`);
- }
- }}
- >
- Install Fabric
- </Button>
- <Button
- variant="outline"
- className="flex-1"
- onClick={async () => {
- if (!activeInstanceId) return;
- try {
- await invoke("install_forge", {
- instanceId: activeInstanceId,
- gameVersion: selectedBaseVersion,
- installerVersion: "latest",
- });
- toast.success("Forge installation started");
- setShowModLoaderSelector(false);
- } catch (e) {
- console.error("Failed to install Forge:", e);
- toast.error(`Failed to install Forge: ${e}`);
- }
- }}
- >
- Install Forge
- </Button>
- </div>
- <Button
- variant="ghost"
- size="sm"
- onClick={() => setShowModLoaderSelector(false)}
- >
- Cancel
- </Button>
- </CardContent>
- </Card>
- )}
- </div>
- </div>
-
- {/* Delete Confirmation Dialog */}
- <Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
- <DialogContent>
- <DialogHeader>
- <DialogTitle>Delete Version</DialogTitle>
- <DialogDescription>
- Are you sure you want to delete version "{versionToDelete}"? This
- action cannot be undone.
- </DialogDescription>
- </DialogHeader>
- <DialogFooter>
- <Button
- variant="outline"
- onClick={() => {
- setShowDeleteDialog(false);
- setVersionToDelete(null);
- }}
- disabled={isDeleting}
- >
- Cancel
- </Button>
- <Button
- variant="destructive"
- onClick={handleDeleteVersion}
- disabled={isDeleting}
- >
- {isDeleting ? (
- <>
- <Loader2 className="mr-2 h-4 w-4 animate-spin" />
- Deleting...
- </>
- ) : (
- "Delete"
- )}
- </Button>
- </DialogFooter>
- </DialogContent>
- </Dialog>
- </div>
- );
-}