From d9c76878c09e1b64c85e328fffd2f0ed50016434 Mon Sep 17 00:00:00 2001 From: gearnode Date: Wed, 19 Feb 2025 10:37:55 +0100 Subject: [PATCH] Refactor create vendor mutation to use connection update Signed-off-by: gearnode --- apps/console/src/pages/VendorListPage.tsx | 75 ++-- ...dorListPageCreateVendorMutation.graphql.ts | 201 +++++++---- .../VendorListPageQuery.graphql.ts | 330 ++++++++++-------- pkg/api/console/v1/schema.graphql | 13 +- pkg/api/console/v1/schema/schema.go | 208 +++++++++-- pkg/api/console/v1/types/types.go | 17 +- pkg/api/console/v1/v1_resolver.go | 19 +- pkg/probo/create_vendor.go | 30 +- 8 files changed, 598 insertions(+), 295 deletions(-) diff --git a/apps/console/src/pages/VendorListPage.tsx b/apps/console/src/pages/VendorListPage.tsx index 61b6bf1da..da1441f0b 100644 --- a/apps/console/src/pages/VendorListPage.tsx +++ b/apps/console/src/pages/VendorListPage.tsx @@ -5,6 +5,7 @@ import { usePreloadedQuery, useQueryLoader, useMutation, + ConnectionHandler, } from "react-relay"; import { useSearchParams } from "react-router"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; @@ -16,6 +17,10 @@ import { Link } from "react-router"; import Fuse from "fuse.js"; import type { VendorListPageQuery as VendorListPageQueryType } from "./__generated__/VendorListPageQuery.graphql"; import { Helmet } from "react-helmet-async"; +import { VendorListPageCreateVendorMutation } from "./__generated__/VendorListPageCreateVendorMutation.graphql"; +import { VendorListPageDeleteVendorMutation } from "./__generated__/VendorListPageDeleteVendorMutation.graphql"; +import { toast } from "@/hooks/use-toast"; + const ITEMS_PER_PAGE = 20; const vendorListPageQuery = graphql` @@ -25,10 +30,11 @@ const vendorListPageQuery = graphql` $last: Int $before: CursorKey ) { - node(id: "AZSfP_xAcAC5IAAAAAAltA") { + currentOrganization: node(id: "AZSfP_xAcAC5IAAAAAAltA") { id ... on Organization { - vendors(first: $first, after: $after, last: $last, before: $before) { + vendors(first: $first, after: $after, last: $last, before: $before) + @connection(key: "VendorListPageQuery_vendors") { edges { node { id @@ -51,12 +57,16 @@ const vendorListPageQuery = graphql` `; const createVendorMutation = graphql` - mutation VendorListPageCreateVendorMutation($input: CreateVendorInput!) { + mutation VendorListPageCreateVendorMutation($input: CreateVendorInput!, $connections: [ID!]!) { createVendor(input: $input) { - id - name - createdAt - updatedAt + vendorEdge @prependEdge(connections: $connections) { + node { + id + name + createdAt + updatedAt + } + } } } `; @@ -92,14 +102,9 @@ const vendorsList = [ { id: "17", name: "CircleCI", createdAt: new Date().toISOString() }, ]; -type LoadQueryType = ReturnType< - typeof useQueryLoader ->[1]; - function VendorListContent({ queryRef, onPageChange, - loadQuery, }: { queryRef: PreloadedQuery; onPageChange: (params: { @@ -108,18 +113,17 @@ function VendorListContent({ last?: number; before?: string; }) => void; - loadQuery: LoadQueryType; }) { const data = usePreloadedQuery(vendorListPageQuery, queryRef); const [searchParams, setSearchParams] = useSearchParams(); const [isPending, startTransition] = useTransition(); const [searchTerm, setSearchTerm] = useState(""); const [filteredVendors, setFilteredVendors] = useState>([]); - const [createVendor] = useMutation(createVendorMutation); - const [deleteVendor] = useMutation(deleteVendorMutation); + const [createVendor] = useMutation(createVendorMutation); + const [deleteVendor] = useMutation(deleteVendorMutation); - const vendors = data.node?.vendors?.edges?.map((edge) => edge?.node) ?? []; - const pageInfo = data.node?.vendors?.pageInfo; + const vendors = data.currentOrganization.vendors?.edges.map((edge) => edge.node) ?? []; + const pageInfo = data.currentOrganization.vendors?.pageInfo; const fuse = new Fuse(vendorsList, { keys: ["name"], @@ -204,23 +208,23 @@ function VendorListContent({ onClick={() => { createVendor({ variables: { + connections: [ConnectionHandler.getConnectionID(data.currentOrganization.id, "VendorListPageQuery_vendors")], input: { - organizationId: data.node.id, + organizationId: data.currentOrganization.id, name: vendor.name, + description: "", + serviceStartAt: new Date().toISOString(), + serviceCriticality: "LOW", + riskTier: "GENERAL", }, }, - onCompleted(response: any) { + onCompleted(response) { setSearchTerm(""); setFilteredVendors([]); - loadQuery( - { - first: ITEMS_PER_PAGE, - after: undefined, - last: undefined, - before: undefined, - }, - { fetchPolicy: "network-only" }, - ); + toast({ + title: "Vendor added", + description: "The vendor has been added successfully", + }); }, }); }} @@ -297,15 +301,10 @@ function VendorListContent({ }, }, onCompleted() { - loadQuery( - { - first: ITEMS_PER_PAGE, - after: undefined, - last: undefined, - before: undefined, - }, - { fetchPolicy: "network-only" }, - ); + toast({ + title: "Vendor deleted", + description: "The vendor has been deleted successfully", + }); }, }); } @@ -360,7 +359,6 @@ export default function VendorListPage() { const [queryRef, loadQuery] = useQueryLoader(vendorListPageQuery); - // Initialize with URL params useEffect(() => { const after = searchParams.get("after"); const before = searchParams.get("before"); @@ -408,7 +406,6 @@ export default function VendorListPage() { diff --git a/apps/console/src/pages/__generated__/VendorListPageCreateVendorMutation.graphql.ts b/apps/console/src/pages/__generated__/VendorListPageCreateVendorMutation.graphql.ts index 917eed081..171d34e8b 100644 --- a/apps/console/src/pages/__generated__/VendorListPageCreateVendorMutation.graphql.ts +++ b/apps/console/src/pages/__generated__/VendorListPageCreateVendorMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<055f5292e2ca7bfecd0d701ce34c8d34>> + * @generated SignedSource<<03e542b8e2ecf3c17be86da4526541d2>> * @lightSyntaxTransform * @nogrep */ @@ -9,20 +9,34 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; +export type RiskTier = "CRITICAL" | "GENERAL" | "SIGNIFICANT"; +export type ServiceCriticality = "HIGH" | "LOW" | "MEDIUM"; export type CreateVendorInput = { description: string; name: string; organizationId: string; + privacyPolicyUrl?: string | null | undefined; + riskTier: RiskTier; + serviceCriticality: ServiceCriticality; + serviceStartAt: any; + serviceTerminationAt?: any | null | undefined; + statusPageUrl?: string | null | undefined; + termsOfServiceUrl?: string | null | undefined; }; export type VendorListPageCreateVendorMutation$variables = { + connections: ReadonlyArray; input: CreateVendorInput; }; export type VendorListPageCreateVendorMutation$data = { readonly createVendor: { - readonly createdAt: any; - readonly id: string; - readonly name: string; - readonly updatedAt: any; + readonly vendorEdge: { + readonly node: { + readonly createdAt: any; + readonly id: string; + readonly name: string; + readonly updatedAt: any; + }; + }; }; }; export type VendorListPageCreateVendorMutation = { @@ -31,88 +45,149 @@ export type VendorListPageCreateVendorMutation = { }; const node: ConcreteRequest = (function(){ -var v0 = [ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "connections" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" +}, +v2 = [ { - "defaultValue": null, - "kind": "LocalArgument", - "name": "input" + "kind": "Variable", + "name": "input", + "variableName": "input" } ], -v1 = [ - { - "alias": null, - "args": [ - { - "kind": "Variable", - "name": "input", - "variableName": "input" - } - ], - "concreteType": "Vendor", - "kind": "LinkedField", - "name": "createVendor", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", - "storageKey": null - } - ], - "storageKey": null - } -]; +v3 = { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "vendorEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "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 +}; return { "fragment": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], "kind": "Fragment", "metadata": null, "name": "VendorListPageCreateVendorMutation", - "selections": (v1/*: any*/), + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateVendorPayload", + "kind": "LinkedField", + "name": "createVendor", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + } + ], "type": "Mutation", "abstractKey": null }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], "kind": "Operation", "name": "VendorListPageCreateVendorMutation", - "selections": (v1/*: any*/) + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateVendorPayload", + "kind": "LinkedField", + "name": "createVendor", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "filters": null, + "handle": "prependEdge", + "key": "", + "kind": "LinkedHandle", + "name": "vendorEdge", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] }, "params": { - "cacheID": "11eabcf8c7c1fef7b2cb37bcadf52666", + "cacheID": "ddfddd8b4266631b16341e6fe2e04cb5", "id": null, "metadata": {}, "name": "VendorListPageCreateVendorMutation", "operationKind": "mutation", - "text": "mutation VendorListPageCreateVendorMutation(\n $input: CreateVendorInput!\n) {\n createVendor(input: $input) {\n id\n name\n createdAt\n updatedAt\n }\n}\n" + "text": "mutation VendorListPageCreateVendorMutation(\n $input: CreateVendorInput!\n) {\n createVendor(input: $input) {\n vendorEdge {\n node {\n id\n name\n createdAt\n updatedAt\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "aeb5751c0d301a9433e706d237a025cd"; +(node as any).hash = "03c48ba8f1db919da507322208e5e136"; export default node; diff --git a/apps/console/src/pages/__generated__/VendorListPageQuery.graphql.ts b/apps/console/src/pages/__generated__/VendorListPageQuery.graphql.ts index 1cd202d05..2b85d7228 100644 --- a/apps/console/src/pages/__generated__/VendorListPageQuery.graphql.ts +++ b/apps/console/src/pages/__generated__/VendorListPageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3b4f62f431760660274bbff4ae888d0a>> + * @generated SignedSource<<874e734a238db8fc4ab486da7d49ceee>> * @lightSyntaxTransform * @nogrep */ @@ -16,7 +16,7 @@ export type VendorListPageQuery$variables = { last?: number | null | undefined; }; export type VendorListPageQuery$data = { - readonly node: { + readonly currentOrganization: { readonly id: string; readonly vendors?: { readonly edges: ReadonlyArray<{ @@ -78,134 +78,127 @@ v5 = { "storageKey": null }, v6 = { - "kind": "InlineFragment", - "selections": [ - { - "alias": null, - "args": [ - { - "kind": "Variable", - "name": "after", - "variableName": "after" - }, - { - "kind": "Variable", - "name": "before", - "variableName": "before" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "first" - }, - { - "kind": "Variable", - "name": "last", - "variableName": "last" - } - ], - "concreteType": "VendorConnection", - "kind": "LinkedField", - "name": "vendors", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "concreteType": "VendorEdge", - "kind": "LinkedField", - "name": "edges", - "plural": true, - "selections": [ - { - "alias": null, - "args": null, - "concreteType": "Vendor", - "kind": "LinkedField", - "name": "node", - "plural": false, - "selections": [ - (v5/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", - "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": "hasNextPage", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "hasPreviousPage", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "startCursor", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "endCursor", - "storageKey": null - } - ], - "storageKey": null - } - ], - "storageKey": null - } - ], - "type": "Organization", - "abstractKey": null -}; + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v7 = [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v5/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + }, + (v6/*: 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": "hasNextPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasPreviousPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "startCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + } + ], + "storageKey": null + } +], +v8 = [ + { + "kind": "Variable", + "name": "after", + "variableName": "after" + }, + { + "kind": "Variable", + "name": "before", + "variableName": "before" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "first" + }, + { + "kind": "Variable", + "name": "last", + "variableName": "last" + } +]; return { "fragment": { "argumentDefinitions": [ @@ -219,7 +212,7 @@ return { "name": "VendorListPageQuery", "selections": [ { - "alias": null, + "alias": "currentOrganization", "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", @@ -227,7 +220,23 @@ return { "plural": false, "selections": [ (v5/*: any*/), - (v6/*: any*/) + { + "kind": "InlineFragment", + "selections": [ + { + "alias": "vendors", + "args": null, + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "__VendorListPageQuery_vendors_connection", + "plural": false, + "selections": (v7/*: any*/), + "storageKey": null + } + ], + "type": "Organization", + "abstractKey": null + } ], "storageKey": "node(id:\"AZSfP_xAcAC5IAAAAAAltA\")" } @@ -247,38 +256,69 @@ return { "name": "VendorListPageQuery", "selections": [ { - "alias": null, + "alias": "currentOrganization", "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__typename", - "storageKey": null - }, + (v6/*: any*/), (v5/*: any*/), - (v6/*: any*/) + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": (v8/*: any*/), + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": (v7/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": (v8/*: any*/), + "filters": null, + "handle": "connection", + "key": "VendorListPageQuery_vendors", + "kind": "LinkedHandle", + "name": "vendors" + } + ], + "type": "Organization", + "abstractKey": null + } ], "storageKey": "node(id:\"AZSfP_xAcAC5IAAAAAAltA\")" } ] }, "params": { - "cacheID": "d38a5cbe98c811f237ea5722871aabf6", + "cacheID": "079490495e96d3609a263570f185673b", "id": null, - "metadata": {}, + "metadata": { + "connection": [ + { + "count": null, + "cursor": null, + "direction": "bidirectional", + "path": [ + "currentOrganization", + "vendors" + ] + } + ] + }, "name": "VendorListPageQuery", "operationKind": "query", - "text": "query VendorListPageQuery(\n $first: Int\n $after: CursorKey\n $last: Int\n $before: CursorKey\n) {\n node(id: \"AZSfP_xAcAC5IAAAAAAltA\") {\n __typename\n id\n ... on Organization {\n vendors(first: $first, after: $after, last: $last, before: $before) {\n edges {\n node {\n id\n name\n createdAt\n updatedAt\n }\n cursor\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n}\n" + "text": "query VendorListPageQuery(\n $first: Int\n $after: CursorKey\n $last: Int\n $before: CursorKey\n) {\n currentOrganization: node(id: \"AZSfP_xAcAC5IAAAAAAltA\") {\n __typename\n id\n ... on Organization {\n vendors(first: $first, after: $after, last: $last, before: $before) {\n edges {\n node {\n id\n name\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "e371fe8685ccc70b229f0d5b07d6e271"; +(node as any).hash = "9613eb9b1e34b2ebffda69c5909f5f5b"; export default node; diff --git a/pkg/api/console/v1/schema.graphql b/pkg/api/console/v1/schema.graphql index 1306f92a8..13ce3ab2c 100644 --- a/pkg/api/console/v1/schema.graphql +++ b/pkg/api/console/v1/schema.graphql @@ -314,7 +314,7 @@ type Query { } type Mutation { - createVendor(input: CreateVendorInput!): Vendor! + createVendor(input: CreateVendorInput!): CreateVendorPayload! updateVendor(input: UpdateVendorInput!): Vendor! deleteVendor(input: DeleteVendorInput!): Void! createPeople(input: CreatePeopleInput!): CreatePeoplePayload! @@ -326,6 +326,13 @@ input CreateVendorInput { organizationId: ID! name: String! description: String! + serviceStartAt: Datetime! + serviceTerminationAt: Datetime + serviceCriticality: ServiceCriticality! + riskTier: RiskTier! + statusPageUrl: String + termsOfServiceUrl: String + privacyPolicyUrl: String } input DeleteVendorInput { @@ -381,4 +388,8 @@ input UpdateVendorInput { type CreatePeoplePayload { peopleEdge: PeopleEdge! +} + +type CreateVendorPayload { + vendorEdge: VendorEdge! } \ No newline at end of file diff --git a/pkg/api/console/v1/schema/schema.go b/pkg/api/console/v1/schema/schema.go index a0a0a2095..f0253e173 100644 --- a/pkg/api/console/v1/schema/schema.go +++ b/pkg/api/console/v1/schema/schema.go @@ -100,6 +100,10 @@ type ComplexityRoot struct { PeopleEdge func(childComplexity int) int } + CreateVendorPayload struct { + VendorEdge func(childComplexity int) int + } + Evidence struct { CreatedAt func(childComplexity int) int FileURL func(childComplexity int) int @@ -289,7 +293,7 @@ type FrameworkResolver interface { Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.ControlConnection, error) } type MutationResolver interface { - CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.Vendor, error) + CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.Vendor, error) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (string, error) CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) @@ -506,6 +510,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CreatePeoplePayload.PeopleEdge(childComplexity), true + case "CreateVendorPayload.vendorEdge": + if e.complexity.CreateVendorPayload.VendorEdge == nil { + break + } + + return e.complexity.CreateVendorPayload.VendorEdge(childComplexity), true + case "Evidence.createdAt": if e.complexity.Evidence.CreatedAt == nil { break @@ -1717,7 +1728,7 @@ type Query { } type Mutation { - createVendor(input: CreateVendorInput!): Vendor! + createVendor(input: CreateVendorInput!): CreateVendorPayload! updateVendor(input: UpdateVendorInput!): Vendor! deleteVendor(input: DeleteVendorInput!): Void! createPeople(input: CreatePeopleInput!): CreatePeoplePayload! @@ -1729,6 +1740,13 @@ input CreateVendorInput { organizationId: ID! name: String! description: String! + serviceStartAt: Datetime! + serviceTerminationAt: Datetime + serviceCriticality: ServiceCriticality! + riskTier: RiskTier! + statusPageUrl: String + termsOfServiceUrl: String + privacyPolicyUrl: String } input DeleteVendorInput { @@ -1784,6 +1802,10 @@ input UpdateVendorInput { type CreatePeoplePayload { peopleEdge: PeopleEdge! +} + +type CreateVendorPayload { + vendorEdge: VendorEdge! }`, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -3723,6 +3745,50 @@ func (ec *executionContext) fieldContext_CreatePeoplePayload_peopleEdge(_ contex 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 { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.VendorEdge, 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.VendorEdge) + fc.Result = res + return ec.marshalNVendorEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorEdge(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CreateVendorPayload_vendorEdge(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CreateVendorPayload", + 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_VendorEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_VendorEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorEdge", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Evidence_id(ctx context.Context, field graphql.CollectedField, obj *types.Evidence) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Evidence_id(ctx, field) if err != nil { @@ -5069,9 +5135,9 @@ func (ec *executionContext) _Mutation_createVendor(ctx context.Context, field gr } return graphql.Null } - res := resTmp.(*types.Vendor) + res := resTmp.(*types.CreateVendorPayload) fc.Result = res - return ec.marshalNVendor2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐVendor(ctx, field.Selections, res) + return ec.marshalNCreateVendorPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorPayload(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Mutation_createVendor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -5082,34 +5148,10 @@ func (ec *executionContext) fieldContext_Mutation_createVendor(ctx context.Conte 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 "description": - return ec.fieldContext_Vendor_description(ctx, field) - case "serviceStartAt": - return ec.fieldContext_Vendor_serviceStartAt(ctx, field) - case "serviceTerminationAt": - return ec.fieldContext_Vendor_serviceTerminationAt(ctx, field) - case "serviceCriticality": - return ec.fieldContext_Vendor_serviceCriticality(ctx, field) - case "riskTier": - return ec.fieldContext_Vendor_riskTier(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 "createdAt": - return ec.fieldContext_Vendor_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_Vendor_updatedAt(ctx, field) - case "version": - return ec.fieldContext_Vendor_version(ctx, field) + case "vendorEdge": + return ec.fieldContext_CreateVendorPayload_vendorEdge(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Vendor", field.Name) + return nil, fmt.Errorf("no field named %q was found under type CreateVendorPayload", field.Name) }, } ctx = graphql.WithFieldContext(ctx, fc) @@ -9719,7 +9761,7 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"organizationId", "name", "description"} + fieldsInOrder := [...]string{"organizationId", "name", "description", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -9747,6 +9789,55 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, return it, err } it.Description = data + case "serviceStartAt": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceStartAt")) + data, err := ec.unmarshalNDatetime2timeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ServiceStartAt = data + case "serviceTerminationAt": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceTerminationAt")) + data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ServiceTerminationAt = data + case "serviceCriticality": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceCriticality")) + data, err := ec.unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx, v) + if err != nil { + return it, err + } + it.ServiceCriticality = data + case "riskTier": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("riskTier")) + data, err := ec.unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx, v) + if err != nil { + return it, err + } + it.RiskTier = data + case "statusPageUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusPageUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.StatusPageURL = data + case "termsOfServiceUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("termsOfServiceUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.TermsOfServiceURL = data + case "privacyPolicyUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("privacyPolicyUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.PrivacyPolicyURL = data } } @@ -10436,6 +10527,45 @@ func (ec *executionContext) _CreatePeoplePayload(ctx context.Context, sel ast.Se return out } +var createVendorPayloadImplementors = []string{"CreateVendorPayload"} + +func (ec *executionContext) _CreateVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateVendorPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, createVendorPayloadImplementors) + + 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("CreateVendorPayload") + case "vendorEdge": + out.Values[i] = ec._CreateVendorPayload_vendorEdge(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 evidenceImplementors = []string{"Evidence", "Node"} func (ec *executionContext) _Evidence(ctx context.Context, sel ast.SelectionSet, obj *types.Evidence) graphql.Marshaler { @@ -12536,6 +12666,20 @@ func (ec *executionContext) unmarshalNCreateVendorInput2githubᚗcomᚋgetprobo return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) marshalNCreateVendorPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorPayload(ctx context.Context, sel ast.SelectionSet, v types.CreateVendorPayload) graphql.Marshaler { + return ec._CreateVendorPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCreateVendorPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorPayload(ctx context.Context, sel ast.SelectionSet, v *types.CreateVendorPayload) 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._CreateVendorPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx context.Context, v any) (page.CursorKey, error) { res, err := types.UnmarshalCursorKeyScalar(v) return res, graphql.ErrorOnPath(ctx, err) diff --git a/pkg/api/console/v1/types/types.go b/pkg/api/console/v1/types/types.go index 1fb6fc6fe..5685241d2 100644 --- a/pkg/api/console/v1/types/types.go +++ b/pkg/api/console/v1/types/types.go @@ -72,9 +72,20 @@ type CreatePeoplePayload struct { } type CreateVendorInput struct { - OrganizationID gid.GID `json:"organizationId"` - Name string `json:"name"` - Description string `json:"description"` + OrganizationID gid.GID `json:"organizationId"` + Name string `json:"name"` + Description string `json:"description"` + ServiceStartAt time.Time `json:"serviceStartAt"` + ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"` + ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"` + RiskTier coredata.RiskTier `json:"riskTier"` + StatusPageURL *string `json:"statusPageUrl,omitempty"` + TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` + PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` +} + +type CreateVendorPayload struct { + VendorEdge *VendorEdge `json:"vendorEdge"` } type DeletePeopleInput struct { diff --git a/pkg/api/console/v1/v1_resolver.go b/pkg/api/console/v1/v1_resolver.go index 516c5e7f1..571982700 100644 --- a/pkg/api/console/v1/v1_resolver.go +++ b/pkg/api/console/v1/v1_resolver.go @@ -66,16 +66,25 @@ func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, } // CreateVendor is the resolver for the createVendor field. -func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.Vendor, error) { +func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) { vendor, err := r.svc.CreateVendor(ctx, probo.CreateVendorRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + ServiceStartAt: input.ServiceStartAt, + ServiceTerminationAt: input.ServiceTerminationAt, + ServiceCriticality: input.ServiceCriticality, + RiskTier: input.RiskTier, + StatusPageURL: input.StatusPageURL, + TermsOfServiceURL: input.TermsOfServiceURL, + PrivacyPolicyURL: input.PrivacyPolicyURL, }) if err != nil { return nil, fmt.Errorf("cannot create vendor: %w", err) } - - return types.NewVendor(vendor), nil + return &types.CreateVendorPayload{ + VendorEdge: types.NewVendorEdge(vendor), + }, nil } // UpdateVendor is the resolver for the updateVendor field. diff --git a/pkg/probo/create_vendor.go b/pkg/probo/create_vendor.go index b49631fd7..096b1d9d4 100644 --- a/pkg/probo/create_vendor.go +++ b/pkg/probo/create_vendor.go @@ -26,8 +26,16 @@ import ( type ( CreateVendorRequest struct { - OrganizationID gid.GID - Name string + OrganizationID gid.GID + Name string + Description string + ServiceStartAt time.Time + ServiceTerminationAt *time.Time + ServiceCriticality coredata.ServiceCriticality + RiskTier coredata.RiskTier + StatusPageURL *string + TermsOfServiceURL *string + PrivacyPolicyURL *string } ) @@ -43,11 +51,19 @@ func (s Service) CreateVendor( organization := &coredata.Organization{} vendor := &coredata.Vendor{ - ID: vendorID, - OrganizationID: req.OrganizationID, - Name: req.Name, - CreatedAt: now, - UpdatedAt: now, + ID: vendorID, + OrganizationID: req.OrganizationID, + Name: req.Name, + CreatedAt: now, + UpdatedAt: now, + Description: req.Description, + ServiceStartAt: req.ServiceStartAt, + ServiceTerminationAt: req.ServiceTerminationAt, + ServiceCriticality: req.ServiceCriticality, + RiskTier: req.RiskTier, + StatusPageURL: req.StatusPageURL, + TermsOfServiceURL: req.TermsOfServiceURL, + PrivacyPolicyURL: req.PrivacyPolicyURL, } err = s.pg.WithTx(