Merge branch 'release/v2.0.4' of https://github.com/Worklenz/worklenz into test/row-kanban-board-v1
This commit is contained in:
@@ -1,78 +0,0 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Layout, Typography, Card, Space, Alert } from 'antd';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import TaskListBoard from '@/components/task-management/task-list-board';
|
||||
import { AppDispatch } from '@/app/store';
|
||||
|
||||
const { Header, Content } = Layout;
|
||||
const { Title, Paragraph } = Typography;
|
||||
|
||||
const TaskManagementDemo: React.FC = () => {
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
|
||||
// Mock project ID for demo
|
||||
const demoProjectId = 'demo-project-123';
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize demo data if needed
|
||||
// You might want to populate some sample tasks here for demonstration
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Layout className="min-h-screen bg-gray-50">
|
||||
<Header className="bg-white shadow-sm">
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<Title level={2} className="mb-0 text-gray-800">
|
||||
Enhanced Task Management System
|
||||
</Title>
|
||||
</div>
|
||||
</Header>
|
||||
|
||||
<Content className="max-w-7xl mx-auto px-4 py-6 w-full">
|
||||
<Space direction="vertical" size="large" className="w-full">
|
||||
{/* Introduction */}
|
||||
<Card>
|
||||
<Title level={3}>Task Management Features</Title>
|
||||
<Paragraph>
|
||||
This enhanced task management system provides a comprehensive interface for managing tasks
|
||||
with the following key features:
|
||||
</Paragraph>
|
||||
<ul className="list-disc list-inside space-y-1 text-gray-700">
|
||||
<li><strong>Dynamic Grouping:</strong> Group tasks by Status, Priority, or Phase</li>
|
||||
<li><strong>Drag & Drop:</strong> Reorder tasks within groups or move between groups</li>
|
||||
<li><strong>Multi-select:</strong> Select multiple tasks for bulk operations</li>
|
||||
<li><strong>Bulk Actions:</strong> Change status, priority, assignees, or delete multiple tasks</li>
|
||||
<li><strong>Subtasks:</strong> Expandable subtask support with progress tracking</li>
|
||||
<li><strong>Real-time Updates:</strong> Live updates via WebSocket connections</li>
|
||||
<li><strong>Rich Task Display:</strong> Progress bars, assignees, labels, due dates, and more</li>
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
{/* Usage Instructions */}
|
||||
<Alert
|
||||
message="Demo Instructions"
|
||||
description={
|
||||
<div>
|
||||
<p><strong>Grouping:</strong> Use the dropdown to switch between Status, Priority, and Phase grouping.</p>
|
||||
<p><strong>Drag & Drop:</strong> Click and drag tasks to reorder within groups or move between groups.</p>
|
||||
<p><strong>Selection:</strong> Click checkboxes to select tasks, then use bulk actions in the blue bar.</p>
|
||||
<p><strong>Subtasks:</strong> Click the +/- buttons next to task names to expand/collapse subtasks.</p>
|
||||
</div>
|
||||
}
|
||||
type="info"
|
||||
showIcon
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Task List Board */}
|
||||
<TaskListBoard
|
||||
projectId={demoProjectId}
|
||||
className="task-management-demo"
|
||||
/>
|
||||
</Space>
|
||||
</Content>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default TaskManagementDemo;
|
||||
@@ -1,36 +1,80 @@
|
||||
import { Input } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { Input, Button } from 'antd';
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { useAppSelector } from '../../../../../../hooks/useAppSelector';
|
||||
import { colors } from '../../../../../../styles/colors';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const AddSubTaskListRow = () => {
|
||||
const [isEdit, setIsEdit] = useState<boolean>(false);
|
||||
interface AddSubTaskListRowProps {
|
||||
visibleColumns: { key: string; label: string; width: number }[];
|
||||
taskColumnKey: string;
|
||||
onAdd: (name: string) => void;
|
||||
onCancel: () => void;
|
||||
parentTaskId: string;
|
||||
}
|
||||
|
||||
// localization
|
||||
const AddSubTaskListRow: React.FC<AddSubTaskListRowProps> = ({
|
||||
visibleColumns,
|
||||
taskColumnKey,
|
||||
onAdd,
|
||||
onCancel,
|
||||
}) => {
|
||||
const [subtaskName, setSubtaskName] = useState('');
|
||||
const inputRef = useRef<any>(null);
|
||||
const { t } = useTranslation('task-list-table');
|
||||
|
||||
// get data theme data from redux
|
||||
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
||||
const customBorderColor = themeMode === 'dark' && ' border-[#303030]';
|
||||
const customBorderColor = themeMode === 'dark' ? ' border-[#303030]' : '';
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter' && subtaskName.trim()) {
|
||||
onAdd(subtaskName.trim());
|
||||
setSubtaskName('');
|
||||
} else if (e.key === 'Escape') {
|
||||
onCancel();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`border-t ${customBorderColor}`}>
|
||||
{isEdit ? (
|
||||
<Input
|
||||
className="h-12 w-full rounded-none"
|
||||
style={{ borderColor: colors.skyBlue }}
|
||||
placeholder={t('addTaskInputPlaceholder')}
|
||||
onBlur={() => setIsEdit(false)}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
onFocus={() => setIsEdit(true)}
|
||||
className="w-[300px] border-none"
|
||||
value={t('addSubTaskText')}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<tr className={`add-subtask-row${customBorderColor}`}>
|
||||
{visibleColumns.map(col => (
|
||||
<td key={col.key} style={{ padding: 0, background: 'inherit' }}>
|
||||
{col.key === taskColumnKey ? (
|
||||
<div style={{ display: 'flex', alignItems: 'center', padding: '4px 0' }}>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
value={subtaskName}
|
||||
onChange={e => setSubtaskName(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onBlur={onCancel}
|
||||
placeholder={t('enterSubtaskName')}
|
||||
style={{ width: '100%' }}
|
||||
autoFocus
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
style={{ marginLeft: 8 }}
|
||||
disabled={!subtaskName.trim()}
|
||||
onClick={() => {
|
||||
if (subtaskName.trim()) {
|
||||
onAdd(subtaskName.trim());
|
||||
setSubtaskName('');
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('add')}
|
||||
</Button>
|
||||
<Button size="small" style={{ marginLeft: 4 }} onClick={onCancel}>
|
||||
{t('cancel')}
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1365,6 +1365,7 @@ const TaskListTable: React.FC<TaskListTableProps> = ({ taskList, tableId, active
|
||||
const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 });
|
||||
const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
|
||||
const [editColumnKey, setEditColumnKey] = useState<string | null>(null);
|
||||
const [showAddSubtaskFor, setShowAddSubtaskFor] = useState<string | null>(null);
|
||||
|
||||
const toggleTaskExpansion = (taskId: string) => {
|
||||
const task = displayTasks.find(t => t.id === taskId);
|
||||
@@ -1857,14 +1858,38 @@ const TaskListTable: React.FC<TaskListTableProps> = ({ taskList, tableId, active
|
||||
{renderTaskRow(updatedTask)}
|
||||
{updatedTask.show_sub_tasks && (
|
||||
<>
|
||||
{updatedTask?.sub_tasks?.map(subtask =>
|
||||
{updatedTask?.sub_tasks?.map(subtask =>
|
||||
subtask?.id ? renderTaskRow(subtask, true) : null
|
||||
)}
|
||||
<tr key={`add-subtask-${updatedTask.id}`}>
|
||||
<td colSpan={visibleColumns.length + 1}>
|
||||
<AddTaskListRow groupId={tableId} parentTask={updatedTask.id} />
|
||||
</td>
|
||||
</tr>
|
||||
{showAddSubtaskFor !== updatedTask.id && (
|
||||
<tr key={`add-subtask-link-${updatedTask.id}`}>
|
||||
<td colSpan={visibleColumns.length + 1}>
|
||||
<div
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
color: '#1677ff',
|
||||
cursor: 'pointer',
|
||||
fontWeight: 500,
|
||||
background: '#f6f8fa'
|
||||
}}
|
||||
onClick={() => setShowAddSubtaskFor(updatedTask.id)}
|
||||
>
|
||||
+ Add Sub Task
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{showAddSubtaskFor === updatedTask.id && (
|
||||
<tr key={`add-subtask-input-${updatedTask.id}`}>
|
||||
<td colSpan={visibleColumns.length + 1}>
|
||||
<AddTaskListRow
|
||||
groupId={tableId}
|
||||
parentTask={updatedTask.id}
|
||||
onCancel={() => setShowAddSubtaskFor(null)}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
||||
Reference in New Issue
Block a user