summaryrefslogtreecommitdiff
path: root/makima/frontend/src/hooks
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2025-12-24 05:45:22 +0000
committersoryu <soryu@soryu.co>2025-12-24 05:45:22 +0000
commit2faba0388f93d8e4fb86219eba7883b331d501ff (patch)
tree92b83b8d558a652d3777627b2ac95ded250faa48 /makima/frontend/src/hooks
parent8f016a0e9d14badc39dffd67ed6fb862f9d08496 (diff)
downloadsoryu-2faba0388f93d8e4fb86219eba7883b331d501ff.tar.gz
soryu-2faba0388f93d8e4fb86219eba7883b331d501ff.zip
Add versioning to files
Diffstat (limited to 'makima/frontend/src/hooks')
-rw-r--r--makima/frontend/src/hooks/useVersionHistory.ts137
1 files changed, 137 insertions, 0 deletions
diff --git a/makima/frontend/src/hooks/useVersionHistory.ts b/makima/frontend/src/hooks/useVersionHistory.ts
new file mode 100644
index 0000000..f9d4122
--- /dev/null
+++ b/makima/frontend/src/hooks/useVersionHistory.ts
@@ -0,0 +1,137 @@
+import { useState, useCallback, useEffect } from "react";
+import {
+ listFileVersions,
+ getFileVersion,
+ restoreFileVersion,
+ type FileVersionSummary,
+ type FileVersion,
+ type FileDetail,
+ VersionConflictError,
+} from "../lib/api";
+
+export interface UseVersionHistoryOptions {
+ fileId: string | null;
+ currentVersion: number;
+}
+
+export interface VersionHistoryState {
+ versions: FileVersionSummary[];
+ loading: boolean;
+ error: string | null;
+ selectedVersion: FileVersion | null;
+ loadingVersion: boolean;
+}
+
+export function useVersionHistory(options: UseVersionHistoryOptions) {
+ const { fileId, currentVersion } = options;
+ const [versions, setVersions] = useState<FileVersionSummary[]>([]);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState<string | null>(null);
+ const [selectedVersion, setSelectedVersion] = useState<FileVersion | null>(null);
+ const [loadingVersion, setLoadingVersion] = useState(false);
+ const [restoring, setRestoring] = useState(false);
+ const [conflict, setConflict] = useState<{ expected: number; actual: number } | null>(null);
+
+ // Fetch version list
+ const fetchVersions = useCallback(async () => {
+ if (!fileId) return;
+
+ setLoading(true);
+ setError(null);
+ try {
+ const response = await listFileVersions(fileId);
+ setVersions(response.versions);
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch versions");
+ } finally {
+ setLoading(false);
+ }
+ }, [fileId]);
+
+ // Fetch a specific version's content
+ const fetchVersion = useCallback(
+ async (version: number): Promise<FileVersion | null> => {
+ if (!fileId) return null;
+
+ setLoadingVersion(true);
+ setError(null);
+ try {
+ const versionData = await getFileVersion(fileId, version);
+ setSelectedVersion(versionData);
+ return versionData;
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch version");
+ return null;
+ } finally {
+ setLoadingVersion(false);
+ }
+ },
+ [fileId]
+ );
+
+ // Restore to a specific version (creates a new version with that content)
+ const restoreToVersion = useCallback(
+ async (targetVersion: number): Promise<FileDetail | null> => {
+ if (!fileId) return null;
+
+ setRestoring(true);
+ setError(null);
+ setConflict(null);
+ try {
+ const result = await restoreFileVersion(fileId, targetVersion, currentVersion);
+ // Refresh version list after restore
+ await fetchVersions();
+ setSelectedVersion(null);
+ return result;
+ } catch (e) {
+ if (e instanceof VersionConflictError) {
+ setConflict({
+ expected: e.expectedVersion,
+ actual: e.actualVersion,
+ });
+ return null;
+ }
+ setError(e instanceof Error ? e.message : "Failed to restore version");
+ return null;
+ } finally {
+ setRestoring(false);
+ }
+ },
+ [fileId, currentVersion, fetchVersions]
+ );
+
+ // Clear selected version
+ const clearSelectedVersion = useCallback(() => {
+ setSelectedVersion(null);
+ }, []);
+
+ // Clear conflict
+ const clearConflict = useCallback(() => {
+ setConflict(null);
+ }, []);
+
+ // Fetch versions when fileId changes
+ useEffect(() => {
+ if (fileId) {
+ fetchVersions();
+ } else {
+ setVersions([]);
+ setSelectedVersion(null);
+ }
+ }, [fileId, fetchVersions]);
+
+ return {
+ versions,
+ loading,
+ error,
+ selectedVersion,
+ loadingVersion,
+ restoring,
+ conflict,
+ fetchVersions,
+ fetchVersion,
+ restoreToVersion,
+ clearSelectedVersion,
+ clearConflict,
+ };
+}