From 6eb5e1949ef4756347ee08b1ad68ce00b61d4efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Dudfield?= Date: Tue, 22 Aug 2023 08:56:35 +0200 Subject: [PATCH] Frontend: Validate: ValidationTable: Add error messages inline (#134) So that the error messages are shown below the row with the error. --- FrontEnd/src/components/Validate/Validate.tsx | 11 ++- .../ValidationTable.stories.tsx | 75 +++++++++++++++-- .../ValidationTable/ValidationTable.tsx | 82 +++++++------------ 3 files changed, 107 insertions(+), 61 deletions(-) diff --git a/FrontEnd/src/components/Validate/Validate.tsx b/FrontEnd/src/components/Validate/Validate.tsx index e6e4e6fd..f972b52d 100644 --- a/FrontEnd/src/components/Validate/Validate.tsx +++ b/FrontEnd/src/components/Validate/Validate.tsx @@ -68,9 +68,18 @@ export function ValidatePure({ return ( <> ); diff --git a/FrontEnd/src/components/ValidationTable/ValidationTable.stories.tsx b/FrontEnd/src/components/ValidationTable/ValidationTable.stories.tsx index 7b00948d..045c6537 100644 --- a/FrontEnd/src/components/ValidationTable/ValidationTable.stories.tsx +++ b/FrontEnd/src/components/ValidationTable/ValidationTable.stories.tsx @@ -1,6 +1,7 @@ import { ComponentMeta, Story } from '@storybook/react'; import { FileWithPath } from 'react-dropzone'; import ValidationTable, { ValidationTableProps } from './ValidationTable'; +import fs from 'fs'; export default { title: 'ValidationTable', @@ -12,26 +13,82 @@ const Template: Story = (args) => ( ); -// @todo: need realistic example data for this validation table. +const HEADERS = [ + { label: 'Tag' }, + { label: 'Subquadrat' }, + { label: 'SpCode' }, + { label: 'DBH' }, + { label: 'Htmeas' }, + { label: 'Codes' }, + { label: 'Comments' }, +]; -const uploadedData: FileWithPath[] = []; +// some example uploaded data +const uploadedData: FileWithPath[] = [ + new File( + [ + new Blob( + [ + [ + 'Tag,Subquadrat,SpCode,DBH,Htmeas,Codes,Comments', + 'Tag0,Subquadrat0,SpCode0,DBH0,Htmeas0,Codes0,Comment0', + 'Tag1,Subquadrat1,SpCode1,DBH1,Htmeas1,Codes1,Comment1', + 'Tag2,Subquadrat2,SpCode2,DBH2,Htmeas2,Codes2,Comment2', + 'Tag3,Subquadrat3,SpCode3,DBH3,Htmeas3,Codes3,Comment3', + 'Tag4,Subquadrat4,SpCode4,DBH4,Htmeas4,Codes4,Comment4', + 'Tag5,Subquadrat5,SpCode5,DBH5,Htmeas5,Codes5,Comment5', + ].join('\n'), + ], + { type: 'text/plain' } + ), + ], + 'test1.csv', + { lastModified: new Date().getTime() } + ), + new File( + [ + new Blob( + [ + [ + 'Tag,Subquadrat,SpCode,DBH,Htmeas,Codes,Comments', + 'Tag0,Subquadrat0,SpCode0,DBH0,Htmeas0,Codes0,Comment0', + 'Tag1,Subquadrat1,SpCode1,DBH1,Htmeas1,Codes1,Comment1', + 'Tag2,Subquadrat2,SpCode2,DBH2,Htmeas2,Codes2,Comment2', + 'Tag3,Subquadrat3,SpCode3,DBH3,Htmeas3,Codes3,Comment3', + 'Tag4,Subquadrat4,SpCode4,DBH4,Htmeas4,Codes4,Comment4', + 'Tag5,Subquadrat5,SpCode5,DBH5,Htmeas5,Codes5,Comment5', + ].join('\n'), + ], + { type: 'text/plain' } + ), + ], + 'test2.csv', + { lastModified: new Date().getTime() } + ), +]; export const NoError = Template.bind({}); NoError.args = { - error: false, - errorMessage: {}, + errorMessage: { + 'test1.csv': {}, + 'test2.csv': {}, + }, uploadedData: uploadedData, + headers: HEADERS, }; export const Error = Template.bind({}); Error.args = { - error: true, errorMessage: { - filename: { - 0: 'ERROR: testing message 0', - 3: 'ERROR: testing message 3', - 5: 'ERROR: testing message 5', + 'test1.csv': { + 0: 'ERROR: testing error message on row 0', + 3: 'ERROR: testing error message on row 3', + 4: 'ERROR: testing error message on row 4', + }, + 'test2.csv': { + 1: 'ERROR: testing error message on row 1', }, }, uploadedData: uploadedData, + headers: HEADERS, }; diff --git a/FrontEnd/src/components/ValidationTable/ValidationTable.tsx b/FrontEnd/src/components/ValidationTable/ValidationTable.tsx index e5857d76..41069a11 100644 --- a/FrontEnd/src/components/ValidationTable/ValidationTable.tsx +++ b/FrontEnd/src/components/ValidationTable/ValidationTable.tsx @@ -7,22 +7,19 @@ import { TableCell, Typography, Paper, - TableFooter, } from '@mui/material'; import { parse } from 'papaparse'; import { useState } from 'react'; import { FileWithPath } from 'react-dropzone'; -import { useNavigate } from 'react-router-dom'; -import Button from '../Button'; import './ValidationTable.css'; export interface ValidationTableProps { /** An array of uploaded data. */ uploadedData: FileWithPath[]; - /** If there is an error this is true. */ - error: boolean; /** If there are errors, these errors are indexed into the uploadedData field. */ errorMessage: { [fileName: string]: { [currentRow: string]: string } }; + /** The headers for the table. */ + headers: { label: string }[]; children?: React.ReactNode | React.ReactNode[]; } @@ -30,27 +27,14 @@ export interface dataStructure { [key: string]: string; } -// @todo: are these headers really fixed? -// @todo: Maybe these headers should be passed in as a prop? -const HEADERS = [ - { label: 'Tag' }, - { label: 'Subquadrat' }, - { label: 'SpCode' }, - { label: 'DBH' }, - { label: 'Htmeas' }, - { label: 'Codes' }, - { label: 'Comments' }, -]; - /** * Shows a data table with the possibility of showing errors. */ export default function ValidationTable({ uploadedData, - error, errorMessage, + headers, }: ValidationTableProps): JSX.Element { - let navigate = useNavigate(); let tempData: { fileName: string; data: dataStructure[] }[] = []; const initState: { fileName: string; data: dataStructure[] }[] = []; const [data, setData] = useState(initState); @@ -94,49 +78,45 @@ export default function ValidationTable({ <> - {HEADERS.map((row, index) => { + {headers.map((row, index) => { return {row.label}; })} + + {fileData!.data.map((data: dataStructure, rowIdx) => { + return ( + <> + + {headers.map((header, i) => ( + + {data[header.label]} + + ))} + - {fileData!.data.map((data: dataStructure) => { - return ( - - - {HEADERS.map((header, i) => ( - {data[header.label]} - ))} - - - ); - })} + {errorMessage[fileName][rowIdx] && ( + + + + ^ {errorMessage[fileName][rowIdx]} + + + + )} + + ); + })} + )} - {errorMessage && ( - - - - -
    - {Object.keys(errorMessage[fileName]).map((row) => { - return ( -
  • - Row {row}: {errorMessage[fileName][row]} -
  • - ); - })} -
-
-
-
-
- )} ); })} -