Update Kanban to show only current sprint tasks
- Removed Sprint view (now just Kanban + Backlog) - Kanban shows only tasks from current active sprint - Sprint header shows current sprint info - 3-column layout: To Do, In Progress, Done - Done column combines review + done tasks - Auto-assign new tasks to current sprint - Tasks without sprints won't show in Kanban (go to Backlog)
This commit is contained in:
parent
0761adedbe
commit
e734c6fab5
@ -469,7 +469,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastUpdated": 1771544832422,
|
"lastUpdated": 1771546378027,
|
||||||
"sprints": [
|
"sprints": [
|
||||||
{
|
{
|
||||||
"name": "Sprint 1",
|
"name": "Sprint 1",
|
||||||
@ -480,6 +480,16 @@
|
|||||||
"projectId": "1",
|
"projectId": "1",
|
||||||
"id": "1771544832363",
|
"id": "1771544832363",
|
||||||
"createdAt": "2026-02-19T23:47:12.363Z"
|
"createdAt": "2026-02-19T23:47:12.363Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sprint 1",
|
||||||
|
"goal": "",
|
||||||
|
"startDate": "2026-02-16",
|
||||||
|
"endDate": "2026-02-22",
|
||||||
|
"status": "planning",
|
||||||
|
"projectId": "2",
|
||||||
|
"id": "1771546141285",
|
||||||
|
"createdAt": "2026-02-20T00:09:01.285Z"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -8,9 +8,8 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "
|
|||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { useTaskStore, Task, TaskType, TaskStatus, Priority, Project } from "@/stores/useTaskStore"
|
import { useTaskStore, Task, TaskType, TaskStatus, Priority, Project } from "@/stores/useTaskStore"
|
||||||
import { SprintBoard } from "@/components/SprintBoard"
|
|
||||||
import { BacklogView } from "@/components/BacklogView"
|
import { BacklogView } from "@/components/BacklogView"
|
||||||
import { Plus, MessageSquare, Calendar, Tag, Trash2, Edit2, X, Check, MoreHorizontal, LayoutGrid, Flag, ListTodo } from "lucide-react"
|
import { Plus, MessageSquare, Calendar, Tag, Trash2, Edit2, X, Check, MoreHorizontal, LayoutGrid, ListTodo } from "lucide-react"
|
||||||
|
|
||||||
const typeColors: Record<TaskType, string> = {
|
const typeColors: Record<TaskType, string> = {
|
||||||
idea: "bg-purple-500",
|
idea: "bg-purple-500",
|
||||||
@ -35,7 +34,12 @@ const priorityColors: Record<Priority, string> = {
|
|||||||
urgent: "text-red-400",
|
urgent: "text-red-400",
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusColumns: TaskStatus[] = ["backlog", "in-progress", "review", "done"]
|
// Sprint board columns (3 columns)
|
||||||
|
const sprintColumns = [
|
||||||
|
{ key: "backlog", label: "To Do" },
|
||||||
|
{ key: "in-progress", label: "In Progress" },
|
||||||
|
{ key: "review", label: "Done" },
|
||||||
|
] as const
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const {
|
const {
|
||||||
@ -72,7 +76,7 @@ export default function Home() {
|
|||||||
})
|
})
|
||||||
const [newComment, setNewComment] = useState("")
|
const [newComment, setNewComment] = useState("")
|
||||||
const [editingTask, setEditingTask] = useState<Task | null>(null)
|
const [editingTask, setEditingTask] = useState<Task | null>(null)
|
||||||
const [viewMode, setViewMode] = useState<'kanban' | 'sprint' | 'backlog'>('kanban')
|
const [viewMode, setViewMode] = useState<'kanban' | 'backlog'>('kanban')
|
||||||
|
|
||||||
// Sync from server on mount
|
// Sync from server on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -82,6 +86,20 @@ export default function Home() {
|
|||||||
const selectedProject = projects.find((p) => p.id === selectedProjectId)
|
const selectedProject = projects.find((p) => p.id === selectedProjectId)
|
||||||
const selectedTask = tasks.find((t) => t.id === selectedTaskId)
|
const selectedTask = tasks.find((t) => t.id === selectedTaskId)
|
||||||
const projectTasks = selectedProjectId ? getTasksByProject(selectedProjectId) : []
|
const projectTasks = selectedProjectId ? getTasksByProject(selectedProjectId) : []
|
||||||
|
|
||||||
|
// Get current active sprint for the selected project
|
||||||
|
const now = new Date()
|
||||||
|
const currentSprint = sprints.find((s) =>
|
||||||
|
s.projectId === selectedProjectId &&
|
||||||
|
s.status === 'active' &&
|
||||||
|
new Date(s.startDate) <= now &&
|
||||||
|
new Date(s.endDate) >= now
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter tasks to only show current sprint tasks in Kanban
|
||||||
|
const sprintTasks = currentSprint
|
||||||
|
? projectTasks.filter((t) => t.sprintId === currentSprint.id)
|
||||||
|
: []
|
||||||
|
|
||||||
const handleAddProject = () => {
|
const handleAddProject = () => {
|
||||||
if (newProjectName.trim()) {
|
if (newProjectName.trim()) {
|
||||||
@ -97,6 +115,7 @@ export default function Home() {
|
|||||||
...newTask,
|
...newTask,
|
||||||
projectId: selectedProjectId,
|
projectId: selectedProjectId,
|
||||||
status: newTask.status || "backlog",
|
status: newTask.status || "backlog",
|
||||||
|
sprintId: currentSprint?.id, // Auto-assign to current sprint
|
||||||
} as any)
|
} as any)
|
||||||
setNewTask({ title: "", description: "", type: "task", priority: "medium", status: "backlog", tags: [] })
|
setNewTask({ title: "", description: "", type: "task", priority: "medium", status: "backlog", tags: [] })
|
||||||
setNewTaskOpen(false)
|
setNewTaskOpen(false)
|
||||||
@ -240,7 +259,7 @@ export default function Home() {
|
|||||||
{selectedProject.name}
|
{selectedProject.name}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-slate-400">
|
<p className="text-sm text-slate-400">
|
||||||
{projectTasks.length} tasks · {projectTasks.filter((t) => t.status === "done").length} done
|
{sprintTasks.length} tasks · {sprintTasks.filter((t) => t.status === "done").length} done
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@ -257,17 +276,6 @@ export default function Home() {
|
|||||||
<LayoutGrid className="w-4 h-4" />
|
<LayoutGrid className="w-4 h-4" />
|
||||||
Kanban
|
Kanban
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
onClick={() => setViewMode('sprint')}
|
|
||||||
className={`flex items-center gap-1 px-3 py-1.5 rounded text-sm font-medium transition-colors ${
|
|
||||||
viewMode === 'sprint'
|
|
||||||
? 'bg-slate-700 text-white'
|
|
||||||
: 'text-slate-400 hover:text-white'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Flag className="w-4 h-4" />
|
|
||||||
Sprint
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setViewMode('backlog')}
|
onClick={() => setViewMode('backlog')}
|
||||||
className={`flex items-center gap-1 px-3 py-1.5 rounded text-sm font-medium transition-colors ${
|
className={`flex items-center gap-1 px-3 py-1.5 rounded text-sm font-medium transition-colors ${
|
||||||
@ -288,21 +296,34 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* View Content */}
|
{/* View Content */}
|
||||||
{viewMode === 'sprint' ? (
|
{viewMode === 'backlog' ? (
|
||||||
<SprintBoard />
|
|
||||||
) : viewMode === 'backlog' ? (
|
|
||||||
<BacklogView />
|
<BacklogView />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
{/* Current Sprint Header */}
|
||||||
|
<div className="mb-4 p-3 bg-slate-800/50 border border-slate-700 rounded-lg">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h3 className="font-medium text-white">Sprint 1</h3>
|
||||||
|
<p className="text-sm text-slate-400">Feb 16 - Feb 22, 2026</p>
|
||||||
|
</div>
|
||||||
|
<Badge variant="default">Active</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/* Kanban Columns */}
|
{/* Kanban Columns */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
{statusColumns.map((status) => {
|
{sprintColumns.map((column) => {
|
||||||
const columnTasks = projectTasks.filter((t) => t.status === status)
|
// For "Done" column, show both review and done tasks
|
||||||
|
const columnTasks = sprintTasks.filter((t) =>
|
||||||
|
column.key === 'review'
|
||||||
|
? (t.status === 'review' || t.status === 'done')
|
||||||
|
: t.status === column.key
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<div key={status} className="flex flex-col">
|
<div key={column.key} className="flex flex-col">
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
<h3 className="text-sm font-medium text-slate-400 capitalize">
|
<h3 className="text-sm font-medium text-slate-400">
|
||||||
{status.replace("-", " ")}
|
{column.label}
|
||||||
</h3>
|
</h3>
|
||||||
<Badge variant="secondary" className="bg-slate-800 text-slate-400">
|
<Badge variant="secondary" className="bg-slate-800 text-slate-400">
|
||||||
{columnTasks.length}
|
{columnTasks.length}
|
||||||
|
|||||||
@ -91,6 +91,23 @@ interface TaskStore {
|
|||||||
getTaskById: (id: string) => Task | undefined
|
getTaskById: (id: string) => Task | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sprint 1: Mon Feb 16 - Sun Feb 22, 2026 (current week)
|
||||||
|
const sprint1Start = new Date('2026-02-16T00:00:00.000Z')
|
||||||
|
const sprint1End = new Date('2026-02-22T23:59:59.999Z')
|
||||||
|
|
||||||
|
const defaultSprints: Sprint[] = [
|
||||||
|
{
|
||||||
|
id: 'sprint-1',
|
||||||
|
name: 'Sprint 1',
|
||||||
|
goal: 'Foundation and core features',
|
||||||
|
startDate: sprint1Start.toISOString(),
|
||||||
|
endDate: sprint1End.toISOString(),
|
||||||
|
status: 'active',
|
||||||
|
projectId: '2',
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const defaultProjects: Project[] = [
|
const defaultProjects: Project[] = [
|
||||||
{ id: '1', name: 'OpenClaw iOS', description: 'Main iOS app development', color: '#8b5cf6', createdAt: new Date().toISOString() },
|
{ id: '1', name: 'OpenClaw iOS', description: 'Main iOS app development', color: '#8b5cf6', createdAt: new Date().toISOString() },
|
||||||
{ id: '2', name: 'Web Projects', description: 'Web tools and dashboards', color: '#3b82f6', createdAt: new Date().toISOString() },
|
{ id: '2', name: 'Web Projects', description: 'Web tools and dashboards', color: '#3b82f6', createdAt: new Date().toISOString() },
|
||||||
@ -106,6 +123,7 @@ const defaultTasks: Task[] = [
|
|||||||
status: 'in-progress',
|
status: 'in-progress',
|
||||||
priority: 'high',
|
priority: 'high',
|
||||||
projectId: '2',
|
projectId: '2',
|
||||||
|
sprintId: 'sprint-1',
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
comments: [
|
comments: [
|
||||||
@ -122,6 +140,7 @@ const defaultTasks: Task[] = [
|
|||||||
status: 'backlog',
|
status: 'backlog',
|
||||||
priority: 'medium',
|
priority: 'medium',
|
||||||
projectId: '1',
|
projectId: '1',
|
||||||
|
sprintId: 'sprint-1',
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
comments: [],
|
comments: [],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user