diff --git a/apps/console/src/App.tsx b/apps/console/src/App.tsx index 137a264ea..93ebb751c 100644 --- a/apps/console/src/App.tsx +++ b/apps/console/src/App.tsx @@ -33,12 +33,15 @@ const VendorOverviewPage = lazy(() => import("./pages/VendorOverviewPage")); const SettingsPage = lazy(() => import("./pages/SettingsPage")); const CreatePeoplePage = lazy(() => import("./pages/CreatePeoplePage")); const FrameworkOverviewPage = lazy( - () => import("./pages/FrameworkOverviewPage"), + () => import("./pages/FrameworkOverviewPage") ); const ControlOverviewPage = lazy(() => import("./pages/ControlOverviewPage")); const PeopleOverviewPage = lazy(() => import("./pages/PeopleOverviewPage")); const LoginPage = lazy(() => import("./pages/LoginPage")); const RegisterPage = lazy(() => import("./pages/RegisterPage")); +const CreateOrganizationPage = lazy( + () => import("./pages/CreateOrganizationPage") +); function App() { return ( @@ -202,6 +205,16 @@ function App() { } /> + + + + + + } + /> { + console.log(data.organizations); + if ( data.organizations && - data.organizations.length > 0 && + data.organizations.edges.length > 0 && !currentOrganization ) { // Type assertion to include plan field - setCurrentOrganization(data.organizations[0] as Organization); + setCurrentOrganization(data.organizations.edges[0].node); } }, [data.organizations, currentOrganization, setCurrentOrganization]); @@ -109,27 +118,32 @@ export function TeamSwitcher({ Organizations - {data.organizations.map((org: Organization, index: number) => ( + {data.organizations.edges.map((edge, index) => ( setCurrentOrganization(org)} + key={edge.node.id} + onClick={() => setCurrentOrganization(edge.node)} className="gap-2 p-2" >
- +
- {org.name} + {edge.node.name} ⌘{index + 1}
))} - -
- -
-
- Add organization -
+ + +
+ +
+
+ Add organization +
+
diff --git a/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts b/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts index c2f30a8a3..4ce2037ad 100644 --- a/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts +++ b/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -29,7 +29,14 @@ var v0 = { "kind": "ScalarField", "name": "id", "storageKey": null -}; +}, +v1 = [ + { + "kind": "Literal", + "name": "first", + "value": 25 + } +]; return { "fragment": { "argumentDefinitions": [], @@ -80,29 +87,111 @@ return { (v0/*: any*/), { "alias": null, - "args": null, - "concreteType": "Organization", + "args": (v1/*: any*/), + "concreteType": "OrganizationConnection", "kind": "LinkedField", "name": "organizations", - "plural": true, + "plural": false, "selections": [ - (v0/*: any*/), { "alias": null, "args": null, - "kind": "ScalarField", - "name": "name", + "concreteType": "OrganizationEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "logoUrl", + "storageKey": null + }, + { + "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, - "kind": "ScalarField", - "name": "logoUrl", + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] } ], - "storageKey": null + "storageKey": "organizations(first:25)" + }, + { + "alias": null, + "args": (v1/*: any*/), + "filters": null, + "handle": "connection", + "key": "TeamSwitcher_organizations", + "kind": "LinkedHandle", + "name": "organizations" }, { "alias": null, @@ -124,12 +213,12 @@ return { ] }, "params": { - "cacheID": "48137f101a20a5ce116cbf46c2a8cd63", + "cacheID": "52b7d912665a4da10a79b82987a7e58a", "id": null, "metadata": {}, "name": "AppSidebarQuery", "operationKind": "query", - "text": "query AppSidebarQuery {\n viewer {\n id\n ...TeamSwitcher_organizations\n ...NavUser_viewer\n }\n}\n\nfragment NavUser_viewer on User {\n id\n fullName\n email\n}\n\nfragment TeamSwitcher_organizations on User {\n organizations {\n id\n name\n logoUrl\n }\n}\n" + "text": "query AppSidebarQuery {\n viewer {\n id\n ...TeamSwitcher_organizations\n ...NavUser_viewer\n }\n}\n\nfragment NavUser_viewer on User {\n id\n fullName\n email\n}\n\nfragment TeamSwitcher_organizations on User {\n organizations(first: 25) {\n edges {\n node {\n id\n name\n logoUrl\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" } }; })(); diff --git a/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts b/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts index 451419ebf..05996a42b 100644 --- a/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts +++ b/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<8ecb9304d0a498d483d1a8c251f8c49a>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -11,11 +11,16 @@ import { ReaderFragment } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type TeamSwitcher_organizations$data = { - readonly organizations: ReadonlyArray<{ - readonly id: string; - readonly logoUrl: string; - readonly name: string; - }>; + readonly organizations: { + readonly __id: string; + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly logoUrl: string; + readonly name: string; + }; + }>; + }; readonly " $fragmentType": "TeamSwitcher_organizations"; }; export type TeamSwitcher_organizations$key = { @@ -26,37 +31,121 @@ export type TeamSwitcher_organizations$key = { const node: ReaderFragment = { "argumentDefinitions": [], "kind": "Fragment", - "metadata": null, + "metadata": { + "connection": [ + { + "count": null, + "cursor": null, + "direction": "forward", + "path": [ + "organizations" + ] + } + ] + }, "name": "TeamSwitcher_organizations", "selections": [ { - "alias": null, + "alias": "organizations", "args": null, - "concreteType": "Organization", + "concreteType": "OrganizationConnection", "kind": "LinkedField", - "name": "organizations", - "plural": true, + "name": "__TeamSwitcher_organizations_connection", + "plural": false, "selections": [ { "alias": null, "args": null, - "kind": "ScalarField", - "name": "id", + "concreteType": "OrganizationEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Organization", + "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": "logoUrl", + "storageKey": null + }, + { + "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, - "kind": "ScalarField", - "name": "name", + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], "storageKey": null }, { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "logoUrl", - "storageKey": null + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] } ], "storageKey": null @@ -66,6 +155,6 @@ const node: ReaderFragment = { "abstractKey": null }; -(node as any).hash = "318f68b82b5b87500ec99ffcdd2929ab"; +(node as any).hash = "22731866cafda226a19f8c64fda51ba5"; export default node; diff --git a/apps/console/src/layouts/ConsoleLayout.tsx b/apps/console/src/layouts/ConsoleLayout.tsx index 6807ec76d..2b137894e 100644 --- a/apps/console/src/layouts/ConsoleLayout.tsx +++ b/apps/console/src/layouts/ConsoleLayout.tsx @@ -73,7 +73,7 @@ function BreadcrumbFrameworkOverview() { } `, { frameworkId: frameworkId! }, - { fetchPolicy: "store-or-network" }, + { fetchPolicy: "store-or-network" } ); return ( @@ -133,7 +133,7 @@ function BreadcrumbPeopleOverview() { } `, { peopleId: peopleId! }, - { fetchPolicy: "store-or-network" }, + { fetchPolicy: "store-or-network" } ); return ( @@ -177,7 +177,7 @@ function BreadcrumbVendorOverview() { } `, { vendorId: vendorId! }, - { fetchPolicy: "store-or-network" }, + { fetchPolicy: "store-or-network" } ); return ( @@ -215,7 +215,7 @@ function BreadcrumbControlOverview() { } `, { frameworkId: frameworkId!, controlId: controlId! }, - { fetchPolicy: "store-or-network" }, + { fetchPolicy: "store-or-network" } ); return ( @@ -243,6 +243,20 @@ function BreadcrumbControlOverview() { ); } +function BreadcrumbCreateOrganization() { + return ( + <> + + + + Create Organization + + + + + ); +} + export default function ConsoleLayout() { return ( @@ -280,6 +294,10 @@ export default function ConsoleLayout() { element={} />
+ } + /> diff --git a/apps/console/src/pages/CreateOrganizationPage.tsx b/apps/console/src/pages/CreateOrganizationPage.tsx new file mode 100644 index 000000000..1da1d8e92 --- /dev/null +++ b/apps/console/src/pages/CreateOrganizationPage.tsx @@ -0,0 +1,186 @@ +import { useState } from "react"; +import { useNavigate } from "react-router"; +import { + graphql, + ConnectionHandler, + useMutation, + useLazyLoadQuery, +} from "react-relay"; +import { Helmet } from "react-helmet-async"; +import { Button } from "@/components/ui/button"; +import { useOrganization } from "@/contexts/OrganizationContext"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { useToast } from "@/hooks/use-toast"; +import { HelpCircle } from "lucide-react"; +import { CreateOrganizationPageCreateOrganizationMutation } from "./__generated__/CreateOrganizationPageCreateOrganizationMutation.graphql"; +import { CreateOrganizationPageViewerQuery } from "./__generated__/CreateOrganizationPageViewerQuery.graphql"; + +const createOrganizationMutation = graphql` + mutation CreateOrganizationPageCreateOrganizationMutation( + $input: CreateOrganizationInput! + $connections: [ID!]! + ) { + createOrganization(input: $input) { + organizationEdge @appendEdge(connections: $connections) { + node { + id + name + logoUrl + } + } + } + } +`; + +const viewerQuery = graphql` + query CreateOrganizationPageViewerQuery { + viewer { + id + } + } +`; + +function EditableField({ + label, + value, + onChange, + type = "text", + helpText, + required, +}: { + label: string; + value: string; + onChange: (value: string) => void; + type?: string; + helpText?: string; + required?: boolean; +}) { + return ( +
+
+ + +
+
+ onChange(e.target.value)} + required={required} + /> + {helpText &&

{helpText}

} +
+
+ ); +} + +export default function CreateOrganizationPage() { + const navigate = useNavigate(); + const { setCurrentOrganization } = useOrganization(); + const data = useLazyLoadQuery( + viewerQuery, + {} + ); + const [createOrganization] = + useMutation( + createOrganizationMutation + ); + const { toast } = useToast(); + const [formData, setFormData] = useState({ + name: "", + }); + + const handleFieldChange = (field: keyof typeof formData, value: string) => { + setFormData((prev) => ({ + ...prev, + [field]: value, + })); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + createOrganization({ + variables: { + input: { + name: formData.name, + }, + connections: [ + ConnectionHandler.getConnectionID( + data.viewer.id, + "TeamSwitcher_organizations" + ), + ], + }, + onCompleted: (response) => { + const newOrg = response.createOrganization.organizationEdge.node; + setCurrentOrganization(newOrg); + toast({ + title: "Success", + description: "Organization created successfully", + variant: "default", + }); + navigate("/"); + }, + onError: (error) => { + toast({ + title: "Error", + description: error.message || "Failed to create organization", + variant: "destructive", + }); + }, + }); + }; + + return ( + <> + + Create Organization - Probo + + +
+
+

+ Create Organization +

+

+ Create a new organization to manage your compliance and security + needs. +

+
+ +
+ + + Organization Details + + Enter the basic information about your organization. + + + + handleFieldChange("name", value)} + helpText="The name of your organization as it will appear throughout the platform." + required + /> + + + + +
+
+ + ); +} diff --git a/apps/console/src/pages/HomePage.tsx b/apps/console/src/pages/HomePage.tsx index 69819d0bb..9e0854493 100644 --- a/apps/console/src/pages/HomePage.tsx +++ b/apps/console/src/pages/HomePage.tsx @@ -13,104 +13,108 @@ export const HomePageQuery = graphql` viewer { id organizations { - name - createdAt - updatedAt - vendors { - edges { - node { - id - name - createdAt - updatedAt + edges { + node { + name + createdAt + updatedAt + vendors { + edges { + node { + id + name + createdAt + updatedAt + } + } } - } - } - peoples { - edges { - node { - id - fullName - primaryEmailAddress - additionalEmailAddresses - createdAt - updatedAt + peoples { + edges { + node { + id + fullName + primaryEmailAddress + additionalEmailAddresses + createdAt + updatedAt + } + } } - } - } - frameworks { - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - edges { - cursor - node { - id - name - description - controls { - edges { - node { - id - name - state - stateTransisions { - edges { - node { - id - toState - fromState - createdAt - updatedAt + frameworks { + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + edges { + cursor + node { + id + name + description + controls { + edges { + node { + id + name + state + stateTransisions { + edges { + node { + id + toState + fromState + createdAt + updatedAt + } + } } - } - } - tasks { - edges { - node { - id - name - state - evidences { - edges { - node { - id - state - fileUrl - stateTransisions { - edges { - node { - id - fromState - toState - reason - createdAt - updatedAt + tasks { + edges { + node { + id + name + state + evidences { + edges { + node { + id + state + fileUrl + stateTransisions { + edges { + node { + id + fromState + toState + reason + createdAt + updatedAt + } + } } + createdAt + updatedAt } } - createdAt - updatedAt } + stateTransisions { + edges { + node { + id + toState + fromState + reason + createdAt + updatedAt + } + } + } + createdAt + updatedAt } } - stateTransisions { - edges { - node { - id - toState - fromState - reason - createdAt - updatedAt - } - } - } - createdAt - updatedAt } } } diff --git a/apps/console/src/pages/SettingsPage.tsx b/apps/console/src/pages/SettingsPage.tsx index 048c71ef9..76311869f 100644 --- a/apps/console/src/pages/SettingsPage.tsx +++ b/apps/console/src/pages/SettingsPage.tsx @@ -23,12 +23,13 @@ import { useQueryLoader, } from "react-relay"; import type { SettingsPageQuery as SettingsPageQueryType } from "./__generated__/SettingsPageQuery.graphql"; +import { useOrganization } from "@/contexts/OrganizationContext"; const settingsPageQuery = graphql` - query SettingsPageQuery { - viewer { + query SettingsPageQuery($organizationID: ID!) { + organization: node(id: $organizationID) { id - organizations { + ... on Organization { name logoUrl } @@ -49,7 +50,7 @@ function SettingsPageContent({ queryRef: PreloadedQuery; }) { const data = usePreloadedQuery(settingsPageQuery, queryRef); - const organization = data.viewer.organizations[0]; + const organization = data.organization; const members: Member[] = []; return ( @@ -216,9 +217,11 @@ export default function SettingsPage() { const [queryRef, loadQuery] = useQueryLoader(settingsPageQuery); + const { currentOrganization } = useOrganization(); + useEffect(() => { - loadQuery({}); - }, [loadQuery]); + loadQuery({ organizationID: currentOrganization!.id }); + }, [loadQuery, currentOrganization]); if (!queryRef) { return ; diff --git a/apps/console/src/pages/__generated__/CreateOrganizationPageCreateOrganizationMutation.graphql.ts b/apps/console/src/pages/__generated__/CreateOrganizationPageCreateOrganizationMutation.graphql.ts new file mode 100644 index 000000000..ecefbadac --- /dev/null +++ b/apps/console/src/pages/__generated__/CreateOrganizationPageCreateOrganizationMutation.graphql.ts @@ -0,0 +1,174 @@ +/** + * @generated SignedSource<<75687d4b60d4ae79658fffb99ea6f52b>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type CreateOrganizationInput = { + name: string; +}; +export type CreateOrganizationPageCreateOrganizationMutation$variables = { + connections: ReadonlyArray; + input: CreateOrganizationInput; +}; +export type CreateOrganizationPageCreateOrganizationMutation$data = { + readonly createOrganization: { + readonly organizationEdge: { + readonly node: { + readonly id: string; + readonly logoUrl: string; + readonly name: string; + }; + }; + }; +}; +export type CreateOrganizationPageCreateOrganizationMutation = { + response: CreateOrganizationPageCreateOrganizationMutation$data; + variables: CreateOrganizationPageCreateOrganizationMutation$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, + "concreteType": "OrganizationEdge", + "kind": "LinkedField", + "name": "organizationEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Organization", + "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": "logoUrl", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "CreateOrganizationPageCreateOrganizationMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateOrganizationPayload", + "kind": "LinkedField", + "name": "createOrganization", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "CreateOrganizationPageCreateOrganizationMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateOrganizationPayload", + "kind": "LinkedField", + "name": "createOrganization", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "filters": null, + "handle": "appendEdge", + "key": "", + "kind": "LinkedHandle", + "name": "organizationEdge", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "aa445272c59c25a9a2edc7592c1fd7cc", + "id": null, + "metadata": {}, + "name": "CreateOrganizationPageCreateOrganizationMutation", + "operationKind": "mutation", + "text": "mutation CreateOrganizationPageCreateOrganizationMutation(\n $input: CreateOrganizationInput!\n) {\n createOrganization(input: $input) {\n organizationEdge {\n node {\n id\n name\n logoUrl\n }\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "ec0da70244afe2faa02b05ee418b829e"; + +export default node; diff --git a/apps/console/src/pages/__generated__/CreateOrganizationPageViewerQuery.graphql.ts b/apps/console/src/pages/__generated__/CreateOrganizationPageViewerQuery.graphql.ts new file mode 100644 index 000000000..967c30494 --- /dev/null +++ b/apps/console/src/pages/__generated__/CreateOrganizationPageViewerQuery.graphql.ts @@ -0,0 +1,74 @@ +/** + * @generated SignedSource<<91e1415ad0a7d8ee0ae2a8e212f42f19>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type CreateOrganizationPageViewerQuery$variables = Record; +export type CreateOrganizationPageViewerQuery$data = { + readonly viewer: { + readonly id: string; + }; +}; +export type CreateOrganizationPageViewerQuery = { + response: CreateOrganizationPageViewerQuery$data; + variables: CreateOrganizationPageViewerQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "viewer", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "CreateOrganizationPageViewerQuery", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "CreateOrganizationPageViewerQuery", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "8bb495e88bada2ffda332ffbc11f3340", + "id": null, + "metadata": {}, + "name": "CreateOrganizationPageViewerQuery", + "operationKind": "query", + "text": "query CreateOrganizationPageViewerQuery {\n viewer {\n id\n }\n}\n" + } +}; +})(); + +(node as any).hash = "2341c7947749857243e9f492235dfd61"; + +export default node; diff --git a/apps/console/src/pages/__generated__/HomePageQuery.graphql.ts b/apps/console/src/pages/__generated__/HomePageQuery.graphql.ts index 1816575e2..059ee67ae 100644 --- a/apps/console/src/pages/__generated__/HomePageQuery.graphql.ts +++ b/apps/console/src/pages/__generated__/HomePageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<17467071cb25b3e291532a4fb9074d67>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -16,115 +16,119 @@ export type HomePageQuery$variables = Record; export type HomePageQuery$data = { readonly viewer: { readonly id: string; - readonly organizations: ReadonlyArray<{ - readonly createdAt: any; - readonly frameworks: { - readonly edges: ReadonlyArray<{ - readonly cursor: any; - readonly node: { - readonly controls: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly id: string; - readonly name: string; - readonly state: ControlState; - readonly stateTransisions: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly createdAt: any; - readonly fromState: ControlState | null | undefined; - readonly id: string; - readonly toState: ControlState; - readonly updatedAt: any; + readonly organizations: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly frameworks: { + readonly edges: ReadonlyArray<{ + readonly cursor: any; + readonly node: { + readonly controls: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly name: string; + readonly state: ControlState; + readonly stateTransisions: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly fromState: ControlState | null | undefined; + readonly id: string; + readonly toState: ControlState; + readonly updatedAt: any; + }; + }>; }; - }>; - }; - readonly tasks: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly createdAt: any; - readonly evidences: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly createdAt: any; - readonly fileUrl: string; - readonly id: string; - readonly state: EvidenceState; - readonly stateTransisions: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly createdAt: any; - readonly fromState: EvidenceState | null | undefined; - readonly id: string; - readonly reason: string | null | undefined; - readonly toState: EvidenceState; - readonly updatedAt: any; + readonly tasks: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly evidences: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly fileUrl: string; + readonly id: string; + readonly state: EvidenceState; + readonly stateTransisions: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly fromState: EvidenceState | null | undefined; + readonly id: string; + readonly reason: string | null | undefined; + readonly toState: EvidenceState; + readonly updatedAt: any; + }; + }>; }; - }>; - }; - readonly updatedAt: any; + readonly updatedAt: any; + }; + }>; }; - }>; - }; - readonly id: string; - readonly name: string; - readonly state: TaskState; - readonly stateTransisions: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly createdAt: any; - readonly fromState: TaskState | null | undefined; - readonly id: string; - readonly reason: string | null | undefined; - readonly toState: TaskState; - readonly updatedAt: any; + readonly id: string; + readonly name: string; + readonly state: TaskState; + readonly stateTransisions: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly fromState: TaskState | null | undefined; + readonly id: string; + readonly reason: string | null | undefined; + readonly toState: TaskState; + readonly updatedAt: any; + }; + }>; }; - }>; - }; - readonly updatedAt: any; + readonly updatedAt: any; + }; + }>; }; - }>; - }; + }; + }>; }; - }>; + readonly description: string; + readonly id: string; + readonly name: string; + }; + }>; + readonly pageInfo: { + readonly endCursor: any | null | undefined; + readonly hasNextPage: boolean; + readonly hasPreviousPage: boolean; + readonly startCursor: any | null | undefined; }; - readonly description: string; - readonly id: string; - readonly name: string; }; - }>; - readonly pageInfo: { - readonly endCursor: any | null | undefined; - readonly hasNextPage: boolean; - readonly hasPreviousPage: boolean; - readonly startCursor: any | null | undefined; + readonly name: string; + readonly peoples: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly additionalEmailAddresses: ReadonlyArray; + readonly createdAt: any; + readonly fullName: string; + readonly id: string; + readonly primaryEmailAddress: string; + readonly updatedAt: any; + }; + }>; + }; + readonly updatedAt: any; + readonly vendors: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly createdAt: any; + readonly id: string; + readonly name: string; + readonly updatedAt: any; + }; + }>; + }; }; - }; - readonly name: string; - readonly peoples: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly additionalEmailAddresses: ReadonlyArray; - readonly createdAt: any; - readonly fullName: string; - readonly id: string; - readonly primaryEmailAddress: string; - readonly updatedAt: any; - }; - }>; - }; - readonly updatedAt: any; - readonly vendors: { - readonly edges: ReadonlyArray<{ - readonly node: { - readonly createdAt: any; - readonly id: string; - readonly name: string; - readonly updatedAt: any; - }; - }>; - }; - }>; + }>; + }; }; }; export type HomePageQuery = { @@ -624,17 +628,39 @@ return { { "alias": null, "args": null, - "concreteType": "Organization", + "concreteType": "OrganizationConnection", "kind": "LinkedField", "name": "organizations", - "plural": true, + "plural": false, "selections": [ - (v1/*: any*/), - (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/), - (v5/*: any*/), - (v10/*: any*/) + { + "alias": null, + "args": null, + "concreteType": "OrganizationEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v10/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } ], "storageKey": null } @@ -663,18 +689,40 @@ return { { "alias": null, "args": null, - "concreteType": "Organization", + "concreteType": "OrganizationConnection", "kind": "LinkedField", "name": "organizations", - "plural": true, + "plural": false, "selections": [ - (v1/*: any*/), - (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/), - (v5/*: any*/), - (v10/*: any*/), - (v0/*: any*/) + { + "alias": null, + "args": null, + "concreteType": "OrganizationEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v10/*: any*/), + (v0/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } ], "storageKey": null } @@ -684,16 +732,16 @@ return { ] }, "params": { - "cacheID": "d40cf8a4787ed129284c566abd99fdaf", + "cacheID": "5a56fefd066703ca0ebac1ef3e9a7e1f", "id": null, "metadata": {}, "name": "HomePageQuery", "operationKind": "query", - "text": "query HomePageQuery {\n viewer {\n id\n organizations {\n name\n createdAt\n updatedAt\n vendors {\n edges {\n node {\n id\n name\n createdAt\n updatedAt\n }\n }\n }\n peoples {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n additionalEmailAddresses\n createdAt\n updatedAt\n }\n }\n }\n frameworks {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n name\n description\n controls {\n edges {\n node {\n id\n name\n state\n stateTransisions {\n edges {\n node {\n id\n toState\n fromState\n createdAt\n updatedAt\n }\n }\n }\n tasks {\n edges {\n node {\n id\n name\n state\n evidences {\n edges {\n node {\n id\n state\n fileUrl\n stateTransisions {\n edges {\n node {\n id\n fromState\n toState\n reason\n createdAt\n updatedAt\n }\n }\n }\n createdAt\n updatedAt\n }\n }\n }\n stateTransisions {\n edges {\n node {\n id\n toState\n fromState\n reason\n createdAt\n updatedAt\n }\n }\n }\n createdAt\n updatedAt\n }\n }\n }\n }\n }\n }\n }\n }\n }\n id\n }\n }\n}\n" + "text": "query HomePageQuery {\n viewer {\n id\n organizations {\n edges {\n node {\n name\n createdAt\n updatedAt\n vendors {\n edges {\n node {\n id\n name\n createdAt\n updatedAt\n }\n }\n }\n peoples {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n additionalEmailAddresses\n createdAt\n updatedAt\n }\n }\n }\n frameworks {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n name\n description\n controls {\n edges {\n node {\n id\n name\n state\n stateTransisions {\n edges {\n node {\n id\n toState\n fromState\n createdAt\n updatedAt\n }\n }\n }\n tasks {\n edges {\n node {\n id\n name\n state\n evidences {\n edges {\n node {\n id\n state\n fileUrl\n stateTransisions {\n edges {\n node {\n id\n fromState\n toState\n reason\n createdAt\n updatedAt\n }\n }\n }\n createdAt\n updatedAt\n }\n }\n }\n stateTransisions {\n edges {\n node {\n id\n toState\n fromState\n reason\n createdAt\n updatedAt\n }\n }\n }\n createdAt\n updatedAt\n }\n }\n }\n }\n }\n }\n }\n }\n }\n id\n }\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "e9da69d4e7095f003eb28bf51e7c399d"; +(node as any).hash = "7a1699535af738f939d954a88c6daa9e"; export default node; diff --git a/apps/console/src/pages/__generated__/SettingsPageQuery.graphql.ts b/apps/console/src/pages/__generated__/SettingsPageQuery.graphql.ts index f70880e86..d83ed5638 100644 --- a/apps/console/src/pages/__generated__/SettingsPageQuery.graphql.ts +++ b/apps/console/src/pages/__generated__/SettingsPageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<9a5ce377f093c4bbbb2375aacc373fb0>> * @lightSyntaxTransform * @nogrep */ @@ -9,14 +9,14 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type SettingsPageQuery$variables = Record; +export type SettingsPageQuery$variables = { + organizationID: string; +}; export type SettingsPageQuery$data = { - readonly viewer: { + readonly organization: { readonly id: string; - readonly organizations: ReadonlyArray<{ - readonly logoUrl: string; - readonly name: string; - }>; + readonly logoUrl?: string; + readonly name?: string; }; }; export type SettingsPageQuery = { @@ -25,56 +25,65 @@ export type SettingsPageQuery = { }; const node: ConcreteRequest = (function(){ -var v0 = { +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "organizationID" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "organizationID" + } +], +v2 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v1 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null -}, -v2 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "logoUrl", - "storageKey": null +v3 = { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "logoUrl", + "storageKey": null + } + ], + "type": "Organization", + "abstractKey": null }; return { "fragment": { - "argumentDefinitions": [], + "argumentDefinitions": (v0/*: any*/), "kind": "Fragment", "metadata": null, "name": "SettingsPageQuery", "selections": [ { - "alias": null, - "args": null, - "concreteType": "User", + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, "kind": "LinkedField", - "name": "viewer", + "name": "node", "plural": false, "selections": [ - (v0/*: any*/), - { - "alias": null, - "args": null, - "concreteType": "Organization", - "kind": "LinkedField", - "name": "organizations", - "plural": true, - "selections": [ - (v1/*: any*/), - (v2/*: any*/) - ], - "storageKey": null - } + (v2/*: any*/), + (v3/*: any*/) ], "storageKey": null } @@ -84,49 +93,43 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": [], + "argumentDefinitions": (v0/*: any*/), "kind": "Operation", "name": "SettingsPageQuery", "selections": [ { - "alias": null, - "args": null, - "concreteType": "User", + "alias": "organization", + "args": (v1/*: any*/), + "concreteType": null, "kind": "LinkedField", - "name": "viewer", + "name": "node", "plural": false, "selections": [ - (v0/*: any*/), { "alias": null, "args": null, - "concreteType": "Organization", - "kind": "LinkedField", - "name": "organizations", - "plural": true, - "selections": [ - (v1/*: any*/), - (v2/*: any*/), - (v0/*: any*/) - ], + "kind": "ScalarField", + "name": "__typename", "storageKey": null - } + }, + (v2/*: any*/), + (v3/*: any*/) ], "storageKey": null } ] }, "params": { - "cacheID": "5a3f5c431e1f886a330d220fd33a33f3", + "cacheID": "1ff42392cdd403c92101dc9c5fb7ceda", "id": null, "metadata": {}, "name": "SettingsPageQuery", "operationKind": "query", - "text": "query SettingsPageQuery {\n viewer {\n id\n organizations {\n name\n logoUrl\n id\n }\n }\n}\n" + "text": "query SettingsPageQuery(\n $organizationID: ID!\n) {\n organization: node(id: $organizationID) {\n __typename\n id\n ... on Organization {\n name\n logoUrl\n }\n }\n}\n" } }; })(); -(node as any).hash = "cef332dd829051516fa47315c3a60d1f"; +(node as any).hash = "60cdb8a35f7e5f58536101243b57e57c"; export default node; diff --git a/pkg/api/console/v1/schema.graphql b/pkg/api/console/v1/schema.graphql index 1e8540684..7b59bc025 100644 --- a/pkg/api/console/v1/schema.graphql +++ b/pkg/api/console/v1/schema.graphql @@ -85,6 +85,16 @@ type PageInfo { endCursor: CursorKey } +type OrganizationConnection { + edges: [OrganizationEdge!]! + pageInfo: PageInfo! +} + +type OrganizationEdge { + cursor: CursorKey! + node: Organization! +} + type Organization implements Node { id: ID! name: String! @@ -342,13 +352,17 @@ type EvidenceStateTransition { updatedAt: Datetime! } -# Authentication types -type User { +type User implements Node { id: ID! fullName: String! email: String! - organizations: [Organization!]! @goField(forceResolver: true) + organizations( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): OrganizationConnection! @goField(forceResolver: true) createdAt: Datetime! updatedAt: Datetime! @@ -371,6 +385,12 @@ type Mutation { createPeople(input: CreatePeopleInput!): CreatePeoplePayload! updatePeople(input: UpdatePeopleInput!): People! deletePeople(input: DeletePeopleInput!): DeletePeoplePayload! + createOrganization( + input: CreateOrganizationInput! + ): CreateOrganizationPayload! + deleteOrganization( + input: DeleteOrganizationInput! + ): DeleteOrganizationPayload! } input CreateVendorInput { @@ -474,3 +494,19 @@ type DeleteVendorPayload { type DeletePeoplePayload { deletedPeopleId: ID! } + +input CreateOrganizationInput { + name: String! +} + +input DeleteOrganizationInput { + organizationId: ID! +} + +type CreateOrganizationPayload { + organizationEdge: OrganizationEdge! +} + +type DeleteOrganizationPayload { + deletedOrganizationId: ID! +} diff --git a/pkg/api/console/v1/schema/schema.go b/pkg/api/console/v1/schema/schema.go index a019cf873..2247d891d 100644 --- a/pkg/api/console/v1/schema/schema.go +++ b/pkg/api/console/v1/schema/schema.go @@ -97,6 +97,10 @@ type ComplexityRoot struct { Node func(childComplexity int) int } + CreateOrganizationPayload struct { + OrganizationEdge func(childComplexity int) int + } + CreatePeoplePayload struct { PeopleEdge func(childComplexity int) int } @@ -105,6 +109,10 @@ type ComplexityRoot struct { VendorEdge func(childComplexity int) int } + DeleteOrganizationPayload struct { + DeletedOrganizationID func(childComplexity int) int + } + DeletePeoplePayload struct { DeletedPeopleID func(childComplexity int) int } @@ -173,12 +181,14 @@ type ComplexityRoot struct { } Mutation struct { - CreatePeople func(childComplexity int, input types.CreatePeopleInput) int - CreateVendor func(childComplexity int, input types.CreateVendorInput) int - DeletePeople func(childComplexity int, input types.DeletePeopleInput) int - DeleteVendor func(childComplexity int, input types.DeleteVendorInput) int - UpdatePeople func(childComplexity int, input types.UpdatePeopleInput) int - UpdateVendor func(childComplexity int, input types.UpdateVendorInput) int + CreateOrganization func(childComplexity int, input types.CreateOrganizationInput) int + CreatePeople func(childComplexity int, input types.CreatePeopleInput) int + CreateVendor func(childComplexity int, input types.CreateVendorInput) int + DeleteOrganization func(childComplexity int, input types.DeleteOrganizationInput) int + DeletePeople func(childComplexity int, input types.DeletePeopleInput) int + DeleteVendor func(childComplexity int, input types.DeleteVendorInput) int + UpdatePeople func(childComplexity int, input types.UpdatePeopleInput) int + UpdateVendor func(childComplexity int, input types.UpdateVendorInput) int } Organization struct { @@ -192,6 +202,16 @@ type ComplexityRoot struct { Vendors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int } + OrganizationConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + } + + OrganizationEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + PageInfo struct { EndCursor func(childComplexity int) int HasNextPage func(childComplexity int) int @@ -275,7 +295,7 @@ type ComplexityRoot struct { Email func(childComplexity int) int FullName func(childComplexity int) int ID func(childComplexity int) int - Organizations func(childComplexity int) int + Organizations func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int UpdatedAt func(childComplexity int) int } @@ -323,6 +343,8 @@ type MutationResolver interface { CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) UpdatePeople(ctx context.Context, input types.UpdatePeopleInput) (*types.People, error) DeletePeople(ctx context.Context, input types.DeletePeopleInput) (*types.DeletePeoplePayload, error) + CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) + DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) } type OrganizationResolver interface { Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error) @@ -338,7 +360,7 @@ type TaskResolver interface { Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.EvidenceConnection, error) } type UserResolver interface { - Organizations(ctx context.Context, obj *types.User) ([]*types.Organization, error) + Organizations(ctx context.Context, obj *types.User, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.OrganizationConnection, error) } type executableSchema struct { @@ -531,6 +553,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.ControlStateTransitionEdge.Node(childComplexity), true + case "CreateOrganizationPayload.organizationEdge": + if e.complexity.CreateOrganizationPayload.OrganizationEdge == nil { + break + } + + return e.complexity.CreateOrganizationPayload.OrganizationEdge(childComplexity), true + case "CreatePeoplePayload.peopleEdge": if e.complexity.CreatePeoplePayload.PeopleEdge == nil { break @@ -545,6 +574,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CreateVendorPayload.VendorEdge(childComplexity), true + case "DeleteOrganizationPayload.deletedOrganizationId": + if e.complexity.DeleteOrganizationPayload.DeletedOrganizationID == nil { + break + } + + return e.complexity.DeleteOrganizationPayload.DeletedOrganizationID(childComplexity), true + case "DeletePeoplePayload.deletedPeopleId": if e.complexity.DeletePeoplePayload.DeletedPeopleID == nil { break @@ -793,6 +829,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.FrameworkEdge.Node(childComplexity), true + case "Mutation.createOrganization": + if e.complexity.Mutation.CreateOrganization == nil { + break + } + + args, err := ec.field_Mutation_createOrganization_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.CreateOrganization(childComplexity, args["input"].(types.CreateOrganizationInput)), true + case "Mutation.createPeople": if e.complexity.Mutation.CreatePeople == nil { break @@ -817,6 +865,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.CreateVendor(childComplexity, args["input"].(types.CreateVendorInput)), true + case "Mutation.deleteOrganization": + if e.complexity.Mutation.DeleteOrganization == nil { + break + } + + args, err := ec.field_Mutation_deleteOrganization_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.DeleteOrganization(childComplexity, args["input"].(types.DeleteOrganizationInput)), true + case "Mutation.deletePeople": if e.complexity.Mutation.DeletePeople == nil { break @@ -936,6 +996,34 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Organization.Vendors(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey)), true + case "OrganizationConnection.edges": + if e.complexity.OrganizationConnection.Edges == nil { + break + } + + return e.complexity.OrganizationConnection.Edges(childComplexity), true + + case "OrganizationConnection.pageInfo": + if e.complexity.OrganizationConnection.PageInfo == nil { + break + } + + return e.complexity.OrganizationConnection.PageInfo(childComplexity), true + + case "OrganizationEdge.cursor": + if e.complexity.OrganizationEdge.Cursor == nil { + break + } + + return e.complexity.OrganizationEdge.Cursor(childComplexity), true + + case "OrganizationEdge.node": + if e.complexity.OrganizationEdge.Node == nil { + break + } + + return e.complexity.OrganizationEdge.Node(childComplexity), true + case "PageInfo.endCursor": if e.complexity.PageInfo.EndCursor == nil { break @@ -1278,7 +1366,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - return e.complexity.User.Organizations(childComplexity), true + args, err := ec.field_User_organizations_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.User.Organizations(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey)), true case "User.updatedAt": if e.complexity.User.UpdatedAt == nil { @@ -1414,8 +1507,10 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { opCtx := graphql.GetOperationContext(ctx) ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( + ec.unmarshalInputCreateOrganizationInput, ec.unmarshalInputCreatePeopleInput, ec.unmarshalInputCreateVendorInput, + ec.unmarshalInputDeleteOrganizationInput, ec.unmarshalInputDeletePeopleInput, ec.unmarshalInputDeleteVendorInput, ec.unmarshalInputUpdatePeopleInput, @@ -1604,6 +1699,16 @@ type PageInfo { endCursor: CursorKey } +type OrganizationConnection { + edges: [OrganizationEdge!]! + pageInfo: PageInfo! +} + +type OrganizationEdge { + cursor: CursorKey! + node: Organization! +} + type Organization implements Node { id: ID! name: String! @@ -1861,13 +1966,17 @@ type EvidenceStateTransition { updatedAt: Datetime! } -# Authentication types -type User { +type User implements Node { id: ID! fullName: String! email: String! - organizations: [Organization!]! @goField(forceResolver: true) + organizations( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): OrganizationConnection! @goField(forceResolver: true) createdAt: Datetime! updatedAt: Datetime! @@ -1890,6 +1999,12 @@ type Mutation { createPeople(input: CreatePeopleInput!): CreatePeoplePayload! updatePeople(input: UpdatePeopleInput!): People! deletePeople(input: DeletePeopleInput!): DeletePeoplePayload! + createOrganization( + input: CreateOrganizationInput! + ): CreateOrganizationPayload! + deleteOrganization( + input: DeleteOrganizationInput! + ): DeleteOrganizationPayload! } input CreateVendorInput { @@ -1993,6 +2108,22 @@ type DeleteVendorPayload { type DeletePeoplePayload { deletedPeopleId: ID! } + +input CreateOrganizationInput { + name: String! +} + +input DeleteOrganizationInput { + organizationId: ID! +} + +type CreateOrganizationPayload { + organizationEdge: OrganizationEdge! +} + +type DeleteOrganizationPayload { + deletedOrganizationId: ID! +} `, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -2309,6 +2440,29 @@ func (ec *executionContext) field_Framework_controls_argsBefore( return zeroVal, nil } +func (ec *executionContext) field_Mutation_createOrganization_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_createOrganization_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_createOrganization_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.CreateOrganizationInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNCreateOrganizationInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateOrganizationInput(ctx, tmp) + } + + var zeroVal types.CreateOrganizationInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_createPeople_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -2355,6 +2509,29 @@ func (ec *executionContext) field_Mutation_createVendor_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_deleteOrganization_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_deleteOrganization_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_deleteOrganization_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.DeleteOrganizationInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNDeleteOrganizationInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationInput(ctx, tmp) + } + + var zeroVal types.DeleteOrganizationInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_deletePeople_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -2878,6 +3055,83 @@ func (ec *executionContext) field_Task_stateTransisions_argsBefore( return zeroVal, nil } +func (ec *executionContext) field_User_organizations_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_User_organizations_argsFirst(ctx, rawArgs) + if err != nil { + return nil, err + } + args["first"] = arg0 + arg1, err := ec.field_User_organizations_argsAfter(ctx, rawArgs) + if err != nil { + return nil, err + } + args["after"] = arg1 + arg2, err := ec.field_User_organizations_argsLast(ctx, rawArgs) + if err != nil { + return nil, err + } + args["last"] = arg2 + arg3, err := ec.field_User_organizations_argsBefore(ctx, rawArgs) + if err != nil { + return nil, err + } + args["before"] = arg3 + return args, nil +} +func (ec *executionContext) field_User_organizations_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_User_organizations_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_User_organizations_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_User_organizations_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___Type_enumValues_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -3888,6 +4142,50 @@ func (ec *executionContext) fieldContext_ControlStateTransitionEdge_node(_ conte return fc, nil } +func (ec *executionContext) _CreateOrganizationPayload_organizationEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreateOrganizationPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CreateOrganizationPayload_organizationEdge(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.OrganizationEdge, 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.OrganizationEdge) + fc.Result = res + return ec.marshalNOrganizationEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationEdge(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CreateOrganizationPayload_organizationEdge(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CreateOrganizationPayload", + 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_OrganizationEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_OrganizationEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type OrganizationEdge", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _CreatePeoplePayload_peopleEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreatePeoplePayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_CreatePeoplePayload_peopleEdge(ctx, field) if err != nil { @@ -3976,6 +4274,44 @@ func (ec *executionContext) fieldContext_CreateVendorPayload_vendorEdge(_ contex return fc, nil } +func (ec *executionContext) _DeleteOrganizationPayload_deletedOrganizationId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteOrganizationPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DeleteOrganizationPayload_deletedOrganizationId(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.DeletedOrganizationID, 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_DeleteOrganizationPayload_deletedOrganizationId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DeleteOrganizationPayload", + 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) _DeletePeoplePayload_deletedPeopleId(ctx context.Context, field graphql.CollectedField, obj *types.DeletePeoplePayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_DeletePeoplePayload_deletedPeopleId(ctx, field) if err != nil { @@ -5698,6 +6034,100 @@ func (ec *executionContext) fieldContext_Mutation_deletePeople(ctx context.Conte return fc, nil } +func (ec *executionContext) _Mutation_createOrganization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createOrganization(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().CreateOrganization(rctx, fc.Args["input"].(types.CreateOrganizationInput)) + }) + 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.CreateOrganizationPayload) + fc.Result = res + return ec.marshalNCreateOrganizationPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateOrganizationPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_createOrganization(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 "organizationEdge": + return ec.fieldContext_CreateOrganizationPayload_organizationEdge(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CreateOrganizationPayload", field.Name) + }, + } + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_createOrganization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_deleteOrganization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteOrganization(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().DeleteOrganization(rctx, fc.Args["input"].(types.DeleteOrganizationInput)) + }) + 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.DeleteOrganizationPayload) + fc.Result = res + return ec.marshalNDeleteOrganizationPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_deleteOrganization(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 "deletedOrganizationId": + return ec.fieldContext_DeleteOrganizationPayload_deletedOrganizationId(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DeleteOrganizationPayload", field.Name) + }, + } + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_deleteOrganization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Organization_id(ctx context.Context, field graphql.CollectedField, obj *types.Organization) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Organization_id(ctx, field) if err != nil { @@ -6035,6 +6465,192 @@ func (ec *executionContext) fieldContext_Organization_updatedAt(_ context.Contex return fc, nil } +func (ec *executionContext) _OrganizationConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.OrganizationConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationConnection_edges(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.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.OrganizationEdge) + fc.Result = res + return ec.marshalNOrganizationEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationEdgeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationConnection_edges(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationConnection", + 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_OrganizationEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_OrganizationEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type OrganizationEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *types.OrganizationConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationConnection_pageInfo(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.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ᚋapiᚋconsoleᚋv1ᚋtypesᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationConnection", + 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) _OrganizationEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *types.OrganizationEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationEdge_cursor(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.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_OrganizationEdge_cursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationEdge", + 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) _OrganizationEdge_node(ctx context.Context, field graphql.CollectedField, obj *types.OrganizationEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationEdge_node(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.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.Organization) + fc.Result = res + return ec.marshalNOrganization2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganization(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationEdge_node(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationEdge", + 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_Organization_id(ctx, field) + case "name": + return ec.fieldContext_Organization_name(ctx, field) + case "logoUrl": + return ec.fieldContext_Organization_logoUrl(ctx, field) + case "frameworks": + return ec.fieldContext_Organization_frameworks(ctx, field) + case "vendors": + return ec.fieldContext_Organization_vendors(ctx, field) + case "peoples": + return ec.fieldContext_Organization_peoples(ctx, field) + case "createdAt": + return ec.fieldContext_Organization_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_Organization_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _PageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *types.PageInfo) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PageInfo_hasNextPage(ctx, field) if err != nil { @@ -7991,7 +8607,7 @@ func (ec *executionContext) _User_organizations(ctx context.Context, field graph ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.User().Organizations(rctx, obj) + return ec.resolvers.User().Organizations(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey)) }) if err != nil { ec.Error(ctx, err) @@ -8003,12 +8619,12 @@ func (ec *executionContext) _User_organizations(ctx context.Context, field graph } return graphql.Null } - res := resTmp.([]*types.Organization) + res := resTmp.(*types.OrganizationConnection) fc.Result = res - return ec.marshalNOrganization2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationᚄ(ctx, field.Selections, res) + return ec.marshalNOrganizationConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationConnection(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_User_organizations(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_User_organizations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, @@ -8016,26 +8632,19 @@ func (ec *executionContext) fieldContext_User_organizations(_ context.Context, f IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "id": - return ec.fieldContext_Organization_id(ctx, field) - case "name": - return ec.fieldContext_Organization_name(ctx, field) - case "logoUrl": - return ec.fieldContext_Organization_logoUrl(ctx, field) - case "frameworks": - return ec.fieldContext_Organization_frameworks(ctx, field) - case "vendors": - return ec.fieldContext_Organization_vendors(ctx, field) - case "peoples": - return ec.fieldContext_Organization_peoples(ctx, field) - case "createdAt": - return ec.fieldContext_Organization_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_Organization_updatedAt(ctx, field) + case "edges": + return ec.fieldContext_OrganizationConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_OrganizationConnection_pageInfo(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name) + return nil, fmt.Errorf("no field named %q was found under type OrganizationConnection", field.Name) }, } + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_User_organizations_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } @@ -10344,6 +10953,33 @@ func (ec *executionContext) fieldContext___Type_specifiedByURL(_ context.Context // region **************************** input.gotpl ***************************** +func (ec *executionContext) unmarshalInputCreateOrganizationInput(ctx context.Context, obj any) (types.CreateOrganizationInput, error) { + var it types.CreateOrganizationInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"name"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "name": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Name = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputCreatePeopleInput(ctx context.Context, obj any) (types.CreatePeopleInput, error) { var it types.CreatePeopleInput asMap := map[string]any{} @@ -10489,6 +11125,33 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, return it, nil } +func (ec *executionContext) unmarshalInputDeleteOrganizationInput(ctx context.Context, obj any) (types.DeleteOrganizationInput, error) { + var it types.DeleteOrganizationInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"organizationId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "organizationId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.OrganizationID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDeletePeopleInput(ctx context.Context, obj any) (types.DeletePeopleInput, error) { var it types.DeletePeopleInput asMap := map[string]any{} @@ -10759,6 +11422,13 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj return graphql.Null } return ec._Evidence(ctx, sel, obj) + case types.User: + return ec._User(ctx, sel, &obj) + case *types.User: + if obj == nil { + return graphql.Null + } + return ec._User(ctx, sel, obj) default: panic(fmt.Errorf("unexpected type %T", obj)) } @@ -11133,6 +11803,45 @@ func (ec *executionContext) _ControlStateTransitionEdge(ctx context.Context, sel return out } +var createOrganizationPayloadImplementors = []string{"CreateOrganizationPayload"} + +func (ec *executionContext) _CreateOrganizationPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateOrganizationPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, createOrganizationPayloadImplementors) + + 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("CreateOrganizationPayload") + case "organizationEdge": + out.Values[i] = ec._CreateOrganizationPayload_organizationEdge(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 createPeoplePayloadImplementors = []string{"CreatePeoplePayload"} func (ec *executionContext) _CreatePeoplePayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreatePeoplePayload) graphql.Marshaler { @@ -11211,6 +11920,45 @@ func (ec *executionContext) _CreateVendorPayload(ctx context.Context, sel ast.Se return out } +var deleteOrganizationPayloadImplementors = []string{"DeleteOrganizationPayload"} + +func (ec *executionContext) _DeleteOrganizationPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteOrganizationPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, deleteOrganizationPayloadImplementors) + + 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("DeleteOrganizationPayload") + case "deletedOrganizationId": + out.Values[i] = ec._DeleteOrganizationPayload_deletedOrganizationId(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 deletePeoplePayloadImplementors = []string{"DeletePeoplePayload"} func (ec *executionContext) _DeletePeoplePayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeletePeoplePayload) graphql.Marshaler { @@ -11862,6 +12610,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "createOrganization": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_createOrganization(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deleteOrganization": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteOrganization(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -12037,6 +12799,94 @@ func (ec *executionContext) _Organization(ctx context.Context, sel ast.Selection return out } +var organizationConnectionImplementors = []string{"OrganizationConnection"} + +func (ec *executionContext) _OrganizationConnection(ctx context.Context, sel ast.SelectionSet, obj *types.OrganizationConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationConnectionImplementors) + + 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("OrganizationConnection") + case "edges": + out.Values[i] = ec._OrganizationConnection_edges(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "pageInfo": + out.Values[i] = ec._OrganizationConnection_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 organizationEdgeImplementors = []string{"OrganizationEdge"} + +func (ec *executionContext) _OrganizationEdge(ctx context.Context, sel ast.SelectionSet, obj *types.OrganizationEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationEdgeImplementors) + + 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("OrganizationEdge") + case "cursor": + out.Values[i] = ec._OrganizationEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "node": + out.Values[i] = ec._OrganizationEdge_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 pageInfoImplementors = []string{"PageInfo"} func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet, obj *types.PageInfo) graphql.Marshaler { @@ -12735,7 +13585,7 @@ func (ec *executionContext) _TaskStateTransitionEdge(ctx context.Context, sel as return out } -var userImplementors = []string{"User"} +var userImplementors = []string{"User", "Node"} func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *types.User) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) @@ -13516,6 +14366,25 @@ func (ec *executionContext) marshalNControlStateTransitionEdge2ᚖgithubᚗcom return ec._ControlStateTransitionEdge(ctx, sel, v) } +func (ec *executionContext) unmarshalNCreateOrganizationInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateOrganizationInput(ctx context.Context, v any) (types.CreateOrganizationInput, error) { + res, err := ec.unmarshalInputCreateOrganizationInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNCreateOrganizationPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateOrganizationPayload(ctx context.Context, sel ast.SelectionSet, v types.CreateOrganizationPayload) graphql.Marshaler { + return ec._CreateOrganizationPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCreateOrganizationPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateOrganizationPayload(ctx context.Context, sel ast.SelectionSet, v *types.CreateOrganizationPayload) 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._CreateOrganizationPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNCreatePeopleInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐCreatePeopleInput(ctx context.Context, v any) (types.CreatePeopleInput, error) { res, err := ec.unmarshalInputCreatePeopleInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -13584,6 +14453,25 @@ func (ec *executionContext) marshalNDatetime2timeᚐTime(ctx context.Context, se return res } +func (ec *executionContext) unmarshalNDeleteOrganizationInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationInput(ctx context.Context, v any) (types.DeleteOrganizationInput, error) { + res, err := ec.unmarshalInputDeleteOrganizationInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNDeleteOrganizationPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationPayload(ctx context.Context, sel ast.SelectionSet, v types.DeleteOrganizationPayload) graphql.Marshaler { + return ec._DeleteOrganizationPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNDeleteOrganizationPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteOrganizationPayload) 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._DeleteOrganizationPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNDeletePeopleInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐDeletePeopleInput(ctx context.Context, v any) (types.DeletePeopleInput, error) { res, err := ec.unmarshalInputDeletePeopleInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -13907,7 +14795,31 @@ func (ec *executionContext) marshalNNode2githubᚗcomᚋgetproboᚋproboᚋpkg return ec._Node(ctx, sel, v) } -func (ec *executionContext) marshalNOrganization2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.Organization) graphql.Marshaler { +func (ec *executionContext) marshalNOrganization2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganization(ctx context.Context, sel ast.SelectionSet, v *types.Organization) 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._Organization(ctx, sel, v) +} + +func (ec *executionContext) marshalNOrganizationConnection2githubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationConnection(ctx context.Context, sel ast.SelectionSet, v types.OrganizationConnection) graphql.Marshaler { + return ec._OrganizationConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNOrganizationConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationConnection(ctx context.Context, sel ast.SelectionSet, v *types.OrganizationConnection) 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._OrganizationConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNOrganizationEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.OrganizationEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -13925,7 +14837,7 @@ func (ec *executionContext) marshalNOrganization2ᚕᚖgithubᚗcomᚋgetprobo if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNOrganization2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganization(ctx, sel, v[i]) + ret[i] = ec.marshalNOrganizationEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationEdge(ctx, sel, v[i]) } if isLen1 { f(i) @@ -13945,14 +14857,14 @@ func (ec *executionContext) marshalNOrganization2ᚕᚖgithubᚗcomᚋgetprobo return ret } -func (ec *executionContext) marshalNOrganization2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganization(ctx context.Context, sel ast.SelectionSet, v *types.Organization) graphql.Marshaler { +func (ec *executionContext) marshalNOrganizationEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganizationEdge(ctx context.Context, sel ast.SelectionSet, v *types.OrganizationEdge) 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._Organization(ctx, sel, v) + return ec._OrganizationEdge(ctx, sel, v) } func (ec *executionContext) marshalNPageInfo2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋapiᚋconsoleᚋv1ᚋtypesᚐPageInfo(ctx context.Context, sel ast.SelectionSet, v *types.PageInfo) graphql.Marshaler { diff --git a/pkg/api/console/v1/types/organization.go b/pkg/api/console/v1/types/organization.go index 2afff1dff..ec4094f7e 100644 --- a/pkg/api/console/v1/types/organization.go +++ b/pkg/api/console/v1/types/organization.go @@ -27,3 +27,9 @@ func NewOrganization(o *coredata.Organization) *Organization { UpdatedAt: o.UpdatedAt, } } + +func NewOrganizationEdge(o *coredata.Organization) *OrganizationEdge { + return &OrganizationEdge{ + Node: NewOrganization(o), + } +} diff --git a/pkg/api/console/v1/types/types.go b/pkg/api/console/v1/types/types.go index 103f4d293..22ca2b0c6 100644 --- a/pkg/api/console/v1/types/types.go +++ b/pkg/api/console/v1/types/types.go @@ -59,6 +59,14 @@ type ControlStateTransitionEdge struct { Node *ControlStateTransition `json:"node"` } +type CreateOrganizationInput struct { + Name string `json:"name"` +} + +type CreateOrganizationPayload struct { + OrganizationEdge *OrganizationEdge `json:"organizationEdge"` +} + type CreatePeopleInput struct { OrganizationID gid.GID `json:"organizationId"` FullName string `json:"fullName"` @@ -88,6 +96,14 @@ type CreateVendorPayload struct { VendorEdge *VendorEdge `json:"vendorEdge"` } +type DeleteOrganizationInput struct { + OrganizationID gid.GID `json:"organizationId"` +} + +type DeleteOrganizationPayload struct { + DeletedOrganizationID gid.GID `json:"deletedOrganizationId"` +} + type DeletePeopleInput struct { PeopleID gid.GID `json:"peopleId"` } @@ -186,6 +202,16 @@ type Organization struct { func (Organization) IsNode() {} func (this Organization) GetID() gid.GID { return this.ID } +type OrganizationConnection struct { + Edges []*OrganizationEdge `json:"edges"` + PageInfo *PageInfo `json:"pageInfo"` +} + +type OrganizationEdge struct { + Cursor page.CursorKey `json:"cursor"` + Node *Organization `json:"node"` +} + type PageInfo struct { HasNextPage bool `json:"hasNextPage"` HasPreviousPage bool `json:"hasPreviousPage"` @@ -292,14 +318,17 @@ type UpdateVendorInput struct { } type User struct { - ID gid.GID `json:"id"` - FullName string `json:"fullName"` - Email string `json:"email"` - Organizations []*Organization `json:"organizations"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID gid.GID `json:"id"` + FullName string `json:"fullName"` + Email string `json:"email"` + Organizations *OrganizationConnection `json:"organizations"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } +func (User) IsNode() {} +func (this User) GetID() gid.GID { return this.ID } + type Vendor struct { ID gid.GID `json:"id"` Name string `json:"name"` diff --git a/pkg/api/console/v1/v1_resolver.go b/pkg/api/console/v1/v1_resolver.go index 1129602e4..9cc77ca5d 100644 --- a/pkg/api/console/v1/v1_resolver.go +++ b/pkg/api/console/v1/v1_resolver.go @@ -169,6 +169,30 @@ func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeleteP }, nil } +// CreateOrganization is the resolver for the createOrganization field. +func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) { + organization, err := r.proboSvc.CreateOrganization(ctx, probo.CreateOrganizationRequest{ + Name: input.Name, + }) + if err != nil { + return nil, fmt.Errorf("cannot create organization: %w", err) + } + + err = r.usrmgrSvc.AddUserToOrganization(ctx, UserFromContext(ctx).ID, organization.ID) + if err != nil { + return nil, fmt.Errorf("cannot add user to organization: %w", err) + } + + return &types.CreateOrganizationPayload{ + OrganizationEdge: types.NewOrganizationEdge(organization), + }, nil +} + +// DeleteOrganization is the resolver for the deleteOrganization field. +func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) { + panic(fmt.Errorf("not implemented: DeleteOrganization - deleteOrganization")) +} + // Frameworks is the resolver for the frameworks field. func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error) { cursor := types.NewCursor(first, after, last, before) @@ -300,29 +324,35 @@ func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *in } // Organizations is the resolver for the organizations field. -func (r *userResolver) Organizations(ctx context.Context, obj *types.User) ([]*types.Organization, error) { +func (r *userResolver) Organizations(ctx context.Context, obj *types.User, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.OrganizationConnection, error) { // Get the user's organization IDs organizationIDs, err := r.usrmgrSvc.GetUserOrganizations(ctx, obj.ID) if err != nil { return nil, fmt.Errorf("failed to get user organizations: %w", err) } - // If the user doesn't have any organizations, return an empty slice + // If the user doesn't have any organizations, return an empty connection if len(organizationIDs) == 0 { - return []*types.Organization{}, nil + return &types.OrganizationConnection{ + Edges: []*types.OrganizationEdge{}, + PageInfo: &types.PageInfo{}, + }, nil } // Get the organization details for each organization ID - var organizations []*types.Organization + var edges []*types.OrganizationEdge for _, organizationID := range organizationIDs { organization, err := r.proboSvc.GetOrganization(ctx, organizationID) if err != nil { return nil, fmt.Errorf("failed to get organization details: %w", err) } - organizations = append(organizations, types.NewOrganization(organization)) + edges = append(edges, types.NewOrganizationEdge(organization)) } - return organizations, nil + return &types.OrganizationConnection{ + Edges: edges, + PageInfo: &types.PageInfo{}, + }, nil } // Control returns schema.ControlResolver implementation. diff --git a/pkg/probo/coredata/organization.go b/pkg/probo/coredata/organization.go index b783696f2..65661544a 100644 --- a/pkg/probo/coredata/organization.go +++ b/pkg/probo/coredata/organization.go @@ -29,7 +29,7 @@ type ( Organization struct { ID gid.GID Name string - LogoURL string + LogoURL string CreatedAt time.Time UpdatedAt time.Time } @@ -82,3 +82,33 @@ LIMIT 1; return nil } + +func (o *Organization) Insert( + ctx context.Context, + conn pg.Conn, +) error { + q := ` +INSERT INTO organizations ( + id, + name, + logo_url, + created_at, + updated_at +) VALUES (@id, @name, @logo_url, @created_at, @updated_at) +` + + args := pgx.NamedArgs{ + "id": o.ID, + "name": o.Name, + "logo_url": o.LogoURL, + "created_at": o.CreatedAt, + "updated_at": o.UpdatedAt, + } + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/probo/create_organization.go b/pkg/probo/create_organization.go new file mode 100644 index 000000000..ae062571a --- /dev/null +++ b/pkg/probo/create_organization.go @@ -0,0 +1,66 @@ +// 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/gid" + "github.com/getprobo/probo/pkg/probo/coredata" + "go.gearno.de/kit/pg" +) + +type ( + CreateOrganizationRequest struct { + Name string + } +) + +func (s Service) CreateOrganization( + ctx context.Context, + req CreateOrganizationRequest, +) (*coredata.Organization, error) { + now := time.Now() + organizationID, err := gid.NewGID(coredata.OrganizationEntityType) + if err != nil { + return nil, fmt.Errorf("cannot create organization global id: %w", err) + } + + organization := &coredata.Organization{ + ID: organizationID, + Name: req.Name, + CreatedAt: now, + UpdatedAt: now, + } + + err = s.pg.WithConn( + ctx, + func(conn pg.Conn) error { + if err := organization.Insert(ctx, conn); err != nil { + return fmt.Errorf("cannot insert control: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return organization, nil +}