- {[1, 2, 3].map((i) => (
-
-
-
-
-
-
- ))}
+
+
);
}
export function ControlPage() {
- const location = useLocation();
-
return (
-
}>
-
-
-
+
}>
+
);
}
diff --git a/apps/console/src/pages/organizations/frameworks/controls/EditControlPage.tsx b/apps/console/src/pages/organizations/frameworks/controls/EditControlPage.tsx
new file mode 100644
index 000000000..1b3a524b1
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/EditControlPage.tsx
@@ -0,0 +1,14 @@
+import { Loader2 } from "lucide-react";
+import EditControlView from "./EditControlView";
+
+export function EditControlViewSkeleton() {
+ return (
+
+
+
+ );
+}
+
+export function EditControlPage() {
+ return
;
+}
diff --git a/apps/console/src/pages/organizations/frameworks/controls/EditControlView.tsx b/apps/console/src/pages/organizations/frameworks/controls/EditControlView.tsx
new file mode 100644
index 000000000..8ced76928
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/EditControlView.tsx
@@ -0,0 +1,201 @@
+import { Suspense, useEffect, useState } from "react";
+import {
+ graphql,
+ PreloadedQuery,
+ useMutation,
+ usePreloadedQuery,
+ useQueryLoader,
+} from "react-relay";
+import { useParams, useNavigate } from "react-router";
+import { useToast } from "@/hooks/use-toast";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { Loader2 } from "lucide-react";
+import { EditControlViewSkeleton } from "./EditControlPage";
+import { EditControlViewQuery } from "./__generated__/EditControlViewQuery.graphql";
+
+const editControlViewQuery = graphql`
+ query EditControlViewQuery($controlId: ID!) {
+ control: node(id: $controlId) {
+ ... on Control {
+ id
+ name
+ description
+ sectionTitle
+ }
+ }
+ }
+`;
+
+const updateControlMutation = graphql`
+ mutation EditControlViewUpdateControlMutation($input: UpdateControlInput!) {
+ updateControl(input: $input) {
+ control {
+ id
+ name
+ description
+ sectionTitle
+ }
+ }
+ }
+`;
+
+function EditControlViewContent({
+ queryRef,
+}: {
+ queryRef: PreloadedQuery
;
+}) {
+ const { organizationId, frameworkId } = useParams<{
+ organizationId: string;
+ frameworkId: string;
+ }>();
+ const navigate = useNavigate();
+ const { toast } = useToast();
+ const data = usePreloadedQuery(editControlViewQuery, queryRef);
+ const [isLoading, setIsLoading] = useState(false);
+ const [commitUpdateControl] = useMutation(updateControlMutation);
+
+ if (!data.control) {
+ return ;
+ }
+
+ const [formData, setFormData] = useState({
+ name: data.control.name || "",
+ description: data.control.description || "",
+ sectionTitle: data.control.sectionTitle || "",
+ });
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsLoading(true);
+
+ commitUpdateControl({
+ variables: {
+ input: {
+ id: data.control.id,
+ name: formData.name,
+ description: formData.description,
+ sectionTitle: formData.sectionTitle,
+ },
+ },
+ onCompleted: (_, errors) => {
+ setIsLoading(false);
+
+ if (errors) {
+ console.error("Error updating control:", errors);
+ toast({
+ title: "Error",
+ description: "Failed to update control. Please try again.",
+ variant: "destructive",
+ });
+ return;
+ }
+
+ toast({
+ title: "Success",
+ description: "Control updated successfully.",
+ });
+
+ navigate(`/organizations/${organizationId}/frameworks/${frameworkId}/controls/${data.control.id}`);
+ },
+ onError: (error) => {
+ setIsLoading(false);
+ console.error("Error updating control:", error);
+ toast({
+ title: "Error",
+ description: "Failed to update control. Please try again.",
+ variant: "destructive",
+ });
+ },
+ });
+ };
+
+ return (
+
+ );
+}
+
+export default function EditControlView({ controlId }: { controlId?: string }) {
+ const { controlId: controlIdParam } = useParams();
+ const [queryRef, loadQuery] =
+ useQueryLoader(editControlViewQuery);
+
+ useEffect(() => {
+ loadQuery({ controlId: (controlId ?? controlIdParam)! });
+ }, [loadQuery, controlId, controlIdParam]);
+
+ if (!queryRef) {
+ return ;
+ }
+
+ return (
+ }>
+
+
+ );
+}
diff --git a/apps/console/src/pages/organizations/frameworks/controls/NewControlPage.tsx b/apps/console/src/pages/organizations/frameworks/controls/NewControlPage.tsx
new file mode 100644
index 000000000..c68493741
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/NewControlPage.tsx
@@ -0,0 +1,14 @@
+import { Loader2 } from "lucide-react";
+import NewControlView from "./NewControlView";
+
+export function NewControlViewSkeleton() {
+ return (
+
+
+
+ );
+}
+
+export function NewControlPage() {
+ return ;
+}
diff --git a/apps/console/src/pages/organizations/frameworks/controls/NewControlView.tsx b/apps/console/src/pages/organizations/frameworks/controls/NewControlView.tsx
new file mode 100644
index 000000000..4655826c9
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/NewControlView.tsx
@@ -0,0 +1,202 @@
+import { useState } from "react";
+import { graphql, useMutation } from "react-relay";
+import { generateUniqueClientID } from "relay-runtime";
+import { useNavigate, useParams } from "react-router";
+import { useToast } from "@/hooks/use-toast";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { Loader2, AlertCircle } from "lucide-react";
+import { NewControlViewCreateControlMutation } from "./__generated__/NewControlViewCreateControlMutation.graphql";
+
+const createControlMutation = graphql`
+ mutation NewControlViewCreateControlMutation($input: CreateControlInput!) {
+ createControl(input: $input) {
+ controlEdge {
+ node {
+ id
+ name
+ description
+ sectionTitle
+ }
+ }
+ }
+ }
+`;
+
+export default function NewControlView() {
+ const { organizationId, frameworkId } = useParams<{
+ organizationId: string;
+ frameworkId: string;
+ }>();
+ const navigate = useNavigate();
+ const { toast } = useToast();
+ const [isLoading, setIsLoading] = useState(false);
+ const [commitCreateControl] = useMutation(
+ createControlMutation
+ );
+
+ // Validate required URL parameters
+ if (!organizationId || !frameworkId) {
+ return (
+
+
+
+
+
Missing required URL parameters. Please check the URL and try again.
+
+
+
+
+
+
+ );
+ }
+
+ const [formData, setFormData] = useState({
+ name: "",
+ description: "",
+ sectionTitle: "",
+ });
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsLoading(true);
+
+ commitCreateControl({
+ variables: {
+ input: {
+ frameworkId,
+ name: formData.name,
+ description: formData.description,
+ sectionTitle: formData.sectionTitle,
+ },
+ },
+ onCompleted: (response, errors) => {
+ setIsLoading(false);
+
+ if (errors) {
+ console.error("Error creating control:", errors);
+ toast({
+ title: "Error",
+ description: "Failed to create control. Please try again.",
+ variant: "destructive",
+ });
+ return;
+ }
+
+ const controlId = response.createControl.controlEdge.node.id;
+ toast({
+ title: "Success",
+ description: "Control created successfully.",
+ });
+
+ navigate(
+ `/organizations/${organizationId}/frameworks/${frameworkId}/controls/${controlId}?t=${Date.now()}`,
+ { replace: true }
+ );
+ },
+ onError: (error) => {
+ setIsLoading(false);
+ console.error("Error creating control:", error);
+ toast({
+ title: "Error",
+ description: "Failed to create control. Please try again.",
+ variant: "destructive",
+ });
+ },
+ updater: (store) => {
+ const payload = store.getRootField('createControl');
+ const newControl = payload.getLinkedRecord('controlEdge').getLinkedRecord('node');
+
+ const framework = store.get(frameworkId);
+ if (framework) {
+ const controls = framework.getLinkedRecord('controls');
+ if (controls) {
+ const edges = controls.getLinkedRecords('edges') || [];
+ const newEdgeId = generateUniqueClientID();
+ const newEdge = store.create(newEdgeId, 'ControlEdge');
+ newEdge.setLinkedRecord(newControl, 'node');
+ controls.setLinkedRecords([newEdge, ...edges], 'edges');
+ }
+ }
+ }
+ });
+ };
+
+ return (
+
+
+
Create Control
+
+
+
+
+ );
+}
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlDeleteMutation.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlDeleteMutation.graphql.ts
new file mode 100644
index 000000000..49e3ead2f
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlDeleteMutation.graphql.ts
@@ -0,0 +1,132 @@
+/**
+ * @generated SignedSource<<210832f4f838924747194254c58b57a4>>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+
+import { ConcreteRequest } from 'relay-runtime';
+export type DeleteControlInput = {
+ controlId: string;
+};
+export type ControlDeleteMutation$variables = {
+ connections: ReadonlyArray;
+ input: DeleteControlInput;
+};
+export type ControlDeleteMutation$data = {
+ readonly deleteControl: {
+ readonly deletedControlId: string;
+ };
+};
+export type ControlDeleteMutation = {
+ response: ControlDeleteMutation$data;
+ variables: ControlDeleteMutation$variables;
+};
+
+const node: ConcreteRequest = (function(){
+var v0 = {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "connections"
+},
+v1 = {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "input"
+},
+v2 = [
+ {
+ "kind": "Variable",
+ "name": "input",
+ "variableName": "input"
+ }
+],
+v3 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "deletedControlId",
+ "storageKey": null
+};
+return {
+ "fragment": {
+ "argumentDefinitions": [
+ (v0/*: any*/),
+ (v1/*: any*/)
+ ],
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "ControlDeleteMutation",
+ "selections": [
+ {
+ "alias": null,
+ "args": (v2/*: any*/),
+ "concreteType": "DeleteControlPayload",
+ "kind": "LinkedField",
+ "name": "deleteControl",
+ "plural": false,
+ "selections": [
+ (v3/*: any*/)
+ ],
+ "storageKey": null
+ }
+ ],
+ "type": "Mutation",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": [
+ (v1/*: any*/),
+ (v0/*: any*/)
+ ],
+ "kind": "Operation",
+ "name": "ControlDeleteMutation",
+ "selections": [
+ {
+ "alias": null,
+ "args": (v2/*: any*/),
+ "concreteType": "DeleteControlPayload",
+ "kind": "LinkedField",
+ "name": "deleteControl",
+ "plural": false,
+ "selections": [
+ (v3/*: any*/),
+ {
+ "alias": null,
+ "args": null,
+ "filters": null,
+ "handle": "deleteEdge",
+ "key": "",
+ "kind": "ScalarHandle",
+ "name": "deletedControlId",
+ "handleArgs": [
+ {
+ "kind": "Variable",
+ "name": "connections",
+ "variableName": "connections"
+ }
+ ]
+ }
+ ],
+ "storageKey": null
+ }
+ ]
+ },
+ "params": {
+ "cacheID": "2d95c1ff9328afa01b0f24d1910898d1",
+ "id": null,
+ "metadata": {},
+ "name": "ControlDeleteMutation",
+ "operationKind": "mutation",
+ "text": "mutation ControlDeleteMutation(\n $input: DeleteControlInput!\n) {\n deleteControl(input: $input) {\n deletedControlId\n }\n}\n"
+ }
+};
+})();
+
+(node as any).hash = "a1e347241b41977cdea4a31d371e8770";
+
+export default node;
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlFragment_Control.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlFragment_Control.graphql.ts
index e00074e67..3ca2a4de7 100644
--- a/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlFragment_Control.graphql.ts
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlFragment_Control.graphql.ts
@@ -1,5 +1,5 @@
/**
- * @generated SignedSource<<8c59833cd4588accdf1d316d9e494d26>>
+ * @generated SignedSource<<50304bfb34b0581895a71491f521c273>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -14,7 +14,7 @@ export type ControlFragment_Control$data = {
readonly description: string;
readonly id: string;
readonly name: string;
- readonly referenceId: string;
+ readonly sectionTitle: string;
readonly " $fragmentType": "ControlFragment_Control";
};
export type ControlFragment_Control$key = {
@@ -53,7 +53,7 @@ const node: ReaderFragment = {
"alias": null,
"args": null,
"kind": "ScalarField",
- "name": "referenceId",
+ "name": "sectionTitle",
"storageKey": null
}
],
@@ -61,6 +61,6 @@ const node: ReaderFragment = {
"abstractKey": null
};
-(node as any).hash = "ccbc9d6743d45b9a4049b661a1f0ad57";
+(node as any).hash = "b04ce9de2a583d415011d88563120b09";
export default node;
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlViewQuery.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlViewQuery.graphql.ts
index 046489dab..1bc7fbff8 100644
--- a/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlViewQuery.graphql.ts
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/ControlViewQuery.graphql.ts
@@ -1,5 +1,5 @@
/**
- * @generated SignedSource<<2b4d05f2a954b567c9278d604e32db9e>>
+ * @generated SignedSource<<53940cf77492a6c53c699caeb14b1b54>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -117,7 +117,7 @@ return {
"alias": null,
"args": null,
"kind": "ScalarField",
- "name": "referenceId",
+ "name": "sectionTitle",
"storageKey": null
}
],
@@ -130,12 +130,12 @@ return {
]
},
"params": {
- "cacheID": "a65968fe47c5fb75f72a01d9785ae176",
+ "cacheID": "5afaae7974871ebac2058831d084514e",
"id": null,
"metadata": {},
"name": "ControlViewQuery",
"operationKind": "query",
- "text": "query ControlViewQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n id\n ...ControlFragment_Control\n }\n}\n\nfragment ControlFragment_Control on Control {\n id\n description\n name\n referenceId\n}\n"
+ "text": "query ControlViewQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n id\n ...ControlFragment_Control\n }\n}\n\nfragment ControlFragment_Control on Control {\n id\n description\n name\n sectionTitle\n}\n"
}
};
})();
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlPageUpdateControlMutation.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlPageUpdateControlMutation.graphql.ts
new file mode 100644
index 000000000..6d006fc25
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlPageUpdateControlMutation.graphql.ts
@@ -0,0 +1,132 @@
+/**
+ * @generated SignedSource<<2e60fc1d41d307f288d47b07d4651997>>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+
+import { ConcreteRequest } from 'relay-runtime';
+export type UpdateControlInput = {
+ description?: string | null | undefined;
+ id: string;
+ name?: string | null | undefined;
+ referenceId?: string | null | undefined;
+};
+export type EditControlPageUpdateControlMutation$variables = {
+ input: UpdateControlInput;
+};
+export type EditControlPageUpdateControlMutation$data = {
+ readonly updateControl: {
+ readonly control: {
+ readonly description: string;
+ readonly id: string;
+ readonly name: string;
+ readonly referenceId: string;
+ };
+ };
+};
+export type EditControlPageUpdateControlMutation = {
+ response: EditControlPageUpdateControlMutation$data;
+ variables: EditControlPageUpdateControlMutation$variables;
+};
+
+const node: ConcreteRequest = (function(){
+var v0 = [
+ {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "input"
+ }
+],
+v1 = [
+ {
+ "alias": null,
+ "args": [
+ {
+ "kind": "Variable",
+ "name": "input",
+ "variableName": "input"
+ }
+ ],
+ "concreteType": "UpdateControlPayload",
+ "kind": "LinkedField",
+ "name": "updateControl",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "concreteType": "Control",
+ "kind": "LinkedField",
+ "name": "control",
+ "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": "description",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "referenceId",
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+];
+return {
+ "fragment": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "EditControlPageUpdateControlMutation",
+ "selections": (v1/*: any*/),
+ "type": "Mutation",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Operation",
+ "name": "EditControlPageUpdateControlMutation",
+ "selections": (v1/*: any*/)
+ },
+ "params": {
+ "cacheID": "62ebcc3fcdb6bf1b1c585227e6555095",
+ "id": null,
+ "metadata": {},
+ "name": "EditControlPageUpdateControlMutation",
+ "operationKind": "mutation",
+ "text": "mutation EditControlPageUpdateControlMutation(\n $input: UpdateControlInput!\n) {\n updateControl(input: $input) {\n control {\n id\n name\n description\n referenceId\n }\n }\n}\n"
+ }
+};
+})();
+
+(node as any).hash = "2a3daa12db6c6ceac41ffb25be14760f";
+
+export default node;
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlViewQuery.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlViewQuery.graphql.ts
new file mode 100644
index 000000000..77c483e39
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlViewQuery.graphql.ts
@@ -0,0 +1,154 @@
+/**
+ * @generated SignedSource<<1e68e8f32977bfde6529ccb4244dd679>>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+
+import { ConcreteRequest } from 'relay-runtime';
+export type EditControlViewQuery$variables = {
+ controlId: string;
+};
+export type EditControlViewQuery$data = {
+ readonly control: {
+ readonly description?: string;
+ readonly id?: string;
+ readonly name?: string;
+ readonly sectionTitle?: string;
+ };
+};
+export type EditControlViewQuery = {
+ response: EditControlViewQuery$data;
+ variables: EditControlViewQuery$variables;
+};
+
+const node: ConcreteRequest = (function(){
+var v0 = [
+ {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "controlId"
+ }
+],
+v1 = [
+ {
+ "kind": "Variable",
+ "name": "id",
+ "variableName": "controlId"
+ }
+],
+v2 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "id",
+ "storageKey": null
+},
+v3 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "name",
+ "storageKey": null
+},
+v4 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "description",
+ "storageKey": null
+},
+v5 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "sectionTitle",
+ "storageKey": null
+};
+return {
+ "fragment": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "EditControlViewQuery",
+ "selections": [
+ {
+ "alias": "control",
+ "args": (v1/*: any*/),
+ "concreteType": null,
+ "kind": "LinkedField",
+ "name": "node",
+ "plural": false,
+ "selections": [
+ {
+ "kind": "InlineFragment",
+ "selections": [
+ (v2/*: any*/),
+ (v3/*: any*/),
+ (v4/*: any*/),
+ (v5/*: any*/)
+ ],
+ "type": "Control",
+ "abstractKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "type": "Query",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Operation",
+ "name": "EditControlViewQuery",
+ "selections": [
+ {
+ "alias": "control",
+ "args": (v1/*: any*/),
+ "concreteType": null,
+ "kind": "LinkedField",
+ "name": "node",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "__typename",
+ "storageKey": null
+ },
+ (v2/*: any*/),
+ {
+ "kind": "InlineFragment",
+ "selections": [
+ (v3/*: any*/),
+ (v4/*: any*/),
+ (v5/*: any*/)
+ ],
+ "type": "Control",
+ "abstractKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ]
+ },
+ "params": {
+ "cacheID": "0b532a5fff1f69df57220aa122e32e18",
+ "id": null,
+ "metadata": {},
+ "name": "EditControlViewQuery",
+ "operationKind": "query",
+ "text": "query EditControlViewQuery(\n $controlId: ID!\n) {\n control: node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n description\n sectionTitle\n }\n id\n }\n}\n"
+ }
+};
+})();
+
+(node as any).hash = "83b8034c722cd3fe442906b74a1613d3";
+
+export default node;
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlViewUpdateControlMutation.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlViewUpdateControlMutation.graphql.ts
new file mode 100644
index 000000000..21b416b49
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/EditControlViewUpdateControlMutation.graphql.ts
@@ -0,0 +1,132 @@
+/**
+ * @generated SignedSource<>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+
+import { ConcreteRequest } from 'relay-runtime';
+export type UpdateControlInput = {
+ description?: string | null | undefined;
+ id: string;
+ name?: string | null | undefined;
+ sectionTitle?: string | null | undefined;
+};
+export type EditControlViewUpdateControlMutation$variables = {
+ input: UpdateControlInput;
+};
+export type EditControlViewUpdateControlMutation$data = {
+ readonly updateControl: {
+ readonly control: {
+ readonly description: string;
+ readonly id: string;
+ readonly name: string;
+ readonly sectionTitle: string;
+ };
+ };
+};
+export type EditControlViewUpdateControlMutation = {
+ response: EditControlViewUpdateControlMutation$data;
+ variables: EditControlViewUpdateControlMutation$variables;
+};
+
+const node: ConcreteRequest = (function(){
+var v0 = [
+ {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "input"
+ }
+],
+v1 = [
+ {
+ "alias": null,
+ "args": [
+ {
+ "kind": "Variable",
+ "name": "input",
+ "variableName": "input"
+ }
+ ],
+ "concreteType": "UpdateControlPayload",
+ "kind": "LinkedField",
+ "name": "updateControl",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "concreteType": "Control",
+ "kind": "LinkedField",
+ "name": "control",
+ "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": "description",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "sectionTitle",
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+];
+return {
+ "fragment": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "EditControlViewUpdateControlMutation",
+ "selections": (v1/*: any*/),
+ "type": "Mutation",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Operation",
+ "name": "EditControlViewUpdateControlMutation",
+ "selections": (v1/*: any*/)
+ },
+ "params": {
+ "cacheID": "266ebf922cda80bcc5d0384f37b2d3fa",
+ "id": null,
+ "metadata": {},
+ "name": "EditControlViewUpdateControlMutation",
+ "operationKind": "mutation",
+ "text": "mutation EditControlViewUpdateControlMutation(\n $input: UpdateControlInput!\n) {\n updateControl(input: $input) {\n control {\n id\n name\n description\n sectionTitle\n }\n }\n}\n"
+ }
+};
+})();
+
+(node as any).hash = "5f232d3fbab52a0bb165bfa58c09bc67";
+
+export default node;
diff --git a/apps/console/src/pages/organizations/frameworks/controls/__generated__/NewControlViewCreateControlMutation.graphql.ts b/apps/console/src/pages/organizations/frameworks/controls/__generated__/NewControlViewCreateControlMutation.graphql.ts
new file mode 100644
index 000000000..e269dd430
--- /dev/null
+++ b/apps/console/src/pages/organizations/frameworks/controls/__generated__/NewControlViewCreateControlMutation.graphql.ts
@@ -0,0 +1,145 @@
+/**
+ * @generated SignedSource<>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+
+import { ConcreteRequest } from 'relay-runtime';
+export type CreateControlInput = {
+ description: string;
+ frameworkId: string;
+ name: string;
+ sectionTitle: string;
+};
+export type NewControlViewCreateControlMutation$variables = {
+ input: CreateControlInput;
+};
+export type NewControlViewCreateControlMutation$data = {
+ readonly createControl: {
+ readonly controlEdge: {
+ readonly node: {
+ readonly description: string;
+ readonly id: string;
+ readonly name: string;
+ readonly sectionTitle: string;
+ };
+ };
+ };
+};
+export type NewControlViewCreateControlMutation = {
+ response: NewControlViewCreateControlMutation$data;
+ variables: NewControlViewCreateControlMutation$variables;
+};
+
+const node: ConcreteRequest = (function(){
+var v0 = [
+ {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "input"
+ }
+],
+v1 = [
+ {
+ "alias": null,
+ "args": [
+ {
+ "kind": "Variable",
+ "name": "input",
+ "variableName": "input"
+ }
+ ],
+ "concreteType": "CreateControlPayload",
+ "kind": "LinkedField",
+ "name": "createControl",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "concreteType": "ControlEdge",
+ "kind": "LinkedField",
+ "name": "controlEdge",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "concreteType": "Control",
+ "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": "description",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "sectionTitle",
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+];
+return {
+ "fragment": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "NewControlViewCreateControlMutation",
+ "selections": (v1/*: any*/),
+ "type": "Mutation",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Operation",
+ "name": "NewControlViewCreateControlMutation",
+ "selections": (v1/*: any*/)
+ },
+ "params": {
+ "cacheID": "2005ccdbeac4998dc5bea71013f4cb5d",
+ "id": null,
+ "metadata": {},
+ "name": "NewControlViewCreateControlMutation",
+ "operationKind": "mutation",
+ "text": "mutation NewControlViewCreateControlMutation(\n $input: CreateControlInput!\n) {\n createControl(input: $input) {\n controlEdge {\n node {\n id\n name\n description\n sectionTitle\n }\n }\n }\n}\n"
+ }
+};
+})();
+
+(node as any).hash = "354415d46fd5d1b15c029b96452054d3";
+
+export default node;
diff --git a/apps/console/src/pages/organizations/measures/MeasureView.tsx b/apps/console/src/pages/organizations/measures/MeasureView.tsx
index e289d38b1..08f759b3a 100644
--- a/apps/console/src/pages/organizations/measures/MeasureView.tsx
+++ b/apps/console/src/pages/organizations/measures/MeasureView.tsx
@@ -396,7 +396,7 @@ const frameworksQuery = graphql`
edges {
node {
id
- referenceId
+ sectionTitle
name
description
}
@@ -419,7 +419,7 @@ const linkedControlsQuery = graphql`
edges {
node {
id
- referenceId
+ sectionTitle
name
description
}
@@ -2087,7 +2087,7 @@ function MeasureViewContent({
const lowerQuery = controlSearchQuery.toLowerCase();
return controls.filter(
(control) =>
- control.referenceId.toLowerCase().includes(lowerQuery) ||
+ control.sectionTitle.toLowerCase().includes(lowerQuery) ||
control.name.toLowerCase().includes(lowerQuery) ||
(control.description &&
control.description.toLowerCase().includes(lowerQuery))
@@ -2733,7 +2733,7 @@ function MeasureViewContent({
- {control.referenceId}
+ {control.sectionTitle}
@@ -3829,7 +3829,7 @@ function MeasureViewContent({
- {control.referenceId}
+ {control.sectionTitle}
diff --git a/apps/console/src/pages/organizations/measures/__generated__/MeasureViewFrameworksQuery.graphql.ts b/apps/console/src/pages/organizations/measures/__generated__/MeasureViewFrameworksQuery.graphql.ts
index 2a585bd42..d984f10d4 100644
--- a/apps/console/src/pages/organizations/measures/__generated__/MeasureViewFrameworksQuery.graphql.ts
+++ b/apps/console/src/pages/organizations/measures/__generated__/MeasureViewFrameworksQuery.graphql.ts
@@ -1,5 +1,5 @@
/**
- * @generated SignedSource<>
+ * @generated SignedSource<>
* @lightSyntaxTransform
* @nogrep
*/
@@ -23,7 +23,7 @@ export type MeasureViewFrameworksQuery$data = {
readonly description: string;
readonly id: string;
readonly name: string;
- readonly referenceId: string;
+ readonly sectionTitle: string;
};
}>;
};
@@ -130,7 +130,7 @@ v7 = [
"alias": null,
"args": null,
"kind": "ScalarField",
- "name": "referenceId",
+ "name": "sectionTitle",
"storageKey": null
},
(v3/*: any*/),
@@ -331,7 +331,7 @@ return {
]
},
"params": {
- "cacheID": "f32215939196e9e13f1347b57111f5cb",
+ "cacheID": "5dc8707d458fdb4ab9cf4967b716b85e",
"id": null,
"metadata": {
"connection": [
@@ -354,11 +354,11 @@ return {
},
"name": "MeasureViewFrameworksQuery",
"operationKind": "query",
- "text": "query MeasureViewFrameworksQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n frameworks(first: 100) {\n edges {\n node {\n id\n name\n controls(first: 100) {\n edges {\n node {\n id\n referenceId\n name\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
+ "text": "query MeasureViewFrameworksQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n frameworks(first: 100) {\n edges {\n node {\n id\n name\n controls(first: 100) {\n edges {\n node {\n id\n sectionTitle\n name\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
-(node as any).hash = "f1183b14c80a91b160f222af00d49b6f";
+(node as any).hash = "106bc944729f346777ecf0182ac41ad3";
export default node;
diff --git a/apps/console/src/pages/organizations/measures/__generated__/MeasureViewLinkedControlsQuery.graphql.ts b/apps/console/src/pages/organizations/measures/__generated__/MeasureViewLinkedControlsQuery.graphql.ts
index 10a511148..f7706f055 100644
--- a/apps/console/src/pages/organizations/measures/__generated__/MeasureViewLinkedControlsQuery.graphql.ts
+++ b/apps/console/src/pages/organizations/measures/__generated__/MeasureViewLinkedControlsQuery.graphql.ts
@@ -1,5 +1,5 @@
/**
- * @generated SignedSource<<9b551f9e8f59a5ffe5c00700cdb59c88>>
+ * @generated SignedSource<>
* @lightSyntaxTransform
* @nogrep
*/
@@ -20,7 +20,7 @@ export type MeasureViewLinkedControlsQuery$data = {
readonly description: string;
readonly id: string;
readonly name: string;
- readonly referenceId: string;
+ readonly sectionTitle: string;
};
}>;
};
@@ -83,7 +83,7 @@ v4 = [
"alias": null,
"args": null,
"kind": "ScalarField",
- "name": "referenceId",
+ "name": "sectionTitle",
"storageKey": null
},
{
@@ -235,7 +235,7 @@ return {
]
},
"params": {
- "cacheID": "b4f524eea7ce57decf321b7efacdaa03",
+ "cacheID": "1d1f61565fa1616f441ad54c7b590200",
"id": null,
"metadata": {
"connection": [
@@ -252,11 +252,11 @@ return {
},
"name": "MeasureViewLinkedControlsQuery",
"operationKind": "query",
- "text": "query MeasureViewLinkedControlsQuery(\n $measureId: ID!\n) {\n measure: node(id: $measureId) {\n __typename\n id\n ... on Measure {\n controls(first: 100) {\n edges {\n node {\n id\n referenceId\n name\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
+ "text": "query MeasureViewLinkedControlsQuery(\n $measureId: ID!\n) {\n measure: node(id: $measureId) {\n __typename\n id\n ... on Measure {\n controls(first: 100) {\n edges {\n node {\n id\n sectionTitle\n name\n description\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
-(node as any).hash = "5dfd96b1ab2edc5c8c654346046a968f";
+(node as any).hash = "5553b0d4c34e498e432315f8fa1dd805";
export default node;
diff --git a/apps/console/src/pages/organizations/risks/ShowRiskView.tsx b/apps/console/src/pages/organizations/risks/ShowRiskView.tsx
index 6d9135fbe..7dcdf3944 100644
--- a/apps/console/src/pages/organizations/risks/ShowRiskView.tsx
+++ b/apps/console/src/pages/organizations/risks/ShowRiskView.tsx
@@ -110,7 +110,7 @@ const showRiskViewQuery = graphql`
edges {
node {
id
- referenceId
+ sectionTitle
name
description
createdAt
@@ -1211,7 +1211,7 @@ function ShowRiskViewContent({
to={`/organizations/${organizationId}/controls/${control.id}`}
className="font-medium text-blue-600 hover:underline"
>
- {control.referenceId} - {control.name}
+ {control.sectionTitle} - {control.name}
diff --git a/apps/console/src/pages/organizations/risks/__generated__/ShowRiskViewQuery.graphql.ts b/apps/console/src/pages/organizations/risks/__generated__/ShowRiskViewQuery.graphql.ts
index 0870a296e..42eb25f40 100644
--- a/apps/console/src/pages/organizations/risks/__generated__/ShowRiskViewQuery.graphql.ts
+++ b/apps/console/src/pages/organizations/risks/__generated__/ShowRiskViewQuery.graphql.ts
@@ -1,5 +1,5 @@
/**
- * @generated SignedSource<>
+ * @generated SignedSource<>
* @lightSyntaxTransform
* @nogrep
*/
@@ -23,7 +23,7 @@ export type ShowRiskViewQuery$data = {
readonly description: string;
readonly id: string;
readonly name: string;
- readonly referenceId: string;
+ readonly sectionTitle: string;
};
}>;
};
@@ -323,7 +323,7 @@ v19 = [
"alias": null,
"args": null,
"kind": "ScalarField",
- "name": "referenceId",
+ "name": "sectionTitle",
"storageKey": null
},
(v3/*: any*/),
@@ -514,7 +514,7 @@ return {
]
},
"params": {
- "cacheID": "9d1057cf6eac37c07ed841a80a4604b9",
+ "cacheID": "fe20c6f4cd1e70c14bb099af7ecfffc2",
"id": null,
"metadata": {
"connection": [
@@ -549,11 +549,11 @@ return {
},
"name": "ShowRiskViewQuery",
"operationKind": "query",
- "text": "query ShowRiskViewQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\n id\n ... on Risk {\n name\n description\n treatment\n owner {\n id\n fullName\n }\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n createdAt\n updatedAt\n measures(first: 100) {\n edges {\n node {\n id\n name\n description\n category\n createdAt\n state\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n title\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n controls(first: 100) {\n edges {\n node {\n id\n referenceId\n name\n description\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
+ "text": "query ShowRiskViewQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\n id\n ... on Risk {\n name\n description\n treatment\n owner {\n id\n fullName\n }\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n createdAt\n updatedAt\n measures(first: 100) {\n edges {\n node {\n id\n name\n description\n category\n createdAt\n state\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n title\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n controls(first: 100) {\n edges {\n node {\n id\n sectionTitle\n name\n description\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
-(node as any).hash = "96763bbbebd3aa29a02fcf1e6e782293";
+(node as any).hash = "f1695786e4eb823466d6ebee4555cd9b";
export default node;
diff --git a/pkg/coredata/control.go b/pkg/coredata/control.go
index 9e68f099a..06a5c289a 100644
--- a/pkg/coredata/control.go
+++ b/pkg/coredata/control.go
@@ -28,22 +28,22 @@ import (
type (
Control struct {
- ID gid.GID `db:"id"`
- ReferenceID string `db:"reference_id"`
- TenantID gid.TenantID `db:"tenant_id"`
- FrameworkID gid.GID `db:"framework_id"`
- Name string `db:"name"`
- Description string `db:"description"`
- CreatedAt time.Time `db:"created_at"`
- UpdatedAt time.Time `db:"updated_at"`
+ ID gid.GID `db:"id"`
+ SectionTitle string `db:"section_title"`
+ TenantID gid.TenantID `db:"tenant_id"`
+ FrameworkID gid.GID `db:"framework_id"`
+ Name string `db:"name"`
+ Description string `db:"description"`
+ CreatedAt time.Time `db:"created_at"`
+ UpdatedAt time.Time `db:"updated_at"`
}
Controls []*Control
UpdateControlParams struct {
- ExpectedVersion int
- Name *string
- Description *string
+ Name *string
+ Description *string
+ SectionTitle *string
}
)
@@ -51,6 +51,8 @@ func (c Control) CursorKey(orderBy ControlOrderField) page.CursorKey {
switch orderBy {
case ControlOrderFieldCreatedAt:
return page.CursorKey{ID: c.ID, Value: c.CreatedAt}
+ case ControlOrderFieldSectionTitle:
+ return page.CursorKey{ID: c.ID, Value: c.SectionTitle}
}
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
@@ -67,7 +69,7 @@ func (c *Controls) LoadByDocumentID(
WITH ctrl AS (
SELECT
c.id,
- c.reference_id,
+ c.section_title,
c.framework_id,
c.tenant_id,
c.name,
@@ -83,7 +85,7 @@ WITH ctrl AS (
)
SELECT
id,
- reference_id,
+ section_title,
framework_id,
tenant_id,
name,
@@ -127,7 +129,7 @@ func (c *Controls) LoadByMeasureID(
WITH ctrl AS (
SELECT
c.id,
- c.reference_id,
+ c.section_title,
c.framework_id,
c.tenant_id,
c.name,
@@ -143,7 +145,7 @@ WITH ctrl AS (
)
SELECT
id,
- reference_id,
+ section_title,
framework_id,
tenant_id,
name,
@@ -186,7 +188,7 @@ func (c *Controls) LoadByRiskID(
WITH ctrl AS (
SELECT DISTINCT
c.id,
- c.reference_id,
+ c.section_title,
c.framework_id,
c.tenant_id,
c.name,
@@ -208,7 +210,7 @@ WITH ctrl AS (
)
SELECT
id,
- reference_id,
+ section_title,
framework_id,
tenant_id,
name,
@@ -251,7 +253,7 @@ func (c *Controls) LoadByFrameworkID(
q := `
SELECT
id,
- reference_id,
+ section_title,
framework_id,
tenant_id,
name,
@@ -285,17 +287,17 @@ WHERE
return nil
}
-func (c *Control) LoadByFrameworkIDAndReferenceID(
+func (c *Control) LoadByFrameworkIDAndSectionTitle(
ctx context.Context,
conn pg.Conn,
scope Scoper,
frameworkID gid.GID,
- referenceID string,
+ sectionTitle string,
) error {
q := `
SELECT
id,
- reference_id,
+ section_title,
framework_id,
tenant_id,
name,
@@ -307,12 +309,12 @@ FROM
WHERE
%s
AND framework_id = @framework_id
- AND reference_id = @reference_id
+ AND section_title = @section_title
LIMIT 1;
`
q = fmt.Sprintf(q, scope.SQLFragment())
- args := pgx.StrictNamedArgs{"framework_id": frameworkID, "reference_id": referenceID}
+ args := pgx.StrictNamedArgs{"framework_id": frameworkID, "section_title": sectionTitle}
maps.Copy(args, scope.SQLArguments())
rows, err := conn.Query(ctx, q, args)
if err != nil {
@@ -338,7 +340,7 @@ func (c *Control) LoadByID(
q := `
SELECT
id,
- reference_id,
+ section_title,
framework_id,
tenant_id,
name,
@@ -382,7 +384,7 @@ INSERT INTO
tenant_id,
id,
framework_id,
- reference_id,
+ section_title,
name,
description,
created_at,
@@ -392,7 +394,7 @@ VALUES (
@tenant_id,
@control_id,
@framework_id,
- @reference_id,
+ @section_title,
@name,
@description,
@created_at,
@@ -401,14 +403,14 @@ VALUES (
`
args := pgx.StrictNamedArgs{
- "tenant_id": scope.GetTenantID(),
- "control_id": c.ID,
- "framework_id": c.FrameworkID,
- "reference_id": c.ReferenceID,
- "name": c.Name,
- "description": c.Description,
- "created_at": c.CreatedAt,
- "updated_at": c.UpdatedAt,
+ "tenant_id": scope.GetTenantID(),
+ "control_id": c.ID,
+ "framework_id": c.FrameworkID,
+ "section_title": c.SectionTitle,
+ "name": c.Name,
+ "description": c.Description,
+ "created_at": c.CreatedAt,
+ "updated_at": c.UpdatedAt,
}
_, err := conn.Exec(ctx, q, args)
return err
@@ -446,6 +448,7 @@ func (c *Control) Update(
UPDATE controls SET
name = COALESCE(@name, name),
description = COALESCE(@description, description),
+ section_title = COALESCE(@section_title, section_title),
updated_at = @updated_at
WHERE %s
AND id = @control_id
@@ -455,15 +458,16 @@ RETURNING
tenant_id,
name,
description,
+ section_title,
created_at,
updated_at
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
- "control_id": c.ID,
- "expected_version": params.ExpectedVersion,
- "updated_at": time.Now(),
+ "control_id": c.ID,
+ "section_title": params.SectionTitle,
+ "updated_at": time.Now(),
}
if params.Name != nil {
diff --git a/pkg/coredata/control_order_field.go b/pkg/coredata/control_order_field.go
index 8004efe45..b4545d086 100644
--- a/pkg/coredata/control_order_field.go
+++ b/pkg/coredata/control_order_field.go
@@ -19,11 +19,19 @@ type (
)
const (
- ControlOrderFieldCreatedAt ControlOrderField = "CREATED_AT"
+ ControlOrderFieldCreatedAt ControlOrderField = "CREATED_AT"
+ ControlOrderFieldSectionTitle ControlOrderField = "SECTION_TITLE"
)
func (p ControlOrderField) Column() string {
- return string(p)
+ switch p {
+ case ControlOrderFieldCreatedAt:
+ return "created_at"
+ case ControlOrderFieldSectionTitle:
+ return "section_title_sort_key(section_title)"
+ default:
+ return string(p)
+ }
}
func (p ControlOrderField) String() string {
diff --git a/pkg/coredata/migrations/20250605T233149Z.sql b/pkg/coredata/migrations/20250605T233149Z.sql
new file mode 100644
index 000000000..c1abda8cb
--- /dev/null
+++ b/pkg/coredata/migrations/20250605T233149Z.sql
@@ -0,0 +1,34 @@
+ALTER TABLE controls DROP COLUMN version;
+
+ALTER TABLE controls RENAME COLUMN reference_id TO section_title;
+
+CREATE OR REPLACE FUNCTION section_title_sort_key(text) RETURNS text AS $$
+DECLARE
+ result text := '';
+ matches text[];
+ remainder text := $1;
+BEGIN
+ WHILE remainder ~ '\d+' LOOP
+ -- Extract text before the number
+ result := result || substring(remainder FROM '^[^\d]*');
+
+ -- Extract and pad the next number
+ matches := regexp_matches(remainder, '(\d+)', ''); -- captures the first number
+ IF matches IS NOT NULL THEN
+ result := result || lpad(matches[1], 10, '0');
+ -- Remove processed part from remainder
+ remainder := substring(remainder FROM '\d+(.*)$');
+ ELSE
+ EXIT;
+ END IF;
+ END LOOP;
+
+ -- Append any remaining non-digit text
+ result := result || remainder;
+
+ RETURN result;
+END;
+$$ LANGUAGE plpgsql IMMUTABLE STRICT;
+
+COMMENT ON FUNCTION section_title_sort_key(text) IS
+ 'Converts numbers in strings to zero-padded format for natural sorting';
diff --git a/pkg/probo/control_service.go b/pkg/probo/control_service.go
index cb76a5b30..03efc1d8e 100644
--- a/pkg/probo/control_service.go
+++ b/pkg/probo/control_service.go
@@ -31,17 +31,18 @@ type (
}
CreateControlRequest struct {
- ID gid.GID
- FrameworkID gid.GID
- Name string
- Description string
+ ID gid.GID
+ FrameworkID gid.GID
+ Name string
+ Description string
+ SectionTitle string
}
UpdateControlRequest struct {
- ID gid.GID
- ExpectedVersion int
- Name *string
- Description *string
+ ID gid.GID
+ Name *string
+ Description *string
+ SectionTitle *string
}
ConnectControlToMitigationRequest struct {
@@ -263,13 +264,14 @@ func (s ControlService) Create(
framework := &coredata.Framework{}
control := &coredata.Control{
- ID: req.ID,
- FrameworkID: req.FrameworkID,
- TenantID: s.svc.scope.GetTenantID(),
- Name: req.Name,
- Description: req.Description,
- CreatedAt: now,
- UpdatedAt: now,
+ ID: gid.New(s.svc.scope.GetTenantID(), coredata.ControlEntityType),
+ FrameworkID: req.FrameworkID,
+ TenantID: s.svc.scope.GetTenantID(),
+ Name: req.Name,
+ Description: req.Description,
+ SectionTitle: req.SectionTitle,
+ CreatedAt: now,
+ UpdatedAt: now,
}
err := s.svc.pg.WithTx(
@@ -317,9 +319,9 @@ func (s ControlService) Update(
req UpdateControlRequest,
) (*coredata.Control, error) {
params := coredata.UpdateControlParams{
- ExpectedVersion: req.ExpectedVersion,
- Name: req.Name,
- Description: req.Description,
+ Name: req.Name,
+ Description: req.Description,
+ SectionTitle: req.SectionTitle,
}
control := &coredata.Control{ID: req.ID}
diff --git a/pkg/probo/framework_service.go b/pkg/probo/framework_service.go
index 2e5432596..de4e6d47f 100644
--- a/pkg/probo/framework_service.go
+++ b/pkg/probo/framework_service.go
@@ -241,14 +241,14 @@ func (s FrameworkService) Import(
now := time.Now()
control := &coredata.Control{
- ID: controlID,
- TenantID: organizationID.TenantID(),
- FrameworkID: frameworkID,
- ReferenceID: control.ID,
- Name: control.Name,
- Description: control.Description,
- CreatedAt: now,
- UpdatedAt: now,
+ ID: controlID,
+ TenantID: organizationID.TenantID(),
+ FrameworkID: frameworkID,
+ SectionTitle: control.ID,
+ Name: control.Name,
+ Description: control.Description,
+ CreatedAt: now,
+ UpdatedAt: now,
}
if err := control.Insert(ctx, tx, s.svc.scope); err != nil {
@@ -307,7 +307,7 @@ func (s FrameworkService) ExportAudit(
}
for _, control := range controls {
- controlDir := filepath.Join(exportDir, control.ReferenceID)
+ controlDir := filepath.Join(exportDir, filepath.Base(control.SectionTitle))
if err := os.MkdirAll(controlDir, 0755); err != nil {
return fmt.Errorf("cannot create control directory: %w", err)
}
@@ -344,7 +344,7 @@ func (s FrameworkService) ExportAudit(
}
for _, document := range documents {
- documentDir := filepath.Join(controlDir, document.Title)
+ documentDir := filepath.Join(controlDir, filepath.Base(document.Title))
if err := os.MkdirAll(documentDir, 0755); err != nil {
return fmt.Errorf("cannot create document directory: %w", err)
}
@@ -361,13 +361,13 @@ func (s FrameworkService) ExportAudit(
}
for _, measure := range measures {
- measureDir := filepath.Join(controlDir, measure.Name)
+ measureDir := filepath.Join(controlDir, filepath.Base(measure.Name))
if err := os.MkdirAll(measureDir, 0755); err != nil {
return fmt.Errorf("cannot create measure directory: %w", err)
}
evidences := coredata.Evidences{}
- cursor := page.NewCursor(
+ evidenceCursor := page.NewCursor(
0,
nil,
page.Head,
@@ -377,12 +377,12 @@ func (s FrameworkService) ExportAudit(
},
)
- if err := evidences.LoadByMeasureID(ctx, conn, s.svc.scope, measure.ID, cursor); err != nil {
+ if err := evidences.LoadByMeasureID(ctx, conn, s.svc.scope, measure.ID, evidenceCursor); err != nil {
return fmt.Errorf("cannot load evidences: %w", err)
}
for _, evidence := range evidences {
- evidenceFile := filepath.Join(measureDir, evidence.Filename)
+ evidenceFile := filepath.Join(measureDir, filepath.Base(evidence.Filename))
if evidence.Type == coredata.EvidenceTypeFile && evidence.ObjectKey != "" {
output, err := s.svc.s3.GetObject(
diff --git a/pkg/probo/measure_service.go b/pkg/probo/measure_service.go
index d7755ddfe..d01beca20 100644
--- a/pkg/probo/measure_service.go
+++ b/pkg/probo/measure_service.go
@@ -235,7 +235,7 @@ func (s MeasureService) Import(
}
control := &coredata.Control{}
- if err := control.LoadByFrameworkIDAndReferenceID(ctx, tx, s.svc.scope, framework.ID, standard.Control); err != nil {
+ if err := control.LoadByFrameworkIDAndSectionTitle(ctx, tx, s.svc.scope, framework.ID, standard.Control); err != nil {
continue
}
diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql
index 78a67f81c..514da8a55 100644
--- a/pkg/server/api/console/v1/schema.graphql
+++ b/pkg/server/api/console/v1/schema.graphql
@@ -169,6 +169,10 @@ enum ControlOrderField
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.ControlOrderFieldCreatedAt"
)
+ SECTION_TITLE
+ @goEnum(
+ value: "github.com/getprobo/probo/pkg/coredata.ControlOrderFieldSectionTitle"
+ )
}
enum MeasureOrderField
@@ -683,7 +687,7 @@ type Framework implements Node {
type Control implements Node {
id: ID!
- referenceId: String!
+ sectionTitle: String!
name: String!
description: String!
@@ -1087,6 +1091,11 @@ type Mutation {
importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload!
deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload!
+ # Control mutations
+ createControl(input: CreateControlInput!): CreateControlPayload!
+ updateControl(input: UpdateControlInput!): UpdateControlPayload!
+ deleteControl(input: DeleteControlInput!): DeleteControlPayload!
+
# Measure mutations
createMeasure(input: CreateMeasureInput!): CreateMeasurePayload!
updateMeasure(input: UpdateMeasureInput!): UpdateMeasurePayload!
@@ -1502,6 +1511,24 @@ input RemoveUserInput {
userId: ID!
}
+input CreateControlInput {
+ frameworkId: ID!
+ sectionTitle: String!
+ name: String!
+ description: String!
+}
+
+input UpdateControlInput {
+ id: ID!
+ sectionTitle: String
+ name: String
+ description: String
+}
+
+input DeleteControlInput {
+ controlId: ID!
+}
+
# Payload Types
type CreateOrganizationPayload {
organizationEdge: OrganizationEdge!
@@ -1515,6 +1542,18 @@ type DeleteOrganizationPayload {
deletedOrganizationId: ID!
}
+type CreateControlPayload {
+ controlEdge: ControlEdge!
+}
+
+type UpdateControlPayload {
+ control: Control!
+}
+
+type DeleteControlPayload {
+ deletedControlId: ID!
+}
+
type CreateVendorPayload {
vendorEdge: VendorEdge!
}
diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go
index e113a06db..1b1dd94b9 100644
--- a/pkg/server/api/console/v1/schema/schema.go
+++ b/pkg/server/api/console/v1/schema/schema.go
@@ -130,15 +130,15 @@ type ComplexityRoot struct {
}
Control struct {
- CreatedAt func(childComplexity int) int
- Description func(childComplexity int) int
- Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) int
- Framework func(childComplexity int) int
- ID func(childComplexity int) int
- Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy) int
- Name func(childComplexity int) int
- ReferenceID func(childComplexity int) int
- UpdatedAt func(childComplexity int) int
+ CreatedAt func(childComplexity int) int
+ Description func(childComplexity int) int
+ Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) int
+ Framework func(childComplexity int) int
+ ID func(childComplexity int) int
+ Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy) int
+ Name func(childComplexity int) int
+ SectionTitle func(childComplexity int) int
+ UpdatedAt func(childComplexity int) int
}
ControlConnection struct {
@@ -165,6 +165,10 @@ type ComplexityRoot struct {
MeasureEdge func(childComplexity int) int
}
+ CreateControlPayload struct {
+ ControlEdge func(childComplexity int) int
+ }
+
CreateDatumPayload struct {
DatumEdge func(childComplexity int) int
}
@@ -259,6 +263,10 @@ type ComplexityRoot struct {
DeletedMeasureID func(childComplexity int) int
}
+ DeleteControlPayload struct {
+ DeletedControlID func(childComplexity int) int
+ }
+
DeleteDatumPayload struct {
DeletedDatumID func(childComplexity int) int
}
@@ -486,6 +494,7 @@ type ComplexityRoot struct {
AssignTask func(childComplexity int, input types.AssignTaskInput) int
ConfirmEmail func(childComplexity int, input types.ConfirmEmailInput) int
CreateAsset func(childComplexity int, input types.CreateAssetInput) int
+ CreateControl func(childComplexity int, input types.CreateControlInput) int
CreateControlDocumentMapping func(childComplexity int, input types.CreateControlDocumentMappingInput) int
CreateControlMeasureMapping func(childComplexity int, input types.CreateControlMeasureMappingInput) int
CreateDatum func(childComplexity int, input types.CreateDatumInput) int
@@ -502,6 +511,7 @@ type ComplexityRoot struct {
CreateVendor func(childComplexity int, input types.CreateVendorInput) int
CreateVendorRiskAssessment func(childComplexity int, input types.CreateVendorRiskAssessmentInput) int
DeleteAsset func(childComplexity int, input types.DeleteAssetInput) int
+ DeleteControl func(childComplexity int, input types.DeleteControlInput) int
DeleteControlDocumentMapping func(childComplexity int, input types.DeleteControlDocumentMappingInput) int
DeleteControlMeasureMapping func(childComplexity int, input types.DeleteControlMeasureMappingInput) int
DeleteDatum func(childComplexity int, input types.DeleteDatumInput) int
@@ -532,6 +542,7 @@ type ComplexityRoot struct {
SendSigningNotifications func(childComplexity int, input types.SendSigningNotificationsInput) int
UnassignTask func(childComplexity int, input types.UnassignTaskInput) int
UpdateAsset func(childComplexity int, input types.UpdateAssetInput) int
+ UpdateControl func(childComplexity int, input types.UpdateControlInput) int
UpdateDatum func(childComplexity int, input types.UpdateDatumInput) int
UpdateDocument func(childComplexity int, input types.UpdateDocumentInput) int
UpdateDocumentVersion func(childComplexity int, input types.UpdateDocumentVersionInput) int
@@ -710,6 +721,10 @@ type ComplexityRoot struct {
Asset func(childComplexity int) int
}
+ UpdateControlPayload struct {
+ Control func(childComplexity int) int
+ }
+
UpdateDatumPayload struct {
Datum func(childComplexity int) int
}
@@ -941,6 +956,9 @@ type MutationResolver interface {
UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error)
ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error)
DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error)
+ CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error)
+ UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error)
+ DeleteControl(ctx context.Context, input types.DeleteControlInput) (*types.DeleteControlPayload, error)
CreateMeasure(ctx context.Context, input types.CreateMeasureInput) (*types.CreateMeasurePayload, error)
UpdateMeasure(ctx context.Context, input types.UpdateMeasureInput) (*types.UpdateMeasurePayload, error)
ImportMeasure(ctx context.Context, input types.ImportMeasureInput) (*types.ImportMeasurePayload, error)
@@ -1332,12 +1350,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Control.Name(childComplexity), true
- case "Control.referenceId":
- if e.complexity.Control.ReferenceID == nil {
+ case "Control.sectionTitle":
+ if e.complexity.Control.SectionTitle == nil {
break
}
- return e.complexity.Control.ReferenceID(childComplexity), true
+ return e.complexity.Control.SectionTitle(childComplexity), true
case "Control.updatedAt":
if e.complexity.Control.UpdatedAt == nil {
@@ -1409,6 +1427,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.CreateControlMeasureMappingPayload.MeasureEdge(childComplexity), true
+ case "CreateControlPayload.controlEdge":
+ if e.complexity.CreateControlPayload.ControlEdge == nil {
+ break
+ }
+
+ return e.complexity.CreateControlPayload.ControlEdge(childComplexity), true
+
case "CreateDatumPayload.datumEdge":
if e.complexity.CreateDatumPayload.DatumEdge == nil {
break
@@ -1652,6 +1677,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.DeleteControlMeasureMappingPayload.DeletedMeasureID(childComplexity), true
+ case "DeleteControlPayload.deletedControlId":
+ if e.complexity.DeleteControlPayload.DeletedControlID == nil {
+ break
+ }
+
+ return e.complexity.DeleteControlPayload.DeletedControlID(childComplexity), true
+
case "DeleteDatumPayload.deletedDatumId":
if e.complexity.DeleteDatumPayload.DeletedDatumID == nil {
break
@@ -2527,6 +2559,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Mutation.CreateAsset(childComplexity, args["input"].(types.CreateAssetInput)), true
+ case "Mutation.createControl":
+ if e.complexity.Mutation.CreateControl == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_createControl_args(ctx, rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.CreateControl(childComplexity, args["input"].(types.CreateControlInput)), true
+
case "Mutation.createControlDocumentMapping":
if e.complexity.Mutation.CreateControlDocumentMapping == nil {
break
@@ -2719,6 +2763,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Mutation.DeleteAsset(childComplexity, args["input"].(types.DeleteAssetInput)), true
+ case "Mutation.deleteControl":
+ if e.complexity.Mutation.DeleteControl == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_deleteControl_args(ctx, rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.DeleteControl(childComplexity, args["input"].(types.DeleteControlInput)), true
+
case "Mutation.deleteControlDocumentMapping":
if e.complexity.Mutation.DeleteControlDocumentMapping == nil {
break
@@ -3079,6 +3135,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Mutation.UpdateAsset(childComplexity, args["input"].(types.UpdateAssetInput)), true
+ case "Mutation.updateControl":
+ if e.complexity.Mutation.UpdateControl == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_updateControl_args(ctx, rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.UpdateControl(childComplexity, args["input"].(types.UpdateControlInput)), true
+
case "Mutation.updateDatum":
if e.complexity.Mutation.UpdateDatum == nil {
break
@@ -3952,6 +4020,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.UpdateAssetPayload.Asset(childComplexity), true
+ case "UpdateControlPayload.control":
+ if e.complexity.UpdateControlPayload.Control == nil {
+ break
+ }
+
+ return e.complexity.UpdateControlPayload.Control(childComplexity), true
+
case "UpdateDatumPayload.datum":
if e.complexity.UpdateDatumPayload.Datum == nil {
break
@@ -4557,6 +4632,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputControlOrder,
ec.unmarshalInputCreateAssetInput,
ec.unmarshalInputCreateControlDocumentMappingInput,
+ ec.unmarshalInputCreateControlInput,
ec.unmarshalInputCreateControlMeasureMappingInput,
ec.unmarshalInputCreateDatumInput,
ec.unmarshalInputCreateDocumentInput,
@@ -4575,6 +4651,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputDatumOrder,
ec.unmarshalInputDeleteAssetInput,
ec.unmarshalInputDeleteControlDocumentMappingInput,
+ ec.unmarshalInputDeleteControlInput,
ec.unmarshalInputDeleteControlMeasureMappingInput,
ec.unmarshalInputDeleteDatumInput,
ec.unmarshalInputDeleteDocumentInput,
@@ -4615,6 +4692,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputTaskOrder,
ec.unmarshalInputUnassignTaskInput,
ec.unmarshalInputUpdateAssetInput,
+ ec.unmarshalInputUpdateControlInput,
ec.unmarshalInputUpdateDatumInput,
ec.unmarshalInputUpdateDocumentInput,
ec.unmarshalInputUpdateDocumentVersionInput,
@@ -4900,6 +4978,10 @@ enum ControlOrderField
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.ControlOrderFieldCreatedAt"
)
+ SECTION_TITLE
+ @goEnum(
+ value: "github.com/getprobo/probo/pkg/coredata.ControlOrderFieldSectionTitle"
+ )
}
enum MeasureOrderField
@@ -5414,7 +5496,7 @@ type Framework implements Node {
type Control implements Node {
id: ID!
- referenceId: String!
+ sectionTitle: String!
name: String!
description: String!
@@ -5818,6 +5900,11 @@ type Mutation {
importFramework(input: ImportFrameworkInput!): ImportFrameworkPayload!
deleteFramework(input: DeleteFrameworkInput!): DeleteFrameworkPayload!
+ # Control mutations
+ createControl(input: CreateControlInput!): CreateControlPayload!
+ updateControl(input: UpdateControlInput!): UpdateControlPayload!
+ deleteControl(input: DeleteControlInput!): DeleteControlPayload!
+
# Measure mutations
createMeasure(input: CreateMeasureInput!): CreateMeasurePayload!
updateMeasure(input: UpdateMeasureInput!): UpdateMeasurePayload!
@@ -6233,6 +6320,24 @@ input RemoveUserInput {
userId: ID!
}
+input CreateControlInput {
+ frameworkId: ID!
+ sectionTitle: String!
+ name: String!
+ description: String!
+}
+
+input UpdateControlInput {
+ id: ID!
+ sectionTitle: String
+ name: String
+ description: String
+}
+
+input DeleteControlInput {
+ controlId: ID!
+}
+
# Payload Types
type CreateOrganizationPayload {
organizationEdge: OrganizationEdge!
@@ -6246,6 +6351,18 @@ type DeleteOrganizationPayload {
deletedOrganizationId: ID!
}
+type CreateControlPayload {
+ controlEdge: ControlEdge!
+}
+
+type UpdateControlPayload {
+ control: Control!
+}
+
+type DeleteControlPayload {
+ deletedControlId: ID!
+}
+
type CreateVendorPayload {
vendorEdge: VendorEdge!
}
@@ -8154,6 +8271,29 @@ func (ec *executionContext) field_Mutation_createControlMeasureMapping_argsInput
return zeroVal, nil
}
+func (ec *executionContext) field_Mutation_createControl_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
+ var err error
+ args := map[string]any{}
+ arg0, err := ec.field_Mutation_createControl_argsInput(ctx, rawArgs)
+ if err != nil {
+ return nil, err
+ }
+ args["input"] = arg0
+ return args, nil
+}
+func (ec *executionContext) field_Mutation_createControl_argsInput(
+ ctx context.Context,
+ rawArgs map[string]any,
+) (types.CreateControlInput, error) {
+ ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ if tmp, ok := rawArgs["input"]; ok {
+ return ec.unmarshalNCreateControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateControlInput(ctx, tmp)
+ }
+
+ var zeroVal types.CreateControlInput
+ return zeroVal, nil
+}
+
func (ec *executionContext) field_Mutation_createDatum_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -8522,6 +8662,29 @@ func (ec *executionContext) field_Mutation_deleteControlMeasureMapping_argsInput
return zeroVal, nil
}
+func (ec *executionContext) field_Mutation_deleteControl_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
+ var err error
+ args := map[string]any{}
+ arg0, err := ec.field_Mutation_deleteControl_argsInput(ctx, rawArgs)
+ if err != nil {
+ return nil, err
+ }
+ args["input"] = arg0
+ return args, nil
+}
+func (ec *executionContext) field_Mutation_deleteControl_argsInput(
+ ctx context.Context,
+ rawArgs map[string]any,
+) (types.DeleteControlInput, error) {
+ ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ if tmp, ok := rawArgs["input"]; ok {
+ return ec.unmarshalNDeleteControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteControlInput(ctx, tmp)
+ }
+
+ var zeroVal types.DeleteControlInput
+ return zeroVal, nil
+}
+
func (ec *executionContext) field_Mutation_deleteDatum_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -9166,6 +9329,29 @@ func (ec *executionContext) field_Mutation_updateAsset_argsInput(
return zeroVal, nil
}
+func (ec *executionContext) field_Mutation_updateControl_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
+ var err error
+ args := map[string]any{}
+ arg0, err := ec.field_Mutation_updateControl_argsInput(ctx, rawArgs)
+ if err != nil {
+ return nil, err
+ }
+ args["input"] = arg0
+ return args, nil
+}
+func (ec *executionContext) field_Mutation_updateControl_argsInput(
+ ctx context.Context,
+ rawArgs map[string]any,
+) (types.UpdateControlInput, error) {
+ ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ if tmp, ok := rawArgs["input"]; ok {
+ return ec.unmarshalNUpdateControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlInput(ctx, tmp)
+ }
+
+ var zeroVal types.UpdateControlInput
+ return zeroVal, nil
+}
+
func (ec *executionContext) field_Mutation_updateDatum_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -12923,8 +13109,8 @@ func (ec *executionContext) fieldContext_Control_id(_ context.Context, field gra
return fc, nil
}
-func (ec *executionContext) _Control_referenceId(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) {
- fc, err := ec.fieldContext_Control_referenceId(ctx, field)
+func (ec *executionContext) _Control_sectionTitle(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Control_sectionTitle(ctx, field)
if err != nil {
return graphql.Null
}
@@ -12937,7 +13123,7 @@ func (ec *executionContext) _Control_referenceId(ctx context.Context, field grap
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
- return obj.ReferenceID, nil
+ return obj.SectionTitle, nil
})
if err != nil {
ec.Error(ctx, err)
@@ -12954,7 +13140,7 @@ func (ec *executionContext) _Control_referenceId(ctx context.Context, field grap
return ec.marshalNString2string(ctx, field.Selections, res)
}
-func (ec *executionContext) fieldContext_Control_referenceId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Control_sectionTitle(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Control",
Field: field,
@@ -13514,8 +13700,8 @@ func (ec *executionContext) fieldContext_ControlEdge_node(_ context.Context, fie
switch field.Name {
case "id":
return ec.fieldContext_Control_id(ctx, field)
- case "referenceId":
- return ec.fieldContext_Control_referenceId(ctx, field)
+ case "sectionTitle":
+ return ec.fieldContext_Control_sectionTitle(ctx, field)
case "name":
return ec.fieldContext_Control_name(ctx, field)
case "description":
@@ -13787,6 +13973,56 @@ func (ec *executionContext) fieldContext_CreateControlMeasureMappingPayload_meas
return fc, nil
}
+func (ec *executionContext) _CreateControlPayload_controlEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreateControlPayload) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_CreateControlPayload_controlEdge(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ControlEdge, 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.ControlEdge)
+ fc.Result = res
+ return ec.marshalNControlEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐControlEdge(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_CreateControlPayload_controlEdge(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "CreateControlPayload",
+ 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_ControlEdge_cursor(ctx, field)
+ case "node":
+ return ec.fieldContext_ControlEdge_node(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type ControlEdge", field.Name)
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _CreateDatumPayload_datumEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreateDatumPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_CreateDatumPayload_datumEdge(ctx, field)
if err != nil {
@@ -15492,6 +15728,50 @@ func (ec *executionContext) fieldContext_DeleteControlMeasureMappingPayload_dele
return fc, nil
}
+func (ec *executionContext) _DeleteControlPayload_deletedControlId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteControlPayload) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_DeleteControlPayload_deletedControlId(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DeletedControlID, 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_DeleteControlPayload_deletedControlId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "DeleteControlPayload",
+ 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) _DeleteDatumPayload_deletedDatumId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteDatumPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_DeleteDatumPayload_deletedDatumId(ctx, field)
if err != nil {
@@ -21881,6 +22161,183 @@ func (ec *executionContext) fieldContext_Mutation_deleteFramework(ctx context.Co
return fc, nil
}
+func (ec *executionContext) _Mutation_createControl(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_createControl(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().CreateControl(rctx, fc.Args["input"].(types.CreateControlInput))
+ })
+ 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.CreateControlPayload)
+ fc.Result = res
+ return ec.marshalNCreateControlPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateControlPayload(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_createControl(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 "controlEdge":
+ return ec.fieldContext_CreateControlPayload_controlEdge(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type CreateControlPayload", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_createControl_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_updateControl(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_updateControl(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().UpdateControl(rctx, fc.Args["input"].(types.UpdateControlInput))
+ })
+ 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.UpdateControlPayload)
+ fc.Result = res
+ return ec.marshalNUpdateControlPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlPayload(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_updateControl(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 "control":
+ return ec.fieldContext_UpdateControlPayload_control(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type UpdateControlPayload", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_updateControl_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_deleteControl(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_deleteControl(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().DeleteControl(rctx, fc.Args["input"].(types.DeleteControlInput))
+ })
+ 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.DeleteControlPayload)
+ fc.Result = res
+ return ec.marshalNDeleteControlPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteControlPayload(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_deleteControl(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 "deletedControlId":
+ return ec.fieldContext_DeleteControlPayload_deletedControlId(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type DeleteControlPayload", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_deleteControl_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Mutation_createMeasure(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_createMeasure(ctx, field)
if err != nil {
@@ -29646,6 +30103,70 @@ func (ec *executionContext) fieldContext_UpdateAssetPayload_asset(_ context.Cont
return fc, nil
}
+func (ec *executionContext) _UpdateControlPayload_control(ctx context.Context, field graphql.CollectedField, obj *types.UpdateControlPayload) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_UpdateControlPayload_control(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Control, 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.Control)
+ fc.Result = res
+ return ec.marshalNControl2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐControl(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_UpdateControlPayload_control(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "UpdateControlPayload",
+ 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_Control_id(ctx, field)
+ case "sectionTitle":
+ return ec.fieldContext_Control_sectionTitle(ctx, field)
+ case "name":
+ return ec.fieldContext_Control_name(ctx, field)
+ case "description":
+ return ec.fieldContext_Control_description(ctx, field)
+ case "framework":
+ return ec.fieldContext_Control_framework(ctx, field)
+ case "measures":
+ return ec.fieldContext_Control_measures(ctx, field)
+ case "documents":
+ return ec.fieldContext_Control_documents(ctx, field)
+ case "createdAt":
+ return ec.fieldContext_Control_createdAt(ctx, field)
+ case "updatedAt":
+ return ec.fieldContext_Control_updatedAt(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Control", field.Name)
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _UpdateDatumPayload_datum(ctx context.Context, field graphql.CollectedField, obj *types.UpdateDatumPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_UpdateDatumPayload_datum(ctx, field)
if err != nil {
@@ -36254,6 +36775,54 @@ func (ec *executionContext) unmarshalInputCreateControlDocumentMappingInput(ctx
return it, nil
}
+func (ec *executionContext) unmarshalInputCreateControlInput(ctx context.Context, obj any) (types.CreateControlInput, error) {
+ var it types.CreateControlInput
+ asMap := map[string]any{}
+ for k, v := range obj.(map[string]any) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"frameworkId", "sectionTitle", "name", "description"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "frameworkId":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("frameworkId"))
+ data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.FrameworkID = data
+ case "sectionTitle":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sectionTitle"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.SectionTitle = data
+ case "name":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Name = data
+ case "description":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Description = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputCreateControlMeasureMappingInput(ctx context.Context, obj any) (types.CreateControlMeasureMappingInput, error) {
var it types.CreateControlMeasureMappingInput
asMap := map[string]any{}
@@ -37223,6 +37792,33 @@ func (ec *executionContext) unmarshalInputDeleteControlDocumentMappingInput(ctx
return it, nil
}
+func (ec *executionContext) unmarshalInputDeleteControlInput(ctx context.Context, obj any) (types.DeleteControlInput, error) {
+ var it types.DeleteControlInput
+ asMap := map[string]any{}
+ for k, v := range obj.(map[string]any) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"controlId"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "controlId":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("controlId"))
+ data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.ControlID = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputDeleteControlMeasureMappingInput(ctx context.Context, obj any) (types.DeleteControlMeasureMappingInput, error) {
var it types.DeleteControlMeasureMappingInput
asMap := map[string]any{}
@@ -38548,6 +39144,54 @@ func (ec *executionContext) unmarshalInputUpdateAssetInput(ctx context.Context,
return it, nil
}
+func (ec *executionContext) unmarshalInputUpdateControlInput(ctx context.Context, obj any) (types.UpdateControlInput, error) {
+ var it types.UpdateControlInput
+ asMap := map[string]any{}
+ for k, v := range obj.(map[string]any) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"id", "sectionTitle", "name", "description"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "id":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.ID = data
+ case "sectionTitle":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sectionTitle"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.SectionTitle = data
+ case "name":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Name = data
+ case "description":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Description = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputUpdateDatumInput(ctx context.Context, obj any) (types.UpdateDatumInput, error) {
var it types.UpdateDatumInput
asMap := map[string]any{}
@@ -40285,8 +40929,8 @@ func (ec *executionContext) _Control(ctx context.Context, sel ast.SelectionSet,
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
- case "referenceId":
- out.Values[i] = ec._Control_referenceId(ctx, field, obj)
+ case "sectionTitle":
+ out.Values[i] = ec._Control_sectionTitle(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
@@ -40656,6 +41300,45 @@ func (ec *executionContext) _CreateControlMeasureMappingPayload(ctx context.Cont
return out
}
+var createControlPayloadImplementors = []string{"CreateControlPayload"}
+
+func (ec *executionContext) _CreateControlPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateControlPayload) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, createControlPayloadImplementors)
+
+ 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("CreateControlPayload")
+ case "controlEdge":
+ out.Values[i] = ec._CreateControlPayload_controlEdge(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 createDatumPayloadImplementors = []string{"CreateDatumPayload"}
func (ec *executionContext) _CreateDatumPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateDatumPayload) graphql.Marshaler {
@@ -41599,6 +42282,45 @@ func (ec *executionContext) _DeleteControlMeasureMappingPayload(ctx context.Cont
return out
}
+var deleteControlPayloadImplementors = []string{"DeleteControlPayload"}
+
+func (ec *executionContext) _DeleteControlPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteControlPayload) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, deleteControlPayloadImplementors)
+
+ 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("DeleteControlPayload")
+ case "deletedControlId":
+ out.Values[i] = ec._DeleteControlPayload_deletedControlId(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 deleteDatumPayloadImplementors = []string{"DeleteDatumPayload"}
func (ec *executionContext) _DeleteDatumPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteDatumPayload) graphql.Marshaler {
@@ -44132,6 +44854,27 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
+ case "createControl":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_createControl(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "updateControl":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_updateControl(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "deleteControl":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_deleteControl(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
case "createMeasure":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_createMeasure(ctx, field)
@@ -46437,6 +47180,45 @@ func (ec *executionContext) _UpdateAssetPayload(ctx context.Context, sel ast.Sel
return out
}
+var updateControlPayloadImplementors = []string{"UpdateControlPayload"}
+
+func (ec *executionContext) _UpdateControlPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateControlPayload) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, updateControlPayloadImplementors)
+
+ 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("UpdateControlPayload")
+ case "control":
+ out.Values[i] = ec._UpdateControlPayload_control(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 updateDatumPayloadImplementors = []string{"UpdateDatumPayload"}
func (ec *executionContext) _UpdateDatumPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateDatumPayload) graphql.Marshaler {
@@ -48830,10 +49612,12 @@ func (ec *executionContext) marshalNControlOrderField2githubᚗcomᚋgetproboᚋ
var (
unmarshalNControlOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlOrderField = map[string]coredata.ControlOrderField{
- "CREATED_AT": coredata.ControlOrderFieldCreatedAt,
+ "CREATED_AT": coredata.ControlOrderFieldCreatedAt,
+ "SECTION_TITLE": coredata.ControlOrderFieldSectionTitle,
}
marshalNControlOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlOrderField = map[coredata.ControlOrderField]string{
- coredata.ControlOrderFieldCreatedAt: "CREATED_AT",
+ coredata.ControlOrderFieldCreatedAt: "CREATED_AT",
+ coredata.ControlOrderFieldSectionTitle: "SECTION_TITLE",
}
)
@@ -48875,6 +49659,11 @@ func (ec *executionContext) marshalNCreateControlDocumentMappingPayload2ᚖgithu
return ec._CreateControlDocumentMappingPayload(ctx, sel, v)
}
+func (ec *executionContext) unmarshalNCreateControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateControlInput(ctx context.Context, v any) (types.CreateControlInput, error) {
+ res, err := ec.unmarshalInputCreateControlInput(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) unmarshalNCreateControlMeasureMappingInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateControlMeasureMappingInput(ctx context.Context, v any) (types.CreateControlMeasureMappingInput, error) {
res, err := ec.unmarshalInputCreateControlMeasureMappingInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -48894,6 +49683,20 @@ func (ec *executionContext) marshalNCreateControlMeasureMappingPayload2ᚖgithub
return ec._CreateControlMeasureMappingPayload(ctx, sel, v)
}
+func (ec *executionContext) marshalNCreateControlPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateControlPayload(ctx context.Context, sel ast.SelectionSet, v types.CreateControlPayload) graphql.Marshaler {
+ return ec._CreateControlPayload(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNCreateControlPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateControlPayload(ctx context.Context, sel ast.SelectionSet, v *types.CreateControlPayload) 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._CreateControlPayload(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalNCreateDatumInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateDatumInput(ctx context.Context, v any) (types.CreateDatumInput, error) {
res, err := ec.unmarshalInputCreateDatumInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -49383,6 +50186,11 @@ func (ec *executionContext) marshalNDeleteControlDocumentMappingPayload2ᚖgithu
return ec._DeleteControlDocumentMappingPayload(ctx, sel, v)
}
+func (ec *executionContext) unmarshalNDeleteControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteControlInput(ctx context.Context, v any) (types.DeleteControlInput, error) {
+ res, err := ec.unmarshalInputDeleteControlInput(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) unmarshalNDeleteControlMeasureMappingInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteControlMeasureMappingInput(ctx context.Context, v any) (types.DeleteControlMeasureMappingInput, error) {
res, err := ec.unmarshalInputDeleteControlMeasureMappingInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -49402,6 +50210,20 @@ func (ec *executionContext) marshalNDeleteControlMeasureMappingPayload2ᚖgithub
return ec._DeleteControlMeasureMappingPayload(ctx, sel, v)
}
+func (ec *executionContext) marshalNDeleteControlPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteControlPayload(ctx context.Context, sel ast.SelectionSet, v types.DeleteControlPayload) graphql.Marshaler {
+ return ec._DeleteControlPayload(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNDeleteControlPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteControlPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteControlPayload) 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._DeleteControlPayload(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalNDeleteDatumInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteDatumInput(ctx context.Context, v any) (types.DeleteDatumInput, error) {
res, err := ec.unmarshalInputDeleteDatumInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -51394,6 +52216,25 @@ func (ec *executionContext) marshalNUpdateAssetPayload2ᚖgithubᚗcomᚋgetprob
return ec._UpdateAssetPayload(ctx, sel, v)
}
+func (ec *executionContext) unmarshalNUpdateControlInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlInput(ctx context.Context, v any) (types.UpdateControlInput, error) {
+ res, err := ec.unmarshalInputUpdateControlInput(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNUpdateControlPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlPayload(ctx context.Context, sel ast.SelectionSet, v types.UpdateControlPayload) graphql.Marshaler {
+ return ec._UpdateControlPayload(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNUpdateControlPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateControlPayload(ctx context.Context, sel ast.SelectionSet, v *types.UpdateControlPayload) 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._UpdateControlPayload(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalNUpdateDatumInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateDatumInput(ctx context.Context, v any) (types.UpdateDatumInput, error) {
res, err := ec.unmarshalInputUpdateDatumInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
diff --git a/pkg/server/api/console/v1/types/control.go b/pkg/server/api/console/v1/types/control.go
index df7a849c4..0b894c903 100644
--- a/pkg/server/api/console/v1/types/control.go
+++ b/pkg/server/api/console/v1/types/control.go
@@ -45,11 +45,11 @@ func NewControlEdge(c *coredata.Control, orderBy coredata.ControlOrderField) *Co
func NewControl(c *coredata.Control) *Control {
return &Control{
- ID: c.ID,
- ReferenceID: c.ReferenceID,
- Name: c.Name,
- Description: c.Description,
- CreatedAt: c.CreatedAt,
- UpdatedAt: c.UpdatedAt,
+ ID: c.ID,
+ SectionTitle: c.SectionTitle,
+ Name: c.Name,
+ Description: c.Description,
+ CreatedAt: c.CreatedAt,
+ UpdatedAt: c.UpdatedAt,
}
}
diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go
index df4a8ec8a..d83e215e0 100644
--- a/pkg/server/api/console/v1/types/types.go
+++ b/pkg/server/api/console/v1/types/types.go
@@ -119,15 +119,15 @@ type ConnectorOrder struct {
}
type Control struct {
- ID gid.GID `json:"id"`
- ReferenceID string `json:"referenceId"`
- Name string `json:"name"`
- Description string `json:"description"`
- Framework *Framework `json:"framework"`
- Measures *MeasureConnection `json:"measures"`
- Documents *DocumentConnection `json:"documents"`
- CreatedAt time.Time `json:"createdAt"`
- UpdatedAt time.Time `json:"updatedAt"`
+ ID gid.GID `json:"id"`
+ SectionTitle string `json:"sectionTitle"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Framework *Framework `json:"framework"`
+ Measures *MeasureConnection `json:"measures"`
+ Documents *DocumentConnection `json:"documents"`
+ CreatedAt time.Time `json:"createdAt"`
+ UpdatedAt time.Time `json:"updatedAt"`
}
func (Control) IsNode() {}
@@ -168,6 +168,13 @@ type CreateControlDocumentMappingPayload struct {
DocumentEdge *DocumentEdge `json:"documentEdge"`
}
+type CreateControlInput struct {
+ FrameworkID gid.GID `json:"frameworkId"`
+ SectionTitle string `json:"sectionTitle"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+}
+
type CreateControlMeasureMappingInput struct {
ControlID gid.GID `json:"controlId"`
MeasureID gid.GID `json:"measureId"`
@@ -178,6 +185,10 @@ type CreateControlMeasureMappingPayload struct {
MeasureEdge *MeasureEdge `json:"measureEdge"`
}
+type CreateControlPayload struct {
+ ControlEdge *ControlEdge `json:"controlEdge"`
+}
+
type CreateDatumInput struct {
OrganizationID gid.GID `json:"organizationId"`
Name string `json:"name"`
@@ -406,6 +417,10 @@ type DeleteControlDocumentMappingPayload struct {
DeletedDocumentID gid.GID `json:"deletedDocumentId"`
}
+type DeleteControlInput struct {
+ ControlID gid.GID `json:"controlId"`
+}
+
type DeleteControlMeasureMappingInput struct {
ControlID gid.GID `json:"controlId"`
MeasureID gid.GID `json:"measureId"`
@@ -416,6 +431,10 @@ type DeleteControlMeasureMappingPayload struct {
DeletedMeasureID gid.GID `json:"deletedMeasureId"`
}
+type DeleteControlPayload struct {
+ DeletedControlID gid.GID `json:"deletedControlId"`
+}
+
type DeleteDatumInput struct {
DatumID gid.GID `json:"datumId"`
}
@@ -980,6 +999,17 @@ type UpdateAssetPayload struct {
Asset *Asset `json:"asset"`
}
+type UpdateControlInput struct {
+ ID gid.GID `json:"id"`
+ SectionTitle *string `json:"sectionTitle,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Description *string `json:"description,omitempty"`
+}
+
+type UpdateControlPayload struct {
+ Control *Control `json:"control"`
+}
+
type UpdateDatumInput struct {
ID gid.GID `json:"id"`
Name *string `json:"name,omitempty"`
diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go
index 3538365cf..2fcc9847c 100644
--- a/pkg/server/api/console/v1/v1_resolver.go
+++ b/pkg/server/api/console/v1/v1_resolver.go
@@ -967,6 +967,59 @@ func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.Dele
}, nil
}
+// CreateControl is the resolver for the createControl field.
+func (r *mutationResolver) CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error) {
+ svc := GetTenantService(ctx, r.proboSvc, input.FrameworkID.TenantID())
+
+ control, err := svc.Controls.Create(ctx, probo.CreateControlRequest{
+ FrameworkID: input.FrameworkID,
+ Name: input.Name,
+ Description: input.Description,
+ SectionTitle: input.SectionTitle,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("cannot create control: %w", err)
+ }
+
+ return &types.CreateControlPayload{
+ ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
+ }, nil
+}
+
+// UpdateControl is the resolver for the updateControl field.
+func (r *mutationResolver) UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error) {
+ svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
+
+ control, err := svc.Controls.Update(ctx, probo.UpdateControlRequest{
+ ID: input.ID,
+ Name: input.Name,
+ Description: input.Description,
+ SectionTitle: input.SectionTitle,
+ })
+
+ if err != nil {
+ return nil, fmt.Errorf("cannot update control: %w", err)
+ }
+
+ return &types.UpdateControlPayload{
+ Control: types.NewControl(control),
+ }, nil
+}
+
+// DeleteControl is the resolver for the deleteControl field.
+func (r *mutationResolver) DeleteControl(ctx context.Context, input types.DeleteControlInput) (*types.DeleteControlPayload, error) {
+ svc := GetTenantService(ctx, r.proboSvc, input.ControlID.TenantID())
+
+ err := svc.Controls.Delete(ctx, input.ControlID)
+ if err != nil {
+ return nil, fmt.Errorf("cannot delete control: %w", err)
+ }
+
+ return &types.DeleteControlPayload{
+ DeletedControlID: input.ControlID,
+ }, nil
+}
+
// // CreateMeasure is the resolver for the createMeasure field.
func (r *mutationResolver) CreateMeasure(ctx context.Context, input types.CreateMeasureInput) (*types.CreateMeasurePayload, error) {
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())