From 3055be860da3f16902dd3a713fbf7cf7a2bc9995 Mon Sep 17 00:00:00 2001 From: Zhi Date: Thu, 12 Mar 2026 14:25:44 +0000 Subject: [PATCH] feat: milestone enhancements - tabs, task/support/meeting types, progress, status --- src/index.css | 9 ++ src/pages/MilestoneDetailPage.tsx | 172 +++++++++++++++++++++++++----- src/pages/MilestonesPage.tsx | 37 ++++++- src/pages/ProjectDetailPage.tsx | 2 +- src/types/index.ts | 21 +++- 5 files changed, 204 insertions(+), 37 deletions(-) diff --git a/src/index.css b/src/index.css index 1b351bf..3f807d4 100644 --- a/src/index.css +++ b/src/index.css @@ -201,3 +201,12 @@ dd { font-size: .9rem; } .btn-secondary { background: none; border: 1px solid var(--border); color: var(--text); padding: 6px 12px; border-radius: 6px; cursor: pointer; } .btn-danger { background: var(--danger); color: #fff; border: none; padding: 6px 12px; border-radius: 6px; cursor: pointer; } .btn-danger:hover { opacity: .9; } + + +/* Tabs */ +.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 16px; } +.tab { background: none; border: none; padding: 10px 16px; color: var(--text-dim); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; } +.tab:hover { color: var(--text); } +.tab.active { color: var(--accent); border-bottom-color: var(--accent); } +.tab-content { margin-top: 16px; } + diff --git a/src/pages/MilestoneDetailPage.tsx b/src/pages/MilestoneDetailPage.tsx index 4c23f1e..301fd04 100644 --- a/src/pages/MilestoneDetailPage.tsx +++ b/src/pages/MilestoneDetailPage.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react' import { useParams, useNavigate } from 'react-router-dom' import api from '@/services/api' -import type { Milestone, MilestoneProgress, Issue } from '@/types' +import type { Milestone, MilestoneProgress, MilestoneItems, Issue } from '@/types' import dayjs from 'dayjs' export default function MilestoneDetailPage() { @@ -9,25 +9,55 @@ export default function MilestoneDetailPage() { const navigate = useNavigate() const [milestone, setMilestone] = useState(null) const [progress, setProgress] = useState(null) - const [issues, setIssues] = useState([]) + const [items, setItems] = useState(null) + const [activeTab, setActiveTab] = useState<'tasks' | 'supports' | 'meetings'>('tasks') + const [showCreateTask, setShowCreateTask] = useState(false) + const [showCreateSupport, setShowCreateSupport] = useState(false) + const [showCreateMeeting, setShowCreateMeeting] = useState(false) + const [newTitle, setNewTitle] = useState('') + const [newDesc, setNewDesc] = useState('') useEffect(() => { api.get(`/milestones/${id}`).then(({ data }) => setMilestone(data)) api.get(`/milestones/${id}/progress`).then(({ data }) => setProgress(data)).catch(() => {}) - api.get(`/milestones/${id}/issues`).then(({ data }) => setIssues(data)).catch(() => {}) + api.get(`/milestones/${id}/items`).then(({ data }) => setItems(data)).catch(() => {}) }, [id]) + const createItem = async (type: 'tasks' | 'supports' | 'meetings') => { + if (!newTitle.trim()) return + await api.post(`/milestones/${id}/${type}`, { + title: newTitle, + description: newDesc || null, + status: 'open', + priority: 'medium' + }) + setNewTitle('') + setNewDesc('') + setShowCreateTask(false) + setShowCreateSupport(false) + setShowCreateMeeting(false) + // Refresh items + api.get(`/milestones/${id}/items`).then(({ data }) => setItems(data)) + } + + const isProgressing = milestone?.status === 'progressing' + if (!milestone) return
Loading...
+ const tasks = items?.tasks || [] + const supports = items?.supports || [] + const meetings = items?.meetings || [] + return (
- +

๐Ÿ {milestone.title}

- {milestone.status} + {milestone.status} {milestone.due_date && Due {dayjs(milestone.due_date).format('YYYY-MM-DD')}} + {milestone.planned_release_date && Planned Release: {dayjs(milestone.planned_release_date).format('YYYY-MM-DD')}}
@@ -40,36 +70,122 @@ export default function MilestoneDetailPage() { {progress && (
-

Progress

+

Progress (Tasks: {progress.completed}/{progress.total})

-
- {progress.progress_percent.toFixed(0)}% +
+ {progress.progress_pct.toFixed(0)}%
-

- {progress.completed_issues} / {progress.total_issues} issues completed -

+ {progress.time_progress_pct !== null && ( + <> +

Time Progress

+
+
+ {progress.time_progress_pct.toFixed(0)}% +
+
+ + )}
)}
-

Issues ({issues.length})

- - - - - - {issues.map((i) => ( - navigate(`/issues/${i.id}`)}> - - - - - - ))} - {issues.length === 0 && } - -
#TitleStatusPriority
{i.id}{i.title}{i.status}{i.priority}
No linked issues
+
+ {!isProgressing && ( + <> + + + + + )} + {isProgressing && Milestone is in progress - cannot add new items} +
+ + {(showCreateTask || showCreateSupport || showCreateMeeting) && ( +
+ setNewTitle(e.target.value)} + style={{ marginBottom: 8 }} + /> +