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:
OpenClaw Bot 2026-02-19 18:39:32 -06:00
parent 0761adedbe
commit e734c6fab5
3 changed files with 76 additions and 26 deletions

View File

@ -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"
} }
] ]
} }

View File

@ -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}

View File

@ -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: [],