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>
This commit is contained in:
@@ -15,8 +15,10 @@ import type {
|
||||
// ==================== Epics API ====================
|
||||
export const epicsApi = {
|
||||
list: async (projectId?: string): Promise<Epic[]> => {
|
||||
const params = projectId ? { projectId } : undefined;
|
||||
return api.get('/api/v1/epics', { params });
|
||||
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> => {
|
||||
@@ -47,8 +49,10 @@ export const epicsApi = {
|
||||
// ==================== Stories API ====================
|
||||
export const storiesApi = {
|
||||
list: async (epicId?: string): Promise<Story[]> => {
|
||||
const params = epicId ? { epicId } : undefined;
|
||||
return api.get('/api/v1/stories', { params });
|
||||
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> => {
|
||||
@@ -79,8 +83,10 @@ export const storiesApi = {
|
||||
// ==================== Tasks API ====================
|
||||
export const tasksApi = {
|
||||
list: async (storyId?: string): Promise<Task[]> => {
|
||||
const params = storyId ? { storyId } : undefined;
|
||||
return api.get('/api/v1/tasks', { params });
|
||||
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> => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { storiesApi } from '@/lib/api/pm';
|
||||
import { epicsApi } from '@/lib/api/pm';
|
||||
import type { Story, CreateStoryDto, UpdateStoryDto, WorkItemStatus } from '@/types/project';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
@@ -23,6 +24,42 @@ export function useStories(epicId?: string) {
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch all stories for a project (by fetching epics first, then all stories)
|
||||
export function useProjectStories(projectId?: string) {
|
||||
return useQuery<Story[]>({
|
||||
queryKey: ['project-stories', projectId],
|
||||
queryFn: async () => {
|
||||
if (!projectId) {
|
||||
throw new Error('projectId is required');
|
||||
}
|
||||
|
||||
console.log('[useProjectStories] Fetching all stories for project...', { projectId });
|
||||
|
||||
try {
|
||||
// First fetch all epics for the project
|
||||
const epics = await epicsApi.list(projectId);
|
||||
console.log('[useProjectStories] Epics fetched:', epics.length);
|
||||
|
||||
// Then fetch stories for each epic
|
||||
const storiesPromises = epics.map((epic) => storiesApi.list(epic.id));
|
||||
const storiesArrays = await Promise.all(storiesPromises);
|
||||
|
||||
// Flatten the array of arrays into a single array
|
||||
const allStories = storiesArrays.flat();
|
||||
console.log('[useProjectStories] Total stories fetched:', allStories.length);
|
||||
|
||||
return allStories;
|
||||
} catch (error) {
|
||||
console.error('[useProjectStories] Fetch failed:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
enabled: !!projectId,
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
retry: 1,
|
||||
});
|
||||
}
|
||||
|
||||
export function useStory(id: string) {
|
||||
return useQuery<Story>({
|
||||
queryKey: ['stories', id],
|
||||
|
||||
Reference in New Issue
Block a user