@@ -336,6 +322,8 @@ const ServicesPage = () => {
Method |
Path |
Name |
+
Domain |
+
Section |
Description |
Active |
@@ -354,6 +342,8 @@ const ServicesPage = () => {
{api.apiPath} |
{api.apiName} |
+
{api.apiDomain || '-'} |
+
{api.apiSection || '-'} |
{api.description || '-'} |
{
))}
{serviceApis.length === 0 && (
- |
+ |
등록된 API가 없습니다.
|
@@ -499,103 +489,6 @@ const ServicesPage = () => {
)}
- {isApiModalOpen && (
-
- )}
);
};
diff --git a/frontend/src/pages/apihub/ApiHubApiDetailPage.tsx b/frontend/src/pages/apihub/ApiHubApiDetailPage.tsx
index 6ac80e2..f5e6f60 100644
--- a/frontend/src/pages/apihub/ApiHubApiDetailPage.tsx
+++ b/frontend/src/pages/apihub/ApiHubApiDetailPage.tsx
@@ -1,15 +1,12 @@
-import { useState, useEffect, useCallback } from 'react';
+import { useState, useEffect, useCallback, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
-import type { ServiceCatalog, ServiceApiItem } from '../../types/apihub';
-import { getCatalog } from '../../services/apiHubService';
+import type { ServiceCatalog } from '../../types/apihub';
+import type { ApiDetailInfo } from '../../types/service';
+import { getCatalog, getServiceCatalog, getApiHubApiDetail } from '../../services/apiHubService';
+import { getSystemConfig } from '../../services/configService';
+import { createKeyRequest } from '../../services/apiKeyService';
-const METHOD_COLORS: Record = {
- GET: 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300',
- POST: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300',
- PUT: 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300',
- PATCH: 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300',
- DELETE: 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300',
-};
+const COMMON_SAMPLE_CODE_KEY = 'COMMON_SAMPLE_CODE';
const METHOD_COLORS_LARGE: Record = {
GET: 'bg-green-500',
@@ -19,55 +16,58 @@ const METHOD_COLORS_LARGE: Record = {
DELETE: 'bg-red-500',
};
-const formatDateTime = (dateStr: string): string => {
- const d = new Date(dateStr);
- const date = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
- const time = `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
- return `${date} ${time}`;
-};
-
-interface LabelValueRowProps {
- label: string;
- value: React.ReactNode;
-}
-
-const LabelValueRow = ({ label, value }: LabelValueRowProps) => (
-
- {label}
- {value}
-
-);
-
const ApiHubApiDetailPage = () => {
const { serviceId, apiId } = useParams<{ serviceId: string; apiId: string }>();
const navigate = useNavigate();
- const [api, setApi] = useState(null);
+ const [detail, setDetail] = useState(null);
const [service, setService] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
+ const [paramInputs, setParamInputs] = useState>({});
+ const [generatedUrl, setGeneratedUrl] = useState(null);
+ const [urlCopied, setUrlCopied] = useState(false);
+ const [validationErrors, setValidationErrors] = useState>({});
+ const [commonSampleCode, setCommonSampleCode] = useState(null);
+ const [urlGenOpen, setUrlGenOpen] = useState(false);
+
+ // 신청 모달 상태
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [modalKeyName, setModalKeyName] = useState('');
+ const [modalPurpose, setModalPurpose] = useState('');
+ const [modalServiceIp, setModalServiceIp] = useState('');
+ const [modalServicePurpose, setModalServicePurpose] = useState('');
+ const [modalDailyRequestEstimate, setModalDailyRequestEstimate] = useState('');
+ const [modalUsagePeriodMode, setModalUsagePeriodMode] = useState<'preset' | 'custom'>('preset');
+ const [modalIsPermanent, setModalIsPermanent] = useState(false);
+ const [modalUsageFromDate, setModalUsageFromDate] = useState('');
+ const [modalUsageToDate, setModalUsageToDate] = useState('');
+ const [modalIsSubmitting, setModalIsSubmitting] = useState(false);
+ const [modalError, setModalError] = useState(null);
+ const [modalSuccess, setModalSuccess] = useState(false);
+ const [modalSelectedApiIds, setModalSelectedApiIds] = useState>(new Set());
+ const [modalCatalog, setModalCatalog] = useState([]);
+ const [modalExpandedDomains, setModalExpandedDomains] = useState>(new Set());
+ const [modalApiSearch, setModalApiSearch] = useState('');
const fetchData = useCallback(async () => {
if (!serviceId || !apiId) return;
try {
- const res = await getCatalog();
- if (res.success && res.data) {
- const foundService = res.data.find((s) => s.serviceId === Number(serviceId));
- if (foundService) {
- setService(foundService);
- const foundApi = foundService.domains
- .flatMap((d) => d.apis)
- .find((a) => a.apiId === Number(apiId));
- if (foundApi) {
- setApi(foundApi);
- } else {
- setError('API를 찾을 수 없습니다');
- }
- } else {
- setError('서비스를 찾을 수 없습니다');
- }
+ const [serviceRes, detailRes, sampleCodeRes] = await Promise.all([
+ getServiceCatalog(Number(serviceId)),
+ getApiHubApiDetail(Number(serviceId), Number(apiId)),
+ getSystemConfig(COMMON_SAMPLE_CODE_KEY),
+ ]);
+ if (serviceRes.success && serviceRes.data) {
+ setService(serviceRes.data);
+ }
+ if (detailRes.success && detailRes.data) {
+ setDetail(detailRes.data);
} else {
setError('API 정보를 불러오지 못했습니다');
}
+ if (sampleCodeRes.success && sampleCodeRes.data?.configValue) {
+ setCommonSampleCode(sampleCodeRes.data.configValue);
+ }
} catch {
setError('API 정보를 불러오는 중 오류가 발생했습니다');
} finally {
@@ -76,9 +76,20 @@ const ApiHubApiDetailPage = () => {
}, [serviceId, apiId]);
useEffect(() => {
+ setParamInputs({});
+ setGeneratedUrl(null);
+ setUrlCopied(false);
+ setValidationErrors({});
+ setIsLoading(true);
+ setError(null);
fetchData();
}, [fetchData]);
+ const urlInputParams = useMemo(() =>
+ detail?.requestParams.filter((p) => p.paramName.toUpperCase() !== 'URL') ?? [],
+ [detail?.requestParams]
+ );
+
if (isLoading) {
return (
@@ -87,7 +98,7 @@ const ApiHubApiDetailPage = () => {
);
}
- if (error || !api) {
+ if (error || !detail) {
return (
|