Files
ColaFlow-Web/lib/api/pm.ts
Yaojia Wang 90e3d2416c feat(frontend): Refactor Kanban board to focus on Story management
Refactored the Kanban board from a mixed Epic/Story/Task view to focus exclusively on Stories, which are the right granularity for Kanban management.

Changes:
- Created StoryCard component with Epic breadcrumb, priority badges, and estimated hours display
- Updated KanbanColumn to use Story type and display epic names
- Created CreateStoryDialog for story creation with epic selection
- Added useProjectStories hook to fetch all stories across epics for a project
- Refactored Kanban page to show Stories only with drag-and-drop status updates
- Updated SignalR event handlers to focus on Story events only
- Changed UI text from 'New Issue' to 'New Story' and 'update issue status' to 'update story status'
- Implemented story status change via useChangeStoryStatus hook

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 15:03:12 +01:00

116 lines
3.2 KiB
TypeScript

import { api } from './client';
import type {
Epic,
CreateEpicDto,
UpdateEpicDto,
Story,
CreateStoryDto,
UpdateStoryDto,
Task,
CreateTaskDto,
UpdateTaskDto,
WorkItemStatus,
} from '@/types/project';
// ==================== Epics API ====================
export const epicsApi = {
list: async (projectId?: string): Promise<Epic[]> => {
if (!projectId) {
throw new Error('projectId is required for listing epics');
}
return api.get(`/api/v1/projects/${projectId}/epics`);
},
get: async (id: string): Promise<Epic> => {
return api.get(`/api/v1/epics/${id}`);
},
create: async (data: CreateEpicDto): Promise<Epic> => {
return api.post('/api/v1/epics', data);
},
update: async (id: string, data: UpdateEpicDto): Promise<Epic> => {
return api.put(`/api/v1/epics/${id}`, data);
},
delete: async (id: string): Promise<void> => {
return api.delete(`/api/v1/epics/${id}`);
},
changeStatus: async (id: string, status: WorkItemStatus): Promise<Epic> => {
return api.put(`/api/v1/epics/${id}/status`, { status });
},
assign: async (id: string, assigneeId: string): Promise<Epic> => {
return api.put(`/api/v1/epics/${id}/assign`, { assigneeId });
},
};
// ==================== Stories API ====================
export const storiesApi = {
list: async (epicId?: string): Promise<Story[]> => {
if (!epicId) {
throw new Error('epicId is required for listing stories');
}
return api.get(`/api/v1/epics/${epicId}/stories`);
},
get: async (id: string): Promise<Story> => {
return api.get(`/api/v1/stories/${id}`);
},
create: async (data: CreateStoryDto): Promise<Story> => {
return api.post('/api/v1/stories', data);
},
update: async (id: string, data: UpdateStoryDto): Promise<Story> => {
return api.put(`/api/v1/stories/${id}`, data);
},
delete: async (id: string): Promise<void> => {
return api.delete(`/api/v1/stories/${id}`);
},
changeStatus: async (id: string, status: WorkItemStatus): Promise<Story> => {
return api.put(`/api/v1/stories/${id}/status`, { status });
},
assign: async (id: string, assigneeId: string): Promise<Story> => {
return api.put(`/api/v1/stories/${id}/assign`, { assigneeId });
},
};
// ==================== Tasks API ====================
export const tasksApi = {
list: async (storyId?: string): Promise<Task[]> => {
if (!storyId) {
throw new Error('storyId is required for listing tasks');
}
return api.get(`/api/v1/stories/${storyId}/tasks`);
},
get: async (id: string): Promise<Task> => {
return api.get(`/api/v1/tasks/${id}`);
},
create: async (data: CreateTaskDto): Promise<Task> => {
return api.post('/api/v1/tasks', data);
},
update: async (id: string, data: UpdateTaskDto): Promise<Task> => {
return api.put(`/api/v1/tasks/${id}`, data);
},
delete: async (id: string): Promise<void> => {
return api.delete(`/api/v1/tasks/${id}`);
},
changeStatus: async (id: string, status: WorkItemStatus): Promise<Task> => {
return api.put(`/api/v1/tasks/${id}/status`, { status });
},
assign: async (id: string, assigneeId: string): Promise<Task> => {
return api.put(`/api/v1/tasks/${id}/assign`, { assigneeId });
},
};