From c56563a85036b15b8db8adcec346065fa1db1375 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Fri, 19 Sep 2025 17:26:17 +0200 Subject: [PATCH] Add trust center references Signed-off-by: Sacha Al Himdani --- .../DeleteTrustCenterReferenceDialog.tsx | 83 + .../TrustCenterReferenceDialog.tsx | 262 ++ .../TrustCenterReferencesSection.tsx | 164 ++ .../src/hooks/graph/TrustCenterGraph.ts | 14 +- .../hooks/graph/TrustCenterReferenceGraph.ts | 133 + .../TrustCenterGraphQuery.graphql.ts | 142 +- ...terReferenceGraphCreateMutation.graphql.ts | 218 ++ ...terReferenceGraphDeleteMutation.graphql.ts | 132 + .../TrustCenterReferenceGraphQuery.graphql.ts | 333 +++ ...terReferenceGraphUpdateMutation.graphql.ts | 157 ++ .../src/hooks/useTrustCenterQueries.ts | 11 + .../trustCenter/TrustCenterPage.tsx | 5 + packages/helpers/src/dom.ts | 13 + packages/helpers/src/index.ts | 2 +- pkg/coredata/entity_type_reg.go | 1 + pkg/coredata/migrations/20250919T142754Z.sql | 13 + pkg/coredata/trust_center_reference.go | 304 +++ .../trust_center_reference_order_field.go | 51 + pkg/probo/service.go | 2 + pkg/probo/trust_center_reference_service.go | 408 +++ pkg/server/api/console/v1/schema.graphql | 100 + pkg/server/api/console/v1/schema/schema.go | 2183 +++++++++++++++++ .../console/v1/types/trust_center_access.go | 2 - .../v1/types/trust_center_reference.go | 65 + pkg/server/api/console/v1/types/types.go | 69 +- pkg/server/api/console/v1/v1_resolver.go | 131 + pkg/server/api/trust/v1/schema.graphql | 25 + pkg/server/api/trust/v1/schema/schema.go | 987 ++++++++ .../trust/v1/types/trust_center_reference.go | 49 + pkg/server/api/trust/v1/types/types.go | 44 +- pkg/server/api/trust/v1/v1_resolver.go | 36 + pkg/trust/service.go | 2 + pkg/trust/trust_center_reference_service.go | 102 + 33 files changed, 6187 insertions(+), 56 deletions(-) create mode 100644 apps/console/src/components/trustCenter/DeleteTrustCenterReferenceDialog.tsx create mode 100644 apps/console/src/components/trustCenter/TrustCenterReferenceDialog.tsx create mode 100644 apps/console/src/components/trustCenter/TrustCenterReferencesSection.tsx create mode 100644 apps/console/src/hooks/graph/TrustCenterReferenceGraph.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterReferenceGraphCreateMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterReferenceGraphDeleteMutation.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterReferenceGraphQuery.graphql.ts create mode 100644 apps/console/src/hooks/graph/__generated__/TrustCenterReferenceGraphUpdateMutation.graphql.ts create mode 100644 pkg/coredata/migrations/20250919T142754Z.sql create mode 100644 pkg/coredata/trust_center_reference.go create mode 100644 pkg/coredata/trust_center_reference_order_field.go create mode 100644 pkg/probo/trust_center_reference_service.go create mode 100644 pkg/server/api/console/v1/types/trust_center_reference.go create mode 100644 pkg/server/api/trust/v1/types/trust_center_reference.go create mode 100644 pkg/trust/trust_center_reference_service.go diff --git a/apps/console/src/components/trustCenter/DeleteTrustCenterReferenceDialog.tsx b/apps/console/src/components/trustCenter/DeleteTrustCenterReferenceDialog.tsx new file mode 100644 index 000000000..2fd399d50 --- /dev/null +++ b/apps/console/src/components/trustCenter/DeleteTrustCenterReferenceDialog.tsx @@ -0,0 +1,83 @@ +import { + Button, + Dialog, + DialogContent, + DialogFooter, + IconTrashCan, + Spinner, + useDialogRef, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { sprintf } from "@probo/helpers"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { deleteTrustCenterReferenceMutation } from "/hooks/graph/TrustCenterReferenceGraph"; + +type Props = { + children: React.ReactNode; + referenceId: string; + referenceName: string; + connectionId: string; + onSuccess?: () => void; +}; + +export function DeleteTrustCenterReferenceDialog({ + children, + referenceId, + referenceName, + connectionId, + onSuccess, +}: Props) { + const { __ } = useTranslate(); + const ref = useDialogRef(); + + const [mutate, isDeleting] = useMutationWithToasts(deleteTrustCenterReferenceMutation, { + successMessage: __("Reference deleted successfully"), + errorMessage: __("Failed to delete reference"), + }); + + const handleDelete = async () => { + await mutate({ + variables: { + input: { + id: referenceId, + }, + connections: [connectionId], + }, + }); + + onSuccess?.(); + ref.current?.close(); + }; + + return ( + + +

+ {sprintf( + __("Are you sure you want to delete the reference \"%s\"?"), + referenceName + )} +

+

+ {__("This action cannot be undone.")} +

+
+ + + + +
+ ); +} diff --git a/apps/console/src/components/trustCenter/TrustCenterReferenceDialog.tsx b/apps/console/src/components/trustCenter/TrustCenterReferenceDialog.tsx new file mode 100644 index 000000000..8713914f2 --- /dev/null +++ b/apps/console/src/components/trustCenter/TrustCenterReferenceDialog.tsx @@ -0,0 +1,262 @@ +import { useTranslate } from "@probo/i18n"; +import { + Button, + Dialog, + DialogContent, + DialogFooter, + Dropzone, + Field, + Spinner, + Textarea, + useDialogRef, +} from "@probo/ui"; +import { type ReactNode, useState, useImperativeHandle, forwardRef } from "react"; +import { z } from "zod"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; +import { + useCreateTrustCenterReferenceMutation, + useUpdateTrustCenterReferenceMutation +} from "/hooks/graph/TrustCenterReferenceGraph"; + +const referenceSchema = z.object({ + name: z.string().min(1, "Name is required"), + description: z.string(), + websiteUrl: z.string().url("Please enter a valid URL"), +}); + +type ReferenceFormData = z.infer; + +export type TrustCenterReferenceDialogRef = { + openCreate: (trustCenterId: string, connectionId: string) => void; + openEdit: (reference: { + id: string; + name: string; + description: string; + websiteUrl: string; + }) => void; +}; + +type Reference = { + id: string; + name: string; + description: string; + websiteUrl: string; +}; + +export const TrustCenterReferenceDialog = forwardRef( + function TrustCenterReferenceDialog({ children }, ref) { + const { __ } = useTranslate(); + const dialogRef = useDialogRef(); + const [mode, setMode] = useState<'create' | 'edit'>('create'); + const [trustCenterId, setTrustCenterId] = useState(""); + const [connectionId, setConnectionId] = useState(""); + const [editReference, setEditReference] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + + const [createReference, isCreating] = useCreateTrustCenterReferenceMutation(); + const [updateReference, isUpdating] = useUpdateTrustCenterReferenceMutation(); + + const { register, handleSubmit, formState: { errors }, reset } = useFormWithSchema( + referenceSchema, + { + defaultValues: { + name: "", + description: "", + websiteUrl: "", + }, + } + ); + + useImperativeHandle(ref, () => ({ + openCreate: (tId: string, cId: string) => { + setMode('create'); + setTrustCenterId(tId); + setConnectionId(cId); + setEditReference(null); + setUploadedFile(null); + reset({ + name: "", + description: "", + websiteUrl: "", + }); + dialogRef.current?.open(); + }, + openEdit: (reference: Reference) => { + setMode('edit'); + setEditReference(reference); + setUploadedFile(null); + reset({ + name: reference.name, + description: reference.description, + websiteUrl: reference.websiteUrl, + }); + dialogRef.current?.open(); + }, + })); + + const handleDrop = (files: File[]) => { + if (files.length > 0) { + const file = files[0]; + setUploadedFile(file); + } + }; + + const onSubmit = handleSubmit(async (data: ReferenceFormData) => { + if (mode === 'create') { + if (!uploadedFile) { + return; + } + + await createReference({ + variables: { + input: { + trustCenterId, + name: data.name, + description: data.description, + websiteUrl: data.websiteUrl, + logoFile: null, + }, + connections: [connectionId], + }, + uploadables: { + "input.logoFile": uploadedFile, + }, + onSuccess: () => { + reset(); + setUploadedFile(null); + dialogRef.current?.close(); + }, + }); + } else if (editReference) { + const input: { + id: string; + name: string; + description: string; + websiteUrl: string; + logoFile?: null; + } = { + id: editReference.id, + name: data.name, + description: data.description, + websiteUrl: data.websiteUrl, + }; + + const uploadables: Record = {}; + + if (uploadedFile) { + input.logoFile = null; + uploadables["input.logoFile"] = uploadedFile; + } + + await updateReference({ + variables: { input }, + uploadables: Object.keys(uploadables).length > 0 ? uploadables : undefined, + onSuccess: () => { + reset(); + setUploadedFile(null); + dialogRef.current?.close(); + }, + }); + } + }); + + const handleClose = () => { + reset(); + setUploadedFile(null); + }; + + const isSubmitting = isCreating || isUpdating; + const title = mode === 'create' ? __("Add Reference") : __("Edit Reference"); + + return ( + <> + {children && ( + mode === 'create' && dialogRef.current?.open()}> + {children} + + )} + + +
+ + + + +