/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useCallback, useEffect, useMemo } from "react"; import { useForm } from "react-hook-form"; import { useHistory, useParams } from "react-router-dom"; import { ColumnDataType, CurrencyDataType, Dataset, DatasetType, LocationState, NumberDataType, } from "../models"; import BackendService from "../services/BackendService"; import StorageService from "../services/StorageService"; import DatasetParsingService from "../services/DatasetParsingService"; import Breadcrumbs from "../components/Breadcrumbs"; import { useWidget, useDashboard, useFullPreview, useChangeBackgroundColor, useScrollUp, useDatasets, } from "../hooks"; import Spinner from "../components/Spinner"; import UtilsService from "../services/UtilsService"; import ParsingFileService from "../services/ParsingFileService"; import ColumnsMetadataService from "../services/ColumnsMetadataService"; import "./EditTable.css"; import ChooseData from "../components/ChooseData"; import CheckData from "../components/CheckData"; import Visualize from "../components/VisualizeTable"; import PrimaryActionBar from "../components/PrimaryActionBar"; import { useTranslation } from "react-i18next"; import Alert from "../components/Alert"; interface FormValues { title: string; summary: string; showTitle: boolean; dynamicDatasets: string; staticDatasets: string; summaryBelow: boolean; datasetType: string; sortData: string; significantDigitLabels: boolean; displayWithPages: boolean; staticFileName: string | undefined; dynamicFileName: string | undefined; } interface PathParams { dashboardId: string; widgetId: string; } function EditTable() { const history = useHistory(); const { state } = history.location; const { t } = useTranslation(); const { dashboardId, widgetId } = useParams(); const { dashboard, loading } = useDashboard(dashboardId); const { dynamicDatasets, staticDatasets, loadingDatasets } = useDatasets(); const { register, errors, handleSubmit, watch, reset } = useForm(); const [dynamicDataset, setDynamicDataset] = useState(undefined); const [staticDataset, setStaticDataset] = useState(undefined); const [csvErrors, setCsvErrors] = useState | undefined>(undefined); const [csvFile, setCsvFile] = useState(undefined); const [fileLoading, setFileLoading] = useState(false); const [datasetLoading, setDatasetLoading] = useState(false); const [editingWidget, setEditingWidget] = useState(false); const [showNoDatasetTypeAlert, setShowNoDatasetTypeAlert] = useState(false); const [step, setStep] = useState(state && state.json ? 1 : 2); const [staticFileName, setStaticFileName] = useState(""); const [oldStep, setOldStep] = useState(-1); const [dynamicFileName, setDynamicFileName] = useState(""); const { widget, datasetType, currentJson, dynamicJson, staticJson, csvJson, setDynamicJson, setCsvJson, } = useWidget(dashboardId, widgetId); const previewPanelId = "preview-table-panel"; const { fullPreview, fullPreviewButton } = useFullPreview(previewPanelId); const [hiddenColumns, setHiddenColumns] = useState>(new Set()); const [sortByColumn, setSortByColumn] = useState(undefined); const [sortByDesc, setSortByDesc] = useState(undefined); const [dataTypes, setDataTypes] = useState>( new Map(), ); const [numberTypes, setNumberTypes] = useState>( new Map(), ); const [currencyTypes, setCurrencyTypes] = useState>( new Map(), ); const title = watch("title"); const showTitle = watch("showTitle"); const summary = watch("summary"); const summaryBelow = watch("summaryBelow"); const significantDigitLabels = watch("significantDigitLabels"); const displayWithPages = watch("displayWithPages"); const [filteredJson, setFilteredJson] = useState([]); const [displayedJson, setDisplayedJson] = useState>([]); const [displayedDatasetType, setDisplayedDatasetType] = useState(); const initializeColumnsMetadata = () => { setHiddenColumns(new Set()); setDataTypes(new Map()); setNumberTypes(new Map()); setCurrencyTypes(new Map()); setSortByColumn(undefined); setSortByDesc(false); }; useMemo(() => { const newFilteredJson = DatasetParsingService.getFilteredJson(displayedJson, hiddenColumns); setFilteredJson(newFilteredJson); }, [displayedJson, hiddenColumns]); useEffect(() => { if (widget && dynamicDatasets && staticDatasets && currentJson && datasetType) { const title = widget.content.title; const showTitle = widget.showTitle; const summary = widget.content.summary; const summaryBelow = widget.content.summaryBelow; const significantDigitLabels = widget.content.significantDigitLabels; const displayWithPages = widget.content.displayWithPages; if (dynamicDataset) { setDynamicFileName(dynamicDataset?.fileName); } if (staticDataset) { setStaticFileName(staticDataset?.fileName); } reset({ title, showTitle, datasetType: displayedDatasetType ? displayedDatasetType : UtilsService.getDatasetTypeFromState(state, datasetType), summary, summaryBelow, significantDigitLabels, displayWithPages, dynamicDatasets: widget.content.datasetType === DatasetType.DynamicDataset ? widget.content.s3Key.json : "", staticDatasets: widget.content.datasetType === DatasetType.StaticDataset ? widget.content.s3Key.json : "", sortData: UtilsService.getSortData( widget.content.sortByColumn, widget.content.sortByDesc, ), }); if (!displayedDatasetType) { setDisplayedDatasetType( state && state.json && state.staticDataset ? DatasetType.StaticDataset : datasetType, ); if (!displayedJson.length) { setDisplayedJson(state && state.json ? state.json : currentJson); } // Initialize fields related to columns metadata if (widget.content.columnsMetadata && (!state || !state.json)) { const columnsMetadata = widget.content.columnsMetadata; const { hiddenColumns, dataTypes, numberTypes, currencyTypes } = ColumnsMetadataService.parseColumnsMetadata(columnsMetadata); setHiddenColumns(hiddenColumns); setDataTypes(dataTypes); setNumberTypes(numberTypes); setCurrencyTypes(currencyTypes); setSortByColumn(widget.content.sortByColumn); setSortByDesc(widget.content.sortByDesc || false); } } if (!dynamicDataset) { setDynamicDataset( dynamicDatasets.find((d) => d.s3Key.json === widget.content.s3Key.json), ); } if (!staticDataset) { setStaticDataset( state && state.staticDataset ? state.staticDataset : staticDatasets.find((d) => d.s3Key.json === widget.content.s3Key.json), ); } } }, [ widget, dynamicDatasets, staticDatasets, reset, state, currentJson, displayedJson, datasetType, displayedDatasetType, dynamicDataset, staticDataset, ]); const onFileProcessed = useCallback( async (data: File) => { if (!data) { return; } setDatasetLoading(true); ParsingFileService.parseFile(data, false, (errors: any, results: any) => { initializeColumnsMetadata(); if (errors !== null && errors.length) { setCsvErrors(errors); setCsvJson([]); setDisplayedJson([]); } else { setShowNoDatasetTypeAlert(false); setCsvErrors(undefined); const csvJson = DatasetParsingService.createHeaderRowJson(results); setCsvJson(csvJson); setDisplayedJson(csvJson); } setDatasetLoading(false); }); setCsvFile(data); }, [setDisplayedJson, setCsvJson], ); const uploadDataset = async (): Promise => { if (!csvFile) { // User did not select a new dataset. // No need to upload anything. return null; } if (!csvFile.lastModified) { return { id: widget?.content.datasetId, fileName: csvFile.name, s3Key: widget?.content.s3Key, }; } setFileLoading(true); const uploadResponse = await StorageService.uploadDataset( csvFile, JSON.stringify(displayedJson), t, ); const newDataset = await BackendService.createDataset(csvFile.name, { raw: uploadResponse.s3Keys.raw, json: uploadResponse.s3Keys.json, }); setFileLoading(false); return newDataset; }; const onSubmit = async (values: FormValues) => { if (!widget) { return; } try { let newDataset; if (csvFile) { newDataset = await uploadDataset(); } setEditingWidget(true); await BackendService.editWidget( dashboardId, widgetId, values.title, values.showTitle, { title: values.title, summary: values.summary, summaryBelow: values.summaryBelow, datasetType: displayedDatasetType, significantDigitLabels: values.significantDigitLabels, displayWithPages: values.displayWithPages, datasetId: newDataset ? newDataset.id : UtilsService.getDatasetPropertyByDatasetType( datasetType, "id", dynamicDataset, staticDataset, ), s3Key: newDataset ? newDataset.s3Key : UtilsService.getDatasetPropertyByDatasetType( datasetType, "s3Key", dynamicDataset, staticDataset, ), fileName: csvFile ? csvFile.name : UtilsService.getDatasetPropertyByDatasetType( datasetType, "fileName", dynamicDataset, staticDataset, ), sortByColumn, sortByDesc, columnsMetadata: ColumnsMetadataService.getColumnsMetadata( hiddenColumns, dataTypes, numberTypes, currencyTypes, ), }, widget.updatedAt, ); setEditingWidget(false); history.push(`/admin/dashboard/edit/${dashboardId}`, { alert: { type: "success", message: t("EditTableScreen.EditTableSuccess", { title: values.title, }), }, }); } catch (err) { console.log(t("AddContentFailure"), err); setEditingWidget(false); } }; const onCancel = () => { history.push(`/admin/dashboard/edit/${dashboardId}`); }; const handleChange = async (event: React.FormEvent) => { const target = event.target as HTMLInputElement; if (target.name === "datasetType") { setDatasetLoading(true); const datasetType = target.value as DatasetType; setDisplayedDatasetType(datasetType); await UtilsService.timeout(0); initializeColumnsMetadata(); if (datasetType === DatasetType.DynamicDataset) { setDisplayedJson(dynamicJson); } if (datasetType === DatasetType.StaticDataset) { if (csvJson && csvJson.length) { setDisplayedJson(csvJson); } else { setDisplayedJson(staticJson); } } setDatasetLoading(false); } }; const advanceStep = () => { setStep(step + 1); }; const backStep = () => { setStep(step - 1); }; const goBack = () => { history.push(`/admin/dashboard/${dashboardId}/add-content`); }; const browseDatasets = () => { history.push({ pathname: `/admin/dashboard/${dashboardId}/choose-static-dataset`, state: { redirectUrl: `/admin/dashboard/${dashboardId}/edit-table/${widgetId}`, crumbLabel: t("EditTableScreen.EditTable"), }, }); }; const selectDynamicDataset = async (selectedDataset: Dataset) => { setDatasetLoading(true); if (selectedDataset && selectedDataset.s3Key && selectedDataset.s3Key.json) { const jsonFile = selectedDataset.s3Key.json; initializeColumnsMetadata(); const dataset = await StorageService.downloadJson(jsonFile); setDynamicDataset(dynamicDatasets.find((d) => d.s3Key.json === jsonFile)); setDynamicJson(dataset); setDisplayedJson(dataset); } setDatasetLoading(false); }; const crumbs = [ { label: t("Dashboards"), url: "/admin/dashboards", }, { label: dashboard?.name, url: `/admin/dashboard/edit/${dashboardId}`, }, ]; if (!loading && widget) { crumbs.push({ label: t("EditTableScreen.EditTable"), url: "", }); } const configHeader = (suffix: string) => (

{t("EditTableScreen.EditTable")}

); useChangeBackgroundColor(); useScrollUp(oldStep, step, setOldStep); return ( <> {loading || loadingDatasets || !widget || !displayedDatasetType || !filteredJson || fileLoading || editingWidget ? ( ) : ( <>
)} ); } export default EditTable;