feat: 이슈 API 연동 및 UI 개선
- 이슈 목록/상세 API 연동 - 테이블 컬럼 너비 조정 - Biome 린터 설정 수정
This commit is contained in:
@@ -4,18 +4,15 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true
|
"recommended": true
|
||||||
},
|
}
|
||||||
"ignore": ["node_modules"]
|
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"indentStyle": "tab",
|
"indentStyle": "tab"
|
||||||
"ignore": ["node_modules"]
|
|
||||||
},
|
},
|
||||||
"javascript": {
|
"javascript": {
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"quoteStyle": "double"
|
"quoteStyle": "double"
|
||||||
},
|
}
|
||||||
"organizeImports": {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,9 +193,9 @@ export function DynamicTable<TData extends BaseData>({
|
|||||||
field.id === "id"
|
field.id === "id"
|
||||||
? 50
|
? 50
|
||||||
: field.id === "name" || field.id === "title"
|
: field.id === "name" || field.id === "title"
|
||||||
? 150
|
? 300
|
||||||
: field.id === "description" || field.id === "contents"
|
: field.id === "description" || field.id === "contents"
|
||||||
? 200
|
? 500
|
||||||
: field.id === "createdAt" || field.id === "updatedAt"
|
: field.id === "createdAt" || field.id === "updatedAt"
|
||||||
? 120 // 10글자 너비
|
? 120 // 10글자 너비
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|||||||
@@ -2,127 +2,45 @@
|
|||||||
import { handleApiError } from "./error";
|
import { handleApiError } from "./error";
|
||||||
|
|
||||||
export interface Issue {
|
export interface Issue {
|
||||||
id: string;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
status: string;
|
status: string;
|
||||||
category: string;
|
priority?: string;
|
||||||
|
category?: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|
||||||
feedbackCount: number;
|
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IssueField {
|
export interface IssueField {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: "text" | "textarea" | "number" | "select";
|
type: "text" | "textarea" | "number" | "select" | "date";
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 이슈 목록에 표시할 필드 스키마를 반환합니다.
|
|
||||||
* 순서: Status, ID, Name, Description, Category
|
|
||||||
*/
|
|
||||||
export async function getIssues(projectId: string): Promise<Issue[]> {
|
export async function getIssues(projectId: string): Promise<Issue[]> {
|
||||||
console.log(`Fetching issues for project: ${projectId}`);
|
console.log(`Fetching issues for project: ${projectId}`);
|
||||||
// ... 실제 API 호출 로직 ...
|
const url = `/api/projects/${projectId}/issues/search`;
|
||||||
return [
|
const response = await fetch(url, {
|
||||||
{
|
method: "POST",
|
||||||
id: "1",
|
headers: {
|
||||||
name: "로그인 버튼 실종",
|
"Content-Type": "application/json",
|
||||||
description: "메인 화면에서 로그인 버튼이 보이지 않는 버그 발생",
|
|
||||||
status: "Open",
|
|
||||||
priority: "High",
|
|
||||||
createdAt: "2023-10-01T10:00:00Z",
|
|
||||||
updatedAt: "2023-10-01T11:00:00Z",
|
|
||||||
},
|
},
|
||||||
{
|
body: JSON.stringify({}),
|
||||||
id: "2",
|
});
|
||||||
name: "데이터 로딩 속도 저하",
|
if (!response.ok) {
|
||||||
description: "대시보드 로딩 시 5초 이상 소요됨",
|
await handleApiError("이슈 목록을 불러오는 데 실패했습니다.", response);
|
||||||
status: "In Progress",
|
}
|
||||||
priority: "Medium",
|
const data = await response.json();
|
||||||
createdAt: "2023-10-02T14:00:00Z",
|
return data.items;
|
||||||
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",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getIssueById(
|
export async function getIssueById(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
issueId: string,
|
issueId: string,
|
||||||
): Promise<Issue> {
|
): Promise<Issue> {
|
||||||
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<IssueField[]> {
|
|
||||||
// ... 기존 코드 ...
|
|
||||||
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<Issue> => {
|
|
||||||
const url = `/api/projects/${projectId}/issues/${issueId}`;
|
const url = `/api/projects/${projectId}/issues/${issueId}`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
@@ -133,6 +51,18 @@ export const getIssue = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// API 응답을 그대로 사용합니다.
|
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export async function getIssueFields(): Promise<IssueField[]> {
|
||||||
|
// 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" },
|
||||||
|
];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user