release: 2026-04-14 (15건 커밋) #45

병합
HYOJIN develop 에서 main 로 15 commits 를 머지했습니다 2026-04-14 15:55:31 +09:00
2개의 변경된 파일24개의 추가작업 그리고 20개의 파일을 삭제
Showing only changes of commit dd1ac022d2 - Show all commits

파일 보기

@ -1,7 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import type { ServiceCatalog, ServiceApiItem } from '../../types/apihub';
import { getCatalog } from '../../services/apiHubService';
import { getServiceCatalog } from '../../services/apiHubService';
const METHOD_COLORS: Record<string, string> = {
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: '알 수 없음',
};
const truncate = (str: string, max: number): string =>
str.length > max ? str.slice(0, max) + '...' : str;
interface DomainSectionProps {
domainName: string;
apis: ServiceApiItem[];
@ -48,14 +45,21 @@ const DomainSection = ({ domainName, apis, serviceId, onNavigate }: DomainSectio
</span>
</div>
<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">
<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">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 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>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
@ -72,14 +76,14 @@ const DomainSection = ({ domainName, apis, serviceId, onNavigate }: DomainSectio
{api.apiMethod}
</span>
</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}
</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}
</td>
<td className="px-4 py-3 text-gray-500 dark:text-gray-400 max-w-sm">
{api.description ? truncate(api.description, 60) : <span className="text-gray-300 dark:text-gray-600">-</span>}
<td className="px-4 py-3 text-gray-500 dark:text-gray-400 truncate" title={api.description || ''}>
{api.description || <span className="text-gray-300 dark:text-gray-600">-</span>}
</td>
<td className="px-4 py-3">
{api.isActive ? (
@ -106,14 +110,9 @@ const ApiHubServicePage = () => {
const fetchData = useCallback(async () => {
if (!serviceId) return;
try {
const res = await getCatalog();
const res = await getServiceCatalog(Number(serviceId));
if (res.success && res.data) {
const found = res.data.find((s) => s.serviceId === Number(serviceId));
if (found) {
setService(found);
} else {
setError('서비스를 찾을 수 없습니다');
}
setService(res.data);
} else {
setError('서비스 정보를 불러오지 못했습니다');
}
@ -158,7 +157,7 @@ const ApiHubServicePage = () => {
const domainsMap = new Map<string, ServiceApiItem[]>();
for (const dg of service.domains) {
const key = dg.domain || '기타';
const key = dg.domain ? dg.domain.toUpperCase() : '기타';
domainsMap.set(key, dg.apis);
}
@ -166,7 +165,7 @@ const ApiHubServicePage = () => {
const domainEntries = [...domainsMap.entries()];
return (
<div>
<div className="max-w-7xl mx-auto">
<button
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"

파일 보기

@ -1,5 +1,10 @@
import { get } from './apiClient';
import type { ServiceCatalog, RecentApi } from '../types/apihub';
import type { ApiDetailInfo } from '../types/service';
export const getCatalog = () => get<ServiceCatalog[]>('/api-hub/catalog');
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}`);