Add assigned people to a task

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-13 10:08:31 +01:00
parent 376edd927d
commit 8cbe08d136
15 changed files with 1881 additions and 61 deletions

View File

@@ -31,6 +31,9 @@ import {
FileText, FileText,
Image, Image,
X, X,
UserPlus,
UserMinus,
User,
} from "lucide-react"; } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { useToast } from "@/hooks/use-toast"; import { useToast } from "@/hooks/use-toast";
@@ -46,6 +49,11 @@ import {
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Helmet } from "react-helmet-async"; import { Helmet } from "react-helmet-async";
import type { ControlOverviewPageQuery as ControlOverviewPageQueryType } from "./__generated__/ControlOverviewPageQuery.graphql"; import type { ControlOverviewPageQuery as ControlOverviewPageQueryType } from "./__generated__/ControlOverviewPageQuery.graphql";
@@ -54,6 +62,9 @@ import type { ControlOverviewPageCreateTaskMutation as ControlOverviewPageCreate
import type { ControlOverviewPageDeleteTaskMutation as ControlOverviewPageDeleteTaskMutationType } from "./__generated__/ControlOverviewPageDeleteTaskMutation.graphql"; import type { ControlOverviewPageDeleteTaskMutation as ControlOverviewPageDeleteTaskMutationType } from "./__generated__/ControlOverviewPageDeleteTaskMutation.graphql";
import type { ControlOverviewPageUploadEvidenceMutation as ControlOverviewPageUploadEvidenceMutationType } from "./__generated__/ControlOverviewPageUploadEvidenceMutation.graphql"; import type { ControlOverviewPageUploadEvidenceMutation as ControlOverviewPageUploadEvidenceMutationType } from "./__generated__/ControlOverviewPageUploadEvidenceMutation.graphql";
import type { ControlOverviewPageDeleteEvidenceMutation as ControlOverviewPageDeleteEvidenceMutationType } from "./__generated__/ControlOverviewPageDeleteEvidenceMutation.graphql"; import type { ControlOverviewPageDeleteEvidenceMutation as ControlOverviewPageDeleteEvidenceMutationType } from "./__generated__/ControlOverviewPageDeleteEvidenceMutation.graphql";
import type { ControlOverviewPageAssignTaskMutation as ControlOverviewPageAssignTaskMutationType } from "./__generated__/ControlOverviewPageAssignTaskMutation.graphql";
import type { ControlOverviewPageUnassignTaskMutation as ControlOverviewPageUnassignTaskMutationType } from "./__generated__/ControlOverviewPageUnassignTaskMutation.graphql";
import type { ControlOverviewPageOrganizationQuery$data } from "./__generated__/ControlOverviewPageOrganizationQuery.graphql";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
// Function to format ISO8601 duration to human-readable format // Function to format ISO8601 duration to human-readable format
@@ -113,6 +124,11 @@ const controlOverviewPageQuery = graphql`
state state
timeEstimate timeEstimate
version version
assignedTo {
id
fullName
primaryEmailAddress
}
evidences(first: 50) evidences(first: 50)
@connection(key: "ControlOverviewPage_evidences") { @connection(key: "ControlOverviewPage_evidences") {
__id __id
@@ -162,6 +178,11 @@ const createTaskMutation = graphql`
description description
timeEstimate timeEstimate
state state
assignedTo {
id
fullName
primaryEmailAddress
}
} }
} }
} }
@@ -222,6 +243,57 @@ const getEvidenceFileUrlQuery = graphql`
} }
`; `;
const assignTaskMutation = graphql`
mutation ControlOverviewPageAssignTaskMutation($input: AssignTaskInput!) {
assignTask(input: $input) {
task {
id
version
assignedTo {
id
fullName
primaryEmailAddress
}
}
}
}
`;
const unassignTaskMutation = graphql`
mutation ControlOverviewPageUnassignTaskMutation($input: UnassignTaskInput!) {
unassignTask(input: $input) {
task {
id
version
assignedTo {
id
fullName
primaryEmailAddress
}
}
}
}
`;
const organizationQuery = graphql`
query ControlOverviewPageOrganizationQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
id
... on Organization {
peoples(first: 100) @connection(key: "ControlOverviewPage_peoples") {
edges {
node {
id
fullName
primaryEmailAddress
}
}
}
}
}
}
`;
function ControlOverviewPageContent({ function ControlOverviewPageContent({
queryRef, queryRef,
}: { }: {
@@ -236,6 +308,32 @@ function ControlOverviewPageContent({
const navigate = useNavigate(); const navigate = useNavigate();
const environment = useRelayEnvironment(); const environment = useRelayEnvironment();
// Load organization data for people selector
const [organizationData, setOrganizationData] =
useState<ControlOverviewPageOrganizationQuery$data | null>(null);
useEffect(() => {
if (organizationId) {
fetchQuery(environment, organizationQuery, {
organizationId,
})
.toPromise()
.then((response) => {
setOrganizationData(
response as ControlOverviewPageOrganizationQuery$data
);
})
.catch((error) => {
console.error("Error fetching organization data:", error);
toast({
title: "Error",
description: "Failed to load people data",
variant: "destructive",
});
});
}
}, [organizationId, environment, toast]);
const formatImportance = (importance: string | undefined): string => { const formatImportance = (importance: string | undefined): string => {
if (!importance) return ""; if (!importance) return "";
@@ -304,6 +402,12 @@ function ControlOverviewPageContent({
useMutation<ControlOverviewPageDeleteEvidenceMutationType>( useMutation<ControlOverviewPageDeleteEvidenceMutationType>(
deleteEvidenceMutation deleteEvidenceMutation
); );
const [assignTask] =
useMutation<ControlOverviewPageAssignTaskMutationType>(assignTaskMutation);
const [unassignTask] =
useMutation<ControlOverviewPageUnassignTaskMutationType>(
unassignTaskMutation
);
const [isCreateTaskOpen, setIsCreateTaskOpen] = useState(false); const [isCreateTaskOpen, setIsCreateTaskOpen] = useState(false);
const [newTaskName, setNewTaskName] = useState(""); const [newTaskName, setNewTaskName] = useState("");
@@ -354,6 +458,16 @@ function ControlOverviewPageContent({
taskId: string; taskId: string;
} | null>(null); } | null>(null);
// Add state for people selector
const [peoplePopoverOpen, setPeoplePopoverOpen] = useState<{
[key: string]: boolean;
}>({});
// Add state for people search
const [peopleSearch, setPeopleSearch] = useState<{
[key: string]: string;
}>({});
const tasks = data.control.tasks?.edges.map((edge) => edge.node) || []; const tasks = data.control.tasks?.edges.map((edge) => edge.node) || [];
const getEvidenceConnectionId = useCallback( const getEvidenceConnectionId = useCallback(
@@ -796,6 +910,57 @@ function ControlOverviewPageContent({
}); });
}; };
// Function to handle assigning a person to a task
const handleAssignPerson = (taskId: string, personId: string) => {
assignTask({
variables: {
input: {
taskId,
assignedToId: personId,
},
},
onCompleted: () => {
toast({
title: "Task assigned",
description: "Task has been assigned successfully.",
});
// Close the popover
setPeoplePopoverOpen((prev) => ({ ...prev, [taskId]: false }));
},
onError: (error) => {
toast({
title: "Error assigning task",
description: error.message,
variant: "destructive",
});
},
});
};
// Function to handle unassigning a person from a task
const handleUnassignPerson = (taskId: string) => {
unassignTask({
variables: {
input: {
taskId,
},
},
onCompleted: () => {
toast({
title: "Task unassigned",
description: "Task has been unassigned successfully.",
});
},
onError: (error) => {
toast({
title: "Error unassigning task",
description: error.message,
variant: "destructive",
});
},
});
};
return ( return (
<> <>
<Helmet> <Helmet>
@@ -1015,25 +1180,21 @@ function ControlOverviewPageContent({
? "border-gray-400 bg-gray-100" ? "border-gray-400 bg-gray-100"
: "border-gray-300" : "border-gray-300"
} ${isDraggingFile ? "opacity-50" : ""}`} } ${isDraggingFile ? "opacity-50" : ""}`}
onClick={() => onClick={(e) => {
task?.id && e.stopPropagation();
task?.state && if (task?.id && task?.state) {
handleTaskClick(task.id, task.state, task.version) handleTaskClick(task.id, task.state, task.version);
} }
}}
> >
{task?.state === "DONE" && ( {task?.state === "DONE" && (
<CheckCircle2 className="w-4 h-4 text-gray-500" /> <CheckCircle2 className="w-4 h-4 text-gray-500" />
)} )}
</div> </div>
<div <div
className={`flex-1 flex items-center justify-between cursor-pointer ${ className={`flex-1 flex items-center justify-between ${
isDraggingFile ? "opacity-50" : "" isDraggingFile ? "opacity-50" : ""
}`} }`}
onClick={() =>
task?.id &&
task?.state &&
handleTaskClick(task.id, task.state, task.version)
}
> >
<div> <div>
<h3 <h3
@@ -1057,9 +1218,182 @@ function ControlOverviewPageContent({
<span>{formatDuration(task.timeEstimate)}</span> <span>{formatDuration(task.timeEstimate)}</span>
</p> </p>
)} )}
{task?.assignedTo && (
<p className="text-xs mt-1 flex items-center text-gray-600">
<User className="w-3 h-3 mr-1" />
<span>{task.assignedTo.fullName}</span>
</p>
)}
</div> </div>
<div className="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity"> <div className="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
{/* People Selector */}
<Popover
open={peoplePopoverOpen[task?.id || ""]}
onOpenChange={(open: boolean) => {
if (task?.id) {
setPeoplePopoverOpen((prev) => ({
...prev,
[task.id]: open,
}));
}
}}
>
<PopoverTrigger asChild>
<button
type="button"
className="text-gray-400 hover:text-blue-600"
onClick={(e) => {
e.stopPropagation();
if (task?.id) {
setPeoplePopoverOpen((prev) => ({
...prev,
[task.id]: !prev[task.id],
}));
}
}}
>
{task?.assignedTo ? (
<UserMinus className="w-4 h-4" />
) : (
<UserPlus className="w-4 h-4" />
)}
</button>
</PopoverTrigger>
<PopoverContent className="w-[250px] p-0" align="end">
{task?.assignedTo ? (
<div className="p-4 space-y-4">
<div className="flex items-center gap-2">
<User className="w-4 h-4 text-gray-500" />
<div className="text-sm">
<p className="font-medium">
{task.assignedTo.fullName}
</p>
<p className="text-xs text-gray-500">
{task.assignedTo.primaryEmailAddress}
</p>
</div>
</div>
<Button
type="button"
variant="destructive"
size="sm"
className="w-full"
onClick={(e) => {
e.stopPropagation();
if (task?.id) {
handleUnassignPerson(task.id);
}
}}
>
<UserMinus className="w-4 h-4 mr-2" />
Unassign
</Button>
</div>
) : (
<div className="max-h-[300px] overflow-y-auto">
<div className="p-2 border-b">
<input
type="text"
placeholder="Search people to assign..."
className="w-full px-3 py-2 text-sm border rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
value={peopleSearch[task?.id || ""] || ""}
onChange={(e) => {
if (task?.id) {
setPeopleSearch((prev) => ({
...prev,
[task.id]: e.target.value,
}));
}
}}
/>
</div>
<div className="px-3 py-2 text-xs text-gray-500">
Click on a person to assign them to this task
</div>
<div className="py-1">
{!organizationData?.organization?.peoples?.edges?.some(
(edge) => {
if (!edge?.node) return false;
const searchTerm = (
peopleSearch[task?.id || ""] || ""
).toLowerCase();
return (
!searchTerm ||
edge.node.fullName
.toLowerCase()
.includes(searchTerm) ||
edge.node.primaryEmailAddress
.toLowerCase()
.includes(searchTerm)
);
}
) && (
<div className="py-6 text-center text-sm">
No people found.
</div>
)}
{organizationData?.organization?.peoples?.edges?.map(
(edge) => {
if (!edge?.node) return null;
const searchTerm = (
peopleSearch[task?.id || ""] || ""
).toLowerCase();
if (
searchTerm &&
!edge.node.fullName
.toLowerCase()
.includes(searchTerm) &&
!edge.node.primaryEmailAddress
.toLowerCase()
.includes(searchTerm)
) {
return null;
}
return (
<div
key={edge.node.id}
className="px-2 py-1 hover:bg-blue-50 cursor-pointer"
>
<button
type="button"
className="flex items-center w-full text-left"
onClick={() => {
if (task?.id) {
handleAssignPerson(
task.id,
edge.node.id
);
setPeoplePopoverOpen((prev) => ({
...prev,
[task.id]: false,
}));
}
}}
>
<User className="mr-2 h-4 w-4 text-blue-500 flex-shrink-0" />
<div>
<p className="font-medium">
{edge.node.fullName}
</p>
<p className="text-xs text-gray-500">
{edge.node.primaryEmailAddress}
</p>
</div>
</button>
</div>
);
}
)}
</div>
</div>
)}
</PopoverContent>
</Popover>
<button <button
type="button"
className="text-gray-400 hover:text-blue-600" className="text-gray-400 hover:text-blue-600"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
@@ -1071,6 +1405,7 @@ function ControlOverviewPageContent({
<Upload className="w-4 h-4" /> <Upload className="w-4 h-4" />
</button> </button>
<button <button
type="button"
className="text-gray-400 hover:text-red-600" className="text-gray-400 hover:text-red-600"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();

View File

@@ -99,6 +99,10 @@ function CreatePeoplePageContent() {
organizationId!, organizationId!,
"PeopleSelector_organization_peoples" "PeopleSelector_organization_peoples"
), ),
ConnectionHandler.getConnectionID(
organizationId!,
"ControlOverviewPage_peoples"
),
], ],
input: { input: {
organizationId: organizationId!, organizationId: organizationId!,

View File

@@ -0,0 +1,146 @@
/**
* @generated SignedSource<<bd1f2132960c1cdd84906d7de58765e9>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type AssignTaskInput = {
assignedToId: string;
taskId: string;
};
export type ControlOverviewPageAssignTaskMutation$variables = {
input: AssignTaskInput;
};
export type ControlOverviewPageAssignTaskMutation$data = {
readonly assignTask: {
readonly task: {
readonly assignedTo: {
readonly fullName: string;
readonly id: string;
readonly primaryEmailAddress: string;
} | null | undefined;
readonly id: string;
readonly version: number;
};
};
};
export type ControlOverviewPageAssignTaskMutation = {
response: ControlOverviewPageAssignTaskMutation$data;
variables: ControlOverviewPageAssignTaskMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v2 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "AssignTaskPayload",
"kind": "LinkedField",
"name": "assignTask",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Task",
"kind": "LinkedField",
"name": "task",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "version",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "primaryEmailAddress",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlOverviewPageAssignTaskMutation",
"selections": (v2/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlOverviewPageAssignTaskMutation",
"selections": (v2/*: any*/)
},
"params": {
"cacheID": "2a75b40af9d9853b851d153595dc1317",
"id": null,
"metadata": {},
"name": "ControlOverviewPageAssignTaskMutation",
"operationKind": "mutation",
"text": "mutation ControlOverviewPageAssignTaskMutation(\n $input: AssignTaskInput!\n) {\n assignTask(input: $input) {\n task {\n id\n version\n assignedTo {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "02f3b1fb21bc39cea7fde9cc3945adc6";
export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<502600204c0e5180095f00fe3372ea5a>> * @generated SignedSource<<1b8a07c3040e6ae6265d0b4eabc394ad>>
* @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 CreateTaskInput = { export type CreateTaskInput = {
assignedToId?: string | null | undefined;
controlId: string; controlId: string;
description: string; description: string;
name: string; name: string;
@@ -24,6 +25,11 @@ export type ControlOverviewPageCreateTaskMutation$data = {
readonly createTask: { readonly createTask: {
readonly taskEdge: { readonly taskEdge: {
readonly node: { readonly node: {
readonly assignedTo: {
readonly fullName: string;
readonly id: string;
readonly primaryEmailAddress: string;
} | null | undefined;
readonly description: string; readonly description: string;
readonly id: string; readonly id: string;
readonly name: string; readonly name: string;
@@ -57,6 +63,13 @@ v2 = [
} }
], ],
v3 = { v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v4 = {
"alias": null, "alias": null,
"args": null, "args": null,
"concreteType": "TaskEdge", "concreteType": "TaskEdge",
@@ -72,13 +85,7 @@ v3 = {
"name": "node", "name": "node",
"plural": false, "plural": false,
"selections": [ "selections": [
{ (v3/*: any*/),
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -106,6 +113,32 @@ v3 = {
"kind": "ScalarField", "kind": "ScalarField",
"name": "state", "name": "state",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "primaryEmailAddress",
"storageKey": null
}
],
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -131,7 +164,7 @@ return {
"name": "createTask", "name": "createTask",
"plural": false, "plural": false,
"selections": [ "selections": [
(v3/*: any*/) (v4/*: any*/)
], ],
"storageKey": null "storageKey": null
} }
@@ -156,7 +189,7 @@ return {
"name": "createTask", "name": "createTask",
"plural": false, "plural": false,
"selections": [ "selections": [
(v3/*: any*/), (v4/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -179,16 +212,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "ed1842681cbb14392603c1b73e82b6f9", "cacheID": "7e8741b4f438fecdf0d991843d0e206a",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "ControlOverviewPageCreateTaskMutation", "name": "ControlOverviewPageCreateTaskMutation",
"operationKind": "mutation", "operationKind": "mutation",
"text": "mutation ControlOverviewPageCreateTaskMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n id\n name\n description\n timeEstimate\n state\n }\n }\n }\n}\n" "text": "mutation ControlOverviewPageCreateTaskMutation(\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"
} }
}; };
})(); })();
(node as any).hash = "d2e06ccdb00312c0862187a18f374d23"; (node as any).hash = "1622754b77775d1662f4cb6af68ca775";
export default node; export default node;

View File

@@ -0,0 +1,254 @@
/**
* @generated SignedSource<<50244c085e737eefef310f74fe8808a3>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ControlOverviewPageOrganizationQuery$variables = {
organizationId: string;
};
export type ControlOverviewPageOrganizationQuery$data = {
readonly organization: {
readonly id: string;
readonly peoples?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly fullName: string;
readonly id: string;
readonly primaryEmailAddress: string;
};
}>;
};
};
};
export type ControlOverviewPageOrganizationQuery = {
response: ControlOverviewPageOrganizationQuery$data;
variables: ControlOverviewPageOrganizationQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"alias": null,
"args": null,
"concreteType": "PeopleEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "primaryEmailAddress",
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
v5 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlOverviewPageOrganizationQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": "peoples",
"args": null,
"concreteType": "PeopleConnection",
"kind": "LinkedField",
"name": "__ControlOverviewPage_peoples_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlOverviewPageOrganizationQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "PeopleConnection",
"kind": "LinkedField",
"name": "peoples",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "peoples(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "ControlOverviewPage_peoples",
"kind": "LinkedHandle",
"name": "peoples"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "2a407ffb628c6c0465efe741ba990440",
"id": null,
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "forward",
"path": [
"organization",
"peoples"
]
}
]
},
"name": "ControlOverviewPageOrganizationQuery",
"operationKind": "query",
"text": "query ControlOverviewPageOrganizationQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n peoples(first: 100) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "ba314af121e5a3d44f9001a7ada7a89a";
export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<1a0065809cf4bdeff6f4bb7ff087cdf7>> * @generated SignedSource<<8f9fcd90d577e5e9f1b7ac31bbc1a14c>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -28,6 +28,11 @@ export type ControlOverviewPageQuery$data = {
readonly __id: string; readonly __id: string;
readonly edges: ReadonlyArray<{ readonly edges: ReadonlyArray<{
readonly node: { readonly node: {
readonly assignedTo: {
readonly fullName: string;
readonly id: string;
readonly primaryEmailAddress: string;
} | null | undefined;
readonly description: string; readonly description: string;
readonly evidences: { readonly evidences: {
readonly __id: string; readonly __id: string;
@@ -131,18 +136,44 @@ v9 = {
v10 = { v10 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "concreteType": "People",
"name": "__typename", "kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "primaryEmailAddress",
"storageKey": null
}
],
"storageKey": null "storageKey": null
}, },
v11 = { v11 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "cursor", "name": "__typename",
"storageKey": null "storageKey": null
}, },
v12 = { v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v13 = {
"alias": null, "alias": null,
"args": null, "args": null,
"concreteType": "PageInfo", "concreteType": "PageInfo",
@@ -167,7 +198,7 @@ v12 = {
], ],
"storageKey": null "storageKey": null
}, },
v13 = { v14 = {
"kind": "ClientExtension", "kind": "ClientExtension",
"selections": [ "selections": [
{ {
@@ -179,7 +210,7 @@ v13 = {
} }
] ]
}, },
v14 = [ v15 = [
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -226,25 +257,25 @@ v14 = [
"name": "createdAt", "name": "createdAt",
"storageKey": null "storageKey": null
}, },
(v10/*: any*/) (v11/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v11/*: any*/) (v12/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v12/*: any*/), (v13/*: any*/),
(v13/*: any*/) (v14/*: any*/)
], ],
v15 = [ v16 = [
{ {
"kind": "Literal", "kind": "Literal",
"name": "first", "name": "first",
"value": 100 "value": 100
} }
], ],
v16 = [ v17 = [
{ {
"kind": "Literal", "kind": "Literal",
"name": "first", "name": "first",
@@ -305,6 +336,7 @@ return {
(v5/*: any*/), (v5/*: any*/),
(v8/*: any*/), (v8/*: any*/),
(v9/*: any*/), (v9/*: any*/),
(v10/*: any*/),
{ {
"alias": "evidences", "alias": "evidences",
"args": null, "args": null,
@@ -312,19 +344,19 @@ return {
"kind": "LinkedField", "kind": "LinkedField",
"name": "__ControlOverviewPage_evidences_connection", "name": "__ControlOverviewPage_evidences_connection",
"plural": false, "plural": false,
"selections": (v14/*: any*/), "selections": (v15/*: any*/),
"storageKey": null "storageKey": null
}, },
(v10/*: any*/) (v11/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v11/*: any*/) (v12/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v12/*: any*/), (v13/*: any*/),
(v13/*: any*/) (v14/*: any*/)
], ],
"storageKey": null "storageKey": null
} }
@@ -353,7 +385,7 @@ return {
"name": "node", "name": "node",
"plural": false, "plural": false,
"selections": [ "selections": [
(v10/*: any*/), (v11/*: any*/),
(v2/*: any*/), (v2/*: any*/),
{ {
"kind": "InlineFragment", "kind": "InlineFragment",
@@ -365,7 +397,7 @@ return {
(v7/*: any*/), (v7/*: any*/),
{ {
"alias": null, "alias": null,
"args": (v15/*: any*/), "args": (v16/*: any*/),
"concreteType": "TaskConnection", "concreteType": "TaskConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "tasks", "name": "tasks",
@@ -393,41 +425,42 @@ return {
(v5/*: any*/), (v5/*: any*/),
(v8/*: any*/), (v8/*: any*/),
(v9/*: any*/), (v9/*: any*/),
(v10/*: any*/),
{ {
"alias": null, "alias": null,
"args": (v16/*: any*/), "args": (v17/*: any*/),
"concreteType": "EvidenceConnection", "concreteType": "EvidenceConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "evidences", "name": "evidences",
"plural": false, "plural": false,
"selections": (v14/*: any*/), "selections": (v15/*: any*/),
"storageKey": "evidences(first:50)" "storageKey": "evidences(first:50)"
}, },
{ {
"alias": null, "alias": null,
"args": (v16/*: any*/), "args": (v17/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "ControlOverviewPage_evidences", "key": "ControlOverviewPage_evidences",
"kind": "LinkedHandle", "kind": "LinkedHandle",
"name": "evidences" "name": "evidences"
}, },
(v10/*: any*/) (v11/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v11/*: any*/) (v12/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v12/*: any*/), (v13/*: any*/),
(v13/*: any*/) (v14/*: any*/)
], ],
"storageKey": "tasks(first:100)" "storageKey": "tasks(first:100)"
}, },
{ {
"alias": null, "alias": null,
"args": (v15/*: any*/), "args": (v16/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "ControlOverviewPage_tasks", "key": "ControlOverviewPage_tasks",
@@ -444,7 +477,7 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "bd9679f5980ac0eed07f28e4f0cf4f27", "cacheID": "1d26d59ea2232a213d01636e8d388919",
"id": null, "id": null,
"metadata": { "metadata": {
"connection": [ "connection": [
@@ -467,11 +500,11 @@ return {
}, },
"name": "ControlOverviewPageQuery", "name": "ControlOverviewPageQuery",
"operationKind": "query", "operationKind": "query",
"text": "query ControlOverviewPageQuery(\n $controlId: ID!\n) {\n control: node(id: $controlId) {\n __typename\n id\n ... on Control {\n name\n description\n state\n importance\n category\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n version\n evidences(first: 50) {\n edges {\n node {\n id\n mimeType\n filename\n size\n state\n createdAt\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 ControlOverviewPageQuery(\n $controlId: ID!\n) {\n control: node(id: $controlId) {\n __typename\n id\n ... on Control {\n name\n description\n state\n importance\n category\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n version\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 createdAt\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 = "81d519cc3ea015284326fa7d5052b25f"; (node as any).hash = "e48b75fde2fcff42e868a0e68abd5809";
export default node; export default node;

View File

@@ -0,0 +1,145 @@
/**
* @generated SignedSource<<ec9f52c0ab13cd30148d7b2a97f59b63>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type UnassignTaskInput = {
taskId: string;
};
export type ControlOverviewPageUnassignTaskMutation$variables = {
input: UnassignTaskInput;
};
export type ControlOverviewPageUnassignTaskMutation$data = {
readonly unassignTask: {
readonly task: {
readonly assignedTo: {
readonly fullName: string;
readonly id: string;
readonly primaryEmailAddress: string;
} | null | undefined;
readonly id: string;
readonly version: number;
};
};
};
export type ControlOverviewPageUnassignTaskMutation = {
response: ControlOverviewPageUnassignTaskMutation$data;
variables: ControlOverviewPageUnassignTaskMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v2 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "UnassignTaskPayload",
"kind": "LinkedField",
"name": "unassignTask",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Task",
"kind": "LinkedField",
"name": "task",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "version",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "primaryEmailAddress",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlOverviewPageUnassignTaskMutation",
"selections": (v2/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlOverviewPageUnassignTaskMutation",
"selections": (v2/*: any*/)
},
"params": {
"cacheID": "dc570710d28f3208dbaff23593819f4d",
"id": null,
"metadata": {},
"name": "ControlOverviewPageUnassignTaskMutation",
"operationKind": "mutation",
"text": "mutation ControlOverviewPageUnassignTaskMutation(\n $input: UnassignTaskInput!\n) {\n unassignTask(input: $input) {\n task {\n id\n version\n assignedTo {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "4c809cd810a4178ab4f7a6d020338187";
export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<c6eaf570ef3d4e5a289ab266f6662546>> * @generated SignedSource<<2e946185d02bd4e3d510d81c68cb9863>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -16,6 +16,7 @@ export type UpdateTaskInput = {
name?: string | null | undefined; name?: string | null | undefined;
state?: TaskState | null | undefined; state?: TaskState | null | undefined;
taskId: string; taskId: string;
timeEstimate?: any | null | undefined;
}; };
export type ControlOverviewPageUpdateTaskStateMutation$variables = { export type ControlOverviewPageUpdateTaskStateMutation$variables = {
input: UpdateTaskInput; input: UpdateTaskInput;

View File

@@ -0,0 +1 @@
ALTER TABLE tasks ADD COLUMN assigned_to TEXT REFERENCES peoples(id);

View File

@@ -38,6 +38,7 @@ type (
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"` UpdatedAt time.Time `db:"updated_at"`
Version int `db:"version"` Version int `db:"version"`
AssignedTo *gid.GID `db:"assigned_to"`
TimeEstimate time.Duration `db:"time_estimate"` TimeEstimate time.Duration `db:"time_estimate"`
} }
@@ -70,6 +71,7 @@ SELECT
description, description,
time_estimate, time_estimate,
state, state,
assigned_to,
content_ref, content_ref,
created_at, created_at,
updated_at, updated_at,
@@ -78,7 +80,7 @@ FROM
tasks tasks
WHERE WHERE
%s %s
AND task_id = @task_id AND id = @task_id
LIMIT 1; LIMIT 1;
` `
@@ -119,7 +121,8 @@ INSERT INTO tasks (
updated_at, updated_at,
version, version,
state, state,
time_estimate time_estimate,
assigned_to
) )
VALUES ( VALUES (
@tenant_id, @tenant_id,
@@ -132,7 +135,8 @@ VALUES (
@updated_at, @updated_at,
@version, @version,
@state, @state,
@time_estimate @time_estimate,
@assigned_to
); );
` `
@@ -148,6 +152,7 @@ VALUES (
"version": t.Version, "version": t.Version,
"state": t.State, "state": t.State,
"time_estimate": t.TimeEstimate, "time_estimate": t.TimeEstimate,
"assigned_to": t.AssignedTo,
} }
_, err := conn.Exec(ctx, q, args) _, err := conn.Exec(ctx, q, args)
return err return err
@@ -171,7 +176,8 @@ SELECT
content_ref, content_ref,
created_at, created_at,
updated_at, updated_at,
version version,
assigned_to
FROM FROM
tasks tasks
WHERE WHERE
@@ -240,6 +246,58 @@ RETURNING
return err return err
} }
func (t *Task) AssignTo(
ctx context.Context,
conn pg.Conn,
scope Scoper,
assignedTo gid.GID,
) error {
q := `
UPDATE tasks
SET
assigned_to = @assigned_to
WHERE
%s
AND id = @task_id
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"task_id": t.ID,
"assigned_to": assignedTo,
}
maps.Copy(args, scope.SQLArguments())
_, err := conn.Exec(ctx, q, args)
return err
}
func (t *Task) Unassign(
ctx context.Context,
conn pg.Conn,
scope Scoper,
) error {
q := `
UPDATE tasks
SET
assigned_to = NULL
WHERE
%s
AND id = @task_id
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"task_id": t.ID,
}
maps.Copy(args, scope.SQLArguments())
_, err := conn.Exec(ctx, q, args)
return err
}
func (t *Task) Delete( func (t *Task) Delete(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,

View File

@@ -36,6 +36,7 @@ type (
ContentRef string ContentRef string
Description string Description string
TimeEstimate time.Duration TimeEstimate time.Duration
AssignedTo *gid.GID
} }
UpdateTaskRequest struct { UpdateTaskRequest struct {
@@ -67,6 +68,7 @@ func (s TaskService) Create(
State: coredata.TaskStateTodo, State: coredata.TaskStateTodo,
Description: req.Description, Description: req.Description,
TimeEstimate: req.TimeEstimate, TimeEstimate: req.TimeEstimate,
AssignedTo: req.AssignedTo,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
} }
@@ -93,6 +95,67 @@ func (s TaskService) Create(
return task, nil return task, nil
} }
func (s TaskService) Assign(
ctx context.Context,
taskID gid.GID,
assignedTo gid.GID,
) (*coredata.Task, error) {
task := &coredata.Task{ID: taskID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := task.LoadByID(ctx, conn, s.svc.scope, taskID); err != nil {
return fmt.Errorf("cannot load task %q: %w", taskID, err)
}
task.AssignedTo = &assignedTo
if err := task.AssignTo(ctx, conn, s.svc.scope, assignedTo); err != nil {
return fmt.Errorf("cannot assign task %q to %q: %w", taskID, assignedTo, err)
}
return nil
},
)
if err != nil {
return nil, err
}
return task, nil
}
func (s TaskService) Unassign(
ctx context.Context,
taskID gid.GID,
) (*coredata.Task, error) {
task := &coredata.Task{ID: taskID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := task.LoadByID(ctx, conn, s.svc.scope, taskID); err != nil {
return fmt.Errorf("cannot load task %q: %w", taskID, err)
}
task.AssignedTo = nil
if err := task.Unassign(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot unassign task %q: %w", taskID, err)
}
return nil
},
)
if err != nil {
return nil, err
}
return task, nil
}
func (s TaskService) Update( func (s TaskService) Update(
ctx context.Context, ctx context.Context,
req UpdateTaskRequest, req UpdateTaskRequest,

View File

@@ -263,6 +263,7 @@ type Task implements Node {
description: String! description: String!
state: TaskState! state: TaskState!
timeEstimate: Duration! timeEstimate: Duration!
assignedTo: People @goField(forceResolver: true)
evidences( evidences(
first: Int first: Int
@@ -345,6 +346,8 @@ type Mutation {
createTask(input: CreateTaskInput!): CreateTaskPayload! createTask(input: CreateTaskInput!): CreateTaskPayload!
updateTask(input: UpdateTaskInput!): UpdateTaskPayload! updateTask(input: UpdateTaskInput!): UpdateTaskPayload!
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload! deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
assignTask(input: AssignTaskInput!): AssignTaskPayload!
unassignTask(input: UnassignTaskInput!): UnassignTaskPayload!
createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload! createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload!
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload! updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
@@ -488,6 +491,7 @@ input CreateTaskInput {
name: String! name: String!
description: String! description: String!
timeEstimate: Duration! timeEstimate: Duration!
assignedToId: ID
} }
type CreateTaskPayload { type CreateTaskPayload {
@@ -646,6 +650,7 @@ input UpdateTaskInput {
name: String name: String
description: String description: String
state: TaskState state: TaskState
timeEstimate: Duration
} }
type UpdateTaskPayload { type UpdateTaskPayload {
@@ -668,3 +673,20 @@ input ImportFrameworkInput {
type ImportFrameworkPayload { type ImportFrameworkPayload {
frameworkEdge: FrameworkEdge! frameworkEdge: FrameworkEdge!
} }
input AssignTaskInput {
taskId: ID!
assignedToId: ID!
}
type AssignTaskPayload {
task: Task!
}
input UnassignTaskInput {
taskId: ID!
}
type UnassignTaskPayload {
task: Task!
}

View File

@@ -57,6 +57,10 @@ type DirectiveRoot struct {
} }
type ComplexityRoot struct { type ComplexityRoot struct {
AssignTaskPayload struct {
Task func(childComplexity int) int
}
ConfirmEmailPayload struct { ConfirmEmailPayload struct {
Success func(childComplexity int) int Success func(childComplexity int) int
} }
@@ -182,6 +186,7 @@ type ComplexityRoot struct {
} }
Mutation struct { Mutation struct {
AssignTask func(childComplexity int, input types.AssignTaskInput) int
ConfirmEmail func(childComplexity int, input types.ConfirmEmailInput) int ConfirmEmail func(childComplexity int, input types.ConfirmEmailInput) int
CreateControl func(childComplexity int, input types.CreateControlInput) int CreateControl func(childComplexity int, input types.CreateControlInput) int
CreateFramework func(childComplexity int, input types.CreateFrameworkInput) int CreateFramework func(childComplexity int, input types.CreateFrameworkInput) int
@@ -197,6 +202,7 @@ type ComplexityRoot struct {
DeleteTask func(childComplexity int, input types.DeleteTaskInput) int DeleteTask func(childComplexity int, input types.DeleteTaskInput) int
DeleteVendor func(childComplexity int, input types.DeleteVendorInput) int DeleteVendor func(childComplexity int, input types.DeleteVendorInput) int
ImportFramework func(childComplexity int, input types.ImportFrameworkInput) int ImportFramework func(childComplexity int, input types.ImportFrameworkInput) int
UnassignTask func(childComplexity int, input types.UnassignTaskInput) int
UpdateControl func(childComplexity int, input types.UpdateControlInput) int UpdateControl func(childComplexity int, input types.UpdateControlInput) int
UpdateFramework func(childComplexity int, input types.UpdateFrameworkInput) int UpdateFramework func(childComplexity int, input types.UpdateFrameworkInput) int
UpdateOrganization func(childComplexity int, input types.UpdateOrganizationInput) int UpdateOrganization func(childComplexity int, input types.UpdateOrganizationInput) int
@@ -290,6 +296,7 @@ type ComplexityRoot struct {
} }
Task struct { Task struct {
AssignedTo func(childComplexity int) int
CreatedAt func(childComplexity int) int CreatedAt 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) int Evidences func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int
@@ -311,6 +318,10 @@ type ComplexityRoot struct {
Node func(childComplexity int) int Node func(childComplexity int) int
} }
UnassignTaskPayload struct {
Task func(childComplexity int) int
}
UpdateControlPayload struct { UpdateControlPayload struct {
Control func(childComplexity int) int Control func(childComplexity int) int
} }
@@ -401,6 +412,8 @@ type MutationResolver interface {
CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error)
UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error) UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error)
DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, 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)
CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error)
UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error)
ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error)
@@ -427,6 +440,7 @@ type QueryResolver interface {
Viewer(ctx context.Context) (*types.User, error) Viewer(ctx context.Context) (*types.User, error)
} }
type TaskResolver interface { type TaskResolver interface {
AssignedTo(ctx context.Context, obj *types.Task) (*types.People, error)
Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceConnection, error) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceConnection, error)
} }
type UserResolver interface { type UserResolver interface {
@@ -452,6 +466,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
_ = ec _ = ec
switch typeName + "." + field { switch typeName + "." + field {
case "AssignTaskPayload.task":
if e.complexity.AssignTaskPayload.Task == nil {
break
}
return e.complexity.AssignTaskPayload.Task(childComplexity), true
case "ConfirmEmailPayload.success": case "ConfirmEmailPayload.success":
if e.complexity.ConfirmEmailPayload.Success == nil { if e.complexity.ConfirmEmailPayload.Success == nil {
break break
@@ -826,6 +847,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.ImportFrameworkPayload.FrameworkEdge(childComplexity), true return e.complexity.ImportFrameworkPayload.FrameworkEdge(childComplexity), true
case "Mutation.assignTask":
if e.complexity.Mutation.AssignTask == nil {
break
}
args, err := ec.field_Mutation_assignTask_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.AssignTask(childComplexity, args["input"].(types.AssignTaskInput)), true
case "Mutation.confirmEmail": case "Mutation.confirmEmail":
if e.complexity.Mutation.ConfirmEmail == nil { if e.complexity.Mutation.ConfirmEmail == nil {
break break
@@ -1006,6 +1039,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.ImportFramework(childComplexity, args["input"].(types.ImportFrameworkInput)), true return e.complexity.Mutation.ImportFramework(childComplexity, args["input"].(types.ImportFrameworkInput)), true
case "Mutation.unassignTask":
if e.complexity.Mutation.UnassignTask == nil {
break
}
args, err := ec.field_Mutation_unassignTask_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.UnassignTask(childComplexity, args["input"].(types.UnassignTaskInput)), true
case "Mutation.updateControl": case "Mutation.updateControl":
if e.complexity.Mutation.UpdateControl == nil { if e.complexity.Mutation.UpdateControl == nil {
break break
@@ -1449,6 +1494,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Session.ID(childComplexity), true return e.complexity.Session.ID(childComplexity), true
case "Task.assignedTo":
if e.complexity.Task.AssignedTo == nil {
break
}
return e.complexity.Task.AssignedTo(childComplexity), true
case "Task.createdAt": case "Task.createdAt":
if e.complexity.Task.CreatedAt == nil { if e.complexity.Task.CreatedAt == nil {
break break
@@ -1545,6 +1597,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.TaskEdge.Node(childComplexity), true return e.complexity.TaskEdge.Node(childComplexity), true
case "UnassignTaskPayload.task":
if e.complexity.UnassignTaskPayload.Task == nil {
break
}
return e.complexity.UnassignTaskPayload.Task(childComplexity), true
case "UpdateControlPayload.control": case "UpdateControlPayload.control":
if e.complexity.UpdateControlPayload.Control == nil { if e.complexity.UpdateControlPayload.Control == nil {
break break
@@ -1775,6 +1834,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
opCtx := graphql.GetOperationContext(ctx) opCtx := graphql.GetOperationContext(ctx)
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap( inputUnmarshalMap := graphql.BuildUnmarshalerMap(
ec.unmarshalInputAssignTaskInput,
ec.unmarshalInputConfirmEmailInput, ec.unmarshalInputConfirmEmailInput,
ec.unmarshalInputCreateControlInput, ec.unmarshalInputCreateControlInput,
ec.unmarshalInputCreateFrameworkInput, ec.unmarshalInputCreateFrameworkInput,
@@ -1790,6 +1850,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputDeleteTaskInput, ec.unmarshalInputDeleteTaskInput,
ec.unmarshalInputDeleteVendorInput, ec.unmarshalInputDeleteVendorInput,
ec.unmarshalInputImportFrameworkInput, ec.unmarshalInputImportFrameworkInput,
ec.unmarshalInputUnassignTaskInput,
ec.unmarshalInputUpdateControlInput, ec.unmarshalInputUpdateControlInput,
ec.unmarshalInputUpdateFrameworkInput, ec.unmarshalInputUpdateFrameworkInput,
ec.unmarshalInputUpdateOrganizationInput, ec.unmarshalInputUpdateOrganizationInput,
@@ -2160,6 +2221,7 @@ type Task implements Node {
description: String! description: String!
state: TaskState! state: TaskState!
timeEstimate: Duration! timeEstimate: Duration!
assignedTo: People @goField(forceResolver: true)
evidences( evidences(
first: Int first: Int
@@ -2242,6 +2304,8 @@ type Mutation {
createTask(input: CreateTaskInput!): CreateTaskPayload! createTask(input: CreateTaskInput!): CreateTaskPayload!
updateTask(input: UpdateTaskInput!): UpdateTaskPayload! updateTask(input: UpdateTaskInput!): UpdateTaskPayload!
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload! deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
assignTask(input: AssignTaskInput!): AssignTaskPayload!
unassignTask(input: UnassignTaskInput!): UnassignTaskPayload!
createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload! createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload!
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload! updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
@@ -2385,6 +2449,7 @@ input CreateTaskInput {
name: String! name: String!
description: String! description: String!
timeEstimate: Duration! timeEstimate: Duration!
assignedToId: ID
} }
type CreateTaskPayload { type CreateTaskPayload {
@@ -2543,6 +2608,7 @@ input UpdateTaskInput {
name: String name: String
description: String description: String
state: TaskState state: TaskState
timeEstimate: Duration
} }
type UpdateTaskPayload { type UpdateTaskPayload {
@@ -2565,6 +2631,23 @@ input ImportFrameworkInput {
type ImportFrameworkPayload { type ImportFrameworkPayload {
frameworkEdge: FrameworkEdge! frameworkEdge: FrameworkEdge!
} }
input AssignTaskInput {
taskId: ID!
assignedToId: ID!
}
type AssignTaskPayload {
task: Task!
}
input UnassignTaskInput {
taskId: ID!
}
type UnassignTaskPayload {
task: Task!
}
`, BuiltIn: false}, `, BuiltIn: false},
} }
var parsedSchema = gqlparser.MustLoadSchema(sources...) var parsedSchema = gqlparser.MustLoadSchema(sources...)
@@ -2727,6 +2810,29 @@ func (ec *executionContext) field_Framework_controls_argsBefore(
return zeroVal, nil return zeroVal, 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 := ec.field_Mutation_assignTask_argsInput(ctx, rawArgs)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_assignTask_argsInput(
ctx context.Context,
rawArgs map[string]any,
) (types.AssignTaskInput, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
if tmp, ok := rawArgs["input"]; ok {
return ec.unmarshalNAssignTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskInput(ctx, tmp)
}
var zeroVal types.AssignTaskInput
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_confirmEmail_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { func (ec *executionContext) field_Mutation_confirmEmail_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error var err error
args := map[string]any{} args := map[string]any{}
@@ -3072,6 +3178,29 @@ func (ec *executionContext) field_Mutation_importFramework_argsInput(
return zeroVal, nil return zeroVal, 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 := ec.field_Mutation_unassignTask_argsInput(ctx, rawArgs)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_unassignTask_argsInput(
ctx context.Context,
rawArgs map[string]any,
) (types.UnassignTaskInput, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
if tmp, ok := rawArgs["input"]; ok {
return ec.unmarshalNUnassignTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskInput(ctx, tmp)
}
var zeroVal types.UnassignTaskInput
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_updateControl_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { func (ec *executionContext) field_Mutation_updateControl_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error var err error
args := map[string]any{} args := map[string]any{}
@@ -3864,6 +3993,66 @@ func (ec *executionContext) field___Type_fields_argsIncludeDeprecated(
// region **************************** field.gotpl ***************************** // region **************************** field.gotpl *****************************
func (ec *executionContext) _AssignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.AssignTaskPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_AssignTaskPayload_task(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Task, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.Task)
fc.Result = res
return ec.marshalNTask2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTask(ctx, field.Selections, res)
}
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 "version":
return ec.fieldContext_Task_version(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 "assignedTo":
return ec.fieldContext_Task_assignedTo(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) _ConfirmEmailPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.ConfirmEmailPayload) (ret graphql.Marshaler) { func (ec *executionContext) _ConfirmEmailPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.ConfirmEmailPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_ConfirmEmailPayload_success(ctx, field) fc, err := ec.fieldContext_ConfirmEmailPayload_success(ctx, field)
if err != nil { if err != nil {
@@ -6578,6 +6767,100 @@ func (ec *executionContext) fieldContext_Mutation_deleteTask(ctx context.Context
return fc, nil return fc, nil
} }
func (ec *executionContext) _Mutation_assignTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_assignTask(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().AssignTask(rctx, fc.Args["input"].(types.AssignTaskInput))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.AssignTaskPayload)
fc.Result = res
return ec.marshalNAssignTaskPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskPayload(ctx, field.Selections, res)
}
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)
},
}
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) {
fc, err := ec.fieldContext_Mutation_unassignTask(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().UnassignTask(rctx, fc.Args["input"].(types.UnassignTaskInput))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.UnassignTaskPayload)
fc.Result = res
return ec.marshalNUnassignTaskPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUnassignTaskPayload(ctx, field.Selections, res)
}
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)
},
}
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_createFramework(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation_createFramework(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_createFramework(ctx, field) fc, err := ec.fieldContext_Mutation_createFramework(ctx, field)
if err != nil { if err != nil {
@@ -9362,6 +9645,59 @@ func (ec *executionContext) fieldContext_Task_timeEstimate(_ context.Context, fi
return fc, nil return fc, nil
} }
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)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Task().AssignedTo(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*types.People)
fc.Result = res
return ec.marshalOPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeople(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Task_assignedTo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Task",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_People_id(ctx, field)
case "fullName":
return ec.fieldContext_People_fullName(ctx, field)
case "primaryEmailAddress":
return ec.fieldContext_People_primaryEmailAddress(ctx, field)
case "additionalEmailAddresses":
return ec.fieldContext_People_additionalEmailAddresses(ctx, field)
case "kind":
return ec.fieldContext_People_kind(ctx, field)
case "createdAt":
return ec.fieldContext_People_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_People_updatedAt(ctx, field)
case "version":
return ec.fieldContext_People_version(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type People", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _Task_evidences(ctx context.Context, field graphql.CollectedField, obj *types.Task) (ret graphql.Marshaler) { func (ec *executionContext) _Task_evidences(ctx context.Context, field graphql.CollectedField, obj *types.Task) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Task_evidences(ctx, field) fc, err := ec.fieldContext_Task_evidences(ctx, field)
if err != nil { if err != nil {
@@ -9662,6 +9998,68 @@ 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 "assignedTo":
return ec.fieldContext_Task_assignedTo(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) _UnassignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.UnassignTaskPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_UnassignTaskPayload_task(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Task, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.Task)
fc.Result = res
return ec.marshalNTask2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTask(ctx, field.Selections, res)
}
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 "version":
return ec.fieldContext_Task_version(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 "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field)
case "evidences": case "evidences":
return ec.fieldContext_Task_evidences(ctx, field) return ec.fieldContext_Task_evidences(ctx, field)
case "createdAt": case "createdAt":
@@ -10006,6 +10404,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 "assignedTo":
return ec.fieldContext_Task_assignedTo(ctx, field)
case "evidences": case "evidences":
return ec.fieldContext_Task_evidences(ctx, field) return ec.fieldContext_Task_evidences(ctx, field)
case "createdAt": case "createdAt":
@@ -12745,6 +13145,40 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
// region **************************** input.gotpl ***************************** // region **************************** input.gotpl *****************************
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.unmarshalNID2githubᚗcomᚋgetproboᚋ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.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.AssignedToID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputConfirmEmailInput(ctx context.Context, obj any) (types.ConfirmEmailInput, error) { func (ec *executionContext) unmarshalInputConfirmEmailInput(ctx context.Context, obj any) (types.ConfirmEmailInput, error) {
var it types.ConfirmEmailInput var it types.ConfirmEmailInput
asMap := map[string]any{} asMap := map[string]any{}
@@ -13019,7 +13453,7 @@ func (ec *executionContext) unmarshalInputCreateTaskInput(ctx context.Context, o
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"controlId", "name", "description", "timeEstimate"} fieldsInOrder := [...]string{"controlId", "name", "description", "timeEstimate", "assignedToId"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -13054,6 +13488,13 @@ func (ec *executionContext) unmarshalInputCreateTaskInput(ctx context.Context, o
return it, err return it, err
} }
it.TimeEstimate = data it.TimeEstimate = data
case "assignedToId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("assignedToId"))
data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.AssignedToID = data
} }
} }
@@ -13346,6 +13787,33 @@ func (ec *executionContext) unmarshalInputImportFrameworkInput(ctx context.Conte
return it, nil 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.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.TaskID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputUpdateControlInput(ctx context.Context, obj any) (types.UpdateControlInput, error) { func (ec *executionContext) unmarshalInputUpdateControlInput(ctx context.Context, obj any) (types.UpdateControlInput, error) {
var it types.UpdateControlInput var it types.UpdateControlInput
asMap := map[string]any{} asMap := map[string]any{}
@@ -13642,7 +14110,7 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"taskId", "expectedVersion", "name", "description", "state"} fieldsInOrder := [...]string{"taskId", "expectedVersion", "name", "description", "state", "timeEstimate"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -13684,6 +14152,13 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
return it, err return it, err
} }
it.State = data it.State = data
case "timeEstimate":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("timeEstimate"))
data, err := ec.unmarshalODuration2ᚖtimeᚐDuration(ctx, v)
if err != nil {
return it, err
}
it.TimeEstimate = data
} }
} }
@@ -13908,6 +14383,45 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
// region **************************** object.gotpl **************************** // region **************************** object.gotpl ****************************
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 confirmEmailPayloadImplementors = []string{"ConfirmEmailPayload"} var confirmEmailPayloadImplementors = []string{"ConfirmEmailPayload"}
func (ec *executionContext) _ConfirmEmailPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ConfirmEmailPayload) graphql.Marshaler { func (ec *executionContext) _ConfirmEmailPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ConfirmEmailPayload) graphql.Marshaler {
@@ -15165,6 +15679,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ 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 "createFramework": case "createFramework":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_createFramework(ctx, field) return ec._Mutation_createFramework(ctx, field)
@@ -16105,6 +16633,34 @@ func (ec *executionContext) _Task(ctx context.Context, sel ast.SelectionSet, obj
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1) atomic.AddUint32(&out.Invalids, 1)
} }
case "assignedTo":
field := field
innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) {
res = ec._Task_assignedTo(ctx, field, obj)
return res
}
if field.Deferrable != nil {
dfs, ok := deferred[field.Deferrable.Label]
di := 0
if ok {
dfs.AddField(field)
di = len(dfs.Values) - 1
} else {
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
deferred[field.Deferrable.Label] = dfs
}
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
return innerFunc(ctx, dfs)
})
// don't run the out.Concurrently() call below
out.Values[i] = graphql.Null
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "evidences": case "evidences":
field := field field := field
@@ -16257,6 +16813,45 @@ func (ec *executionContext) _TaskEdge(ctx context.Context, sel ast.SelectionSet,
return out 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 updateControlPayloadImplementors = []string{"UpdateControlPayload"} var updateControlPayloadImplementors = []string{"UpdateControlPayload"}
func (ec *executionContext) _UpdateControlPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateControlPayload) graphql.Marshaler { func (ec *executionContext) _UpdateControlPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateControlPayload) graphql.Marshaler {
@@ -17169,6 +17764,25 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o
// region ***************************** type.gotpl ***************************** // region ***************************** type.gotpl *****************************
func (ec *executionContext) unmarshalNAssignTaskInput2githubᚗcomᚋgetproboᚋ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) marshalNAssignTaskPayload2githubᚗcomᚋgetproboᚋ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ᚖgithubᚗcomᚋgetproboᚋ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)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._AssignTaskPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) { func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) {
res, err := graphql.UnmarshalBoolean(v) res, err := graphql.UnmarshalBoolean(v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
@@ -18347,6 +18961,25 @@ var (
} }
) )
func (ec *executionContext) unmarshalNUnassignTaskInput2githubᚗcomᚋgetproboᚋ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) marshalNUnassignTaskPayload2githubᚗcomᚋgetproboᚋ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ᚖgithubᚗcomᚋgetproboᚋ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)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._UnassignTaskPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNUpdateControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlInput(ctx context.Context, v any) (types.UpdateControlInput, error) { func (ec *executionContext) unmarshalNUpdateControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlInput(ctx context.Context, v any) (types.UpdateControlInput, error) {
res, err := ec.unmarshalInputUpdateControlInput(ctx, v) res, err := ec.unmarshalInputUpdateControlInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
@@ -18949,6 +19582,22 @@ func (ec *executionContext) marshalODatetime2ᚖtimeᚐTime(ctx context.Context,
return res return res
} }
func (ec *executionContext) unmarshalODuration2ᚖtimeᚐDuration(ctx context.Context, v any) (*time.Duration, error) {
if v == nil {
return nil, nil
}
res, err := graphql.UnmarshalDuration(v)
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalODuration2ᚖtimeᚐDuration(ctx context.Context, sel ast.SelectionSet, v *time.Duration) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalDuration(*v)
return res
}
func (ec *executionContext) unmarshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx context.Context, v any) (*gid.GID, error) { func (ec *executionContext) unmarshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx context.Context, v any) (*gid.GID, error) {
if v == nil { if v == nil {
return nil, nil return nil, nil
@@ -18981,6 +19630,13 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele
return res return res
} }
func (ec *executionContext) marshalOPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeople(ctx context.Context, sel ast.SelectionSet, v *types.People) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec._People(ctx, sel, v)
}
func (ec *executionContext) unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, v any) (*coredata.PeopleKind, error) { func (ec *executionContext) unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, v any) (*coredata.PeopleKind, error) {
if v == nil { if v == nil {
return nil, nil return nil, nil

View File

@@ -16,6 +16,15 @@ type Node interface {
GetID() gid.GID GetID() gid.GID
} }
type AssignTaskInput struct {
TaskID gid.GID `json:"taskId"`
AssignedToID gid.GID `json:"assignedToId"`
}
type AssignTaskPayload struct {
Task *Task `json:"task"`
}
type ConfirmEmailInput struct { type ConfirmEmailInput struct {
Token string `json:"token"` Token string `json:"token"`
} }
@@ -110,6 +119,7 @@ type CreateTaskInput struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
TimeEstimate time.Duration `json:"timeEstimate"` TimeEstimate time.Duration `json:"timeEstimate"`
AssignedToID *gid.GID `json:"assignedToId,omitempty"`
} }
type CreateTaskPayload struct { type CreateTaskPayload struct {
@@ -336,6 +346,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"` TimeEstimate time.Duration `json:"timeEstimate"`
AssignedTo *People `json:"assignedTo,omitempty"`
Evidences *EvidenceConnection `json:"evidences"` Evidences *EvidenceConnection `json:"evidences"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`
@@ -354,6 +365,14 @@ type TaskEdge struct {
Node *Task `json:"node"` Node *Task `json:"node"`
} }
type UnassignTaskInput struct {
TaskID gid.GID `json:"taskId"`
}
type UnassignTaskPayload struct {
Task *Task `json:"task"`
}
type UpdateControlInput struct { type UpdateControlInput struct {
ID gid.GID `json:"id"` ID gid.GID `json:"id"`
ExpectedVersion int `json:"expectedVersion"` ExpectedVersion int `json:"expectedVersion"`
@@ -422,6 +441,7 @@ type UpdateTaskInput struct {
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
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"`
} }
type UpdateTaskPayload struct { type UpdateTaskPayload struct {

View File

@@ -255,6 +255,34 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTas
}, nil }, nil
} }
// AssignTask is the resolver for the assignTask field.
func (r *mutationResolver) AssignTask(ctx context.Context, input types.AssignTaskInput) (*types.AssignTaskPayload, error) {
svc := r.GetTenantServiceIfAuthorized(ctx, input.TaskID.TenantID())
task, err := svc.Tasks.Assign(ctx, input.TaskID, input.AssignedToID)
if err != nil {
return nil, 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) {
svc := r.GetTenantServiceIfAuthorized(ctx, input.TaskID.TenantID())
task, err := svc.Tasks.Unassign(ctx, input.TaskID)
if err != nil {
return nil, fmt.Errorf("cannot unassign task: %w", err)
}
return &types.UnassignTaskPayload{
Task: types.NewTask(task),
}, nil
}
// CreateFramework is the resolver for the createFramework field. // CreateFramework is the resolver for the createFramework field.
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) { func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
svc := r.GetTenantServiceIfAuthorized(ctx, input.OrganizationID.TenantID()) svc := r.GetTenantServiceIfAuthorized(ctx, input.OrganizationID.TenantID())
@@ -581,6 +609,27 @@ func (r *queryResolver) Viewer(ctx context.Context) (*types.User, error) {
return types.NewUser(user), nil return types.NewUser(user), nil
} }
// AssignedTo is the resolver for the assignedTo field.
func (r *taskResolver) AssignedTo(ctx context.Context, obj *types.Task) (*types.People, error) {
svc := r.GetTenantServiceIfAuthorized(ctx, obj.ID.TenantID())
task, err := svc.Tasks.Get(ctx, obj.ID)
if err != nil {
return nil, fmt.Errorf("cannot get task: %w", err)
}
if task.AssignedTo == nil {
return nil, nil
}
people, err := svc.Peoples.Get(ctx, *task.AssignedTo)
if err != nil {
return nil, fmt.Errorf("cannot get assigned to: %w", err)
}
return types.NewPeople(people), nil
}
// Evidences is the resolver for the evidences field. // Evidences is the resolver for the evidences field.
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceConnection, error) { func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceConnection, error) {
svc := r.GetTenantServiceIfAuthorized(ctx, obj.ID.TenantID()) svc := r.GetTenantServiceIfAuthorized(ctx, obj.ID.TenantID())