diff --git a/apps/console/src/hooks/graph/VendorGraph.ts b/apps/console/src/hooks/graph/VendorGraph.ts index 8d037fe90..a1689e57f 100644 --- a/apps/console/src/hooks/graph/VendorGraph.ts +++ b/apps/console/src/hooks/graph/VendorGraph.ts @@ -152,6 +152,7 @@ export const vendorNodeQuery = graphql` websiteUrl ...useVendorFormFragment ...VendorComplianceTabFragment + ...VendorContactsTabFragment ...VendorRiskAssessmentTabFragment ...VendorOverviewTabBusinessAssociateAgreementFragment } diff --git a/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts index 68236ba76..22cc41b4c 100644 --- a/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<9174011c1abd05e499786607130d0c82>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -19,7 +19,7 @@ export type VendorGraphNodeQuery$data = { readonly id?: string; readonly name?: string; readonly websiteUrl?: string | null | undefined; - readonly " $fragmentSpreads": FragmentRefs<"VendorComplianceTabFragment" | "VendorOverviewTabBusinessAssociateAgreementFragment" | "VendorRiskAssessmentTabFragment" | "useVendorFormFragment">; + readonly " $fragmentSpreads": FragmentRefs<"VendorComplianceTabFragment" | "VendorContactsTabFragment" | "VendorOverviewTabBusinessAssociateAgreementFragment" | "VendorRiskAssessmentTabFragment" | "useVendorFormFragment">; }; readonly viewer: { readonly user: { @@ -156,6 +156,21 @@ v16 = { "storageKey": null }, v17 = { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + (v13/*: any*/), + (v14/*: any*/), + (v15/*: any*/), + (v16/*: any*/) + ], + "storageKey": null +}, +v18 = { "kind": "ClientExtension", "selections": [ { @@ -167,9 +182,23 @@ v17 = { } ] }, -v18 = [ +v19 = [ "orderBy" -]; +], +v20 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null +}, +v21 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}; return { "fragment": { "argumentDefinitions": [ @@ -204,6 +233,11 @@ return { "kind": "FragmentSpread", "name": "VendorComplianceTabFragment" }, + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorContactsTabFragment" + }, { "args": null, "kind": "FragmentSpread", @@ -425,34 +459,97 @@ return { ], "storageKey": null }, - { - "alias": null, - "args": null, - "concreteType": "PageInfo", - "kind": "LinkedField", - "name": "pageInfo", - "plural": false, - "selections": [ - (v13/*: any*/), - (v14/*: any*/), - (v15/*: any*/), - (v16/*: any*/) - ], - "storageKey": null - }, - (v17/*: any*/) + (v17/*: any*/), + (v18/*: any*/) ], "storageKey": "complianceReports(first:50)" }, { "alias": null, "args": (v9/*: any*/), - "filters": (v18/*: any*/), + "filters": (v19/*: any*/), "handle": "connection", "key": "VendorComplianceTabFragment_complianceReports", "kind": "LinkedHandle", "name": "complianceReports" }, + { + "alias": null, + "args": (v9/*: any*/), + "concreteType": "VendorContactConnection", + "kind": "LinkedField", + "name": "contacts", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContactEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + (v20/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "phone", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + (v21/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + }, + (v8/*: any*/) + ], + "storageKey": null + }, + (v12/*: any*/) + ], + "storageKey": null + }, + (v17/*: any*/), + (v18/*: any*/) + ], + "storageKey": "contacts(first:50)" + }, + { + "alias": null, + "args": (v9/*: any*/), + "filters": (v19/*: any*/), + "handle": "connection", + "key": "VendorContactsTabFragment_contacts", + "kind": "LinkedHandle", + "name": "contacts" + }, { "alias": null, "args": (v9/*: any*/), @@ -494,13 +591,7 @@ return { "plural": false, "selections": [ (v3/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "fullName", - "storageKey": null - } + (v20/*: any*/) ], "storageKey": null }, @@ -555,14 +646,14 @@ return { ], "storageKey": null }, - (v17/*: any*/) + (v18/*: any*/) ], "storageKey": "riskAssessments(first:50)" }, { "alias": null, "args": (v9/*: any*/), - "filters": (v18/*: any*/), + "filters": (v19/*: any*/), "handle": "connection", "key": "VendorRiskAssessmentTabFragment_riskAssessments", "kind": "LinkedHandle", @@ -593,13 +684,7 @@ return { "storageKey": null }, (v10/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null - } + (v21/*: any*/) ], "storageKey": null } @@ -638,16 +723,16 @@ return { ] }, "params": { - "cacheID": "95f9f21af1253d08c97dfd7d2f65f2e3", + "cacheID": "506d89b503073e18cbf657aec5d62c71", "id": null, "metadata": {}, "name": "VendorGraphNodeQuery", "operationKind": "query", - "text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n }\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n" + "text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n }\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n" } }; })(); -(node as any).hash = "c80a167ea096212995f1d3261bc2bf57"; +(node as any).hash = "b5ea2120ec2f0f09ed29e19bbf232622"; export default node; diff --git a/apps/console/src/pages/organizations/vendors/VendorDetailPage.tsx b/apps/console/src/pages/organizations/vendors/VendorDetailPage.tsx index 7de4774e5..d69ea1821 100644 --- a/apps/console/src/pages/organizations/vendors/VendorDetailPage.tsx +++ b/apps/console/src/pages/organizations/vendors/VendorDetailPage.tsx @@ -112,6 +112,11 @@ export default function VendorDetailPage(props: Props) { > {__("Risk Assessment")} + + {__("Contacts")} + diff --git a/apps/console/src/pages/organizations/vendors/dialogs/CreateContactDialog.tsx b/apps/console/src/pages/organizations/vendors/dialogs/CreateContactDialog.tsx new file mode 100644 index 000000000..8bea0b070 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/CreateContactDialog.tsx @@ -0,0 +1,143 @@ +import { useTranslate } from "@probo/i18n"; +import { + Breadcrumb, + Button, + Dialog, + DialogContent, + DialogFooter, + Field, + useDialogRef, +} from "@probo/ui"; +import { cleanFormData } from "@probo/helpers"; +import { type ReactNode } from "react"; +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { z } from "zod"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; + +type Props = { + children: ReactNode; + connectionId: string; + vendorId: string; +}; + +const createContactMutation = graphql` + mutation CreateContactDialogMutation( + $input: CreateVendorContactInput! + $connections: [ID!]! + ) { + createVendorContact(input: $input) { + vendorContactEdge @prependEdge(connections: $connections) { + node { + ...VendorContactsTabFragment_contact + } + } + } + } +`; + +const phoneRegex = /^\+[0-9]{8,15}$/; + +export function CreateContactDialog({ + children, + connectionId, + vendorId, +}: Props) { + const { __ } = useTranslate(); + + const schema = z.object({ + fullName: z.string().optional(), + email: z.string().email(__("Please enter a valid email address")).optional().or(z.literal("")), + phone: z.string().regex(phoneRegex, __("Phone number must be in international format (e.g., +1234567890)")).optional().or(z.literal("")), + role: z.string().optional(), + }); + + const { register, handleSubmit, formState, reset } = useFormWithSchema( + schema, + { + defaultValues: { + fullName: "", + email: "", + phone: "", + role: "", + }, + } + ); + const [createContact, isLoading] = useMutationWithToasts( + createContactMutation, + { + successMessage: __("Contact created successfully."), + errorMessage: __("Failed to create contact. Please try again."), + } + ); + + const onSubmit = handleSubmit((data) => { + const cleanData = cleanFormData(data); + + createContact({ + variables: { + input: { + vendorId, + ...cleanData, + }, + connections: [connectionId], + }, + onSuccess: () => { + dialogRef.current?.close(); + reset(); + }, + }); + }); + + const dialogRef = useDialogRef(); + + return ( + + } + > +
+ + + + + + + + + +
+
+ ); +} diff --git a/apps/console/src/pages/organizations/vendors/dialogs/EditContactDialog.tsx b/apps/console/src/pages/organizations/vendors/dialogs/EditContactDialog.tsx new file mode 100644 index 000000000..8c1ddcb27 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/EditContactDialog.tsx @@ -0,0 +1,142 @@ +import { useTranslate } from "@probo/i18n"; +import { + Breadcrumb, + Button, + Dialog, + DialogContent, + DialogFooter, + Field, + useDialogRef, +} from "@probo/ui"; +import { cleanFormData } from "@probo/helpers"; +import { useEffect } from "react"; +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { z } from "zod"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; + +type Props = { + contactId: string; + contact: { + fullName?: string | null; + email?: string | null; + phone?: string | null; + role?: string | null; + }; + onClose: () => void; +}; + +const updateContactMutation = graphql` + mutation EditContactDialogUpdateMutation($input: UpdateVendorContactInput!) { + updateVendorContact(input: $input) { + vendorContact { + ...VendorContactsTabFragment_contact + } + } + } +`; + +const phoneRegex = /^\+[0-9]{8,15}$/; + +export function EditContactDialog({ contactId, contact, onClose }: Props) { + const { __ } = useTranslate(); + + const schema = z.object({ + fullName: z.string().optional(), + email: z.string().email(__("Please enter a valid email address")).optional().or(z.literal("")), + phone: z.string().regex(phoneRegex, __("Phone number must be in international format (e.g., +1234567890)")).optional().or(z.literal("")), + role: z.string().optional(), + }); + + const { register, handleSubmit, formState } = useFormWithSchema( + schema, + { + defaultValues: { + fullName: contact.fullName || "", + email: contact.email || "", + phone: contact.phone || "", + role: contact.role || "", + }, + } + ); + + const [updateContact, isLoading] = useMutationWithToasts( + updateContactMutation, + { + successMessage: __("Contact updated successfully."), + errorMessage: __("Failed to update contact. Please try again."), + } + ); + + const onSubmit = handleSubmit((data) => { + const cleanData = cleanFormData(data); + + updateContact({ + variables: { + input: { + id: contactId, + ...cleanData, + }, + }, + onSuccess: () => { + onClose(); + }, + }); + }); + + const dialogRef = useDialogRef(); + + useEffect(() => { + dialogRef.current?.open(); + }, []); + + return ( + + } + > +
+ + + + + + + + + +
+
+ ); +} diff --git a/apps/console/src/pages/organizations/vendors/dialogs/__generated__/CreateContactDialogMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/CreateContactDialogMutation.graphql.ts new file mode 100644 index 000000000..d6d0ff330 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/CreateContactDialogMutation.graphql.ts @@ -0,0 +1,230 @@ +/** + * @generated SignedSource<<843a80b3503ff276081e69b558dcce81>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type CreateVendorContactInput = { + email?: string | null | undefined; + fullName?: string | null | undefined; + phone?: string | null | undefined; + role?: string | null | undefined; + vendorId: string; +}; +export type CreateContactDialogMutation$variables = { + connections: ReadonlyArray; + input: CreateVendorContactInput; +}; +export type CreateContactDialogMutation$data = { + readonly createVendorContact: { + readonly vendorContactEdge: { + readonly node: { + readonly " $fragmentSpreads": FragmentRefs<"VendorContactsTabFragment_contact">; + }; + }; + }; +}; +export type CreateContactDialogMutation = { + response: CreateContactDialogMutation$data; + variables: CreateContactDialogMutation$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" + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "CreateContactDialogMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateVendorContactPayload", + "kind": "LinkedField", + "name": "createVendorContact", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContactEdge", + "kind": "LinkedField", + "name": "vendorContactEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorContactsTabFragment_contact" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "CreateContactDialogMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateVendorContactPayload", + "kind": "LinkedField", + "name": "createVendorContact", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContactEdge", + "kind": "LinkedField", + "name": "vendorContactEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "phone", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "filters": null, + "handle": "prependEdge", + "key": "", + "kind": "LinkedHandle", + "name": "vendorContactEdge", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "dac4774aa797162239a60596464811d8", + "id": null, + "metadata": {}, + "name": "CreateContactDialogMutation", + "operationKind": "mutation", + "text": "mutation CreateContactDialogMutation(\n $input: CreateVendorContactInput!\n) {\n createVendorContact(input: $input) {\n vendorContactEdge {\n node {\n ...VendorContactsTabFragment_contact\n id\n }\n }\n }\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n" + } +}; +})(); + +(node as any).hash = "f44f76bce42470683c55db50426d3f7b"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditContactDialogUpdateMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditContactDialogUpdateMutation.graphql.ts new file mode 100644 index 000000000..fc6b96344 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditContactDialogUpdateMutation.graphql.ts @@ -0,0 +1,180 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type UpdateVendorContactInput = { + email?: string | null | undefined; + fullName?: string | null | undefined; + id: string; + phone?: string | null | undefined; + role?: string | null | undefined; +}; +export type EditContactDialogUpdateMutation$variables = { + input: UpdateVendorContactInput; +}; +export type EditContactDialogUpdateMutation$data = { + readonly updateVendorContact: { + readonly vendorContact: { + readonly " $fragmentSpreads": FragmentRefs<"VendorContactsTabFragment_contact">; + }; + }; +}; +export type EditContactDialogUpdateMutation = { + response: EditContactDialogUpdateMutation$data; + variables: EditContactDialogUpdateMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "EditContactDialogUpdateMutation", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "UpdateVendorContactPayload", + "kind": "LinkedField", + "name": "updateVendorContact", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "vendorContact", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorContactsTabFragment_contact" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "EditContactDialogUpdateMutation", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "UpdateVendorContactPayload", + "kind": "LinkedField", + "name": "updateVendorContact", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "vendorContact", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "phone", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "bacc163156572b5da49705a27084f5c9", + "id": null, + "metadata": {}, + "name": "EditContactDialogUpdateMutation", + "operationKind": "mutation", + "text": "mutation EditContactDialogUpdateMutation(\n $input: UpdateVendorContactInput!\n) {\n updateVendorContact(input: $input) {\n vendorContact {\n ...VendorContactsTabFragment_contact\n id\n }\n }\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n" + } +}; +})(); + +(node as any).hash = "845750bb920bd01ed91bbae1531aaaf0"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/tabs/VendorContactsTab.tsx b/apps/console/src/pages/organizations/vendors/tabs/VendorContactsTab.tsx new file mode 100644 index 000000000..6850a3d05 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/tabs/VendorContactsTab.tsx @@ -0,0 +1,251 @@ +import { useOutletContext } from "react-router"; +import { graphql } from "relay-runtime"; +import type { VendorContactsTabFragment$key } from "./__generated__/VendorContactsTabFragment.graphql"; +import { useTranslate } from "@probo/i18n"; +import { usePageTitle } from "@probo/hooks"; +import { + ActionDropdown, + Button, + DropdownItem, + IconPlusLarge, + IconTrashCan, + IconPencil, + PageHeader, + Tbody, + Td, + Th, + Thead, + Tr, + useConfirm, +} from "@probo/ui"; +import { useFragment, useRefetchableFragment } from "react-relay"; +import type { VendorContactsTabFragment_contact$key } from "./__generated__/VendorContactsTabFragment_contact.graphql"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { sprintf } from "@probo/helpers"; +import { SortableTable, SortableTh } from "/components/SortableTable"; +import { CreateContactDialog } from "../dialogs/CreateContactDialog"; +import { EditContactDialog } from "../dialogs/EditContactDialog"; +import { useState } from "react"; + +export const vendorContactsFragment = graphql` + fragment VendorContactsTabFragment on Vendor + @refetchable(queryName: "VendorContactsListQuery") + @argumentDefinitions( + first: { type: "Int", defaultValue: 50 } + order: { type: "VendorContactOrder", defaultValue: null } + after: { type: "CursorKey", defaultValue: null } + before: { type: "CursorKey", defaultValue: null } + last: { type: "Int", defaultValue: null } + ) { + contacts( + first: $first + after: $after + last: $last + before: $before + orderBy: $order + ) @connection(key: "VendorContactsTabFragment_contacts") { + __id + edges { + node { + id + ...VendorContactsTabFragment_contact + } + } + } + } +`; + +const contactFragment = graphql` + fragment VendorContactsTabFragment_contact on VendorContact { + id + fullName + email + phone + role + createdAt + updatedAt + } +`; + +const deleteContactMutation = graphql` + mutation VendorContactsTabDeleteContactMutation( + $input: DeleteVendorContactInput! + $connections: [ID!]! + ) { + deleteVendorContact(input: $input) { + deletedVendorContactId @deleteEdge(connections: $connections) + } + } +`; + +export default function VendorContactsTab() { + const { vendor } = useOutletContext<{ + vendor: VendorContactsTabFragment$key & { name: string; id: string }; + }>(); + const [data, refetch] = useRefetchableFragment( + vendorContactsFragment, + vendor + ); + const connectionId = data.contacts.__id; + const contacts = data.contacts.edges.map((edge) => edge.node); + const { __ } = useTranslate(); + const [editingContact, setEditingContact] = useState<{ + id: string; + fullName?: string | null; + email?: string | null; + phone?: string | null; + role?: string | null; + } | null>(null); + + usePageTitle(vendor.name + " - " + __("Contacts")); + + return ( +
+ + + + + + + + + + {__("Name")} + {__("Email")} + {__("Phone")} + {__("Role")} + {__("Created")} + {__("Actions")} + + + + {contacts.map((contact) => ( + + ))} + + + + {editingContact && ( + setEditingContact(null)} + /> + )} +
+ ); +} + +type ContactRowProps = { + contactKey: VendorContactsTabFragment_contact$key; + connectionId: string; + onEdit: (contact: { + id: string; + fullName?: string | null; + email?: string | null; + phone?: string | null; + role?: string | null; + }) => void; +}; + +function ContactRow(props: ContactRowProps) { + const { __ } = useTranslate(); + const contact = useFragment( + contactFragment, + props.contactKey + ); + const { dateFormat } = useTranslate(); + const confirm = useConfirm(); + const [deleteContact] = useMutationWithToasts(deleteContactMutation, { + successMessage: __("Contact deleted successfully"), + errorMessage: __("Failed to delete contact"), + }); + + const handleDelete = () => { + confirm( + () => + deleteContact({ + variables: { + connections: [props.connectionId], + input: { + vendorContactId: contact.id, + }, + }, + }), + { + message: sprintf( + __( + 'This will permanently delete the contact "%s". This action cannot be undone.' + ), + contact.fullName || contact.email || __("Unnamed contact") + ), + } + ); + }; + + return ( + + {contact.fullName || __("—")} + + {contact.email ? ( + + {contact.email} + + ) : ( + __("—") + )} + + + {contact.phone ? ( + + {contact.phone} + + ) : ( + __("—") + )} + + {contact.role || __("—")} + {dateFormat(contact.createdAt)} + + + props.onEdit({ + id: contact.id, + fullName: contact.fullName, + email: contact.email, + phone: contact.phone, + role: contact.role, + })} + > + {__("Edit")} + + + {__("Delete")} + + + + + ); +} diff --git a/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsListQuery.graphql.ts b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsListQuery.graphql.ts new file mode 100644 index 000000000..2d9db8f6a --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsListQuery.graphql.ts @@ -0,0 +1,358 @@ +/** + * @generated SignedSource<<65134b167a4268ed8064021f2c608899>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type OrderDirection = "ASC" | "DESC"; +export type VendorContactOrderField = "CREATED_AT" | "EMAIL" | "FULL_NAME"; +export type VendorContactOrder = { + direction: OrderDirection; + field: VendorContactOrderField; +}; +export type VendorContactsListQuery$variables = { + after?: any | null | undefined; + before?: any | null | undefined; + first?: number | null | undefined; + id: string; + last?: number | null | undefined; + order?: VendorContactOrder | null | undefined; +}; +export type VendorContactsListQuery$data = { + readonly node: { + readonly " $fragmentSpreads": FragmentRefs<"VendorContactsTabFragment">; + }; +}; +export type VendorContactsListQuery = { + response: VendorContactsListQuery$data; + variables: VendorContactsListQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "before" +}, +v2 = { + "defaultValue": 50, + "kind": "LocalArgument", + "name": "first" +}, +v3 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" +}, +v4 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "last" +}, +v5 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "order" +}, +v6 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +], +v7 = { + "kind": "Variable", + "name": "after", + "variableName": "after" +}, +v8 = { + "kind": "Variable", + "name": "before", + "variableName": "before" +}, +v9 = { + "kind": "Variable", + "name": "first", + "variableName": "first" +}, +v10 = { + "kind": "Variable", + "name": "last", + "variableName": "last" +}, +v11 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v12 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v13 = [ + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + { + "kind": "Variable", + "name": "orderBy", + "variableName": "order" + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "VendorContactsListQuery", + "selections": [ + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": [ + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + { + "kind": "Variable", + "name": "order", + "variableName": "order" + } + ], + "kind": "FragmentSpread", + "name": "VendorContactsTabFragment" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v3/*: any*/) + ], + "kind": "Operation", + "name": "VendorContactsListQuery", + "selections": [ + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v11/*: any*/), + (v12/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": (v13/*: any*/), + "concreteType": "VendorContactConnection", + "kind": "LinkedField", + "name": "contacts", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContactEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v12/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "phone", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + }, + (v11/*: 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 + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasPreviousPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "startCursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + }, + { + "alias": null, + "args": (v13/*: any*/), + "filters": [ + "orderBy" + ], + "handle": "connection", + "key": "VendorContactsTabFragment_contacts", + "kind": "LinkedHandle", + "name": "contacts" + } + ], + "type": "Vendor", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "bc07b88571f6a7fbb20595cbf442d3b8", + "id": null, + "metadata": {}, + "name": "VendorContactsListQuery", + "operationKind": "query", + "text": "query VendorContactsListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 50\n $last: Int = null\n $order: VendorContactOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...VendorContactsTabFragment_16fISc\n id\n }\n}\n\nfragment VendorContactsTabFragment_16fISc on Vendor {\n contacts(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n" + } +}; +})(); + +(node as any).hash = "aa8ba87386ba04dd624566661fe0a524"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabDeleteContactMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabDeleteContactMutation.graphql.ts new file mode 100644 index 000000000..cc5003970 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabDeleteContactMutation.graphql.ts @@ -0,0 +1,132 @@ +/** + * @generated SignedSource<<3824bce11d22a60d1e50f53c699611c5>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type DeleteVendorContactInput = { + vendorContactId: string; +}; +export type VendorContactsTabDeleteContactMutation$variables = { + connections: ReadonlyArray; + input: DeleteVendorContactInput; +}; +export type VendorContactsTabDeleteContactMutation$data = { + readonly deleteVendorContact: { + readonly deletedVendorContactId: string; + }; +}; +export type VendorContactsTabDeleteContactMutation = { + response: VendorContactsTabDeleteContactMutation$data; + variables: VendorContactsTabDeleteContactMutation$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": "deletedVendorContactId", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "VendorContactsTabDeleteContactMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "DeleteVendorContactPayload", + "kind": "LinkedField", + "name": "deleteVendorContact", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "VendorContactsTabDeleteContactMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "DeleteVendorContactPayload", + "kind": "LinkedField", + "name": "deleteVendorContact", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "filters": null, + "handle": "deleteEdge", + "key": "", + "kind": "ScalarHandle", + "name": "deletedVendorContactId", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "806c0b076e6da2ac4841d172047c8655", + "id": null, + "metadata": {}, + "name": "VendorContactsTabDeleteContactMutation", + "operationKind": "mutation", + "text": "mutation VendorContactsTabDeleteContactMutation(\n $input: DeleteVendorContactInput!\n) {\n deleteVendorContact(input: $input) {\n deletedVendorContactId\n }\n}\n" + } +}; +})(); + +(node as any).hash = "f0595bed2e2e7527eeac8737a0640a4d"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabFragment.graphql.ts b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabFragment.graphql.ts new file mode 100644 index 000000000..a2962dfa9 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabFragment.graphql.ts @@ -0,0 +1,225 @@ +/** + * @generated SignedSource<<6aea0078adcf4d7180d89dbf964eaceb>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type VendorContactsTabFragment$data = { + readonly contacts: { + readonly __id: string; + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"VendorContactsTabFragment_contact">; + }; + }>; + }; + readonly id: string; + readonly " $fragmentType": "VendorContactsTabFragment"; +}; +export type VendorContactsTabFragment$key = { + readonly " $data"?: VendorContactsTabFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"VendorContactsTabFragment">; +}; + +import VendorContactsListQuery_graphql from './VendorContactsListQuery.graphql'; + +const node: ReaderFragment = (function(){ +var v0 = [ + "contacts" +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "argumentDefinitions": [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "before" + }, + { + "defaultValue": 50, + "kind": "LocalArgument", + "name": "first" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "last" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "order" + } + ], + "kind": "Fragment", + "metadata": { + "connection": [ + { + "count": null, + "cursor": null, + "direction": "bidirectional", + "path": (v0/*: any*/) + } + ], + "refetch": { + "connection": { + "forward": { + "count": "first", + "cursor": "after" + }, + "backward": { + "count": "last", + "cursor": "before" + }, + "path": (v0/*: any*/) + }, + "fragmentPathInResult": [ + "node" + ], + "operation": VendorContactsListQuery_graphql, + "identifierInfo": { + "identifierField": "id", + "identifierQueryVariableName": "id" + } + } + }, + "name": "VendorContactsTabFragment", + "selections": [ + { + "alias": "contacts", + "args": [ + { + "kind": "Variable", + "name": "orderBy", + "variableName": "order" + } + ], + "concreteType": "VendorContactConnection", + "kind": "LinkedField", + "name": "__VendorContactsTabFragment_contacts_connection", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContactEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorContact", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorContactsTabFragment_contact" + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "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 + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasPreviousPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "startCursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + }, + (v1/*: any*/) + ], + "type": "Vendor", + "abstractKey": null +}; +})(); + +(node as any).hash = "aa8ba87386ba04dd624566661fe0a524"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabFragment_contact.graphql.ts b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabFragment_contact.graphql.ts new file mode 100644 index 000000000..d488e0dc6 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorContactsTabFragment_contact.graphql.ts @@ -0,0 +1,90 @@ +/** + * @generated SignedSource<<28eef433ba6749a95468492e8ac9d1a6>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type VendorContactsTabFragment_contact$data = { + readonly createdAt: any; + readonly email: string | null | undefined; + readonly fullName: string | null | undefined; + readonly id: string; + readonly phone: string | null | undefined; + readonly role: string | null | undefined; + readonly updatedAt: any; + readonly " $fragmentType": "VendorContactsTabFragment_contact"; +}; +export type VendorContactsTabFragment_contact$key = { + readonly " $data"?: VendorContactsTabFragment_contact$data; + readonly " $fragmentSpreads": FragmentRefs<"VendorContactsTabFragment_contact">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "VendorContactsTabFragment_contact", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "phone", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "role", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "type": "VendorContact", + "abstractKey": null +}; + +(node as any).hash = "9c3e5b8b262263249160f5fd3708162a"; + +export default node; diff --git a/apps/console/src/routes/vendorRoutes.ts b/apps/console/src/routes/vendorRoutes.ts index 25e5aab38..88dea4ef2 100644 --- a/apps/console/src/routes/vendorRoutes.ts +++ b/apps/console/src/routes/vendorRoutes.ts @@ -61,6 +61,14 @@ export const vendorRoutes = [ ) ), }, + { + path: "contacts", + fallback: LinkCardSkeleton, + Component: lazy( + () => + import("../pages/organizations/vendors/tabs/VendorContactsTab") + ), + }, ], }, ] satisfies AppRoute[]; diff --git a/packages/helpers/src/index.ts b/packages/helpers/src/index.ts index 08e6e1dc8..d27df3991 100644 --- a/packages/helpers/src/index.ts +++ b/packages/helpers/src/index.ts @@ -1,4 +1,4 @@ -export { objectKeys, objectEntries } from "./object"; +export { objectKeys, objectEntries, cleanFormData } from "./object"; export { sprintf, faviconUrl, slugify } from "./string"; export { getTreatment, diff --git a/packages/helpers/src/object.ts b/packages/helpers/src/object.ts index 4a991e50b..3aa8b53c4 100644 --- a/packages/helpers/src/object.ts +++ b/packages/helpers/src/object.ts @@ -8,3 +8,15 @@ export function objectKeys>(object: T) { export function objectEntries>(object: T) { return Object.entries(object) as [keyof T, T[keyof T]][]; } + +/** + * Trims string values and converts empty strings to null in form data objects + */ +export function cleanFormData>(data: T): T { + return Object.fromEntries( + Object.entries(data).map(([k, v]) => { + const trimmed = typeof v === 'string' ? v.trim() : v; + return [k, trimmed === "" ? null : trimmed]; + }) + ) as T; +} diff --git a/pkg/coredata/entity_type_reg.go b/pkg/coredata/entity_type_reg.go index 6b747501c..6566d2711 100644 --- a/pkg/coredata/entity_type_reg.go +++ b/pkg/coredata/entity_type_reg.go @@ -41,4 +41,5 @@ const ( TrustCenterAccessEntityType VendorBusinessAssociateAgreementEntityType FileEntityType + VendorContactEntityType ) diff --git a/pkg/coredata/migrations/20250813T160929Z.sql b/pkg/coredata/migrations/20250813T160929Z.sql new file mode 100644 index 000000000..999870c42 --- /dev/null +++ b/pkg/coredata/migrations/20250813T160929Z.sql @@ -0,0 +1,17 @@ +CREATE TABLE vendor_contacts ( + id TEXT PRIMARY KEY, + tenant_id TEXT NOT NULL, + vendor_id TEXT NOT NULL, + full_name TEXT, + email CITEXT, + phone TEXT, + role TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL, + + CONSTRAINT vendor_contacts_vendor_id_fkey + FOREIGN KEY (vendor_id) + REFERENCES vendors(id) + ON UPDATE CASCADE + ON DELETE CASCADE +); diff --git a/pkg/coredata/vendor_contact.go b/pkg/coredata/vendor_contact.go new file mode 100644 index 000000000..7914d3909 --- /dev/null +++ b/pkg/coredata/vendor_contact.go @@ -0,0 +1,277 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package coredata + +import ( + "context" + "errors" + "fmt" + "maps" + "time" + + "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/page" + "github.com/jackc/pgx/v5" + "go.gearno.de/kit/pg" +) + +type ( + VendorContact struct { + ID gid.GID `db:"id"` + VendorID gid.GID `db:"vendor_id"` + FullName *string `db:"full_name"` + Email *string `db:"email"` + Phone *string `db:"phone"` + Role *string `db:"role"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` + } + + VendorContacts []*VendorContact + + ErrVendorContactNotFound struct { + Identifier string + } +) + +func (e ErrVendorContactNotFound) Error() string { + return fmt.Sprintf("vendor contact not found: %s", e.Identifier) +} + +func (vc VendorContact) CursorKey(orderBy VendorContactOrderField) page.CursorKey { + switch orderBy { + case VendorContactOrderFieldCreatedAt: + return page.CursorKey{ID: vc.ID, Value: vc.CreatedAt} + case VendorContactOrderFieldFullName: + return page.CursorKey{ID: vc.ID, Value: vc.FullName} + case VendorContactOrderFieldEmail: + return page.CursorKey{ID: vc.ID, Value: vc.Email} + } + + panic(fmt.Sprintf("unsupported order by: %s", orderBy)) +} + +func (vc *VendorContact) LoadByID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorContactID gid.GID, +) error { + q := ` +SELECT + id, + vendor_id, + full_name, + email, + phone, + role, + created_at, + updated_at +FROM + vendor_contacts +WHERE + %s + AND id = @vendor_contact_id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"vendor_contact_id": vendorContactID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query vendor contact: %w", err) + } + defer rows.Close() + + vendorContact, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[VendorContact]) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return &ErrVendorContactNotFound{Identifier: vendorContactID.String()} + } + + return fmt.Errorf("cannot collect vendor contact: %w", err) + } + + *vc = vendorContact + + return nil +} + +func (vc *VendorContacts) LoadByVendorID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorID gid.GID, + cursor *page.Cursor[VendorContactOrderField], +) error { + q := ` +SELECT + id, + vendor_id, + full_name, + email, + phone, + role, + created_at, + updated_at +FROM + vendor_contacts +WHERE + %s + AND vendor_id = @vendor_id + AND %s +` + q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "vendor_id": vendorID, + } + maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, cursor.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query vendor contacts: %w", err) + } + defer rows.Close() + + vendorContacts, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[VendorContact]) + if err != nil { + return fmt.Errorf("cannot collect vendor contacts: %w", err) + } + + *vc = vendorContacts + + return nil +} + +func (vc VendorContact) Insert( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +INSERT INTO + vendor_contacts ( + tenant_id, + id, + vendor_id, + full_name, + email, + phone, + role, + created_at, + updated_at + ) +VALUES ( + @tenant_id, + @vendor_contact_id, + @vendor_id, + @full_name, + @email, + @phone, + @role, + @created_at, + @updated_at +) +` + + args := pgx.StrictNamedArgs{ + "tenant_id": scope.GetTenantID(), + "vendor_contact_id": vc.ID, + "vendor_id": vc.VendorID, + "full_name": vc.FullName, + "email": vc.Email, + "phone": vc.Phone, + "role": vc.Role, + "created_at": vc.CreatedAt, + "updated_at": vc.UpdatedAt, + } + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot insert vendor contact: %w", err) + } + + return nil +} + +func (vc VendorContact) Update( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +UPDATE + vendor_contacts +SET + full_name = @full_name, + email = @email, + phone = @phone, + role = @role, + updated_at = @updated_at +WHERE + %s + AND id = @vendor_contact_id +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "vendor_contact_id": vc.ID, + "full_name": vc.FullName, + "email": vc.Email, + "phone": vc.Phone, + "role": vc.Role, + "updated_at": vc.UpdatedAt, + } + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot update vendor contact: %w", err) + } + + return nil +} + +func (vc VendorContact) Delete( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +DELETE FROM + vendor_contacts +WHERE + %s + AND id = @vendor_contact_id +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"vendor_contact_id": vc.ID} + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot delete vendor contact: %w", err) + } + + return nil +} diff --git a/pkg/coredata/vendor_contact_order_field.go b/pkg/coredata/vendor_contact_order_field.go new file mode 100644 index 000000000..93a846b53 --- /dev/null +++ b/pkg/coredata/vendor_contact_order_field.go @@ -0,0 +1,42 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package coredata + +type ( + VendorContactOrderField string +) + +const ( + VendorContactOrderFieldCreatedAt VendorContactOrderField = "CREATED_AT" + VendorContactOrderFieldFullName VendorContactOrderField = "FULL_NAME" + VendorContactOrderFieldEmail VendorContactOrderField = "EMAIL" +) + +func (p VendorContactOrderField) Column() string { + return string(p) +} + +func (p VendorContactOrderField) String() string { + return string(p) +} + +func (p VendorContactOrderField) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *VendorContactOrderField) UnmarshalText(text []byte) error { + *p = VendorContactOrderField(text) + return nil +} diff --git a/pkg/probo/service.go b/pkg/probo/service.go index 193de3116..49998f70a 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -72,6 +72,7 @@ type ( Risks *RiskService VendorComplianceReports *VendorComplianceReportService VendorBusinessAssociateAgreements *VendorBusinessAssociateAgreementService + VendorContacts *VendorContactService Connectors *ConnectorService Assets *AssetService Data *DatumService @@ -159,6 +160,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.Risks = &RiskService{svc: tenantService} tenantService.VendorComplianceReports = &VendorComplianceReportService{svc: tenantService} tenantService.VendorBusinessAssociateAgreements = &VendorBusinessAssociateAgreementService{svc: tenantService} + tenantService.VendorContacts = &VendorContactService{svc: tenantService} tenantService.Connectors = &ConnectorService{svc: tenantService} tenantService.Assets = &AssetService{svc: tenantService} tenantService.Data = &DatumService{svc: tenantService} diff --git a/pkg/probo/vendor_contact_service.go b/pkg/probo/vendor_contact_service.go new file mode 100644 index 000000000..a654d6003 --- /dev/null +++ b/pkg/probo/vendor_contact_service.go @@ -0,0 +1,183 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package probo + +import ( + "context" + "fmt" + "time" + + "github.com/getprobo/probo/pkg/coredata" + "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/page" + "go.gearno.de/kit/pg" +) + +type ( + VendorContactService struct { + svc *TenantService + } + + CreateVendorContactRequest struct { + VendorID gid.GID + FullName *string + Email *string + Phone *string + Role *string + } + + UpdateVendorContactRequest struct { + ID gid.GID + FullName **string + Email **string + Phone **string + Role **string + } +) + +func (s VendorContactService) Get( + ctx context.Context, + vendorContactID gid.GID, +) (*coredata.VendorContact, error) { + vendorContact := &coredata.VendorContact{} + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + return vendorContact.LoadByID(ctx, conn, s.svc.scope, vendorContactID) + }, + ) + + if err != nil { + return nil, err + } + + return vendorContact, nil +} + +func (s VendorContactService) List( + ctx context.Context, + vendorID gid.GID, + cursor *page.Cursor[coredata.VendorContactOrderField], +) (*page.Page[*coredata.VendorContact, coredata.VendorContactOrderField], error) { + var vendorContacts coredata.VendorContacts + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + return vendorContacts.LoadByVendorID(ctx, conn, s.svc.scope, vendorID, cursor) + }, + ) + + if err != nil { + return nil, err + } + + return page.NewPage(vendorContacts, cursor), nil +} + +func (s VendorContactService) Create( + ctx context.Context, + req CreateVendorContactRequest, +) (*coredata.VendorContact, error) { + now := time.Now() + vendorContact := &coredata.VendorContact{ + ID: gid.New(s.svc.scope.GetTenantID(), coredata.VendorContactEntityType), + VendorID: req.VendorID, + FullName: req.FullName, + Email: req.Email, + Phone: req.Phone, + Role: req.Role, + CreatedAt: now, + UpdatedAt: now, + } + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + if err := vendorContact.Insert(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot insert vendor contact: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return vendorContact, nil +} + +func (s VendorContactService) Update( + ctx context.Context, + req UpdateVendorContactRequest, +) (*coredata.VendorContact, error) { + vendorContact := &coredata.VendorContact{} + + err := s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + err := vendorContact.LoadByID(ctx, conn, s.svc.scope, req.ID) + if err != nil { + return fmt.Errorf("cannot load vendor contact: %w", err) + } + + if req.FullName != nil { + vendorContact.FullName = *req.FullName + } + if req.Email != nil { + vendorContact.Email = *req.Email + } + if req.Phone != nil { + vendorContact.Phone = *req.Phone + } + if req.Role != nil { + vendorContact.Role = *req.Role + } + vendorContact.UpdatedAt = time.Now() + + return vendorContact.Update(ctx, conn, s.svc.scope) + }, + ) + + if err != nil { + return nil, err + } + + return vendorContact, nil +} + +func (s VendorContactService) Delete( + ctx context.Context, + vendorContactID gid.GID, +) error { + vendorContact := coredata.VendorContact{ID: vendorContactID} + return s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + if err := vendorContact.LoadByID(ctx, conn, s.svc.scope, vendorContactID); err != nil { + return fmt.Errorf("cannot load vendor contact: %w", err) + } + + if err := vendorContact.Delete(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot delete vendor contact: %w", err) + } + + return nil + }, + ) +} diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index 5d4cfc29e..ac0945e5e 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -292,6 +292,24 @@ enum VendorComplianceReportOrderField ) } +enum VendorContactOrderField + @goModel( + model: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderField" + ) { + CREATED_AT + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderFieldCreatedAt" + ) + FULL_NAME + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderFieldFullName" + ) + EMAIL + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderFieldEmail" + ) +} + enum OrganizationOrderField @goModel( model: "github.com/getprobo/probo/pkg/coredata.OrganizationOrderField" @@ -679,6 +697,14 @@ input VendorComplianceReportOrder field: VendorComplianceReportOrderField! } +input VendorContactOrder + @goModel( + model: "github.com/getprobo/probo/pkg/server/api/console/v1/types.VendorContactOrderBy" + ) { + direction: OrderDirection! + field: VendorContactOrderField! +} + input OrganizationOrder { direction: OrderDirection! field: OrganizationOrderField! @@ -917,6 +943,14 @@ type Vendor implements Node { businessAssociateAgreement: VendorBusinessAssociateAgreement @goField(forceResolver: true) + contacts( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: VendorContactOrder + ): VendorContactConnection! @goField(forceResolver: true) + riskAssessments( first: Int after: CursorKey @@ -970,6 +1004,17 @@ type VendorBusinessAssociateAgreement implements Node { updatedAt: Datetime! } +type VendorContact implements Node { + id: ID! + vendor: Vendor! @goField(forceResolver: true) + fullName: String + email: String + phone: String + role: String + createdAt: Datetime! + updatedAt: Datetime! +} + type Framework implements Node { id: ID! name: String! @@ -1418,6 +1463,16 @@ type VendorComplianceReportEdge { node: VendorComplianceReport! } +type VendorContactConnection { + edges: [VendorContactEdge!]! + pageInfo: PageInfo! +} + +type VendorContactEdge { + cursor: CursorKey! + node: VendorContact! +} + type ConnectorConnection { edges: [ConnectorEdge!]! pageInfo: PageInfo! @@ -1529,6 +1584,11 @@ type Mutation { updateVendor(input: UpdateVendorInput!): UpdateVendorPayload! deleteVendor(input: DeleteVendorInput!): DeleteVendorPayload! + # Vendor Contact mutations + createVendorContact(input: CreateVendorContactInput!): CreateVendorContactPayload! + updateVendorContact(input: UpdateVendorContactInput!): UpdateVendorContactPayload! + deleteVendorContact(input: DeleteVendorContactInput!): DeleteVendorContactPayload! + # Framework mutations createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload! updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload! @@ -1763,6 +1823,26 @@ input DeleteVendorInput { vendorId: ID! } +input CreateVendorContactInput { + vendorId: ID! + fullName: String + email: String + phone: String + role: String +} + +input UpdateVendorContactInput { + id: ID! + fullName: String + email: String + phone: String + role: String +} + +input DeleteVendorContactInput { + vendorContactId: ID! +} + input CreatePeopleInput { organizationId: ID! fullName: String! @@ -2135,6 +2215,18 @@ type DeleteVendorPayload { deletedVendorId: ID! } +type CreateVendorContactPayload { + vendorContactEdge: VendorContactEdge! +} + +type UpdateVendorContactPayload { + vendorContact: VendorContact! +} + +type DeleteVendorContactPayload { + deletedVendorContactId: ID! +} + type CreatePeoplePayload { peopleEdge: PeopleEdge! } diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 2358fedd1..84707eac4 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -77,6 +77,7 @@ type ResolverRoot interface { VendorBusinessAssociateAgreement() VendorBusinessAssociateAgreementResolver VendorComplianceReport() VendorComplianceReportResolver VendorConnection() VendorConnectionResolver + VendorContact() VendorContactResolver VendorRiskAssessment() VendorRiskAssessmentResolver Viewer() ViewerResolver } @@ -280,6 +281,10 @@ type ComplexityRoot struct { TrustCenterAccessEdge func(childComplexity int) int } + CreateVendorContactPayload struct { + VendorContactEdge func(childComplexity int) int + } + CreateVendorPayload struct { VendorEdge func(childComplexity int) int } @@ -398,6 +403,10 @@ type ComplexityRoot struct { DeletedVendorComplianceReportID func(childComplexity int) int } + DeleteVendorContactPayload struct { + DeletedVendorContactID func(childComplexity int) int + } + DeleteVendorPayload struct { DeletedVendorID func(childComplexity int) int } @@ -602,6 +611,7 @@ type ComplexityRoot struct { CreateTask func(childComplexity int, input types.CreateTaskInput) int CreateTrustCenterAccess func(childComplexity int, input types.CreateTrustCenterAccessInput) int CreateVendor func(childComplexity int, input types.CreateVendorInput) int + CreateVendorContact func(childComplexity int, input types.CreateVendorContactInput) int CreateVendorRiskAssessment func(childComplexity int, input types.CreateVendorRiskAssessmentInput) int DeleteAsset func(childComplexity int, input types.DeleteAssetInput) int DeleteAudit func(childComplexity int, input types.DeleteAuditInput) int @@ -625,6 +635,7 @@ type ComplexityRoot struct { DeleteVendor func(childComplexity int, input types.DeleteVendorInput) int DeleteVendorBusinessAssociateAgreement func(childComplexity int, input types.DeleteVendorBusinessAssociateAgreementInput) int DeleteVendorComplianceReport func(childComplexity int, input types.DeleteVendorComplianceReportInput) int + DeleteVendorContact func(childComplexity int, input types.DeleteVendorContactInput) int ExportDocumentVersionPDF func(childComplexity int, input types.ExportDocumentVersionPDFInput) int FulfillEvidence func(childComplexity int, input types.FulfillEvidenceInput) int GenerateDocumentChangelog func(childComplexity int, input types.GenerateDocumentChangelogInput) int @@ -653,6 +664,7 @@ type ComplexityRoot struct { UpdateTrustCenter func(childComplexity int, input types.UpdateTrustCenterInput) int UpdateVendor func(childComplexity int, input types.UpdateVendorInput) int UpdateVendorBusinessAssociateAgreement func(childComplexity int, input types.UpdateVendorBusinessAssociateAgreementInput) int + UpdateVendorContact func(childComplexity int, input types.UpdateVendorContactInput) int UploadAuditReport func(childComplexity int, input types.UploadAuditReportInput) int UploadMeasureEvidence func(childComplexity int, input types.UploadMeasureEvidenceInput) int UploadTaskEvidence func(childComplexity int, input types.UploadTaskEvidenceInput) int @@ -923,6 +935,10 @@ type ComplexityRoot struct { VendorBusinessAssociateAgreement func(childComplexity int) int } + UpdateVendorContactPayload struct { + VendorContact func(childComplexity int) int + } + UpdateVendorPayload struct { Vendor func(childComplexity int) int } @@ -973,6 +989,7 @@ type ComplexityRoot struct { Category func(childComplexity int) int Certifications func(childComplexity int) int ComplianceReports func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) int + Contacts func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) int CreatedAt func(childComplexity int) int DataProcessingAgreementURL func(childComplexity int) int Description func(childComplexity int) int @@ -1035,6 +1052,27 @@ type ComplexityRoot struct { TotalCount func(childComplexity int) int } + VendorContact struct { + CreatedAt func(childComplexity int) int + Email func(childComplexity int) int + FullName func(childComplexity int) int + ID func(childComplexity int) int + Phone func(childComplexity int) int + Role func(childComplexity int) int + UpdatedAt func(childComplexity int) int + Vendor func(childComplexity int) int + } + + VendorContactConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + } + + VendorContactEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + VendorEdge struct { Cursor func(childComplexity int) int Node func(childComplexity int) int @@ -1171,6 +1209,9 @@ type MutationResolver interface { CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.UpdateVendorPayload, error) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (*types.DeleteVendorPayload, error) + CreateVendorContact(ctx context.Context, input types.CreateVendorContactInput) (*types.CreateVendorContactPayload, error) + UpdateVendorContact(ctx context.Context, input types.UpdateVendorContactInput) (*types.UpdateVendorContactPayload, error) + DeleteVendorContact(ctx context.Context, input types.DeleteVendorContactInput) (*types.DeleteVendorContactPayload, error) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) @@ -1295,6 +1336,7 @@ type VendorResolver interface { Organization(ctx context.Context, obj *types.Vendor) (*types.Organization, error) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) BusinessAssociateAgreement(ctx context.Context, obj *types.Vendor) (*types.VendorBusinessAssociateAgreement, error) + Contacts(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) (*types.VendorContactConnection, error) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) BusinessOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) SecurityOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) @@ -1312,6 +1354,9 @@ type VendorComplianceReportResolver interface { type VendorConnectionResolver interface { TotalCount(ctx context.Context, obj *types.VendorConnection) (int, error) } +type VendorContactResolver interface { + Vendor(ctx context.Context, obj *types.VendorContact) (*types.Vendor, error) +} type VendorRiskAssessmentResolver interface { Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) @@ -1964,6 +2009,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.CreateTrustCenterAccessPayload.TrustCenterAccessEdge(childComplexity), true + case "CreateVendorContactPayload.vendorContactEdge": + if e.complexity.CreateVendorContactPayload.VendorContactEdge == nil { + break + } + + return e.complexity.CreateVendorContactPayload.VendorContactEdge(childComplexity), true + case "CreateVendorPayload.vendorEdge": if e.complexity.CreateVendorPayload.VendorEdge == nil { break @@ -2249,6 +2301,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.DeleteVendorComplianceReportPayload.DeletedVendorComplianceReportID(childComplexity), true + case "DeleteVendorContactPayload.deletedVendorContactId": + if e.complexity.DeleteVendorContactPayload.DeletedVendorContactID == nil { + break + } + + return e.complexity.DeleteVendorContactPayload.DeletedVendorContactID(childComplexity), true + case "DeleteVendorPayload.deletedVendorId": if e.complexity.DeleteVendorPayload.DeletedVendorID == nil { break @@ -3284,6 +3343,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.CreateVendor(childComplexity, args["input"].(types.CreateVendorInput)), true + case "Mutation.createVendorContact": + if e.complexity.Mutation.CreateVendorContact == nil { + break + } + + args, err := ec.field_Mutation_createVendorContact_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.CreateVendorContact(childComplexity, args["input"].(types.CreateVendorContactInput)), true + case "Mutation.createVendorRiskAssessment": if e.complexity.Mutation.CreateVendorRiskAssessment == nil { break @@ -3560,6 +3631,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.DeleteVendorComplianceReport(childComplexity, args["input"].(types.DeleteVendorComplianceReportInput)), true + case "Mutation.deleteVendorContact": + if e.complexity.Mutation.DeleteVendorContact == nil { + break + } + + args, err := ec.field_Mutation_deleteVendorContact_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.DeleteVendorContact(childComplexity, args["input"].(types.DeleteVendorContactInput)), true + case "Mutation.exportDocumentVersionPDF": if e.complexity.Mutation.ExportDocumentVersionPDF == nil { break @@ -3896,6 +3979,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.UpdateVendorBusinessAssociateAgreement(childComplexity, args["input"].(types.UpdateVendorBusinessAssociateAgreementInput)), true + case "Mutation.updateVendorContact": + if e.complexity.Mutation.UpdateVendorContact == nil { + break + } + + args, err := ec.field_Mutation_updateVendorContact_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateVendorContact(childComplexity, args["input"].(types.UpdateVendorContactInput)), true + case "Mutation.uploadAuditReport": if e.complexity.Mutation.UploadAuditReport == nil { break @@ -5015,6 +5110,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.UpdateVendorBusinessAssociateAgreementPayload.VendorBusinessAssociateAgreement(childComplexity), true + case "UpdateVendorContactPayload.vendorContact": + if e.complexity.UpdateVendorContactPayload.VendorContact == nil { + break + } + + return e.complexity.UpdateVendorContactPayload.VendorContact(childComplexity), true + case "UpdateVendorPayload.vendor": if e.complexity.UpdateVendorPayload.Vendor == nil { break @@ -5179,6 +5281,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Vendor.ComplianceReports(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.VendorComplianceReportOrderBy)), true + case "Vendor.contacts": + if e.complexity.Vendor.Contacts == nil { + break + } + + args, err := ec.field_Vendor_contacts_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Vendor.Contacts(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.VendorContactOrderBy)), true + case "Vendor.createdAt": if e.complexity.Vendor.CreatedAt == nil { break @@ -5499,6 +5613,90 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.VendorConnection.TotalCount(childComplexity), true + case "VendorContact.createdAt": + if e.complexity.VendorContact.CreatedAt == nil { + break + } + + return e.complexity.VendorContact.CreatedAt(childComplexity), true + + case "VendorContact.email": + if e.complexity.VendorContact.Email == nil { + break + } + + return e.complexity.VendorContact.Email(childComplexity), true + + case "VendorContact.fullName": + if e.complexity.VendorContact.FullName == nil { + break + } + + return e.complexity.VendorContact.FullName(childComplexity), true + + case "VendorContact.id": + if e.complexity.VendorContact.ID == nil { + break + } + + return e.complexity.VendorContact.ID(childComplexity), true + + case "VendorContact.phone": + if e.complexity.VendorContact.Phone == nil { + break + } + + return e.complexity.VendorContact.Phone(childComplexity), true + + case "VendorContact.role": + if e.complexity.VendorContact.Role == nil { + break + } + + return e.complexity.VendorContact.Role(childComplexity), true + + case "VendorContact.updatedAt": + if e.complexity.VendorContact.UpdatedAt == nil { + break + } + + return e.complexity.VendorContact.UpdatedAt(childComplexity), true + + case "VendorContact.vendor": + if e.complexity.VendorContact.Vendor == nil { + break + } + + return e.complexity.VendorContact.Vendor(childComplexity), true + + case "VendorContactConnection.edges": + if e.complexity.VendorContactConnection.Edges == nil { + break + } + + return e.complexity.VendorContactConnection.Edges(childComplexity), true + + case "VendorContactConnection.pageInfo": + if e.complexity.VendorContactConnection.PageInfo == nil { + break + } + + return e.complexity.VendorContactConnection.PageInfo(childComplexity), true + + case "VendorContactEdge.cursor": + if e.complexity.VendorContactEdge.Cursor == nil { + break + } + + return e.complexity.VendorContactEdge.Cursor(childComplexity), true + + case "VendorContactEdge.node": + if e.complexity.VendorContactEdge.Node == nil { + break + } + + return e.complexity.VendorContactEdge.Node(childComplexity), true + case "VendorEdge.cursor": if e.complexity.VendorEdge.Cursor == nil { break @@ -5674,6 +5872,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputCreateRiskMeasureMappingInput, ec.unmarshalInputCreateTaskInput, ec.unmarshalInputCreateTrustCenterAccessInput, + ec.unmarshalInputCreateVendorContactInput, ec.unmarshalInputCreateVendorInput, ec.unmarshalInputCreateVendorRiskAssessmentInput, ec.unmarshalInputDatumOrder, @@ -5698,6 +5897,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputDeleteTrustCenterAccessInput, ec.unmarshalInputDeleteVendorBusinessAssociateAgreementInput, ec.unmarshalInputDeleteVendorComplianceReportInput, + ec.unmarshalInputDeleteVendorContactInput, ec.unmarshalInputDeleteVendorInput, ec.unmarshalInputDocumentFilter, ec.unmarshalInputDocumentOrder, @@ -5744,6 +5944,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputUpdateTaskInput, ec.unmarshalInputUpdateTrustCenterInput, ec.unmarshalInputUpdateVendorBusinessAssociateAgreementInput, + ec.unmarshalInputUpdateVendorContactInput, ec.unmarshalInputUpdateVendorInput, ec.unmarshalInputUploadAuditReportInput, ec.unmarshalInputUploadMeasureEvidenceInput, @@ -5752,6 +5953,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputUploadVendorComplianceReportInput, ec.unmarshalInputUserOrder, ec.unmarshalInputVendorComplianceReportOrder, + ec.unmarshalInputVendorContactOrder, ec.unmarshalInputVendorOrder, ec.unmarshalInputVendorRiskAssessmentOrder, ) @@ -6145,6 +6347,24 @@ enum VendorComplianceReportOrderField ) } +enum VendorContactOrderField + @goModel( + model: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderField" + ) { + CREATED_AT + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderFieldCreatedAt" + ) + FULL_NAME + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderFieldFullName" + ) + EMAIL + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorContactOrderFieldEmail" + ) +} + enum OrganizationOrderField @goModel( model: "github.com/getprobo/probo/pkg/coredata.OrganizationOrderField" @@ -6532,6 +6752,14 @@ input VendorComplianceReportOrder field: VendorComplianceReportOrderField! } +input VendorContactOrder + @goModel( + model: "github.com/getprobo/probo/pkg/server/api/console/v1/types.VendorContactOrderBy" + ) { + direction: OrderDirection! + field: VendorContactOrderField! +} + input OrganizationOrder { direction: OrderDirection! field: OrganizationOrderField! @@ -6770,6 +6998,14 @@ type Vendor implements Node { businessAssociateAgreement: VendorBusinessAssociateAgreement @goField(forceResolver: true) + contacts( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: VendorContactOrder + ): VendorContactConnection! @goField(forceResolver: true) + riskAssessments( first: Int after: CursorKey @@ -6823,6 +7059,17 @@ type VendorBusinessAssociateAgreement implements Node { updatedAt: Datetime! } +type VendorContact implements Node { + id: ID! + vendor: Vendor! @goField(forceResolver: true) + fullName: String + email: String + phone: String + role: String + createdAt: Datetime! + updatedAt: Datetime! +} + type Framework implements Node { id: ID! name: String! @@ -7271,6 +7518,16 @@ type VendorComplianceReportEdge { node: VendorComplianceReport! } +type VendorContactConnection { + edges: [VendorContactEdge!]! + pageInfo: PageInfo! +} + +type VendorContactEdge { + cursor: CursorKey! + node: VendorContact! +} + type ConnectorConnection { edges: [ConnectorEdge!]! pageInfo: PageInfo! @@ -7382,6 +7639,11 @@ type Mutation { updateVendor(input: UpdateVendorInput!): UpdateVendorPayload! deleteVendor(input: DeleteVendorInput!): DeleteVendorPayload! + # Vendor Contact mutations + createVendorContact(input: CreateVendorContactInput!): CreateVendorContactPayload! + updateVendorContact(input: UpdateVendorContactInput!): UpdateVendorContactPayload! + deleteVendorContact(input: DeleteVendorContactInput!): DeleteVendorContactPayload! + # Framework mutations createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload! updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload! @@ -7616,6 +7878,26 @@ input DeleteVendorInput { vendorId: ID! } +input CreateVendorContactInput { + vendorId: ID! + fullName: String + email: String + phone: String + role: String +} + +input UpdateVendorContactInput { + id: ID! + fullName: String + email: String + phone: String + role: String +} + +input DeleteVendorContactInput { + vendorContactId: ID! +} + input CreatePeopleInput { organizationId: ID! fullName: String! @@ -7988,6 +8270,18 @@ type DeleteVendorPayload { deletedVendorId: ID! } +type CreateVendorContactPayload { + vendorContactEdge: VendorContactEdge! +} + +type UpdateVendorContactPayload { + vendorContact: VendorContact! +} + +type DeleteVendorContactPayload { + deletedVendorContactId: ID! +} + type CreatePeoplePayload { peopleEdge: PeopleEdge! } @@ -10374,6 +10668,29 @@ func (ec *executionContext) field_Mutation_createTrustCenterAccess_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_createVendorContact_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_createVendorContact_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_createVendorContact_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.CreateVendorContactInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNCreateVendorContactInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorContactInput(ctx, tmp) + } + + var zeroVal types.CreateVendorContactInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_createVendorRiskAssessment_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -10903,6 +11220,29 @@ func (ec *executionContext) field_Mutation_deleteVendorComplianceReport_argsInpu return zeroVal, nil } +func (ec *executionContext) field_Mutation_deleteVendorContact_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_deleteVendorContact_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_deleteVendorContact_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.DeleteVendorContactInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNDeleteVendorContactInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorContactInput(ctx, tmp) + } + + var zeroVal types.DeleteVendorContactInput + 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{} @@ -11547,6 +11887,29 @@ func (ec *executionContext) field_Mutation_updateVendorBusinessAssociateAgreemen return zeroVal, nil } +func (ec *executionContext) field_Mutation_updateVendorContact_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_updateVendorContact_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_updateVendorContact_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.UpdateVendorContactInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNUpdateVendorContactInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorContactInput(ctx, tmp) + } + + var zeroVal types.UpdateVendorContactInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_updateVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -13798,6 +14161,101 @@ func (ec *executionContext) field_Vendor_complianceReports_argsOrderBy( return zeroVal, nil } +func (ec *executionContext) field_Vendor_contacts_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Vendor_contacts_argsFirst(ctx, rawArgs) + if err != nil { + return nil, err + } + args["first"] = arg0 + arg1, err := ec.field_Vendor_contacts_argsAfter(ctx, rawArgs) + if err != nil { + return nil, err + } + args["after"] = arg1 + arg2, err := ec.field_Vendor_contacts_argsLast(ctx, rawArgs) + if err != nil { + return nil, err + } + args["last"] = arg2 + arg3, err := ec.field_Vendor_contacts_argsBefore(ctx, rawArgs) + if err != nil { + return nil, err + } + args["before"] = arg3 + arg4, err := ec.field_Vendor_contacts_argsOrderBy(ctx, rawArgs) + if err != nil { + return nil, err + } + args["orderBy"] = arg4 + return args, nil +} +func (ec *executionContext) field_Vendor_contacts_argsFirst( + ctx context.Context, + rawArgs map[string]any, +) (*int, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + if tmp, ok := rawArgs["first"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_contacts_argsAfter( + ctx context.Context, + rawArgs map[string]any, +) (*page.CursorKey, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + if tmp, ok := rawArgs["after"]; ok { + return ec.unmarshalOCursorKey2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx, tmp) + } + + var zeroVal *page.CursorKey + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_contacts_argsLast( + ctx context.Context, + rawArgs map[string]any, +) (*int, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("last")) + if tmp, ok := rawArgs["last"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_contacts_argsBefore( + ctx context.Context, + rawArgs map[string]any, +) (*page.CursorKey, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("before")) + if tmp, ok := rawArgs["before"]; ok { + return ec.unmarshalOCursorKey2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx, tmp) + } + + var zeroVal *page.CursorKey + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_contacts_argsOrderBy( + ctx context.Context, + rawArgs map[string]any, +) (*types.VendorContactOrderBy, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("orderBy")) + if tmp, ok := rawArgs["orderBy"]; ok { + return ec.unmarshalOVendorContactOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactOrderBy(ctx, tmp) + } + + var zeroVal *types.VendorContactOrderBy + return zeroVal, nil +} + func (ec *executionContext) field_Vendor_riskAssessments_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -14159,6 +14617,8 @@ func (ec *executionContext) fieldContext_AssessVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": return ec.fieldContext_Vendor_riskAssessments(ctx, field) case "businessOwner": @@ -18512,6 +18972,56 @@ func (ec *executionContext) fieldContext_CreateTrustCenterAccessPayload_trustCen return fc, nil } +func (ec *executionContext) _CreateVendorContactPayload_vendorContactEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreateVendorContactPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CreateVendorContactPayload_vendorContactEdge(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.VendorContactEdge, 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.VendorContactEdge) + fc.Result = res + return ec.marshalNVendorContactEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactEdge(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CreateVendorContactPayload_vendorContactEdge(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CreateVendorContactPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_VendorContactEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_VendorContactEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorContactEdge", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _CreateVendorPayload_vendorEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreateVendorPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_CreateVendorPayload_vendorEdge(ctx, field) if err != nil { @@ -20423,6 +20933,50 @@ func (ec *executionContext) fieldContext_DeleteVendorComplianceReportPayload_del return fc, nil } +func (ec *executionContext) _DeleteVendorContactPayload_deletedVendorContactId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteVendorContactPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DeleteVendorContactPayload_deletedVendorContactId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeletedVendorContactID, 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_DeleteVendorContactPayload_deletedVendorContactId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DeleteVendorContactPayload", + 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 { @@ -26429,6 +26983,183 @@ func (ec *executionContext) fieldContext_Mutation_deleteVendor(ctx context.Conte return fc, nil } +func (ec *executionContext) _Mutation_createVendorContact(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createVendorContact(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().CreateVendorContact(rctx, fc.Args["input"].(types.CreateVendorContactInput)) + }) + 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.CreateVendorContactPayload) + fc.Result = res + return ec.marshalNCreateVendorContactPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorContactPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_createVendorContact(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 "vendorContactEdge": + return ec.fieldContext_CreateVendorContactPayload_vendorContactEdge(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CreateVendorContactPayload", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_createVendorContact_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_updateVendorContact(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_updateVendorContact(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().UpdateVendorContact(rctx, fc.Args["input"].(types.UpdateVendorContactInput)) + }) + 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.UpdateVendorContactPayload) + fc.Result = res + return ec.marshalNUpdateVendorContactPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorContactPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_updateVendorContact(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 "vendorContact": + return ec.fieldContext_UpdateVendorContactPayload_vendorContact(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UpdateVendorContactPayload", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_updateVendorContact_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_deleteVendorContact(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteVendorContact(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().DeleteVendorContact(rctx, fc.Args["input"].(types.DeleteVendorContactInput)) + }) + 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.DeleteVendorContactPayload) + fc.Result = res + return ec.marshalNDeleteVendorContactPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorContactPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_deleteVendorContact(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 "deletedVendorContactId": + return ec.fieldContext_DeleteVendorContactPayload_deletedVendorContactId(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DeleteVendorContactPayload", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_deleteVendorContact_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) { fc, err := ec.fieldContext_Mutation_createFramework(ctx, field) if err != nil { @@ -37674,6 +38405,68 @@ func (ec *executionContext) fieldContext_UpdateVendorBusinessAssociateAgreementP return fc, nil } +func (ec *executionContext) _UpdateVendorContactPayload_vendorContact(ctx context.Context, field graphql.CollectedField, obj *types.UpdateVendorContactPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_UpdateVendorContactPayload_vendorContact(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.VendorContact, 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.VendorContact) + fc.Result = res + return ec.marshalNVendorContact2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContact(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_UpdateVendorContactPayload_vendorContact(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "UpdateVendorContactPayload", + 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_VendorContact_id(ctx, field) + case "vendor": + return ec.fieldContext_VendorContact_vendor(ctx, field) + case "fullName": + return ec.fieldContext_VendorContact_fullName(ctx, field) + case "email": + return ec.fieldContext_VendorContact_email(ctx, field) + case "phone": + return ec.fieldContext_VendorContact_phone(ctx, field) + case "role": + return ec.fieldContext_VendorContact_role(ctx, field) + case "createdAt": + return ec.fieldContext_VendorContact_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_VendorContact_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorContact", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _UpdateVendorPayload_vendor(ctx context.Context, field graphql.CollectedField, obj *types.UpdateVendorPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UpdateVendorPayload_vendor(ctx, field) if err != nil { @@ -37727,6 +38520,8 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": return ec.fieldContext_Vendor_riskAssessments(ctx, field) case "businessOwner": @@ -38933,6 +39728,67 @@ func (ec *executionContext) fieldContext_Vendor_businessAssociateAgreement(_ con return fc, nil } +func (ec *executionContext) _Vendor_contacts(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Vendor_contacts(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Vendor().Contacts(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.VendorContactOrderBy)) + }) + 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.VendorContactConnection) + fc.Result = res + return ec.marshalNVendorContactConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactConnection(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Vendor_contacts(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Vendor", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "edges": + return ec.fieldContext_VendorContactConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_VendorContactConnection_pageInfo(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorContactConnection", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Vendor_contacts_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Vendor_riskAssessments(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Vendor_riskAssessments(ctx, field) if err != nil { @@ -39885,6 +40741,8 @@ func (ec *executionContext) fieldContext_VendorBusinessAssociateAgreement_vendor return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": return ec.fieldContext_Vendor_riskAssessments(ctx, field) case "businessOwner": @@ -40329,6 +41187,8 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": return ec.fieldContext_Vendor_riskAssessments(ctx, field) case "businessOwner": @@ -41039,6 +41899,612 @@ func (ec *executionContext) fieldContext_VendorConnection_pageInfo(_ context.Con return fc, nil } +func (ec *executionContext) _VendorContact_id(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, 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_VendorContact_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + 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) _VendorContact_vendor(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_vendor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.VendorContact().Vendor(rctx, obj) + }) + 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.Vendor) + fc.Result = res + return ec.marshalNVendor2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendor(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_vendor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + 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_Vendor_id(ctx, field) + case "name": + return ec.fieldContext_Vendor_name(ctx, field) + case "category": + return ec.fieldContext_Vendor_category(ctx, field) + case "description": + return ec.fieldContext_Vendor_description(ctx, field) + case "organization": + return ec.fieldContext_Vendor_organization(ctx, field) + case "complianceReports": + return ec.fieldContext_Vendor_complianceReports(ctx, field) + case "businessAssociateAgreement": + return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) + case "riskAssessments": + return ec.fieldContext_Vendor_riskAssessments(ctx, field) + case "businessOwner": + return ec.fieldContext_Vendor_businessOwner(ctx, field) + case "securityOwner": + return ec.fieldContext_Vendor_securityOwner(ctx, field) + case "statusPageUrl": + return ec.fieldContext_Vendor_statusPageUrl(ctx, field) + case "termsOfServiceUrl": + return ec.fieldContext_Vendor_termsOfServiceUrl(ctx, field) + case "privacyPolicyUrl": + return ec.fieldContext_Vendor_privacyPolicyUrl(ctx, field) + case "serviceLevelAgreementUrl": + return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) + case "dataProcessingAgreementUrl": + return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) + case "certifications": + return ec.fieldContext_Vendor_certifications(ctx, field) + case "securityPageUrl": + return ec.fieldContext_Vendor_securityPageUrl(ctx, field) + case "trustPageUrl": + return ec.fieldContext_Vendor_trustPageUrl(ctx, field) + case "headquarterAddress": + return ec.fieldContext_Vendor_headquarterAddress(ctx, field) + case "legalName": + return ec.fieldContext_Vendor_legalName(ctx, field) + case "websiteUrl": + return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) + case "createdAt": + return ec.fieldContext_Vendor_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_Vendor_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Vendor", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContact_fullName(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_fullName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.FullName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_fullName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContact_email(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_email(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Email, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_email(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContact_phone(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_phone(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Phone, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_phone(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContact_role(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_role(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Role, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_role(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContact_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_createdAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.CreatedAt, 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.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContact_updatedAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorContact) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContact_updatedAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.UpdatedAt, 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.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContact_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContact", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContactConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.VendorContactConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContactConnection_edges(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Edges, 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.VendorContactEdge) + fc.Result = res + return ec.marshalNVendorContactEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactEdgeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContactConnection_edges(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContactConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_VendorContactEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_VendorContactEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorContactEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContactConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *types.VendorContactConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContactConnection_pageInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, 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.PageInfo) + fc.Result = res + return ec.marshalNPageInfo2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContactConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContactConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + case "hasPreviousPage": + return ec.fieldContext_PageInfo_hasPreviousPage(ctx, field) + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContactEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *types.VendorContactEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContactEdge_cursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cursor, 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.(page.CursorKey) + fc.Result = res + return ec.marshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContactEdge_cursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContactEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type CursorKey does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorContactEdge_node(ctx context.Context, field graphql.CollectedField, obj *types.VendorContactEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorContactEdge_node(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.Node, 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.VendorContact) + fc.Result = res + return ec.marshalNVendorContact2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContact(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorContactEdge_node(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorContactEdge", + 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_VendorContact_id(ctx, field) + case "vendor": + return ec.fieldContext_VendorContact_vendor(ctx, field) + case "fullName": + return ec.fieldContext_VendorContact_fullName(ctx, field) + case "email": + return ec.fieldContext_VendorContact_email(ctx, field) + case "phone": + return ec.fieldContext_VendorContact_phone(ctx, field) + case "role": + return ec.fieldContext_VendorContact_role(ctx, field) + case "createdAt": + return ec.fieldContext_VendorContact_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_VendorContact_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorContact", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _VendorEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *types.VendorEdge) (ret graphql.Marshaler) { fc, err := ec.fieldContext_VendorEdge_cursor(ctx, field) if err != nil { @@ -41136,6 +42602,8 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": return ec.fieldContext_Vendor_riskAssessments(ctx, field) case "businessOwner": @@ -41278,6 +42746,8 @@ func (ec *executionContext) fieldContext_VendorRiskAssessment_vendor(_ context.C return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": return ec.fieldContext_Vendor_riskAssessments(ctx, field) case "businessOwner": @@ -45306,6 +46776,61 @@ func (ec *executionContext) unmarshalInputCreateTrustCenterAccessInput(ctx conte return it, nil } +func (ec *executionContext) unmarshalInputCreateVendorContactInput(ctx context.Context, obj any) (types.CreateVendorContactInput, error) { + var it types.CreateVendorContactInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"vendorId", "fullName", "email", "phone", "role"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "vendorId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vendorId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.VendorID = data + case "fullName": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fullName")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.FullName = data + case "email": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Email = data + case "phone": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Phone = data + case "role": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("role")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Role = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, obj any) (types.CreateVendorInput, error) { var it types.CreateVendorInput asMap := map[string]any{} @@ -46150,6 +47675,33 @@ func (ec *executionContext) unmarshalInputDeleteVendorComplianceReportInput(ctx return it, nil } +func (ec *executionContext) unmarshalInputDeleteVendorContactInput(ctx context.Context, obj any) (types.DeleteVendorContactInput, error) { + var it types.DeleteVendorContactInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"vendorContactId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "vendorContactId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vendorContactId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.VendorContactID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDeleteVendorInput(ctx context.Context, obj any) (types.DeleteVendorInput, error) { var it types.DeleteVendorInput asMap := map[string]any{} @@ -47987,6 +49539,61 @@ func (ec *executionContext) unmarshalInputUpdateVendorBusinessAssociateAgreement return it, nil } +func (ec *executionContext) unmarshalInputUpdateVendorContactInput(ctx context.Context, obj any) (types.UpdateVendorContactInput, error) { + var it types.UpdateVendorContactInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"id", "fullName", "email", "phone", "role"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "id": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.ID = data + case "fullName": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fullName")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.FullName = data + case "email": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Email = data + case "phone": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Phone = data + case "role": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("role")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Role = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, obj any) (types.UpdateVendorInput, error) { var it types.UpdateVendorInput asMap := map[string]any{} @@ -48427,6 +50034,40 @@ func (ec *executionContext) unmarshalInputVendorComplianceReportOrder(ctx contex return it, nil } +func (ec *executionContext) unmarshalInputVendorContactOrder(ctx context.Context, obj any) (types.VendorContactOrderBy, error) { + var it types.VendorContactOrderBy + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"direction", "field"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "direction": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) + data, err := ec.unmarshalNOrderDirection2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐOrderDirection(ctx, v) + if err != nil { + return it, err + } + it.Direction = data + case "field": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("field")) + data, err := ec.unmarshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField(ctx, v) + if err != nil { + return it, err + } + it.Field = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputVendorOrder(ctx context.Context, obj any) (types.VendorOrderBy, error) { var it types.VendorOrderBy asMap := map[string]any{} @@ -48510,6 +50151,13 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj return graphql.Null } return ec._VendorRiskAssessment(ctx, sel, obj) + case types.VendorContact: + return ec._VendorContact(ctx, sel, &obj) + case *types.VendorContact: + if obj == nil { + return graphql.Null + } + return ec._VendorContact(ctx, sel, obj) case types.VendorComplianceReport: return ec._VendorComplianceReport(ctx, sel, &obj) case *types.VendorComplianceReport: @@ -50751,6 +52399,45 @@ func (ec *executionContext) _CreateTrustCenterAccessPayload(ctx context.Context, return out } +var createVendorContactPayloadImplementors = []string{"CreateVendorContactPayload"} + +func (ec *executionContext) _CreateVendorContactPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateVendorContactPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, createVendorContactPayloadImplementors) + + 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("CreateVendorContactPayload") + case "vendorContactEdge": + out.Values[i] = ec._CreateVendorContactPayload_vendorContactEdge(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 createVendorPayloadImplementors = []string{"CreateVendorPayload"} func (ec *executionContext) _CreateVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateVendorPayload) graphql.Marshaler { @@ -51959,6 +53646,45 @@ func (ec *executionContext) _DeleteVendorComplianceReportPayload(ctx context.Con return out } +var deleteVendorContactPayloadImplementors = []string{"DeleteVendorContactPayload"} + +func (ec *executionContext) _DeleteVendorContactPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteVendorContactPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, deleteVendorContactPayloadImplementors) + + 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("DeleteVendorContactPayload") + case "deletedVendorContactId": + out.Values[i] = ec._DeleteVendorContactPayload_deletedVendorContactId(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 { @@ -54195,6 +55921,27 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "createVendorContact": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_createVendorContact(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updateVendorContact": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateVendorContact(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deleteVendorContact": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteVendorContact(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "createFramework": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_createFramework(ctx, field) @@ -57744,6 +59491,45 @@ func (ec *executionContext) _UpdateVendorBusinessAssociateAgreementPayload(ctx c return out } +var updateVendorContactPayloadImplementors = []string{"UpdateVendorContactPayload"} + +func (ec *executionContext) _UpdateVendorContactPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateVendorContactPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, updateVendorContactPayloadImplementors) + + 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("UpdateVendorContactPayload") + case "vendorContact": + out.Values[i] = ec._UpdateVendorContactPayload_vendorContact(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 updateVendorPayloadImplementors = []string{"UpdateVendorPayload"} func (ec *executionContext) _UpdateVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateVendorPayload) graphql.Marshaler { @@ -58290,6 +60076,42 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o continue } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "contacts": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Vendor_contacts(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + 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 "riskAssessments": field := field @@ -58901,6 +60723,187 @@ func (ec *executionContext) _VendorConnection(ctx context.Context, sel ast.Selec return out } +var vendorContactImplementors = []string{"VendorContact", "Node"} + +func (ec *executionContext) _VendorContact(ctx context.Context, sel ast.SelectionSet, obj *types.VendorContact) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorContactImplementors) + + 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("VendorContact") + case "id": + out.Values[i] = ec._VendorContact_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "vendor": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._VendorContact_vendor(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + 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 "fullName": + out.Values[i] = ec._VendorContact_fullName(ctx, field, obj) + case "email": + out.Values[i] = ec._VendorContact_email(ctx, field, obj) + case "phone": + out.Values[i] = ec._VendorContact_phone(ctx, field, obj) + case "role": + out.Values[i] = ec._VendorContact_role(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._VendorContact_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "updatedAt": + out.Values[i] = ec._VendorContact_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + 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 vendorContactConnectionImplementors = []string{"VendorContactConnection"} + +func (ec *executionContext) _VendorContactConnection(ctx context.Context, sel ast.SelectionSet, obj *types.VendorContactConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorContactConnectionImplementors) + + 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("VendorContactConnection") + case "edges": + out.Values[i] = ec._VendorContactConnection_edges(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "pageInfo": + out.Values[i] = ec._VendorContactConnection_pageInfo(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 vendorContactEdgeImplementors = []string{"VendorContactEdge"} + +func (ec *executionContext) _VendorContactEdge(ctx context.Context, sel ast.SelectionSet, obj *types.VendorContactEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorContactEdgeImplementors) + + 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("VendorContactEdge") + case "cursor": + out.Values[i] = ec._VendorContactEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "node": + out.Values[i] = ec._VendorContactEdge_node(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 vendorEdgeImplementors = []string{"VendorEdge"} func (ec *executionContext) _VendorEdge(ctx context.Context, sel ast.SelectionSet, obj *types.VendorEdge) graphql.Marshaler { @@ -60596,6 +62599,25 @@ func (ec *executionContext) marshalNCreateTrustCenterAccessPayload2ᚖgithubᚗc return ec._CreateTrustCenterAccessPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNCreateVendorContactInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorContactInput(ctx context.Context, v any) (types.CreateVendorContactInput, error) { + res, err := ec.unmarshalInputCreateVendorContactInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNCreateVendorContactPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorContactPayload(ctx context.Context, sel ast.SelectionSet, v types.CreateVendorContactPayload) graphql.Marshaler { + return ec._CreateVendorContactPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCreateVendorContactPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorContactPayload(ctx context.Context, sel ast.SelectionSet, v *types.CreateVendorContactPayload) 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._CreateVendorContactPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNCreateVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorInput(ctx context.Context, v any) (types.CreateVendorInput, error) { res, err := ec.unmarshalInputCreateVendorInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -61269,6 +63291,25 @@ func (ec *executionContext) marshalNDeleteVendorComplianceReportPayload2ᚖgithu return ec._DeleteVendorComplianceReportPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNDeleteVendorContactInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorContactInput(ctx context.Context, v any) (types.DeleteVendorContactInput, error) { + res, err := ec.unmarshalInputDeleteVendorContactInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNDeleteVendorContactPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorContactPayload(ctx context.Context, sel ast.SelectionSet, v types.DeleteVendorContactPayload) graphql.Marshaler { + return ec._DeleteVendorContactPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNDeleteVendorContactPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorContactPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteVendorContactPayload) 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._DeleteVendorContactPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNDeleteVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋ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) @@ -63481,6 +65522,25 @@ func (ec *executionContext) marshalNUpdateVendorBusinessAssociateAgreementPayloa return ec._UpdateVendorBusinessAssociateAgreementPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNUpdateVendorContactInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorContactInput(ctx context.Context, v any) (types.UpdateVendorContactInput, error) { + res, err := ec.unmarshalInputUpdateVendorContactInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNUpdateVendorContactPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorContactPayload(ctx context.Context, sel ast.SelectionSet, v types.UpdateVendorContactPayload) graphql.Marshaler { + return ec._UpdateVendorContactPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNUpdateVendorContactPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorContactPayload(ctx context.Context, sel ast.SelectionSet, v *types.UpdateVendorContactPayload) 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._UpdateVendorContactPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNUpdateVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorInput(ctx context.Context, v any) (types.UpdateVendorInput, error) { res, err := ec.unmarshalInputUpdateVendorInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -63927,6 +65987,114 @@ func (ec *executionContext) marshalNVendorConnection2ᚖgithubᚗcomᚋgetprobo return ec._VendorConnection(ctx, sel, v) } +func (ec *executionContext) marshalNVendorContact2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContact(ctx context.Context, sel ast.SelectionSet, v *types.VendorContact) 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._VendorContact(ctx, sel, v) +} + +func (ec *executionContext) marshalNVendorContactConnection2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactConnection(ctx context.Context, sel ast.SelectionSet, v types.VendorContactConnection) graphql.Marshaler { + return ec._VendorContactConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNVendorContactConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactConnection(ctx context.Context, sel ast.SelectionSet, v *types.VendorContactConnection) 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._VendorContactConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNVendorContactEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.VendorContactEdge) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNVendorContactEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactEdge(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNVendorContactEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactEdge(ctx context.Context, sel ast.SelectionSet, v *types.VendorContactEdge) 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._VendorContactEdge(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField(ctx context.Context, v any) (coredata.VendorContactOrderField, error) { + tmp, err := graphql.UnmarshalString(v) + res := unmarshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField[tmp] + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField(ctx context.Context, sel ast.SelectionSet, v coredata.VendorContactOrderField) graphql.Marshaler { + _ = sel + res := graphql.MarshalString(marshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField[v]) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +var ( + unmarshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField = map[string]coredata.VendorContactOrderField{ + "CREATED_AT": coredata.VendorContactOrderFieldCreatedAt, + "FULL_NAME": coredata.VendorContactOrderFieldFullName, + "EMAIL": coredata.VendorContactOrderFieldEmail, + } + marshalNVendorContactOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorContactOrderField = map[coredata.VendorContactOrderField]string{ + coredata.VendorContactOrderFieldCreatedAt: "CREATED_AT", + coredata.VendorContactOrderFieldFullName: "FULL_NAME", + coredata.VendorContactOrderFieldEmail: "EMAIL", + } +) + func (ec *executionContext) marshalNVendorEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.VendorEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -65288,6 +67456,14 @@ func (ec *executionContext) unmarshalOVendorComplianceReportOrder2ᚖgithubᚗco return &res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalOVendorContactOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorContactOrderBy(ctx context.Context, v any) (*types.VendorContactOrderBy, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputVendorContactOrder(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOVendorOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorOrderBy(ctx context.Context, v any) (*types.VendorOrderBy, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index 1cfb3c955..a0a3fd719 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -377,6 +377,18 @@ type CreateTrustCenterAccessPayload struct { TrustCenterAccessEdge *TrustCenterAccessEdge `json:"trustCenterAccessEdge"` } +type CreateVendorContactInput struct { + VendorID gid.GID `json:"vendorId"` + FullName *string `json:"fullName,omitempty"` + Email *string `json:"email,omitempty"` + Phone *string `json:"phone,omitempty"` + Role *string `json:"role,omitempty"` +} + +type CreateVendorContactPayload struct { + VendorContactEdge *VendorContactEdge `json:"vendorContactEdge"` +} + type CreateVendorInput struct { OrganizationID gid.GID `json:"organizationId"` Name string `json:"name"` @@ -611,6 +623,14 @@ type DeleteVendorComplianceReportPayload struct { DeletedVendorComplianceReportID gid.GID `json:"deletedVendorComplianceReportId"` } +type DeleteVendorContactInput struct { + VendorContactID gid.GID `json:"vendorContactId"` +} + +type DeleteVendorContactPayload struct { + DeletedVendorContactID gid.GID `json:"deletedVendorContactId"` +} + type DeleteVendorInput struct { VendorID gid.GID `json:"vendorId"` } @@ -1274,6 +1294,18 @@ type UpdateVendorBusinessAssociateAgreementPayload struct { VendorBusinessAssociateAgreement *VendorBusinessAssociateAgreement `json:"vendorBusinessAssociateAgreement"` } +type UpdateVendorContactInput struct { + ID gid.GID `json:"id"` + FullName *string `json:"fullName,omitempty"` + Email *string `json:"email,omitempty"` + Phone *string `json:"phone,omitempty"` + Role *string `json:"role,omitempty"` +} + +type UpdateVendorContactPayload struct { + VendorContact *VendorContact `json:"vendorContact"` +} + type UpdateVendorInput struct { ID gid.GID `json:"id"` Name *string `json:"name,omitempty"` @@ -1382,6 +1414,7 @@ type Vendor struct { Organization *Organization `json:"organization"` ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"` BusinessAssociateAgreement *VendorBusinessAssociateAgreement `json:"businessAssociateAgreement,omitempty"` + Contacts *VendorContactConnection `json:"contacts"` RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"` BusinessOwner *People `json:"businessOwner,omitempty"` SecurityOwner *People `json:"securityOwner,omitempty"` @@ -1446,6 +1479,30 @@ type VendorComplianceReportEdge struct { Node *VendorComplianceReport `json:"node"` } +type VendorContact struct { + ID gid.GID `json:"id"` + Vendor *Vendor `json:"vendor"` + FullName *string `json:"fullName,omitempty"` + Email *string `json:"email,omitempty"` + Phone *string `json:"phone,omitempty"` + Role *string `json:"role,omitempty"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func (VendorContact) IsNode() {} +func (this VendorContact) GetID() gid.GID { return this.ID } + +type VendorContactConnection struct { + Edges []*VendorContactEdge `json:"edges"` + PageInfo *PageInfo `json:"pageInfo"` +} + +type VendorContactEdge struct { + Cursor page.CursorKey `json:"cursor"` + Node *VendorContact `json:"node"` +} + type VendorEdge struct { Cursor page.CursorKey `json:"cursor"` Node *Vendor `json:"node"` diff --git a/pkg/server/api/console/v1/types/vendor_contact.go b/pkg/server/api/console/v1/types/vendor_contact.go new file mode 100644 index 000000000..c6951cb67 --- /dev/null +++ b/pkg/server/api/console/v1/types/vendor_contact.go @@ -0,0 +1,56 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package types + +import ( + "github.com/getprobo/probo/pkg/coredata" + "github.com/getprobo/probo/pkg/page" +) + +type ( + VendorContactOrderBy OrderBy[coredata.VendorContactOrderField] +) + +func NewVendorContactConnection(p *page.Page[*coredata.VendorContact, coredata.VendorContactOrderField]) *VendorContactConnection { + var edges = make([]*VendorContactEdge, len(p.Data)) + + for i := range edges { + edges[i] = NewVendorContactEdge(p.Data[i], p.Cursor.OrderBy.Field) + } + + return &VendorContactConnection{ + Edges: edges, + PageInfo: NewPageInfo(p), + } +} + +func NewVendorContactEdge(c *coredata.VendorContact, orderBy coredata.VendorContactOrderField) *VendorContactEdge { + return &VendorContactEdge{ + Cursor: c.CursorKey(orderBy), + Node: NewVendorContact(c), + } +} + +func NewVendorContact(c *coredata.VendorContact) *VendorContact { + return &VendorContact{ + ID: c.ID, + FullName: c.FullName, + Email: c.Email, + Phone: c.Phone, + Role: c.Role, + CreatedAt: c.CreatedAt, + UpdatedAt: c.UpdatedAt, + } +} diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index b59c70c4c..f56e259c8 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -1250,6 +1250,64 @@ func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteV }, nil } +// CreateVendorContact is the resolver for the createVendorContact field. +func (r *mutationResolver) CreateVendorContact(ctx context.Context, input types.CreateVendorContactInput) (*types.CreateVendorContactPayload, error) { + prb := r.ProboService(ctx, input.VendorID.TenantID()) + + req := probo.CreateVendorContactRequest{ + VendorID: input.VendorID, + FullName: input.FullName, + Email: input.Email, + Phone: input.Phone, + Role: input.Role, + } + + vendorContact, err := prb.VendorContacts.Create(ctx, req) + if err != nil { + return nil, fmt.Errorf("failed to create vendor contact: %w", err) + } + + return &types.CreateVendorContactPayload{ + VendorContactEdge: types.NewVendorContactEdge(vendorContact, coredata.VendorContactOrderFieldCreatedAt), + }, nil +} + +// UpdateVendorContact is the resolver for the updateVendorContact field. +func (r *mutationResolver) UpdateVendorContact(ctx context.Context, input types.UpdateVendorContactInput) (*types.UpdateVendorContactPayload, error) { + prb := r.ProboService(ctx, input.ID.TenantID()) + + req := probo.UpdateVendorContactRequest{ + ID: input.ID, + FullName: &input.FullName, + Email: &input.Email, + Phone: &input.Phone, + Role: &input.Role, + } + + vendorContact, err := prb.VendorContacts.Update(ctx, req) + if err != nil { + return nil, fmt.Errorf("failed to update vendor contact: %w", err) + } + + return &types.UpdateVendorContactPayload{ + VendorContact: types.NewVendorContact(vendorContact), + }, nil +} + +// DeleteVendorContact is the resolver for the deleteVendorContact field. +func (r *mutationResolver) DeleteVendorContact(ctx context.Context, input types.DeleteVendorContactInput) (*types.DeleteVendorContactPayload, error) { + prb := r.ProboService(ctx, input.VendorContactID.TenantID()) + + err := prb.VendorContacts.Delete(ctx, input.VendorContactID) + if err != nil { + return nil, fmt.Errorf("failed to delete vendor contact: %w", err) + } + + return &types.DeleteVendorContactPayload{ + DeletedVendorContactID: input.VendorContactID, + }, nil +} + // CreateFramework is the resolver for the createFramework field. func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) { prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -2972,6 +3030,12 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error panic(fmt.Errorf("cannot get vendor compliance report: %w", err)) } return types.NewVendorComplianceReport(vendorComplianceReport), nil + case coredata.VendorContactEntityType: + vendorContact, err := prb.VendorContacts.Get(ctx, id) + if err != nil { + panic(fmt.Errorf("cannot get vendor contact: %w", err)) + } + return types.NewVendorContact(vendorContact), nil case coredata.DocumentVersionEntityType: documentVersion, err := prb.Documents.GetVersion(ctx, id) if err != nil { @@ -3405,6 +3469,31 @@ func (r *vendorResolver) BusinessAssociateAgreement(ctx context.Context, obj *ty return types.NewVendorBusinessAssociateAgreement(vendorBusinessAssociateAgreement, file), nil } +// Contacts is the resolver for the contacts field. +func (r *vendorResolver) Contacts(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) (*types.VendorContactConnection, error) { + prb := r.ProboService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.VendorContactOrderField]{ + Field: coredata.VendorContactOrderFieldCreatedAt, + Direction: page.OrderDirectionDesc, + } + if orderBy != nil { + pageOrderBy = page.OrderBy[coredata.VendorContactOrderField]{ + Field: orderBy.Field, + Direction: orderBy.Direction, + } + } + + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + page, err := prb.VendorContacts.List(ctx, obj.ID, cursor) + if err != nil { + panic(fmt.Errorf("failed to list vendor contacts: %w", err)) + } + + return types.NewVendorContactConnection(page), nil +} + // RiskAssessments is the resolver for the riskAssessments field. func (r *vendorResolver) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) { prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -3547,6 +3636,24 @@ func (r *vendorConnectionResolver) TotalCount(ctx context.Context, obj *types.Ve panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } +// Vendor is the resolver for the vendor field. +func (r *vendorContactResolver) Vendor(ctx context.Context, obj *types.VendorContact) (*types.Vendor, error) { + prb := r.ProboService(ctx, obj.ID.TenantID()) + + // Get the vendor contact to access the VendorID + vendorContact, err := prb.VendorContacts.Get(ctx, obj.ID) + if err != nil { + panic(fmt.Errorf("failed to get vendor contact: %w", err)) + } + + vendor, err := prb.Vendors.Get(ctx, vendorContact.VendorID) + if err != nil { + panic(fmt.Errorf("failed to get vendor: %w", err)) + } + + return types.NewVendor(vendor), nil +} + // Vendor is the resolver for the vendor field. func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) { prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -3728,6 +3835,9 @@ func (r *Resolver) VendorConnection() schema.VendorConnectionResolver { return &vendorConnectionResolver{r} } +// VendorContact returns schema.VendorContactResolver implementation. +func (r *Resolver) VendorContact() schema.VendorContactResolver { return &vendorContactResolver{r} } + // VendorRiskAssessment returns schema.VendorRiskAssessmentResolver implementation. func (r *Resolver) VendorRiskAssessment() schema.VendorRiskAssessmentResolver { return &vendorRiskAssessmentResolver{r} @@ -3769,5 +3879,6 @@ type vendorResolver struct{ *Resolver } type vendorBusinessAssociateAgreementResolver struct{ *Resolver } type vendorComplianceReportResolver struct{ *Resolver } type vendorConnectionResolver struct{ *Resolver } +type vendorContactResolver struct{ *Resolver } type vendorRiskAssessmentResolver struct{ *Resolver } type viewerResolver struct{ *Resolver }