in frontend/src/containers/AddTable.tsx [48:465]
function AddTable() {
const history = useHistory<LocationState>();
const { state } = history.location;
const { t } = useTranslation();
const { dashboardId } = useParams<PathParams>();
const { dashboard, loading } = useDashboard(dashboardId);
const { dynamicDatasets } = useDatasets();
const { register, errors, handleSubmit, reset, watch } =
useForm<FormValues>();
const [currentJson, setCurrentJson] = useState<Array<any>>(
state && state.json ? state.json : []
);
const [dynamicJson, setDynamicJson] = useState<Array<any>>([]);
const [staticJson] = useState<Array<any>>(
state && state.json ? state.json : []
);
const [csvJson, setCsvJson] = useState<Array<any>>([]);
const [filteredJson, setFilteredJson] = useState<Array<any>>(currentJson);
const [dynamicDataset, setDynamicDataset] = useState<Dataset | undefined>(
undefined
);
const [staticDataset] = useState<Dataset | undefined>(
state && state.staticDataset ? state.staticDataset : undefined
);
const [csvErrors, setCsvErrors] = useState<Array<object> | undefined>(
undefined
);
const [csvFile, setCsvFile] = useState<File | undefined>(undefined);
const [fileLoading, setFileLoading] = useState(false);
const [datasetLoading, setDatasetLoading] = useState(false);
const [creatingWidget, setCreatingWidget] = useState(false);
const [showNoDatasetTypeAlert, setShowNoDatasetTypeAlert] = useState(false);
const [datasetType, setDatasetType] = useState<DatasetType | undefined>(
state && state.json ? DatasetType.StaticDataset : undefined
);
const [step, setStep] = useState<number>(state && state.json ? 1 : 0);
const [selectedHeaders, setSelectedHeaders] = useState<Set<string>>(
new Set<string>()
);
const [hiddenColumns, setHiddenColumns] = useState<Set<string>>(
new Set<string>()
);
const [sortByColumn, setSortByColumn] = useState<string | undefined>(
undefined
);
const [sortByDesc, setSortByDesc] = useState<boolean | undefined>(undefined);
const { fullPreview, fullPreviewButton } = useFullPreview();
const [dataTypes, setDataTypes] = useState<Map<string, ColumnDataType>>(
new Map<string, ColumnDataType>()
);
const [numberTypes, setNumberTypes] = useState<Map<string, NumberDataType>>(
new Map<string, NumberDataType>()
);
const [currencyTypes, setCurrencyTypes] = useState<
Map<string, CurrencyDataType>
>(new Map<string, CurrencyDataType>());
const [oldStep, setOldStep] = useState<number>(-1);
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 initializeColumnsMetadata = () => {
setSelectedHeaders(new Set<string>());
setHiddenColumns(new Set<string>());
setDataTypes(new Map<string, ColumnDataType>());
setNumberTypes(new Map<string, NumberDataType>());
setCurrencyTypes(new Map<string, CurrencyDataType>());
setSortByColumn(undefined);
setSortByDesc(false);
};
useMemo(() => {
const newFilteredJson = DatasetParsingService.getFilteredJson(
currentJson,
hiddenColumns
);
setFilteredJson(newFilteredJson);
}, [currentJson, hiddenColumns]);
const uploadDataset = async (): Promise<Dataset> => {
if (!csvFile) {
throw new Error(t("CSVFileNotSpecified"));
}
setFileLoading(true);
const uploadResponse = await StorageService.uploadDataset(
csvFile,
JSON.stringify(currentJson),
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) => {
try {
let newDataset;
if (csvFile) {
newDataset = await uploadDataset();
}
setCreatingWidget(true);
await BackendService.createWidget(
dashboardId,
values.title,
WidgetType.Table,
values.showTitle,
{
title: values.title,
summary: values.summary,
summaryBelow: values.summaryBelow,
datasetType: datasetType,
significantDigitLabels: values.significantDigitLabels,
displayWithPages: values.displayWithPages,
datasetId: newDataset
? newDataset.id
: datasetType === DatasetType.DynamicDataset
? dynamicDataset?.id
: staticDataset?.id,
s3Key: newDataset
? newDataset.s3Key
: datasetType === DatasetType.DynamicDataset
? dynamicDataset?.s3Key
: staticDataset?.s3Key,
fileName: csvFile
? csvFile.name
: datasetType === DatasetType.DynamicDataset
? dynamicDataset?.fileName
: staticDataset?.fileName,
sortByColumn,
sortByDesc,
columnsMetadata: ColumnsMetadataService.getColumnsMetadata(
hiddenColumns,
dataTypes,
numberTypes,
currencyTypes
),
}
);
setCreatingWidget(false);
history.push(`/admin/dashboard/edit/${dashboardId}`, {
alert: {
type: "success",
message: t("AddTableScreen.AddTableSuccess", { title: values.title }),
},
});
} catch (err) {
console.log(t("AddContentFailure"), err);
setCreatingWidget(false);
}
};
const onCancel = () => {
history.push(`/admin/dashboard/edit/${dashboardId}`);
};
const advanceStep = () => {
setStep(step + 1);
};
const backStep = () => {
setStep(step - 1);
};
const goBack = () => {
history.push(`/admin/dashboard/${dashboardId}/add-content`);
};
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);
setDynamicJson(dataset);
setCurrentJson(dataset);
setDynamicDataset(dynamicDatasets.find((d) => d.s3Key.json === jsonFile));
}
setDatasetLoading(false);
};
const browseDatasets = () => {
history.push({
pathname: `/admin/dashboard/${dashboardId}/choose-static-dataset`,
state: {
redirectUrl: `/admin/dashboard/${dashboardId}/add-table/`,
crumbLabel: t("AddTableScreen.AddTable"),
},
});
};
const onFileProcessed = (data: File) => {
if (!data) {
return;
}
setDatasetLoading(true);
ParsingFileService.parseFile(data, false, (errors: any, results: any) => {
initializeColumnsMetadata();
if (errors !== null && errors.length) {
setCsvErrors(errors);
setCsvJson([]);
setCurrentJson([]);
} else {
setShowNoDatasetTypeAlert(false);
setCsvErrors(undefined);
const csvJson = DatasetParsingService.createHeaderRowJson(results);
setCsvJson(csvJson);
setCurrentJson(csvJson);
}
setDatasetLoading(false);
});
setCsvFile(data);
};
const handleChange = async (event: React.FormEvent<HTMLFieldSetElement>) => {
const target = event.target as HTMLInputElement;
if (target.name === "datasetType") {
const datasetType = target.value as DatasetType;
setDatasetType(datasetType);
initializeColumnsMetadata();
await UtilsService.timeout(0);
if (datasetType === DatasetType.DynamicDataset) {
setCurrentJson(dynamicJson);
}
if (datasetType === DatasetType.StaticDataset) {
if (csvJson && csvJson.length) {
setCurrentJson(csvJson);
} else {
setCurrentJson(staticJson);
}
}
}
};
useEffect(() => {
if (datasetType) {
reset({
datasetType,
});
}
}, []);
const crumbs = [
{
label: t("Dashboards"),
url: "/admin/dashboards",
},
{
label: dashboard?.name,
url: `/admin/dashboard/edit/${dashboardId}`,
},
];
if (!loading) {
crumbs.push({
label: t("AddTableScreen.AddTable"),
url: "",
});
}
const configHeader = (
<div>
<h1 className="margin-top-0">{t("AddTableScreen.AddTable")}</h1>
<StepIndicator
current={step}
segments={[
{
label: t("AddTableScreen.ChooseData"),
},
{
label: t("AddTableScreen.CheckData"),
},
{
label: t("AddTableScreen.Visualize"),
},
]}
showStepChart={true}
showStepText={false}
/>
</div>
);
useChangeBackgroundColor();
useScrollUp(oldStep, step, setOldStep);
return (
<>
<Breadcrumbs crumbs={crumbs} />
<div className="grid-row width-desktop">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="grid-col-12"></div>
<div hidden={step !== 0}>
<PrimaryActionBar>
{configHeader}
<div className="margin-y-3" hidden={!showNoDatasetTypeAlert}>
<Alert
type="error"
message={t("AddTableScreen.ChooseDataset")}
slim
/>
</div>
<ChooseData
selectDynamicDataset={selectDynamicDataset}
dynamicDatasets={dynamicDatasets}
datasetType={datasetType}
onFileProcessed={onFileProcessed}
handleChange={handleChange}
backStep={goBack}
advanceStep={advanceStep}
fileLoading={fileLoading}
browseDatasets={browseDatasets}
hasErrors={!currentJson.length}
csvErrors={csvErrors}
csvFile={csvFile}
onCancel={onCancel}
register={register}
widgetType={t("ChooseDataDescriptionTable")}
staticFileName={undefined}
dynamicFileName={undefined}
setShowNoDatasetTypeAlert={setShowNoDatasetTypeAlert}
/>
</PrimaryActionBar>
</div>
<div hidden={step !== 1}>
<PrimaryActionBar>
{configHeader}
<CheckData
data={currentJson}
advanceStep={advanceStep}
backStep={backStep}
selectedHeaders={selectedHeaders}
setSelectedHeaders={setSelectedHeaders}
hiddenColumns={hiddenColumns}
setHiddenColumns={setHiddenColumns}
onCancel={onCancel}
dataTypes={dataTypes}
setDataTypes={setDataTypes}
numberTypes={numberTypes}
setNumberTypes={setNumberTypes}
currencyTypes={currencyTypes}
setCurrencyTypes={setCurrencyTypes}
sortByColumn={sortByColumn}
sortByDesc={sortByDesc}
setSortByColumn={setSortByColumn}
setSortByDesc={setSortByDesc}
reset={reset}
widgetType={t("CheckDataDescriptionTable")}
/>
</PrimaryActionBar>
</div>
<div hidden={step !== 2}>
<Visualize
errors={errors}
register={register}
json={filteredJson}
originalJson={currentJson}
headers={
currentJson.length
? (Object.keys(currentJson[0]) as Array<string>)
: []
}
csvJson={csvJson}
datasetLoading={datasetLoading}
datasetType={datasetType}
onCancel={onCancel}
backStep={backStep}
advanceStep={advanceStep}
fileLoading={fileLoading}
processingWidget={creatingWidget}
fullPreviewButton={fullPreviewButton}
fullPreview={fullPreview}
submitButtonLabel={t("AddTableScreen.AddTable")}
sortByColumn={sortByColumn}
sortByDesc={sortByDesc}
setSortByColumn={setSortByColumn}
setSortByDesc={setSortByDesc}
title={title}
showTitle={showTitle}
significantDigitLabels={significantDigitLabels}
displayWithPages={displayWithPages}
summary={summary}
summaryBelow={summaryBelow}
columnsMetadata={ColumnsMetadataService.getColumnsMetadata(
hiddenColumns,
dataTypes,
numberTypes,
currencyTypes
)}
configHeader={configHeader}
/>
</div>
</form>
</div>
</>
);
}