TCP 서버 모드 추가
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
import React, {useState} from 'react';
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/components/ui/select';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Tabs, TabsList, TabsTrigger} from '@/components/ui/tabs';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import EditableInput from '../shared/EditableInput';
|
||||
import PropertyTable from '../shared/PropertyTable';
|
||||
import ServerManager from '@/components/ServerManager.jsx';
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@/components/ui/table.jsx';
|
||||
import {useAPI} from '@/providers/APIProvider';
|
||||
import MonacoEditor from '@/components/shared/MonacoEditor';
|
||||
// import MonacoVariableEditor from './MonacoVariableEditor'; // Import the new component
|
||||
|
||||
const HTTP_METHODS = [
|
||||
'POST', 'GET', 'PUT', 'DELETE', 'CONNECT',
|
||||
'HEAD', 'OPTIONS', 'TRACE', 'PATCH'
|
||||
];
|
||||
|
||||
export const HTTPClientView = ({model, index}) => {
|
||||
const { getServer } = useAPI();
|
||||
const [currentModel, setCurrentModel] = useState(model);
|
||||
const [basePath, setBasePath] = useState('');
|
||||
const [currentTab, setCurrentTab] = useState('body');
|
||||
const [currentResponseTab, setCurrentResponseTab] = useState('response-body');
|
||||
const [responseData, setResponseData] = useState({
|
||||
headers: [],
|
||||
status: '',
|
||||
time: '',
|
||||
size: ''
|
||||
});
|
||||
|
||||
const [editorContents, setEditorContents] = useState({
|
||||
requestBody: currentModel.requestBody || '',
|
||||
responseBody: currentModel.responseBody || '',
|
||||
console: '',
|
||||
preRequestScript: currentModel.preRequestScript || '',
|
||||
postRequestScript: currentModel.postRequestScript || ''
|
||||
});
|
||||
|
||||
const handleServerChange = (serverId) => {
|
||||
const selectedServer = getServer(serverId);
|
||||
|
||||
setCurrentModel(prev => ({
|
||||
...prev,
|
||||
server: serverId
|
||||
}));
|
||||
|
||||
if (selectedServer) {
|
||||
setBasePath(selectedServer.basePath || '');
|
||||
}
|
||||
};
|
||||
|
||||
const handleHeadersChange = (headers) => {
|
||||
setCurrentModel(prev => ({
|
||||
...prev,
|
||||
headers
|
||||
}));
|
||||
};
|
||||
|
||||
const handlePathChange = (path) => {
|
||||
const queryParams = parseQueryParams(path);
|
||||
setCurrentModel(prev => ({
|
||||
...prev,
|
||||
path,
|
||||
queryParams
|
||||
}));
|
||||
};
|
||||
|
||||
const parseQueryParams = (path) => {
|
||||
const queryParams = [];
|
||||
const queryString = path.split('?')[1];
|
||||
|
||||
if (queryString) {
|
||||
queryString.split('&').forEach(param => {
|
||||
const [key, value] = param.split('=');
|
||||
queryParams.push({
|
||||
enabled: true,
|
||||
key,
|
||||
value: value || ''
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return queryParams;
|
||||
};
|
||||
|
||||
const renderRequestVariables = () => (
|
||||
<div className="p-4">
|
||||
<h3 className="text-sm font-medium mb-2">Available Variables</h3>
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<Label>request</Label>
|
||||
<div className="text-sm text-gray-500">Request object containing headers, body, etc.</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>environment</Label>
|
||||
<div className="text-sm text-gray-500">Current environment variables</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const renderResponseHeaders = () => (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Value</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{responseData.headers.map((header, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>{header.name}</TableCell>
|
||||
<TableCell>{header.value}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full p-4 space-y-4">
|
||||
{/* Request Header Section */}
|
||||
<div className="flex items-center space-x-2">
|
||||
<div>
|
||||
<span>{currentModel.collectionName}</span>
|
||||
{' > '}
|
||||
<span>{currentModel.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Request Controls */}
|
||||
<div className="flex items-center space-x-2">
|
||||
<Select
|
||||
value={currentModel.method}
|
||||
onValueChange={(value) => setCurrentModel(prev => ({...prev, method: value}))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue placeholder="Method"/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{HTTP_METHODS.map(method => (
|
||||
<SelectItem key={method} value={method}>
|
||||
{method}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<ServerManager
|
||||
onServerChange={handleServerChange}
|
||||
/>
|
||||
<Input
|
||||
value={basePath} // 선택된 서버의 basePath 표시
|
||||
readOnly
|
||||
className="w-40"
|
||||
/>
|
||||
<EditableInput
|
||||
value={currentModel.path}
|
||||
onChange={handlePathChange}
|
||||
className="flex-1"
|
||||
/>
|
||||
|
||||
<Button>Send</Button>
|
||||
<Button variant="secondary">Save</Button>
|
||||
</div>
|
||||
|
||||
{/* Request/Response Tabs */}
|
||||
<Tabs value={currentTab} onValueChange={setCurrentTab}>
|
||||
<TabsList>
|
||||
<TabsTrigger value="body">Body</TabsTrigger>
|
||||
<TabsTrigger value="params">Params</TabsTrigger>
|
||||
<TabsTrigger value="headers">Headers</TabsTrigger>
|
||||
<TabsTrigger value="pre-request">Pre-Request</TabsTrigger>
|
||||
<TabsTrigger value="post-request">Post-Request</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<div className="mt-2">
|
||||
{/* Body Tab Content */}
|
||||
<div style={{ display: currentTab === 'body' ? 'block' : 'none' }}>
|
||||
<Select
|
||||
value={currentModel.contentType}
|
||||
// onValueChange={(value) => setCurrentModel(prev => ({ ...prev, contentType: value }))}
|
||||
onValueChange={(value) => {
|
||||
// Update both content type and editor content
|
||||
setCurrentModel(prev => ({
|
||||
...prev,
|
||||
contentType: value,
|
||||
// Optionally format the content when switching to JSON
|
||||
requestBody: value === 'json' && prev.requestBody ?
|
||||
JSON.stringify(JSON.parse(prev.requestBody), null, 2) :
|
||||
prev.requestBody
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Content Type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="json">JSON</SelectItem>
|
||||
<SelectItem value="xml">XML</SelectItem>
|
||||
<SelectItem value="plaintext">Text/Plain</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<MonacoEditor
|
||||
id={`request-body-${model.id}`}
|
||||
value={currentModel.requestBody}
|
||||
language={
|
||||
currentModel.contentType
|
||||
}
|
||||
onChange={(newValue) => {
|
||||
setCurrentModel(prev => ({
|
||||
...prev,
|
||||
requestBody: newValue
|
||||
}));
|
||||
}}
|
||||
height="64"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Params Tab Content */}
|
||||
<div style={{ display: currentTab === 'params' ? 'block' : 'none' }}>
|
||||
<PropertyTable
|
||||
properties={currentModel.queryParams}
|
||||
onChange={handlePathChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Headers Tab Content */}
|
||||
<div style={{ display: currentTab === 'headers' ? 'block' : 'none' }}>
|
||||
<PropertyTable
|
||||
properties={currentModel.headers}
|
||||
onChange={handleHeadersChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Pre-Request Tab Content */}
|
||||
<div style={{ display: currentTab === 'pre-request' ? 'block' : 'none' }} className="flex">
|
||||
<div className="flex-1">
|
||||
<MonacoEditor
|
||||
id={`pre-request-${model.id}`}
|
||||
value={editorContents.preRequestScript}
|
||||
language="javascript"
|
||||
onChange={(value) => {
|
||||
setEditorContents(prev => ({ ...prev, preRequestScript: value }));
|
||||
setCurrentModel(prev => ({ ...prev, preRequestScript: value }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Post-Request Tab Content */}
|
||||
<div style={{ display: currentTab === 'post-request' ? 'block' : 'none' }} className="flex">
|
||||
<div>
|
||||
<MonacoEditor
|
||||
id={`post-request-${model.id}`}
|
||||
value={editorContents.postRequestScript}
|
||||
language="javascript"
|
||||
onChange={(value) => {
|
||||
setEditorContents(prev => ({ ...prev, postRequestScript: value }));
|
||||
setCurrentModel(prev => ({ ...prev, postRequestScript: value }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs>
|
||||
{/* Response Section */}
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center space-x-2 mb-2">
|
||||
<span>Response</span>
|
||||
<span className="text-sm text-gray-500">{responseData.status}</span>
|
||||
<span className="text-sm text-gray-500">{responseData.time}</span>
|
||||
<span className="text-sm text-gray-500">{responseData.size}</span>
|
||||
</div>
|
||||
|
||||
<Tabs value={currentResponseTab} onValueChange={setCurrentResponseTab}>
|
||||
<TabsList>
|
||||
<TabsTrigger value="response-body">Body</TabsTrigger>
|
||||
<TabsTrigger value="response-headers">Headers</TabsTrigger>
|
||||
<TabsTrigger value="console">Console</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<div className="mt-2">
|
||||
<div style={{display: currentResponseTab === 'response-body' ? 'block' : 'none'}}>
|
||||
<MonacoEditor
|
||||
id={`response-body-${model.id}`}
|
||||
value={editorContents.responseBody}
|
||||
readOnly={true}
|
||||
onChange={() => {}} // Read-only, so no onChange needed
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{display: currentResponseTab === 'response-headers' ? 'block' : 'none'}}>
|
||||
{renderResponseHeaders()}
|
||||
</div>
|
||||
|
||||
<div style={{display: currentResponseTab === 'console' ? 'block' : 'none'}}>
|
||||
<MonacoEditor
|
||||
id={`console-${model.id}`}
|
||||
value={editorContents.console}
|
||||
language="plaintext"
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HTTPClientView;
|
||||
Reference in New Issue
Block a user