diff --git a/bode/bode/models/task/actions.py b/bode/bode/models/task/actions.py index e2bc79f..06812cb 100644 --- a/bode/bode/models/task/actions.py +++ b/bode/bode/models/task/actions.py @@ -32,6 +32,9 @@ def edit_task(task_id, **task_data): def is_interchangable_relation(relation): return relation.type == RelationType.Interchangable.value and str(relation.first_task_id) == task_id + def is_subtask_relation(relation): + return relation.type == RelationType.Subtask.value and str(relation.first_task_id) == task_id + task = get_task(task_id) for key, value in task_data.items(): @@ -47,12 +50,16 @@ def is_interchangable_relation(relation): if related_task.status != TaskStatus.TODO.value: continue inter_task_data = { - "title": related_task.title, - "description": related_task.description, - "due_date": related_task.due_date, "status": TaskStatus.INDIRECTLY_DONE.value, } edit_task(str(related_task.id), **inter_task_data) + if is_subtask_relation(relation): + if related_task.status == TaskStatus.DONE.value: + continue + subtask_data = { + "status": TaskStatus.DONE.value, + } + edit_task(str(related_task.id), **subtask_data) return task diff --git a/bode/bode/resources/tasks/schemas.py b/bode/bode/resources/tasks/schemas.py index 7e67c71..df2fb41 100644 --- a/bode/bode/resources/tasks/schemas.py +++ b/bode/bode/resources/tasks/schemas.py @@ -33,7 +33,7 @@ class TaskSchema(BaseSchema): due_date = fields.DateTime() status = fields.String(validate=validate.OneOf(TaskStatus.list())) rrule = fields.String() - is_blocked = fields.Function(lambda task: task.status != TaskStatus.DONE.value and is_task_blocked(task.id)) + is_blocked = fields.Function(lambda task: is_task_blocked(task.id)) tags = fields.List(fields.Nested(TagSchema)) relation_types = fields.List(fields.String(validate=validate.OneOf(DirectedRelationType.list()))) diff --git a/cabra/src/assets/indirectly_done_icon.svg b/cabra/src/assets/indirectly_done_icon.svg new file mode 100644 index 0000000..de1a165 --- /dev/null +++ b/cabra/src/assets/indirectly_done_icon.svg @@ -0,0 +1,23 @@ + + + +Created with Fabric.js 4.6.0 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cabra/src/pages/components/CheckBox.tsx b/cabra/src/pages/components/CheckBox.tsx index a48779e..1a058b0 100644 --- a/cabra/src/pages/components/CheckBox.tsx +++ b/cabra/src/pages/components/CheckBox.tsx @@ -2,7 +2,7 @@ import tw, { TwStyle, styled } from "twin.macro"; import CheckboxBlankIcon from "remixicon-react/CheckboxBlankCircleLineIcon"; import CheckboxCheckedIcon from "remixicon-react/CheckboxCircleLineIcon"; -import CheckboxMultiIcon from "remixicon-react/CheckboxMultipleLineIcon"; +import CheckboxIndirectlyDoneIcon from "../../assets/indirectly_done_icon.svg"; import DisabledIcon from "remixicon-react/IndeterminateCircleLineIcon"; import { InputHTMLAttributes } from "react"; import ReactTooltip from "react-tooltip"; @@ -14,6 +14,7 @@ type Props = Omit< > & { id: string; status: TaskStatus; + blocked: boolean; size?: Size; }; type Size = "sm" | "base" | "lg"; @@ -31,7 +32,7 @@ const iconSizes: Record = { base: { size: 24 }, lg: { size: 28 }, }; -const Label = styled.label<{ size: Size }>` +const Label = styled.label<{ size: Size; blocked: boolean }>` ${tw`select-none`} span { @@ -44,15 +45,12 @@ const Label = styled.label<{ size: Size }>` ${tw`bg-slate-500 cursor-auto`} } input:enabled ~ span { + ${({ blocked }) => blocked && tw`bg-orange-300`} ${tw`hover:opacity-60`} } `; -const resolveIcon = ( - status: TaskStatus, - size: Size, - disabled: boolean | undefined -) => { +const resolveIcon = (status: TaskStatus, size: Size, disabled: boolean) => { if (disabled) { return ; } @@ -62,14 +60,31 @@ const resolveIcon = ( case TaskStatus.TODO: return ; case TaskStatus.INDIRECTLY_DONE: - return ; + return ; + } +}; + +const resolveTooltip = (status: TaskStatus, blocked: boolean) => { + if (blocked) { + if (status === TaskStatus.DONE) { + return "Task is done but is blocked by not done task."; + } + return "Task is blocked by not done task."; + } + switch (status) { + case TaskStatus.DONE: + return "Task was done."; + case TaskStatus.INDIRECTLY_DONE: + return "Task was done indirectly by other task."; + case TaskStatus.TODO: + return "Task to do."; } }; export default function Checkbox({ id, size = "base", - disabled, + blocked, status, ...props }: Props) { @@ -78,18 +93,24 @@ export default function Checkbox({ - {disabled && ( - - Task is blocked by other task. - - )} + + {resolveTooltip(status, blocked)} + ); } diff --git a/cabra/src/pages/components/RelatedTask.tsx b/cabra/src/pages/components/RelatedTask.tsx index bfbe1b1..ff8ddf5 100644 --- a/cabra/src/pages/components/RelatedTask.tsx +++ b/cabra/src/pages/components/RelatedTask.tsx @@ -59,7 +59,7 @@ export default function RelatedTask({ id={task.id} checked={task.status !== TaskStatus.TODO} onChange={handleIsDoneChange} - disabled={task.isBlocked} + blocked={task.isBlocked} status={task.status} />

diff --git a/cabra/src/pages/components/TaskDetailsCard.tsx b/cabra/src/pages/components/TaskDetailsCard.tsx index cfd24a0..7c5eebb 100644 --- a/cabra/src/pages/components/TaskDetailsCard.tsx +++ b/cabra/src/pages/components/TaskDetailsCard.tsx @@ -58,7 +58,7 @@ export default function TaskDetails({ id }: Props) { checked={task.status !== TaskStatus.TODO} id={`task-${task.id}`} onChange={handleStatusChange} - disabled={task.isBlocked} + blocked={task.isBlocked} status={task.status} /> diff --git a/cabra/src/pages/components/TaskListItem.tsx b/cabra/src/pages/components/TaskListItem.tsx index 72ef294..ed87501 100644 --- a/cabra/src/pages/components/TaskListItem.tsx +++ b/cabra/src/pages/components/TaskListItem.tsx @@ -69,7 +69,7 @@ export default function TaskListItem({ task }: Props) { checked={task.status !== TaskStatus.TODO} id={`task-${task.id}`} onChange={handleIsDoneChange} - disabled={task.isBlocked} + blocked={task.isBlocked} size="sm" status={task.status} /> diff --git a/cabra/src/pages/hooks/useTaskDetails.ts b/cabra/src/pages/hooks/useTaskDetails.ts index cbccb88..7fac696 100644 --- a/cabra/src/pages/hooks/useTaskDetails.ts +++ b/cabra/src/pages/hooks/useTaskDetails.ts @@ -36,6 +36,9 @@ const useTask = (id: string) => { client.invalidateQueries( getRelatedTasks.cacheKey(task?.id, DirectedRelationType.Blocks) ); + client.invalidateQueries( + getRelatedTasks.cacheKey(task?.id, DirectedRelationType.Subtask) + ); }, }); const handleStatusChange = async () => {