@@ -16,6 +16,8 @@ import {
1616 useConfirm ,
1717 Tabs ,
1818 TabItem ,
19+ IconArrowDown ,
20+ Spinner ,
1921} from "@probo/ui" ;
2022import { useTranslate } from "@probo/i18n" ;
2123import { usePageTitle } from "@probo/hooks" ;
@@ -32,7 +34,8 @@ import { useOrganizationId } from "/hooks/useOrganizationId";
3234import { useParams } from "react-router" ;
3335import { CreateProcessingActivityDialog } from "./dialogs/CreateProcessingActivityDialog" ;
3436import { deleteProcessingActivityMutation , ProcessingActivitiesConnectionKey , processingActivitiesQuery } from "../../../hooks/graph/ProcessingActivityGraph" ;
35- import { sprintf , promisifyMutation } from "@probo/helpers" ;
37+ import { sprintf , promisifyMutation , downloadFile , toDateInput } from "@probo/helpers" ;
38+ import { useMutationWithToasts } from "/hooks/useMutationWithToasts" ;
3639import { SnapshotBanner } from "/components/SnapshotBanner" ;
3740import type { NodeOf } from "/types" ;
3841import type {
@@ -174,6 +177,36 @@ const tiaListPageFragment = graphql`
174177 }
175178` ;
176179
180+ const exportProcessingActivitiesPDFMutation = graphql `
181+ mutation ProcessingActivitiesPageExportPDFMutation(
182+ $input: ExportProcessingActivitiesPDFInput!
183+ ) {
184+ exportProcessingActivitiesPDF(input: $input) {
185+ data
186+ }
187+ }
188+ ` ;
189+
190+ const exportDataProtectionImpactAssessmentsPDFMutation = graphql `
191+ mutation ProcessingActivitiesPageExportDPIAPDFMutation(
192+ $input: ExportDataProtectionImpactAssessmentsPDFInput!
193+ ) {
194+ exportDataProtectionImpactAssessmentsPDF(input: $input) {
195+ data
196+ }
197+ }
198+ ` ;
199+
200+ const exportTransferImpactAssessmentsPDFMutation = graphql `
201+ mutation ProcessingActivitiesPageExportTIAPDFMutation(
202+ $input: ExportTransferImpactAssessmentsPDFInput!
203+ ) {
204+ exportTransferImpactAssessmentsPDF(input: $input) {
205+ data
206+ }
207+ }
208+ ` ;
209+
177210export default function ProcessingActivitiesPage ( { queryRef } : ProcessingActivitiesPageProps ) {
178211 const { __ } = useTranslate ( ) ;
179212 const organizationId = useOrganizationId ( ) ;
@@ -233,6 +266,126 @@ export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivit
233266 isAuthorized ( "ProcessingActivity" , "deleteProcessingActivity" )
234267 ) ;
235268
269+ const canExportPDF = ! isSnapshotMode && isAuthorized ( "ProcessingActivity" , "exportProcessingActivitiesPDF" ) ;
270+ const [ exportPDF , isExportingPDF ] = useMutationWithToasts < {
271+ response : {
272+ exportProcessingActivitiesPDF ?: {
273+ data : string ;
274+ } ;
275+ } ;
276+ variables : {
277+ input : {
278+ organizationId : string ;
279+ filter : { snapshotId : string } | null ;
280+ } ;
281+ } ;
282+ } > (
283+ exportProcessingActivitiesPDFMutation ,
284+ {
285+ successMessage : __ ( "PDF download started." ) ,
286+ errorMessage : __ ( "Failed to generate PDF" ) ,
287+ }
288+ ) ;
289+
290+ const handleExportPDF = ( ) => {
291+ exportPDF ( {
292+ variables : {
293+ input : {
294+ organizationId : organizationId ,
295+ filter : snapshotId ? { snapshotId } : null ,
296+ } ,
297+ } ,
298+ onCompleted : ( data ) => {
299+ if ( data . exportProcessingActivitiesPDF ?. data ) {
300+ downloadFile (
301+ data . exportProcessingActivitiesPDF . data ,
302+ `processing-activities-${ toDateInput ( new Date ( ) . toISOString ( ) ) } .pdf`
303+ ) ;
304+ }
305+ } ,
306+ } ) ;
307+ } ;
308+
309+ const canExportDPIAPDF = ! isSnapshotMode && isAuthorized ( "Organization" , "exportDataProtectionImpactAssessmentsPDF" ) ;
310+ const [ exportDPIAPDF , isExportingDPIAPDF ] = useMutationWithToasts < {
311+ response : {
312+ exportDataProtectionImpactAssessmentsPDF ?: {
313+ data : string ;
314+ } ;
315+ } ;
316+ variables : {
317+ input : {
318+ organizationId : string ;
319+ filter : { snapshotId : string } | null ;
320+ } ;
321+ } ;
322+ } > (
323+ exportDataProtectionImpactAssessmentsPDFMutation ,
324+ {
325+ successMessage : __ ( "PDF download started." ) ,
326+ errorMessage : __ ( "Failed to generate PDF" ) ,
327+ }
328+ ) ;
329+
330+ const handleExportDPIAPDF = ( ) => {
331+ exportDPIAPDF ( {
332+ variables : {
333+ input : {
334+ organizationId : organizationId ,
335+ filter : snapshotId ? { snapshotId } : null ,
336+ } ,
337+ } ,
338+ onCompleted : ( data ) => {
339+ if ( data . exportDataProtectionImpactAssessmentsPDF ?. data ) {
340+ downloadFile (
341+ data . exportDataProtectionImpactAssessmentsPDF . data ,
342+ `data-protection-impact-assessments-${ toDateInput ( new Date ( ) . toISOString ( ) ) } .pdf`
343+ ) ;
344+ }
345+ } ,
346+ } ) ;
347+ } ;
348+
349+ const canExportTIAPDF = ! isSnapshotMode && isAuthorized ( "Organization" , "exportTransferImpactAssessmentsPDF" ) ;
350+ const [ exportTIAPDF , isExportingTIAPDF ] = useMutationWithToasts < {
351+ response : {
352+ exportTransferImpactAssessmentsPDF ?: {
353+ data : string ;
354+ } ;
355+ } ;
356+ variables : {
357+ input : {
358+ organizationId : string ;
359+ filter : { snapshotId : string } | null ;
360+ } ;
361+ } ;
362+ } > (
363+ exportTransferImpactAssessmentsPDFMutation ,
364+ {
365+ successMessage : __ ( "PDF download started." ) ,
366+ errorMessage : __ ( "Failed to generate PDF" ) ,
367+ }
368+ ) ;
369+
370+ const handleExportTIAPDF = ( ) => {
371+ exportTIAPDF ( {
372+ variables : {
373+ input : {
374+ organizationId : organizationId ,
375+ filter : snapshotId ? { snapshotId } : null ,
376+ } ,
377+ } ,
378+ onCompleted : ( data ) => {
379+ if ( data . exportTransferImpactAssessmentsPDF ?. data ) {
380+ downloadFile (
381+ data . exportTransferImpactAssessmentsPDF . data ,
382+ `transfer-impact-assessments-${ toDateInput ( new Date ( ) . toISOString ( ) ) } .pdf`
383+ ) ;
384+ }
385+ } ,
386+ } ) ;
387+ } ;
388+
236389 return (
237390 < div className = "space-y-6" >
238391 { isSnapshotMode && snapshotId && (
@@ -267,6 +420,18 @@ export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivit
267420
268421 { activeTab === "activities" && (
269422 < >
423+ { canExportPDF && (
424+ < div className = "flex justify-end mb-2 -mt-4" >
425+ < Button
426+ variant = "secondary"
427+ icon = { isExportingPDF ? Spinner : IconArrowDown }
428+ disabled = { isExportingPDF }
429+ onClick = { handleExportPDF }
430+ >
431+ { __ ( "Export PDF" ) }
432+ </ Button >
433+ </ div >
434+ ) }
270435 { activities . length > 0 ? (
271436 < Card >
272437 < Table >
@@ -322,6 +487,18 @@ export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivit
322487
323488 { activeTab === "dpia" && (
324489 < >
490+ { canExportDPIAPDF && (
491+ < div className = "flex justify-end mb-2 -mt-4" >
492+ < Button
493+ variant = "secondary"
494+ icon = { isExportingDPIAPDF ? Spinner : IconArrowDown }
495+ disabled = { isExportingDPIAPDF }
496+ onClick = { handleExportDPIAPDF }
497+ >
498+ { __ ( "Export PDF" ) }
499+ </ Button >
500+ </ div >
501+ ) }
325502 { dpias . length > 0 ? (
326503 < Card >
327504 < Table >
@@ -369,6 +546,18 @@ export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivit
369546
370547 { activeTab === "tia" && (
371548 < >
549+ { canExportTIAPDF && (
550+ < div className = "flex justify-end mb-2 -mt-4" >
551+ < Button
552+ variant = "secondary"
553+ icon = { isExportingTIAPDF ? Spinner : IconArrowDown }
554+ disabled = { isExportingTIAPDF }
555+ onClick = { handleExportTIAPDF }
556+ >
557+ { __ ( "Export PDF" ) }
558+ </ Button >
559+ </ div >
560+ ) }
372561 { tias . length > 0 ? (
373562 < Card >
374563 < Table >
0 commit comments