서버 관리
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {APIProvider, useAPI} from './providers/APIProvider';
|
||||
import {LoadTestProvider} from './providers/LoadTestProvider';
|
||||
import DialogManager from './components/shared/DialogManager';
|
||||
import DialogManager from '@/components/shared/DialogManager';
|
||||
import {monacoConfig} from '@/config/monaco.js';
|
||||
import LoginDialog from '@/components/account/LoginDialog.jsx';
|
||||
import AppMenu from './components/app-menu/AppMenu';
|
||||
@@ -33,7 +33,8 @@ const AppContent = ({ options, showLogin, setShowLogin }) => {
|
||||
showQueueEdit: false,
|
||||
showUserEdit: false,
|
||||
showPasswordChange: false,
|
||||
selectedItem: null,
|
||||
showServerEdit: false,
|
||||
selectedItem: null
|
||||
});
|
||||
|
||||
const handleMenuClick = async (action, screen, item = null) => {
|
||||
@@ -69,6 +70,10 @@ const AppContent = ({ options, showLogin, setShowLogin }) => {
|
||||
case 'socket-edit':
|
||||
setDialogState(prev => ({...prev, showTCPServerEdit: true, selectedItem: item}));
|
||||
break;
|
||||
case 'server-add':
|
||||
case 'server-edit':
|
||||
setDialogState(prev => ({...prev, showServerEdit: true, selectedItem: item}));
|
||||
break;
|
||||
case 'collection-add':
|
||||
setDialogState(prev => ({...prev, showAddCollection: true}));
|
||||
break;
|
||||
@@ -84,7 +89,7 @@ const AppContent = ({ options, showLogin, setShowLogin }) => {
|
||||
case 'logout':
|
||||
const success = await handleLogout();
|
||||
if (success) {
|
||||
window.location.href = "/actionLogout.do";
|
||||
window.location.href = `${options.contextPath}/actionLogout.do`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -117,7 +122,7 @@ const AppContent = ({ options, showLogin, setShowLogin }) => {
|
||||
setIsInitialized(true);
|
||||
checkAuth();
|
||||
}
|
||||
}, [isInitialized]);
|
||||
}, [isInitialized, checkAuth]);
|
||||
|
||||
const handleDialogChange = (dialogName, isOpen) => {
|
||||
setDialogState(prev => ({...prev, [dialogName]: isOpen}));
|
||||
@@ -144,6 +149,7 @@ const AppContent = ({ options, showLogin, setShowLogin }) => {
|
||||
showUserEdit={dialogState.showUserEdit}
|
||||
selectedItem={dialogState.selectedItem}
|
||||
showPasswordChange={dialogState.showPasswordChange}
|
||||
showServerEdit={dialogState.showServerEdit}
|
||||
onDialogChange={handleDialogChange}
|
||||
/>
|
||||
<div className="flex-1 mt-14">
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow
|
||||
} from '@/components/ui/table';
|
||||
import { useAPI } from '@/providers/APIProvider';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Plus, Trash2 } from 'lucide-react';
|
||||
|
||||
const DEFAULT_SERVER = {
|
||||
id: null,
|
||||
name: '',
|
||||
scheme: 'http',
|
||||
hostname: '',
|
||||
port: 80,
|
||||
basePath: '/',
|
||||
enabled: true,
|
||||
serverOptions: []
|
||||
};
|
||||
|
||||
const ServerEditDialog = ({ open, onOpenChange, item }) => {
|
||||
const { createServer, updateServer } = useAPI();
|
||||
const [server, setServer] = useState(DEFAULT_SERVER);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (item) {
|
||||
// // Ensure serverOptions is always an array
|
||||
// setServer({
|
||||
// ...item,
|
||||
// serverOptions: item.serverOptions || []
|
||||
// });
|
||||
// } else {
|
||||
// setServer(DEFAULT_SERVER);
|
||||
// }
|
||||
// }, [item]);
|
||||
useEffect(() => {
|
||||
console.log('Dialog useEffect - item:', item, 'open:', open); // Debug log
|
||||
if (!open) {
|
||||
setServer(DEFAULT_SERVER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item) {
|
||||
setServer({
|
||||
...item,
|
||||
serverOptions: item.serverOptions || []
|
||||
});
|
||||
} else {
|
||||
setServer(DEFAULT_SERVER);
|
||||
}
|
||||
}, [item, open]);
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
setServer(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const addOption = () => {
|
||||
setServer(prev => ({
|
||||
...prev,
|
||||
serverOptions: [
|
||||
...(prev.serverOptions || []),
|
||||
{
|
||||
optionKey: '',
|
||||
optionName: '',
|
||||
offset: 0,
|
||||
length: 0,
|
||||
defaultValue: ''
|
||||
}
|
||||
]
|
||||
}));
|
||||
};
|
||||
|
||||
const removeOption = (index) => {
|
||||
setServer(prev => {
|
||||
const newOptions = [...prev.serverOptions];
|
||||
newOptions.splice(index, 1);
|
||||
return { ...prev, serverOptions: newOptions };
|
||||
});
|
||||
};
|
||||
|
||||
const updateOptionField = (index, field, value) => {
|
||||
setServer(prev => {
|
||||
const newOptions = [...prev.serverOptions];
|
||||
newOptions[index] = { ...newOptions[index], [field]: value };
|
||||
return { ...prev, serverOptions: newOptions };
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
if (server.id) {
|
||||
await updateServer(server);
|
||||
} else {
|
||||
await createServer(server);
|
||||
}
|
||||
onOpenChange(false);
|
||||
} catch (error) {
|
||||
console.error('Failed to save server:', error);
|
||||
alert('Failed to save server');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDialogChange = (open) => {
|
||||
if (!open) {
|
||||
setServer(DEFAULT_SERVER);
|
||||
}
|
||||
onOpenChange(open);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleDialogChange}>
|
||||
<DialogContent className="max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{server.id == null ? '서버 등록' : '서버 수정'}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
서버의 정보를 입력하거나 수정할 수 있습니다. 필수 항목을 모두 입력해주세요.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<ScrollArea className="max-h-[80vh]">
|
||||
<form id="serverForm" onSubmit={handleSubmit} className="space-y-4 p-1">
|
||||
{/* Server Name */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name" className="must">서버명</Label>
|
||||
<Input
|
||||
id="name"
|
||||
required
|
||||
value={server.name}
|
||||
onChange={(e) => handleChange('name', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Server Address */}
|
||||
<div className="space-y-2">
|
||||
<Label className="must">서버 주소</Label>
|
||||
<div className="flex gap-2">
|
||||
<Select
|
||||
value={server.scheme}
|
||||
onValueChange={(value) => handleChange('scheme', value)}
|
||||
>
|
||||
<SelectTrigger className="w-[120px]">
|
||||
<SelectValue placeholder="Scheme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="http">http</SelectItem>
|
||||
<SelectItem value="https">https</SelectItem>
|
||||
<SelectItem value="tcp">tcp</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="flex items-center">://</span>
|
||||
<Input
|
||||
placeholder="hostname"
|
||||
required
|
||||
value={server.hostname}
|
||||
onChange={(e) => handleChange('hostname', e.target.value)}
|
||||
/>
|
||||
<span className="flex items-center">:</span>
|
||||
<Input
|
||||
type="number"
|
||||
required
|
||||
className="w-[120px]"
|
||||
value={server.port}
|
||||
onChange={(e) => handleChange('port', parseInt(e.target.value))}
|
||||
/>
|
||||
<Input
|
||||
placeholder="base path"
|
||||
required
|
||||
value={server.basePath}
|
||||
onChange={(e) => handleChange('basePath', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Enabled Status */}
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="enabled"
|
||||
checked={server.enabled}
|
||||
onCheckedChange={(checked) => handleChange('enabled', checked)}
|
||||
/>
|
||||
<Label htmlFor="enabled">사용</Label>
|
||||
</div>
|
||||
|
||||
{/* Server Options */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<Label>서버 메시지 옵션</Label>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={addOption}
|
||||
>
|
||||
<Plus className="h-4 w-4 mr-1" />
|
||||
옵션 추가
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[150px]">키</TableHead>
|
||||
<TableHead className="w-[150px]">이름</TableHead>
|
||||
<TableHead className="w-[120px]">메시지 위치</TableHead>
|
||||
<TableHead className="w-[120px]">메시지 길이</TableHead>
|
||||
<TableHead>기본 값</TableHead>
|
||||
<TableHead className="w-[80px]"></TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{(server.serverOptions || []).map((option, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>
|
||||
<Input
|
||||
value={option.optionKey}
|
||||
onChange={(e) => updateOptionField(index, 'optionKey', e.target.value)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
value={option.optionName}
|
||||
onChange={(e) => updateOptionField(index, 'optionName', e.target.value)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
value={option.offset}
|
||||
onChange={(e) => updateOptionField(index, 'offset', parseInt(e.target.value))}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
value={option.length}
|
||||
onChange={(e) => updateOptionField(index, 'length', parseInt(e.target.value))}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
value={option.defaultValue}
|
||||
onChange={(e) => updateOptionField(index, 'defaultValue', e.target.value)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => removeOption(index)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</form>
|
||||
</ScrollArea>
|
||||
|
||||
<DialogFooter className="flex justify-end space-x-2">
|
||||
<Button variant="secondary" onClick={() => handleDialogChange(false)}>
|
||||
닫기
|
||||
</Button>
|
||||
<Button type="submit" variant="default" onClick={handleSubmit}>
|
||||
저장
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerEditDialog;
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import DataTable from '@/components/shared/DataTable';
|
||||
import { useAPI } from '@/providers/APIProvider';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
const ServerList = ({ onMenuClick }) => {
|
||||
const {
|
||||
serverList,
|
||||
loadServerList,
|
||||
deleteServers,
|
||||
loading
|
||||
} = useAPI();
|
||||
|
||||
const [searchTerm, setSearchTerm] = React.useState('');
|
||||
const [selectedIds, setSelectedIds] = React.useState([]);
|
||||
const [page, setPage] = React.useState(0);
|
||||
|
||||
React.useEffect(() => {
|
||||
loadServerList({ page });
|
||||
}, [page, loadServerList]);
|
||||
|
||||
const columns = [
|
||||
{ key: 'name', label: '이름' },
|
||||
{
|
||||
key: 'address',
|
||||
label: '주소',
|
||||
render: (_, row) => `${row.scheme}://${row.hostname}:${row.port}${row.basePath}`
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
label: '사용 중',
|
||||
render: (value) => (
|
||||
<Badge variant={value ? 'success' : 'destructive'}>
|
||||
{value ? '사용' : '미사용'}
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const handleSearch = () => {
|
||||
setPage(0);
|
||||
loadServerList({ name: searchTerm, page: 0 });
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
const success = await deleteServers(selectedIds);
|
||||
if (success) {
|
||||
setSelectedIds([]);
|
||||
}
|
||||
};
|
||||
|
||||
const renderRowActions = (row) => (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mr-2"
|
||||
// onClick={() => onMenuClick('server-edit', null, {...row})}
|
||||
onClick={() => {
|
||||
console.log('Before onMenuClick:', row); // Debug log
|
||||
onMenuClick('server-edit', null, row);
|
||||
}}
|
||||
>
|
||||
수정
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
const tableActions = (
|
||||
<>
|
||||
<Button variant="destructive" onClick={handleSearch}>조회</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={handleDelete}
|
||||
disabled={selectedIds.length === 0}
|
||||
>
|
||||
삭제
|
||||
</Button>
|
||||
<Button onClick={() => onMenuClick('server-add')}>등록</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="container mx-auto p-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>서버 목록</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center space-x-4 mb-4">
|
||||
<div className="flex-1 max-w-sm">
|
||||
<Input
|
||||
placeholder="이름으로 검색"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleSearch();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{tableActions}
|
||||
</div>
|
||||
<DataTable
|
||||
data={serverList}
|
||||
columns={columns}
|
||||
loading={loading}
|
||||
selectable
|
||||
selectedIds={selectedIds}
|
||||
onSelectIds={setSelectedIds}
|
||||
onPageChange={setPage}
|
||||
onDelete={handleDelete}
|
||||
renderRowActions={renderRowActions}
|
||||
deleteDialogTitle="서버 삭제"
|
||||
deleteDialogDescription="선택한 서버를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerList;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AddAPIDialog from '@/components/api-tester/AddAPIDialog.jsx';
|
||||
import React from 'react';
|
||||
import AddAPIDialog from '@/components/api-tester/AddAPIDialog.jsx';
|
||||
import AddCollectionDialog from '@/components/api-tester/AddCollectionDialog.jsx';
|
||||
import AddScenarioDialog from '@/components/api-tester/AddScenarioDialog.jsx';
|
||||
import VariableModal from '@/components/api-tester/VariableModal.jsx';
|
||||
@@ -8,7 +8,71 @@ import TCPServerEditDialog from '@/components/tcp-servers/TCPServerEditDialog.js
|
||||
import QueueEditDialog from '@/components/queues/QueueEditDialog.jsx';
|
||||
import UserEditDialog from '@/components/users/UserEditDialog.jsx';
|
||||
import PasswordChangeDialog from '@/components/account/PasswordChangeDialog.jsx';
|
||||
import ServerEditDialog from '@/components/servers/ServerEditDialog.jsx';
|
||||
|
||||
// const DialogManager = ({
|
||||
// showAddApi,
|
||||
// showAddCollection,
|
||||
// showAddScenario,
|
||||
// showVariableModal,
|
||||
// showMockRouteEdit,
|
||||
// showTCPServerEdit,
|
||||
// showQueueEdit,
|
||||
// showUserEdit,
|
||||
// selectedItem,
|
||||
// showPasswordChange,
|
||||
// showServerEdit,
|
||||
// onDialogChange
|
||||
// }) => {
|
||||
//
|
||||
// return <>
|
||||
// <AddCollectionDialog
|
||||
// open={showAddCollection}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showAddCollection', isOpen)}
|
||||
// />
|
||||
// <AddAPIDialog
|
||||
// open={showAddApi}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showAddApi', isOpen)}
|
||||
// />
|
||||
// <AddScenarioDialog
|
||||
// open={showAddScenario}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showAddScenario', isOpen)}
|
||||
// />
|
||||
// <VariableModal
|
||||
// open={showVariableModal}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showVariableModal', isOpen)}
|
||||
// />
|
||||
// <MockRouteEditDialog
|
||||
// open={showMockRouteEdit}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showMockRouteEdit', isOpen)}
|
||||
// item={selectedItem}
|
||||
// />
|
||||
// <TCPServerEditDialog
|
||||
// open={showTCPServerEdit}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showTCPServerEdit', isOpen)}
|
||||
// item={selectedItem}
|
||||
// />
|
||||
// <QueueEditDialog
|
||||
// open={showQueueEdit}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showQueueEdit', isOpen)}
|
||||
// item={selectedItem}
|
||||
// />
|
||||
// <UserEditDialog
|
||||
// open={showUserEdit}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showUserEdit', isOpen)}
|
||||
// item={selectedItem}
|
||||
// />
|
||||
// <PasswordChangeDialog
|
||||
// open={showPasswordChange}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showPasswordChange', isOpen)}
|
||||
// />
|
||||
// <ServerEditDialog
|
||||
// open={showServerEdit}
|
||||
// onOpenChange={(isOpen) => onDialogChange('showServerEdit', isOpen)}
|
||||
// item={selectedItem}
|
||||
// />
|
||||
// </>;
|
||||
// }
|
||||
const DialogManager = ({
|
||||
showAddApi,
|
||||
showAddCollection,
|
||||
@@ -18,12 +82,12 @@ const DialogManager = ({
|
||||
showTCPServerEdit,
|
||||
showQueueEdit,
|
||||
showUserEdit,
|
||||
showServerEdit,
|
||||
selectedItem,
|
||||
showPasswordChange,
|
||||
onDialogChange
|
||||
}) => {
|
||||
|
||||
return <>
|
||||
return (
|
||||
<>
|
||||
<AddCollectionDialog
|
||||
open={showAddCollection}
|
||||
onOpenChange={(isOpen) => onDialogChange('showAddCollection', isOpen)}
|
||||
@@ -60,11 +124,13 @@ const DialogManager = ({
|
||||
onOpenChange={(isOpen) => onDialogChange('showUserEdit', isOpen)}
|
||||
item={selectedItem}
|
||||
/>
|
||||
<PasswordChangeDialog
|
||||
open={showPasswordChange}
|
||||
onOpenChange={(isOpen) => onDialogChange('showPasswordChange', isOpen)}
|
||||
<ServerEditDialog
|
||||
open={showServerEdit}
|
||||
onOpenChange={(isOpen) => onDialogChange('showServerEdit', isOpen)}
|
||||
item={selectedItem}
|
||||
/>
|
||||
</>;
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogManager;
|
||||
|
||||
@@ -5,10 +5,10 @@ export const menuConfig = [
|
||||
label: '응답관리',
|
||||
items: [
|
||||
{id: 'response-list', label: 'API 응답 목록', action: 'response-list', screen: 'response-list'},
|
||||
{id: 'response-add', label: 'API 응답 추가', action: 'response-add'},
|
||||
{type: 'separator'},
|
||||
// {id: 'response-add', label: 'API 응답 추가', action: 'response-add'},
|
||||
// {type: 'separator'},
|
||||
{id: 'socket-list', label: 'TCP 서버 목록', action: 'socket-list', screen: 'socket-list'},
|
||||
{id: 'socket-add', label: 'TCP 서버 추가', action: 'socket-add'},
|
||||
// {id: 'socket-add', label: 'TCP 서버 추가', action: 'socket-add'},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -47,9 +47,7 @@ export const menuConfig = [
|
||||
label: '시스템 관리',
|
||||
items: [
|
||||
{id: 'user-list', label: '사용자 관리', action: 'user-list', screen: 'user-list'},
|
||||
{type: 'separator'},
|
||||
{id: 'server-management', label: '서버 관리', action: 'server-management', screen: 'server-management'},
|
||||
{id: 'server-add', label: '서버 추가', action: 'server-add', screen: 'server-add'},
|
||||
{id: 'server-list', label: '서버 관리', action: 'server-list', screen: 'server-list'},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ import MockRouteList from '../components/mock-route/MockRouteList.jsx';
|
||||
import TCPServerList from '@/components/tcp-servers/TCPServerList.jsx';
|
||||
import QueueList from '@/components/queues/QueueList.jsx';
|
||||
import UserList from '@/components/users/UserList.jsx';
|
||||
import ServerList from '@/components/servers/ServerList.jsx';
|
||||
|
||||
export const SCREENS = {
|
||||
'api-tester': APITester,
|
||||
@@ -13,4 +14,5 @@ export const SCREENS = {
|
||||
'socket-list': TCPServerList,
|
||||
'queue-list': QueueList,
|
||||
'user-list': UserList,
|
||||
'server-list': ServerList
|
||||
};
|
||||
|
||||
@@ -52,6 +52,14 @@ export const APIProvider = ({
|
||||
last: true
|
||||
});
|
||||
|
||||
const [serverList, setServerList] = useState({
|
||||
content: [],
|
||||
totalPages: 0,
|
||||
number: 0,
|
||||
first: true,
|
||||
last: true
|
||||
});
|
||||
|
||||
|
||||
// Initialize services
|
||||
const collections$ = collectionService(contextPath);
|
||||
@@ -447,6 +455,66 @@ export const APIProvider = ({
|
||||
}
|
||||
}, []);
|
||||
|
||||
const loadServerList = useCallback(async (params = { page: 0 }) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await servers$.loadServerList(params);
|
||||
setServerList(data);
|
||||
return data;
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const deleteServers = useCallback(async (ids) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
await servers$.deleteServers(ids);
|
||||
await loadServerList();
|
||||
return true;
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
return false;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadServerList]);
|
||||
|
||||
const createServer = useCallback(async (server) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const newServer = await servers$.createServer(server);
|
||||
await loadServerList();
|
||||
return newServer;
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadServerList]);
|
||||
|
||||
const updateServer = useCallback(async (server) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const updatedServer = await servers$.updateServer(server.id, server);
|
||||
await loadServerList();
|
||||
return updatedServer;
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadServerList]);
|
||||
|
||||
const contextValue = {
|
||||
apiClient,
|
||||
collections,
|
||||
@@ -454,6 +522,11 @@ export const APIProvider = ({
|
||||
servers,
|
||||
loadServers,
|
||||
getServer,
|
||||
serverList,
|
||||
loadServerList,
|
||||
deleteServers,
|
||||
createServer,
|
||||
updateServer,
|
||||
loading,
|
||||
error,
|
||||
loadCollections,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {getCSRFToken} from '@/services/token.js';
|
||||
|
||||
export const serverService = () => {
|
||||
return {
|
||||
async loadServers() {
|
||||
@@ -13,6 +15,60 @@ export const serverService = () => {
|
||||
basePath: server?.basePath || '',
|
||||
environment: server?.environment || 'unknown'
|
||||
}));
|
||||
},
|
||||
|
||||
async loadServerList(params = { page: 0, name: '' }) {
|
||||
const searchParams = new URLSearchParams({
|
||||
page: params.page,
|
||||
size: 10,
|
||||
...(params.name && { name: params.name })
|
||||
});
|
||||
|
||||
const response = await fetch(`/servers?${searchParams}`);
|
||||
if (!response.ok) throw new Error('Failed to load servers');
|
||||
return response.json();
|
||||
},
|
||||
|
||||
async createServer(server) {
|
||||
const response = await fetch('/servers', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-XSRF-TOKEN': getCSRFToken()
|
||||
},
|
||||
body: JSON.stringify(server)
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Failed to create server');
|
||||
return response.json();
|
||||
},
|
||||
|
||||
async updateServer(id, server) {
|
||||
const response = await fetch(`/servers/update/${id}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-XSRF-TOKEN': getCSRFToken()
|
||||
},
|
||||
body: JSON.stringify(server)
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Failed to update server');
|
||||
return response.json();
|
||||
},
|
||||
|
||||
async deleteServers(ids) {
|
||||
const response = await fetch('/servers/delete', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-XSRF-TOKEN': getCSRFToken()
|
||||
},
|
||||
body: JSON.stringify(ids)
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Failed to delete servers');
|
||||
return response.json();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user