From 87044a747b47bd83249d61a45842c7f7b2eae56d Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 11 Jan 2026 05:52:14 +0000 Subject: Contract system --- .../src/components/files/RepoSyncIndicator.tsx | 190 +++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 makima/frontend/src/components/files/RepoSyncIndicator.tsx (limited to 'makima/frontend/src/components/files/RepoSyncIndicator.tsx') diff --git a/makima/frontend/src/components/files/RepoSyncIndicator.tsx b/makima/frontend/src/components/files/RepoSyncIndicator.tsx new file mode 100644 index 0000000..82d79f7 --- /dev/null +++ b/makima/frontend/src/components/files/RepoSyncIndicator.tsx @@ -0,0 +1,190 @@ +import { useState, useCallback } from "react"; +import { syncFileFromRepo } from "../../lib/api"; + +interface RepoSyncIndicatorProps { + fileId: string; + repoFilePath: string | null | undefined; + repoSyncStatus: string | null | undefined; + repoSyncedAt: string | null | undefined; + onSyncComplete?: () => void; + /** Callback to push file content to repo (creates a task) */ + onPushToRepo?: () => void; + /** Whether a push operation is in progress */ + isPushing?: boolean; +} + +/** + * Shows repository file link status and provides sync functionality. + * Displays the linked file path and allows updating from the repo via daemon, + * or pushing local changes back to the repo. + */ +export function RepoSyncIndicator({ + fileId, + repoFilePath, + repoSyncStatus, + repoSyncedAt, + onSyncComplete, + onPushToRepo, + isPushing = false, +}: RepoSyncIndicatorProps) { + const [isSyncing, setIsSyncing] = useState(false); + const [error, setError] = useState(null); + + const handleSync = useCallback(async () => { + setIsSyncing(true); + setError(null); + try { + await syncFileFromRepo(fileId); + // The actual update happens via WebSocket notification + // Give a brief delay then notify parent + setTimeout(() => { + onSyncComplete?.(); + }, 500); + } catch (err) { + setError(err instanceof Error ? err.message : "Sync failed"); + } finally { + setIsSyncing(false); + } + }, [fileId, onSyncComplete]); + + // Don't render if no repo file path is set + if (!repoFilePath) { + return null; + } + + const isActuallySyncing = isSyncing || repoSyncStatus === "syncing"; + const isSynced = repoSyncStatus === "synced"; + const isModified = repoSyncStatus === "modified"; + + // Format the synced timestamp + const syncedAtFormatted = repoSyncedAt + ? new Date(repoSyncedAt).toLocaleString() + : null; + + return ( +
+ {/* File path icon and link */} +
+ + + + + + {repoFilePath} + +
+ + {/* Status indicator */} + {isSynced && ( + + + + + + )} + {isModified && ( + + + + + + + + )} + + {/* Pull from repo button */} + + + {/* Push to repo button */} + {onPushToRepo && ( + + )} + + {/* Error message */} + {error && ( + + Failed + + )} +
+ ); +} -- cgit v1.2.3