Skip to content

Commit

Permalink
feat: finished refactor of annotation table making it robust to reren…
Browse files Browse the repository at this point in the history
…ders
  • Loading branch information
nicoalee committed Oct 20, 2023
1 parent 3ab48be commit ad50dd7
Show file tree
Hide file tree
Showing 30 changed files with 859 additions and 1,038 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import NeurosynthTableStyles from 'components/Tables/NeurosynthTable/NeurosynthT
import { EPropertyType } from 'components/EditMetadata';
import { useGetAnnotationById } from 'hooks';
import { NoteCollectionReturn } from 'neurostore-typescript-sdk';
import { AnnotationNoteValue } from 'components/HotTables/helpers/utils';
import { AnnotationNoteValue } from 'components/HotTables/HotTables.types';

export const getFilteredAnnotationNotes = (
annotationNotes: NoteCollectionReturn[],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HotTable } from '@handsontable/react';
import { Box, Typography } from '@mui/material';
import { registerAllModules } from 'handsontable/registry';
import styles from 'components/HotTables/AnnotationsHotTable/AnnotationsHotTable.module.css';
import styles from 'components/HotTables/HotTables.module.css';
import { IStorePoint, MapOrSpaceType } from 'pages/Studies/StudyStore.helpers';
import { useEffect, useRef } from 'react';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,169 +1,99 @@
import LoadingButton from 'components/Buttons/LoadingButton/LoadingButton';
import EditAnnotationsHotTable from 'components/HotTables/EditAnnotationsHotTable/EditAnnotationsHotTable';
import StateHandlerComponent from 'components/StateHandlerComponent/StateHandlerComponent';
import { DetailedSettings as MergeCellsSettings } from 'handsontable/plugins/mergeCells';
import { ColumnSettings } from 'handsontable/settings';
import { useGetAnnotationById, useUpdateAnnotationById } from 'hooks';
import { NoteCollectionReturn } from 'neurostore-typescript-sdk';
import { useCallback, useEffect, useRef, useState } from 'react';
import AnnotationsHotTable from 'components/HotTables/AnnotationsHotTable/AnnotationsHotTable';
import {
AnnotationNoteValue,
NoteKeyType,
annotationNotesToHotData,
createColumns,
getMergeCells,
hotDataToAnnotationNotes,
noteKeyArrToObj,
noteKeyObjToArr,
} from '../HotTables/helpers/utils';
import { useAuth0 } from '@auth0/auth0-react';
import { useUpdateAnnotationById } from 'hooks';
import { useSnackbar } from 'notistack';
import { useCallback, useState } from 'react';

const hardCodedColumns = ['Study', 'Analysis'];

const EditAnnotations: React.FC<{ annotationId: string }> = (props) => {
const { user } = useAuth0();
const { enqueueSnackbar } = useSnackbar();
const { mutate, isLoading: updateAnnotationIsLoading } = useUpdateAnnotationById(
props.annotationId
);
const {
data,
isLoading: getAnnotationIsLoading,
isError,
} = useGetAnnotationById(props.annotationId);
// const {
// theUserOwnsThisAnnotation,
// hotDataToStudyMapping,
// noteKeys,
// hotData,
// hotColumns,
// mergeCells,
// getAnnotationIsError,
// getAnnotationIsLoading,
// } = useEditAnnotations();
// const [annotationIsEdited, setAnnotationIsEdited] = useState(false);

const theLoggedInUserOwnsThisAnnotation = (user?.sub || null) === (data?.user || undefined);
// const handleClickSave = () => {
// if (!props.annotationId) return;
// if (!theUserOwnsThisAnnotation) {
// enqueueSnackbar('You do not have permission to edit this annotation', {
// variant: 'error',
// });
// return;
// }

// tracks the changes made to hot table
const hotTableDataUpdatesRef = useRef<{
initialized: boolean;
hotData: (string | number | boolean | null)[][];
noteKeys: NoteKeyType[];
}>({
initialized: false,
hotData: [],
noteKeys: [],
});
const [annotationIsEdited, setAnnotationIsEdited] = useState(false);
const [initialAnnotationHotState, setInitialAnnotationHotState] = useState<{
hotDataToStudyMapping: Map<number, { studyId: string; analysisId: string }>;
noteKeys: NoteKeyType[];
hotData: AnnotationNoteValue[][];
hotColumns: ColumnSettings[];
mergeCells: MergeCellsSettings[];
}>({
hotDataToStudyMapping: new Map<number, { studyId: string; analysisId: string }>(),
noteKeys: [],
hotData: [],
hotColumns: [],
mergeCells: [],
});
// const updatedAnnotationNotes = hotDataToAnnotationNotes(
// hotData,
// hotDataToStudyMapping,
// noteKeys
// );
// const updatedNoteKeyObj = noteKeyArrToObj(noteKeys);

useEffect(() => {
if (data && !hotTableDataUpdatesRef.current.initialized) {
hotTableDataUpdatesRef.current.initialized = true;
const noteKeys = noteKeyObjToArr(data.note_keys);
const { hotData, hotDataToStudyMapping } = annotationNotesToHotData(
noteKeys,
data.notes as NoteCollectionReturn[] | undefined,
(annotationNote) => {
const studyName =
annotationNote.study_name && annotationNote.study_year
? `(${annotationNote.study_year}) ${annotationNote.study_name}`
: annotationNote.study_name
? annotationNote.study_name
: '';
// mutate(
// {
// argAnnotationId: props.annotationId,
// annotation: {
// notes: updatedAnnotationNotes.map((annotationNote) => ({
// note: annotationNote.note,
// analysis: annotationNote.analysis,
// study: annotationNote.study,
// })),
// note_keys: updatedNoteKeyObj,
// },
// },
// {
// onSuccess: () => {
// setAnnotationIsEdited(false);
// },
// }
// );
// };

const analysisName = annotationNote.analysis_name || '';

return [studyName, analysisName];
}
);

setInitialAnnotationHotState({
hotDataToStudyMapping,
noteKeys,
hotColumns: createColumns(noteKeys),
hotData: hotData,
mergeCells: getMergeCells(hotDataToStudyMapping),
});
}
}, [data]);

const handleClickSave = () => {
if (!props.annotationId) return;
if (!theLoggedInUserOwnsThisAnnotation) {
enqueueSnackbar('You do not have permission to edit this annotation', {
variant: 'error',
});
return;
}

const { hotData, noteKeys } = hotTableDataUpdatesRef.current;

const updatedAnnotationNotes = hotDataToAnnotationNotes(
hotData,
initialAnnotationHotState.hotDataToStudyMapping,
noteKeys
);
const updatedNoteKeyObj = noteKeyArrToObj(noteKeys);

mutate(
{
argAnnotationId: props.annotationId,
annotation: {
notes: updatedAnnotationNotes.map((annotationNote) => ({
note: annotationNote.note,
analysis: annotationNote.analysis,
study: annotationNote.study,
})),
note_keys: updatedNoteKeyObj,
},
},
{
onSuccess: () => {
setAnnotationIsEdited(false);
},
}
);
};

const handleChange = useCallback(
(hotData: AnnotationNoteValue[][], noteKeys: NoteKeyType[]) => {
setAnnotationIsEdited(true);
hotTableDataUpdatesRef.current = {
...hotTableDataUpdatesRef.current,
hotData,
noteKeys,
};
},
[]
);
// const handleChange = useCallback(
// (hotData: AnnotationNoteValue[][], noteKeys: NoteKeyType[]) => {
// setAnnotationIsEdited(true);
// hotTableDataUpdatesRef.current = {
// ...hotTableDataUpdatesRef.current,
// hotData,
// noteKeys,
// };
// },
// []
// );

return (
<StateHandlerComponent isLoading={getAnnotationIsLoading} isError={isError}>
<AnnotationsHotTable
{...initialAnnotationHotState}
allowAddColumn
hardCodedReadOnlyCols={hardCodedColumns}
allowRemoveColumns
onChange={handleChange}
wordWrap={true}
size="fitToPage"
/>
<LoadingButton
size="large"
text="save"
disabled={!annotationIsEdited}
isLoading={updateAnnotationIsLoading}
loaderColor="secondary"
color="primary"
variant="contained"
sx={{ width: '300px' }}
onClick={handleClickSave}
/>
</StateHandlerComponent>
<></>
// <StateHandlerComponent isLoading={getAnnotationIsLoading} isError={getAnnotationIsError}>
// {/* <EditAnnotationsHotTable
// allowAddColumn={theUserOwnsThisAnnotation}
// hardCodedReadOnlyCols={hardCodedColumns}
// allowRemoveColumns={true}
// onChange={handleChange}
// size="fitToPage"
// /> */}
// <LoadingButton
// size="large"
// text="save"
// disabled={!annotationIsEdited}
// isLoading={updateAnnotationIsLoading}
// loaderColor="secondary"
// color="primary"
// variant="contained"
// sx={{ width: '300px' }}
// onClick={handleClickSave}
// />
// </StateHandlerComponent>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import HelpIcon from '@mui/icons-material/Help';
import { Box, Button, Tooltip, Typography } from '@mui/material';
import ConfirmationDialog from 'components/Dialogs/ConfirmationDialog/ConfirmationDialog';
import DisplayAnalysisWarnings from 'components/DisplayStudy/DisplayAnalyses/DisplayAnalysisWarnings/DisplayAnalysisWarnings';
import EditAnalysisDetails from 'components/EditStudyComponents/EditAnalyses/EditAnalysisDetails/EditAnalysisDetails';
import { useDeleteAnalysis } from 'pages/Studies/StudyStore';
import { useState } from 'react';
import EditAnalysisDetails from 'components/EditStudyComponents/EditAnalyses/EditAnalysisDetails/EditAnalysisDetails';
import EditAnalysisPoints from 'components/HotTables/EditAnalysisPointsHotTable/EditAnalysisPoints';
import EditAnalysisPointSpaceAndStatistic from 'components/EditStudyComponents/EditAnalyses/EditAnalysisPoints/EditAnalysisPointSpaceAndStatistic/EditAnalysisPointSpaceAndStatistic';
import { useDeleteAnnotationNote } from 'stores/AnnotationStore.actions';
import EditAnalysisPoints from '../EditAnalysisPoints/EditAnalysisPoints/EditAnalysisPoints';

const EditAnalysis: React.FC<{ analysisId?: string; onDeleteAnalysis: () => void }> = (props) => {
const deleteAnalysis = useDeleteAnalysis();
Expand All @@ -31,28 +30,8 @@ const EditAnalysis: React.FC<{ analysisId?: string; onDeleteAnalysis: () => void
return (
<Box sx={{ marginBottom: '2rem', width: '100%' }}>
<DisplayAnalysisWarnings analysisId={props.analysisId} />
<Box>
<Typography sx={{ marginBottom: '1rem', fontWeight: 'bold' }}>
Analysis Details
</Typography>
<EditAnalysisDetails analysisId={props.analysisId} />
</Box>

<Box sx={{ marginTop: '2rem', width: '100%' }}>
<Box sx={{ display: 'flex', alignItems: 'center', margin: '0.5rem 0' }}>
<Typography sx={{ fontWeight: 'bold', marginRight: '1rem' }}>
Analysis Coordinates
</Typography>
<Tooltip
title="To add or remove rows, right click on a cell to open the context menu. You must enter all coordinates in order to save the overall study. Please note that the ordering of points is not guaranteed."
placement="right"
>
<HelpIcon color="primary" />
</Tooltip>
</Box>
<EditAnalysisPointSpaceAndStatistic analysisId={props.analysisId} />
<EditAnalysisPoints analysisId={props.analysisId} />
</Box>
<EditAnalysisDetails analysisId={props.analysisId} />
<EditAnalysisPoints analysisId={props.analysisId} />
{/* TODO: This can be added back later when we have a better understanding of where it fits in as currently, all meta-analysis algorithms do not use this */}
{/* <Box sx={{ marginTop: '2rem' }}>
<Typography sx={{ marginBottom: '1rem', fontWeight: 'bold' }}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, TextField } from '@mui/material';
import { Box, TextField, Typography } from '@mui/material';
import {
useAddOrUpdateAnalysis,
useStudyAnalysisDescription,
Expand All @@ -25,6 +25,9 @@ const EditAnalysisDetails: React.FC<{ analysisId?: string }> = (props) => {

return (
<Box sx={{ width: '100%' }}>
<Typography sx={{ marginBottom: '1rem', fontWeight: 'bold' }}>
Analysis Details
</Typography>
<TextField
label="name"
size="small"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import EditAnalysisPointsHotTable from 'components/HotTables/EditAnalysisPointsHotTable/EditAnalysisPointsHotTable';
import EditAnalysisPointSpaceAndStatistic from '../EditAnalysisPointSpaceAndStatistic/EditAnalysisPointSpaceAndStatistic';
import { Box, Tooltip, Typography } from '@mui/material';
import HelpIcon from '@mui/icons-material/Help';

const EditAnalysisPoints: React.FC<{ analysisId?: string }> = (props) => {
return (
<Box sx={{ marginTop: '2rem', width: '100%' }}>
<Box sx={{ display: 'flex', alignItems: 'center', margin: '0.5rem 0' }}>
<Typography sx={{ fontWeight: 'bold', marginRight: '1rem' }}>
Analysis Coordinates
</Typography>
<Tooltip
title="To add or remove rows, right click on a cell to open the context menu. You must enter all coordinates in order to save the overall study. Please note that the ordering of points is not guaranteed."
placement="right"
>
<HelpIcon color="primary" />
</Tooltip>
</Box>
<EditAnalysisPointSpaceAndStatistic analysisId={props.analysisId} />
<EditAnalysisPointsHotTable analysisId={props.analysisId} />
</Box>
);
};

export default EditAnalysisPoints;
Loading

0 comments on commit ad50dd7

Please sign in to comment.