Add deadline on task

Signed-off-by: Andreas Reußner <andreas.reussner@outlook.de>
This commit is contained in:
Andreas Reußner
2025-06-02 10:47:26 +02:00
committed by Sacha Al Himdani
parent 02ff3b02d9
commit fc008c27f4
16 changed files with 343 additions and 33 deletions

View File

@@ -109,6 +109,7 @@ import { MeasureViewRisksQuery } from "./__generated__/MeasureViewRisksQuery.gra
import { MeasureViewDeleteMeasureMutation } from "./__generated__/MeasureViewDeleteMeasureMutation.graphql"; import { MeasureViewDeleteMeasureMutation } from "./__generated__/MeasureViewDeleteMeasureMutation.graphql";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw"; import rehypeRaw from "rehype-raw";
import { format, formatISO, parseISO } from "date-fns";
// Function to format ISO8601 duration to human-readable format // Function to format ISO8601 duration to human-readable format
const formatDuration = (isoDuration: string): string => { const formatDuration = (isoDuration: string): string => {
@@ -181,6 +182,7 @@ const measureViewQuery = graphql`
description description
state state
timeEstimate timeEstimate
deadline
assignedTo { assignedTo {
id id
fullName fullName
@@ -218,6 +220,7 @@ const updateTaskStateMutation = graphql`
id id
state state
timeEstimate timeEstimate
deadline
} }
} }
} }
@@ -235,6 +238,7 @@ const createTaskMutation = graphql`
name name
description description
timeEstimate timeEstimate
deadline
state state
assignedTo { assignedTo {
id id
@@ -743,6 +747,7 @@ function MeasureViewContent({
const [isCreateTaskOpen, setIsCreateTaskOpen] = useState(false); const [isCreateTaskOpen, setIsCreateTaskOpen] = useState(false);
const [newTaskName, setNewTaskName] = useState(""); const [newTaskName, setNewTaskName] = useState("");
const [newTaskDescription, setNewTaskDescription] = useState(""); const [newTaskDescription, setNewTaskDescription] = useState("");
const [newDeadline, setNewDeadline] = useState("");
const [timeEstimateDays, setTimeEstimateDays] = useState(""); const [timeEstimateDays, setTimeEstimateDays] = useState("");
const [timeEstimateHours, setTimeEstimateHours] = useState(""); const [timeEstimateHours, setTimeEstimateHours] = useState("");
const [timeEstimateMinutes, setTimeEstimateMinutes] = useState(""); const [timeEstimateMinutes, setTimeEstimateMinutes] = useState("");
@@ -991,6 +996,7 @@ function MeasureViewContent({
name: newTaskName, name: newTaskName,
description: newTaskDescription, description: newTaskDescription,
timeEstimate: isoTimeEstimate === "" ? null : isoTimeEstimate, timeEstimate: isoTimeEstimate === "" ? null : isoTimeEstimate,
deadline: newDeadline === "" ? null : formatISO(newDeadline),
}, },
}, },
onCompleted: () => { onCompleted: () => {
@@ -1004,6 +1010,7 @@ function MeasureViewContent({
setTimeEstimateHours(""); setTimeEstimateHours("");
setTimeEstimateMinutes(""); setTimeEstimateMinutes("");
setIsCreateTaskOpen(false); setIsCreateTaskOpen(false);
setNewDeadline("");
}, },
onError: (error) => { onError: (error) => {
toast({ toast({
@@ -1718,9 +1725,11 @@ function MeasureViewContent({
// Add state variables for tracking edit mode and duration components // Add state variables for tracking edit mode and duration components
const [isEditingDuration, setIsEditingDuration] = useState(false); const [isEditingDuration, setIsEditingDuration] = useState(false);
const [isEditingDeadline, setIsEditingDeadline] = useState(false);
const [editTimeEstimateDays, setEditTimeEstimateDays] = useState(""); const [editTimeEstimateDays, setEditTimeEstimateDays] = useState("");
const [editTimeEstimateHours, setEditTimeEstimateHours] = useState(""); const [editTimeEstimateHours, setEditTimeEstimateHours] = useState("");
const [editTimeEstimateMinutes, setEditTimeEstimateMinutes] = useState(""); const [editTimeEstimateMinutes, setEditTimeEstimateMinutes] = useState("");
const [editDeadline, setEditDeadline] = useState("");
// Function to parse ISO duration string into components for editing // Function to parse ISO duration string into components for editing
const parseISODuration = useCallback( const parseISODuration = useCallback(
@@ -1750,6 +1759,40 @@ function MeasureViewContent({
[] []
); );
// Function to handle saving the updated deadline
const handleSaveDeadline = useCallback(
(taskId: string) => {
const newDeadline = editDeadline === "" ? null : formatISO(editDeadline);
updateTask({
variables: {
input: {
taskId,
deadline: newDeadline,
},
},
onCompleted: () => {
setIsEditingDeadline(false);
// Update the selected task state if it's the current task
if (selectedTask && selectedTask.id === taskId) {
setSelectedTask({
...selectedTask,
deadline: newDeadline,
});
}
},
onError: (error) => {
toast({
title: "Error updating task",
description: error.message,
variant: "destructive",
});
},
});
},
[editDeadline, updateTask, toast, selectedTask, setSelectedTask]
);
// Function to handle saving the updated duration // Function to handle saving the updated duration
const handleSaveDuration = useCallback( const handleSaveDuration = useCallback(
(taskId: string) => { (taskId: string) => {
@@ -2605,6 +2648,11 @@ function MeasureViewContent({
{formatDuration(task.timeEstimate)} {formatDuration(task.timeEstimate)}
</div> </div>
)} )}
{task.deadline && (
<div className="text-sm text-secondary">
{formatDate(task.deadline)}
</div>
)}
</div> </div>
</div> </div>
@@ -3063,6 +3111,69 @@ function MeasureViewContent({
)} )}
</div> </div>
{/* Deadline */}
<div>
<h3 className="text-sm font-medium text-secondary mb-2">
Deadline
</h3>
{isEditingDeadline ? (
<div className="space-y-2">
<div className="flex gap-2">
<div className="flex-1">
<Input
type="date"
value={editDeadline}
onChange={(e) =>
setEditDeadline(e.target.value)
}
/>
</div>
</div>
<div className="flex justify-end gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setIsEditingDeadline(false)}
>
Cancel
</Button>
<Button
size="sm"
onClick={() => handleSaveDeadline(selectedTask.id)}
>
Save
</Button>
</div>
</div>
) : (
<div className="flex items-center justify-between">
<div>
{selectedTask.deadline ? (
<span>
{formatDate(selectedTask.deadline)}
</span>
) : (
<span className="text-secondary">
No deadline
</span>
)}
</div>
<Button
variant="ghost"
size="sm"
className="p-1 h-auto"
onClick={() => {
const selectedDeadline = selectedTask.deadline ? format(selectedTask.deadline, 'yyyy-MM-dd') : "";
setEditDeadline(selectedDeadline);
setIsEditingDeadline(true);
}}
>
Edit
</Button>
</div>
)}
</div>
{/* Evidence section */} {/* Evidence section */}
<div> <div>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
@@ -3846,6 +3957,15 @@ function MeasureViewContent({
</div> </div>
</div> </div>
</div> </div>
<div className="grid w-full items-center gap-1.5">
<Label htmlFor="task-deadline">Deadline (optional)</Label>
<Input
id="task-deadline"
type="date"
value={newDeadline}
onChange={(e) => setNewDeadline(e.target.value)}
/>
</div>
</div> </div>
<DialogFooter className="mt-4"> <DialogFooter className="mt-4">

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<b53893b96884bbc49ad8f2dbdb22e2ea>> * @generated SignedSource<<d258cc7c047ea5b1e81d5ef895e63ac6>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime';
export type TaskState = "DONE" | "TODO"; export type TaskState = "DONE" | "TODO";
export type CreateTaskInput = { export type CreateTaskInput = {
assignedToId?: string | null | undefined; assignedToId?: string | null | undefined;
deadline?: string | null | undefined;
description: string; description: string;
measureId?: string | null | undefined; measureId?: string | null | undefined;
name: string; name: string;
@@ -31,6 +32,7 @@ export type MeasureViewCreateTaskMutation$data = {
readonly id: string; readonly id: string;
readonly primaryEmailAddress: string; readonly primaryEmailAddress: string;
} | null | undefined; } | null | undefined;
readonly deadline: string | null | undefined;
readonly description: string; readonly description: string;
readonly id: string; readonly id: string;
readonly name: string; readonly name: string;
@@ -108,6 +110,13 @@ v4 = {
"name": "timeEstimate", "name": "timeEstimate",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -213,16 +222,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "53b934e0e7a3d4abf8789ad8672687df", "cacheID": "8f9aeb0df92f9535d728ef27a7dee963",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "MeasureViewCreateTaskMutation", "name": "MeasureViewCreateTaskMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation MeasureViewCreateTaskMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n id\n name\n description\n timeEstimate\n state\n assignedTo {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n }\n}\n" "text": "mutation MeasureViewCreateTaskMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n id\n name\n description\n timeEstimate\n deadline\n state\n assignedTo {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "0df98f5aee4233dc4ffedcff8256891a"; (node as any).hash = "f323b5caa0912478e715f0c409898eff";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<03d8e2eca1cc7ffaf797c66ef7fa11c1>> * @generated SignedSource<<a6d5ebf3d09595b1da2cd16746fa1163>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -48,6 +48,7 @@ export type MeasureViewQuery$data = {
readonly id: string; readonly id: string;
readonly primaryEmailAddress: string; readonly primaryEmailAddress: string;
} | null | undefined; } | null | undefined;
readonly deadline: string | null | undefined;
readonly description: string; readonly description: string;
readonly evidences: { readonly evidences: {
readonly __id: string; readonly __id: string;
@@ -261,6 +262,13 @@ v12 = {
"storageKey": null "storageKey": null
}, },
v13 = { v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
v14 = {
"alias": null, "alias": null,
"args": null, "args": null,
"concreteType": "People", "concreteType": "People",
@@ -286,14 +294,14 @@ v13 = {
], ],
"storageKey": null "storageKey": null
}, },
v14 = [ v15 = [
{ {
"kind": "Literal", "kind": "Literal",
"name": "first", "name": "first",
"value": 100 "value": 100
} }
], ],
v15 = [ v16 = [
{ {
"kind": "Literal", "kind": "Literal",
"name": "first", "name": "first",
@@ -363,6 +371,7 @@ return {
(v5/*: any*/), (v5/*: any*/),
(v12/*: any*/), (v12/*: any*/),
(v13/*: any*/), (v13/*: any*/),
(v14/*: any*/),
{ {
"alias": "evidences", "alias": "evidences",
"args": null, "args": null,
@@ -422,7 +431,7 @@ return {
(v6/*: any*/), (v6/*: any*/),
{ {
"alias": null, "alias": null,
"args": (v14/*: any*/), "args": (v15/*: any*/),
"concreteType": "EvidenceConnection", "concreteType": "EvidenceConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "evidences", "name": "evidences",
@@ -432,7 +441,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v14/*: any*/), "args": (v15/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "MeasureView_evidences", "key": "MeasureView_evidences",
@@ -441,7 +450,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v14/*: any*/), "args": (v15/*: any*/),
"concreteType": "TaskConnection", "concreteType": "TaskConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "tasks", "name": "tasks",
@@ -469,9 +478,10 @@ return {
(v5/*: any*/), (v5/*: any*/),
(v12/*: any*/), (v12/*: any*/),
(v13/*: any*/), (v13/*: any*/),
(v14/*: any*/),
{ {
"alias": null, "alias": null,
"args": (v15/*: any*/), "args": (v16/*: any*/),
"concreteType": "EvidenceConnection", "concreteType": "EvidenceConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "evidences", "name": "evidences",
@@ -481,7 +491,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v15/*: any*/), "args": (v16/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "MeasureView_task_evidences", "key": "MeasureView_task_evidences",
@@ -503,7 +513,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v14/*: any*/), "args": (v15/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "MeasureView_tasks", "key": "MeasureView_tasks",
@@ -520,7 +530,7 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "d3e4d9723d12bce8158b83eb76d05a90", "cacheID": "2693fa3e0141f58235566f539194fcd6",
"id": null, "id": null,
"metadata": { "metadata": {
"connection": [ "connection": [
@@ -552,11 +562,11 @@ return {
}, },
"name": "MeasureViewQuery", "name": "MeasureViewQuery",
"operationKind": "query", "operationKind": "query",
"text": "query MeasureViewQuery(\n $measureId: ID!\n) {\n measure: node(id: $measureId) {\n __typename\n id\n ... on Measure {\n name\n description\n state\n category\n evidences(first: 100) {\n edges {\n node {\n id\n mimeType\n filename\n size\n state\n type\n url\n createdAt\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n assignedTo {\n id\n fullName\n primaryEmailAddress\n }\n evidences(first: 50) {\n edges {\n node {\n id\n mimeType\n filename\n size\n state\n type\n url\n createdAt\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n" "text": "query MeasureViewQuery(\n $measureId: ID!\n) {\n measure: node(id: $measureId) {\n __typename\n id\n ... on Measure {\n name\n description\n state\n category\n evidences(first: 100) {\n edges {\n node {\n id\n mimeType\n filename\n size\n state\n type\n url\n createdAt\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n deadline\n assignedTo {\n id\n fullName\n primaryEmailAddress\n }\n evidences(first: 50) {\n edges {\n node {\n id\n mimeType\n filename\n size\n state\n type\n url\n createdAt\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "288412cccb1f4c14b1852504e5536af1"; (node as any).hash = "4e211c36d94ebd914b6de254dfbdf946";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<1595fa9771d6baa14534b181f4a1384a>> * @generated SignedSource<<28c68c446adeac27a47de2b754d48d5d>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -11,6 +11,7 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type TaskState = "DONE" | "TODO"; export type TaskState = "DONE" | "TODO";
export type UpdateTaskInput = { export type UpdateTaskInput = {
deadline?: string | null | undefined;
description?: string | null | undefined; description?: string | null | undefined;
name?: string | null | undefined; name?: string | null | undefined;
state?: TaskState | null | undefined; state?: TaskState | null | undefined;
@@ -23,6 +24,7 @@ export type MeasureViewUpdateTaskStateMutation$variables = {
export type MeasureViewUpdateTaskStateMutation$data = { export type MeasureViewUpdateTaskStateMutation$data = {
readonly updateTask: { readonly updateTask: {
readonly task: { readonly task: {
readonly deadline: string | null | undefined;
readonly id: string; readonly id: string;
readonly state: TaskState; readonly state: TaskState;
readonly timeEstimate: any | null | undefined; readonly timeEstimate: any | null | undefined;
@@ -85,6 +87,13 @@ v1 = [
"kind": "ScalarField", "kind": "ScalarField",
"name": "timeEstimate", "name": "timeEstimate",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -111,16 +120,16 @@ return {
"selections": (v1/*: any*/) "selections": (v1/*: any*/)
}, },
"params": { "params": {
"cacheID": "f545a0b12edb8f231a1a7a7c38b6e905", "cacheID": "a0001fad3af2ba3fc16a1f0af4f19370",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "MeasureViewUpdateTaskStateMutation", "name": "MeasureViewUpdateTaskStateMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation MeasureViewUpdateTaskStateMutation(\n $input: UpdateTaskInput!\n) {\n updateTask(input: $input) {\n task {\n id\n state\n timeEstimate\n }\n }\n}\n" "text": "mutation MeasureViewUpdateTaskStateMutation(\n $input: UpdateTaskInput!\n) {\n updateTask(input: $input) {\n task {\n id\n state\n timeEstimate\n deadline\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "e1d67c030523e56d6bcd595c27fcb3dc"; (node as any).hash = "b3b0d47e0632b106b6313edbd2de38ce";
export default node; export default node;

View File

@@ -1,4 +1,4 @@
import { Suspense, useEffect, useState } from "react"; import {ChangeEvent, Suspense, useEffect, useState} from "react";
import { import {
useQueryLoader, useQueryLoader,
graphql, graphql,
@@ -47,6 +47,7 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { ListTaskViewOrganizationQuery } from "./__generated__/ListTaskViewOrganizationQuery.graphql"; import { ListTaskViewOrganizationQuery } from "./__generated__/ListTaskViewOrganizationQuery.graphql";
import {formatDate, parseISO} from "date-fns";
// Function to format ISO8601 duration to human-readable format // Function to format ISO8601 duration to human-readable format
const formatDuration = (isoDuration: string | null | undefined): string => { const formatDuration = (isoDuration: string | null | undefined): string => {
@@ -121,6 +122,7 @@ const createTaskMutation = graphql`
description description
state state
timeEstimate timeEstimate
deadline
measure { measure {
id id
name name
@@ -164,6 +166,7 @@ const listTaskViewQuery = graphql`
description description
state state
timeEstimate timeEstimate
deadline
measure { measure {
id id
name name
@@ -213,6 +216,7 @@ interface Task {
description?: string; description?: string;
state: string; state: string;
timeEstimate?: number | null; timeEstimate?: number | null;
deadline?: string | null;
assignedTo?: { assignedTo?: {
id: string; id: string;
fullName: string; fullName: string;
@@ -273,6 +277,11 @@ function TaskCard({ task, onClick, onToggleState }: {
{formatDuration(task.timeEstimate.toString())} {formatDuration(task.timeEstimate.toString())}
</span> </span>
)} )}
{task.deadline && (
<span className="text-xs text-gray-500">
{formatDate(task.deadline, "dd MMM yyyy")}
</span>
)}
</div> </div>
{task.parent && ( {task.parent && (
<div className="flex items-center gap-1 text-sm text-gray-500"> <div className="flex items-center gap-1 text-sm text-gray-500">
@@ -346,6 +355,8 @@ function ListTaskContent({
const [selectedMeasure, setSelectedMeasure] = useState<{id: string, name: string} | null>(null); const [selectedMeasure, setSelectedMeasure] = useState<{id: string, name: string} | null>(null);
const [timeEstimate, setTimeEstimate] = useState<number | null>(null); const [timeEstimate, setTimeEstimate] = useState<number | null>(null);
const [timeUnit, setTimeUnit] = useState<"minutes" | "hours" | "days" | "weeks">("hours"); const [timeUnit, setTimeUnit] = useState<"minutes" | "hours" | "days" | "weeks">("hours");
const [deadlineString, setDeadlineString] = useState<string>('');
const [deadline, setDeadline] = useState<Date | null>(null);
// Create task mutation // Create task mutation
const [createTask, isCreatingTask] = useMutation(createTaskMutation); const [createTask, isCreatingTask] = useMutation(createTaskMutation);
@@ -382,6 +393,19 @@ function ListTaskContent({
} }
}, [environment, organization?.id]); }, [environment, organization?.id]);
// Parse deadline string into Date-object
const handleDeadlineChange = (event: ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
setDeadlineString(value);
if (value) {
const date = parseISO(value);
setDeadline(date);
} else {
setDeadline(null)
}
};
// Filter measures based on search query // Filter measures based on search query
const filteredMeasures = measures.filter(measure => const filteredMeasures = measures.filter(measure =>
measure.name.toLowerCase().includes(measureSearchQuery.toLowerCase()) || measure.name.toLowerCase().includes(measureSearchQuery.toLowerCase()) ||
@@ -439,6 +463,7 @@ function ListTaskContent({
measureId: selectedMeasure?.id || null, measureId: selectedMeasure?.id || null,
assignedToId: assignee?.id, assignedToId: assignee?.id,
timeEstimate: formattedTimeEstimate, timeEstimate: formattedTimeEstimate,
deadline: deadline
}, },
connections: [data.node?.tasks?.__id || ""], connections: [data.node?.tasks?.__id || ""],
}, },
@@ -462,6 +487,8 @@ function ListTaskContent({
setTimeEstimate(null); setTimeEstimate(null);
setTimeUnit("hours"); setTimeUnit("hours");
setMeasureSearchQuery(""); setMeasureSearchQuery("");
setDeadlineString('');
setDeadline(null);
}; };
// Get initials from name // Get initials from name
@@ -825,6 +852,15 @@ function ListTaskContent({
)} )}
</div> </div>
</div> </div>
{/* Deadline */}
<div className="flex justify-between items-center broder-b border-[rgba(2,42,2,0.08)] py-3">
<Label className="text-sm font-medium text-gray-500">Deadline</Label>
<div className="flex items-center gap-1.5">
<Input type="date" value={deadlineString} onChange={handleDeadlineChange}
className="text-sm font-medium bg-[rgba(0,39,0,0.05)] px-[10px] py-[6px] rounded-lg"/>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<84a35602a155b0f1fa8504cf32c10932>> * @generated SignedSource<<a4c4d53df4bc73d2bdc48ef0eb38a500>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime';
export type TaskState = "DONE" | "TODO"; export type TaskState = "DONE" | "TODO";
export type CreateTaskInput = { export type CreateTaskInput = {
assignedToId?: string | null | undefined; assignedToId?: string | null | undefined;
deadline?: string | null | undefined;
description: string; description: string;
measureId?: string | null | undefined; measureId?: string | null | undefined;
name: string; name: string;
@@ -30,6 +31,7 @@ export type ListTaskViewCreateTaskMutation$data = {
readonly fullName: string; readonly fullName: string;
readonly id: string; readonly id: string;
} | null | undefined; } | null | undefined;
readonly deadline: string | null | undefined;
readonly description: string; readonly description: string;
readonly id: string; readonly id: string;
readonly measure: { readonly measure: {
@@ -119,6 +121,13 @@ v5 = {
"name": "timeEstimate", "name": "timeEstimate",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -223,16 +232,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "7b9680f637411402ff51239a43b44a14", "cacheID": "6fe245ddb913332138beda8377ebd88c",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "ListTaskViewCreateTaskMutation", "name": "ListTaskViewCreateTaskMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation ListTaskViewCreateTaskMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n id\n name\n description\n state\n timeEstimate\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n }\n }\n }\n}\n" "text": "mutation ListTaskViewCreateTaskMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n id\n name\n description\n state\n timeEstimate\n deadline\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n }\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "43ccaf49d31ec84dcf3b6b3f2e3a851c"; (node as any).hash = "934ee4a5b5bfd4c9e9c4acab49d11304";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<7732676a00f7ed0f6817555b68540aca>> * @generated SignedSource<<14a914bdd269eb18124d002d2c61a5b9>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -25,6 +25,7 @@ export type ListTaskViewQuery$data = {
readonly fullName: string; readonly fullName: string;
readonly id: string; readonly id: string;
} | null | undefined; } | null | undefined;
readonly deadline: string | null | undefined;
readonly description: string; readonly description: string;
readonly id: string; readonly id: string;
readonly measure: { readonly measure: {
@@ -120,6 +121,13 @@ v5 = [
"name": "timeEstimate", "name": "timeEstimate",
"storageKey": null "storageKey": null
}, },
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -301,7 +309,7 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "52b577b08c305249855293949d6e2339", "cacheID": "7519a481d7930f14c53c8c1a72d66f58",
"id": null, "id": null,
"metadata": { "metadata": {
"connection": [ "connection": [
@@ -318,11 +326,11 @@ return {
}, },
"name": "ListTaskViewQuery", "name": "ListTaskViewQuery",
"operationKind": "query", "operationKind": "query",
"text": "query ListTaskViewQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n name\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n" "text": "query ListTaskViewQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n name\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n deadline\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "5ca091444c547744068f2b2a83cb31df"; (node as any).hash = "52b99d58a5b95dadd4e66bfad588d924";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<7098e326d01cc6831f293726096a7275>> * @generated SignedSource<<c0e5d40aeab42e5f50cf93b75ddb7328>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -11,6 +11,7 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type TaskState = "DONE" | "TODO"; export type TaskState = "DONE" | "TODO";
export type UpdateTaskInput = { export type UpdateTaskInput = {
deadline?: string | null | undefined;
description?: string | null | undefined; description?: string | null | undefined;
name?: string | null | undefined; name?: string | null | undefined;
state?: TaskState | null | undefined; state?: TaskState | null | undefined;

View File

@@ -0,0 +1 @@
ALTER TABLE tasks ADD COLUMN deadline TIMESTAMP WITH TIME ZONE;

View File

@@ -38,6 +38,7 @@ type (
ReferenceID string `db:"reference_id"` ReferenceID string `db:"reference_id"`
TimeEstimate *time.Duration `db:"time_estimate"` TimeEstimate *time.Duration `db:"time_estimate"`
AssignedToID *gid.GID `db:"assigned_to"` AssignedToID *gid.GID `db:"assigned_to"`
Deadline *time.Time `db:"deadline"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"` UpdatedAt time.Time `db:"updated_at"`
} }
@@ -71,6 +72,7 @@ SELECT
reference_id, reference_id,
time_estimate, time_estimate,
assigned_to, assigned_to,
deadline,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -119,6 +121,7 @@ INSERT INTO
state, state,
time_estimate, time_estimate,
assigned_to, assigned_to,
deadline,
created_at, created_at,
updated_at updated_at
) )
@@ -133,6 +136,7 @@ VALUES (
@state, @state,
@time_estimate, @time_estimate,
@assigned_to, @assigned_to,
@deadline,
@created_at, @created_at,
@updated_at @updated_at
); );
@@ -149,6 +153,7 @@ VALUES (
"state": c.State, "state": c.State,
"time_estimate": c.TimeEstimate, "time_estimate": c.TimeEstimate,
"assigned_to": c.AssignedToID, "assigned_to": c.AssignedToID,
"deadline": c.Deadline,
"created_at": c.CreatedAt, "created_at": c.CreatedAt,
"updated_at": c.UpdatedAt, "updated_at": c.UpdatedAt,
} }
@@ -174,6 +179,7 @@ INSERT INTO
state, state,
time_estimate, time_estimate,
assigned_to, assigned_to,
deadline,
created_at, created_at,
updated_at updated_at
) )
@@ -188,6 +194,7 @@ VALUES (
@state, @state,
@time_estimate, @time_estimate,
@assigned_to, @assigned_to,
@deadline,
@created_at, @created_at,
@updated_at @updated_at
) )
@@ -205,6 +212,7 @@ RETURNING
state, state,
time_estimate, time_estimate,
assigned_to, assigned_to,
deadline,
created_at, created_at,
updated_at updated_at
` `
@@ -220,6 +228,7 @@ RETURNING
"state": c.State, "state": c.State,
"time_estimate": c.TimeEstimate, "time_estimate": c.TimeEstimate,
"assigned_to": c.AssignedToID, "assigned_to": c.AssignedToID,
"deadline": c.Deadline,
"created_at": c.CreatedAt, "created_at": c.CreatedAt,
"updated_at": c.UpdatedAt, "updated_at": c.UpdatedAt,
} }
@@ -256,6 +265,7 @@ func (c *Tasks) LoadByOrganizationID(
reference_id, reference_id,
time_estimate, time_estimate,
assigned_to, assigned_to,
deadline,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -304,6 +314,7 @@ SELECT
reference_id, reference_id,
time_estimate, time_estimate,
assigned_to, assigned_to,
deadline,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -347,7 +358,8 @@ SET
state = @state, state = @state,
time_estimate = @time_estimate, time_estimate = @time_estimate,
updated_at = @updated_at, updated_at = @updated_at,
assigned_to = @assigned_to assigned_to = @assigned_to,
deadline = @deadline
WHERE %s WHERE %s
AND id = @task_id AND id = @task_id
` `
@@ -361,6 +373,7 @@ WHERE %s
"time_estimate": c.TimeEstimate, "time_estimate": c.TimeEstimate,
"updated_at": c.UpdatedAt, "updated_at": c.UpdatedAt,
"assigned_to": c.AssignedToID, "assigned_to": c.AssignedToID,
"deadline": c.Deadline,
} }
maps.Copy(args, scope.SQLArguments()) maps.Copy(args, scope.SQLArguments())

View File

@@ -38,6 +38,7 @@ type (
Description string Description string
TimeEstimate *time.Duration TimeEstimate *time.Duration
AssignedToID *gid.GID AssignedToID *gid.GID
Deadline *time.Time
} }
UpdateTaskRequest struct { UpdateTaskRequest struct {
@@ -46,6 +47,7 @@ type (
Description *string Description *string
State *coredata.TaskState State *coredata.TaskState
TimeEstimate *time.Duration TimeEstimate *time.Duration
Deadline *time.Time
} }
) )
@@ -69,6 +71,7 @@ func (s TaskService) Create(
Description: req.Description, Description: req.Description,
TimeEstimate: req.TimeEstimate, TimeEstimate: req.TimeEstimate,
AssignedToID: req.AssignedToID, AssignedToID: req.AssignedToID,
Deadline: req.Deadline,
State: coredata.TaskStateTodo, State: coredata.TaskStateTodo,
ReferenceID: "custom-task-" + referenceID.String(), ReferenceID: "custom-task-" + referenceID.String(),
CreatedAt: now, CreatedAt: now,
@@ -203,6 +206,10 @@ func (s TaskService) Update(
task.TimeEstimate = req.TimeEstimate task.TimeEstimate = req.TimeEstimate
} }
if req.Deadline != nil {
task.Deadline = req.Deadline
}
task.UpdatedAt = time.Now() task.UpdatedAt = time.Now()
if err := task.Update(ctx, conn, s.svc.scope); err != nil { if err := task.Update(ctx, conn, s.svc.scope); err != nil {

View File

@@ -758,6 +758,7 @@ type Task implements Node {
description: String! description: String!
state: TaskState! state: TaskState!
timeEstimate: Duration timeEstimate: Duration
deadline: Datetime
assignedTo: People @goField(forceResolver: true) assignedTo: People @goField(forceResolver: true)
organization: Organization! @goField(forceResolver: true) organization: Organization! @goField(forceResolver: true)
@@ -1329,6 +1330,7 @@ input CreateTaskInput {
description: String! description: String!
timeEstimate: Duration timeEstimate: Duration
assignedToId: ID assignedToId: ID
deadline: Datetime
} }
input UpdateTaskInput { input UpdateTaskInput {
@@ -1337,6 +1339,7 @@ input UpdateTaskInput {
description: String description: String
state: TaskState state: TaskState
timeEstimate: Duration timeEstimate: Duration
deadline: Datetime
} }
input DeleteTaskInput { input DeleteTaskInput {

View File

@@ -680,6 +680,7 @@ type ComplexityRoot struct {
Task struct { Task struct {
AssignedTo func(childComplexity int) int AssignedTo func(childComplexity int) int
CreatedAt func(childComplexity int) int CreatedAt func(childComplexity int) int
Deadline func(childComplexity int) int
Description func(childComplexity int) int Description func(childComplexity int) int
Evidences func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) int Evidences func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) int
ID func(childComplexity int) int ID func(childComplexity int) int
@@ -3834,6 +3835,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Task.CreatedAt(childComplexity), true return e.complexity.Task.CreatedAt(childComplexity), true
case "Task.deadline":
if e.complexity.Task.Deadline == nil {
break
}
return e.complexity.Task.Deadline(childComplexity), true
case "Task.description": case "Task.description":
if e.complexity.Task.Description == nil { if e.complexity.Task.Description == nil {
break break
@@ -5481,6 +5489,7 @@ type Task implements Node {
description: String! description: String!
state: TaskState! state: TaskState!
timeEstimate: Duration timeEstimate: Duration
deadline: Datetime
assignedTo: People @goField(forceResolver: true) assignedTo: People @goField(forceResolver: true)
organization: Organization! @goField(forceResolver: true) organization: Organization! @goField(forceResolver: true)
@@ -6052,6 +6061,7 @@ input CreateTaskInput {
description: String! description: String!
timeEstimate: Duration timeEstimate: Duration
assignedToId: ID assignedToId: ID
deadline: Datetime
} }
input UpdateTaskInput { input UpdateTaskInput {
@@ -6060,6 +6070,7 @@ input UpdateTaskInput {
description: String description: String
state: TaskState state: TaskState
timeEstimate: Duration timeEstimate: Duration
deadline: Datetime
} }
input DeleteTaskInput { input DeleteTaskInput {
@@ -12379,6 +12390,8 @@ func (ec *executionContext) fieldContext_AssignTaskPayload_task(_ context.Contex
return ec.fieldContext_Task_state(ctx, field) return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate": case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field) return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo": case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field) return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization": case "organization":
@@ -18910,6 +18923,8 @@ func (ec *executionContext) fieldContext_Evidence_task(_ context.Context, field
return ec.fieldContext_Task_state(ctx, field) return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate": case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field) return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo": case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field) return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization": case "organization":
@@ -28879,6 +28894,47 @@ func (ec *executionContext) fieldContext_Task_timeEstimate(_ context.Context, fi
return fc, nil return fc, nil
} }
func (ec *executionContext) _Task_deadline(ctx context.Context, field graphql.CollectedField, obj *types.Task) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Task_deadline(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Deadline, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*time.Time)
fc.Result = res
return ec.marshalODatetime2ᚖtimeᚐTime(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Task_deadline(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Task",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Datetime does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Task_assignedTo(ctx context.Context, field graphql.CollectedField, obj *types.Task) (ret graphql.Marshaler) { func (ec *executionContext) _Task_assignedTo(ctx context.Context, field graphql.CollectedField, obj *types.Task) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Task_assignedTo(ctx, field) fc, err := ec.fieldContext_Task_assignedTo(ctx, field)
if err != nil { if err != nil {
@@ -29431,6 +29487,8 @@ func (ec *executionContext) fieldContext_TaskEdge_node(_ context.Context, field
return ec.fieldContext_Task_state(ctx, field) return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate": case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field) return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo": case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field) return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization": case "organization":
@@ -29499,6 +29557,8 @@ func (ec *executionContext) fieldContext_UnassignTaskPayload_task(_ context.Cont
return ec.fieldContext_Task_state(ctx, field) return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate": case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field) return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo": case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field) return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization": case "organization":
@@ -30193,6 +30253,8 @@ func (ec *executionContext) fieldContext_UpdateTaskPayload_task(_ context.Contex
return ec.fieldContext_Task_state(ctx, field) return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate": case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field) return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo": case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field) return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization": case "organization":
@@ -36789,7 +36851,7 @@ func (ec *executionContext) unmarshalInputCreateTaskInput(ctx context.Context, o
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"organizationId", "measureId", "name", "description", "timeEstimate", "assignedToId"} fieldsInOrder := [...]string{"organizationId", "measureId", "name", "description", "timeEstimate", "assignedToId", "deadline"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -36838,6 +36900,13 @@ func (ec *executionContext) unmarshalInputCreateTaskInput(ctx context.Context, o
return it, err return it, err
} }
it.AssignedToID = data it.AssignedToID = data
case "deadline":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deadline"))
data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v)
if err != nil {
return it, err
}
it.Deadline = data
} }
} }
@@ -38947,7 +39016,7 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"taskId", "name", "description", "state", "timeEstimate"} fieldsInOrder := [...]string{"taskId", "name", "description", "state", "timeEstimate", "deadline"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -38989,6 +39058,13 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
return it, err return it, err
} }
it.TimeEstimate = data it.TimeEstimate = data
case "deadline":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deadline"))
data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v)
if err != nil {
return it, err
}
it.Deadline = data
} }
} }
@@ -46022,6 +46098,8 @@ func (ec *executionContext) _Task(ctx context.Context, sel ast.SelectionSet, obj
} }
case "timeEstimate": case "timeEstimate":
out.Values[i] = ec._Task_timeEstimate(ctx, field, obj) out.Values[i] = ec._Task_timeEstimate(ctx, field, obj)
case "deadline":
out.Values[i] = ec._Task_deadline(ctx, field, obj)
case "assignedTo": case "assignedTo":
field := field field := field

View File

@@ -52,5 +52,6 @@ func NewTask(t *coredata.Task) *Task {
TimeEstimate: t.TimeEstimate, TimeEstimate: t.TimeEstimate,
CreatedAt: t.CreatedAt, CreatedAt: t.CreatedAt,
UpdatedAt: t.UpdatedAt, UpdatedAt: t.UpdatedAt,
Deadline: t.Deadline,
} }
} }

View File

@@ -313,6 +313,7 @@ type CreateTaskInput struct {
Description string `json:"description"` Description string `json:"description"`
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"` TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
AssignedToID *gid.GID `json:"assignedToId,omitempty"` AssignedToID *gid.GID `json:"assignedToId,omitempty"`
Deadline *time.Time `json:"deadline,omitempty"`
} }
type CreateTaskPayload struct { type CreateTaskPayload struct {
@@ -934,6 +935,7 @@ type Task struct {
Description string `json:"description"` Description string `json:"description"`
State coredata.TaskState `json:"state"` State coredata.TaskState `json:"state"`
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"` TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
Deadline *time.Time `json:"deadline,omitempty"`
AssignedTo *People `json:"assignedTo,omitempty"` AssignedTo *People `json:"assignedTo,omitempty"`
Organization *Organization `json:"organization"` Organization *Organization `json:"organization"`
Measure *Measure `json:"measure,omitempty"` Measure *Measure `json:"measure,omitempty"`
@@ -1083,6 +1085,7 @@ type UpdateTaskInput struct {
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
State *coredata.TaskState `json:"state,omitempty"` State *coredata.TaskState `json:"state,omitempty"`
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"` TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
Deadline *time.Time `json:"deadline,omitempty"`
} }
type UpdateTaskPayload struct { type UpdateTaskPayload struct {

View File

@@ -1114,6 +1114,7 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTas
Name: input.Name, Name: input.Name,
Description: input.Description, Description: input.Description,
TimeEstimate: input.TimeEstimate, TimeEstimate: input.TimeEstimate,
Deadline: input.Deadline,
}) })
if err != nil { if err != nil {
panic(fmt.Errorf("cannot create task: %w", err)) panic(fmt.Errorf("cannot create task: %w", err))
@@ -1134,6 +1135,7 @@ func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTas
Description: input.Description, Description: input.Description,
State: input.State, State: input.State,
TimeEstimate: input.TimeEstimate, TimeEstimate: input.TimeEstimate,
Deadline: input.Deadline,
}) })
if err != nil { if err != nil {
panic(fmt.Errorf("cannot update task: %w", err)) panic(fmt.Errorf("cannot update task: %w", err))