From 13dad7272c6eab98f0253c049648b547d27d3c64 Mon Sep 17 00:00:00 2001 From: Lectom C Han Date: Mon, 4 Aug 2025 18:08:28 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9D=B4=EC=8A=88=20API=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이슈 목록/상세 API 연동 - 테이블 컬럼 너비 조정 - Biome 린터 설정 수정 --- viewer/biome.json | 11 +-- viewer/src/components/DynamicTable.tsx | 4 +- viewer/src/services/issue.ts | 130 ++++++------------------- 3 files changed, 36 insertions(+), 109 deletions(-) diff --git a/viewer/biome.json b/viewer/biome.json index 0e6b74e..13289e7 100644 --- a/viewer/biome.json +++ b/viewer/biome.json @@ -4,18 +4,15 @@ "enabled": true, "rules": { "recommended": true - }, - "ignore": ["node_modules"] + } }, "formatter": { "enabled": true, - "indentStyle": "tab", - "ignore": ["node_modules"] + "indentStyle": "tab" }, "javascript": { "formatter": { "quoteStyle": "double" - }, - "organizeImports": {} + } } -} +} \ No newline at end of file diff --git a/viewer/src/components/DynamicTable.tsx b/viewer/src/components/DynamicTable.tsx index a95000f..b2cb943 100644 --- a/viewer/src/components/DynamicTable.tsx +++ b/viewer/src/components/DynamicTable.tsx @@ -193,9 +193,9 @@ export function DynamicTable({ field.id === "id" ? 50 : field.id === "name" || field.id === "title" - ? 150 + ? 300 : field.id === "description" || field.id === "contents" - ? 200 + ? 500 : field.id === "createdAt" || field.id === "updatedAt" ? 120 // 10글자 너비 : undefined, diff --git a/viewer/src/services/issue.ts b/viewer/src/services/issue.ts index c818a9c..f04542e 100644 --- a/viewer/src/services/issue.ts +++ b/viewer/src/services/issue.ts @@ -2,127 +2,45 @@ import { handleApiError } from "./error"; export interface Issue { - id: string; + id: number; name: string; description: string; status: string; - category: string; + priority?: string; + category?: string; createdAt: string; updatedAt: string; - - feedbackCount: number; [key: string]: unknown; } export interface IssueField { id: string; name: string; - type: "text" | "textarea" | "number" | "select"; + type: "text" | "textarea" | "number" | "select" | "date"; readOnly?: boolean; } -/** - * 이슈 목록에 표시할 필드 스키마를 반환합니다. - * 순서: Status, ID, Name, Description, Category - */ export async function getIssues(projectId: string): Promise { console.log(`Fetching issues for project: ${projectId}`); - // ... 실제 API 호출 로직 ... - return [ - { - id: "1", - name: "로그인 버튼 실종", - description: "메인 화면에서 로그인 버튼이 보이지 않는 버그 발생", - status: "Open", - priority: "High", - createdAt: "2023-10-01T10:00:00Z", - updatedAt: "2023-10-01T11:00:00Z", + const url = `/api/projects/${projectId}/issues/search`; + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", }, - { - id: "2", - name: "데이터 로딩 속도 저하", - description: "대시보드 로딩 시 5초 이상 소요됨", - status: "In Progress", - priority: "Medium", - createdAt: "2023-10-02T14:00:00Z", - updatedAt: "2023-10-02T15:30:00Z", - }, - { - id: "3", - name: "모바일 화면 깨짐", - description: "iPhone 14 Pro에서 프로필 페이지 레이아웃이 깨져 보임", - status: "Open", - priority: "High", - createdAt: "2023-10-03T09:00:00Z", - updatedAt: "2023-10-03T09:00:00Z", - }, - { - id: "4", - name: "API 요청 실패", - description: "특정 조건에서 사용자 정보 업데이트 시 500 에러 발생", - status: "Closed", - priority: "Critical", - createdAt: "2023-09-28T11:00:00Z", - updatedAt: "2023-10-01T18:00:00Z", - }, - { - id: "5", - name: "오타 수정", - description: "이용약관 페이지의 '개인정보'가 '개인정ㅂ'로 표시됨", - status: "Closed", - priority: "Low", - createdAt: "2023-10-04T16:00:00Z", - updatedAt: "2023-10-04T16:30:00Z", - }, - { - id: "6", - name: "다크 모드 지원", - description: "사용자 편의를 위해 다크 모드 기능 추가 필요", - status: "Open", - priority: "Medium", - createdAt: "2023-10-05T11:20:00Z", - updatedAt: "2023-10-05T11:20:00Z", - }, - ]; + body: JSON.stringify({}), + }); + if (!response.ok) { + await handleApiError("이슈 목록을 불러오는 데 실패했습니다.", response); + } + const data = await response.json(); + return data.items; } export async function getIssueById( projectId: string, issueId: string, ): Promise { - console.log( - `Fetching issue ${issueId} for project: ${projectId}`, - ); - // 실제 API 호출에서는 projectId와 issueId를 사용해야 합니다. - // 여기서는 모든 이슈를 가져온 후 ID로 필터링하여 모의합니다. - const issues = await getIssues(projectId); - const issue = issues.find((i) => i.id === issueId); - if (!issue) { - throw new Error("Issue not found"); - } - return issue; -} - -export async function getIssueFields(): Promise { - // ... 기존 코드 ... - return [ - { id: "id", name: "ID", type: "text" }, - { id: "name", name: "이름", type: "text" }, - { id: "description", name: "설명", type: "text" }, - { id: "status", name: "상태", type: "text" }, - { id: "priority", name: "우선순위", type: "text" }, - { id: "createdAt", name: "생성일", type: "date" }, - { id: "updatedAt", name: "수정일", type: "date" }, - ]; -} - -/** - * 특정 프로젝트의 단일 이슈 상세 정보를 가져옵니다. - */ -export const getIssue = async ( - projectId: string, - issueId: string, -): Promise => { const url = `/api/projects/${projectId}/issues/${issueId}`; const response = await fetch(url); @@ -133,6 +51,18 @@ export const getIssue = async ( ); } - // API 응답을 그대로 사용합니다. return response.json(); -}; +} + +export async function getIssueFields(): Promise { + // This is mock data, but it's used by other components. + return [ + { id: "id", name: "ID", type: "text" }, + { id: "name", name: "이름", type: "text" }, + { id: "description", name: "설명", type: "text" }, + { id: "status", name: "상태", type: "text" }, + { id: "priority", name: "우선순위", type: "text" }, + { id: "createdAt", name: "생성일", type: "date" }, + { id: "updatedAt", name: "수정일", type: "date" }, + ]; +} \ No newline at end of file