From 61b1a24149822cd254a97abc8b2e98f11bbafd78 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 27 May 2025 12:32:04 +0200 Subject: [PATCH] Add policies signature history Signed-off-by: Bryan Frimin Signed-off-by: Sacha Al Himdani --- apps/console2/package.json | 2 +- apps/console2/relay.config.json | 3 +- .../src/components/form/PeopleSelect.tsx | 29 +- ...MeasureLinkDialogCreateMutation.graphql.ts | 4 +- .../MeasureLinkDialogQuery.graphql.ts | 4 +- .../usePolicyFormFragment.graphql.ts | 76 ----- .../useRiskFormFragment.graphql.ts | 4 +- apps/console2/src/hooks/graph/PeopleGraph.ts | 31 ++ .../PeopleGraphQuery.graphql.ts} | 32 ++- .../PolicyGraphListQuery.graphql.ts | 49 +--- .../PolicyGraphNodeQuery.graphql.ts | 167 +++++++---- .../RiskGraphFragment.graphql.ts | 4 +- .../RiskGraphNodeQuery.graphql.ts | 4 +- .../__generated__/RisksListQuery.graphql.ts | 6 +- .../MeasuresPageFragment.graphql.ts | 4 +- .../MeasuresPageImportMutation.graphql.ts | 4 +- .../organizations/policies/PoliciesPage.tsx | 8 +- .../organizations/policies/PolicyPage.tsx | 16 +- .../PoliciesPageListFragment.graphql.ts | 33 +-- .../PoliciesPageRowFragment.graphql.ts | 6 +- ...reateDraftPolicyVersionMutation.graphql.ts | 135 --------- .../PolicyPagePolicyFragment.graphql.ts | 169 ++++++----- .../dialogs/PolicySignaturesDialog.tsx | 267 ++++++++++++++++++ .../dialogs/PolicyVersionHistoryDialog.tsx | 41 ++- ...Dialog_requestSignatureMutation.graphql.ts | 254 +++++++++++++++++ ...olicySignaturesDialog_signature.graphql.ts | 96 +++++++ .../PolicySignaturesDialog_version.graphql.ts | 67 +++++ ...icyVersionHistoryDialogFragment.graphql.ts | 4 +- ...dateVersionDialogCreateMutation.graphql.ts | 6 +- .../FormRiskDialogMutation.graphql.ts | 4 +- ...ormRiskDialogUpdateRiskMutation.graphql.ts | 4 +- .../RiskDetailPageQuery.graphql.ts | 262 ----------------- .../RisksPageDeleteMutation.graphql.ts | 132 --------- .../RiskMeasuresTabFragment.graphql.ts | 4 +- .../__generated__/VendorsPageQuery.graphql.ts | 6 +- packages/i18n/TranslatorProvider.tsx | 37 ++- .../ui/src/Atoms/Icons/IconCircleCheck.tsx | 1 - packages/ui/src/Atoms/Icons/circle-check.svg | 3 +- packages/ui/src/Atoms/Toasts/Toasts.tsx | 58 +++- .../Badge/PolicyVersionBadge.stories.tsx | 21 ++ .../Molecules/Badge/PolicyVersionBadge.tsx | 15 + packages/ui/src/Molecules/Dialog/Dialog.tsx | 19 +- packages/ui/src/index.ts | 1 + packages/ui/src/theme.css | 2 +- relay.config.json | 6 - 45 files changed, 1154 insertions(+), 946 deletions(-) delete mode 100644 apps/console2/src/hooks/forms/__generated__/usePolicyFormFragment.graphql.ts create mode 100644 apps/console2/src/hooks/graph/PeopleGraph.ts rename apps/console2/src/{components/form/__generated__/PeopleSelectQuery.graphql.ts => hooks/graph/__generated__/PeopleGraphQuery.graphql.ts} (75%) delete mode 100644 apps/console2/src/pages/organizations/policies/__generated__/PolicyPageCreateDraftPolicyVersionMutation.graphql.ts create mode 100644 apps/console2/src/pages/organizations/policies/dialogs/PolicySignaturesDialog.tsx create mode 100644 apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_requestSignatureMutation.graphql.ts create mode 100644 apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_signature.graphql.ts create mode 100644 apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_version.graphql.ts delete mode 100644 apps/console2/src/pages/organizations/risks/__generated__/RiskDetailPageQuery.graphql.ts delete mode 100644 apps/console2/src/pages/organizations/risks/__generated__/RisksPageDeleteMutation.graphql.ts create mode 100644 packages/ui/src/Molecules/Badge/PolicyVersionBadge.stories.tsx create mode 100644 packages/ui/src/Molecules/Badge/PolicyVersionBadge.tsx delete mode 100644 relay.config.json diff --git a/apps/console2/package.json b/apps/console2/package.json index b49abeee9..1476a64db 100644 --- a/apps/console2/package.json +++ b/apps/console2/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "relay": "find src -type d -name \"__generated\" -exec rm -rf {} + && npx relay-compiler", + "relay": "find src -type d -name \"__generated__\" -exec rm -rf {} + && npx relay-compiler ./relay.config.json", "build": "tsc -b && vite build", "lint": "eslint .", "check": "tsc --noEmit -p tsconfig.app.json", diff --git a/apps/console2/relay.config.json b/apps/console2/relay.config.json index 4e160c620..6c55a8183 100644 --- a/apps/console2/relay.config.json +++ b/apps/console2/relay.config.json @@ -2,5 +2,6 @@ "src": "./src", "schema": "../../pkg/server/api/console/v1/schema.graphql", "language": "typescript", - "eagerEsModules": true + "eagerEsModules": true, + "noFutureProofEnums": true } diff --git a/apps/console2/src/components/form/PeopleSelect.tsx b/apps/console2/src/components/form/PeopleSelect.tsx index 3702c10fc..676d2b422 100644 --- a/apps/console2/src/components/form/PeopleSelect.tsx +++ b/apps/console2/src/components/form/PeopleSelect.tsx @@ -1,27 +1,8 @@ import { Avatar, Option, Select } from "@probo/ui"; import { Suspense } from "react"; -import { useLazyLoadQuery } from "react-relay"; -import { graphql } from "relay-runtime"; -import type { PeopleSelectQuery as PeopleSelectQueryType } from "./__generated__/PeopleSelectQuery.graphql"; import { useTranslate } from "@probo/i18n"; -import { Controller, type Control } from "react-hook-form"; - -const peopleQuery = graphql` - query PeopleSelectQuery($organizationId: ID!) { - organization: node(id: $organizationId) { - ... on Organization { - peoples(first: 100, orderBy: { direction: ASC, field: CREATED_AT }) { - edges { - node { - id - fullName - } - } - } - } - } - } -`; +import { type Control, Controller } from "react-hook-form"; +import { usePeople } from "/hooks/graph/PeopleGraph.ts"; export function PeopleSelect({ organization, @@ -55,11 +36,7 @@ function PeopleSelectWithQuery({ control: Control; }) { const { __ } = useTranslate(); - const data = useLazyLoadQuery(peopleQuery, { - organizationId: organization, - }); - - const people = data.organization?.peoples?.edges.map((edge) => edge.node); + const people = usePeople(organization); return ( <> diff --git a/apps/console2/src/components/risks/__generated__/MeasureLinkDialogCreateMutation.graphql.ts b/apps/console2/src/components/risks/__generated__/MeasureLinkDialogCreateMutation.graphql.ts index 23d412e47..18c6385d0 100644 --- a/apps/console2/src/components/risks/__generated__/MeasureLinkDialogCreateMutation.graphql.ts +++ b/apps/console2/src/components/risks/__generated__/MeasureLinkDialogCreateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<391c4db090caa19c60582c18d426764a>> + * @generated SignedSource<<043e8cc5beda1ac8949a7c02adcff4bf>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED" | "%future added value"; +export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED"; export type CreateRiskMeasureMappingInput = { measureId: string; riskId: string; diff --git a/apps/console2/src/components/risks/__generated__/MeasureLinkDialogQuery.graphql.ts b/apps/console2/src/components/risks/__generated__/MeasureLinkDialogQuery.graphql.ts index b3a5b7422..cde38a9e4 100644 --- a/apps/console2/src/components/risks/__generated__/MeasureLinkDialogQuery.graphql.ts +++ b/apps/console2/src/components/risks/__generated__/MeasureLinkDialogQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<746421c9f8fc0c80ed1fd5643b3bbae8>> + * @generated SignedSource<<6a9b2c4428ed2255dda81771894c0c6c>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED" | "%future added value"; +export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED"; export type MeasureLinkDialogQuery$variables = { organizationId: string; }; diff --git a/apps/console2/src/hooks/forms/__generated__/usePolicyFormFragment.graphql.ts b/apps/console2/src/hooks/forms/__generated__/usePolicyFormFragment.graphql.ts deleted file mode 100644 index dae848b09..000000000 --- a/apps/console2/src/hooks/forms/__generated__/usePolicyFormFragment.graphql.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @generated SignedSource<<3ffcc7618d81b47e39ca5731fe75e2ed>> - * @lightSyntaxTransform - * @nogrep - */ - -/* tslint:disable */ -/* eslint-disable */ -// @ts-nocheck - -import { ReaderFragment } from 'relay-runtime'; -import { FragmentRefs } from "relay-runtime"; -export type usePolicyFormFragment$data = { - readonly description: string; - readonly id: string; - readonly owner: { - readonly id: string; - }; - readonly title: string; - readonly " $fragmentType": "usePolicyFormFragment"; -}; -export type usePolicyFormFragment$key = { - readonly " $data"?: usePolicyFormFragment$data; - readonly " $fragmentSpreads": FragmentRefs<"usePolicyFormFragment">; -}; - -const node: ReaderFragment = (function(){ -var v0 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null -}; -return { - "argumentDefinitions": [], - "kind": "Fragment", - "metadata": null, - "name": "usePolicyFormFragment", - "selections": [ - (v0/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "title", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "description", - "storageKey": null - }, - { - "alias": null, - "args": null, - "concreteType": "People", - "kind": "LinkedField", - "name": "owner", - "plural": false, - "selections": [ - (v0/*: any*/) - ], - "storageKey": null - } - ], - "type": "Policy", - "abstractKey": null -}; -})(); - -(node as any).hash = "619d6845e45fb8c052a8989ea546414d"; - -export default node; diff --git a/apps/console2/src/hooks/forms/__generated__/useRiskFormFragment.graphql.ts b/apps/console2/src/hooks/forms/__generated__/useRiskFormFragment.graphql.ts index 9579ea90a..fcb7ea998 100644 --- a/apps/console2/src/hooks/forms/__generated__/useRiskFormFragment.graphql.ts +++ b/apps/console2/src/hooks/forms/__generated__/useRiskFormFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<6cf0470d3c2e5d8d9d6ca52bf3375026>> + * @generated SignedSource<<38b7fae585eb2c09409935db8ad3cfe9>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED" | "%future added value"; +export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED"; import { FragmentRefs } from "relay-runtime"; export type useRiskFormFragment$data = { readonly category: string; diff --git a/apps/console2/src/hooks/graph/PeopleGraph.ts b/apps/console2/src/hooks/graph/PeopleGraph.ts new file mode 100644 index 000000000..0f7ae0bc7 --- /dev/null +++ b/apps/console2/src/hooks/graph/PeopleGraph.ts @@ -0,0 +1,31 @@ +import { graphql } from "relay-runtime"; +import type { PeopleGraphQuery } from "./__generated__/PeopleGraphQuery.graphql"; +import { useLazyLoadQuery } from "react-relay"; +import { useMemo } from "react"; + +const peopleQuery = graphql` + query PeopleGraphQuery($organizationId: ID!) { + organization: node(id: $organizationId) { + ... on Organization { + peoples(first: 100, orderBy: { direction: ASC, field: CREATED_AT }) { + edges { + node { + id + fullName + primaryEmailAddress + } + } + } + } + } + } +`; + +export function usePeople(organizationId: string) { + const data = useLazyLoadQuery(peopleQuery, { + organizationId: organizationId, + }); + return useMemo(() => { + return data.organization?.peoples?.edges.map((edge) => edge.node) ?? []; + }, [data]); +} diff --git a/apps/console2/src/components/form/__generated__/PeopleSelectQuery.graphql.ts b/apps/console2/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts similarity index 75% rename from apps/console2/src/components/form/__generated__/PeopleSelectQuery.graphql.ts rename to apps/console2/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts index 24b0fbc67..e48d43d05 100644 --- a/apps/console2/src/components/form/__generated__/PeopleSelectQuery.graphql.ts +++ b/apps/console2/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<758e3ece2d7d1d52975886d41b6ae905>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,24 +9,25 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type PeopleSelectQuery$variables = { +export type PeopleGraphQuery$variables = { organizationId: string; }; -export type PeopleSelectQuery$data = { +export type PeopleGraphQuery$data = { readonly organization: { readonly peoples?: { readonly edges: ReadonlyArray<{ readonly node: { readonly fullName: string; readonly id: string; + readonly primaryEmailAddress: string; }; }>; }; }; }; -export type PeopleSelectQuery = { - response: PeopleSelectQuery$data; - variables: PeopleSelectQuery$variables; +export type PeopleGraphQuery = { + response: PeopleGraphQuery$data; + variables: PeopleGraphQuery$variables; }; const node: ConcreteRequest = (function(){ @@ -99,6 +100,13 @@ v3 = { "kind": "ScalarField", "name": "fullName", "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "primaryEmailAddress", + "storageKey": null } ], "storageKey": null @@ -118,7 +126,7 @@ return { "argumentDefinitions": (v0/*: any*/), "kind": "Fragment", "metadata": null, - "name": "PeopleSelectQuery", + "name": "PeopleGraphQuery", "selections": [ { "alias": "organization", @@ -140,7 +148,7 @@ return { "operation": { "argumentDefinitions": (v0/*: any*/), "kind": "Operation", - "name": "PeopleSelectQuery", + "name": "PeopleGraphQuery", "selections": [ { "alias": "organization", @@ -165,16 +173,16 @@ return { ] }, "params": { - "cacheID": "4e58fc42b352af93ba7067921531af3e", + "cacheID": "cf76244f6aaa0c573bdeb7bf118ad2a3", "id": null, "metadata": {}, - "name": "PeopleSelectQuery", + "name": "PeopleGraphQuery", "operationKind": "query", - "text": "query PeopleSelectQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n peoples(first: 100, orderBy: {direction: ASC, field: CREATED_AT}) {\n edges {\n node {\n id\n fullName\n }\n }\n }\n }\n id\n }\n}\n" + "text": "query PeopleGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n peoples(first: 100, orderBy: {direction: ASC, field: CREATED_AT}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "77119544e99cf9dd74d8a0f446df108e"; +(node as any).hash = "11220f45320400c451abeaf7479a8e47"; export default node; diff --git a/apps/console2/src/hooks/graph/__generated__/PolicyGraphListQuery.graphql.ts b/apps/console2/src/hooks/graph/__generated__/PolicyGraphListQuery.graphql.ts index fa785c492..6ce5883a5 100644 --- a/apps/console2/src/hooks/graph/__generated__/PolicyGraphListQuery.graphql.ts +++ b/apps/console2/src/hooks/graph/__generated__/PolicyGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<26cd4feab2589e8b641b339c977905a3>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -53,20 +53,11 @@ v3 = { "name": "__typename", "storageKey": null }, -v4 = { - "kind": "Literal", - "name": "first", - "value": 100 -}, -v5 = [ - (v4/*: any*/), +v4 = [ { "kind": "Literal", - "name": "orderBy", - "value": { - "direction": "DESC", - "field": "CREATED_AT" - } + "name": "first", + "value": 100 } ]; return { @@ -118,7 +109,7 @@ return { "selections": [ { "alias": null, - "args": (v5/*: any*/), + "args": (v4/*: any*/), "concreteType": "PolicyConnection", "kind": "LinkedField", "name": "policies", @@ -221,9 +212,7 @@ return { }, { "alias": null, - "args": [ - (v4/*: any*/) - ], + "args": (v4/*: any*/), "concreteType": "PolicyVersionSignatureConnection", "kind": "LinkedField", "name": "signatures", @@ -306,20 +295,6 @@ return { "kind": "ScalarField", "name": "hasNextPage", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "hasPreviousPage", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "startCursor", - "storageKey": null } ], "storageKey": null @@ -337,14 +312,12 @@ return { ] } ], - "storageKey": "policies(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})" + "storageKey": "policies(first:100)" }, { "alias": null, - "args": (v5/*: any*/), - "filters": [ - "orderBy" - ], + "args": (v4/*: any*/), + "filters": null, "handle": "connection", "key": "PoliciesPageFragment_policies", "kind": "LinkedHandle", @@ -360,12 +333,12 @@ return { ] }, "params": { - "cacheID": "838223ae76604de3893662f5a496c1d3", + "cacheID": "b0b3546b418ff2cfd5dd7678d3b0be14", "id": null, "metadata": {}, "name": "PolicyGraphListQuery", "operationKind": "query", - "text": "query PolicyGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...PoliciesPageListFragment\n }\n}\n\nfragment PoliciesPageListFragment on Organization {\n policies(first: 100, orderBy: {direction: DESC, field: CREATED_AT}) {\n edges {\n node {\n id\n ...PoliciesPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment PoliciesPageRowFragment on Policy {\n id\n title\n description\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n}\n" + "text": "query PolicyGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...PoliciesPageListFragment\n }\n}\n\nfragment PoliciesPageListFragment on Organization {\n policies(first: 100) {\n edges {\n node {\n id\n ...PoliciesPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment PoliciesPageRowFragment on Policy {\n id\n title\n description\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n}\n" } }; })(); diff --git a/apps/console2/src/hooks/graph/__generated__/PolicyGraphNodeQuery.graphql.ts b/apps/console2/src/hooks/graph/__generated__/PolicyGraphNodeQuery.graphql.ts index e974f4161..010b74867 100644 --- a/apps/console2/src/hooks/graph/__generated__/PolicyGraphNodeQuery.graphql.ts +++ b/apps/console2/src/hooks/graph/__generated__/PolicyGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -65,7 +65,58 @@ v5 = [ "name": "first", "value": 20 } -]; +], +v6 = [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } +], +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null +}, +v9 = { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] +}; return { "fragment": { "argumentDefinitions": (v0/*: any*/), @@ -201,13 +252,7 @@ return { }, { "alias": null, - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100 - } - ], + "args": (v6/*: any*/), "concreteType": "PolicyVersionSignatureConnection", "kind": "LinkedField", "name": "signatures", @@ -236,16 +281,63 @@ return { "kind": "ScalarField", "name": "state", "storageKey": null - } + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "signedBy", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "primaryEmailAddress", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "signedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "requestedAt", + "storageKey": null + }, + (v2/*: any*/) ], "storageKey": null - } + }, + (v7/*: any*/) ], "storageKey": null - } + }, + (v8/*: any*/), + (v9/*: any*/) ], "storageKey": "signatures(first:100)" }, + { + "alias": null, + "args": (v6/*: any*/), + "filters": null, + "handle": "connection", + "key": "PolicyPage_signatures", + "kind": "LinkedHandle", + "name": "signatures" + }, { "alias": null, "args": null, @@ -270,53 +362,12 @@ return { ], "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "cursor", - "storageKey": null - } + (v7/*: any*/) ], "storageKey": null }, - { - "alias": null, - "args": null, - "concreteType": "PageInfo", - "kind": "LinkedField", - "name": "pageInfo", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "endCursor", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "hasNextPage", - "storageKey": null - } - ], - "storageKey": null - }, - { - "kind": "ClientExtension", - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__id", - "storageKey": null - } - ] - } + (v8/*: any*/), + (v9/*: any*/) ], "storageKey": "versions(first:20)" }, @@ -339,12 +390,12 @@ return { ] }, "params": { - "cacheID": "e3a62b161b9fce47237c98f90a5d6d2e", + "cacheID": "e9c0e78ebbf62684edbfa11ac1ee5d25", "id": null, "metadata": {}, "name": "PolicyGraphNodeQuery", "operationKind": "query", - "text": "query PolicyGraphNodeQuery(\n $policyId: ID!\n) {\n node(id: $policyId) {\n __typename\n ... on Policy {\n ...PolicyPagePolicyFragment\n }\n id\n }\n}\n\nfragment PolicyPagePolicyFragment on Policy {\n id\n title\n owner {\n id\n fullName\n }\n versions(first: 20) {\n edges {\n node {\n id\n content\n status\n publishedAt\n version\n updatedAt\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n ...PolicyVersionHistoryDialogFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment PolicyVersionHistoryDialogFragment on PolicyVersion {\n id\n version\n status\n content\n changelog\n publishedAt\n updatedAt\n publishedBy {\n fullName\n id\n }\n}\n" + "text": "query PolicyGraphNodeQuery(\n $policyId: ID!\n) {\n node(id: $policyId) {\n __typename\n ... on Policy {\n ...PolicyPagePolicyFragment\n }\n id\n }\n}\n\nfragment PolicyPagePolicyFragment on Policy {\n id\n title\n owner {\n id\n fullName\n }\n versions(first: 20) {\n edges {\n node {\n id\n content\n status\n publishedAt\n version\n updatedAt\n signatures(first: 100) {\n edges {\n node {\n id\n state\n signedBy {\n id\n }\n ...PolicySignaturesDialog_signature\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n ...PolicyVersionHistoryDialogFragment\n ...PolicySignaturesDialog_version\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment PolicySignaturesDialog_signature on PolicyVersionSignature {\n id\n state\n signedAt\n requestedAt\n signedBy {\n fullName\n primaryEmailAddress\n id\n }\n}\n\nfragment PolicySignaturesDialog_version on PolicyVersion {\n version\n status\n publishedAt\n updatedAt\n}\n\nfragment PolicyVersionHistoryDialogFragment on PolicyVersion {\n id\n version\n status\n content\n changelog\n publishedAt\n updatedAt\n publishedBy {\n fullName\n id\n }\n}\n" } }; })(); diff --git a/apps/console2/src/hooks/graph/__generated__/RiskGraphFragment.graphql.ts b/apps/console2/src/hooks/graph/__generated__/RiskGraphFragment.graphql.ts index 9a8f95c11..4588db048 100644 --- a/apps/console2/src/hooks/graph/__generated__/RiskGraphFragment.graphql.ts +++ b/apps/console2/src/hooks/graph/__generated__/RiskGraphFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<352ca1fa13e246dd48eb0cd346a251ef>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED" | "%future added value"; +export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED"; import { FragmentRefs } from "relay-runtime"; export type RiskGraphFragment$data = { readonly id: string; diff --git a/apps/console2/src/hooks/graph/__generated__/RiskGraphNodeQuery.graphql.ts b/apps/console2/src/hooks/graph/__generated__/RiskGraphNodeQuery.graphql.ts index 2e977e063..667a1bc09 100644 --- a/apps/console2/src/hooks/graph/__generated__/RiskGraphNodeQuery.graphql.ts +++ b/apps/console2/src/hooks/graph/__generated__/RiskGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3485aabb6e5e1992e2f0c089deaf4b2d>> + * @generated SignedSource<<18341e1d2a7f480ad73ef32506121c5e>> * @lightSyntaxTransform * @nogrep */ @@ -10,7 +10,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; -export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED" | "%future added value"; +export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED"; export type RiskGraphNodeQuery$variables = { riskId: string; }; diff --git a/apps/console2/src/hooks/graph/__generated__/RisksListQuery.graphql.ts b/apps/console2/src/hooks/graph/__generated__/RisksListQuery.graphql.ts index 14392032f..0a6f03f93 100644 --- a/apps/console2/src/hooks/graph/__generated__/RisksListQuery.graphql.ts +++ b/apps/console2/src/hooks/graph/__generated__/RisksListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<5cce23056dd540654c65719414023e64>> + * @generated SignedSource<<7c5151b921734cd14b58af145eba7267>> * @lightSyntaxTransform * @nogrep */ @@ -10,8 +10,8 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; -export type OrderDirection = "ASC" | "DESC" | "%future added value"; -export type RiskOrderField = "CATEGORY" | "CREATED_AT" | "INITIAL_RISK_SCORE" | "NAME" | "RESIDUAL_RISK_SCORE" | "TREATMENT" | "UPDATED_AT" | "%future added value"; +export type OrderDirection = "ASC" | "DESC"; +export type RiskOrderField = "CATEGORY" | "CREATED_AT" | "INITIAL_RISK_SCORE" | "NAME" | "RESIDUAL_RISK_SCORE" | "TREATMENT" | "UPDATED_AT"; export type RiskOrder = { direction: OrderDirection; field: RiskOrderField; diff --git a/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageFragment.graphql.ts b/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageFragment.graphql.ts index 866dfb223..179458bed 100644 --- a/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageFragment.graphql.ts +++ b/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED" | "%future added value"; +export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED"; import { FragmentRefs } from "relay-runtime"; export type MeasuresPageFragment$data = { readonly measures: { diff --git a/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageImportMutation.graphql.ts b/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageImportMutation.graphql.ts index 06bf10ad8..65721978c 100644 --- a/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageImportMutation.graphql.ts +++ b/apps/console2/src/pages/organizations/measures/__generated__/MeasuresPageImportMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<5a6e0e680ef636cf776a56f490733aee>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED" | "%future added value"; +export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED"; export type ImportMeasureInput = { file: any; organizationId: string; diff --git a/apps/console2/src/pages/organizations/policies/PoliciesPage.tsx b/apps/console2/src/pages/organizations/policies/PoliciesPage.tsx index 54f9f338d..3e4e29b69 100644 --- a/apps/console2/src/pages/organizations/policies/PoliciesPage.tsx +++ b/apps/console2/src/pages/organizations/policies/PoliciesPage.tsx @@ -33,13 +33,7 @@ import type { PoliciesPageRowFragment$key } from "./__generated__/PoliciesPageRo const policiesFragment = graphql` fragment PoliciesPageListFragment on Organization { - policies( - first: 100 - after: null - last: null - before: null - orderBy: { direction: DESC, field: CREATED_AT } - ) @connection(key: "PoliciesPageFragment_policies") { + policies(first: 100) @connection(key: "PoliciesPageFragment_policies") { __id edges { node { diff --git a/apps/console2/src/pages/organizations/policies/PolicyPage.tsx b/apps/console2/src/pages/organizations/policies/PolicyPage.tsx index cb261ca1f..3dbdd2f7f 100644 --- a/apps/console2/src/pages/organizations/policies/PolicyPage.tsx +++ b/apps/console2/src/pages/organizations/policies/PolicyPage.tsx @@ -31,6 +31,7 @@ import { IconPencil, useConfirmDialogRef, IconClock, + IconSignature, } from "@probo/ui"; import { useOrganizationId } from "/hooks/useOrganizationId"; import { Button } from "@probo/ui"; @@ -40,6 +41,7 @@ import { useNavigate } from "react-router"; import UpdateVersionDialog from "./dialogs/UpdateVersionDialog"; import { useRef } from "react"; import { PolicyVersionHistoryDialog } from "./dialogs/PolicyVersionHistoryDialog"; +import { PolicySignaturesDialog } from "./dialogs/PolicySignaturesDialog"; type Props = { queryRef: PreloadedQuery; @@ -63,15 +65,21 @@ const policyFragment = graphql` publishedAt version updatedAt - signatures(first: 100) { + signatures(first: 100) @connection(key: "PolicyPage_signatures") { + __id edges { node { id state + signedBy { + id + } + ...PolicySignaturesDialog_signature } } } ...PolicyVersionHistoryDialogFragment + ...PolicySignaturesDialog_version } } } @@ -108,7 +116,6 @@ export default function PolicyPage(props: Props) { ); const [deletePolicy, isDeleting] = useDeletePolicyMutation(); const versionConnectionId = policy.versions.__id; - const versions = policy.versions.edges.map((edge) => edge.node); usePageTitle(policy.title); @@ -197,6 +204,11 @@ export default function PolicyPage(props: Props) { {__("Version history")} + + + > + * @generated SignedSource<<89063899241b0557e2a6df4ff74ecea1>> * @lightSyntaxTransform * @nogrep */ @@ -35,7 +35,7 @@ const node: ReaderFragment = { { "count": null, "cursor": null, - "direction": "bidirectional", + "direction": "forward", "path": [ "policies" ] @@ -46,16 +46,7 @@ const node: ReaderFragment = { "selections": [ { "alias": "policies", - "args": [ - { - "kind": "Literal", - "name": "orderBy", - "value": { - "direction": "DESC", - "field": "CREATED_AT" - } - } - ], + "args": null, "concreteType": "PolicyConnection", "kind": "LinkedField", "name": "__PoliciesPageFragment_policies_connection", @@ -130,20 +121,6 @@ const node: ReaderFragment = { "kind": "ScalarField", "name": "hasNextPage", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "hasPreviousPage", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "startCursor", - "storageKey": null } ], "storageKey": null @@ -161,13 +138,13 @@ const node: ReaderFragment = { ] } ], - "storageKey": "__PoliciesPageFragment_policies_connection(orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})" + "storageKey": null } ], "type": "Organization", "abstractKey": null }; -(node as any).hash = "2f34601ba53a0900494a1bb0d8be1773"; +(node as any).hash = "1c1fa3340a1fe9de3995ffcb374c9124"; export default node; diff --git a/apps/console2/src/pages/organizations/policies/__generated__/PoliciesPageRowFragment.graphql.ts b/apps/console2/src/pages/organizations/policies/__generated__/PoliciesPageRowFragment.graphql.ts index 37f7b58f4..8318f2c70 100644 --- a/apps/console2/src/pages/organizations/policies/__generated__/PoliciesPageRowFragment.graphql.ts +++ b/apps/console2/src/pages/organizations/policies/__generated__/PoliciesPageRowFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<76980bd62a1a415efbb27298d27874da>> + * @generated SignedSource<<3d1854151a950f0b4b85faf16c995c61>> * @lightSyntaxTransform * @nogrep */ @@ -9,8 +9,8 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type PolicyStatus = "DRAFT" | "PUBLISHED" | "%future added value"; -export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED" | "%future added value"; +export type PolicyStatus = "DRAFT" | "PUBLISHED"; +export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED"; import { FragmentRefs } from "relay-runtime"; export type PoliciesPageRowFragment$data = { readonly description: string; diff --git a/apps/console2/src/pages/organizations/policies/__generated__/PolicyPageCreateDraftPolicyVersionMutation.graphql.ts b/apps/console2/src/pages/organizations/policies/__generated__/PolicyPageCreateDraftPolicyVersionMutation.graphql.ts deleted file mode 100644 index 76e9164c3..000000000 --- a/apps/console2/src/pages/organizations/policies/__generated__/PolicyPageCreateDraftPolicyVersionMutation.graphql.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @generated SignedSource<<0c65ab6f2531f65b9687e3ca13074774>> - * @lightSyntaxTransform - * @nogrep - */ - -/* tslint:disable */ -/* eslint-disable */ -// @ts-nocheck - -import { ConcreteRequest } from 'relay-runtime'; -export type PolicyStatus = "DRAFT" | "PUBLISHED" | "%future added value"; -export type CreateDraftPolicyVersionInput = { - policyID: string; -}; -export type PolicyPageCreateDraftPolicyVersionMutation$variables = { - input: CreateDraftPolicyVersionInput; -}; -export type PolicyPageCreateDraftPolicyVersionMutation$data = { - readonly createDraftPolicyVersion: { - readonly policyVersionEdge: { - readonly node: { - readonly id: string; - readonly status: PolicyStatus; - readonly version: number; - }; - }; - }; -}; -export type PolicyPageCreateDraftPolicyVersionMutation = { - response: PolicyPageCreateDraftPolicyVersionMutation$data; - variables: PolicyPageCreateDraftPolicyVersionMutation$variables; -}; - -const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "input" - } -], -v1 = [ - { - "alias": null, - "args": [ - { - "kind": "Variable", - "name": "input", - "variableName": "input" - } - ], - "concreteType": "CreateDraftPolicyVersionPayload", - "kind": "LinkedField", - "name": "createDraftPolicyVersion", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "concreteType": "PolicyVersionEdge", - "kind": "LinkedField", - "name": "policyVersionEdge", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "concreteType": "PolicyVersion", - "kind": "LinkedField", - "name": "node", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "version", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "status", - "storageKey": null - } - ], - "storageKey": null - } - ], - "storageKey": null - } - ], - "storageKey": null - } -]; -return { - "fragment": { - "argumentDefinitions": (v0/*: any*/), - "kind": "Fragment", - "metadata": null, - "name": "PolicyPageCreateDraftPolicyVersionMutation", - "selections": (v1/*: any*/), - "type": "Mutation", - "abstractKey": null - }, - "kind": "Request", - "operation": { - "argumentDefinitions": (v0/*: any*/), - "kind": "Operation", - "name": "PolicyPageCreateDraftPolicyVersionMutation", - "selections": (v1/*: any*/) - }, - "params": { - "cacheID": "197f53d67c5393a8163be2a8ce356cd0", - "id": null, - "metadata": {}, - "name": "PolicyPageCreateDraftPolicyVersionMutation", - "operationKind": "mutation", - "text": "mutation PolicyPageCreateDraftPolicyVersionMutation(\n $input: CreateDraftPolicyVersionInput!\n) {\n createDraftPolicyVersion(input: $input) {\n policyVersionEdge {\n node {\n id\n version\n status\n }\n }\n }\n}\n" - } -}; -})(); - -(node as any).hash = "7fcf72158c1dc58ae8f9d7efaa6d93a9"; - -export default node; diff --git a/apps/console2/src/pages/organizations/policies/__generated__/PolicyPagePolicyFragment.graphql.ts b/apps/console2/src/pages/organizations/policies/__generated__/PolicyPagePolicyFragment.graphql.ts index 6b02e64e4..e8f20cd26 100644 --- a/apps/console2/src/pages/organizations/policies/__generated__/PolicyPagePolicyFragment.graphql.ts +++ b/apps/console2/src/pages/organizations/policies/__generated__/PolicyPagePolicyFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<769555856fa8bff973c4685249abbb2f>> + * @generated SignedSource<<088b04713ff854ffccb30532513bb093>> * @lightSyntaxTransform * @nogrep */ @@ -9,8 +9,8 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type PolicyStatus = "DRAFT" | "PUBLISHED" | "%future added value"; -export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED" | "%future added value"; +export type PolicyStatus = "DRAFT" | "PUBLISHED"; +export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED"; import { FragmentRefs } from "relay-runtime"; export type PolicyPagePolicyFragment$data = { readonly id: string; @@ -27,17 +27,22 @@ export type PolicyPagePolicyFragment$data = { readonly id: string; readonly publishedAt: any | null | undefined; readonly signatures: { + readonly __id: string; readonly edges: ReadonlyArray<{ readonly node: { readonly id: string; + readonly signedBy: { + readonly id: string; + }; readonly state: PolicyVersionSignatureState; + readonly " $fragmentSpreads": FragmentRefs<"PolicySignaturesDialog_signature">; }; }>; }; readonly status: PolicyStatus; readonly updatedAt: any; readonly version: number; - readonly " $fragmentSpreads": FragmentRefs<"PolicyVersionHistoryDialogFragment">; + readonly " $fragmentSpreads": FragmentRefs<"PolicySignaturesDialog_version" | "PolicyVersionHistoryDialogFragment">; }; }>; }; @@ -55,12 +60,69 @@ var v0 = { "kind": "ScalarField", "name": "id", "storageKey": null +}, +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null +}, +v4 = { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] }; return { "argumentDefinitions": [], "kind": "Fragment", "metadata": { "connection": [ + { + "count": null, + "cursor": null, + "direction": "forward", + "path": null + }, { "count": null, "cursor": null, @@ -161,17 +223,11 @@ return { "storageKey": null }, { - "alias": null, - "args": [ - { - "kind": "Literal", - "name": "first", - "value": 100 - } - ], + "alias": "signatures", + "args": null, "concreteType": "PolicyVersionSignatureConnection", "kind": "LinkedField", - "name": "signatures", + "name": "__PolicyPage_signatures_connection", "plural": false, "selections": [ { @@ -197,15 +253,36 @@ return { "kind": "ScalarField", "name": "state", "storageKey": null - } + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "signedBy", + "plural": false, + "selections": [ + (v0/*: any*/) + ], + "storageKey": null + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "PolicySignaturesDialog_signature" + }, + (v1/*: any*/) ], "storageKey": null - } + }, + (v2/*: any*/) ], "storageKey": null - } + }, + (v3/*: any*/), + (v4/*: any*/) ], - "storageKey": "signatures(first:100)" + "storageKey": null }, { "args": null, @@ -213,62 +290,20 @@ return { "name": "PolicyVersionHistoryDialogFragment" }, { - "alias": null, "args": null, - "kind": "ScalarField", - "name": "__typename", - "storageKey": null - } + "kind": "FragmentSpread", + "name": "PolicySignaturesDialog_version" + }, + (v1/*: any*/) ], "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "cursor", - "storageKey": null - } + (v2/*: any*/) ], "storageKey": null }, - { - "alias": null, - "args": null, - "concreteType": "PageInfo", - "kind": "LinkedField", - "name": "pageInfo", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "endCursor", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "hasNextPage", - "storageKey": null - } - ], - "storageKey": null - }, - { - "kind": "ClientExtension", - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__id", - "storageKey": null - } - ] - } + (v3/*: any*/), + (v4/*: any*/) ], "storageKey": null } @@ -278,6 +313,6 @@ return { }; })(); -(node as any).hash = "684db4b721c50638ee5ec1f9f4ebdd16"; +(node as any).hash = "b53b22a05e1abd608ecd688b6a9d5bad"; export default node; diff --git a/apps/console2/src/pages/organizations/policies/dialogs/PolicySignaturesDialog.tsx b/apps/console2/src/pages/organizations/policies/dialogs/PolicySignaturesDialog.tsx new file mode 100644 index 000000000..19a970f50 --- /dev/null +++ b/apps/console2/src/pages/organizations/policies/dialogs/PolicySignaturesDialog.tsx @@ -0,0 +1,267 @@ +import { + Avatar, + Badge, + Button, + Dialog, + DialogContent, + DialogFooter, + DialogTitle, + IconCircleCheck, + IconClock, + PolicyVersionBadge, + Spinner, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useState, type ReactNode, Suspense } from "react"; +import type { PolicyPagePolicyFragment$data } from "../__generated__/PolicyPagePolicyFragment.graphql"; +import clsx from "clsx"; +import type { ItemOf, NodeOf } from "/types"; +import { graphql, useFragment } from "react-relay"; +import type { PolicySignaturesDialog_version$key } from "./__generated__/PolicySignaturesDialog_version.graphql"; +import type { PolicySignaturesDialog_signature$key } from "./__generated__/PolicySignaturesDialog_signature.graphql"; +import { usePeople } from "/hooks/graph/PeopleGraph.ts"; +import { useOrganizationId } from "/hooks/useOrganizationId.ts"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts.ts"; +import { sprintf } from "@probo/helpers"; + +type Props = { + policy: PolicyPagePolicyFragment$data; + children?: ReactNode; +}; + +type Version = NodeOf; + +export function PolicySignaturesDialog(props: Props) { + const { __ } = useTranslate(); + const versions = props.policy.versions.edges.map((edge) => edge.node); + const [selectedVersionId, setSelectedVersionId] = useState( + versions[0].id + ); + const selectedVersion = versions.find((v) => v.id === selectedVersionId); + return ( + + + +
+ + {__("Signatures")} + +

+ {__( + "Click request to ask for a signature from people in your organization." + )} +

+ }> + + +
+
+ +
+ ); +} + +const versionFragment = graphql` + fragment PolicySignaturesDialog_version on PolicyVersion { + version + status + publishedAt + updatedAt + } +`; + +function VersionItem(props: { + version: Version; + active?: boolean; + onSelect: (v: string) => void; +}) { + const { dateTimeFormat, __ } = useTranslate(); + const version = useFragment( + versionFragment, + props.version + ); + return ( + + ); +} + +function SignatureList(props: { version: Version }) { + const signatures = props.version.signatures.edges.map((edge) => edge.node); + const { __ } = useTranslate(); + const signatureMap = new Map(signatures.map((s) => [s.signedBy.id, s])); + const organizationId = useOrganizationId(); + const people = usePeople(organizationId); + + if (people.length === 0) { + return ( +
+ {__("No people available to request signatures from")} +
+ ); + } + + return ( +
+ {people.map((p) => ( + + ))} +
+ ); +} + +/** + * Fragments + */ +const signatureFragment = graphql` + fragment PolicySignaturesDialog_signature on PolicyVersionSignature { + id + state + signedAt + requestedAt + signedBy { + fullName + primaryEmailAddress + } + } +`; + +/** + * Mutations + */ +const requestSignatureMutation = graphql` + mutation PolicySignaturesDialog_requestSignatureMutation( + $input: RequestSignatureInput! + $connections: [ID!]! + ) { + requestSignature(input: $input) { + policyVersionSignatureEdge @prependEdge(connections: $connections) { + node { + id + state + signedBy { + id + } + ...PolicySignaturesDialog_signature + } + } + } + } +`; + +function SignatureItem(props: { + versionId: string; + signature?: PolicySignaturesDialog_signature$key; + people: ItemOf>; + connectionId: string; +}) { + const signature = useFragment(signatureFragment, props.signature); + const { __, dateTimeFormat } = useTranslate(); + const [requestSignature, isSendingRequest] = useMutationWithToasts( + requestSignatureMutation, + { + successMessage: __("Signature request sent successfully"), + errorMessage: __("Failed to send signature request"), + } + ); + + // No signature request for this user + if (!signature) { + return ( +
+ +
+
+ {props.people.fullName} +
+
+ {props.people.primaryEmailAddress} +
+
+ +
+ ); + } + + const isSigned = signature.state === "SIGNED"; + const label = isSigned ? __("Signed on %s") : __("Requested on %s"); + + return ( +
+ +
+
+ {signature.signedBy.fullName} +
+
+ {isSigned ? ( + + ) : ( + + )} + + {sprintf( + label, + dateTimeFormat( + isSigned ? signature.signedAt : signature.requestedAt + ) + )} + +
+
+ + {isSigned ? __("Signed") : __("Pending")} + +
+ ); +} diff --git a/apps/console2/src/pages/organizations/policies/dialogs/PolicyVersionHistoryDialog.tsx b/apps/console2/src/pages/organizations/policies/dialogs/PolicyVersionHistoryDialog.tsx index 5bb226814..8b710eb36 100644 --- a/apps/console2/src/pages/organizations/policies/dialogs/PolicyVersionHistoryDialog.tsx +++ b/apps/console2/src/pages/organizations/policies/dialogs/PolicyVersionHistoryDialog.tsx @@ -9,15 +9,9 @@ import { import { graphql } from "relay-runtime"; import { useTranslate } from "@probo/i18n"; import { useState, type ReactNode } from "react"; -import type { - PolicyPagePolicyFragment$data, - PolicyPagePolicyFragment$key, -} from "../__generated__/PolicyPagePolicyFragment.graphql"; +import type { PolicyPagePolicyFragment$data } from "../__generated__/PolicyPagePolicyFragment.graphql"; import { useFragment } from "react-relay"; -import type { - PolicyVersionHistoryDialogFragment$data, - PolicyVersionHistoryDialogFragment$key, -} from "./__generated__/PolicyVersionHistoryDialogFragment.graphql"; +import type { PolicyVersionHistoryDialogFragment$key } from "./__generated__/PolicyVersionHistoryDialogFragment.graphql"; import clsx from "clsx"; import type { NodeOf } from "/types"; @@ -48,15 +42,16 @@ export function PolicyVersionHistoryDialog(props: Props) { const versions = props.policy.versions.edges.map((edge) => edge.node); const [selectedVersion, setSelectedVersion] = useState(versions[0]); return ( - + - ); } function VersionItem(props: { + policy: PolicyPagePolicyFragment$data; version: Version; active?: boolean; onSelect: (v: Version) => void; @@ -81,26 +77,25 @@ function VersionItem(props: { historyFragment, props.version ); - const { dateFormat } = useTranslate(); + const { dateTimeFormat } = useTranslate(); return ( diff --git a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_requestSignatureMutation.graphql.ts b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_requestSignatureMutation.graphql.ts new file mode 100644 index 000000000..a5bacc379 --- /dev/null +++ b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_requestSignatureMutation.graphql.ts @@ -0,0 +1,254 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED"; +export type RequestSignatureInput = { + policyVersionId: string; + signatoryId: string; +}; +export type PolicySignaturesDialog_requestSignatureMutation$variables = { + connections: ReadonlyArray; + input: RequestSignatureInput; +}; +export type PolicySignaturesDialog_requestSignatureMutation$data = { + readonly requestSignature: { + readonly policyVersionSignatureEdge: { + readonly node: { + readonly id: string; + readonly signedBy: { + readonly id: string; + }; + readonly state: PolicyVersionSignatureState; + readonly " $fragmentSpreads": FragmentRefs<"PolicySignaturesDialog_signature">; + }; + }; + }; +}; +export type PolicySignaturesDialog_requestSignatureMutation = { + response: PolicySignaturesDialog_requestSignatureMutation$data; + variables: PolicySignaturesDialog_requestSignatureMutation$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": "id", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "PolicySignaturesDialog_requestSignatureMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "RequestSignaturePayload", + "kind": "LinkedField", + "name": "requestSignature", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "PolicyVersionSignatureEdge", + "kind": "LinkedField", + "name": "policyVersionSignatureEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "PolicyVersionSignature", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "signedBy", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "PolicySignaturesDialog_signature" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "PolicySignaturesDialog_requestSignatureMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "RequestSignaturePayload", + "kind": "LinkedField", + "name": "requestSignature", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "PolicyVersionSignatureEdge", + "kind": "LinkedField", + "name": "policyVersionSignatureEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "PolicyVersionSignature", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "signedBy", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "primaryEmailAddress", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "signedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "requestedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "filters": null, + "handle": "prependEdge", + "key": "", + "kind": "LinkedHandle", + "name": "policyVersionSignatureEdge", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "20c460adbc3480622c4c91220a6e54fe", + "id": null, + "metadata": {}, + "name": "PolicySignaturesDialog_requestSignatureMutation", + "operationKind": "mutation", + "text": "mutation PolicySignaturesDialog_requestSignatureMutation(\n $input: RequestSignatureInput!\n) {\n requestSignature(input: $input) {\n policyVersionSignatureEdge {\n node {\n id\n state\n signedBy {\n id\n }\n ...PolicySignaturesDialog_signature\n }\n }\n }\n}\n\nfragment PolicySignaturesDialog_signature on PolicyVersionSignature {\n id\n state\n signedAt\n requestedAt\n signedBy {\n fullName\n primaryEmailAddress\n id\n }\n}\n" + } +}; +})(); + +(node as any).hash = "24825b1c4040debb7edda76c8ad3d662"; + +export default node; diff --git a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_signature.graphql.ts b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_signature.graphql.ts new file mode 100644 index 000000000..a69bce4e1 --- /dev/null +++ b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_signature.graphql.ts @@ -0,0 +1,96 @@ +/** + * @generated SignedSource<<4bda7ac839740680ea31b4c20299d9d4>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED"; +import { FragmentRefs } from "relay-runtime"; +export type PolicySignaturesDialog_signature$data = { + readonly id: string; + readonly requestedAt: any; + readonly signedAt: any | null | undefined; + readonly signedBy: { + readonly fullName: string; + readonly primaryEmailAddress: string; + }; + readonly state: PolicyVersionSignatureState; + readonly " $fragmentType": "PolicySignaturesDialog_signature"; +}; +export type PolicySignaturesDialog_signature$key = { + readonly " $data"?: PolicySignaturesDialog_signature$data; + readonly " $fragmentSpreads": FragmentRefs<"PolicySignaturesDialog_signature">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "PolicySignaturesDialog_signature", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "signedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "requestedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "signedBy", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "primaryEmailAddress", + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "PolicyVersionSignature", + "abstractKey": null +}; + +(node as any).hash = "b2e435dc6db3a0df223af98251adcb30"; + +export default node; diff --git a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_version.graphql.ts b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_version.graphql.ts new file mode 100644 index 000000000..50dda97f5 --- /dev/null +++ b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicySignaturesDialog_version.graphql.ts @@ -0,0 +1,67 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type PolicyStatus = "DRAFT" | "PUBLISHED"; +import { FragmentRefs } from "relay-runtime"; +export type PolicySignaturesDialog_version$data = { + readonly publishedAt: any | null | undefined; + readonly status: PolicyStatus; + readonly updatedAt: any; + readonly version: number; + readonly " $fragmentType": "PolicySignaturesDialog_version"; +}; +export type PolicySignaturesDialog_version$key = { + readonly " $data"?: PolicySignaturesDialog_version$data; + readonly " $fragmentSpreads": FragmentRefs<"PolicySignaturesDialog_version">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "PolicySignaturesDialog_version", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "version", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "publishedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "type": "PolicyVersion", + "abstractKey": null +}; + +(node as any).hash = "cdec8e3244fd6329a86b5825a4133c44"; + +export default node; diff --git a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicyVersionHistoryDialogFragment.graphql.ts b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicyVersionHistoryDialogFragment.graphql.ts index 780d91263..f658a09d2 100644 --- a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicyVersionHistoryDialogFragment.graphql.ts +++ b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/PolicyVersionHistoryDialogFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<929e2bdd729e8b9654b27cd9e9dbccb2>> + * @generated SignedSource<<45feb21e3f613b3818af04725831a427>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type PolicyStatus = "DRAFT" | "PUBLISHED" | "%future added value"; +export type PolicyStatus = "DRAFT" | "PUBLISHED"; import { FragmentRefs } from "relay-runtime"; export type PolicyVersionHistoryDialogFragment$data = { readonly changelog: string; diff --git a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/UpdateVersionDialogCreateMutation.graphql.ts b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/UpdateVersionDialogCreateMutation.graphql.ts index 89648b053..a39226f80 100644 --- a/apps/console2/src/pages/organizations/policies/dialogs/__generated__/UpdateVersionDialogCreateMutation.graphql.ts +++ b/apps/console2/src/pages/organizations/policies/dialogs/__generated__/UpdateVersionDialogCreateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<7b7cbab5e73007ace1e7d07970b633e8>> * @lightSyntaxTransform * @nogrep */ @@ -9,8 +9,8 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type PolicyStatus = "DRAFT" | "PUBLISHED" | "%future added value"; -export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED" | "%future added value"; +export type PolicyStatus = "DRAFT" | "PUBLISHED"; +export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED"; export type CreateDraftPolicyVersionInput = { policyID: string; }; diff --git a/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogMutation.graphql.ts b/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogMutation.graphql.ts index 2e9ffb1b0..e313a7c08 100644 --- a/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogMutation.graphql.ts +++ b/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<05dd3d535fb39d12fc0c015864a85d31>> + * @generated SignedSource<<7d5730a1c721f5256e6e0c07199aa0d2>> * @lightSyntaxTransform * @nogrep */ @@ -10,7 +10,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; -export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED" | "%future added value"; +export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED"; export type CreateRiskInput = { category: string; description: string; diff --git a/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogUpdateRiskMutation.graphql.ts b/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogUpdateRiskMutation.graphql.ts index c7b7130d3..ff47596f8 100644 --- a/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogUpdateRiskMutation.graphql.ts +++ b/apps/console2/src/pages/organizations/risks/__generated__/FormRiskDialogUpdateRiskMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<71792ccd18aa886a5df0ecfa8a23fda9>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -10,7 +10,7 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; -export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED" | "%future added value"; +export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED"; export type UpdateRiskInput = { category?: string | null | undefined; description?: string | null | undefined; diff --git a/apps/console2/src/pages/organizations/risks/__generated__/RiskDetailPageQuery.graphql.ts b/apps/console2/src/pages/organizations/risks/__generated__/RiskDetailPageQuery.graphql.ts deleted file mode 100644 index 554016736..000000000 --- a/apps/console2/src/pages/organizations/risks/__generated__/RiskDetailPageQuery.graphql.ts +++ /dev/null @@ -1,262 +0,0 @@ -/** - * @generated SignedSource<> - * @lightSyntaxTransform - * @nogrep - */ - -/* tslint:disable */ -/* eslint-disable */ -// @ts-nocheck - -import { ConcreteRequest } from 'relay-runtime'; -import { FragmentRefs } from "relay-runtime"; -export type RiskTreatment = "ACCEPTED" | "AVOIDED" | "MITIGATED" | "TRANSFERRED" | "%future added value"; -export type RiskDetailPageQuery$variables = { - riskId: string; -}; -export type RiskDetailPageQuery$data = { - readonly node: { - readonly createdAt?: any; - readonly description?: string; - readonly inherentImpact?: number; - readonly inherentLikelihood?: number; - readonly name?: string; - readonly note?: string; - readonly owner?: { - readonly fullName: string; - readonly id: string; - } | null | undefined; - readonly residualImpact?: number; - readonly residualLikelihood?: number; - readonly treatment?: RiskTreatment; - readonly updatedAt?: any; - readonly " $fragmentSpreads": FragmentRefs<"useRiskFormFragment">; - }; -}; -export type RiskDetailPageQuery = { - response: RiskDetailPageQuery$data; - variables: RiskDetailPageQuery$variables; -}; - -const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "riskId" - } -], -v1 = [ - { - "kind": "Variable", - "name": "id", - "variableName": "riskId" - } -], -v2 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null -}, -v3 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "description", - "storageKey": null -}, -v4 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "treatment", - "storageKey": null -}, -v5 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null -}, -v6 = { - "alias": null, - "args": null, - "concreteType": "People", - "kind": "LinkedField", - "name": "owner", - "plural": false, - "selections": [ - (v5/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "fullName", - "storageKey": null - } - ], - "storageKey": null -}, -v7 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "inherentLikelihood", - "storageKey": null -}, -v8 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "inherentImpact", - "storageKey": null -}, -v9 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "residualLikelihood", - "storageKey": null -}, -v10 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "residualImpact", - "storageKey": null -}, -v11 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "note", - "storageKey": null -}, -v12 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null -}, -v13 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", - "storageKey": null -}; -return { - "fragment": { - "argumentDefinitions": (v0/*: any*/), - "kind": "Fragment", - "metadata": null, - "name": "RiskDetailPageQuery", - "selections": [ - { - "alias": null, - "args": (v1/*: any*/), - "concreteType": null, - "kind": "LinkedField", - "name": "node", - "plural": false, - "selections": [ - { - "kind": "InlineFragment", - "selections": [ - (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/), - (v6/*: any*/), - (v7/*: any*/), - (v8/*: any*/), - (v9/*: any*/), - (v10/*: any*/), - (v11/*: any*/), - (v12/*: any*/), - (v13/*: any*/), - { - "args": null, - "kind": "FragmentSpread", - "name": "useRiskFormFragment" - } - ], - "type": "Risk", - "abstractKey": null - } - ], - "storageKey": null - } - ], - "type": "Query", - "abstractKey": null - }, - "kind": "Request", - "operation": { - "argumentDefinitions": (v0/*: any*/), - "kind": "Operation", - "name": "RiskDetailPageQuery", - "selections": [ - { - "alias": null, - "args": (v1/*: any*/), - "concreteType": null, - "kind": "LinkedField", - "name": "node", - "plural": false, - "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__typename", - "storageKey": null - }, - (v5/*: any*/), - { - "kind": "InlineFragment", - "selections": [ - (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/), - (v6/*: any*/), - (v7/*: any*/), - (v8/*: any*/), - (v9/*: any*/), - (v10/*: any*/), - (v11/*: any*/), - (v12/*: any*/), - (v13/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "category", - "storageKey": null - } - ], - "type": "Risk", - "abstractKey": null - } - ], - "storageKey": null - } - ] - }, - "params": { - "cacheID": "0ed24be13c829da91705d506a46eb562", - "id": null, - "metadata": {}, - "name": "RiskDetailPageQuery", - "operationKind": "query", - "text": "query RiskDetailPageQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\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 ...useRiskFormFragment\n }\n id\n }\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n owner {\n id\n }\n}\n" - } -}; -})(); - -(node as any).hash = "94de027c557f9b633765f9dde7c0aae1"; - -export default node; diff --git a/apps/console2/src/pages/organizations/risks/__generated__/RisksPageDeleteMutation.graphql.ts b/apps/console2/src/pages/organizations/risks/__generated__/RisksPageDeleteMutation.graphql.ts deleted file mode 100644 index c1161a030..000000000 --- a/apps/console2/src/pages/organizations/risks/__generated__/RisksPageDeleteMutation.graphql.ts +++ /dev/null @@ -1,132 +0,0 @@ -/** - * @generated SignedSource<> - * @lightSyntaxTransform - * @nogrep - */ - -/* tslint:disable */ -/* eslint-disable */ -// @ts-nocheck - -import { ConcreteRequest } from 'relay-runtime'; -export type DeleteRiskInput = { - riskId: string; -}; -export type RisksPageDeleteMutation$variables = { - connections: ReadonlyArray; - input: DeleteRiskInput; -}; -export type RisksPageDeleteMutation$data = { - readonly deleteRisk: { - readonly deletedRiskId: string; - }; -}; -export type RisksPageDeleteMutation = { - response: RisksPageDeleteMutation$data; - variables: RisksPageDeleteMutation$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": "deletedRiskId", - "storageKey": null -}; -return { - "fragment": { - "argumentDefinitions": [ - (v0/*: any*/), - (v1/*: any*/) - ], - "kind": "Fragment", - "metadata": null, - "name": "RisksPageDeleteMutation", - "selections": [ - { - "alias": null, - "args": (v2/*: any*/), - "concreteType": "DeleteRiskPayload", - "kind": "LinkedField", - "name": "deleteRisk", - "plural": false, - "selections": [ - (v3/*: any*/) - ], - "storageKey": null - } - ], - "type": "Mutation", - "abstractKey": null - }, - "kind": "Request", - "operation": { - "argumentDefinitions": [ - (v1/*: any*/), - (v0/*: any*/) - ], - "kind": "Operation", - "name": "RisksPageDeleteMutation", - "selections": [ - { - "alias": null, - "args": (v2/*: any*/), - "concreteType": "DeleteRiskPayload", - "kind": "LinkedField", - "name": "deleteRisk", - "plural": false, - "selections": [ - (v3/*: any*/), - { - "alias": null, - "args": null, - "filters": null, - "handle": "deleteEdge", - "key": "", - "kind": "ScalarHandle", - "name": "deletedRiskId", - "handleArgs": [ - { - "kind": "Variable", - "name": "connections", - "variableName": "connections" - } - ] - } - ], - "storageKey": null - } - ] - }, - "params": { - "cacheID": "a08977dc1d81b5ab63e431014b2d2b41", - "id": null, - "metadata": {}, - "name": "RisksPageDeleteMutation", - "operationKind": "mutation", - "text": "mutation RisksPageDeleteMutation(\n $input: DeleteRiskInput!\n) {\n deleteRisk(input: $input) {\n deletedRiskId\n }\n}\n" - } -}; -})(); - -(node as any).hash = "fb17a17779665063283d3d73fcb39785"; - -export default node; diff --git a/apps/console2/src/pages/organizations/risks/tabs/__generated__/RiskMeasuresTabFragment.graphql.ts b/apps/console2/src/pages/organizations/risks/tabs/__generated__/RiskMeasuresTabFragment.graphql.ts index 2bd1467df..3d696ed04 100644 --- a/apps/console2/src/pages/organizations/risks/tabs/__generated__/RiskMeasuresTabFragment.graphql.ts +++ b/apps/console2/src/pages/organizations/risks/tabs/__generated__/RiskMeasuresTabFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<83a07ae53aaa5005db49f5ea8b4479c6>> + * @generated SignedSource<<62ef6617862f528f26edaffe3adc3069>> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,7 @@ // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED" | "%future added value"; +export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED"; import { FragmentRefs } from "relay-runtime"; export type RiskMeasuresTabFragment$data = { readonly id: string; diff --git a/apps/console2/src/pages/organizations/vendors/__generated__/VendorsPageQuery.graphql.ts b/apps/console2/src/pages/organizations/vendors/__generated__/VendorsPageQuery.graphql.ts index e46017928..2e0202ceb 100644 --- a/apps/console2/src/pages/organizations/vendors/__generated__/VendorsPageQuery.graphql.ts +++ b/apps/console2/src/pages/organizations/vendors/__generated__/VendorsPageQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<2de1bbc55eb7b45a9546c8ec306ad979>> * @lightSyntaxTransform * @nogrep */ @@ -9,8 +9,8 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; -export type BusinessImpact = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM" | "%future added value"; -export type DataSensitivity = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM" | "NONE" | "%future added value"; +export type BusinessImpact = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM"; +export type DataSensitivity = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM" | "NONE"; export type VendorsPageQuery$variables = { organizationId: string; }; diff --git a/packages/i18n/TranslatorProvider.tsx b/packages/i18n/TranslatorProvider.tsx index 12e31679e..75ebc7561 100644 --- a/packages/i18n/TranslatorProvider.tsx +++ b/packages/i18n/TranslatorProvider.tsx @@ -50,26 +50,41 @@ export function TranslatorProvider({ export function useTranslate() { const { translate, lang } = useContext(TranslatorContext); + const dateFormat = ( + date: Date | string | null | undefined, + options: Intl.DateTimeFormatOptions = { + year: "numeric", + month: "short", + day: "numeric", + weekday: "short", + } + ) => { + if (!date) { + return ""; + } + if (typeof date === "string") { + return new Intl.DateTimeFormat(lang, options).format(parseDate(date)); + } + return new Intl.DateTimeFormat(lang, options).format(date); + }; return { lang, __: translate, - dateFormat: ( + dateFormat: dateFormat, + + dateTimeFormat: ( date: Date | string | null | undefined, options: Intl.DateTimeFormatOptions = { - year: "numeric", - month: "short", + hour: "2-digit", + hour12: false, + minute: "2-digit", day: "numeric", - weekday: "short", + month: "short", + year: "numeric", } ) => { - if (!date) { - return ""; - } - if (typeof date === "string") { - return new Intl.DateTimeFormat(lang, options).format(parseDate(date)); - } - return new Intl.DateTimeFormat(lang, options).format(date); + return dateFormat(date, options); }, }; } diff --git a/packages/ui/src/Atoms/Icons/IconCircleCheck.tsx b/packages/ui/src/Atoms/Icons/IconCircleCheck.tsx index 69e574b77..2699b5760 100644 --- a/packages/ui/src/Atoms/Icons/IconCircleCheck.tsx +++ b/packages/ui/src/Atoms/Icons/IconCircleCheck.tsx @@ -2,7 +2,6 @@ import type {IconProps} from "./type.ts"; export function IconCircleCheck({size = 24, className}: IconProps) { return - diff --git a/packages/ui/src/Atoms/Icons/circle-check.svg b/packages/ui/src/Atoms/Icons/circle-check.svg index 8923d3105..be7466163 100644 --- a/packages/ui/src/Atoms/Icons/circle-check.svg +++ b/packages/ui/src/Atoms/Icons/circle-check.svg @@ -1,4 +1,3 @@ - - + diff --git a/packages/ui/src/Atoms/Toasts/Toasts.tsx b/packages/ui/src/Atoms/Toasts/Toasts.tsx index e98d5675c..44350adbd 100644 --- a/packages/ui/src/Atoms/Toasts/Toasts.tsx +++ b/packages/ui/src/Atoms/Toasts/Toasts.tsx @@ -9,15 +9,23 @@ type Toast = { id: string; }; +const duration = 3000; + const useToasts = create( combine({ toasts: [] as Toast[] }, (set) => ({ - add: (toast: Pick) => + add: (toast: Pick) => { + const id = Date.now().toString(); set((state) => ({ - toasts: [ - { ...toast, id: Date.now().toString() }, - ...state.toasts, - ], - })), + toasts: [{ ...toast, id }, ...state.toasts], + })); + setTimeout(() => { + set((state) => ({ + toasts: [ + ...state.toasts.filter((toast) => toast.id !== id), + ], + })); + }, duration); + }, remove: (id: string) => set((state) => ({ toasts: state.toasts.filter((toast) => toast.id !== id), @@ -51,15 +59,32 @@ export function Toasts() { } const toast = tv({ - base: "p-2 border rounded relative animate-in slide-in-from-right w-full cursor-pointer", + slots: { + wrapper: + "p-2 border rounded relative animate-in slide-in-from-right w-full cursor-pointer ", + timer: "absolute bottom-0 left-0 w-full h-1 starting:scale-x-0 scale-x-100 origin-left transition-all ease-linear", + }, variants: { variant: { - success: - "bg-success text-invert text-txt-success border-border-success", - error: "bg-danger text-invert text-txt-danger border-border-danger", - warning: - "bg-warning text-invert text-txt-warning border-border-warning", - info: "bg-info text-invert text-txt-info border-border-info", + success: { + wrapper: + "bg-success text-invert text-txt-success border-border-success", + timer: "bg-border-success", + }, + error: { + wrapper: + "bg-danger text-invert text-txt-danger border-border-danger", + timer: "bg-border-danger", + }, + warning: { + wrapper: + "bg-warning text-invert text-txt-warning border-border-warning", + timer: "bg-border-warning", + }, + info: { + wrapper: "bg-info text-invert text-txt-info border-border-info", + timer: "bg-border-info", + }, }, }, defaultVariants: { @@ -68,10 +93,15 @@ const toast = tv({ }); export function Toast({ onClose, ...props }: Toast & { onClose: () => void }) { + const { wrapper, timer } = toast(props); return ( -
+
{props.title}
{props.description}
+
); } diff --git a/packages/ui/src/Molecules/Badge/PolicyVersionBadge.stories.tsx b/packages/ui/src/Molecules/Badge/PolicyVersionBadge.stories.tsx new file mode 100644 index 000000000..8681476f6 --- /dev/null +++ b/packages/ui/src/Molecules/Badge/PolicyVersionBadge.stories.tsx @@ -0,0 +1,21 @@ +import { PolicyVersionBadge } from "./PolicyVersionBadge"; +import type { Meta, StoryObj } from "@storybook/react"; + +export default { + title: "Molecules/Badges/PolicyVersionBadge", + component: PolicyVersionBadge, + argTypes: {}, +} satisfies Meta; + +type Story = StoryObj; + +export const Default: Story = { + render() { + return ( +
+ + +
+ ); + }, +}; diff --git a/packages/ui/src/Molecules/Badge/PolicyVersionBadge.tsx b/packages/ui/src/Molecules/Badge/PolicyVersionBadge.tsx new file mode 100644 index 000000000..2fb105532 --- /dev/null +++ b/packages/ui/src/Molecules/Badge/PolicyVersionBadge.tsx @@ -0,0 +1,15 @@ +import { useTranslate } from "@probo/i18n"; +import { Badge } from "../../Atoms/Badge/Badge.tsx"; + +type Props = { + state: "DRAFT" | "PUBLISHED"; +}; + +export function PolicyVersionBadge(props: Props) { + const { __ } = useTranslate(); + return ( + + {props.state === "DRAFT" ? __("Draft") : __("Published")} + + ); +} diff --git a/packages/ui/src/Molecules/Dialog/Dialog.tsx b/packages/ui/src/Molecules/Dialog/Dialog.tsx index 34d4afd0a..2cc58f5af 100644 --- a/packages/ui/src/Molecules/Dialog/Dialog.tsx +++ b/packages/ui/src/Molecules/Dialog/Dialog.tsx @@ -17,7 +17,6 @@ import { type ComponentProps, type CSSProperties, type HTMLAttributes, - type ReactElement, type ReactNode, type RefObject, } from "react"; @@ -128,14 +127,16 @@ export function DialogFooter({ ); } -export function DialogContent( - props: HTMLAttributes & { - padded?: boolean; - scrollableChildren?: boolean; - }, -) { +export function DialogContent({ + padded, + scrollableChildren, + ...props +}: HTMLAttributes & { + padded?: boolean; + scrollableChildren?: boolean; +}) { let children = props.children; - if (props.scrollableChildren) { + if (scrollableChildren) { children = Children.map(props.children, (c) => { if ( isValidElement<{ @@ -162,7 +163,7 @@ export function DialogContent( className={clsx( "overflow-y-auto", props.className, - props.padded && "p-6", + padded && "p-6", )} style={ { diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index be58af96b..fec3d4d4e 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -49,6 +49,7 @@ export { } from "./Molecules/Dialog/Dialog"; export { RiskBadge } from "./Molecules/Badge/RiskBadge"; export { SeverityBadge } from "./Molecules/Badge/SeverityBadge.tsx"; +export { PolicyVersionBadge } from "./Molecules/Badge/PolicyVersionBadge.tsx"; export { ConfirmDialog, useConfirmDialogRef, diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css index 3aea724f6..18839ab9e 100644 --- a/packages/ui/src/theme.css +++ b/packages/ui/src/theme.css @@ -206,7 +206,7 @@ --color-dialog: #151715; /* Borders */ - --color-border-solid: #2b2f2a; + --color-border-solid: rgba(239, 254, 226, 0.08); --color-border-low: rgba(239, 254, 226, 0.08); --color-border-mid: rgba(233, 254, 223, 0.1); --color-border-strong: rgba(241, 255, 237, 0.25); diff --git a/relay.config.json b/relay.config.json deleted file mode 100644 index dced57dd9..000000000 --- a/relay.config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "src": "./apps/console2/src", - "schema": "./pkg/server/api/console/v1/schema.graphql", - "language": "typescript", - "eagerEsModules": true -}