// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT-0 import { FormSchema, DocumentMetadata, FormMetadata, AggregateMetrics } from '@aws/api-typescript'; import { Button, Column, ColumnLayout, Container, Grid, KeyValuePair, Stack, Tabs, } from 'aws-northstar'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { API } from '../../api/client'; import { friendlyDuration, friendlyPercent, getMetricsForLastThreeMonths } from '../../api/metrics'; import { listAllPages } from '../../api/utils'; import { DocumentsTable } from './documents-table'; import { FormsTable } from './forms-table'; export interface DashboardProps {} /** * Default app content container for the "/" route…displays various metrics * about the processing of disclosure documents, along with a browseable view * of all documents that have been uploaded to the processing backend */ const Dashboard: React.FC<DashboardProps> = () => { const [dataLoaded, setDataLoaded] = useState<boolean>(false); const [formsLoaded, setFormsLoaded] = useState<boolean>(false); const [_, setDocumentsLoaded] = useState<boolean>(false); const [documentsLoaded, setSchemasLoaded] = useState<boolean>(false); const [schemas, setSchemas] = useState<FormSchema[]>([]); const [documents, setDocuments] = useState<DocumentMetadata[]>([]); const [forms, setForms] = useState<FormMetadata[]>([]); const [metrics, setMetrics] = useState<AggregateMetrics>(); const tabHistoryKey = 'dashboardTab'; const defaultTab = 'documents'; const fetchMetrics = useCallback(async () => { setMetrics(await getMetricsForLastThreeMonths()); }, []); const fetchDocuments = useCallback(async () => { setDocumentsLoaded(false); const documentsResponse = await listAllPages(API.listDocuments.bind(API), 'documents'); setDocuments(documentsResponse); setDocumentsLoaded(true); }, []); const fetchSchemas = useCallback(async () => { setSchemasLoaded(false); const schemasResponse = await listAllPages(API.listFormSchemas.bind(API), 'schemas'); setSchemas(schemasResponse); setSchemasLoaded(true); }, []); const fetchForms = useCallback(async () => { setFormsLoaded(false); const formsResponse = await listAllPages(API.listForms.bind(API), 'forms'); setForms(formsResponse); setFormsLoaded(true); }, []); const fetchData = useCallback(async () => { setDataLoaded(false); await Promise.all([fetchDocuments(), fetchSchemas(), fetchForms(), fetchMetrics()]); setDataLoaded(true); }, []); const submitDocument = useCallback(async (file: File, schemaId: string) => { const { url, documentId, location } = await API.getDocumentUploadUrl({ fileName: file.name, contentType: file.type, }); await fetch(url, { method: 'PUT', body: file, }); await API.submitSourceDocument({ submitSourceDocumentInput: { documentId, location, name: file.name, schemaId, }, }); // Start fetching documents but don't block returning from upload callback void (async () => fetchData())(); }, []); useEffect(() => { fetchData().catch((err:any) => console.log(err)); }, []); // tabs for the documents and forms views const tabs = useMemo(() => { return [ { label: 'Documents', id: defaultTab, content: <DocumentsTable dataLoaded={documentsLoaded} reloadAction={fetchDocuments} documents={documents} upload={submitDocument} schemas={schemas} />, }, { label: 'Forms', id: 'forms', content: <FormsTable forms={forms} reloadAction={fetchForms} dataLoaded={formsLoaded} />, }, ]; }, [forms, documents, fetchDocuments, documentsLoaded, fetchForms, formsLoaded, fetchSchemas]); return ( <Grid container spacing={1}> <Grid item xs={2}> {' '} </Grid> <Grid item xs={12}> <Container headingVariant="h2" title="Document Data Extraction Platform Dashboard" actionGroup={ <> <Button variant="icon" icon={'refresh'} onClick={fetchData} loading={!dataLoaded} /> </> } > <ColumnLayout> <Column key="column1"> <Stack> <KeyValuePair label="Documents Processed" value={metrics?.totalProcessedDocumentCount ?? '-'} /> <KeyValuePair label="Forms Extracted" value={metrics?.totalSuccessfulFormCount ?? '-'} /> </Stack> </Column> <Column key="column2"> <Stack> <KeyValuePair label="Average Review Time" value={friendlyDuration(metrics?.averageReviewTimeMilliseconds)} /> </Stack> </Column> <Column key="column3"> <Stack> <KeyValuePair label="Average Extraction Accuracy" value={friendlyPercent(metrics?.averageExtractionAccuracyDistance)} /> <KeyValuePair label="Average Extraction Confidence" value={friendlyPercent(metrics?.averageConfidence)} /> </Stack> </Column> </ColumnLayout> </Container> <Tabs onChange={(activeTabId: string) => localStorage.setItem(tabHistoryKey, activeTabId)} activeId={localStorage.getItem(tabHistoryKey) ?? defaultTab} tabs={tabs} variant={'container'} /> </Grid> </Grid> ); }; export default Dashboard;