/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import "./ExportModal.scss"; import React, { useCallback, useEffect, useRef, useState } from "react"; import { Button, Modal, ProgressLinear, ProgressRadial, Text } from "@itwin/itwinui-react"; import type { EC3Job, EC3ReportJobCreate } from "@itwin/insights-client"; import { CarbonUploadState } from "@itwin/insights-client"; import { useApiContext } from "./context/APIContext"; import type { EC3ConfigPropsWithCallbacks } from "./EC3/EC3Config"; interface JobSuccess { status: CarbonUploadState.Succeeded; link: string; } interface JobFailed { status: CarbonUploadState.Failed; message: string; } interface JobQueued { status: CarbonUploadState.Queued; } interface JobRunning { status: CarbonUploadState.Running; } type JobStatus = JobSuccess | JobFailed | JobQueued | JobRunning; type ExportProps = Omit & { projectName: string; isOpen: boolean; close: () => void; templateId: string | undefined; token: string | undefined; }; export const ExportModal = (props: ExportProps) => { const PIN_INTERVAL = 5000; const ec3JobsClient = useApiContext().ec3JobsClient; const getAccessToken = useApiContext().config.getAccessToken; const [jobStatus, setJobStatus] = useState({ status: CarbonUploadState.Queued }); const intervalRef = useRef(); const pinStatus = useCallback( (job: EC3Job) => { const intervalId = window.setInterval(async () => { const token = await getAccessToken(); if (!(job.id && token)) return; const currentJobStatus = await ec3JobsClient.getEC3JobStatus(token, job.id); if (currentJobStatus.status === CarbonUploadState.Succeeded) { setJobStatus({ status: CarbonUploadState.Succeeded, link: currentJobStatus._links.ec3Project.href }); } else if (currentJobStatus.status === CarbonUploadState.Failed) { setJobStatus({ status: CarbonUploadState.Failed, message: currentJobStatus.message! }); } else { setJobStatus({ status: currentJobStatus.status }); } props?.onExportResult?.(currentJobStatus, props.templateId); }, PIN_INTERVAL); intervalRef.current = intervalId; }, [setJobStatus, ec3JobsClient, getAccessToken, props], ); const runJob = useCallback( async (token: string) => { const accessToken = await getAccessToken(); if (props.templateId && token) { try { const jobRequest: EC3ReportJobCreate = { configurationId: props.templateId, projectName: props.projectName, ec3BearerToken: token, }; const jobCreated = await ec3JobsClient.createJob(accessToken, jobRequest); if (jobCreated.id) { pinStatus(jobCreated); } else { setJobStatus({ status: CarbonUploadState.Failed, message: "Failed to create Job" }); } } catch (e) { setJobStatus({ status: CarbonUploadState.Failed, message: "Missing required permissions. Please contact the project administrator." }); /* eslint-disable no-console */ console.error(e); } } else { setJobStatus({ status: CarbonUploadState.Failed, message: "Invalid reportId" }); } }, [props, pinStatus, ec3JobsClient, getAccessToken], ); const onClose = useCallback(() => { window.clearInterval(intervalRef.current); props.close(); }, [props]); const getStatusComponent = useCallback((state: JobStatus) => { switch (state.status) { case CarbonUploadState.Queued: return (
Export queued
); case CarbonUploadState.Running: return (
Export running
); case CarbonUploadState.Succeeded: return (
); case CarbonUploadState.Failed: return (
Export failed
{state.message}
); default: return (
Invalid Job Status
); } }, []); useEffect(() => { return () => { window.clearInterval(intervalRef.current); }; }, []); useEffect(() => { if (props.isOpen && props.token) { setJobStatus({ status: CarbonUploadState.Queued }); runJob(props.token).catch((err) => { setJobStatus({ status: CarbonUploadState.Failed, message: "Error while running job" }); /* eslint-disable no-console */ console.error(err); }); } }, [props.isOpen, props.token, runJob]); useEffect(() => { if (jobStatus.status === CarbonUploadState.Succeeded || jobStatus.status === CarbonUploadState.Failed) { if (intervalRef.current) { window.clearInterval(intervalRef.current); } } }, [jobStatus]); return ( {!jobStatus && (
)} {jobStatus && getStatusComponent(jobStatus)}
); };