mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-06-12 09:47:51 +02:00
refactor: sync
This commit is contained in:
@@ -555,9 +555,7 @@ export function CreateProfileDialog({
|
||||
})()}
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="font-medium">
|
||||
Chromium (Wayfern)
|
||||
</div>
|
||||
<div className="font-medium">Wayfern</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Anti-Detect Browser
|
||||
</div>
|
||||
@@ -580,9 +578,7 @@ export function CreateProfileDialog({
|
||||
})()}
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="font-medium">
|
||||
Firefox (Camoufox)
|
||||
</div>
|
||||
<div className="font-medium">Camoufox</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Anti-Detect Browser
|
||||
</div>
|
||||
|
||||
@@ -1595,7 +1595,10 @@ export function ProfilesDataTable({
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Created on {osName} - view only</p>
|
||||
<p>
|
||||
This profile was created on {osName} and is not supported on
|
||||
this system
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -1608,7 +1611,12 @@ export function ProfilesDataTable({
|
||||
: "another OS";
|
||||
return (
|
||||
<NonHoverableTooltip
|
||||
content={<p>Created on {osName} - view only</p>}
|
||||
content={
|
||||
<p>
|
||||
This profile was created on {osName} and is not supported on
|
||||
this system
|
||||
</p>
|
||||
}
|
||||
sideOffset={4}
|
||||
horizontalOffset={8}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
"use client";
|
||||
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { LoadingButton } from "@/components/loading-button";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { showErrorToast, showSuccessToast } from "@/lib/toast-utils";
|
||||
|
||||
interface UnsyncedEntityCounts {
|
||||
proxies: number;
|
||||
groups: number;
|
||||
vpns: number;
|
||||
}
|
||||
|
||||
interface SyncAllDialogProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function SyncAllDialog({ isOpen, onClose }: SyncAllDialogProps) {
|
||||
const { t } = useTranslation();
|
||||
const [counts, setCounts] = useState<UnsyncedEntityCounts | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isEnabling, setIsEnabling] = useState(false);
|
||||
|
||||
const loadCounts = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const result = await invoke<UnsyncedEntityCounts>(
|
||||
"get_unsynced_entity_counts",
|
||||
);
|
||||
setCounts(result);
|
||||
} catch (error) {
|
||||
console.error("Failed to get unsynced entity counts:", error);
|
||||
setCounts(null);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
void loadCounts();
|
||||
}
|
||||
}, [isOpen, loadCounts]);
|
||||
|
||||
const handleEnableAll = useCallback(async () => {
|
||||
setIsEnabling(true);
|
||||
try {
|
||||
await invoke("enable_sync_for_all_entities");
|
||||
showSuccessToast(t("syncAll.success"));
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error("Failed to enable sync for all entities:", error);
|
||||
showErrorToast(String(error));
|
||||
} finally {
|
||||
setIsEnabling(false);
|
||||
}
|
||||
}, [onClose, t]);
|
||||
|
||||
const totalCount =
|
||||
(counts?.proxies ?? 0) + (counts?.groups ?? 0) + (counts?.vpns ?? 0);
|
||||
|
||||
// Don't show if there's nothing to sync
|
||||
if (!isLoading && totalCount === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts: string[] = [];
|
||||
if (counts?.proxies && counts.proxies > 0) {
|
||||
parts.push(t("syncAll.proxies", { count: counts.proxies }));
|
||||
}
|
||||
if (counts?.groups && counts.groups > 0) {
|
||||
parts.push(t("syncAll.groups", { count: counts.groups }));
|
||||
}
|
||||
if (counts?.vpns && counts.vpns > 0) {
|
||||
parts.push(t("syncAll.vpns", { count: counts.vpns }));
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen && totalCount > 0} onOpenChange={onClose}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t("syncAll.title")}</DialogTitle>
|
||||
<DialogDescription>{t("syncAll.description")}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center py-8">
|
||||
<div className="w-6 h-6 rounded-full border-2 border-current animate-spin border-t-transparent" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="py-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("syncAll.itemsList", { items: parts.join(", ") })}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DialogFooter className="flex gap-2">
|
||||
<Button variant="outline" onClick={onClose} disabled={isEnabling}>
|
||||
{t("syncAll.skip")}
|
||||
</Button>
|
||||
<LoadingButton
|
||||
onClick={handleEnableAll}
|
||||
isLoading={isEnabling}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{t("syncAll.enableAll")}
|
||||
</LoadingButton>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import type { SyncSettings } from "@/types";
|
||||
|
||||
interface SyncConfigDialogProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onClose: (loginOccurred?: boolean) => void;
|
||||
}
|
||||
|
||||
export function SyncConfigDialog({ isOpen, onClose }: SyncConfigDialogProps) {
|
||||
@@ -179,8 +179,8 @@ export function SyncConfigDialog({ isOpen, onClose }: SyncConfigDialogProps) {
|
||||
} catch (e) {
|
||||
console.error("Failed to restart sync service:", e);
|
||||
}
|
||||
// Auto-close dialog after successful login
|
||||
onClose();
|
||||
// Auto-close dialog after successful login, signal that login occurred
|
||||
onClose(true);
|
||||
} catch (error) {
|
||||
console.error("OTP verification failed:", error);
|
||||
showErrorToast(String(error));
|
||||
|
||||
Reference in New Issue
Block a user