Add batch server and group creation functionality (#499)

This commit is contained in:
samanhappy
2025-12-11 14:21:58 +08:00
committed by GitHub
parent ab7c210281
commit 1dfa0a990b
11 changed files with 815 additions and 56 deletions

View File

@@ -6,6 +6,7 @@ import { useServerData } from '@/hooks/useServerData';
import AddGroupForm from '@/components/AddGroupForm';
import EditGroupForm from '@/components/EditGroupForm';
import GroupCard from '@/components/GroupCard';
import GroupImportForm from '@/components/GroupImportForm';
const GroupsPage: React.FC = () => {
const { t } = useTranslation();
@@ -15,12 +16,13 @@ const GroupsPage: React.FC = () => {
error: groupError,
setError: setGroupError,
deleteGroup,
triggerRefresh
triggerRefresh,
} = useGroupData();
const { servers } = useServerData({ refreshOnMount: true });
const [editingGroup, setEditingGroup] = useState<Group | null>(null);
const [showAddForm, setShowAddForm] = useState(false);
const [showImportForm, setShowImportForm] = useState(false);
const handleEditClick = (group: Group) => {
setEditingGroup(group);
@@ -47,6 +49,11 @@ const GroupsPage: React.FC = () => {
triggerRefresh(); // Refresh the groups list after adding
};
const handleImportSuccess = () => {
setShowImportForm(false);
triggerRefresh(); // Refresh the groups list after import
};
return (
<div>
<div className="flex justify-between items-center mb-8">
@@ -56,11 +63,38 @@ const GroupsPage: React.FC = () => {
onClick={handleAddGroup}
className="px-4 py-2 bg-blue-100 text-blue-800 rounded hover:bg-blue-200 flex items-center btn-primary transition-all duration-200"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 mr-2" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 3a1 1 0 00-1 1v5H4a1 1 0 100 2h5v5a1 1 0 102 0v-5h5a1 1 0 100-2h-5V4a1 1 0 00-1-1z" clipRule="evenodd" />
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4 mr-2"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M10 3a1 1 0 00-1 1v5H4a1 1 0 100 2h5v5a1 1 0 102 0v-5h5a1 1 0 100-2h-5V4a1 1 0 00-1-1z"
clipRule="evenodd"
/>
</svg>
{t('groups.add')}
</button>
<button
onClick={() => setShowImportForm(true)}
className="px-4 py-2 bg-blue-100 text-blue-800 rounded hover:bg-blue-200 flex items-center btn-primary transition-all duration-200"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4 mr-2"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
{t('groupImport.button')}
</button>
</div>
</div>
@@ -73,9 +107,25 @@ const GroupsPage: React.FC = () => {
{groupsLoading ? (
<div className="bg-white shadow rounded-lg p-6 loading-container">
<div className="flex flex-col items-center justify-center">
<svg className="animate-spin h-10 w-10 text-blue-500 mb-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
<svg
className="animate-spin h-10 w-10 text-blue-500 mb-4"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
<p className="text-gray-600">{t('app.loading')}</p>
</div>
@@ -98,8 +148,13 @@ const GroupsPage: React.FC = () => {
</div>
)}
{showAddForm && (
<AddGroupForm onAdd={handleAddComplete} onCancel={handleAddComplete} />
{showAddForm && <AddGroupForm onAdd={handleAddComplete} onCancel={handleAddComplete} />}
{showImportForm && (
<GroupImportForm
onSuccess={handleImportSuccess}
onCancel={() => setShowImportForm(false)}
/>
)}
{editingGroup && (
@@ -113,4 +168,4 @@ const GroupsPage: React.FC = () => {
);
};
export default GroupsPage;
export default GroupsPage;