디스코드 웹 훅 테스트 구현
This commit is contained in:
@@ -5,6 +5,9 @@ import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ExternalCallAPI } from "@/lib/api/externalCall";
|
||||
import { toast } from "sonner";
|
||||
import { Globe } from "lucide-react";
|
||||
import { ExternalCallSettings as ExternalCallSettingsType } from "@/types/connectionTypes";
|
||||
|
||||
@@ -13,12 +16,128 @@ interface ExternalCallSettingsProps {
|
||||
onSettingsChange: (settings: ExternalCallSettingsType) => void;
|
||||
}
|
||||
|
||||
const handleTestExternalCall = async (settings: ExternalCallSettingsType) => {
|
||||
let loadingToastId: string | number | undefined;
|
||||
|
||||
try {
|
||||
// 설정을 백엔드 형식으로 변환
|
||||
const backendSettings: Record<string, unknown> = {
|
||||
callType: settings.callType,
|
||||
timeout: 10000, // 10초 타임아웃 설정
|
||||
};
|
||||
|
||||
if (settings.callType === "rest-api") {
|
||||
backendSettings.apiType = settings.apiType;
|
||||
|
||||
switch (settings.apiType) {
|
||||
case "slack":
|
||||
backendSettings.webhookUrl = settings.slackWebhookUrl;
|
||||
backendSettings.message =
|
||||
settings.slackMessage || "테스트 메시지: {{recordCount}}건의 데이터가 처리되었습니다.";
|
||||
backendSettings.channel = settings.slackChannel;
|
||||
break;
|
||||
case "kakao-talk":
|
||||
backendSettings.accessToken = settings.kakaoAccessToken;
|
||||
backendSettings.message =
|
||||
settings.kakaoMessage || "테스트 메시지: {{recordCount}}건의 데이터가 처리되었습니다.";
|
||||
break;
|
||||
case "discord":
|
||||
backendSettings.webhookUrl = settings.discordWebhookUrl;
|
||||
backendSettings.message =
|
||||
settings.discordMessage || "테스트 메시지: {{recordCount}}건의 데이터가 처리되었습니다.";
|
||||
backendSettings.username = settings.discordUsername;
|
||||
break;
|
||||
case "generic":
|
||||
default:
|
||||
backendSettings.url = settings.apiUrl;
|
||||
backendSettings.method = settings.httpMethod || "POST";
|
||||
try {
|
||||
backendSettings.headers = settings.headers ? JSON.parse(settings.headers) : {};
|
||||
} catch (error) {
|
||||
console.warn("Headers JSON 파싱 실패, 기본값 사용:", error);
|
||||
backendSettings.headers = {};
|
||||
}
|
||||
backendSettings.body = settings.bodyTemplate || "{}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 로딩 토스트 시작
|
||||
loadingToastId = toast.loading("외부 호출 테스트 중...", {
|
||||
duration: 12000, // 12초 후 자동으로 사라짐
|
||||
});
|
||||
|
||||
// 타임아웃을 위한 Promise.race 사용
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
setTimeout(() => reject(new Error("테스트 요청이 10초 내에 완료되지 않았습니다.")), 10000);
|
||||
});
|
||||
|
||||
const testPromise = ExternalCallAPI.testExternalCall({
|
||||
settings: backendSettings,
|
||||
templateData: {
|
||||
recordCount: 5,
|
||||
tableName: "test_table",
|
||||
timestamp: new Date().toISOString(),
|
||||
message: "데이터플로우 테스트 실행",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await Promise.race([testPromise, timeoutPromise]);
|
||||
|
||||
// 로딩 토스트 제거
|
||||
if (loadingToastId) {
|
||||
toast.dismiss(loadingToastId);
|
||||
}
|
||||
|
||||
if (result.success && result.result?.success) {
|
||||
toast.success("외부 호출 테스트 성공!", {
|
||||
description: `응답 시간: ${result.result.executionTime}ms`,
|
||||
duration: 4000,
|
||||
});
|
||||
} else {
|
||||
toast.error("외부 호출 테스트 실패", {
|
||||
description: result.result?.error || result.error || "알 수 없는 오류",
|
||||
duration: 6000,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("테스트 실행 중 오류:", error);
|
||||
|
||||
// 로딩 토스트 제거
|
||||
if (loadingToastId) {
|
||||
toast.dismiss(loadingToastId);
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
toast.error("테스트 실행 중 오류가 발생했습니다.", {
|
||||
description: error.message,
|
||||
duration: 6000,
|
||||
});
|
||||
} else {
|
||||
toast.error("테스트 실행 중 알 수 없는 오류가 발생했습니다.", {
|
||||
duration: 6000,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const ExternalCallSettings: React.FC<ExternalCallSettingsProps> = ({ settings, onSettingsChange }) => {
|
||||
return (
|
||||
<div className="rounded-lg border border-l-4 border-l-orange-500 bg-orange-50/30 p-4">
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<Globe className="h-4 w-4 text-orange-500" />
|
||||
<span className="text-sm font-medium">외부 호출 설정</span>
|
||||
<div className="mb-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Globe className="h-4 w-4 text-orange-500" />
|
||||
<span className="text-sm font-medium">외부 호출 설정</span>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleTestExternalCall(settings)}
|
||||
className="h-7 px-2 text-xs"
|
||||
>
|
||||
테스트
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
@@ -147,7 +266,7 @@ export const ExternalCallSettings: React.FC<ExternalCallSettingsProps> = ({ sett
|
||||
<>
|
||||
<div>
|
||||
<Label htmlFor="discordWebhookUrl" className="text-sm">
|
||||
디스코드 웹훅 URL
|
||||
디스코드 웹훅 URL <span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
id="discordWebhookUrl"
|
||||
@@ -157,6 +276,18 @@ export const ExternalCallSettings: React.FC<ExternalCallSettingsProps> = ({ sett
|
||||
className="text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="discordUsername" className="text-sm">
|
||||
이름
|
||||
</Label>
|
||||
<Input
|
||||
id="discordUsername"
|
||||
value={settings.discordUsername || ""}
|
||||
onChange={(e) => onSettingsChange({ ...settings, discordUsername: e.target.value })}
|
||||
placeholder="ERP 시스템"
|
||||
className="text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="discordMessage" className="text-sm">
|
||||
메시지 내용
|
||||
|
||||
Reference in New Issue
Block a user