@wamra/gantt-task-react
Version:
Interactive Gantt Chart for React with TypeScript
846 lines (845 loc) • 25.2 kB
TypeScript
import type { ComponentType, MouseEvent, ReactNode } from "react";
import type { Locale as DateLocale } from "date-fns";
import { OptimizedListParams } from "../helpers/use-optimized-list";
import { TaskListHeaderActionsProps } from "../components/task-list/TaskListHeaderActions";
export declare enum ViewMode {
Hour = "Hour",
QuarterDay = "Quarter Day",
HalfDay = "Half Day",
Day = "Day",
TwoDays = "Two Days",
/** ISO-8601 week */
Week = "Week",
Month = "Month",
QuarterYear = "QuarterYear",
Year = "Year"
}
export interface DateSetup {
dateFormats: DateFormats;
dateLocale: DateLocale;
isUnknownDates: boolean;
preStepsCount: number;
viewMode: ViewMode;
}
export type RenderTopHeader = (date: Date, viewMode: ViewMode, dateSetup: DateSetup) => ReactNode;
export type RenderBottomHeader = (date: Date, viewMode: ViewMode, dateSetup: DateSetup, index: number, isUnknownDates: boolean) => ReactNode;
export interface Dependency {
sourceId: string;
sourceTarget: DateExtremity;
ownTarget: DateExtremity;
}
export interface ExpandedDependency {
containerHeight: number;
containerY: number;
innerFromY: number;
innerToY: number;
marginBetweenTasks: number | null;
ownTarget: DateExtremity;
source: Task;
sourceTarget: DateExtremity;
}
export interface ExpandedDependent {
containerHeight: number;
containerY: number;
innerFromY: number;
innerToY: number;
marginBetweenTasks: number | null;
dependent: Task;
dependentTarget: DateExtremity;
ownTarget: DateExtremity;
}
export interface ColorStyles {
arrowColor: string;
arrowCriticalColor: string;
arrowWarningColor: string;
barLabelColor: string;
barLabelWhenOutsideColor: string;
barProgressColor: string;
barProgressCriticalColor: string;
barProgressSelectedColor: string;
barProgressSelectedCriticalColor: string;
barBackgroundColor: string;
barBackgroundCriticalColor: string;
barBackgroundSelectedColor: string;
barBackgroundSelectedCriticalColor: string;
groupProgressColor: string;
groupProgressCriticalColor: string;
groupProgressSelectedColor: string;
groupProgressSelectedCriticalColor: string;
groupBackgroundColor: string;
groupBackgroundCriticalColor: string;
groupBackgroundSelectedColor: string;
groupBackgroundSelectedCriticalColor: string;
projectProgressColor: string;
projectProgressCriticalColor: string;
projectProgressSelectedColor: string;
projectProgressSelectedCriticalColor: string;
projectBackgroundColor: string;
projectBackgroundCriticalColor: string;
projectBackgroundSelectedColor: string;
projectBackgroundSelectedCriticalColor: string;
milestoneBackgroundColor: string;
milestoneBackgroundCriticalColor: string;
milestoneBackgroundSelectedColor: string;
milestoneBackgroundSelectedCriticalColor: string;
evenTaskBackgroundColor: string;
oddTaskBackgroundColor: string;
holidayBackgroundColor: string;
taskDragColor: string;
selectedTaskBackgroundColor: string;
todayColor: string;
contextMenuBoxShadow: string;
contextMenuBgColor: string;
contextMenuTextColor: string;
}
/**
* date-fns formats
*/
export interface DateFormats {
dateColumnFormat: string;
dayBottomHeaderFormat: string;
dayTopHeaderFormat: string;
hourBottomHeaderFormat: string;
monthBottomHeaderFormat: string;
monthTopHeaderFormat: string;
}
export interface Distances {
actionColumnWidth: number;
arrowIndent: number;
barCornerRadius: number;
/**
* How many of row width can be taken by task.
* From 0 to 100
*/
barFill: number;
columnWidth: number;
contextMenuIconWidth: number;
contextMenuOptionHeight: number;
contextMenuSidePadding: number;
dateCellWidth: number;
dependenciesCellWidth: number;
dependencyFixHeight: number;
dependencyFixIndent: number;
dependencyFixWidth: number;
expandIconWidth: number;
handleWidth: number;
headerHeight: number;
minimumRowDisplayed: number;
nestedTaskNameOffset: number;
relationCircleOffset: number;
relationCircleRadius: number;
rowHeight: number;
tableWidth?: number;
taskWarningOffset: number;
titleCellWidth: number;
}
export type TaskType = "task" | "milestone" | "project";
export interface Task {
id: string;
type: TaskType;
name: string;
start: Date;
end: Date;
/**
* From 0 to 100
*/
progress: number;
assignees?: string[];
styles?: Partial<ColorStyles>;
isDisabled?: boolean;
isRelationDisabled?: boolean;
/**
* Project or task
*/
parent?: string;
dependencies?: Dependency[];
hideChildren?: boolean;
displayOrder?: number;
comparisonLevel?: number;
}
export interface EmptyTask {
id: string;
type: "empty";
name: string;
parent?: string;
comparisonLevel?: number;
displayOrder?: number;
isDisabled?: boolean;
styles?: Partial<ColorStyles>;
}
export type TaskOrEmpty = Task | EmptyTask;
export type OnArrowDoubleClick = (taskFrom: Task, taskFromIndex: number, taskTo: Task, taskToIndex: number) => void;
export type OnRelationChange = (
/**
* Task, target, index
*/
from: [Task, DateExtremity, number],
/**
* Task, target, index
*/
to: [Task, DateExtremity, number],
/**
* One of tasks is descendant of other task
*/
isOneDescendant: boolean) => void;
export type OnDateChangeSuggestionType = [
/**
* Start date
*/
Date,
/**
* End date
*/
Date,
/**
* Suggested task
*/
Task,
/**
* Index in array of tasks
*/
number
];
export type OnDateChange = (task: TaskOrEmpty, dependentTasks: readonly Task[], index: number, parents: readonly Task[], suggestions: readonly OnDateChangeSuggestionType[]) => void;
export type OnProgressChange = (task: Task, children: readonly Task[], index: number) => void;
export type OnEditTask = (task: TaskOrEmpty, index: number, getMetadata: GetMetadata) => void;
export type OnMoveTaskBeforeAfter = (task: TaskOrEmpty, taskForMove: TaskOrEmpty, dependentTasks: readonly Task[], taskIndex: number, taskForMoveIndex: number, parents: readonly Task[], suggestions: readonly OnDateChangeSuggestionType[]) => void;
export type OnMoveTaskInside = (parent: Task, childs: readonly TaskOrEmpty[], dependentTasks: readonly Task[], parentIndex: number, childIndexes: readonly number[], parents: readonly Task[], suggestions: readonly OnDateChangeSuggestionType[]) => void;
export type OnAddTask = (parentTask: Task, getMetadata: GetMetadata) => void;
export type FixPosition = (task: Task, date: Date,
/**
* index in the array of tasks
*/
index: number) => void;
export type OnChangeTasksAction = {
type: "add_tasks";
} | {
type: "date_change";
} | {
type: "delete_relation";
payload: {
taskFrom: Task;
taskFromIndex: number;
taskTo: Task;
taskToIndex: number;
};
} | {
type: "delete_task";
payload: {
tasks: readonly TaskOrEmpty[];
taskIndexes: readonly number[];
};
} | {
type: "edit_task";
} | {
type: "fix_dependency_position";
} | {
type: "fix_end_position";
} | {
type: "fix_start_position";
} | {
type: "move_task_before";
} | {
type: "move_task_after";
} | {
type: "move_task_inside";
} | {
type: "progress_change";
} | {
type: "relation_change";
} | {
type: "expandState_change";
payload: {
changedTask: Task;
};
};
export type RelationKind = "startToStart" | "startToEnd" | "endToStart" | "endToEnd";
export type OnChangeTasks = (nextTasks: readonly TaskOrEmpty[], action: OnChangeTasksAction) => void;
export interface EventOption {
/**
* Time step value for date changes.
*/
timeStep?: number;
/**
* Invokes on bar double click.
*/
onDoubleClick?: (task: Task) => void;
/**
* Invokes on bar click.
*/
onClick?: (task: TaskOrEmpty) => void;
/**
* Recount descedents of a group task when moving
*/
isMoveChildsWithParent?: boolean;
/**
* Recount parents of tasks in callback `onChangeTasks`
*/
isUpdateDisabledParentsOnChange?: boolean;
/**
* Invokes when the task expand status changed(task.hideChildren)
*/
onChangeExpandState?: (changedTask: Task) => void;
/**
* Invokes on every change of the list of tasks
*/
onChangeTasks?: OnChangeTasks;
/**
* Invokes on end and start time change. Chart undoes operation if method return false or error.
*/
onDateChange?: OnDateChange;
authorizedRelations?: RelationKind[];
/**
* Invokes on click on fix element next to relation arrow
*/
onFixDependencyPosition?: OnDateChange;
/**
* Invokes new relation between tasks
*/
onRelationChange?: OnRelationChange;
/**
* Invokes on progress change
*/
onProgressChange?: OnProgressChange;
/**
* Callback for getting data of the added task
*/
onAddTask?: (task: Task) => Promise<TaskOrEmpty | null>;
/**
* Invokes on edit button click
*/
onAddTaskClick?: OnAddTask;
/**
* Invokes on delete selected task
*/
onDelete?: (tasks: readonly TaskOrEmpty[], dependentTasks: readonly Task[], indexes: Array<{
task: TaskOrEmpty;
index: number;
}>, parents: readonly Task[], suggestions: readonly OnDateChangeSuggestionType[]) => void;
/**
* Callback for getting new data of the edited task
*/
onEditTask?: (task: TaskOrEmpty) => Promise<TaskOrEmpty | null>;
/**
* Invokes on edit button click
*/
onEditTaskClick?: OnEditTask;
/**
* Invokes on move task after other task
*/
onMoveTaskBefore?: OnMoveTaskBeforeAfter;
/**
* Invokes on move task after other task
*/
onMoveTaskAfter?: OnMoveTaskBeforeAfter;
/**
* Invokes on move task inside other task
*/
onMoveTaskInside?: OnMoveTaskInside;
/**
* Invokes on double click on the relation arrow between tasks
*/
onArrowDoubleClick?: OnArrowDoubleClick;
/**
* Invokes on click on fix element on the start of task
*/
fixStartPosition?: FixPosition;
/**
* Invokes on click on fix element on the end of task
*/
fixEndPosition?: FixPosition;
onWheel?: (wheelEvent: WheelEvent) => void;
}
export interface DisplayOption {
viewMode?: ViewMode;
isDeleteDependencyOnDoubleClick?: boolean;
/**
* Display offsets from start on timeline instead of dates
*/
isUnknownDates?: boolean;
/**
* Locale of date-fns
*/
dateLocale?: DateLocale;
viewDate?: Date;
preStepsCount?: number;
rtl?: boolean;
/**
* Show an warning icon next to task
* if some childs aren't within the time interval of the task
* and show elements to fix these warnings
*/
isShowChildOutOfParentWarnings?: boolean;
/**
* Show an warning icon next to task
* if some dependencies are conflicting
* and show elements to fix these warnings
*/
isShowDependencyWarnings?: boolean;
/**
* Show critical path
*/
isShowCriticalPath?: boolean;
/**
* Show numbers of tasks next to tasks
*/
isShowTaskNumbers?: boolean;
}
export interface Icons {
renderAddIcon: (task: TaskOrEmpty) => ReactNode;
renderClosedIcon: (task: TaskOrEmpty) => ReactNode;
renderDeleteIcon: (task: TaskOrEmpty) => ReactNode;
renderEditIcon: (task: TaskOrEmpty) => ReactNode;
renderOpenedIcon: (task: TaskOrEmpty) => ReactNode;
renderNoChildrenIcon: (task: TaskOrEmpty) => ReactNode;
}
export type BarMoveAction = "progress" | "end" | "start" | "move";
export interface StylingOption {
/**
* Allow drag-n-drop of tasks in the table
*/
canMoveTasks?: boolean;
canResizeColumns?: boolean;
colors?: Partial<ColorStyles>;
dateFormats?: Partial<DateFormats>;
distances?: Partial<Distances>;
icons?: Partial<Icons>;
columns?: readonly Column[];
onResizeColumn?: OnResizeColumn;
fontFamily?: string;
fontSize?: string;
TooltipContent?: ComponentType<{
task: Task;
fontSize: string;
fontFamily: string;
}>;
TaskListHeader?: ComponentType<TaskListHeaderProps>;
TaskListTable?: ComponentType<TaskListTableProps>;
/**
* Render function of bottom part of header above chart
*/
renderBottomHeader?: RenderBottomHeader;
/**
* Render function of top part of header above chart
*/
renderTopHeader?: RenderTopHeader;
/**
* Check is current date is a holiday
* @param date the date
* @param minTaskDate lower date of all tasks
* @param dateSetup
* @param dateExtremity start or end date
*/
checkIsHoliday?: (date: Date, minTaskDate: Date, dateSetup: DateSetup, dateExtremity: DateExtremity) => boolean;
/**
* Round the date of task after move or resize
* @param date Date after move
* @param viewMode current date unit
* @param dateExtremity start or end date
* @param action current user action
* @returns rounded date
*/
roundDate?: (date: Date, viewMode: ViewMode, dateExtremity: DateExtremity, action: BarMoveAction) => Date;
dateMoveStep?: GanttDateRounding;
ContextualPalette?: React.FC<TaskContextualPaletteProps>;
TaskDependencyContextualPalette?: React.FC<TaskDependencyContextualPaletteProps>;
}
export interface GanttDateRounding {
value: number;
timeUnit: GanttDateRoundingTimeUnit;
}
export declare enum GanttDateRoundingTimeUnit {
MINUTE = 0,
HOUR = 1,
DAY = 2
}
export interface TaskContextualPaletteProps {
selectedTask: Task;
onClosePalette: () => void;
}
export interface TaskDependencyContextualPaletteProps {
taskFrom: Task;
extremityFrom: DateExtremity;
taskTo: Task;
extremityTo: DateExtremity;
onClosePalette: () => void;
}
export type DateExtremity = "startOfTask" | "endOfTask";
export interface GanttProps extends EventOption, DisplayOption, StylingOption {
/**
* Can be used to compare multiple graphs. This prop is the number of graps being compared
*/
comparisonLevels?: number;
contextMenuOptions?: ContextMenuOptionType[];
enableTableListContextMenu?: number;
/**
* Get new id for task after using copy-paste
*/
getCopiedTaskId?: GetCopiedTaskId;
/**
* Move dates of tasks to working days during change
*/
isAdjustToWorkingDates?: boolean;
tasks: readonly TaskOrEmpty[];
}
export interface TaskListTableProps {
canMoveTasks: boolean;
childTasksMap: ChildByLevelMap;
colors: ColorStyles;
columns: readonly Column[];
cutIdsMirror: Readonly<Record<string, true>>;
dateSetup: DateSetup;
dependencyMap: DependencyMap;
distances: Distances;
fontFamily: string;
fontSize: string;
fullRowHeight: number;
ganttFullHeight: number;
getTaskCurrentState: (task: Task) => Task;
handleAddTask: (task: Task) => void;
handleDeleteTasks: (task: TaskOrEmpty[]) => void;
handleEditTask: (task: TaskOrEmpty) => void;
handleMoveTaskBefore: (target: TaskOrEmpty, taskForMove: TaskOrEmpty) => void;
handleMoveTaskAfter: (target: TaskOrEmpty, taskForMove: TaskOrEmpty) => void;
handleMoveTasksInside: (parent: Task, childs: readonly TaskOrEmpty[]) => void;
handleOpenContextMenu: (task: TaskOrEmpty, clientX: number, clientY: number) => void;
icons?: Partial<Icons>;
isShowTaskNumbers: boolean;
mapTaskToNestedIndex: MapTaskToNestedIndex;
onClick: (task: TaskOrEmpty) => void;
onExpanderClick: (task: Task) => void;
renderedIndexes: OptimizedListParams | null;
scrollToTask: (task: Task) => void;
selectTaskOnMouseDown: (taskId: string, event: MouseEvent) => void;
selectedIdsMirror: Readonly<Record<string, true>>;
taskListWidth: number;
tasks: readonly TaskOrEmpty[];
}
export interface TaskListHeaderProps extends TaskListHeaderActionsProps {
headerHeight: number;
columns: readonly Column[];
fontFamily: string;
fontSize: string;
canResizeColumns: boolean;
onColumnResizeStart: (columnIndex: number, clientX: number) => void;
colors: ColorStyles;
}
export type TaskToGlobalIndexMap = Map<number, Map<string, number>>;
export type TaskToRowIndexMap = Map<number, Map<string, number>>;
export type RowIndexToTaskMap = Map<number, Map<number, TaskOrEmpty>>;
export type GlobalRowIndexToTaskMap = Map<number, TaskOrEmpty>;
export type ChildByLevelMap = Map<number, Map<string, TaskOrEmpty[]>>;
export type RootMapByLevel = Map<number, TaskOrEmpty[]>;
export type TaskMapByLevel = Map<number, Map<string, TaskOrEmpty>>;
export type MapTaskToNestedIndex = Map<number, Map<string, [number, string]>>;
export interface TaskOutOfParentWarning {
isOutside: boolean;
date: Date;
}
export interface TaskOutOfParentWarnings {
start?: TaskOutOfParentWarning;
end?: TaskOutOfParentWarning;
}
/**
* comparison level -> task id -> {
* start: {
* isOutsie: false,
* date: Date,
* },
*
* end: {
* isOutsie: false,
* date: Date,
* },
* }
*/
export type ChildOutOfParentWarnings = Map<number, Map<string, TaskOutOfParentWarnings>>;
export type DependencyMap = Map<number, Map<string, ExpandedDependency[]>>;
export type DependentMap = Map<number, Map<string, ExpandedDependent[]>>;
export type DependencyMargins = Map<number, Map<string, Map<string, number>>>;
export type TaskToHasDependencyWarningMap = Map<number, Set<string>>;
export type CriticalPath = {
tasks: Set<string>;
dependencies: Map<string, Set<string>>;
};
export type CriticalPaths = Map<number, CriticalPath>;
export type TaskCoordinates = {
/**
* Width of inner svg wrapper
*/
containerWidth: number;
/**
* Left border of inner svg wrapper relative to the root svg
*/
containerX: number;
/**
* Left border relative to the wrapper svg
*/
innerX1: number;
/**
* Right border relative to the wrapper svg
*/
innerX2: number;
/**
* Top border of inner svg wrapper relative to the root svg
*/
levelY: number;
/**
* Width of the progress bar
*/
progressWidth: number;
/**
* Left border of the progress bar relative to the root svg
*/
progressX: number;
/**
* Width of the task
*/
width: number;
/**
* Left border of the task relative to the root svg
*/
x1: number;
/**
* Right border of the task relative to the root svg
*/
x2: number;
/**
* Top border of the task relative to the root svg
*/
y: number;
};
/**
* comparison level -> task id -> {
* x1: number;
* x2: number;
* y: number;
* }
*/
export type MapTaskToCoordinates = Map<number, Map<string, TaskCoordinates>>;
export type ChangeInProgress = {
action: BarMoveAction;
additionalLeftSpace: number;
additionalRightSpace: number;
changedTask: Task;
coordinates: TaskCoordinates;
coordinatesDiff: number;
initialCoordinates: TaskCoordinates;
lastClientX: number;
startX: number;
originalTask: Task;
taskRootNode: Element;
tsDiff: number;
};
export type GetMetadata = (task: TaskOrEmpty) => ChangeMetadata;
export type ColumnData = {
canMoveTasks: boolean;
dateSetup: DateSetup;
depth: number;
dependencies: Task[];
distances: Distances;
handleAddTask: (task: Task) => void;
handleDeleteTasks: (task: TaskOrEmpty[]) => void;
handleEditTask: (task: TaskOrEmpty) => void;
hasChildren: boolean;
icons?: Partial<Icons>;
indexStr: string;
isClosed: boolean;
isShowTaskNumbers: boolean;
onExpanderClick: (task: Task) => void;
task: TaskOrEmpty;
colors: Partial<ColorStyles>;
};
export type ColumnProps = {
data: ColumnData;
};
export type Column = {
id: string;
Cell: ComponentType<ColumnProps>;
width: number;
title?: ReactNode;
canResize?: boolean;
};
export type OnResizeColumn = (nextColumns: readonly Column[], columnIndex: number, deltaWidth: number) => void;
export type ChangeAction = {
type: "add-childs";
parent: Task;
addedIdsMap: Map<number, Set<string>>;
addedChildsByLevelMap: ChildByLevelMap;
addedRootsByLevelMap: RootMapByLevel;
descendants: readonly TaskOrEmpty[];
} | {
type: "change";
task: TaskOrEmpty;
} | {
type: "change_start_and_end";
task: Task;
changedTask: Task;
originalTask: Task;
} | {
type: "delete";
tasks: readonly TaskOrEmpty[];
deletedIdsMap: Map<number, Set<string>>;
} | {
type: "move-before";
target: TaskOrEmpty;
taskForMove: TaskOrEmpty;
} | {
type: "move-after";
target: TaskOrEmpty;
taskForMove: TaskOrEmpty;
} | {
type: "move-inside";
parent: Task;
childs: readonly TaskOrEmpty[];
movedIdsMap: Map<number, Set<string>>;
};
export type ChangeMetadata = [
/**
* dependent tasks
*/
Task[],
/**
* indexes in list of tasks
*/
Array<{
task: TaskOrEmpty;
index: number;
}>,
/**
* array of parents of the task
*/
Task[],
/**
* array of suggesgions for change parent
*/
OnDateChangeSuggestionType[]
];
export type ContextMenuType = {
task: TaskOrEmpty | null;
x: number;
y: number;
};
export type ActionMetaType = {
/**
* Check is task id exists at current level (1 by default)
*/
checkTaskIdExists: CheckTaskIdExistsAtLevel;
/**
* Copy all selected tasks
*/
copySelectedTasks: () => void;
/**
* Copy single task
* @param task the task
*/
copyTask: (task: TaskOrEmpty) => void;
/**
* Cut all selected tasks
*/
cutSelectedTasks: () => void;
/**
* Cut single task
* @param task the task
*/
cutTask: (task: TaskOrEmpty) => void;
/**
* @returns List of parent tasks under copy action
*/
getCopyParentTasks: () => readonly TaskOrEmpty[];
/**
* @returns List of tasks under copy action
*/
getCopyTasks: () => readonly TaskOrEmpty[];
/**
* @returns List of tasks with all their descendants under copy action
*/
getCopyTasksWithDescendants: () => readonly TaskOrEmpty[];
/**
* @returns List of parent tasks under cut action
*/
getCutParentTasks: () => readonly TaskOrEmpty[];
/**
* @returns List of tasks under cut action
*/
getCutTasks: () => readonly TaskOrEmpty[];
/**
* @returns List of parent tasks
*/
getParentTasks: () => readonly TaskOrEmpty[];
/**
* @returns List of selected tasks
*/
getSelectedTasks: () => readonly TaskOrEmpty[];
/**
* @returns List of tasks with all their descendants
*/
getTasksWithDescendants: () => readonly TaskOrEmpty[];
/**
* Add childs to the container task
* @param parent the container task
* @param descendants list of added childs with their descendants
*/
handleAddChilds: (parent: Task, descendants: readonly TaskOrEmpty[]) => void;
/**
* Delete tasks
* @param tasksForDelete list of tasks for delete
*/
handleDeleteTasks: (tasksForDelete: readonly TaskOrEmpty[]) => void;
/**
* Move tasks to the container task
* @param parent the container task
* @param childs list of moved tasks
*/
handleMoveTasksInside: (parent: Task, childs: readonly TaskOrEmpty[]) => void;
/**
* Make copies of the list of tasks
*/
makeCopies: (tasks: readonly TaskOrEmpty[]) => readonly TaskOrEmpty[];
/**
* Reset selection
*/
resetSelectedTasks: () => void;
/**
* Task that triggered context menu
*/
task: TaskOrEmpty;
};
export type CheckIsAvailableMetaType = {
/**
*
* @returns Check are there tasks under the copy action
*/
checkHasCopyTasks: () => boolean;
/**
*
* @returns Check are there tasks under the cut action
*/
checkHasCutTasks: () => boolean;
/**
* Context menu trigger task
*/
task: TaskOrEmpty;
};
export type ContextMenuOptionType = {
/**
* Invokes on click on menu option
* @param meta Metadata for the action
*/
action: (meta: ActionMetaType) => void;
/**
* Check is the current action available. Available by default
* @param meta Metadata for checking
*/
checkIsAvailable?: (meta: CheckIsAvailableMetaType) => void;
label: ReactNode;
icon?: ReactNode;
};
export type CheckTaskIdExistsAtLevel = (newId: string, comparisonLevel?: number) => boolean;
export type GetCopiedTaskId = (task: TaskOrEmpty, checkExists: (newId: string) => boolean) => string;
export type AdjustTaskToWorkingDatesParams = {
action: BarMoveAction;
changedTask: Task;
originalTask: Task;
roundDate: (date: Date, action: BarMoveAction, dateExtremity: DateExtremity) => Date;
};