From bab9301c316b3ccd272c9914061138623d47b6d1 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:17:30 +0400 Subject: [PATCH] style: make ui for proxies and groups similar --- src/components/group-management-dialog.tsx | 84 ++++--- src/components/proxy-check-button.tsx | 15 +- src/components/proxy-management-dialog.tsx | 270 ++++++++++----------- 3 files changed, 193 insertions(+), 176 deletions(-) diff --git a/src/components/group-management-dialog.tsx b/src/components/group-management-dialog.tsx index 8f7c197..c2f38fe 100644 --- a/src/components/group-management-dialog.tsx +++ b/src/components/group-management-dialog.tsx @@ -7,6 +7,7 @@ import { LuPencil, LuTrash2 } from "react-icons/lu"; import { CreateGroupDialog } from "@/components/create-group-dialog"; import { DeleteGroupDialog } from "@/components/delete-group-dialog"; import { EditGroupDialog } from "@/components/edit-group-dialog"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -26,7 +27,12 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import type { ProfileGroup } from "@/types"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import type { GroupWithCount, ProfileGroup } from "@/types"; import { RippleButton } from "./ui/ripple"; interface GroupManagementDialogProps { @@ -40,7 +46,7 @@ export function GroupManagementDialog({ onClose, onGroupManagementComplete, }: GroupManagementDialogProps) { - const [groups, setGroups] = useState([]); + const [groups, setGroups] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -48,13 +54,17 @@ export function GroupManagementDialog({ const [createDialogOpen, setCreateDialogOpen] = useState(false); const [editDialogOpen, setEditDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); - const [selectedGroup, setSelectedGroup] = useState(null); + const [selectedGroup, setSelectedGroup] = useState( + null, + ); const loadGroups = useCallback(async () => { setIsLoading(true); setError(null); try { - const groupList = await invoke("get_profile_groups"); + const groupList = await invoke( + "get_groups_with_profile_counts", + ); setGroups(groupList); } catch (err) { console.error("Failed to load groups:", err); @@ -65,23 +75,19 @@ export function GroupManagementDialog({ }, []); const handleGroupCreated = useCallback( - (newGroup: ProfileGroup) => { - setGroups((prev) => [...prev, newGroup]); + (_newGroup: ProfileGroup) => { + void loadGroups(); onGroupManagementComplete(); }, - [onGroupManagementComplete], + [loadGroups, onGroupManagementComplete], ); const handleGroupUpdated = useCallback( - (updatedGroup: ProfileGroup) => { - setGroups((prev) => - prev.map((group) => - group.id === updatedGroup.id ? updatedGroup : group, - ), - ); + (_updatedGroup: ProfileGroup) => { + void loadGroups(); onGroupManagementComplete(); }, - [onGroupManagementComplete], + [loadGroups, onGroupManagementComplete], ); const handleGroupDeleted = useCallback(() => { @@ -89,12 +95,12 @@ export function GroupManagementDialog({ onGroupManagementComplete(); }, [loadGroups, onGroupManagementComplete]); - const handleEditGroup = useCallback((group: ProfileGroup) => { + const handleEditGroup = useCallback((group: GroupWithCount) => { setSelectedGroup(group); setEditDialogOpen(true); }, []); - const handleDeleteGroup = useCallback((group: ProfileGroup) => { + const handleDeleteGroup = useCallback((group: GroupWithCount) => { setSelectedGroup(group); setDeleteDialogOpen(true); }, []); @@ -154,6 +160,7 @@ export function GroupManagementDialog({ Name + Profiles Actions @@ -163,22 +170,39 @@ export function GroupManagementDialog({ {group.name} + + {group.count} +
- - + + + + + +

Edit group

+
+
+ + + + + +

Delete group

+
+
diff --git a/src/components/proxy-check-button.tsx b/src/components/proxy-check-button.tsx index c55b7f7..a352ee9 100644 --- a/src/components/proxy-check-button.tsx +++ b/src/components/proxy-check-button.tsx @@ -63,12 +63,17 @@ export function ProxyCheckButton({ locationParts.length > 0 ? locationParts.join(", ") : "Unknown"; toast.success( -
+
Your proxy location is: - {location} - {result.country_code && ( - - )} +
+ {location} + {result.country_code && ( + + )} +
, ); } catch (error) { diff --git a/src/components/proxy-management-dialog.tsx b/src/components/proxy-management-dialog.tsx index b9099c2..ad6a840 100644 --- a/src/components/proxy-management-dialog.tsx +++ b/src/components/proxy-management-dialog.tsx @@ -4,7 +4,8 @@ import { invoke } from "@tauri-apps/api/core"; import { emit } from "@tauri-apps/api/event"; import * as React from "react"; import { useCallback, useState } from "react"; -import { FiEdit2, FiPlus, FiTrash2, FiWifi } from "react-icons/fi"; +import { GoPlus } from "react-icons/go"; +import { LuPencil, LuTrash2 } from "react-icons/lu"; import { toast } from "sonner"; import { DeleteConfirmationDialog } from "@/components/delete-confirmation-dialog"; import { ProxyFormDialog } from "@/components/proxy-form-dialog"; @@ -13,18 +14,27 @@ import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, + DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { Label } from "@/components/ui/label"; import { ScrollArea } from "@/components/ui/scroll-area"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { useProxyEvents } from "@/hooks/use-proxy-events"; -import { trimName } from "@/lib/name-utils"; import type { ProxyCheckResult, StoredProxy } from "@/types"; import { ProxyCheckButton } from "./proxy-check-button"; import { RippleButton } from "./ui/ripple"; @@ -112,157 +122,135 @@ export function ProxyManagementDialog({ return ( <> - - -
- - Proxy Management -
+ + + Proxy Management + + Manage your saved proxy configurations for reuse across profiles + -
- {/* Header with Create Button */} -
-
-

Stored Proxies

-

- Manage your saved proxy configurations for reuse across - profiles -

-
+
+ {/* Create new proxy button */} +
+ - - Create Proxy + + Create
- {/* Proxy List - Scrollable */} -
- {isLoading && ( -
-
-
- )} - {storedProxies.length === 0 && !isLoading ? ( -
- -

- No proxies configured -

-

- Create your first proxy configuration to get started -

- - - Create First Proxy - -
- ) : ( - -
- {storedProxies.map((proxy) => ( -
-
- {proxy.name.length > 30 ? ( - - - - {trimName(proxy.name)} - - - - - {proxy.name} - - - - ) : ( - - {proxy.name} - - )} -
-
- - {proxyUsage[proxy.id] ?? 0} - -
-
- { - setProxyCheckResults((prev) => ({ - ...prev, - [proxy.id]: result, - })); - }} - onCheckFailed={(result) => { - setProxyCheckResults((prev) => ({ - ...prev, - [proxy.id]: result, - })); - }} - /> - - - - - -

Edit proxy

-
-
- - - - - - - - {(proxyUsage[proxy.id] ?? 0) > 0 ? ( -

- Cannot delete: in use by{" "} - {proxyUsage[proxy.id]} profile - {proxyUsage[proxy.id] > 1 ? "s" : ""} -

- ) : ( -

Delete proxy

- )} -
-
-
-
- ))} -
+ {/* Proxies list */} + {isLoading ? ( +
+ Loading proxies... +
+ ) : storedProxies.length === 0 ? ( +
+ No proxies created yet. Create your first proxy using the button + above. +
+ ) : ( +
+ + + + + Name + Usage + Actions + + + + {storedProxies.map((proxy) => ( + + + {proxy.name} + + + + {proxyUsage[proxy.id] ?? 0} + + + +
+ { + setProxyCheckResults((prev) => ({ + ...prev, + [proxy.id]: result, + })); + }} + onCheckFailed={(result) => { + setProxyCheckResults((prev) => ({ + ...prev, + [proxy.id]: result, + })); + }} + /> + + + + + +

Edit proxy

+
+
+ + + + + + + + {(proxyUsage[proxy.id] ?? 0) > 0 ? ( +

+ Cannot delete: in use by{" "} + {proxyUsage[proxy.id]} profile + {proxyUsage[proxy.id] > 1 ? "s" : ""} +

+ ) : ( +

Delete proxy

+ )} +
+
+
+
+
+ ))} +
+
- )} -
+
+ )}
- - Close + + + Close +