@@ -7,7 +7,7 @@ import {
|
||||
useQueryLoader,
|
||||
useMutation,
|
||||
} from "react-relay";
|
||||
import { CheckCircle2, Plus } from "lucide-react";
|
||||
import { CheckCircle2, Plus, Trash2 } from "lucide-react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -26,6 +26,8 @@ import { Helmet } from "react-helmet-async";
|
||||
import type { ControlOverviewPageQuery as ControlOverviewPageQueryType } from "./__generated__/ControlOverviewPageQuery.graphql";
|
||||
import type { ControlOverviewPageUpdateTaskStateMutation as ControlOverviewPageUpdateTaskStateMutationType } from "./__generated__/ControlOverviewPageUpdateTaskStateMutation.graphql";
|
||||
import type { ControlOverviewPageCreateTaskMutation as ControlOverviewPageCreateTaskMutationType } from "./__generated__/ControlOverviewPageCreateTaskMutation.graphql";
|
||||
// The import below will be generated after the first run
|
||||
// import type { ControlOverviewPageDeleteTaskMutation as ControlOverviewPageDeleteTaskMutationType } from "./__generated__/ControlOverviewPageDeleteTaskMutation.graphql";
|
||||
|
||||
const controlOverviewPageQuery = graphql`
|
||||
query ControlOverviewPageQuery($controlId: ID!) {
|
||||
@@ -83,6 +85,17 @@ const createTaskMutation = graphql`
|
||||
}
|
||||
`;
|
||||
|
||||
const deleteTaskMutation = graphql`
|
||||
mutation ControlOverviewPageDeleteTaskMutation(
|
||||
$input: DeleteTaskInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
deleteTask(input: $input) {
|
||||
deletedTaskId @deleteEdge(connections: $connections)
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
function ControlOverviewPageContent({
|
||||
queryRef,
|
||||
}: {
|
||||
@@ -99,6 +112,8 @@ function ControlOverviewPageContent({
|
||||
);
|
||||
const [createTask] =
|
||||
useMutation<ControlOverviewPageCreateTaskMutationType>(createTaskMutation);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [deleteTask] = useMutation<any>(deleteTaskMutation);
|
||||
const control = data.control;
|
||||
const tasks = control?.tasks?.edges.map((edge) => edge?.node) ?? [];
|
||||
|
||||
@@ -107,6 +122,13 @@ function ControlOverviewPageContent({
|
||||
const [newTaskName, setNewTaskName] = useState("");
|
||||
const [newTaskDescription, setNewTaskDescription] = useState("");
|
||||
|
||||
// State for the delete task dialog
|
||||
const [isDeleteTaskOpen, setIsDeleteTaskOpen] = useState(false);
|
||||
const [taskToDelete, setTaskToDelete] = useState<{
|
||||
id: string;
|
||||
name: string;
|
||||
} | null>(null);
|
||||
|
||||
const handleTaskClick = (taskId: string, currentState: string) => {
|
||||
const newState = currentState === "DONE" ? "TODO" : "DONE";
|
||||
|
||||
@@ -192,6 +214,39 @@ function ControlOverviewPageContent({
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteTask = (taskId: string, taskName: string) => {
|
||||
setTaskToDelete({ id: taskId, name: taskName });
|
||||
setIsDeleteTaskOpen(true);
|
||||
};
|
||||
|
||||
const confirmDeleteTask = () => {
|
||||
if (!taskToDelete) return;
|
||||
|
||||
deleteTask({
|
||||
variables: {
|
||||
connections: [`${data.control?.tasks?.__id}`],
|
||||
input: {
|
||||
taskId: taskToDelete.id,
|
||||
},
|
||||
},
|
||||
onCompleted: () => {
|
||||
toast({
|
||||
title: "Task deleted",
|
||||
description: "Task has been deleted successfully.",
|
||||
});
|
||||
setIsDeleteTaskOpen(false);
|
||||
setTaskToDelete(null);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: "Error deleting task",
|
||||
description: error.message,
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white p-6 space-y-6">
|
||||
<div className="space-y-4">
|
||||
@@ -339,16 +394,16 @@ function ControlOverviewPageContent({
|
||||
</div>
|
||||
<div className="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<div className="text-gray-400 text-sm">06.00 - 07.30</div>
|
||||
<button className="text-gray-400 hover:text-gray-600">
|
||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M12 12h.01M12 6h.01M12 18h.01"
|
||||
/>
|
||||
</svg>
|
||||
<button
|
||||
className="text-gray-400 hover:text-red-600"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (task?.id && task?.name) {
|
||||
handleDeleteTask(task.id, task.name);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -362,6 +417,30 @@ function ControlOverviewPageContent({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Delete Task Confirmation Dialog */}
|
||||
<Dialog open={isDeleteTaskOpen} onOpenChange={setIsDeleteTaskOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Delete Task</DialogTitle>
|
||||
<DialogDescription>
|
||||
Are you sure you want to delete the task "
|
||||
{taskToDelete?.name}"? This action cannot be undone.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setIsDeleteTaskOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="destructive" onClick={confirmDeleteTask}>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
132
apps/console/src/pages/__generated__/ControlOverviewPageDeleteTaskMutation.graphql.ts
generated
Normal file
132
apps/console/src/pages/__generated__/ControlOverviewPageDeleteTaskMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @generated SignedSource<<cd5744c9739535825e9922b9cb95f034>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type DeleteTaskInput = {
|
||||
taskId: string;
|
||||
};
|
||||
export type ControlOverviewPageDeleteTaskMutation$variables = {
|
||||
connections: ReadonlyArray<string>;
|
||||
input: DeleteTaskInput;
|
||||
};
|
||||
export type ControlOverviewPageDeleteTaskMutation$data = {
|
||||
readonly deleteTask: {
|
||||
readonly deletedTaskId: string;
|
||||
};
|
||||
};
|
||||
export type ControlOverviewPageDeleteTaskMutation = {
|
||||
response: ControlOverviewPageDeleteTaskMutation$data;
|
||||
variables: ControlOverviewPageDeleteTaskMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = {
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "connections"
|
||||
},
|
||||
v1 = {
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
},
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "deletedTaskId",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": [
|
||||
(v0/*: any*/),
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "ControlOverviewPageDeleteTaskMutation",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "DeleteTaskPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "deleteTask",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": [
|
||||
(v1/*: any*/),
|
||||
(v0/*: any*/)
|
||||
],
|
||||
"kind": "Operation",
|
||||
"name": "ControlOverviewPageDeleteTaskMutation",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "DeleteTaskPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "deleteTask",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"filters": null,
|
||||
"handle": "deleteEdge",
|
||||
"key": "",
|
||||
"kind": "ScalarHandle",
|
||||
"name": "deletedTaskId",
|
||||
"handleArgs": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "connections",
|
||||
"variableName": "connections"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "06db9599a3e83354c0e865d08cdb29dd",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ControlOverviewPageDeleteTaskMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation ControlOverviewPageDeleteTaskMutation(\n $input: DeleteTaskInput!\n) {\n deleteTask(input: $input) {\n deletedTaskId\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "885a98007e48ab3175d0480c5a750e19";
|
||||
|
||||
export default node;
|
||||
@@ -393,6 +393,7 @@ type Mutation {
|
||||
): DeleteOrganizationPayload!
|
||||
updateTaskState(input: UpdateTaskStateInput!): UpdateTaskStatePayload!
|
||||
createTask(input: CreateTaskInput!): CreateTaskPayload!
|
||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||
}
|
||||
|
||||
input CreateVendorInput {
|
||||
@@ -531,3 +532,11 @@ input CreateTaskInput {
|
||||
type CreateTaskPayload {
|
||||
taskEdge: TaskEdge!
|
||||
}
|
||||
|
||||
input DeleteTaskInput {
|
||||
taskId: ID!
|
||||
}
|
||||
|
||||
type DeleteTaskPayload {
|
||||
deletedTaskId: ID!
|
||||
}
|
||||
|
||||
@@ -121,6 +121,10 @@ type ComplexityRoot struct {
|
||||
DeletedPeopleID func(childComplexity int) int
|
||||
}
|
||||
|
||||
DeleteTaskPayload struct {
|
||||
DeletedTaskID func(childComplexity int) int
|
||||
}
|
||||
|
||||
DeleteVendorPayload struct {
|
||||
DeletedVendorID func(childComplexity int) int
|
||||
}
|
||||
@@ -191,6 +195,7 @@ type ComplexityRoot struct {
|
||||
CreateVendor func(childComplexity int, input types.CreateVendorInput) int
|
||||
DeleteOrganization func(childComplexity int, input types.DeleteOrganizationInput) int
|
||||
DeletePeople func(childComplexity int, input types.DeletePeopleInput) int
|
||||
DeleteTask func(childComplexity int, input types.DeleteTaskInput) int
|
||||
DeleteVendor func(childComplexity int, input types.DeleteVendorInput) int
|
||||
UpdatePeople func(childComplexity int, input types.UpdatePeopleInput) int
|
||||
UpdateTaskState func(childComplexity int, input types.UpdateTaskStateInput) int
|
||||
@@ -357,6 +362,7 @@ type MutationResolver interface {
|
||||
DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error)
|
||||
UpdateTaskState(ctx context.Context, input types.UpdateTaskStateInput) (*types.UpdateTaskStatePayload, error)
|
||||
CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error)
|
||||
DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error)
|
||||
}
|
||||
type OrganizationResolver interface {
|
||||
Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error)
|
||||
@@ -607,6 +613,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.DeletePeoplePayload.DeletedPeopleID(childComplexity), true
|
||||
|
||||
case "DeleteTaskPayload.deletedTaskId":
|
||||
if e.complexity.DeleteTaskPayload.DeletedTaskID == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.DeleteTaskPayload.DeletedTaskID(childComplexity), true
|
||||
|
||||
case "DeleteVendorPayload.deletedVendorId":
|
||||
if e.complexity.DeleteVendorPayload.DeletedVendorID == nil {
|
||||
break
|
||||
@@ -920,6 +933,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Mutation.DeletePeople(childComplexity, args["input"].(types.DeletePeopleInput)), true
|
||||
|
||||
case "Mutation.deleteTask":
|
||||
if e.complexity.Mutation.DeleteTask == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_deleteTask_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.DeleteTask(childComplexity, args["input"].(types.DeleteTaskInput)), true
|
||||
|
||||
case "Mutation.deleteVendor":
|
||||
if e.complexity.Mutation.DeleteVendor == nil {
|
||||
break
|
||||
@@ -1563,6 +1588,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
ec.unmarshalInputCreateVendorInput,
|
||||
ec.unmarshalInputDeleteOrganizationInput,
|
||||
ec.unmarshalInputDeletePeopleInput,
|
||||
ec.unmarshalInputDeleteTaskInput,
|
||||
ec.unmarshalInputDeleteVendorInput,
|
||||
ec.unmarshalInputUpdatePeopleInput,
|
||||
ec.unmarshalInputUpdateTaskStateInput,
|
||||
@@ -2059,6 +2085,7 @@ type Mutation {
|
||||
): DeleteOrganizationPayload!
|
||||
updateTaskState(input: UpdateTaskStateInput!): UpdateTaskStatePayload!
|
||||
createTask(input: CreateTaskInput!): CreateTaskPayload!
|
||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||
}
|
||||
|
||||
input CreateVendorInput {
|
||||
@@ -2197,6 +2224,14 @@ input CreateTaskInput {
|
||||
type CreateTaskPayload {
|
||||
taskEdge: TaskEdge!
|
||||
}
|
||||
|
||||
input DeleteTaskInput {
|
||||
taskId: ID!
|
||||
}
|
||||
|
||||
type DeleteTaskPayload {
|
||||
deletedTaskId: ID!
|
||||
}
|
||||
`, BuiltIn: false},
|
||||
}
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
@@ -2651,6 +2686,29 @@ func (ec *executionContext) field_Mutation_deletePeople_argsInput(
|
||||
return zeroVal, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_deleteTask_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
arg0, err := ec.field_Mutation_deleteTask_argsInput(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args["input"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
func (ec *executionContext) field_Mutation_deleteTask_argsInput(
|
||||
ctx context.Context,
|
||||
rawArgs map[string]any,
|
||||
) (types.DeleteTaskInput, error) {
|
||||
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||
if tmp, ok := rawArgs["input"]; ok {
|
||||
return ec.unmarshalNDeleteTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteTaskInput(ctx, tmp)
|
||||
}
|
||||
|
||||
var zeroVal types.DeleteTaskInput
|
||||
return zeroVal, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_deleteVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
@@ -4513,6 +4571,44 @@ func (ec *executionContext) fieldContext_DeletePeoplePayload_deletedPeopleId(_ c
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DeleteTaskPayload_deletedTaskId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteTaskPayload) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DeleteTaskPayload_deletedTaskId(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.DeletedTaskID, 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.(gid.GID)
|
||||
fc.Result = res
|
||||
return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_DeleteTaskPayload_deletedTaskId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "DeleteTaskPayload",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type ID does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DeleteVendorPayload_deletedVendorId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteVendorPayload) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DeleteVendorPayload_deletedVendorId(ctx, field)
|
||||
if err != nil {
|
||||
@@ -6385,6 +6481,53 @@ func (ec *executionContext) fieldContext_Mutation_createTask(ctx context.Context
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_deleteTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_deleteTask(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().DeleteTask(rctx, fc.Args["input"].(types.DeleteTaskInput))
|
||||
})
|
||||
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.DeleteTaskPayload)
|
||||
fc.Result = res
|
||||
return ec.marshalNDeleteTaskPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteTaskPayload(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_deleteTask(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 "deletedTaskId":
|
||||
return ec.fieldContext_DeleteTaskPayload_deletedTaskId(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type DeleteTaskPayload", field.Name)
|
||||
},
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_deleteTask_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Organization_id(ctx context.Context, field graphql.CollectedField, obj *types.Organization) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Organization_id(ctx, field)
|
||||
if err != nil {
|
||||
@@ -11533,6 +11676,33 @@ func (ec *executionContext) unmarshalInputDeletePeopleInput(ctx context.Context,
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputDeleteTaskInput(ctx context.Context, obj any) (types.DeleteTaskInput, error) {
|
||||
var it types.DeleteTaskInput
|
||||
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) unmarshalInputDeleteVendorInput(ctx context.Context, obj any) (types.DeleteVendorInput, error) {
|
||||
var it types.DeleteVendorInput
|
||||
asMap := map[string]any{}
|
||||
@@ -12425,6 +12595,45 @@ func (ec *executionContext) _DeletePeoplePayload(ctx context.Context, sel ast.Se
|
||||
return out
|
||||
}
|
||||
|
||||
var deleteTaskPayloadImplementors = []string{"DeleteTaskPayload"}
|
||||
|
||||
func (ec *executionContext) _DeleteTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteTaskPayload) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, deleteTaskPayloadImplementors)
|
||||
|
||||
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("DeleteTaskPayload")
|
||||
case "deletedTaskId":
|
||||
out.Values[i] = ec._DeleteTaskPayload_deletedTaskId(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 deleteVendorPayloadImplementors = []string{"DeleteVendorPayload"}
|
||||
|
||||
func (ec *executionContext) _DeleteVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteVendorPayload) graphql.Marshaler {
|
||||
@@ -13065,6 +13274,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "deleteTask":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_deleteTask(ctx, field)
|
||||
})
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
@@ -14990,6 +15206,25 @@ func (ec *executionContext) marshalNDeletePeoplePayload2ᚖgithubᚗcomᚋgetpro
|
||||
return ec._DeletePeoplePayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNDeleteTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteTaskInput(ctx context.Context, v any) (types.DeleteTaskInput, error) {
|
||||
res, err := ec.unmarshalInputDeleteTaskInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNDeleteTaskPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteTaskPayload(ctx context.Context, sel ast.SelectionSet, v types.DeleteTaskPayload) graphql.Marshaler {
|
||||
return ec._DeleteTaskPayload(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNDeleteTaskPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteTaskPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteTaskPayload) 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._DeleteTaskPayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNDeleteVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorInput(ctx context.Context, v any) (types.DeleteVendorInput, error) {
|
||||
res, err := ec.unmarshalInputDeleteVendorInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
||||
@@ -122,6 +122,14 @@ type DeletePeoplePayload struct {
|
||||
DeletedPeopleID gid.GID `json:"deletedPeopleId"`
|
||||
}
|
||||
|
||||
type DeleteTaskInput struct {
|
||||
TaskID gid.GID `json:"taskId"`
|
||||
}
|
||||
|
||||
type DeleteTaskPayload struct {
|
||||
DeletedTaskID gid.GID `json:"deletedTaskId"`
|
||||
}
|
||||
|
||||
type DeleteVendorInput struct {
|
||||
VendorID gid.GID `json:"vendorId"`
|
||||
}
|
||||
|
||||
@@ -225,6 +225,18 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTas
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteTask is the resolver for the deleteTask field.
|
||||
func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) {
|
||||
err := r.proboSvc.DeleteTask(ctx, input.TaskID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete task: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteTaskPayload{
|
||||
DeletedTaskID: input.TaskID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Frameworks is the resolver for the frameworks field.
|
||||
func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error) {
|
||||
cursor := types.NewCursor(first, after, last, before)
|
||||
|
||||
@@ -269,3 +269,75 @@ WHERE
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Task) Delete(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope *Scope,
|
||||
) error {
|
||||
// Use a single transaction with conditional logic to handle both cases
|
||||
q := `
|
||||
WITH control_count AS (
|
||||
SELECT COUNT(*) AS count FROM controls_tasks WHERE task_id = @task_id
|
||||
),
|
||||
delete_link AS (
|
||||
DELETE FROM controls_tasks
|
||||
WHERE task_id = @task_id AND control_id = @control_id
|
||||
RETURNING task_id
|
||||
),
|
||||
delete_transitions AS (
|
||||
DELETE FROM task_state_transitions
|
||||
WHERE %s AND task_id = @task_id AND (SELECT count FROM control_count) <= 1
|
||||
RETURNING task_id
|
||||
),
|
||||
delete_all_links AS (
|
||||
DELETE FROM controls_tasks
|
||||
WHERE task_id = @task_id AND (SELECT count FROM control_count) <= 1
|
||||
RETURNING task_id
|
||||
),
|
||||
delete_task AS (
|
||||
DELETE FROM tasks
|
||||
WHERE %s AND id = @task_id AND (SELECT count FROM control_count) <= 1
|
||||
RETURNING id
|
||||
)
|
||||
SELECT
|
||||
(SELECT count FROM control_count) AS control_count,
|
||||
(SELECT COUNT(*) FROM delete_link) AS deleted_links,
|
||||
(SELECT COUNT(*) FROM delete_transitions) AS deleted_transitions,
|
||||
(SELECT COUNT(*) FROM delete_all_links) AS deleted_all_links,
|
||||
(SELECT COUNT(*) FROM delete_task) AS deleted_tasks;
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), scope.SQLFragment())
|
||||
|
||||
args := pgx.NamedArgs{
|
||||
"task_id": t.ID,
|
||||
"control_id": t.ControlID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
var controlCount, deletedLinks, deletedTransitions, deletedAllLinks, deletedTasks int
|
||||
err := conn.QueryRow(ctx, q, args).Scan(
|
||||
&controlCount,
|
||||
&deletedLinks,
|
||||
&deletedTransitions,
|
||||
&deletedAllLinks,
|
||||
&deletedTasks,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot execute delete operation: %w", err)
|
||||
}
|
||||
|
||||
if controlCount <= 1 {
|
||||
if deletedTransitions == 0 || deletedAllLinks == 0 || deletedTasks == 0 {
|
||||
return fmt.Errorf("failed to delete task completely: transitions=%d, links=%d, tasks=%d",
|
||||
deletedTransitions, deletedAllLinks, deletedTasks)
|
||||
}
|
||||
} else {
|
||||
if deletedLinks == 0 {
|
||||
return fmt.Errorf("failed to delete control-task link")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
22
pkg/probo/delete_task.go
Normal file
22
pkg/probo/delete_task.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package probo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/getprobo/probo/pkg/gid"
|
||||
"github.com/getprobo/probo/pkg/probo/coredata"
|
||||
"go.gearno.de/kit/pg"
|
||||
)
|
||||
|
||||
func (s Service) DeleteTask(
|
||||
ctx context.Context,
|
||||
taskID gid.GID,
|
||||
) error {
|
||||
task := coredata.Task{ID: taskID}
|
||||
return s.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return task.Delete(ctx, conn, s.scope)
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user