gbclient/app/sync/page.tsx

204 lines
5.8 KiB
TypeScript
Raw Normal View History

"use client";
import { useState, useEffect } from "react";
import { invoke } from "@tauri-apps/api/core";
interface RcloneConfig {
name: string;
remote_path: string;
local_path: string;
access_key: string;
secret_key: string;
}
interface SyncStatus {
name: string;
status: string;
transferred: string;
bytes: string;
errors: number;
last_updated: string;
}
type Screen = "Main" | "Status";
function Page() {
const [state, setState] = useState({
name: "",
access_key: "",
secret_key: "",
status_text: "Enter credentials to set up sync",
sync_statuses: [] as SyncStatus[],
show_config_dialog: false,
show_about_dialog: false,
current_screen: "Main" as Screen,
});
useEffect(() => {
if (state.current_screen === "Status") {
const interval = setInterval(() => {
// In a real app, you would fetch actual configs here
// This is just a mock implementation
invoke<SyncStatus>("get_status", { remoteName: "example" })
.then((status) => {
setState(prev => ({
...prev,
sync_statuses: [status]
}));
})
.catch(console.error);
}, 5000);
return () => clearInterval(interval);
}
}, [state.current_screen]);
const saveConfig = async () => {
if (!state.name || !state.access_key || !state.secret_key) {
setState(prev => ({ ...prev, status_text: "All fields are required!" }));
return;
}
const config: RcloneConfig = {
name: state.name,
remote_path: `s3://${state.name}`,
local_path: `${window.__TAURI__.path.homeDir}/General Bots/${state.name}`,
access_key: state.access_key,
secret_key: state.secret_key,
};
try {
await core.invoke("save_config", { config });
setState(prev => ({
...prev,
status_text: "New sync saved!",
show_config_dialog: false
}));
} catch (e) {
setState(prev => ({
...prev,
status_text: `Failed to save config: ${e}`
}));
}
};
const startSync = async () => {
// In a real app, you would fetch actual configs here
const config: RcloneConfig = {
name: state.name || "example",
remote_path: `s3://${state.name || "example"}`,
local_path: `${window.__TAURI__.path.homeDir}/General Bots/${state.name || "example"}`,
access_key: state.access_key || "dummy",
secret_key: state.secret_key || "dummy",
};
try {
await core.invoke("start_sync", { config });
setState(prev => ({
...prev,
status_text: "Sync started!"
}));
} catch (e) {
setState(prev => ({
...prev,
status_text: `Failed to start sync: ${e}`
}));
}
};
const stopSync = async () => {
try {
await core.invoke("stop_sync");
setState(prev => ({
...prev,
status_text: "Sync stopped."
}));
} catch (e) {
setState(prev => ({
...prev,
status_text: `Failed to stop sync: ${e}`
}));
}
};
return (
<div className="app">
<div className="menu-bar">
<button onClick={() => setState(prev => ({ ...prev, show_config_dialog: true }))}>
Add Sync Configuration
</button>
<button onClick={() => setState(prev => ({ ...prev, show_about_dialog: true }))}>
About
</button>
</div>
{state.current_screen === "Main" ? (
<div className="main-screen">
<h1>General Bots</h1>
<p>{state.status_text}</p>
<button onClick={startSync}>Start Sync</button>
<button onClick={stopSync}>Stop Sync</button>
<button onClick={() => setState(prev => ({ ...prev, current_screen: "Status" }))}>
Show Status
</button>
</div>
) : (
<div className="status-screen">
<h1>Sync Status</h1>
<div className="status-list">
{state.sync_statuses.map((status, index) => (
<div key={index} className="status-item">
<h2>{status.name}</h2>
<p>Status: {status.status}</p>
<p>Transferred: {status.transferred}</p>
<p>Bytes: {status.bytes}</p>
<p>Errors: {status.errors}</p>
<p>Last Updated: {status.last_updated}</p>
</div>
))}
</div>
<button onClick={() => setState(prev => ({ ...prev, current_screen: "Main" }))}>
Back
</button>
</div>
)}
{state.show_config_dialog && (
<div className="dialog">
<h2>Add Sync Configuration</h2>
<input
value={state.name}
onChange={(e) => setState(prev => ({ ...prev, name: e.target.value }))}
placeholder="Enter sync name"
/>
<input
value={state.access_key}
onChange={(e) => setState(prev => ({ ...prev, access_key: e.target.value }))}
placeholder="Enter access key"
/>
<input
value={state.secret_key}
onChange={(e) => setState(prev => ({ ...prev, secret_key: e.target.value }))}
placeholder="Enter secret key"
/>
<button onClick={saveConfig}>Save</button>
<button onClick={() => setState(prev => ({ ...prev, show_config_dialog: false }))}>
Cancel
</button>
</div>
)}
{state.show_about_dialog && (
<div className="dialog">
<h2>About General Bots</h2>
<p>Version: 1.0.0</p>
<p>A professional-grade sync tool for OneDrive/Dropbox-like functionality.</p>
<button onClick={() => setState(prev => ({ ...prev, show_about_dialog: false }))}>
Close
</button>
</div>
)}
</div>
);
}
export default Page;