From bb68af1d3c15509576228ae850f11c5974ec44b8 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Tue, 26 Aug 2025 15:44:09 +0200 Subject: [PATCH] Add continual improvement registries Signed-off-by: Sacha Al Himdani --- .../ContinualImprovementRegistryGraph.ts | 233 ++ ...mentRegistryGraphCreateMutation.graphql.ts | 350 ++ ...mentRegistryGraphDeleteMutation.graphql.ts | 132 + ...provementRegistryGraphListQuery.graphql.ts | 340 ++ ...provementRegistryGraphNodeQuery.graphql.ts | 291 ++ ...mentRegistryGraphUpdateMutation.graphql.ts | 236 ++ apps/console/src/layouts/MainLayout.tsx | 10 +- .../ComplianceRegistriesPage.tsx | 12 +- .../ComplianceRegistryDetailsPage.tsx | 2 +- .../ContinualImprovementRegistriesPage.tsx | 276 ++ ...ontinualImprovementRegistryDetailsPage.tsx | 287 ++ ...provementRegistriesPageFragment.graphql.ts | 323 ++ ...lImprovementRegistriesPageQuery.graphql.ts | 340 ++ ...ementRegistriesPageRefetchQuery.graphql.ts | 350 ++ ...eateContinualImprovementRegistryDialog.tsx | 248 ++ .../NonconformityRegistriesPage.tsx | 2 +- .../NonconformityRegistryDetailsPage.tsx | 2 +- apps/console/src/routes.tsx | 2 + .../src/routes/complianceRegistryRoutes.ts | 4 +- .../continualImprovementRegistryRoutes.ts | 29 + .../src/routes/nonconformityRegistryRoutes.ts | 4 +- packages/ui/src/Atoms/Icons/IconRotateCw.tsx | 10 + packages/ui/src/Atoms/Icons/index.tsx | 1 + packages/ui/src/Atoms/Sidebar/Sidebar.tsx | 2 +- .../continual_improvement_registries.go | 324 ++ ...nual_improvement_registries_order_field.go | 55 + ...ntinual_improvement_registries_priority.go | 60 + ...continual_improvement_registries_status.go | 60 + pkg/coredata/entity_type_reg.go | 1 + pkg/coredata/migrations/20250826T121441Z.sql | 45 + ...ontinual_improvement_registries_service.go | 279 ++ pkg/probo/service.go | 7 +- pkg/server/api/console/v1/schema.graphql | 152 + pkg/server/api/console/v1/schema/schema.go | 2932 ++++++++++++++++- .../types/continual_improvement_registry.go | 74 + pkg/server/api/console/v1/types/types.go | 108 +- pkg/server/api/console/v1/v1_resolver.go | 177 + 37 files changed, 7696 insertions(+), 64 deletions(-) create mode 100644 apps/console/src/hooks/graph/ContinualImprovementRegistryGraph.ts create mode 100644 apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphCreateMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphDeleteMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphListQuery.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphNodeQuery.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphUpdateMutation.graphql.ts create mode 100644 apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistriesPage.tsx create mode 100644 apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistryDetailsPage.tsx create mode 100644 apps/console/src/pages/organizations/continualImprovementRegistries/__generated__/ContinualImprovementRegistriesPageFragment.graphql.ts create mode 100644 apps/console/src/pages/organizations/continualImprovementRegistries/__generated__/ContinualImprovementRegistriesPageQuery.graphql.ts create mode 100644 apps/console/src/pages/organizations/continualImprovementRegistries/__generated__/ContinualImprovementRegistriesPageRefetchQuery.graphql.ts create mode 100644 apps/console/src/pages/organizations/continualImprovementRegistries/dialogs/CreateContinualImprovementRegistryDialog.tsx create mode 100644 apps/console/src/routes/continualImprovementRegistryRoutes.ts create mode 100644 packages/ui/src/Atoms/Icons/IconRotateCw.tsx create mode 100644 pkg/coredata/continual_improvement_registries.go create mode 100644 pkg/coredata/continual_improvement_registries_order_field.go create mode 100644 pkg/coredata/continual_improvement_registries_priority.go create mode 100644 pkg/coredata/continual_improvement_registries_status.go create mode 100644 pkg/coredata/migrations/20250826T121441Z.sql create mode 100644 pkg/probo/continual_improvement_registries_service.go create mode 100644 pkg/server/api/console/v1/types/continual_improvement_registry.go diff --git a/apps/console/src/hooks/graph/ContinualImprovementRegistryGraph.ts b/apps/console/src/hooks/graph/ContinualImprovementRegistryGraph.ts new file mode 100644 index 000000000..6dd4bbed0 --- /dev/null +++ b/apps/console/src/hooks/graph/ContinualImprovementRegistryGraph.ts @@ -0,0 +1,233 @@ +import { graphql } from "relay-runtime"; +import { useMutation } from "react-relay"; +import { useConfirm } from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { promisifyMutation, sprintf } from "@probo/helpers"; +import { useMutationWithToasts } from "../useMutationWithToasts"; + +export const ContinualImprovementRegistriesConnectionKey = "ContinualImprovementRegistriesPage_continualImprovementRegistries"; + +export const continualImprovementRegistriesQuery = graphql` + query ContinualImprovementRegistryGraphListQuery($organizationId: ID!) { + node(id: $organizationId) { + ... on Organization { + ...ContinualImprovementRegistriesPageFragment + } + } + } +`; + +export const continualImprovementRegistryNodeQuery = graphql` + query ContinualImprovementRegistryGraphNodeQuery($continualImprovementRegistryId: ID!) { + node(id: $continualImprovementRegistryId) { + ... on ContinualImprovementRegistry { + id + referenceId + description + source + targetDate + status + priority + audit { + id + name + framework { + id + name + } + } + owner { + id + fullName + } + organization { + id + name + } + createdAt + updatedAt + } + } + } +`; + +export const createContinualImprovementRegistryMutation = graphql` + mutation ContinualImprovementRegistryGraphCreateMutation( + $input: CreateContinualImprovementRegistryInput! + $connections: [ID!]! + ) { + createContinualImprovementRegistry(input: $input) { + continualImprovementRegistryEdge @prependEdge(connections: $connections) { + node { + id + referenceId + description + source + targetDate + status + priority + audit { + id + name + framework { + name + } + } + owner { + id + fullName + } + createdAt + } + } + } + } +`; + +export const updateContinualImprovementRegistryMutation = graphql` + mutation ContinualImprovementRegistryGraphUpdateMutation($input: UpdateContinualImprovementRegistryInput!) { + updateContinualImprovementRegistry(input: $input) { + continualImprovementRegistry { + id + referenceId + description + source + targetDate + status + priority + owner { + id + fullName + } + audit { + id + name + framework { + id + name + } + } + updatedAt + } + } + } +`; + +export const deleteContinualImprovementRegistryMutation = graphql` + mutation ContinualImprovementRegistryGraphDeleteMutation( + $input: DeleteContinualImprovementRegistryInput! + $connections: [ID!]! + ) { + deleteContinualImprovementRegistry(input: $input) { + deletedContinualImprovementRegistryId @deleteEdge(connections: $connections) + } + } +`; + +export const useDeleteContinualImprovementRegistry = ( + registry: { id: string; referenceId: string }, + connectionId: string +) => { + const { __ } = useTranslate(); + const [mutate] = useMutationWithToasts(deleteContinualImprovementRegistryMutation, { + successMessage: __("Continual improvement registry entry deleted successfully"), + errorMessage: __("Failed to delete continual improvement registry entry"), + }); + const confirm = useConfirm(); + + return () => { + confirm( + () => + mutate({ + variables: { + input: { + continualImprovementRegistryId: registry.id, + }, + connections: [connectionId], + }, + }), + { + message: sprintf( + __( + "This will permanently delete the continual improvement registry entry %s. This action cannot be undone." + ), + registry.referenceId + ), + } + ); + }; +}; + +export const useCreateContinualImprovementRegistry = (connectionId: string) => { + const [mutate] = useMutation(createContinualImprovementRegistryMutation); + const { __ } = useTranslate(); + + return (input: { + organizationId: string; + referenceId: string; + description?: string; + source?: string; + auditId: string; + ownerId: string; + targetDate?: string; + status: string; + priority: string; + }) => { + if (!input.organizationId) { + return alert(__("Failed to create continual improvement registry entry: organization is required")); + } + if (!input.referenceId) { + return alert(__("Failed to create continual improvement registry entry: reference ID is required")); + } + if (!input.auditId) { + return alert(__("Failed to create continual improvement registry entry: audit is required")); + } + if (!input.ownerId) { + return alert(__("Failed to create continual improvement registry entry: owner is required")); + } + + return promisifyMutation(mutate)({ + variables: { + input: { + organizationId: input.organizationId, + referenceId: input.referenceId, + description: input.description, + source: input.source, + auditId: input.auditId, + ownerId: input.ownerId, + targetDate: input.targetDate, + status: input.status || "OPEN", + priority: input.priority || "MEDIUM", + }, + connections: [connectionId], + }, + }); + }; +}; + +export const useUpdateContinualImprovementRegistry = () => { + const [mutate] = useMutation(updateContinualImprovementRegistryMutation); + const { __ } = useTranslate(); + + return (input: { + id: string; + referenceId?: string; + description?: string; + source?: string; + auditId?: string; + ownerId?: string; + targetDate?: string; + status?: string; + priority?: string; + }) => { + if (!input.id) { + return alert(__("Failed to update continual improvement registry entry: registry ID is required")); + } + + return promisifyMutation(mutate)({ + variables: { + input, + }, + }); + }; +}; diff --git a/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphCreateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphCreateMutation.graphql.ts new file mode 100644 index 000000000..efdb50686 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphCreateMutation.graphql.ts @@ -0,0 +1,350 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ContinualImprovementRegistriesPriority = "HIGH" | "LOW" | "MEDIUM"; +export type ContinualImprovementRegistriesStatus = "CLOSED" | "IN_PROGRESS" | "OPEN"; +export type CreateContinualImprovementRegistryInput = { + auditId: string; + description?: string | null | undefined; + organizationId: string; + ownerId: string; + priority: ContinualImprovementRegistriesPriority; + referenceId: string; + source?: string | null | undefined; + status: ContinualImprovementRegistriesStatus; + targetDate?: any | null | undefined; +}; +export type ContinualImprovementRegistryGraphCreateMutation$variables = { + connections: ReadonlyArray; + input: CreateContinualImprovementRegistryInput; +}; +export type ContinualImprovementRegistryGraphCreateMutation$data = { + readonly createContinualImprovementRegistry: { + readonly continualImprovementRegistryEdge: { + readonly node: { + readonly audit: { + readonly framework: { + readonly name: string; + }; + readonly id: string; + readonly name: string | null | undefined; + }; + readonly createdAt: any; + readonly description: string | null | undefined; + readonly id: string; + readonly owner: { + readonly fullName: string; + readonly id: string; + }; + readonly priority: ContinualImprovementRegistriesPriority; + readonly referenceId: string; + readonly source: string | null | undefined; + readonly status: ContinualImprovementRegistriesStatus; + readonly targetDate: any | null | undefined; + }; + }; + }; +}; +export type ContinualImprovementRegistryGraphCreateMutation = { + response: ContinualImprovementRegistryGraphCreateMutation$data; + variables: ContinualImprovementRegistryGraphCreateMutation$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": "referenceId", + "storageKey": null +}, +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null +}, +v6 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null +}, +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "targetDate", + "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null +}, +v9 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "priority", + "storageKey": null +}, +v10 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v11 = { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "owner", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null +}, +v12 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "ContinualImprovementRegistryGraphCreateMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateContinualImprovementRegistryPayload", + "kind": "LinkedField", + "name": "createContinualImprovementRegistry", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistryEdge", + "kind": "LinkedField", + "name": "continualImprovementRegistryEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistry", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "audit", + "plural": false, + "selections": [ + (v3/*: any*/), + (v10/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v10/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + }, + (v11/*: any*/), + (v12/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "ContinualImprovementRegistryGraphCreateMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "CreateContinualImprovementRegistryPayload", + "kind": "LinkedField", + "name": "createContinualImprovementRegistry", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistryEdge", + "kind": "LinkedField", + "name": "continualImprovementRegistryEdge", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistry", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "audit", + "plural": false, + "selections": [ + (v3/*: any*/), + (v10/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v10/*: any*/), + (v3/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + }, + (v11/*: any*/), + (v12/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "filters": null, + "handle": "prependEdge", + "key": "", + "kind": "LinkedHandle", + "name": "continualImprovementRegistryEdge", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "a3ddc3c5ac1f55ef2db276ae41ae213b", + "id": null, + "metadata": {}, + "name": "ContinualImprovementRegistryGraphCreateMutation", + "operationKind": "mutation", + "text": "mutation ContinualImprovementRegistryGraphCreateMutation(\n $input: CreateContinualImprovementRegistryInput!\n) {\n createContinualImprovementRegistry(input: $input) {\n continualImprovementRegistryEdge {\n node {\n id\n referenceId\n description\n source\n targetDate\n status\n priority\n audit {\n id\n name\n framework {\n name\n id\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n }\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "5d9e0771c839c6c220dabdb00267a7ee"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphDeleteMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphDeleteMutation.graphql.ts new file mode 100644 index 000000000..22d3365bc --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphDeleteMutation.graphql.ts @@ -0,0 +1,132 @@ +/** + * @generated SignedSource<<55e8b0de5cb20c0a479bb4862aab4677>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type DeleteContinualImprovementRegistryInput = { + continualImprovementRegistryId: string; +}; +export type ContinualImprovementRegistryGraphDeleteMutation$variables = { + connections: ReadonlyArray; + input: DeleteContinualImprovementRegistryInput; +}; +export type ContinualImprovementRegistryGraphDeleteMutation$data = { + readonly deleteContinualImprovementRegistry: { + readonly deletedContinualImprovementRegistryId: string; + }; +}; +export type ContinualImprovementRegistryGraphDeleteMutation = { + response: ContinualImprovementRegistryGraphDeleteMutation$data; + variables: ContinualImprovementRegistryGraphDeleteMutation$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": "deletedContinualImprovementRegistryId", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "ContinualImprovementRegistryGraphDeleteMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "DeleteContinualImprovementRegistryPayload", + "kind": "LinkedField", + "name": "deleteContinualImprovementRegistry", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + } + ], + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "ContinualImprovementRegistryGraphDeleteMutation", + "selections": [ + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "DeleteContinualImprovementRegistryPayload", + "kind": "LinkedField", + "name": "deleteContinualImprovementRegistry", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "filters": null, + "handle": "deleteEdge", + "key": "", + "kind": "ScalarHandle", + "name": "deletedContinualImprovementRegistryId", + "handleArgs": [ + { + "kind": "Variable", + "name": "connections", + "variableName": "connections" + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "1f973509e72c6a1a729e98a8b4240b25", + "id": null, + "metadata": {}, + "name": "ContinualImprovementRegistryGraphDeleteMutation", + "operationKind": "mutation", + "text": "mutation ContinualImprovementRegistryGraphDeleteMutation(\n $input: DeleteContinualImprovementRegistryInput!\n) {\n deleteContinualImprovementRegistry(input: $input) {\n deletedContinualImprovementRegistryId\n }\n}\n" + } +}; +})(); + +(node as any).hash = "7c7512a398e2391d5f7f083395cc6395"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphListQuery.graphql.ts new file mode 100644 index 000000000..b963daa32 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphListQuery.graphql.ts @@ -0,0 +1,340 @@ +/** + * @generated SignedSource<<7d5f12e454c99687263a264f59618ebe>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type ContinualImprovementRegistryGraphListQuery$variables = { + organizationId: string; +}; +export type ContinualImprovementRegistryGraphListQuery$data = { + readonly node: { + readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementRegistriesPageFragment">; + }; +}; +export type ContinualImprovementRegistryGraphListQuery = { + response: ContinualImprovementRegistryGraphListQuery$data; + variables: ContinualImprovementRegistryGraphListQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "organizationId" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "organizationId" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v4 = [ + { + "kind": "Literal", + "name": "first", + "value": 10 + } +], +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ContinualImprovementRegistryGraphListQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "ContinualImprovementRegistriesPageFragment" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ContinualImprovementRegistryGraphListQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": (v4/*: any*/), + "concreteType": "ContinualImprovementRegistryConnection", + "kind": "LinkedField", + "name": "continualImprovementRegistries", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "totalCount", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistryEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistry", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "referenceId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "targetDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "priority", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "audit", + "plural": false, + "selections": [ + (v3/*: any*/), + (v5/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v3/*: any*/), + (v5/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "owner", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + }, + (v2/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": "continualImprovementRegistries(first:10)" + }, + { + "alias": null, + "args": (v4/*: any*/), + "filters": null, + "handle": "connection", + "key": "ContinualImprovementRegistriesPage_continualImprovementRegistries", + "kind": "LinkedHandle", + "name": "continualImprovementRegistries" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "875ae8e8faf73c6c1672d6c033e8dcf0", + "id": null, + "metadata": {}, + "name": "ContinualImprovementRegistryGraphListQuery", + "operationKind": "query", + "text": "query ContinualImprovementRegistryGraphListQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ContinualImprovementRegistriesPageFragment\n }\n id\n }\n}\n\nfragment ContinualImprovementRegistriesPageFragment on Organization {\n id\n continualImprovementRegistries(first: 10) {\n totalCount\n edges {\n node {\n id\n referenceId\n description\n source\n targetDate\n status\n priority\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "1098fc11629892073fbe6d7561b229e3"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphNodeQuery.graphql.ts new file mode 100644 index 000000000..9cf3cc659 --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphNodeQuery.graphql.ts @@ -0,0 +1,291 @@ +/** + * @generated SignedSource<<6ac0e2eaa895ed1c2409e524e0333ab6>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ContinualImprovementRegistriesPriority = "HIGH" | "LOW" | "MEDIUM"; +export type ContinualImprovementRegistriesStatus = "CLOSED" | "IN_PROGRESS" | "OPEN"; +export type ContinualImprovementRegistryGraphNodeQuery$variables = { + continualImprovementRegistryId: string; +}; +export type ContinualImprovementRegistryGraphNodeQuery$data = { + readonly node: { + readonly audit?: { + readonly framework: { + readonly id: string; + readonly name: string; + }; + readonly id: string; + readonly name: string | null | undefined; + }; + readonly createdAt?: any; + readonly description?: string | null | undefined; + readonly id?: string; + readonly organization?: { + readonly id: string; + readonly name: string; + }; + readonly owner?: { + readonly fullName: string; + readonly id: string; + }; + readonly priority?: ContinualImprovementRegistriesPriority; + readonly referenceId?: string; + readonly source?: string | null | undefined; + readonly status?: ContinualImprovementRegistriesStatus; + readonly targetDate?: any | null | undefined; + readonly updatedAt?: any; + }; +}; +export type ContinualImprovementRegistryGraphNodeQuery = { + response: ContinualImprovementRegistryGraphNodeQuery$data; + variables: ContinualImprovementRegistryGraphNodeQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "continualImprovementRegistryId" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "continualImprovementRegistryId" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "referenceId", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null +}, +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null +}, +v6 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "targetDate", + "storageKey": null +}, +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "priority", + "storageKey": null +}, +v9 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v10 = [ + (v2/*: any*/), + (v9/*: any*/) +], +v11 = { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "audit", + "plural": false, + "selections": [ + (v2/*: any*/), + (v9/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": (v10/*: any*/), + "storageKey": null + } + ], + "storageKey": null +}, +v12 = { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "owner", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null +}, +v13 = { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": (v10/*: any*/), + "storageKey": null +}, +v14 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}, +v15 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ContinualImprovementRegistryGraphNodeQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + (v8/*: any*/), + (v11/*: any*/), + (v12/*: any*/), + (v13/*: any*/), + (v14/*: any*/), + (v15/*: any*/) + ], + "type": "ContinualImprovementRegistry", + "abstractKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ContinualImprovementRegistryGraphNodeQuery", + "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 + }, + (v2/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + (v8/*: any*/), + (v11/*: any*/), + (v12/*: any*/), + (v13/*: any*/), + (v14/*: any*/), + (v15/*: any*/) + ], + "type": "ContinualImprovementRegistry", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "c3195d70369df1a1ca2a73fdfef37039", + "id": null, + "metadata": {}, + "name": "ContinualImprovementRegistryGraphNodeQuery", + "operationKind": "query", + "text": "query ContinualImprovementRegistryGraphNodeQuery(\n $continualImprovementRegistryId: ID!\n) {\n node(id: $continualImprovementRegistryId) {\n __typename\n ... on ContinualImprovementRegistry {\n id\n referenceId\n description\n source\n targetDate\n status\n priority\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n organization {\n id\n name\n }\n createdAt\n updatedAt\n }\n id\n }\n}\n" + } +}; +})(); + +(node as any).hash = "fe3c3ff44245eb13ea465ae5809ef5bd"; + +export default node; diff --git a/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphUpdateMutation.graphql.ts new file mode 100644 index 000000000..188c8010a --- /dev/null +++ b/apps/console/src/hooks/graph/__generated__/ContinualImprovementRegistryGraphUpdateMutation.graphql.ts @@ -0,0 +1,236 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ContinualImprovementRegistriesPriority = "HIGH" | "LOW" | "MEDIUM"; +export type ContinualImprovementRegistriesStatus = "CLOSED" | "IN_PROGRESS" | "OPEN"; +export type UpdateContinualImprovementRegistryInput = { + auditId?: string | null | undefined; + description?: string | null | undefined; + id: string; + ownerId?: string | null | undefined; + priority?: ContinualImprovementRegistriesPriority | null | undefined; + referenceId?: string | null | undefined; + source?: string | null | undefined; + status?: ContinualImprovementRegistriesStatus | null | undefined; + targetDate?: any | null | undefined; +}; +export type ContinualImprovementRegistryGraphUpdateMutation$variables = { + input: UpdateContinualImprovementRegistryInput; +}; +export type ContinualImprovementRegistryGraphUpdateMutation$data = { + readonly updateContinualImprovementRegistry: { + readonly continualImprovementRegistry: { + readonly audit: { + readonly framework: { + readonly id: string; + readonly name: string; + }; + readonly id: string; + readonly name: string | null | undefined; + }; + readonly description: string | null | undefined; + readonly id: string; + readonly owner: { + readonly fullName: string; + readonly id: string; + }; + readonly priority: ContinualImprovementRegistriesPriority; + readonly referenceId: string; + readonly source: string | null | undefined; + readonly status: ContinualImprovementRegistriesStatus; + readonly targetDate: any | null | undefined; + readonly updatedAt: any; + }; + }; +}; +export type ContinualImprovementRegistryGraphUpdateMutation = { + response: ContinualImprovementRegistryGraphUpdateMutation$data; + variables: ContinualImprovementRegistryGraphUpdateMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v3 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateContinualImprovementRegistryPayload", + "kind": "LinkedField", + "name": "updateContinualImprovementRegistry", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ContinualImprovementRegistry", + "kind": "LinkedField", + "name": "continualImprovementRegistry", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "referenceId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "source", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "targetDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "priority", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "owner", + "plural": false, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "audit", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ContinualImprovementRegistryGraphUpdateMutation", + "selections": (v3/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ContinualImprovementRegistryGraphUpdateMutation", + "selections": (v3/*: any*/) + }, + "params": { + "cacheID": "b3b3931c06838e6e60f33738be340d6c", + "id": null, + "metadata": {}, + "name": "ContinualImprovementRegistryGraphUpdateMutation", + "operationKind": "mutation", + "text": "mutation ContinualImprovementRegistryGraphUpdateMutation(\n $input: UpdateContinualImprovementRegistryInput!\n) {\n updateContinualImprovementRegistry(input: $input) {\n continualImprovementRegistry {\n id\n referenceId\n description\n source\n targetDate\n status\n priority\n owner {\n id\n fullName\n }\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n updatedAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "e59f20342fd5532b1815034334cd5560"; + +export default node; diff --git a/apps/console/src/layouts/MainLayout.tsx b/apps/console/src/layouts/MainLayout.tsx index 7a2be775d..90df4310c 100644 --- a/apps/console/src/layouts/MainLayout.tsx +++ b/apps/console/src/layouts/MainLayout.tsx @@ -18,6 +18,7 @@ import { IconListStack, IconBox, IconShield, + IconRotateCw, Layout, SidebarItem, UserDropdown as UserDropdownRoot, @@ -144,12 +145,17 @@ export function MainLayout() { + + {registry.referenceId} @@ -233,11 +233,11 @@ function RegistryRow({ - {registry.audit?.name - ? `${registry.audit.framework.name} - ${registry.audit.name}` - : registry.audit?.framework.name || "-" - } - + {registry.audit.name + ? `${registry.audit.framework.name} - ${registry.audit.name}` + : registry.audit.framework.name + } + {registry.owner?.fullName || "-"} {registry.dueDate ? ( diff --git a/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx b/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx index 3f434a57f..a6e63e40f 100644 --- a/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx +++ b/apps/console/src/pages/organizations/complianceRegistries/ComplianceRegistryDetailsPage.tsx @@ -133,7 +133,7 @@ export default function ComplianceRegistryDetailsPage(props: Props) {
diff --git a/apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistriesPage.tsx b/apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistriesPage.tsx new file mode 100644 index 000000000..0c4058c4c --- /dev/null +++ b/apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistriesPage.tsx @@ -0,0 +1,276 @@ +import { + Button, + IconPlusLarge, + PageHeader, + Card, + Thead, + Tbody, + Tr, + Th, + Td, + Badge, + ActionDropdown, + DropdownItem, + IconTrashCan, + Table, + useConfirm, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { usePageTitle } from "@probo/hooks"; +import { + ConnectionHandler, + graphql, + usePaginationFragment, + usePreloadedQuery, + useMutation, + type PreloadedQuery, +} from "react-relay"; +import { useOrganizationId } from "/hooks/useOrganizationId"; +import { CreateContinualImprovementRegistryDialog } from "./dialogs/CreateContinualImprovementRegistryDialog"; +import { deleteContinualImprovementRegistryMutation, ContinualImprovementRegistriesConnectionKey } from "../../../hooks/graph/ContinualImprovementRegistryGraph"; +import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers"; +import type { NodeOf } from "/types"; +import type { ContinualImprovementRegistriesPageQuery } from "./__generated__/ContinualImprovementRegistriesPageQuery.graphql"; +import type { + ContinualImprovementRegistriesPageFragment$key, + ContinualImprovementRegistriesPageFragment$data, +} from "./__generated__/ContinualImprovementRegistriesPageFragment.graphql"; + +interface ContinualImprovementRegistriesPageProps { + queryRef: PreloadedQuery; +} + +const continualImprovementRegistriesPageFragment = graphql` + fragment ContinualImprovementRegistriesPageFragment on Organization + @refetchable(queryName: "ContinualImprovementRegistriesPageRefetchQuery") + @argumentDefinitions( + first: { type: "Int", defaultValue: 10 } + after: { type: "CursorKey" } + ) { + id + continualImprovementRegistries(first: $first, after: $after) + @connection(key: "ContinualImprovementRegistriesPage_continualImprovementRegistries") { + __id + totalCount + edges { + node { + id + referenceId + description + source + targetDate + status + priority + audit { + id + name + framework { + id + name + } + } + owner { + id + fullName + } + createdAt + updatedAt + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +`; + +export default function ContinualImprovementRegistriesPage({ queryRef }: ContinualImprovementRegistriesPageProps) { + const { __ } = useTranslate(); + const organizationId = useOrganizationId(); + + usePageTitle(__("Continual Improvement Registries")); + + const organization = usePreloadedQuery( + graphql` + query ContinualImprovementRegistriesPageQuery($organizationId: ID!) { + node(id: $organizationId) { + ... on Organization { + ...ContinualImprovementRegistriesPageFragment + } + } + } + `, + queryRef + ); + + const { + data, + loadNext, + hasNext, + isLoadingNext, + } = usePaginationFragment< + ContinualImprovementRegistriesPageQuery, + ContinualImprovementRegistriesPageFragment$key + >(continualImprovementRegistriesPageFragment, organization.node); + if (!data) { + return
{__("Organization not found")}
; + } + + const connectionId = ConnectionHandler.getConnectionID( + organizationId, + ContinualImprovementRegistriesConnectionKey + ); + const registries = data?.continualImprovementRegistries?.edges?.map((edge) => edge.node) ?? []; + + return ( +
+ + + + + + + {registries.length > 0 ? ( + + + + + + + + + + + + + + + + {registries.map((registry) => ( + + ))} + +
{__("Reference ID")}{__("Description")}{__("Status")}{__("Priority")}{__("Audit")}{__("Owner")}{__("Target Date")}{__("Actions")}
+ + {hasNext && ( +
+ +
+ )} +
+ ) : ( + +
+

+ {__("No continual improvement registry entries yet")} +

+

+ {__("Create your first continual improvement registry entry to get started.")} +

+
+
+ )} +
+ ); +} + +function RegistryRow({ + registry, + connectionId, +}: { + registry: NodeOf>; + connectionId: string; +}) { + const organizationId = useOrganizationId(); + const { __ } = useTranslate(); + const [deleteRegistry] = useMutation(deleteContinualImprovementRegistryMutation); + const confirm = useConfirm(); + + const formatDate = (dateString: string) => { + return new Date(dateString).toLocaleDateString(); + }; + + const handleDelete = () => { + confirm( + () => + promisifyMutation(deleteRegistry)({ + variables: { + input: { + continualImprovementRegistryId: registry.id, + }, + connections: [connectionId], + }, + }), + { + message: sprintf( + __( + "This will permanently delete the continual improvement registry entry %s. This action cannot be undone." + ), + registry.referenceId + ), + } + ); + }; + + return ( + + + {registry.referenceId} + + {registry.description || "-"} + + + {getStatusLabel(registry.status)} + + + + + {registry.priority === "HIGH" ? __("High") : registry.priority === "MEDIUM" ? __("Medium") : __("Low")} + + + + {registry.audit.name + ? `${registry.audit.framework.name} - ${registry.audit.name}` + : registry.audit.framework.name + } + + {registry.owner?.fullName || "-"} + + {registry.targetDate ? ( + + ) : ( + {__("No target date")} + )} + + + + + {__("Delete")} + + + + + ); +} diff --git a/apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistryDetailsPage.tsx b/apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistryDetailsPage.tsx new file mode 100644 index 000000000..aafa149cc --- /dev/null +++ b/apps/console/src/pages/organizations/continualImprovementRegistries/ContinualImprovementRegistryDetailsPage.tsx @@ -0,0 +1,287 @@ +import { + ConnectionHandler, + usePreloadedQuery, + type PreloadedQuery, +} from "react-relay"; +import { + continualImprovementRegistryNodeQuery, + useDeleteContinualImprovementRegistry, + useUpdateContinualImprovementRegistry, + ContinualImprovementRegistriesConnectionKey, +} from "../../../hooks/graph/ContinualImprovementRegistryGraph"; +import { + ActionDropdown, + Badge, + Breadcrumb, + Button, + DropdownItem, + Field, + Option, + Input, + Card, + Textarea, + useToast, + Select, + Label, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useOrganizationId } from "/hooks/useOrganizationId"; +import { PeopleSelectField } from "/components/form/PeopleSelectField"; +import { AuditSelectField } from "/components/form/AuditSelectField"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; +import { Controller } from "react-hook-form"; +import z from "zod"; +import { getStatusVariant, getStatusLabel, formatDatetime } from "@probo/helpers"; +import type { ContinualImprovementRegistryGraphNodeQuery } from "/hooks/graph/__generated__/ContinualImprovementRegistryGraphNodeQuery.graphql"; + +const updateRegistrySchema = z.object({ + referenceId: z.string().min(1, "Reference ID is required"), + description: z.string().optional(), + source: z.string().optional(), + targetDate: z.string().optional(), + status: z.enum(["OPEN", "IN_PROGRESS", "CLOSED"]), + priority: z.enum(["LOW", "MEDIUM", "HIGH"]), + ownerId: z.string().min(1, "Owner is required"), + auditId: z.string().min(1, "Audit is required"), +}); + +type Props = { + queryRef: PreloadedQuery; +}; + +export default function ContinualImprovementRegistryDetailsPage(props: Props) { + const data = usePreloadedQuery(continualImprovementRegistryNodeQuery, props.queryRef); + const registry = data.node; + const { __ } = useTranslate(); + const { toast } = useToast(); + const organizationId = useOrganizationId(); + + if (!registry) { + return
{__("Continual improvement registry entry not found")}
; + } + + const updateRegistry = useUpdateContinualImprovementRegistry(); + + const connectionId = ConnectionHandler.getConnectionID( + organizationId, + ContinualImprovementRegistriesConnectionKey + ); + + const deleteRegistry = useDeleteContinualImprovementRegistry({ id: registry.id!, referenceId: registry.referenceId! }, connectionId); + + const { register, handleSubmit, formState, control } = useFormWithSchema( + updateRegistrySchema, + { + defaultValues: { + referenceId: registry.referenceId || "", + description: registry.description || "", + source: registry.source || "", + targetDate: registry.targetDate + ? new Date(registry.targetDate).toISOString().split("T")[0] + : "", + status: registry.status || "OPEN", + priority: registry.priority || "MEDIUM", + ownerId: registry.owner?.id || "", + auditId: registry.audit?.id || "", + }, + } + ); + + const onSubmit = handleSubmit(async (formData) => { + try { + await updateRegistry({ + id: registry.id!, + referenceId: formData.referenceId, + description: formData.description || undefined, + source: formData.source || undefined, + targetDate: formatDatetime(formData.targetDate), + status: formData.status, + priority: formData.priority, + ownerId: formData.ownerId, + auditId: formData.auditId, + }); + + toast({ + title: __("Success"), + description: __("Continual improvement registry entry updated successfully"), + variant: "success", + }); + } catch (error) { + toast({ + title: __("Error"), + description: __("Failed to update continual improvement registry entry"), + variant: "error", + }); + } + }); + + const statusOptions = [ + { value: "OPEN", label: __("Open") }, + { value: "IN_PROGRESS", label: __("In Progress") }, + { value: "CLOSED", label: __("Closed") }, + ]; + + const priorityOptions = [ + { value: "LOW", label: __("Low") }, + { value: "MEDIUM", label: __("Medium") }, + { value: "HIGH", label: __("High") }, + ]; + + return ( +
+
+ + + + {__("Delete")} + + +
+ + +
+
+
+

{registry.referenceId}

+ + {getStatusLabel(registry.status || "OPEN")} + + + {registry.priority === "HIGH" ? __("High") : registry.priority === "MEDIUM" ? __("Medium") : __("Low")} + +
+
+ +
+ + + + +
+ +