Add validator lib

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-11-03 08:19:09 +01:00
committed by Sacha Al Himdani
parent 288c59a5f2
commit f9216d30b2
102 changed files with 7409 additions and 1068 deletions

View File

@@ -1,7 +1,7 @@
import { useTranslate } from "@probo/i18n";
import { Option } from "@probo/ui";
import type {
ProcessingActivitySpecialOrCriminalData,
ProcessingActivitySpecialOrCriminalDatum,
ProcessingActivityLawfulBasis,
ProcessingActivityDataProtectionImpactAssessment,
ProcessingActivityTransferImpactAssessment,
@@ -11,7 +11,7 @@ export function SpecialOrCriminalDataOptions() {
const { __ } = useTranslate();
const options: Array<{
value: ProcessingActivitySpecialOrCriminalData;
value: ProcessingActivitySpecialOrCriminalDatum;
label: string;
}> = [
{ value: "YES", label: __("Yes") },
@@ -56,16 +56,19 @@ export function LawfulBasisOptions() {
);
}
export function getLawfulBasisLabel(value: ProcessingActivityLawfulBasis | null | undefined, __: (key: string) => string): string {
export function getLawfulBasisLabel(
value: ProcessingActivityLawfulBasis | null | undefined,
__: (key: string) => string
): string {
if (!value) return "-";
const labels = {
"CONSENT": __("Consent"),
"CONTRACTUAL_NECESSITY": __("Contractual Necessity"),
"LEGAL_OBLIGATION": __("Legal Obligation"),
"LEGITIMATE_INTEREST": __("Legitimate Interest"),
"PUBLIC_TASK": __("Public Task"),
"VITAL_INTERESTS": __("Vital Interests"),
CONSENT: __("Consent"),
CONTRACTUAL_NECESSITY: __("Contractual Necessity"),
LEGAL_OBLIGATION: __("Legal Obligation"),
LEGITIMATE_INTEREST: __("Legitimate Interest"),
PUBLIC_TASK: __("Public Task"),
VITAL_INTERESTS: __("Vital Interests"),
};
return labels[value] || value;
@@ -79,12 +82,18 @@ export function TransferSafeguardsOptions() {
label: string;
}> = [
{ value: "__NONE__", label: __("None") },
{ value: "STANDARD_CONTRACTUAL_CLAUSES", label: __("Standard Contractual Clauses") },
{
value: "STANDARD_CONTRACTUAL_CLAUSES",
label: __("Standard Contractual Clauses"),
},
{ value: "BINDING_CORPORATE_RULES", label: __("Binding Corporate Rules") },
{ value: "ADEQUACY_DECISION", label: __("Adequacy Decision") },
{ value: "DEROGATIONS", label: __("Derogations") },
{ value: "CODES_OF_CONDUCT", label: __("Codes of Conduct") },
{ value: "CERTIFICATION_MECHANISMS", label: __("Certification Mechanisms") },
{
value: "CERTIFICATION_MECHANISMS",
label: __("Certification Mechanisms"),
},
];
return (

View File

@@ -107,6 +107,14 @@ export function useVendorForm(vendorKey: useVendorFormFragment$key) {
id: vendor.id,
...data,
description: data.description || null,
statusPageUrl: data.statusPageUrl || null,
termsOfServiceUrl: data.termsOfServiceUrl || null,
privacyPolicyUrl: data.privacyPolicyUrl || null,
serviceLevelAgreementUrl: data.serviceLevelAgreementUrl || null,
dataProcessingAgreementUrl: data.dataProcessingAgreementUrl || null,
websiteUrl: data.websiteUrl || null,
securityPageUrl: data.securityPageUrl || null,
trustPageUrl: data.trustPageUrl || null,
},
},
}).then(() => {

View File

@@ -3,6 +3,7 @@ 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 assetsQuery = graphql`
query AssetGraphListQuery($organizationId: ID!, $snapshotId: ID) {
@@ -197,8 +198,11 @@ export const useCreateAsset = (connectionId: string) => {
};
export const useUpdateAsset = () => {
const [mutate] = useMutation(updateAssetMutation);
const { __ } = useTranslate();
const [mutate] = useMutationWithToasts(updateAssetMutation, {
successMessage: __("Asset updated successfully"),
errorMessage: __("Failed to update asset"),
});
return (input: {
id: string;
@@ -213,7 +217,7 @@ export const useUpdateAsset = () => {
return alert(__("Failed to update asset: asset ID is required"));
}
return promisifyMutation(mutate)({
return mutate({
variables: {
input,
},

View File

@@ -151,7 +151,7 @@ export const useCreateAudit = (connectionId: string) => {
return (input: {
organizationId: string;
frameworkId: string;
name?: string;
name?: string | null;
validFrom?: string;
validUntil?: string;
reportKey?: string;
@@ -187,7 +187,7 @@ export const useUpdateAudit = () => {
return (input: {
id: string;
name?: string;
name?: string | null;
validFrom?: string | null;
validUntil?: string | null;
state?: string;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<d01ca9f47a4ce6e732cffd5deb9150c6>>
* @generated SignedSource<<a804557b48f2dbc4749c8399e708b9fe>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -11,9 +11,9 @@
import { ConcreteRequest } from 'relay-runtime';
export type ProcessingActivityDataProtectionImpactAssessment = "NEEDED" | "NOT_NEEDED";
export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS";
export type ProcessingActivitySpecialOrCriminalData = "NO" | "POSSIBLE" | "YES";
export type ProcessingActivitySpecialOrCriminalDatum = "NO" | "POSSIBLE" | "YES";
export type ProcessingActivityTransferImpactAssessment = "NEEDED" | "NOT_NEEDED";
export type ProcessingActivityTransferSafeguards = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES";
export type ProcessingActivityTransferSafeguard = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES";
export type CreateProcessingActivityInput = {
consentEvidenceLink?: string | null | undefined;
dataProtectionImpactAssessment: ProcessingActivityDataProtectionImpactAssessment;
@@ -28,9 +28,9 @@ export type CreateProcessingActivityInput = {
recipients?: string | null | undefined;
retentionPeriod?: string | null | undefined;
securityMeasures?: string | null | undefined;
specialOrCriminalData: ProcessingActivitySpecialOrCriminalData;
specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum;
transferImpactAssessment: ProcessingActivityTransferImpactAssessment;
transferSafeguards?: ProcessingActivityTransferSafeguards | null | undefined;
transferSafeguards?: ProcessingActivityTransferSafeguard | null | undefined;
vendorIds?: ReadonlyArray<string> | null | undefined;
};
export type ProcessingActivityGraphCreateMutation$variables = {
@@ -55,9 +55,9 @@ export type ProcessingActivityGraphCreateMutation$data = {
readonly recipients: string | null | undefined;
readonly retentionPeriod: string | null | undefined;
readonly securityMeasures: string | null | undefined;
readonly specialOrCriminalData: ProcessingActivitySpecialOrCriminalData;
readonly specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum;
readonly transferImpactAssessment: ProcessingActivityTransferImpactAssessment;
readonly transferSafeguards: ProcessingActivityTransferSafeguards | null | undefined;
readonly transferSafeguards: ProcessingActivityTransferSafeguard | null | undefined;
readonly vendors: {
readonly edges: ReadonlyArray<{
readonly node: {

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<5dea7ccaf98a1223d9e4cc1ecdfbb0bc>>
* @generated SignedSource<<736925258373b1116c286fc16d19ad7d>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -11,9 +11,9 @@
import { ConcreteRequest } from 'relay-runtime';
export type ProcessingActivityDataProtectionImpactAssessment = "NEEDED" | "NOT_NEEDED";
export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS";
export type ProcessingActivitySpecialOrCriminalData = "NO" | "POSSIBLE" | "YES";
export type ProcessingActivitySpecialOrCriminalDatum = "NO" | "POSSIBLE" | "YES";
export type ProcessingActivityTransferImpactAssessment = "NEEDED" | "NOT_NEEDED";
export type ProcessingActivityTransferSafeguards = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES";
export type ProcessingActivityTransferSafeguard = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES";
export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL";
export type ProcessingActivityGraphNodeQuery$variables = {
processingActivityId: string;
@@ -39,9 +39,9 @@ export type ProcessingActivityGraphNodeQuery$data = {
readonly retentionPeriod?: string | null | undefined;
readonly securityMeasures?: string | null | undefined;
readonly snapshotId?: string | null | undefined;
readonly specialOrCriminalData?: ProcessingActivitySpecialOrCriminalData;
readonly specialOrCriminalData?: ProcessingActivitySpecialOrCriminalDatum;
readonly transferImpactAssessment?: ProcessingActivityTransferImpactAssessment;
readonly transferSafeguards?: ProcessingActivityTransferSafeguards | null | undefined;
readonly transferSafeguards?: ProcessingActivityTransferSafeguard | null | undefined;
readonly updatedAt?: any;
readonly vendors?: {
readonly edges: ReadonlyArray<{

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<08099a83039838c6c79dbf1ca7c99034>>
* @generated SignedSource<<7004a9f42c1d7e16eadf8adbdb613b2a>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -11,9 +11,9 @@
import { ConcreteRequest } from 'relay-runtime';
export type ProcessingActivityDataProtectionImpactAssessment = "NEEDED" | "NOT_NEEDED";
export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS";
export type ProcessingActivitySpecialOrCriminalData = "NO" | "POSSIBLE" | "YES";
export type ProcessingActivitySpecialOrCriminalDatum = "NO" | "POSSIBLE" | "YES";
export type ProcessingActivityTransferImpactAssessment = "NEEDED" | "NOT_NEEDED";
export type ProcessingActivityTransferSafeguards = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES";
export type ProcessingActivityTransferSafeguard = "ADEQUACY_DECISION" | "BINDING_CORPORATE_RULES" | "CERTIFICATION_MECHANISMS" | "CODES_OF_CONDUCT" | "DEROGATIONS" | "STANDARD_CONTRACTUAL_CLAUSES";
export type UpdateProcessingActivityInput = {
consentEvidenceLink?: string | null | undefined;
dataProtectionImpactAssessment?: ProcessingActivityDataProtectionImpactAssessment | null | undefined;
@@ -28,9 +28,9 @@ export type UpdateProcessingActivityInput = {
recipients?: string | null | undefined;
retentionPeriod?: string | null | undefined;
securityMeasures?: string | null | undefined;
specialOrCriminalData?: ProcessingActivitySpecialOrCriminalData | null | undefined;
specialOrCriminalData?: ProcessingActivitySpecialOrCriminalDatum | null | undefined;
transferImpactAssessment?: ProcessingActivityTransferImpactAssessment | null | undefined;
transferSafeguards?: ProcessingActivityTransferSafeguards | null | undefined;
transferSafeguards?: ProcessingActivityTransferSafeguard | null | undefined;
vendorIds?: ReadonlyArray<string> | null | undefined;
};
export type ProcessingActivityGraphUpdateMutation$variables = {
@@ -52,9 +52,9 @@ export type ProcessingActivityGraphUpdateMutation$data = {
readonly recipients: string | null | undefined;
readonly retentionPeriod: string | null | undefined;
readonly securityMeasures: string | null | undefined;
readonly specialOrCriminalData: ProcessingActivitySpecialOrCriminalData;
readonly specialOrCriminalData: ProcessingActivitySpecialOrCriminalDatum;
readonly transferImpactAssessment: ProcessingActivityTransferImpactAssessment;
readonly transferSafeguards: ProcessingActivityTransferSafeguards | null | undefined;
readonly transferSafeguards: ProcessingActivityTransferSafeguard | null | undefined;
readonly updatedAt: any;
readonly vendors: {
readonly edges: ReadonlyArray<{

View File

@@ -80,15 +80,11 @@ export default function AssetDetailsPage(props: Props) {
const updateAsset = useUpdateAsset();
const onSubmit = handleSubmit(async (formData) => {
try {
await updateAsset({
id: assetEntry?.id,
...formData,
});
reset(formData);
} catch (error) {
console.error("Failed to update asset:", error);
}
await updateAsset({
id: assetEntry?.id,
...formData,
});
reset(formData);
});
const breadcrumbAssetsUrl = isSnapshotMode && snapshotId

View File

@@ -36,7 +36,7 @@ import { getAuditStateLabel, getAuditStateVariant, auditStates, fileSize, sprint
import type { AuditGraphNodeQuery } from "/hooks/graph/__generated__/AuditGraphNodeQuery.graphql";
const updateAuditSchema = z.object({
name: z.string().optional(),
name: z.string().nullable().optional(),
validFrom: z.string().optional(),
validUntil: z.string().optional(),
state: z.enum(["NOT_STARTED", "IN_PROGRESS", "COMPLETED", "REJECTED", "OUTDATED"]),
@@ -63,7 +63,7 @@ export default function AuditDetailsPage(props: Props) {
const { control, formState, handleSubmit, register, reset } = useFormWithSchema(updateAuditSchema, {
defaultValues: {
name: auditEntry.name || "",
name: auditEntry.name || null,
validFrom: auditEntry.validFrom?.split('T')[0] || "",
validUntil: auditEntry.validUntil?.split('T')[0] || "",
state: auditEntry.state || "NOT_STARTED",
@@ -82,7 +82,7 @@ export default function AuditDetailsPage(props: Props) {
try {
await updateAudit({
id: auditEntry.id,
name: formData.name,
name: formData.name || null,
validFrom: formatDatetime(formData.validFrom) ?? null,
validUntil: formatDatetime(formData.validUntil) ?? null,
state: formData.state,

View File

@@ -79,7 +79,7 @@ export function CreateAuditDialog({
await createAudit({
organizationId,
frameworkId: data.frameworkId,
name: data.name,
name: data.name || null,
validFrom: formatDatetime(data.validFrom),
validUntil: formatDatetime(data.validUntil),
state: data.state,