Fix task display

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-01-05 12:58:42 +01:00
parent e077b5866f
commit 6ab5ace353
18 changed files with 216 additions and 655 deletions

View File

@@ -73,10 +73,7 @@ const createTaskSchema = z.object({
name: z.string().min(1),
description: z.string().optional().nullable(),
timeEstimate: z.string().optional().nullable(),
assignedToId: z.preprocess(
(val) => (val === "" || val == null ? undefined : val),
z.string({ required_error: "Assigned to is required" }).min(1, "Assigned to is required")
),
assignedToId: z.string().optional().nullable(),
measureId: z.preprocess(
(val) => (val === "" || val == null ? undefined : val),
z.string({ required_error: "Measure is required" }).min(1, "Measure is required")
@@ -88,7 +85,7 @@ const updateTaskSchema = z.object({
name: z.string().min(1),
description: z.string().optional().nullable(),
timeEstimate: z.string().optional().nullable(),
assignedToId: z.string().optional(),
assignedToId: z.string().optional().nullable(),
measureId: z.string().optional(),
deadline: z.string().optional().nullable(),
});
@@ -137,6 +134,7 @@ export default function TaskFormDialog(props: Props) {
description: data.description || null,
timeEstimate: data.timeEstimate || null,
deadline: formatDatetime(data.deadline) ?? null,
assignedToId: data.assignedToId ?? null,
},
},
});
@@ -149,7 +147,7 @@ export default function TaskFormDialog(props: Props) {
description: data.description || null,
timeEstimate: data.timeEstimate || null,
deadline: formatDatetime(data.deadline) ?? null,
assignedToId: data.assignedToId,
assignedToId: data.assignedToId || null,
measureId: data.measureId,
},
connections: [props.connection!],
@@ -165,7 +163,6 @@ export default function TaskFormDialog(props: Props) {
dialogRef.current?.close();
});
const showMeasure = !props.measureId && !isUpdating;
const isCreating = !isUpdating;
return (
<Dialog
@@ -198,18 +195,17 @@ export default function TaskFormDialog(props: Props) {
{/* Properties form */}
<div className="py-5 px-6 bg-subtle">
<Label>{__("Properties")}</Label>
{isCreating && (
<PropertyRow
label={__("Assigned to")}
error={formState.errors.assignedToId?.message}
>
<PeopleSelectField
name="assignedToId"
control={control}
organizationId={organizationId}
/>
</PropertyRow>
)}
<PropertyRow
label={__("Assigned to")}
error={formState.errors.assignedToId?.message}
>
<PeopleSelectField
name="assignedToId"
control={control}
organizationId={organizationId}
optional={true}
/>
</PropertyRow>
{showMeasure && (
<PropertyRow
label={__("Measure")}

View File

@@ -1,9 +1,8 @@
import { promisifyMutation } from "@probo/helpers";
import { promisifyMutation, formatDate, formatDuration } from "@probo/helpers";
import { usePageTitle } from "@probo/hooks";
import { useTranslate } from "@probo/i18n";
import {
ActionDropdown,
Avatar,
Card,
DropdownItem,
IconArrowCornerDownLeft,
@@ -40,6 +39,8 @@ type Props = {
name: string;
state: "TODO" | "DONE";
description?: string | null;
timeEstimate?: string | null;
deadline?: string | null;
measure?: {
id: string;
name: string;
@@ -128,7 +129,7 @@ export default function TasksCard({ tasks, connectionId }: Props) {
}
type TaskRowProps = {
task: ItemOf<Props["tasks"]> & TaskFormDialogFragment$key;
task: ItemOf<Props["tasks"]>;
connectionId: string;
hasAnyAction: boolean;
};
@@ -207,30 +208,48 @@ function TaskRow(props: TaskRowProps) {
<TaskStateIcon state={props.task.state} />
</button>
</div>
<div className="text-sm space-y-1">
<div className="text-sm space-y-1 flex-1">
<h2 className="font-medium">{props.task.name}</h2>
{props.task.measure && (
<p className="text-txt-secondary flex items-center gap-2">
<IconArrowCornerDownLeft className="scale-x-[-1]" size={16} />
<Link
className="hover:underline"
to={`/organizations/${organizationId}/measures/${props.task.measure?.id}`}
>
{props.task.measure?.name}
</Link>
{props.task.description && (
<p className="text-txt-secondary whitespace-pre-wrap break-words">
{props.task.description}
</p>
)}
<div className="flex flex-wrap items-center gap-3 text-txt-secondary text-xs">
{props.task.measure && (
<span className="flex items-center gap-1">
<IconArrowCornerDownLeft className="scale-x-[-1]" size={14} />
<Link
className="hover:underline"
to={`/organizations/${organizationId}/measures/${props.task.measure?.id}`}
>
{props.task.measure?.name}
</Link>
</span>
)}
{props.task.timeEstimate && (
<span>{formatDuration(props.task.timeEstimate, __)}</span>
)}
{props.task.deadline && (
<time dateTime={props.task.deadline}>
{formatDate(props.task.deadline)}
</time>
)}
</div>
</div>
</div>
{props.task.assignedTo?.fullName && (
<div className="text-sm text-txt-secondary ml-auto mr-8">
<Link
className="hover:underline"
to={`/organizations/${organizationId}/people/${props.task.assignedTo.id}`}
>
{props.task.assignedTo.fullName}
</Link>
</div>
)}
<div className="flex gap-2 items-center">
{isUpdating && <Spinner size={16} />}
{props.task.assignedTo && (
<Link
to={`/organizations/${organizationId}/people/${props.task.assignedTo?.id}`}
>
<Avatar name={props.task.assignedTo?.fullName ?? ""} />
</Link>
)}
{props.hasAnyAction && (
<ActionDropdown>
{isAuthorized("Task", "updateTask") && (

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<1cc9998f8dcbb02ac977744023d372d6>>
* @generated SignedSource<<1d9eed2918f5f58de18ef4ea5f0058b7>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type TaskState = "DONE" | "TODO";
export type UpdateTaskInput = {
assignedToId?: string | null | undefined;
deadline?: any | null | undefined;
description?: string | null | undefined;
name?: string | null | undefined;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<cff26152bf46e7734e8ae5f5671b47b6>>
* @generated SignedSource<<40ebf241dc89f4b4b1705e4a2fabb935>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -296,12 +296,12 @@ return {
]
},
"params": {
"cacheID": "a0b3367a3288c70f0bbcde73ec237bee",
"cacheID": "72cbeaa7667c477f85e5c3ecb09b7bf4",
"id": null,
"metadata": {},
"name": "TaskGraphQuery",
"operationKind": "query",
"text": "query TaskGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n ...TasksPageFragment\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment on Organization {\n tasks(first: 500) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\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 hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
"text": "query TaskGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n ...TasksPageFragment\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment on Organization {\n tasks(first: 500) {\n edges {\n node {\n id\n name\n state\n description\n timeEstimate\n deadline\n ...TaskFormDialogFragment\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 hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();

View File

@@ -20,6 +20,8 @@ const tasksQuery = graphql`
name
state
description
timeEstimate
deadline
...TaskFormDialogFragment
assignedTo {
id

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<f2e7ca902ae7ee08f260f27a0fefa043>>
* @generated SignedSource<<f1100222ab7c7aeff0f7643640ecc23c>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -25,10 +25,12 @@ export type MeasureTasksTabQuery$data = {
readonly fullName: string;
readonly id: string;
} | null | undefined;
readonly deadline: any | null | undefined;
readonly description: string | null | undefined;
readonly id: string;
readonly name: string;
readonly state: TaskState;
readonly timeEstimate: any | null | undefined;
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
};
}>;
@@ -84,6 +86,20 @@ v5 = {
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "timeEstimate",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"concreteType": "People",
@@ -102,21 +118,21 @@ v6 = {
],
"storageKey": null
},
v7 = {
v9 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v8 = {
v10 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v9 = {
v11 = {
"alias": null,
"args": null,
"concreteType": "PageInfo",
@@ -141,7 +157,7 @@ v9 = {
],
"storageKey": null
},
v10 = {
v12 = {
"kind": "ClientExtension",
"selections": [
{
@@ -153,7 +169,7 @@ v10 = {
}
]
},
v11 = [
v13 = [
{
"kind": "Literal",
"name": "first",
@@ -207,22 +223,24 @@ return {
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "TaskFormDialogFragment"
},
(v6/*: any*/),
(v7/*: any*/)
(v8/*: any*/),
(v9/*: any*/)
],
"storageKey": null
},
(v8/*: any*/)
(v10/*: any*/)
],
"storageKey": null
},
(v9/*: any*/),
(v10/*: any*/)
(v11/*: any*/),
(v12/*: any*/)
],
"storageKey": null
}
@@ -251,14 +269,14 @@ return {
"name": "node",
"plural": false,
"selections": [
(v7/*: any*/),
(v9/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v11/*: any*/),
"args": (v13/*: any*/),
"concreteType": "TaskConnection",
"kind": "LinkedField",
"name": "tasks",
@@ -284,21 +302,9 @@ return {
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "timeEstimate",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
@@ -311,22 +317,22 @@ return {
],
"storageKey": null
},
(v7/*: any*/)
(v9/*: any*/)
],
"storageKey": null
},
(v8/*: any*/)
(v10/*: any*/)
],
"storageKey": null
},
(v9/*: any*/),
(v10/*: any*/)
(v11/*: any*/),
(v12/*: any*/)
],
"storageKey": "tasks(first:100)"
},
{
"alias": null,
"args": (v11/*: any*/),
"args": (v13/*: any*/),
"filters": null,
"handle": "connection",
"key": "Measure__tasks",
@@ -343,7 +349,7 @@ return {
]
},
"params": {
"cacheID": "bc71d01128d96026a1e630b96e649409",
"cacheID": "7988e2a18d5929fe99d9cef8de244627",
"id": null,
"metadata": {
"connection": [
@@ -360,11 +366,11 @@ return {
},
"name": "MeasureTasksTabQuery",
"operationKind": "query",
"text": "query MeasureTasksTabQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n tasks(first: 100) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n"
"text": "query MeasureTasksTabQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n tasks(first: 100) {\n edges {\n node {\n id\n name\n state\n description\n timeEstimate\n deadline\n ...TaskFormDialogFragment\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n"
}
};
})();
(node as any).hash = "12445eb032af3bc00fea9edce6f427e2";
(node as any).hash = "358a07bb3e13ea9828d0703541caf894";
export default node;

View File

@@ -39,6 +39,8 @@ const tasksFragment = graphql`
name
state
description
timeEstimate
deadline
...TaskFormDialogFragment
measure {
id

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<8bba8d318de0f4b0d28a8fba8b8e0bdf>>
* @generated SignedSource<<f6e71f80c25925eb372e360c1b9ec122>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -21,6 +21,7 @@ export type TasksPageFragment$data = {
readonly fullName: string;
readonly id: string;
} | null | undefined;
readonly deadline: any | null | undefined;
readonly description: string | null | undefined;
readonly id: string;
readonly measure: {
@@ -29,6 +30,7 @@ export type TasksPageFragment$data = {
} | null | undefined;
readonly name: string;
readonly state: TaskState;
readonly timeEstimate: any | null | undefined;
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
};
}>;
@@ -168,6 +170,20 @@ return {
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "timeEstimate",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{
"args": null,
"kind": "FragmentSpread",
@@ -286,6 +302,6 @@ return {
};
})();
(node as any).hash = "84864638db9ddf53e9ae7da7952803af";
(node as any).hash = "466d3b82119334991a0714bb0b7cd6d0";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<46a3b0baa64ec5a6a1c6d289a3737ade>>
* @generated SignedSource<<e765e52f0386640e282459c13a3e9769>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -369,16 +369,16 @@ return {
]
},
"params": {
"cacheID": "58db4c11a870b12c21eef1c6f24271b0",
"cacheID": "d31450ee0ddd09b0e08b43c9f7728f5f",
"id": null,
"metadata": {},
"name": "TasksPageFragment_query",
"operationKind": "query",
"text": "query TasksPageFragment_query(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 500\n $last: Int = null\n $order: TaskOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...TasksPageFragment_16fISc\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment_16fISc on Organization {\n tasks(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\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 hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
"text": "query TasksPageFragment_query(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 500\n $last: Int = null\n $order: TaskOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...TasksPageFragment_16fISc\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment_16fISc on Organization {\n tasks(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n name\n state\n description\n timeEstimate\n deadline\n ...TaskFormDialogFragment\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 hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "84864638db9ddf53e9ae7da7952803af";
(node as any).hash = "466d3b82119334991a0714bb0b7cd6d0";
export default node;

View File

@@ -33,8 +33,8 @@ func TestTask_Assign(t *testing.T) {
peopleID := factory.NewPeople(owner).WithFullName("Task Assignee").Create()
query := `
mutation AssignTask($input: AssignTaskInput!) {
assignTask(input: $input) {
mutation UpdateTask($input: UpdateTaskInput!) {
updateTask(input: $input) {
task {
id
assignedTo {
@@ -47,7 +47,7 @@ func TestTask_Assign(t *testing.T) {
`
var result struct {
AssignTask struct {
UpdateTask struct {
Task struct {
ID string `json:"id"`
AssignedTo struct {
@@ -55,7 +55,7 @@ func TestTask_Assign(t *testing.T) {
FullName string `json:"fullName"`
} `json:"assignedTo"`
} `json:"task"`
} `json:"assignTask"`
} `json:"updateTask"`
}
err := owner.Execute(query, map[string]any{
@@ -66,9 +66,9 @@ func TestTask_Assign(t *testing.T) {
}, &result)
require.NoError(t, err)
assert.Equal(t, taskID, result.AssignTask.Task.ID)
assert.Equal(t, peopleID, result.AssignTask.Task.AssignedTo.ID)
assert.Equal(t, "Task Assignee", result.AssignTask.Task.AssignedTo.FullName)
assert.Equal(t, taskID, result.UpdateTask.Task.ID)
assert.Equal(t, peopleID, result.UpdateTask.Task.AssignedTo.ID)
assert.Equal(t, "Task Assignee", result.UpdateTask.Task.AssignedTo.FullName)
}
func TestTask_Unassign(t *testing.T) {
@@ -82,8 +82,8 @@ func TestTask_Unassign(t *testing.T) {
// First assign the task
assignQuery := `
mutation AssignTask($input: AssignTaskInput!) {
assignTask(input: $input) {
mutation UpdateTask($input: UpdateTaskInput!) {
updateTask(input: $input) {
task {
id
}
@@ -100,8 +100,8 @@ func TestTask_Unassign(t *testing.T) {
require.NoError(t, err)
query := `
mutation UnassignTask($input: UnassignTaskInput!) {
unassignTask(input: $input) {
mutation UpdateTask($input: UpdateTaskInput!) {
updateTask(input: $input) {
task {
id
assignedTo {
@@ -113,23 +113,24 @@ func TestTask_Unassign(t *testing.T) {
`
var result struct {
UnassignTask struct {
UpdateTask struct {
Task struct {
ID string `json:"id"`
AssignedTo *struct {
ID string `json:"id"`
} `json:"assignedTo"`
} `json:"task"`
} `json:"unassignTask"`
} `json:"updateTask"`
}
err = owner.Execute(query, map[string]any{
"input": map[string]any{
"taskId": taskID,
"taskId": taskID,
"assignedToId": nil,
},
}, &result)
require.NoError(t, err)
assert.Equal(t, taskID, result.UnassignTask.Task.ID)
assert.Nil(t, result.UnassignTask.Task.AssignedTo)
assert.Equal(t, taskID, result.UpdateTask.Task.ID)
assert.Nil(t, result.UpdateTask.Task.AssignedTo)
}

View File

@@ -615,8 +615,8 @@ func TestTask_OmittableAssignee(t *testing.T) {
t.Run("set assignee", func(t *testing.T) {
query := `
mutation AssignTask($input: AssignTaskInput!) {
assignTask(input: $input) {
mutation UpdateTask($input: UpdateTaskInput!) {
updateTask(input: $input) {
task {
id
assignedTo {
@@ -629,7 +629,7 @@ func TestTask_OmittableAssignee(t *testing.T) {
`
var result struct {
AssignTask struct {
UpdateTask struct {
Task struct {
ID string `json:"id"`
AssignedTo struct {
@@ -637,7 +637,7 @@ func TestTask_OmittableAssignee(t *testing.T) {
FullName string `json:"fullName"`
} `json:"assignedTo"`
} `json:"task"`
} `json:"assignTask"`
} `json:"updateTask"`
}
err := owner.Execute(query, map[string]any{
@@ -647,13 +647,13 @@ func TestTask_OmittableAssignee(t *testing.T) {
},
}, &result)
require.NoError(t, err)
assert.Equal(t, peopleID, result.AssignTask.Task.AssignedTo.ID)
assert.Equal(t, peopleID, result.UpdateTask.Task.AssignedTo.ID)
})
t.Run("clear assignee", func(t *testing.T) {
query := `
mutation UnassignTask($input: UnassignTaskInput!) {
unassignTask(input: $input) {
mutation UpdateTask($input: UpdateTaskInput!) {
updateTask(input: $input) {
task {
id
assignedTo {
@@ -665,23 +665,24 @@ func TestTask_OmittableAssignee(t *testing.T) {
`
var result struct {
UnassignTask struct {
UpdateTask struct {
Task struct {
ID string `json:"id"`
AssignedTo *struct {
ID string `json:"id"`
} `json:"assignedTo"`
} `json:"task"`
} `json:"unassignTask"`
} `json:"updateTask"`
}
err := owner.Execute(query, map[string]any{
"input": map[string]any{
"taskId": taskID,
"taskId": taskID,
"assignedToId": nil,
},
}, &result)
require.NoError(t, err)
assert.Nil(t, result.UnassignTask.Task.AssignedTo)
assert.Nil(t, result.UpdateTask.Task.AssignedTo)
})
}

View File

@@ -26,3 +26,36 @@ function parseDate(dateString: string): Date {
parts[2] ? parseInt(parts[2], 10) : 1
);
}
export function formatDuration(duration?: string | null, __?: (s: string) => string): string | null {
if (!duration || !__) return null;
const timeMatch = duration.match(/PT(\d+)([MH])/);
if (timeMatch) {
const amount = parseInt(timeMatch[1], 10) || 0;
const unit = timeMatch[2];
if (unit === "M") {
return `${amount} ${amount === 1 ? __("Minute") : __("Minutes")}`;
} else if (unit === "H") {
return `${amount} ${amount === 1 ? __("Hour") : __("Hours")}`;
}
}
const dateMatch = duration.match(/P(\d+)([DW])/);
if (dateMatch) {
const amount = parseInt(dateMatch[1], 10) || 0;
const unit = dateMatch[2];
if (unit === "W") {
return `${amount} ${amount === 1 ? __("Week") : __("Weeks")}`;
} else if (unit === "D") {
const days = amount;
if (days % 7 === 0 && days > 0) {
const weeks = days / 7;
return `${weeks} ${weeks === 1 ? __("Week") : __("Weeks")}`;
}
return `${days} ${days === 1 ? __("Day") : __("Days")}`;
}
}
return null;
}

View File

@@ -61,7 +61,7 @@ export {
} from "./trustCenterVisibility";
export { promisifyMutation } from "./relay";
export { fileType, fileSize } from "./file";
export { formatDatetime, formatDate, toDateInput } from "./date";
export { formatDatetime, formatDate, toDateInput, formatDuration } from "./date";
export { getTrustCenterUrl } from "./trustCenter";
export { formatError, type GraphQLError } from "./error";
export { Role, getAssignableRoles } from "./roles";

View File

@@ -49,6 +49,7 @@ type (
State *coredata.TaskState
TimeEstimate **time.Duration
Deadline **time.Time
AssignedToID **gid.GID
}
)
@@ -73,6 +74,7 @@ func (utr *UpdateTaskRequest) Validate() error {
v.Check(utr.Description, "description", validator.SafeText(ContentMaxLength))
v.Check(utr.TimeEstimate, "time_estimate", validator.RangeDuration(0, 1000*time.Hour))
v.Check(utr.State, "state", validator.OneOfSlice(coredata.TaskStates()))
v.Check(utr.AssignedToID, "assigned_to_id", validator.GID(coredata.PeopleEntityType))
return v.Error()
}
@@ -261,6 +263,18 @@ func (s TaskService) Update(
task.Deadline = *req.Deadline
}
if req.AssignedToID != nil {
if *req.AssignedToID == nil {
task.AssignedToID = nil
} else {
people := &coredata.People{}
if err := people.LoadByID(ctx, conn, s.svc.scope, **req.AssignedToID); err != nil {
return fmt.Errorf("cannot load assignee: %w", err)
}
task.AssignedToID = *req.AssignedToID
}
}
task.UpdatedAt = time.Now()
if err := task.Update(ctx, conn, s.svc.scope); err != nil {

View File

@@ -3104,8 +3104,6 @@ type Mutation {
createTask(input: CreateTaskInput!): CreateTaskPayload!
updateTask(input: UpdateTaskInput!): UpdateTaskPayload!
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
assignTask(input: AssignTaskInput!): AssignTaskPayload!
unassignTask(input: UnassignTaskInput!): UnassignTaskPayload!
# Risk mutations
createRisk(input: CreateRiskInput!): CreateRiskPayload!
updateRisk(input: UpdateRiskInput!): UpdateRiskPayload!
@@ -3609,20 +3607,13 @@ input UpdateTaskInput {
state: TaskState
timeEstimate: Duration @goField(omittable: true)
deadline: Datetime @goField(omittable: true)
assignedToId: ID @goField(omittable: true)
}
input DeleteTaskInput {
taskId: ID!
}
input AssignTaskInput {
taskId: ID!
assignedToId: ID!
}
input UnassignTaskInput {
taskId: ID!
}
input CreateControlMeasureMappingInput {
controlId: ID!
@@ -4321,13 +4312,6 @@ type DeleteTaskPayload {
deletedTaskId: ID!
}
type AssignTaskPayload {
task: Task!
}
type UnassignTaskPayload {
task: Task!
}
type CreateControlMeasureMappingPayload {
controlEdge: ControlEdge!

View File

@@ -154,10 +154,6 @@ type ComplexityRoot struct {
Node func(childComplexity int) int
}
AssignTaskPayload struct {
Task func(childComplexity int) int
}
Audit struct {
Controls func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) int
CreatedAt func(childComplexity int) int
@@ -947,7 +943,6 @@ type ComplexityRoot struct {
Mutation struct {
AcceptInvitation func(childComplexity int, input types.AcceptInvitationInput) int
AssessVendor func(childComplexity int, input types.AssessVendorInput) int
AssignTask func(childComplexity int, input types.AssignTaskInput) int
BulkDeleteDocuments func(childComplexity int, input types.BulkDeleteDocumentsInput) int
BulkExportDocuments func(childComplexity int, input types.BulkExportDocumentsInput) int
BulkPublishDocumentVersions func(childComplexity int, input types.BulkPublishDocumentVersionsInput) int
@@ -1050,7 +1045,6 @@ type ComplexityRoot struct {
RequestSignature func(childComplexity int, input types.RequestSignatureInput) int
SendSigningNotifications func(childComplexity int, input types.SendSigningNotificationsInput) int
SignDocument func(childComplexity int, input types.SignDocumentInput) int
UnassignTask func(childComplexity int, input types.UnassignTaskInput) int
UpdateAsset func(childComplexity int, input types.UpdateAssetInput) int
UpdateAudit func(childComplexity int, input types.UpdateAuditInput) int
UpdateContinualImprovement func(childComplexity int, input types.UpdateContinualImprovementInput) int
@@ -1605,10 +1599,6 @@ type ComplexityRoot struct {
Node func(childComplexity int) int
}
UnassignTaskPayload struct {
Task func(childComplexity int) int
}
UpdateAssetPayload struct {
Asset func(childComplexity int) int
}
@@ -2127,8 +2117,6 @@ type MutationResolver interface {
CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error)
UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error)
DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error)
AssignTask(ctx context.Context, input types.AssignTaskInput) (*types.AssignTaskPayload, error)
UnassignTask(ctx context.Context, input types.UnassignTaskInput) (*types.UnassignTaskPayload, error)
CreateRisk(ctx context.Context, input types.CreateRiskInput) (*types.CreateRiskPayload, error)
UpdateRisk(ctx context.Context, input types.UpdateRiskInput) (*types.UpdateRiskPayload, error)
DeleteRisk(ctx context.Context, input types.DeleteRiskInput) (*types.DeleteRiskPayload, error)
@@ -2549,13 +2537,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.AssetEdge.Node(childComplexity), true
case "AssignTaskPayload.task":
if e.complexity.AssignTaskPayload.Task == nil {
break
}
return e.complexity.AssignTaskPayload.Task(childComplexity), true
case "Audit.controls":
if e.complexity.Audit.Controls == nil {
break
@@ -4916,17 +4897,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
}
return e.complexity.Mutation.AssessVendor(childComplexity, args["input"].(types.AssessVendorInput)), true
case "Mutation.assignTask":
if e.complexity.Mutation.AssignTask == nil {
break
}
args, err := ec.field_Mutation_assignTask_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.AssignTask(childComplexity, args["input"].(types.AssignTaskInput)), true
case "Mutation.bulkDeleteDocuments":
if e.complexity.Mutation.BulkDeleteDocuments == nil {
break
@@ -6049,17 +6019,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
}
return e.complexity.Mutation.SignDocument(childComplexity, args["input"].(types.SignDocumentInput)), true
case "Mutation.unassignTask":
if e.complexity.Mutation.UnassignTask == nil {
break
}
args, err := ec.field_Mutation_unassignTask_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.UnassignTask(childComplexity, args["input"].(types.UnassignTaskInput)), true
case "Mutation.updateAsset":
if e.complexity.Mutation.UpdateAsset == nil {
break
@@ -8718,13 +8677,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterReferenceEdge.Node(childComplexity), true
case "UnassignTaskPayload.task":
if e.complexity.UnassignTaskPayload.Task == nil {
break
}
return e.complexity.UnassignTaskPayload.Task(childComplexity), true
case "UpdateAssetPayload.asset":
if e.complexity.UpdateAssetPayload.Asset == nil {
break
@@ -9755,7 +9707,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputAssessVendorInput,
ec.unmarshalInputAssetFilter,
ec.unmarshalInputAssetOrder,
ec.unmarshalInputAssignTaskInput,
ec.unmarshalInputAuditOrder,
ec.unmarshalInputBulkDeleteDocumentsInput,
ec.unmarshalInputBulkExportDocumentsInput,
@@ -9904,7 +9855,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputTrustCenterDocumentAccessOrder,
ec.unmarshalInputTrustCenterFileOrder,
ec.unmarshalInputTrustCenterReferenceOrder,
ec.unmarshalInputUnassignTaskInput,
ec.unmarshalInputUpdateAssetInput,
ec.unmarshalInputUpdateAuditInput,
ec.unmarshalInputUpdateContinualImprovementInput,
@@ -13153,8 +13103,6 @@ type Mutation {
createTask(input: CreateTaskInput!): CreateTaskPayload!
updateTask(input: UpdateTaskInput!): UpdateTaskPayload!
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
assignTask(input: AssignTaskInput!): AssignTaskPayload!
unassignTask(input: UnassignTaskInput!): UnassignTaskPayload!
# Risk mutations
createRisk(input: CreateRiskInput!): CreateRiskPayload!
updateRisk(input: UpdateRiskInput!): UpdateRiskPayload!
@@ -13658,20 +13606,13 @@ input UpdateTaskInput {
state: TaskState
timeEstimate: Duration @goField(omittable: true)
deadline: Datetime @goField(omittable: true)
assignedToId: ID @goField(omittable: true)
}
input DeleteTaskInput {
taskId: ID!
}
input AssignTaskInput {
taskId: ID!
assignedToId: ID!
}
input UnassignTaskInput {
taskId: ID!
}
input CreateControlMeasureMappingInput {
controlId: ID!
@@ -14370,13 +14311,6 @@ type DeleteTaskPayload {
deletedTaskId: ID!
}
type AssignTaskPayload {
task: Task!
}
type UnassignTaskPayload {
task: Task!
}
type CreateControlMeasureMappingPayload {
controlEdge: ControlEdge!
@@ -15835,17 +15769,6 @@ func (ec *executionContext) field_Mutation_assessVendor_args(ctx context.Context
return args, nil
}
func (ec *executionContext) field_Mutation_assignTask_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNAssignTaskInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskInput)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_bulkDeleteDocuments_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -16968,17 +16891,6 @@ func (ec *executionContext) field_Mutation_signDocument_args(ctx context.Context
return args, nil
}
func (ec *executionContext) field_Mutation_unassignTask_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNUnassignTaskInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskInput)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_updateAsset_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -19591,61 +19503,6 @@ func (ec *executionContext) fieldContext_AssetEdge_node(_ context.Context, field
return fc, nil
}
func (ec *executionContext) _AssignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.AssignTaskPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_AssignTaskPayload_task,
func(ctx context.Context) (any, error) {
return obj.Task, nil
},
nil,
ec.marshalNTask2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTask,
true,
true,
)
}
func (ec *executionContext) fieldContext_AssignTaskPayload_task(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "AssignTaskPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Task_id(ctx, field)
case "name":
return ec.fieldContext_Task_name(ctx, field)
case "description":
return ec.fieldContext_Task_description(ctx, field)
case "state":
return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization":
return ec.fieldContext_Task_organization(ctx, field)
case "measure":
return ec.fieldContext_Task_measure(ctx, field)
case "evidences":
return ec.fieldContext_Task_evidences(ctx, field)
case "createdAt":
return ec.fieldContext_Task_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_Task_updatedAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Task", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _Audit_id(ctx context.Context, field graphql.CollectedField, obj *types.Audit) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -35210,96 +35067,6 @@ func (ec *executionContext) fieldContext_Mutation_deleteTask(ctx context.Context
return fc, nil
}
func (ec *executionContext) _Mutation_assignTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Mutation_assignTask,
func(ctx context.Context) (any, error) {
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().AssignTask(ctx, fc.Args["input"].(types.AssignTaskInput))
},
nil,
ec.marshalNAssignTaskPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskPayload,
true,
true,
)
}
func (ec *executionContext) fieldContext_Mutation_assignTask(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "task":
return ec.fieldContext_AssignTaskPayload_task(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type AssignTaskPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_assignTask_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_unassignTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Mutation_unassignTask,
func(ctx context.Context) (any, error) {
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().UnassignTask(ctx, fc.Args["input"].(types.UnassignTaskInput))
},
nil,
ec.marshalNUnassignTaskPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskPayload,
true,
true,
)
}
func (ec *executionContext) fieldContext_Mutation_unassignTask(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "task":
return ec.fieldContext_UnassignTaskPayload_task(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type UnassignTaskPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_unassignTask_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_createRisk(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -51510,61 +51277,6 @@ func (ec *executionContext) fieldContext_TrustCenterReferenceEdge_node(_ context
return fc, nil
}
func (ec *executionContext) _UnassignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.UnassignTaskPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_UnassignTaskPayload_task,
func(ctx context.Context) (any, error) {
return obj.Task, nil
},
nil,
ec.marshalNTask2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTask,
true,
true,
)
}
func (ec *executionContext) fieldContext_UnassignTaskPayload_task(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "UnassignTaskPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Task_id(ctx, field)
case "name":
return ec.fieldContext_Task_name(ctx, field)
case "description":
return ec.fieldContext_Task_description(ctx, field)
case "state":
return ec.fieldContext_Task_state(ctx, field)
case "timeEstimate":
return ec.fieldContext_Task_timeEstimate(ctx, field)
case "deadline":
return ec.fieldContext_Task_deadline(ctx, field)
case "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field)
case "organization":
return ec.fieldContext_Task_organization(ctx, field)
case "measure":
return ec.fieldContext_Task_measure(ctx, field)
case "evidences":
return ec.fieldContext_Task_evidences(ctx, field)
case "createdAt":
return ec.fieldContext_Task_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_Task_updatedAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Task", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _UpdateAssetPayload_asset(ctx context.Context, field graphql.CollectedField, obj *types.UpdateAssetPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -59571,40 +59283,6 @@ func (ec *executionContext) unmarshalInputAssetOrder(ctx context.Context, obj an
return it, nil
}
func (ec *executionContext) unmarshalInputAssignTaskInput(ctx context.Context, obj any) (types.AssignTaskInput, error) {
var it types.AssignTaskInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"taskId", "assignedToId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "taskId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("taskId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.TaskID = data
case "assignedToId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("assignedToId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.AssignedToID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputAuditOrder(ctx context.Context, obj any) (types.AuditOrderBy, error) {
var it types.AuditOrderBy
asMap := map[string]any{}
@@ -65337,33 +65015,6 @@ func (ec *executionContext) unmarshalInputTrustCenterReferenceOrder(ctx context.
return it, nil
}
func (ec *executionContext) unmarshalInputUnassignTaskInput(ctx context.Context, obj any) (types.UnassignTaskInput, error) {
var it types.UnassignTaskInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"taskId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "taskId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("taskId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.TaskID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputUpdateAssetInput(ctx context.Context, obj any) (types.UpdateAssetInput, error) {
var it types.UpdateAssetInput
asMap := map[string]any{}
@@ -66807,7 +66458,7 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
asMap[k] = v
}
fieldsInOrder := [...]string{"taskId", "name", "description", "state", "timeEstimate", "deadline"}
fieldsInOrder := [...]string{"taskId", "name", "description", "state", "timeEstimate", "deadline", "assignedToId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -66856,6 +66507,13 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
return it, err
}
it.Deadline = graphql.OmittableOf(data)
case "assignedToId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("assignedToId"))
data, err := ec.unmarshalOID2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.AssignedToID = graphql.OmittableOf(data)
}
}
@@ -68716,45 +68374,6 @@ func (ec *executionContext) _AssetEdge(ctx context.Context, sel ast.SelectionSet
return out
}
var assignTaskPayloadImplementors = []string{"AssignTaskPayload"}
func (ec *executionContext) _AssignTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *types.AssignTaskPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, assignTaskPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("AssignTaskPayload")
case "task":
out.Values[i] = ec._AssignTaskPayload_task(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var auditImplementors = []string{"Audit", "Node"}
func (ec *executionContext) _Audit(ctx context.Context, sel ast.SelectionSet, obj *types.Audit) graphql.Marshaler {
@@ -77466,20 +77085,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "assignTask":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_assignTask(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "unassignTask":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_unassignTask(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "createRisk":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_createRisk(ctx, field)
@@ -84213,45 +83818,6 @@ func (ec *executionContext) _TrustCenterReferenceEdge(ctx context.Context, sel a
return out
}
var unassignTaskPayloadImplementors = []string{"UnassignTaskPayload"}
func (ec *executionContext) _UnassignTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UnassignTaskPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, unassignTaskPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("UnassignTaskPayload")
case "task":
out.Values[i] = ec._UnassignTaskPayload_task(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var updateAssetPayloadImplementors = []string{"UpdateAssetPayload"}
func (ec *executionContext) _UpdateAssetPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateAssetPayload) graphql.Marshaler {
@@ -88155,25 +87721,6 @@ var (
}
)
func (ec *executionContext) unmarshalNAssignTaskInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskInput(ctx context.Context, v any) (types.AssignTaskInput, error) {
res, err := ec.unmarshalInputAssignTaskInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNAssignTaskPayload2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskPayload(ctx context.Context, sel ast.SelectionSet, v types.AssignTaskPayload) graphql.Marshaler {
return ec._AssignTaskPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNAssignTaskPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskPayload(ctx context.Context, sel ast.SelectionSet, v *types.AssignTaskPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._AssignTaskPayload(ctx, sel, v)
}
func (ec *executionContext) marshalNAudit2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAudit(ctx context.Context, sel ast.SelectionSet, v *types.Audit) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
@@ -95238,25 +94785,6 @@ var (
}
)
func (ec *executionContext) unmarshalNUnassignTaskInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskInput(ctx context.Context, v any) (types.UnassignTaskInput, error) {
res, err := ec.unmarshalInputUnassignTaskInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNUnassignTaskPayload2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskPayload(ctx context.Context, sel ast.SelectionSet, v types.UnassignTaskPayload) graphql.Marshaler {
return ec._UnassignTaskPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNUnassignTaskPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskPayload(ctx context.Context, sel ast.SelectionSet, v *types.UnassignTaskPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._UnassignTaskPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNUpdateAssetInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateAssetInput(ctx context.Context, v any) (types.UpdateAssetInput, error) {
res, err := ec.unmarshalInputUpdateAssetInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)

View File

@@ -64,15 +64,6 @@ type AssetFilter struct {
SnapshotID *gid.GID `json:"snapshotId,omitempty"`
}
type AssignTaskInput struct {
TaskID gid.GID `json:"taskId"`
AssignedToID gid.GID `json:"assignedToId"`
}
type AssignTaskPayload struct {
Task *Task `json:"task"`
}
type Audit struct {
ID gid.GID `json:"id"`
Name *string `json:"name,omitempty"`
@@ -1959,14 +1950,6 @@ type TrustCenterReferenceEdge struct {
Node *TrustCenterReference `json:"node"`
}
type UnassignTaskInput struct {
TaskID gid.GID `json:"taskId"`
}
type UnassignTaskPayload struct {
Task *Task `json:"task"`
}
type UpdateAssetInput struct {
ID gid.GID `json:"id"`
Name *string `json:"name,omitempty"`
@@ -2262,6 +2245,7 @@ type UpdateTaskInput struct {
State *coredata.TaskState `json:"state,omitempty"`
TimeEstimate graphql.Omittable[*time.Duration] `json:"timeEstimate,omitempty"`
Deadline graphql.Omittable[*time.Time] `json:"deadline,omitempty"`
AssignedToID graphql.Omittable[*gid.GID] `json:"assignedToId,omitempty"`
}
type UpdateTaskPayload struct {

View File

@@ -2798,6 +2798,7 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTas
Name: input.Name,
Description: input.Description,
TimeEstimate: input.TimeEstimate,
AssignedToID: input.AssignedToID,
Deadline: input.Deadline,
})
if err != nil {
@@ -2826,6 +2827,7 @@ func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTas
State: input.State,
TimeEstimate: UnwrapOmittable(input.TimeEstimate),
Deadline: UnwrapOmittable(input.Deadline),
AssignedToID: UnwrapOmittable(input.AssignedToID),
})
if err != nil {
panic(fmt.Errorf("cannot update task: %w", err))
@@ -2852,34 +2854,6 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTas
}, nil
}
// AssignTask is the resolver for the assignTask field.
func (r *mutationResolver) AssignTask(ctx context.Context, input types.AssignTaskInput) (*types.AssignTaskPayload, error) {
prb := r.ProboService(ctx, input.TaskID.TenantID())
task, err := prb.Tasks.Assign(ctx, input.TaskID, input.AssignedToID)
if err != nil {
panic(fmt.Errorf("cannot assign task: %w", err))
}
return &types.AssignTaskPayload{
Task: types.NewTask(task),
}, nil
}
// UnassignTask is the resolver for the unassignTask field.
func (r *mutationResolver) UnassignTask(ctx context.Context, input types.UnassignTaskInput) (*types.UnassignTaskPayload, error) {
prb := r.ProboService(ctx, input.TaskID.TenantID())
task, err := prb.Tasks.Unassign(ctx, input.TaskID)
if err != nil {
panic(fmt.Errorf("cannot unassign task: %w", err))
}
return &types.UnassignTaskPayload{
Task: types.NewTask(task),
}, nil
}
// CreateRisk is the resolver for the createRisk field.
func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRiskInput) (*types.CreateRiskPayload, error) {
r.MustBeAuthorized(ctx, input.OrganizationID, authz.ActionCreateRisk)