@@ -97,6 +97,8 @@ export const frameworkControlNodeQuery = graphql`
|
||||
name
|
||||
sectionTitle
|
||||
description
|
||||
status
|
||||
exclusionJustification
|
||||
...FrameworkControlDialogFragment
|
||||
measures(first: 100)
|
||||
@connection(key: "FrameworkGraphControl_measures") {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<9972eafa19f49d7beea0458c5b9c06d9>>
|
||||
* @generated SignedSource<<95d2adf687d1cae6938863ba004db9a8>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type ControlStatus = "EXCLUDED" | "INCLUDED";
|
||||
export type FrameworkGraphControlNodeQuery$variables = {
|
||||
controlId: string;
|
||||
};
|
||||
@@ -25,6 +26,7 @@ export type FrameworkGraphControlNodeQuery$data = {
|
||||
};
|
||||
}>;
|
||||
};
|
||||
readonly exclusionJustification?: string | null | undefined;
|
||||
readonly id?: string;
|
||||
readonly measures?: {
|
||||
readonly __id: string;
|
||||
@@ -37,6 +39,7 @@ export type FrameworkGraphControlNodeQuery$data = {
|
||||
};
|
||||
readonly name?: string;
|
||||
readonly sectionTitle?: string;
|
||||
readonly status?: ControlStatus;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"FrameworkControlDialogFragment">;
|
||||
};
|
||||
};
|
||||
@@ -92,17 +95,31 @@ v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
v7 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"name": "exclusionJustification",
|
||||
"storageKey": null
|
||||
},
|
||||
v8 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v9 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
},
|
||||
v10 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
@@ -127,7 +144,7 @@ v8 = {
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
v9 = {
|
||||
v11 = {
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
@@ -139,7 +156,7 @@ v9 = {
|
||||
}
|
||||
]
|
||||
},
|
||||
v10 = [
|
||||
v12 = [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
@@ -168,6 +185,8 @@ return {
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
{
|
||||
"args": null,
|
||||
"kind": "FragmentSpread",
|
||||
@@ -203,16 +222,16 @@ return {
|
||||
"kind": "FragmentSpread",
|
||||
"name": "LinkedMeasuresCardFragment"
|
||||
},
|
||||
(v6/*: any*/)
|
||||
(v8/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v7/*: any*/)
|
||||
(v9/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/)
|
||||
(v10/*: any*/),
|
||||
(v11/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
@@ -246,16 +265,16 @@ return {
|
||||
"kind": "FragmentSpread",
|
||||
"name": "LinkedDocumentsCardFragment"
|
||||
},
|
||||
(v6/*: any*/)
|
||||
(v8/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v7/*: any*/)
|
||||
(v9/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/)
|
||||
(v10/*: any*/),
|
||||
(v11/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -284,7 +303,7 @@ return {
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v6/*: any*/),
|
||||
(v8/*: any*/),
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
@@ -292,9 +311,11 @@ return {
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v10/*: any*/),
|
||||
"args": (v12/*: any*/),
|
||||
"concreteType": "MeasureConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "measures",
|
||||
@@ -325,22 +346,22 @@ return {
|
||||
"name": "state",
|
||||
"storageKey": null
|
||||
},
|
||||
(v6/*: any*/)
|
||||
(v8/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v7/*: any*/)
|
||||
(v9/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/)
|
||||
(v10/*: any*/),
|
||||
(v11/*: any*/)
|
||||
],
|
||||
"storageKey": "measures(first:100)"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v10/*: any*/),
|
||||
"args": (v12/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "FrameworkGraphControl_measures",
|
||||
@@ -349,7 +370,7 @@ return {
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v10/*: any*/),
|
||||
"args": (v12/*: any*/),
|
||||
"concreteType": "DocumentConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "documents",
|
||||
@@ -424,13 +445,7 @@ return {
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
}
|
||||
(v6/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -440,22 +455,22 @@ return {
|
||||
],
|
||||
"storageKey": "versions(first:1)"
|
||||
},
|
||||
(v6/*: any*/)
|
||||
(v8/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v7/*: any*/)
|
||||
(v9/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/)
|
||||
(v10/*: any*/),
|
||||
(v11/*: any*/)
|
||||
],
|
||||
"storageKey": "documents(first:100)"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v10/*: any*/),
|
||||
"args": (v12/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "FrameworkGraphControl_documents",
|
||||
@@ -472,7 +487,7 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "165ee5f4a3579e54fb7acafd6fd7ab12",
|
||||
"cacheID": "ed223aa33ef15ba2e170e8aeae990f8e",
|
||||
"id": null,
|
||||
"metadata": {
|
||||
"connection": [
|
||||
@@ -498,11 +513,11 @@ return {
|
||||
},
|
||||
"name": "FrameworkGraphControlNodeQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query FrameworkGraphControlNodeQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n sectionTitle\n description\n ...FrameworkControlDialogFragment\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\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 ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n"
|
||||
"text": "query FrameworkGraphControlNodeQuery(\n $controlId: ID!\n) {\n node(id: $controlId) {\n __typename\n ... on Control {\n id\n name\n sectionTitle\n description\n status\n exclusionJustification\n ...FrameworkControlDialogFragment\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\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 ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "a2b0b5449af380ea2843aab6ce187b75";
|
||||
(node as any).hash = "d5c8f5ce17bd227c83fec31d63a82262";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<f1a5a3800adf762d96c4e257075a0f48>>
|
||||
* @generated SignedSource<<8901b5c750861080551542d26c2681d6>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -123,6 +123,19 @@ return {
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Organization",
|
||||
"kind": "LinkedField",
|
||||
"name": "organization",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
(v2/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
@@ -169,7 +182,21 @@ return {
|
||||
"name": "sectionTitle",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/)
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "exclusionJustification",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -201,12 +228,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "cf02a37946ff1ec0d7bb2b9a24f26c2a",
|
||||
"cacheID": "29d6f638feb1bb633169abcfe083f5d2",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "FrameworkGraphNodeQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query FrameworkGraphNodeQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n name\n ...FrameworkDetailPageFragment\n }\n id\n }\n}\n\nfragment FrameworkDetailPageFragment on Framework {\n id\n name\n description\n controls(first: 250, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n }\n }\n }\n}\n"
|
||||
"text": "query FrameworkGraphNodeQuery(\n $frameworkId: ID!\n) {\n node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n name\n ...FrameworkDetailPageFragment\n }\n id\n }\n}\n\nfragment FrameworkDetailPageFragment on Framework {\n id\n name\n description\n organization {\n name\n id\n }\n controls(first: 250, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n status\n exclusionJustification\n }\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -146,8 +146,10 @@ export default function FrameworkControlPage({ queryRef }: Props) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between">
|
||||
<div className="text-xl font-medium px-[6px] py-[2px] border border-border-low rounded-lg w-max bg-active mb-3">
|
||||
{control.sectionTitle}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="text-xl font-medium px-[6px] py-[2px] border border-border-low rounded-lg w-max bg-active mb-3">
|
||||
{control.sectionTitle}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<FrameworkControlDialog
|
||||
@@ -171,25 +173,39 @@ export default function FrameworkControlPage({ queryRef }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-base">{control.name}</div>
|
||||
<LinkedMeasuresCard
|
||||
variant="card"
|
||||
measures={control.measures?.edges.map((edge) => edge.node) ?? []}
|
||||
params={{ controlId: control.id }}
|
||||
connectionId={control.measures?.__id!}
|
||||
onAttach={attachMeasure}
|
||||
onDetach={detachMeasure}
|
||||
disabled={isAttachingMeasure || isDetachingMeasure}
|
||||
/>
|
||||
<LinkedDocumentsCard
|
||||
variant="card"
|
||||
documents={control.documents?.edges.map((edge) => edge.node) ?? []}
|
||||
params={{ controlId: control.id }}
|
||||
connectionId={control.documents?.__id!}
|
||||
onAttach={attachDocument}
|
||||
onDetach={detachDocument}
|
||||
disabled={isAttachingDocument || isDetachingDocument}
|
||||
{control.status === "EXCLUDED" && (
|
||||
<div className="bg-danger border border-border-danger rounded-lg p-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="font-medium text-txt-danger">
|
||||
{__("This control is excluded")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<strong>{__("Justification:")}</strong> {control.exclusionJustification || __("No justification provided")}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={control.status === "EXCLUDED" ? "opacity-60" : ""}>
|
||||
<div className="text-base">{control.name}</div>
|
||||
<LinkedMeasuresCard
|
||||
variant="card"
|
||||
measures={control.measures?.edges.map((edge) => edge.node) ?? []}
|
||||
params={{ controlId: control.id }}
|
||||
connectionId={control.measures?.__id!}
|
||||
onAttach={attachMeasure}
|
||||
onDetach={detachMeasure}
|
||||
disabled={isAttachingMeasure || isDetachingMeasure}
|
||||
/>
|
||||
<LinkedDocumentsCard
|
||||
variant="card"
|
||||
documents={control.documents?.edges.map((edge) => edge.node) ?? []}
|
||||
params={{ controlId: control.id }}
|
||||
connectionId={control.documents?.__id!}
|
||||
onAttach={attachDocument}
|
||||
onDetach={detachDocument}
|
||||
disabled={isAttachingDocument || isDetachingDocument}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ const frameworkDetailFragment = graphql`
|
||||
id
|
||||
name
|
||||
description
|
||||
organization {
|
||||
name
|
||||
}
|
||||
controls(first: 250, orderBy: { field: SECTION_TITLE, direction: ASC }) {
|
||||
__id
|
||||
edges {
|
||||
@@ -43,6 +46,8 @@ const frameworkDetailFragment = graphql`
|
||||
id
|
||||
sectionTitle
|
||||
name
|
||||
status
|
||||
exclusionJustification
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,7 +145,7 @@ export default function FrameworkDetailPage(props: Props) {
|
||||
if (data.generateFrameworkStateOfApplicability?.data) {
|
||||
const link = window.document.createElement("a");
|
||||
link.href = data.generateFrameworkStateOfApplicability.data;
|
||||
link.download = `${framework.name}-SOA.xlsx`;
|
||||
link.download = `${framework.organization.name}-${framework.name}-SOA.xlsx`;
|
||||
window.document.body.appendChild(link);
|
||||
link.click();
|
||||
window.document.body.removeChild(link);
|
||||
@@ -169,6 +174,7 @@ export default function FrameworkDetailPage(props: Props) {
|
||||
key={control.id}
|
||||
id={control.sectionTitle}
|
||||
description={control.name}
|
||||
excluded={control.status === "EXCLUDED"}
|
||||
to={`/organizations/${organizationId}/frameworks/${framework.id}/controls/${control.id}`}
|
||||
active={selectedControl?.id === control.id}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<d3c93020e1d7d125fc2055a650dd62e3>>
|
||||
* @generated SignedSource<<c6e55821a322dceae5408ac3898cfa48>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,21 +9,27 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type ControlStatus = "EXCLUDED" | "INCLUDED";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type FrameworkDetailPageFragment$data = {
|
||||
readonly controls: {
|
||||
readonly __id: string;
|
||||
readonly edges: ReadonlyArray<{
|
||||
readonly node: {
|
||||
readonly exclusionJustification: string | null | undefined;
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly sectionTitle: string;
|
||||
readonly status: ControlStatus;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
readonly description: string;
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly organization: {
|
||||
readonly name: string;
|
||||
};
|
||||
readonly " $fragmentType": "FrameworkDetailPageFragment";
|
||||
};
|
||||
export type FrameworkDetailPageFragment$key = {
|
||||
@@ -61,6 +67,18 @@ return {
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Organization",
|
||||
"kind": "LinkedField",
|
||||
"name": "organization",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
@@ -107,7 +125,21 @@ return {
|
||||
"name": "sectionTitle",
|
||||
"storageKey": null
|
||||
},
|
||||
(v1/*: any*/)
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "exclusionJustification",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -135,6 +167,6 @@ return {
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "ad59b1c61a01fdcb5afbf0ee920a46bb";
|
||||
(node as any).hash = "c31fd5c0f675d2524f736d69c4ebebe3";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
DialogFooter,
|
||||
Input,
|
||||
Textarea,
|
||||
Option,
|
||||
useDialogRef,
|
||||
} from "@probo/ui";
|
||||
import type { ReactNode } from "react";
|
||||
@@ -16,6 +17,7 @@ import type { FrameworkControlDialogFragment$key } from "./__generated__/Framewo
|
||||
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
||||
import { z } from "zod";
|
||||
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
|
||||
import { ControlledSelect } from "/components/form/ControlledField";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
@@ -30,6 +32,8 @@ const controlFragment = graphql`
|
||||
name
|
||||
description
|
||||
sectionTitle
|
||||
status
|
||||
exclusionJustification
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -62,6 +66,16 @@ const schema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
sectionTitle: z.string(),
|
||||
status: z.enum(["INCLUDED", "EXCLUDED"]),
|
||||
exclusionJustification: z.string().optional(),
|
||||
}).refine((data) => {
|
||||
if (data.status === "EXCLUDED") {
|
||||
return data.exclusionJustification && data.exclusionJustification.trim().length > 0;
|
||||
}
|
||||
return true;
|
||||
}, {
|
||||
message: "Exclusion justification is required when status is excluded",
|
||||
path: ["exclusionJustification"],
|
||||
});
|
||||
|
||||
export function FrameworkControlDialog(props: Props) {
|
||||
@@ -77,14 +91,19 @@ export function FrameworkControlDialog(props: Props) {
|
||||
successMessage: __("Control created successfully."),
|
||||
errorMessage: __("Failed to create control. Please try again."),
|
||||
});
|
||||
const { control, handleSubmit, register, reset } = useFormWithSchema(schema, {
|
||||
const { control, handleSubmit, register, reset, watch } = useFormWithSchema(schema, {
|
||||
defaultValues: {
|
||||
name: frameworkControl?.name ?? "",
|
||||
description: frameworkControl?.description ?? "",
|
||||
sectionTitle: frameworkControl?.sectionTitle ?? "",
|
||||
status: frameworkControl?.status ?? "INCLUDED",
|
||||
exclusionJustification: frameworkControl?.exclusionJustification ?? "",
|
||||
},
|
||||
});
|
||||
|
||||
const statusValue = watch("status");
|
||||
const showExclusionJustification = statusValue === "EXCLUDED";
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
if (frameworkControl) {
|
||||
// Update the control
|
||||
@@ -95,6 +114,8 @@ export function FrameworkControlDialog(props: Props) {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
sectionTitle: data.sectionTitle,
|
||||
status: data.status,
|
||||
exclusionJustification: data.status === "EXCLUDED" ? data.exclusionJustification : null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -107,6 +128,8 @@ export function FrameworkControlDialog(props: Props) {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
sectionTitle: data.sectionTitle,
|
||||
status: data.status,
|
||||
exclusionJustification: data.status === "EXCLUDED" ? data.exclusionJustification : null,
|
||||
},
|
||||
connections: [props.connectionId!],
|
||||
},
|
||||
@@ -148,11 +171,26 @@ export function FrameworkControlDialog(props: Props) {
|
||||
<Textarea
|
||||
id="content"
|
||||
variant="ghost"
|
||||
required
|
||||
autogrow
|
||||
placeholder={__("Add description")}
|
||||
{...register("description")}
|
||||
/>
|
||||
<ControlledSelect
|
||||
control={control}
|
||||
name="status"
|
||||
placeholder={__("Select status")}
|
||||
>
|
||||
<Option value="INCLUDED">{__("Included")}</Option>
|
||||
<Option value="EXCLUDED">{__("Excluded")}</Option>
|
||||
</ControlledSelect>
|
||||
{showExclusionJustification && (
|
||||
<Input
|
||||
id="exclusionJustification"
|
||||
variant="bordered"
|
||||
placeholder={__("Reason for exclusion")}
|
||||
{...register("exclusionJustification")}
|
||||
/>
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<Button type="submit" disabled={isMutating}>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<3a14264d0b2b45f62b29aaefcf7e2c7f>>
|
||||
* @generated SignedSource<<5c976aa26b87b4f77dfcfeba71d3bbe3>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -10,11 +10,14 @@
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type ControlStatus = "EXCLUDED" | "INCLUDED";
|
||||
export type CreateControlInput = {
|
||||
description: string;
|
||||
exclusionJustification?: string | null | undefined;
|
||||
frameworkId: string;
|
||||
name: string;
|
||||
sectionTitle: string;
|
||||
status?: ControlStatus | null | undefined;
|
||||
};
|
||||
export type FrameworkControlDialogCreateMutation$variables = {
|
||||
connections: ReadonlyArray<string>;
|
||||
@@ -164,6 +167,20 @@ return {
|
||||
"kind": "ScalarField",
|
||||
"name": "sectionTitle",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "exclusionJustification",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
@@ -193,12 +210,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "87e5bd454a1adfe2f67ecb006e21e115",
|
||||
"cacheID": "3df2d5a0a51c774ccf711423e947093d",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "FrameworkControlDialogCreateMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation FrameworkControlDialogCreateMutation(\n $input: CreateControlInput!\n) {\n createControl(input: $input) {\n controlEdge {\n node {\n ...FrameworkControlDialogFragment\n id\n }\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n}\n"
|
||||
"text": "mutation FrameworkControlDialogCreateMutation(\n $input: CreateControlInput!\n) {\n createControl(input: $input) {\n controlEdge {\n node {\n ...FrameworkControlDialogFragment\n id\n }\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<6052cc5cfc8407e61eaa1a842e976a90>>
|
||||
* @generated SignedSource<<8b52b1e3fd91d74821361d9ae652d9bd>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,12 +9,15 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type ControlStatus = "EXCLUDED" | "INCLUDED";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type FrameworkControlDialogFragment$data = {
|
||||
readonly description: string;
|
||||
readonly exclusionJustification: string | null | undefined;
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly sectionTitle: string;
|
||||
readonly status: ControlStatus;
|
||||
readonly " $fragmentType": "FrameworkControlDialogFragment";
|
||||
};
|
||||
export type FrameworkControlDialogFragment$key = {
|
||||
@@ -55,12 +58,26 @@ const node: ReaderFragment = {
|
||||
"kind": "ScalarField",
|
||||
"name": "sectionTitle",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "exclusionJustification",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Control",
|
||||
"abstractKey": null
|
||||
};
|
||||
|
||||
(node as any).hash = "ff1a543d6a2225d9bacfe7db3b142f1a";
|
||||
(node as any).hash = "856a8302abf15737b6a4d4316b77f8cc";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<250267db99194edcb6fa20053d1d82df>>
|
||||
* @generated SignedSource<<7d04994d5cabbbfc12f82754e8da0d83>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -10,11 +10,14 @@
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type ControlStatus = "EXCLUDED" | "INCLUDED";
|
||||
export type UpdateControlInput = {
|
||||
description?: string | null | undefined;
|
||||
exclusionJustification?: string | null | undefined;
|
||||
id: string;
|
||||
name?: string | null | undefined;
|
||||
sectionTitle?: string | null | undefined;
|
||||
status?: ControlStatus | null | undefined;
|
||||
};
|
||||
export type FrameworkControlDialogUpdateMutation$variables = {
|
||||
input: UpdateControlInput;
|
||||
@@ -133,6 +136,20 @@ return {
|
||||
"kind": "ScalarField",
|
||||
"name": "sectionTitle",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "exclusionJustification",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
@@ -143,12 +160,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "442b248ff35d4448c66052906ea5fff1",
|
||||
"cacheID": "cee79ce9185400bad478453c44930dd6",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "FrameworkControlDialogUpdateMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation FrameworkControlDialogUpdateMutation(\n $input: UpdateControlInput!\n) {\n updateControl(input: $input) {\n control {\n ...FrameworkControlDialogFragment\n id\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n}\n"
|
||||
"text": "mutation FrameworkControlDialogUpdateMutation(\n $input: UpdateControlInput!\n) {\n updateControl(input: $input) {\n control {\n ...FrameworkControlDialogFragment\n id\n }\n }\n}\n\nfragment FrameworkControlDialogFragment on Control {\n id\n name\n description\n sectionTitle\n status\n exclusionJustification\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user