141 lines
4.4 KiB
TypeScript
141 lines
4.4 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
import { Plus, Trash2 } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
|
|
interface HeadersManagerProps {
|
|
headers: Record<string, string>;
|
|
onChange: (headers: Record<string, string>) => void;
|
|
}
|
|
|
|
interface HeaderItem {
|
|
key: string;
|
|
value: string;
|
|
}
|
|
|
|
export function HeadersManager({ headers, onChange }: HeadersManagerProps) {
|
|
const [headersList, setHeadersList] = useState<HeaderItem[]>([]);
|
|
|
|
// 초기 헤더 로드
|
|
useEffect(() => {
|
|
const list = Object.entries(headers || {}).map(([key, value]) => ({
|
|
key,
|
|
value,
|
|
}));
|
|
|
|
// 헤더가 없으면 기본 헤더 추가
|
|
if (list.length === 0) {
|
|
list.push({ key: "Content-Type", value: "application/json" });
|
|
}
|
|
|
|
setHeadersList(list);
|
|
}, []);
|
|
|
|
// 헤더 추가
|
|
const addHeader = () => {
|
|
setHeadersList([...headersList, { key: "", value: "" }]);
|
|
};
|
|
|
|
// 헤더 삭제
|
|
const removeHeader = (index: number) => {
|
|
const newList = headersList.filter((_, i) => i !== index);
|
|
setHeadersList(newList);
|
|
updateParent(newList);
|
|
};
|
|
|
|
// 헤더 업데이트
|
|
const updateHeader = (index: number, field: "key" | "value", value: string) => {
|
|
const newList = [...headersList];
|
|
newList[index][field] = value;
|
|
setHeadersList(newList);
|
|
updateParent(newList);
|
|
};
|
|
|
|
// 부모 컴포넌트에 변경사항 전달
|
|
const updateParent = (list: HeaderItem[]) => {
|
|
const headersObject = list.reduce(
|
|
(acc, { key, value }) => {
|
|
if (key.trim()) {
|
|
acc[key] = value;
|
|
}
|
|
return acc;
|
|
},
|
|
{} as Record<string, string>,
|
|
);
|
|
onChange(headersObject);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label className="text-sm font-medium">헤더 설정</Label>
|
|
<Button type="button" variant="outline" size="sm" onClick={addHeader}>
|
|
<Plus className="mr-1 h-3 w-3" />
|
|
헤더 추가
|
|
</Button>
|
|
</div>
|
|
|
|
{headersList.length > 0 ? (
|
|
<div className="rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead className="w-[35%]">키</TableHead>
|
|
<TableHead className="w-[55%]">값</TableHead>
|
|
<TableHead className="w-[10%] text-right">작업</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{headersList.map((header, index) => (
|
|
<TableRow key={index}>
|
|
<TableCell>
|
|
<Input
|
|
type="text"
|
|
value={header.key}
|
|
onChange={(e) => updateHeader(index, "key", e.target.value)}
|
|
placeholder="예: Authorization"
|
|
className="h-8"
|
|
/>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Input
|
|
type="text"
|
|
value={header.value}
|
|
onChange={(e) => updateHeader(index, "value", e.target.value)}
|
|
placeholder="예: Bearer token123"
|
|
className="h-8"
|
|
/>
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => removeHeader(index)}
|
|
className="h-8 w-8 p-0 text-red-600 hover:bg-red-50 hover:text-red-700"
|
|
>
|
|
<Trash2 className="h-4 w-4" />
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
) : (
|
|
<div className="rounded-md border border-dashed p-4 text-center text-sm text-gray-500">
|
|
헤더가 없습니다. 헤더 추가 버튼을 클릭하여 추가하세요.
|
|
</div>
|
|
)}
|
|
|
|
<p className="text-xs text-gray-500">
|
|
* 공통으로 사용할 HTTP 헤더를 설정합니다. 인증 헤더는 별도의 인증 설정에서 관리됩니다.
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|