Add task search (vibe-kanban) (#48)
* Perfect! I've successfully added search functionality to the TaskKanbanBoard component. The implementation includes: 1. **Search input field** at the top of the kanban board 2. **Real-time filtering** that searches both task titles and descriptions 3. **Case-insensitive search** for better user experience 4. **Clean integration** with the existing kanban board structure The search functionality works by filtering tasks before they're grouped by status, so only matching tasks will appear on the board across all columns. * Perfect! I've successfully moved the search input to the header, positioning it to the left of the "Add Task" button. The improvements include: 1. **Better positioning**: Search input is now in the header alongside the "Add Task" button 2. **Improved layout**: The search input has a fixed width (w-64) and is properly spaced 3. **Clean integration**: The search functionality is maintained while improving the visual hierarchy 4. **Responsive design**: The search input is grouped with the "Add Task" button for better visual balance The search functionality remains the same - it filters tasks by title and description in real-time as you type. * Prettier
This commit is contained in:
committed by
GitHub
parent
26032c11cd
commit
d2e3cbd4f6
@@ -12,6 +12,7 @@ type Task = TaskWithAttemptStatus;
|
|||||||
|
|
||||||
interface TaskKanbanBoardProps {
|
interface TaskKanbanBoardProps {
|
||||||
tasks: Task[];
|
tasks: Task[];
|
||||||
|
searchQuery?: string;
|
||||||
onDragEnd: (event: DragEndEvent) => void;
|
onDragEnd: (event: DragEndEvent) => void;
|
||||||
onEditTask: (task: Task) => void;
|
onEditTask: (task: Task) => void;
|
||||||
onDeleteTask: (taskId: string) => void;
|
onDeleteTask: (taskId: string) => void;
|
||||||
@@ -44,11 +45,25 @@ const statusBoardColors: Record<TaskStatus, string> = {
|
|||||||
|
|
||||||
export function TaskKanbanBoard({
|
export function TaskKanbanBoard({
|
||||||
tasks,
|
tasks,
|
||||||
|
searchQuery = '',
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
onEditTask,
|
onEditTask,
|
||||||
onDeleteTask,
|
onDeleteTask,
|
||||||
onViewTaskDetails,
|
onViewTaskDetails,
|
||||||
}: TaskKanbanBoardProps) {
|
}: TaskKanbanBoardProps) {
|
||||||
|
const filterTasks = (tasks: Task[]) => {
|
||||||
|
if (!searchQuery.trim()) {
|
||||||
|
return tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = searchQuery.toLowerCase();
|
||||||
|
return tasks.filter(
|
||||||
|
(task) =>
|
||||||
|
task.title.toLowerCase().includes(query) ||
|
||||||
|
(task.description && task.description.toLowerCase().includes(query))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const groupTasksByStatus = () => {
|
const groupTasksByStatus = () => {
|
||||||
const groups: Record<TaskStatus, Task[]> = {} as Record<TaskStatus, Task[]>;
|
const groups: Record<TaskStatus, Task[]> = {} as Record<TaskStatus, Task[]>;
|
||||||
|
|
||||||
@@ -57,7 +72,9 @@ export function TaskKanbanBoard({
|
|||||||
groups[status] = [];
|
groups[status] = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
const filteredTasks = filterTasks(tasks);
|
||||||
|
|
||||||
|
filteredTasks.forEach((task) => {
|
||||||
// Convert old capitalized status to lowercase if needed
|
// Convert old capitalized status to lowercase if needed
|
||||||
const normalizedStatus = task.status.toLowerCase() as TaskStatus;
|
const normalizedStatus = task.status.toLowerCase() as TaskStatus;
|
||||||
if (groups[normalizedStatus]) {
|
if (groups[normalizedStatus]) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
|
|||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
import { Plus, Settings, FolderOpen } from 'lucide-react';
|
import { Plus, Settings, FolderOpen } from 'lucide-react';
|
||||||
import { makeRequest } from '@/lib/api';
|
import { makeRequest } from '@/lib/api';
|
||||||
import { TaskFormDialog } from '@/components/tasks/TaskFormDialog';
|
import { TaskFormDialog } from '@/components/tasks/TaskFormDialog';
|
||||||
@@ -44,6 +45,7 @@ export function ProjectTasks() {
|
|||||||
const [isTaskDialogOpen, setIsTaskDialogOpen] = useState(false);
|
const [isTaskDialogOpen, setIsTaskDialogOpen] = useState(false);
|
||||||
const [editingTask, setEditingTask] = useState<Task | null>(null);
|
const [editingTask, setEditingTask] = useState<Task | null>(null);
|
||||||
const [isProjectSettingsOpen, setIsProjectSettingsOpen] = useState(false);
|
const [isProjectSettingsOpen, setIsProjectSettingsOpen] = useState(false);
|
||||||
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
|
||||||
// Panel state
|
// Panel state
|
||||||
const [selectedTask, setSelectedTask] = useState<Task | null>(null);
|
const [selectedTask, setSelectedTask] = useState<Task | null>(null);
|
||||||
@@ -402,10 +404,19 @@ export function ProjectTasks() {
|
|||||||
<Settings className="h-4 w-4" />
|
<Settings className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={handleCreateNewTask}>
|
<div className="flex items-center gap-3">
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Input
|
||||||
Add Task
|
type="text"
|
||||||
</Button>
|
placeholder="Search tasks..."
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
className="w-64"
|
||||||
|
/>
|
||||||
|
<Button onClick={handleCreateNewTask}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
Add Task
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tasks View */}
|
{/* Tasks View */}
|
||||||
@@ -428,6 +439,7 @@ export function ProjectTasks() {
|
|||||||
<div className="min-w-[900px] max-w-[2000px] relative py-1">
|
<div className="min-w-[900px] max-w-[2000px] relative py-1">
|
||||||
<TaskKanbanBoard
|
<TaskKanbanBoard
|
||||||
tasks={tasks}
|
tasks={tasks}
|
||||||
|
searchQuery={searchQuery}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onEditTask={handleEditTask}
|
onEditTask={handleEditTask}
|
||||||
onDeleteTask={handleDeleteTask}
|
onDeleteTask={handleDeleteTask}
|
||||||
|
|||||||
Reference in New Issue
Block a user