generated from gc/template-java-maven
feat(api-hub): API HUB 상세 화면 개선
- 요청 URL 생성 영역 아코디언 형태로 변경 - 샘플 URL 영역 추가 (기본 정보 하단) - 출력결과 2열 레이아웃 (변수명|의미(단위)) 추가 - 공통 샘플 코드 연동 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
부모
ac0f51b816
커밋
dd1ac022d2
@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import type { ServiceCatalog, ServiceApiItem } from '../../types/apihub';
|
import type { ServiceCatalog, ServiceApiItem } from '../../types/apihub';
|
||||||
import { getCatalog } from '../../services/apiHubService';
|
import { getServiceCatalog } from '../../services/apiHubService';
|
||||||
|
|
||||||
const METHOD_COLORS: Record<string, string> = {
|
const METHOD_COLORS: Record<string, string> = {
|
||||||
GET: 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300',
|
GET: 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300',
|
||||||
@ -29,9 +29,6 @@ const HEALTH_LABEL: Record<string, string> = {
|
|||||||
UNKNOWN: '알 수 없음',
|
UNKNOWN: '알 수 없음',
|
||||||
};
|
};
|
||||||
|
|
||||||
const truncate = (str: string, max: number): string =>
|
|
||||||
str.length > max ? str.slice(0, max) + '...' : str;
|
|
||||||
|
|
||||||
interface DomainSectionProps {
|
interface DomainSectionProps {
|
||||||
domainName: string;
|
domainName: string;
|
||||||
apis: ServiceApiItem[];
|
apis: ServiceApiItem[];
|
||||||
@ -48,14 +45,21 @@ const DomainSection = ({ domainName, apis, serviceId, onNavigate }: DomainSectio
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden border border-gray-100 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden border border-gray-100 dark:border-gray-700">
|
||||||
<table className="w-full text-sm">
|
<table className="w-full text-sm table-fixed">
|
||||||
|
<colgroup>
|
||||||
|
<col className="w-[8%]" />
|
||||||
|
<col className="w-[27%]" />
|
||||||
|
<col className="w-[20%]" />
|
||||||
|
<col className="w-[40%]" />
|
||||||
|
<col className="w-[5%]" />
|
||||||
|
</colgroup>
|
||||||
<thead className="bg-gray-50 dark:bg-gray-700">
|
<thead className="bg-gray-50 dark:bg-gray-700">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase w-24">메서드</th>
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">메서드</th>
|
||||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">경로</th>
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">경로</th>
|
||||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">API명</th>
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">API명</th>
|
||||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">설명</th>
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">설명</th>
|
||||||
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase w-16">상태</th>
|
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">상태</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
|
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
@ -72,14 +76,14 @@ const DomainSection = ({ domainName, apis, serviceId, onNavigate }: DomainSectio
|
|||||||
{api.apiMethod}
|
{api.apiMethod}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3 font-mono text-xs text-gray-700 dark:text-gray-300 max-w-xs truncate" title={api.apiPath}>
|
<td className="px-4 py-3 font-mono text-xs text-gray-700 dark:text-gray-300 truncate" title={api.apiPath}>
|
||||||
{api.apiPath}
|
{api.apiPath}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3 text-gray-900 dark:text-gray-100 font-medium max-w-xs truncate" title={api.apiName}>
|
<td className="px-4 py-3 text-gray-900 dark:text-gray-100 font-medium truncate" title={api.apiName}>
|
||||||
{api.apiName}
|
{api.apiName}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3 text-gray-500 dark:text-gray-400 max-w-sm">
|
<td className="px-4 py-3 text-gray-500 dark:text-gray-400 truncate" title={api.description || ''}>
|
||||||
{api.description ? truncate(api.description, 60) : <span className="text-gray-300 dark:text-gray-600">-</span>}
|
{api.description || <span className="text-gray-300 dark:text-gray-600">-</span>}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3">
|
<td className="px-4 py-3">
|
||||||
{api.isActive ? (
|
{api.isActive ? (
|
||||||
@ -106,14 +110,9 @@ const ApiHubServicePage = () => {
|
|||||||
const fetchData = useCallback(async () => {
|
const fetchData = useCallback(async () => {
|
||||||
if (!serviceId) return;
|
if (!serviceId) return;
|
||||||
try {
|
try {
|
||||||
const res = await getCatalog();
|
const res = await getServiceCatalog(Number(serviceId));
|
||||||
if (res.success && res.data) {
|
if (res.success && res.data) {
|
||||||
const found = res.data.find((s) => s.serviceId === Number(serviceId));
|
setService(res.data);
|
||||||
if (found) {
|
|
||||||
setService(found);
|
|
||||||
} else {
|
|
||||||
setError('서비스를 찾을 수 없습니다');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setError('서비스 정보를 불러오지 못했습니다');
|
setError('서비스 정보를 불러오지 못했습니다');
|
||||||
}
|
}
|
||||||
@ -158,7 +157,7 @@ const ApiHubServicePage = () => {
|
|||||||
|
|
||||||
const domainsMap = new Map<string, ServiceApiItem[]>();
|
const domainsMap = new Map<string, ServiceApiItem[]>();
|
||||||
for (const dg of service.domains) {
|
for (const dg of service.domains) {
|
||||||
const key = dg.domain || '기타';
|
const key = dg.domain ? dg.domain.toUpperCase() : '기타';
|
||||||
domainsMap.set(key, dg.apis);
|
domainsMap.set(key, dg.apis);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +165,7 @@ const ApiHubServicePage = () => {
|
|||||||
const domainEntries = [...domainsMap.entries()];
|
const domainEntries = [...domainsMap.entries()];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="max-w-7xl mx-auto">
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate('/api-hub')}
|
onClick={() => navigate('/api-hub')}
|
||||||
className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 mb-4 inline-block"
|
className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 mb-4 inline-block"
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { get } from './apiClient';
|
import { get } from './apiClient';
|
||||||
import type { ServiceCatalog, RecentApi } from '../types/apihub';
|
import type { ServiceCatalog, RecentApi } from '../types/apihub';
|
||||||
|
import type { ApiDetailInfo } from '../types/service';
|
||||||
|
|
||||||
export const getCatalog = () => get<ServiceCatalog[]>('/api-hub/catalog');
|
export const getCatalog = () => get<ServiceCatalog[]>('/api-hub/catalog');
|
||||||
export const getRecentApis = () => get<RecentApi[]>('/api-hub/recent-apis');
|
export const getRecentApis = () => get<RecentApi[]>('/api-hub/recent-apis');
|
||||||
|
export const getServiceCatalog = (serviceId: number) =>
|
||||||
|
get<ServiceCatalog>(`/api-hub/services/${serviceId}`);
|
||||||
|
export const getApiHubApiDetail = (serviceId: number, apiId: number) =>
|
||||||
|
get<ApiDetailInfo>(`/api-hub/services/${serviceId}/apis/${apiId}`);
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user