From ff7ba08fc1158739be728d3b7c9aa470a2174174 Mon Sep 17 00:00:00 2001 From: Yannis Varni Date: Fri, 3 Oct 2025 15:38:00 +0200 Subject: [PATCH] File refs in one table Added a file service Refactored evidence and vendor compliance associated services and resolvers Created SQL migration scripts Updated GraphQL schema accordingly and the UI components Removed unused methods and resolvers for evidence service Signed-off-by: Yannis Varni --- apps/console/src/hooks/graph/EvidenceGraph.ts | 9 +- .../EvidenceGraphFileQuery.graphql.ts | 65 +- .../MeasureGraphNodeQuery.graphql.ts | 50 +- .../VendorGraphNodeQuery.graphql.ts | 37 +- .../dialog/EvidenceDownloadDialog.tsx | 2 +- .../measures/dialog/EvidencePreviewDialog.tsx | 24 +- ...ateEvidenceDialogUploadMutation.graphql.ts | 50 +- .../measures/tabs/MeasureEvidencesTab.tsx | 25 +- .../MeasureEvidencesTabFragment.graphql.ts | 47 +- ...reEvidencesTabFragment_evidence.graphql.ts | 55 +- .../MeasureEvidencesTabQuery.graphql.ts | 52 +- .../ImportAssessmentDialogMutation.graphql.ts | 43 +- .../vendors/tabs/VendorComplianceTab.tsx | 9 +- .../ComplianceReportListQuery.graphql.ts | 43 +- ...dorComplianceTabFragment_report.graphql.ts | 47 +- ...mplianceTabUploadReportMutation.graphql.ts | 43 +- pkg/coredata/evidence.go | 162 +- pkg/coredata/file.go | 36 + pkg/coredata/migrations/20251003T132724Z.sql | 41 + pkg/coredata/migrations/20251003T151644Z.sql | 41 + pkg/coredata/migrations/20251006T133729Z.sql | 7 + pkg/coredata/vendor_compliance_report.go | 75 +- pkg/filevalidation/validator.go | 1 + pkg/probo/evidence_service.go | 391 +---- pkg/probo/file_service.go | 187 +++ pkg/probo/framework_service.go | 11 +- pkg/probo/service.go | 4 +- pkg/probo/vendor_compliance_report_service.go | 131 +- pkg/server/api/console/v1/schema.graphql | 31 +- pkg/server/api/console/v1/schema/schema.go | 1325 +++++++---------- pkg/server/api/console/v1/types/evidence.go | 6 - pkg/server/api/console/v1/types/file.go | 30 + pkg/server/api/console/v1/types/types.go | 26 +- .../v1/types/vendor_compliance_report.go | 1 - pkg/server/api/console/v1/v1_resolver.go | 137 +- 35 files changed, 1586 insertions(+), 1658 deletions(-) create mode 100644 pkg/coredata/migrations/20251003T132724Z.sql create mode 100644 pkg/coredata/migrations/20251003T151644Z.sql create mode 100644 pkg/coredata/migrations/20251006T133729Z.sql create mode 100644 pkg/probo/file_service.go create mode 100644 pkg/server/api/console/v1/types/file.go diff --git a/apps/console/src/hooks/graph/EvidenceGraph.ts b/apps/console/src/hooks/graph/EvidenceGraph.ts index a7bfee726..1418eb4ed 100644 --- a/apps/console/src/hooks/graph/EvidenceGraph.ts +++ b/apps/console/src/hooks/graph/EvidenceGraph.ts @@ -5,9 +5,12 @@ export const evidenceFileQuery = graphql` node(id: $evidenceId) { ... on Evidence { id - mimeType - filename - fileUrl + file { + mimeType + fileName + size + downloadUrl + } } } } diff --git a/apps/console/src/hooks/graph/__generated__/EvidenceGraphFileQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/EvidenceGraphFileQuery.graphql.ts index efbf0c457..d0257b410 100644 --- a/apps/console/src/hooks/graph/__generated__/EvidenceGraphFileQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/EvidenceGraphFileQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<0c4d6a4bd477e15ae3c627cf338a99dd>> + * @generated SignedSource<<843df409ed1ee9ba19760921dbd6e8df>> * @lightSyntaxTransform * @nogrep */ @@ -14,10 +14,13 @@ export type EvidenceGraphFileQuery$variables = { }; export type EvidenceGraphFileQuery$data = { readonly node: { - readonly fileUrl?: string | null | undefined; - readonly filename?: string; + readonly file?: { + readonly downloadUrl: string; + readonly fileName: string; + readonly mimeType: string; + readonly size: any; + } | null | undefined; readonly id?: string; - readonly mimeType?: string; }; }; export type EvidenceGraphFileQuery = { @@ -58,14 +61,21 @@ v4 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "filename", + "name": "fileName", "storageKey": null }, v5 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "fileUrl", + "name": "size", + "storageKey": null +}, +v6 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "downloadUrl", "storageKey": null }; return { @@ -87,9 +97,21 @@ return { "kind": "InlineFragment", "selections": [ (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/), - (v5/*: any*/) + { + "alias": null, + "args": null, + "concreteType": "File", + "kind": "LinkedField", + "name": "file", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/) + ], + "storageKey": null + } ], "type": "Evidence", "abstractKey": null @@ -126,9 +148,22 @@ return { { "kind": "InlineFragment", "selections": [ - (v3/*: any*/), - (v4/*: any*/), - (v5/*: any*/) + { + "alias": null, + "args": null, + "concreteType": "File", + "kind": "LinkedField", + "name": "file", + "plural": false, + "selections": [ + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + } ], "type": "Evidence", "abstractKey": null @@ -139,16 +174,16 @@ return { ] }, "params": { - "cacheID": "db46f9bf993514c7bc89845e6d6459f8", + "cacheID": "780e108a52d2fcbde6653de5d2ee058b", "id": null, "metadata": {}, "name": "EvidenceGraphFileQuery", "operationKind": "query", - "text": "query EvidenceGraphFileQuery(\n $evidenceId: ID!\n) {\n node(id: $evidenceId) {\n __typename\n ... on Evidence {\n id\n mimeType\n filename\n fileUrl\n }\n id\n }\n}\n" + "text": "query EvidenceGraphFileQuery(\n $evidenceId: ID!\n) {\n node(id: $evidenceId) {\n __typename\n ... on Evidence {\n id\n file {\n mimeType\n fileName\n size\n downloadUrl\n id\n }\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "3c9aa6ff338d2380a7a03b8ea61e83e0"; +(node as any).hash = "186386e82f82feb9c5b5a54f9d937903"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/MeasureGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/MeasureGraphNodeQuery.graphql.ts index 94920b3e0..1338faeef 100644 --- a/apps/console/src/hooks/graph/__generated__/MeasureGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/MeasureGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<074d65be2a59b6b8284ff6be0f75707d>> + * @generated SignedSource<<1f413a42110dae78274cf3250fa4db4e>> * @lightSyntaxTransform * @nogrep */ @@ -594,22 +594,34 @@ return { { "alias": null, "args": null, - "kind": "ScalarField", - "name": "filename", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "mimeType", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "size", + "concreteType": "File", + "kind": "LinkedField", + "name": "file", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mimeType", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "size", + "storageKey": null + }, + (v2/*: any*/) + ], "storageKey": null }, { @@ -660,12 +672,12 @@ return { ] }, "params": { - "cacheID": "6146a6fada0328c7b69652646212be05", + "cacheID": "d20815cee9ca8dec2e09fcefdd54a68a", "id": null, "metadata": {}, "name": "MeasureGraphNodeQuery", "operationKind": "query", - "text": "query MeasureGraphNodeQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n name\n description\n state\n category\n evidencesInfos: evidences(first: 0) {\n totalCount\n }\n risksInfos: risks(first: 0) {\n totalCount\n }\n tasksInfos: tasks(first: 0) {\n totalCount\n }\n controlsInfos: controls(first: 0) {\n totalCount\n }\n ...MeasureRisksTabFragment\n ...MeasureTasksTabFragment\n ...MeasureControlsTabFragment\n ...MeasureFormDialogMeasureFragment\n ...MeasureEvidencesTabFragment\n }\n id\n }\n}\n\nfragment LinkedControlsCardFragment on Control {\n id\n name\n sectionTitle\n framework {\n id\n name\n }\n}\n\nfragment LinkedRisksCardFragment on Risk {\n id\n name\n inherentRiskScore\n residualRiskScore\n}\n\nfragment MeasureControlsTabFragment on Measure {\n id\n controls(first: 20) {\n edges {\n node {\n id\n ...LinkedControlsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment on Measure {\n id\n evidences(first: 50) {\n edges {\n node {\n id\n filename\n mimeType\n ...MeasureEvidencesTabFragment_evidence\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment_evidence on Evidence {\n id\n filename\n size\n type\n createdAt\n mimeType\n}\n\nfragment MeasureFormDialogMeasureFragment on Measure {\n id\n description\n name\n category\n state\n}\n\nfragment MeasureRisksTabFragment on Measure {\n id\n risks(first: 100) {\n edges {\n node {\n id\n ...LinkedRisksCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment MeasureTasksTabFragment on Measure {\n tasks(first: 100) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n" + "text": "query MeasureGraphNodeQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n name\n description\n state\n category\n evidencesInfos: evidences(first: 0) {\n totalCount\n }\n risksInfos: risks(first: 0) {\n totalCount\n }\n tasksInfos: tasks(first: 0) {\n totalCount\n }\n controlsInfos: controls(first: 0) {\n totalCount\n }\n ...MeasureRisksTabFragment\n ...MeasureTasksTabFragment\n ...MeasureControlsTabFragment\n ...MeasureFormDialogMeasureFragment\n ...MeasureEvidencesTabFragment\n }\n id\n }\n}\n\nfragment LinkedControlsCardFragment on Control {\n id\n name\n sectionTitle\n framework {\n id\n name\n }\n}\n\nfragment LinkedRisksCardFragment on Risk {\n id\n name\n inherentRiskScore\n residualRiskScore\n}\n\nfragment MeasureControlsTabFragment on Measure {\n id\n controls(first: 20) {\n edges {\n node {\n id\n ...LinkedControlsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment on Measure {\n id\n evidences(first: 50) {\n edges {\n node {\n id\n file {\n fileName\n mimeType\n size\n id\n }\n ...MeasureEvidencesTabFragment_evidence\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment MeasureEvidencesTabFragment_evidence on Evidence {\n id\n file {\n fileName\n mimeType\n size\n id\n }\n type\n createdAt\n}\n\nfragment MeasureFormDialogMeasureFragment on Measure {\n id\n description\n name\n category\n state\n}\n\nfragment MeasureRisksTabFragment on Measure {\n id\n risks(first: 100) {\n edges {\n node {\n id\n ...LinkedRisksCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment MeasureTasksTabFragment on Measure {\n tasks(first: 100) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n" } }; })(); diff --git a/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts index c48553457..c132831e8 100644 --- a/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -145,7 +145,7 @@ v13 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "fileUrl", + "name": "fileName", "storageKey": null }, v14 = { @@ -229,14 +229,14 @@ v23 = { }, v24 = [ (v3/*: any*/), + (v13/*: any*/), { "alias": null, "args": null, "kind": "ScalarField", - "name": "fileName", + "name": "fileUrl", "storageKey": null }, - (v13/*: any*/), { "alias": null, "args": null, @@ -500,12 +500,31 @@ return { "name": "reportName", "storageKey": null }, - (v13/*: any*/), { "alias": null, "args": null, - "kind": "ScalarField", - "name": "fileSize", + "concreteType": "File", + "kind": "LinkedField", + "name": "file", + "plural": false, + "selections": [ + (v13/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mimeType", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "size", + "storageKey": null + }, + (v3/*: any*/) + ], "storageKey": null }, (v9/*: any*/) @@ -791,12 +810,12 @@ return { ] }, "params": { - "cacheID": "4a112f861864990f5022d279ba8d43d4", + "cacheID": "faee4f059ef9baab46d5f2420e36bb60", "id": null, "metadata": {}, "name": "VendorGraphNodeQuery", "operationKind": "query", - "text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n snapshotId\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorServicesTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n ...VendorOverviewTabDataPrivacyAgreementFragment\n }\n id\n }\n viewer {\n user {\n id\n people(organizationId: $organizationId) {\n id\n }\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorOverviewTabDataPrivacyAgreementFragment on Vendor {\n dataPrivacyAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n createdAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment VendorServicesTabFragment on Vendor {\n services(first: 50) {\n edges {\n node {\n id\n ...VendorServicesTabFragment_service\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorServicesTabFragment_service on VendorService {\n id\n name\n description\n createdAt\n updatedAt\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n category\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n countries\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n" + "text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n snapshotId\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorServicesTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n ...VendorOverviewTabDataPrivacyAgreementFragment\n }\n id\n }\n viewer {\n user {\n id\n people(organizationId: $organizationId) {\n id\n }\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n file {\n fileName\n mimeType\n size\n id\n }\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorOverviewTabDataPrivacyAgreementFragment on Vendor {\n dataPrivacyAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n createdAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment VendorServicesTabFragment on Vendor {\n services(first: 50) {\n edges {\n node {\n id\n ...VendorServicesTabFragment_service\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorServicesTabFragment_service on VendorService {\n id\n name\n description\n createdAt\n updatedAt\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n category\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n countries\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n" } }; })(); diff --git a/apps/console/src/pages/organizations/measures/dialog/EvidenceDownloadDialog.tsx b/apps/console/src/pages/organizations/measures/dialog/EvidenceDownloadDialog.tsx index c935fda8f..a75cdc1cf 100644 --- a/apps/console/src/pages/organizations/measures/dialog/EvidenceDownloadDialog.tsx +++ b/apps/console/src/pages/organizations/measures/dialog/EvidenceDownloadDialog.tsx @@ -50,7 +50,7 @@ function DownloadLink({ evidenceId, onClose }: Props) { const evidence = data.node; useEffect(() => { - downloadFile(evidence.fileUrl, evidence.filename ?? "evidence"); + downloadFile(evidence.file?.downloadUrl, evidence.file?.fileName ?? "evidence"); onClose(); }, [evidence]); diff --git a/apps/console/src/pages/organizations/measures/dialog/EvidencePreviewDialog.tsx b/apps/console/src/pages/organizations/measures/dialog/EvidencePreviewDialog.tsx index 19297ff6c..31d5d19a9 100644 --- a/apps/console/src/pages/organizations/measures/dialog/EvidencePreviewDialog.tsx +++ b/apps/console/src/pages/organizations/measures/dialog/EvidencePreviewDialog.tsx @@ -75,13 +75,13 @@ function EvidencePreviewContent({ const { __ } = useTranslate(); const { toast } = useToast(); const isUriFile = - evidence.mimeType === "text/uri-list" || evidence.mimeType === "text/uri"; + evidence.file?.mimeType === "text/uri-list" || evidence.file?.mimeType === "text/uri"; useEffect(() => { if (!isUriFile) { return; } const abortController = new AbortController(); - fetchUrlFromUriFile(evidence.fileUrl ?? "", { + fetchUrlFromUriFile(evidence.file?.downloadUrl ?? "", { signal: abortController.signal, }) .then((url) => { @@ -101,9 +101,9 @@ function EvidencePreviewContent({ return () => { abortController.abort(); }; - }, [evidence.fileUrl, isUriFile]); + }, [evidence.file?.downloadUrl, isUriFile]); - if (!evidence.fileUrl) { + if (!evidence.file?.downloadUrl) { return null; } @@ -115,22 +115,22 @@ function EvidencePreviewContent({ ); } - if (evidence.mimeType?.startsWith("image/")) { + if (evidence.file.mimeType?.startsWith("image/")) { return ( {evidence.filename} ); } - if (evidence.mimeType?.includes("pdf")) { + if (evidence.file.mimeType?.includes("pdf")) { return (