diff --git a/README.md b/README.md index 9373a31..c72df22 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ npm start | :----------------- | :---------------------------------------------------------- | :-------------------------------------------------------------------------------------- | | onSelect | (task: Task, isSelected: boolean) => void | Specifies the function to be executed on the taskbar select or unselect event. | | onDoubleClick | (task: Task) => void | Specifies the function to be executed on the taskbar onDoubleClick event. | -| onTaskDelete\* | (task: Task) => void/boolean/Promise/Promise | Specifies the function to be executed on the taskbar on Delete button press event. | +| onDelete\* | (task: Task) => void/boolean/Promise/Promise | Specifies the function to be executed on the taskbar on Delete button press event. | | onDateChange\* | (task: Task) => void/boolean/Promise/Promise | Specifies the function to be executed when drag taskbar event on timeline has finished. | | onProgressChange\* | (task: Task) => void/boolean/Promise/Promise | Specifies the function to be executed when drag taskbar progress event has finished. | | timeStep | (task: Task) => number | A time step value for onDateChange. Specify in milliseconds. | @@ -131,6 +131,7 @@ npm start | | | - **progressSelectedColor**: String. Specifies the taskbar progress fill color globally on select. | | isDisabled | bool | Disables all action for current task. | | fontSize | string | Specifies the taskbar font size locally. | +| project | string | Task project name | \*Required diff --git a/example/src/App.tsx b/example/src/App.tsx index 5fc513d..ab9d131 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Task, ViewMode, Gantt } from "gantt-task-react"; import { ViewSwitcher } from "./components/view-switcher"; -import { initTasks } from "./helper"; +import { getStartEndDateForProject, initTasks } from "./helper"; import "gantt-task-react/dist/index.css"; //Init @@ -18,7 +18,20 @@ const App = () => { const onTaskChange = (task: Task) => { console.log("On date change Id:" + task.id); - const newTasks = tasks.map(t => (t.id === task.id ? task : t)); + let newTasks = tasks.map(t => (t.id === task.id ? task : t)); + if (task.project) { + const [start, end] = getStartEndDateForProject(newTasks, task.project); + const project = newTasks[newTasks.findIndex(t => t.id === task.project)]; + if ( + project.start.getTime() !== start.getTime() || + project.end.getTime() !== end.getTime() + ) { + const changedProject = { ...project, start, end }; + newTasks = newTasks.map(t => + t.id === task.project ? changedProject : t + ); + } + } setTasks(newTasks); }; @@ -55,20 +68,22 @@ const App = () => { tasks={tasks} viewMode={view} onDateChange={onTaskChange} - onTaskDelete={onTaskDelete} + onDelete={onTaskDelete} onProgressChange={onProgressChange} onDoubleClick={onDblClick} onSelect={onSelect} listCellWidth={isChecked ? "155px" : ""} columnWidth={columnWidth} /> -

Milestones are not available

+

+ Milestones and projects are not available +

Gantt With Limited Height

t.project === projectId); + let start = projectTasks[0].start; + let end = projectTasks[0].end; + + for (let i = 0; i < projectTasks.length; i++) { + const task = projectTasks[i]; + if (start.getTime() > task.start.getTime()) { + start = task.start; + } + if (end.getTime() < task.end.getTime()) { + end = task.end; + } + } + return [start, end]; +} diff --git a/package.json b/package.json index e79a733..556a796 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gantt-task-react", - "version": "0.2.2", + "version": "0.3.0", "description": "Interactive Gantt Chart for React with TypeScript.", "author": "MaTeMaTuK ", "homepage": "https://github.com/MaTeMaTuK/gantt-task-react", diff --git a/src/components/gantt/gantt.tsx b/src/components/gantt/gantt.tsx index 554d134..373aa22 100644 --- a/src/components/gantt/gantt.tsx +++ b/src/components/gantt/gantt.tsx @@ -46,7 +46,7 @@ export const Gantt: React.FunctionComponent = ({ onDateChange, onProgressChange, onDoubleClick, - onTaskDelete, + onDelete, onSelect, }) => { const wrapperRef = useRef(null); @@ -300,7 +300,7 @@ export const Gantt: React.FunctionComponent = ({ onDateChange, onProgressChange, onDoubleClick, - onTaskDelete, + onDelete, TooltipContent, }; diff --git a/src/components/gantt/task-gantt-content.tsx b/src/components/gantt/task-gantt-content.tsx index 35d5245..f0b2ca2 100644 --- a/src/components/gantt/task-gantt-content.tsx +++ b/src/components/gantt/task-gantt-content.tsx @@ -61,7 +61,7 @@ export const TaskGanttContent: React.FC = ({ onDateChange, onProgressChange, onDoubleClick, - onTaskDelete, + onDelete, TooltipContent, }) => { const point = svg?.current?.createSVGPoint(); @@ -204,9 +204,9 @@ export const TaskGanttContent: React.FC = ({ // Keyboard events else if (isKeyboardEvent(event)) { if (action === "delete") { - if (onTaskDelete) { + if (onDelete) { try { - const result = await onTaskDelete(task); + const result = await onDelete(task); if (result !== undefined && result) { setGanttEvent({ action, changedTask: task }); } diff --git a/src/components/task-item/project/project.module.css b/src/components/task-item/project/project.module.css new file mode 100644 index 0000000..c277961 --- /dev/null +++ b/src/components/task-item/project/project.module.css @@ -0,0 +1,13 @@ +.projectWrapper { + cursor: pointer; + outline: none; +} + +.projectBackground { + user-select: none; + opacity: 0.5; +} + +.projectTop { + user-select: none; +} diff --git a/src/components/task-item/project/project.tsx b/src/components/task-item/project/project.tsx new file mode 100644 index 0000000..21bddb3 --- /dev/null +++ b/src/components/task-item/project/project.tsx @@ -0,0 +1,76 @@ +import React from "react"; +import { progressWithByParams } from "../../../helpers/bar-helper"; +import { TaskItemProps } from "../task-item"; +import styles from "./project.module.css"; + +export const Project: React.FC = ({ task, isSelected }) => { + const barColor = isSelected + ? task.styles.backgroundSelectedColor + : task.styles.backgroundColor; + const processColor = isSelected + ? task.styles.progressSelectedColor + : task.styles.progressColor; + const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); + const projectWith = task.x2 - task.x1; + + const projectLeftTriangle = [ + task.x1, + task.y + task.height / 2 - 1, + task.x1, + task.y + task.height, + task.x1 + 15, + task.y + task.height / 2 - 1, + ].join(","); + const projectRightTriangle = [ + task.x2, + task.y + task.height / 2 - 1, + task.x2, + task.y + task.height, + task.x2 - 15, + task.y + task.height / 2 - 1, + ].join(","); + + return ( + + + + + + + + ); +}; diff --git a/src/components/task-item/task-item.tsx b/src/components/task-item/task-item.tsx index 8d92fdf..50d5f89 100644 --- a/src/components/task-item/task-item.tsx +++ b/src/components/task-item/task-item.tsx @@ -3,6 +3,7 @@ import { BarTask } from "../../types/bar-task"; import { GanttContentMoveAction } from "../../types/gantt-task-actions"; import { Bar } from "./bar/bar"; import { Milestone } from "./milestone/milestone"; +import { Project } from "./project/project"; import style from "./task-list.module.css"; export type TaskItemProps = { @@ -40,6 +41,9 @@ export const TaskItem: React.FC = props => { case "milestone": setTaskItem(); break; + case "project": + setTaskItem(); + break; default: setTaskItem(); break; diff --git a/src/types/public-types.ts b/src/types/public-types.ts index 6971f4b..b50d432 100644 --- a/src/types/public-types.ts +++ b/src/types/public-types.ts @@ -6,7 +6,7 @@ export enum ViewMode { Week = "Week", Month = "Month", } -export type TaskType = "task" | "milestone"; +export type TaskType = "task" | "milestone" | "project"; export interface Task { id: string; type: TaskType; @@ -24,6 +24,7 @@ export interface Task { progressSelectedColor?: string; }; isDisabled?: boolean; + project?: string; dependencies?: string[]; } @@ -55,9 +56,7 @@ export interface EventOption { /** * Invokes on delete selected task. Chart undoes operation if method return false or error. */ - onTaskDelete?: ( - task: Task - ) => void | boolean | Promise | Promise; + onDelete?: (task: Task) => void | boolean | Promise | Promise; } export interface DisplayOption {