diff --git a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helper.spec.ts b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helper.spec.ts
new file mode 100644
index 000000000..8677b4d94
--- /dev/null
+++ b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helper.spec.ts
@@ -0,0 +1,112 @@
+import { IAnalysesSelection } from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationDialogBase.types';
+import { getWeightAndConditionsForSpecification } from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers';
+import { EPropertyType } from 'components/EditMetadata';
+import { IAutocompleteObject } from 'components/NeurosynthAutocomplete/NeurosynthAutocomplete';
+
+describe('CreateMetaAnalysisSpecificationReviewHelpers', () => {
+ describe('getWeightAndConditionsForSpecification', () => {
+ it('should set multiple weights and multiple conditions if the reference database is not default', () => {
+ const mockEstimator: IAutocompleteObject = {
+ label: 'ALESubtraction',
+ description: '',
+ };
+
+ const mockSelection: IAnalysesSelection = {
+ selectionKey: 'key',
+ selectionValue: 'val-selected',
+ referenceDataset: 'val-reference',
+ type: EPropertyType.STRING,
+ };
+
+ const result = getWeightAndConditionsForSpecification(mockEstimator, mockSelection);
+
+ expect(result.weights).toEqual([1, -1]);
+ expect(result.conditions).toEqual(['val-selected', 'val-reference']);
+ expect(result.databaseStudyset).toBeUndefined();
+ });
+
+ it('should return empty lists if the estimator is not defined', () => {
+ const mockSelection: IAnalysesSelection = {
+ selectionKey: 'key',
+ selectionValue: 'val',
+ referenceDataset: 'neuroquery',
+ type: EPropertyType.STRING,
+ };
+
+ const result = getWeightAndConditionsForSpecification(undefined, mockSelection);
+
+ expect(result.conditions.length).toEqual(0);
+ expect(result.weights.length).toEqual(0);
+ expect(result.databaseStudyset).toBeUndefined();
+ });
+
+ it('should set a single weight and a single condition if the reference database is default', () => {
+ const mockEstimator: IAutocompleteObject = {
+ label: 'ALESubtraction',
+ description: '',
+ };
+
+ const mockSelection: IAnalysesSelection = {
+ selectionKey: 'key',
+ selectionValue: 'val',
+ referenceDataset: 'neuroquery',
+ type: EPropertyType.STRING,
+ };
+
+ const result = getWeightAndConditionsForSpecification(mockEstimator, mockSelection);
+
+ expect(result.conditions.length).toEqual(1);
+ expect(result.weights).toEqual([1]);
+ expect(result.databaseStudyset).toEqual('neuroquery');
+ });
+
+ it('should parse the array into correct boolean types', () => {
+ let mockEstimator: IAutocompleteObject = {
+ label: 'ALESubtraction',
+ description: '',
+ };
+
+ let mockSelection: IAnalysesSelection = {
+ selectionKey: 'key',
+ selectionValue: 'true',
+ referenceDataset: 'false',
+ type: EPropertyType.BOOLEAN,
+ };
+
+ let result = getWeightAndConditionsForSpecification(mockEstimator, mockSelection);
+ expect(result.conditions).toEqual([true, false]);
+
+ mockEstimator = {
+ label: 'ALESubtraction',
+ description: '',
+ };
+
+ mockSelection = {
+ selectionKey: 'key',
+ selectionValue: true,
+ referenceDataset: 'false',
+ type: EPropertyType.BOOLEAN,
+ };
+
+ result = getWeightAndConditionsForSpecification(mockEstimator, mockSelection);
+ expect(result.conditions).toEqual([true, false]);
+ });
+
+ it('should parse the array into correct string types', () => {
+ let mockEstimator: IAutocompleteObject = {
+ label: 'ALESubtraction',
+ description: '',
+ };
+
+ let mockSelection: IAnalysesSelection = {
+ selectionKey: 'key',
+ selectionValue: 'true',
+ referenceDataset: 'false',
+ type: EPropertyType.STRING,
+ };
+
+ let result = getWeightAndConditionsForSpecification(mockEstimator, mockSelection);
+ expect(result.conditions).toEqual(['true', 'false']);
+ });
+ });
+});
diff --git a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers.ts b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers.ts
index 0f445fc80..aa334fa4b 100644
--- a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers.ts
+++ b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers.ts
@@ -4,6 +4,7 @@ import {
selectedReferenceDatasetIsDefaultDataset,
} from '../CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers';
import { IAnalysesSelection } from '../CreateMetaAnalysisSpecificationDialogBase.types';
+import { EPropertyType } from 'components/EditMetadata';
export const getWeightAndConditionsForSpecification = (
estimator: IAutocompleteObject | null | undefined,
@@ -41,6 +42,21 @@ export const getWeightAndConditionsForSpecification = (
conditions = [selection.selectionValue] as string[] | boolean[];
}
+ // parse condition into correct type
+ conditions.forEach((condition, index) => {
+ switch (selection.type) {
+ case EPropertyType.BOOLEAN:
+ conditions[index] =
+ typeof condition === 'boolean' ? condition : condition === 'true';
+ break;
+ case EPropertyType.STRING:
+ conditions[index] = condition.toString();
+ break;
+ default:
+ throw new Error('unsupported selection type');
+ }
+ });
+
return {
weights,
conditions,
diff --git a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/CreateMetaAnalysisSpecificationSelectionStepMultiGroup.tsx b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/CreateMetaAnalysisSpecificationSelectionStepMultiGroup.tsx
index 8a36c4889..e54c2be6b 100644
--- a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/CreateMetaAnalysisSpecificationSelectionStepMultiGroup.tsx
+++ b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/CreateMetaAnalysisSpecificationSelectionStepMultiGroup.tsx
@@ -20,7 +20,6 @@ const CreateMetaAnalysisSpecificationSelectionStepMultiGroup: React.FC<{
selectedValue: IAnalysesSelection;
}> = (props) => {
const { algorithm, onSelectValue, annotationId, selectedValue } = props;
-
const columnOptions = useInclusionColumnOptions(annotationId, selectedValue?.selectionKey);
const colOptionsToMultiGroupOptions: IMultiGroupOption[] = useMemo(() => {
return columnOptions
@@ -40,9 +39,7 @@ const CreateMetaAnalysisSpecificationSelectionStepMultiGroup: React.FC<{
const selectedOption = useMemo(() => {
if (!selectedValue.referenceDataset) return undefined;
- const foundOption = multiGroupOptions.find(
- (x) => x.label === selectedValue.referenceDataset
- );
+ const foundOption = multiGroupOptions.find((x) => x.id === selectedValue.referenceDataset);
return foundOption;
}, [multiGroupOptions, selectedValue.referenceDataset]);
diff --git a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.spec.ts b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.spec.ts
new file mode 100644
index 000000000..13f0900d6
--- /dev/null
+++ b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.spec.ts
@@ -0,0 +1,51 @@
+import {
+ isMultiGroupAlgorithm,
+ selectedReferenceDatasetIsDefaultDataset,
+} from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers';
+import {
+ DEFAULT_REFERENCE_DATASETS,
+ MULTIGROUP_ALGORITHMS,
+} from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.types';
+
+describe('SelectAnalysesComponentHelpers', () => {
+ describe('selectedReferenceDatasetIsDefaultDataset', () => {
+ it('should be truthy for default datasets', () => {
+ DEFAULT_REFERENCE_DATASETS.forEach((dataset) => {
+ const result = selectedReferenceDatasetIsDefaultDataset(dataset.id);
+ expect(result).toBeTruthy();
+ });
+ });
+
+ it('should return false for non reference datasets', () => {
+ const result = selectedReferenceDatasetIsDefaultDataset('random dataset');
+ expect(result).toBeFalsy();
+ });
+
+ it('should return false for undefined', () => {
+ const result = selectedReferenceDatasetIsDefaultDataset(undefined);
+ expect(result).toBeFalsy();
+ });
+ });
+
+ describe('isMultiGroupAlgorithm', () => {
+ it('should be truthy for multigroup algorithms', () => {
+ MULTIGROUP_ALGORITHMS.forEach((multigroupAlgorithm) => {
+ const result = isMultiGroupAlgorithm({
+ label: multigroupAlgorithm,
+ description: '',
+ });
+ expect(result).toBeTruthy();
+ });
+ });
+
+ it('should return false for non reference datasets', () => {
+ const result = isMultiGroupAlgorithm({ label: 'random', description: '' });
+ expect(result).toBeFalsy();
+ });
+
+ it('should return false for undefined', () => {
+ const result = isMultiGroupAlgorithm(undefined);
+ expect(result).toBeFalsy();
+ });
+ });
+});
diff --git a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.ts b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.ts
index 932d191ff..b58e5d143 100644
--- a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.ts
+++ b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers.ts
@@ -93,5 +93,5 @@ export const selectedReferenceDatasetIsDefaultDataset = (
) => {
if (!selectedReferenceDataset) return false;
- return DEFAULT_REFERENCE_DATASETS.some((x) => x.label === selectedReferenceDataset);
+ return DEFAULT_REFERENCE_DATASETS.some((x) => x.id === selectedReferenceDataset);
};
diff --git a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesSummaryComponent.tsx b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesSummaryComponent.tsx
index 23b3b8580..91f9267c6 100644
--- a/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesSummaryComponent.tsx
+++ b/compose/neurosynth-frontend/src/components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesSummaryComponent.tsx
@@ -76,6 +76,9 @@ const SelectAnalysesSummaryComponent: React.FC<{
return (
+
+ Included:
+ {' '}
{count.studies} studies
{' '}
diff --git a/compose/neurosynth-frontend/src/components/Dialogs/EditSpecificationDialog/EditSpecificationDialog.tsx b/compose/neurosynth-frontend/src/components/Dialogs/EditSpecificationDialog/EditSpecificationDialog.tsx
index 74b2fce50..26a11285e 100644
--- a/compose/neurosynth-frontend/src/components/Dialogs/EditSpecificationDialog/EditSpecificationDialog.tsx
+++ b/compose/neurosynth-frontend/src/components/Dialogs/EditSpecificationDialog/EditSpecificationDialog.tsx
@@ -20,12 +20,13 @@ import {
} from 'neurosynth-compose-typescript-sdk';
import { useEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
-import BaseDialog, { IDialog } from '../BaseDialog';
-import SelectSpecificationComponent from '../CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationAlgorithmStep/SelectSpecificationComponent/SelectSpecificationComponent';
-import { IAnalysesSelection } from '../CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationDialogBase.types';
-import SelectAnalysesComponent from '../CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent';
-import { isMultiGroupAlgorithm } from '../CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers';
-import { getWeightAndConditionsForSpecification } from '../CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers';
+import BaseDialog, { IDialog } from 'components/Dialogs/BaseDialog';
+import SelectSpecificationComponent from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationAlgorithmStep/SelectSpecificationComponent/SelectSpecificationComponent';
+import { IAnalysesSelection } from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationDialogBase.types';
+import SelectAnalysesComponent from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent';
+import { isMultiGroupAlgorithm } from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers';
+import { getWeightAndConditionsForSpecification } from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationReview/CreateMetaAnalysisSpecificationReview.helpers';
+import CreateMetaAnalysisSpecificationSelectionStepMultiGroup from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/CreateMetaAnalysisSpecificationSelectionStepMultiGroup';
const metaAnalysisSpecification: IMetaAnalysisParamsSpecification = metaAnalysisSpec;
@@ -64,6 +65,10 @@ const EditSpecificationDialog: React.FC = (props) => {
selectionKey: specification.filter,
type: getType(specification?.conditions?.[0]),
selectionValue: (specification.conditions || [])[0],
+ referenceDataset:
+ specification?.conditions?.[1] !== undefined
+ ? specification.conditions[1].toString()
+ : specification?.database_studyset || undefined,
});
const estimator = specification?.estimator?.type
@@ -103,7 +108,6 @@ const EditSpecificationDialog: React.FC = (props) => {
algorithmSpec.estimator,
selectedValue
);
-
mutate(
{
specificationId: specification.id,
@@ -133,6 +137,8 @@ const EditSpecificationDialog: React.FC = (props) => {
);
};
+ const isMultiGroup = isMultiGroupAlgorithm(algorithmSpec.estimator);
+
const disabled = useMemo(() => {
const isMultiGroup = isMultiGroupAlgorithm(algorithmSpec.estimator);
return (
@@ -191,6 +197,16 @@ const EditSpecificationDialog: React.FC = (props) => {
}}
algorithm={algorithmSpec}
/>
+ {isMultiGroup && (
+ setSelectedValue(newVal)}
+ annotationId={
+ (metaAnalysis?.annotation as AnnotationReturn)?.neurostore_id || ''
+ }
+ selectedValue={selectedValue}
+ algorithm={algorithmSpec}
+ />
+ )}
{
+ const queryClient = useQueryClient();
+ const { enqueueSnackbar } = useSnackbar();
+ return useMutation(
+ (id) => API.NeurosynthServices.NeurosynthDefaultApi.metaAnalysesIdDelete(id),
+ {
+ onSuccess: () => {
+ queryClient.invalidateQueries('meta-analyses');
+ },
+ onError: () => {
+ enqueueSnackbar('There was an error deleting the meta-analysis', {
+ variant: 'error',
+ });
+ },
+ }
+ );
+};
+
+export default useDeleteMetaAnalysis;
diff --git a/compose/neurosynth-frontend/src/pages/MetaAnalyses/MetaAnalysisPage/MetaAnalysisPage.tsx b/compose/neurosynth-frontend/src/pages/MetaAnalyses/MetaAnalysisPage/MetaAnalysisPage.tsx
index 829989e7e..939b31575 100644
--- a/compose/neurosynth-frontend/src/pages/MetaAnalyses/MetaAnalysisPage/MetaAnalysisPage.tsx
+++ b/compose/neurosynth-frontend/src/pages/MetaAnalyses/MetaAnalysisPage/MetaAnalysisPage.tsx
@@ -2,6 +2,7 @@ import { useAuth0 } from '@auth0/auth0-react';
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
import { Box, Button, Link, Paper, Typography } from '@mui/material';
import CodeSnippet from 'components/CodeSnippet/CodeSnippet';
+import { isMultiGroupAlgorithm } from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesComponent.helpers';
import SelectAnalysesSummaryComponent from 'components/Dialogs/CreateMetaAnalysisSpecificationDialog/CreateMetaAnalysisSpecificationSelectionStep/SelectAnalysesComponent/SelectAnalysesSummaryComponent';
import EditSpecificationDialog from 'components/Dialogs/EditSpecificationDialog/EditSpecificationDialog';
import DisplayMetaAnalysisResult from 'components/DisplayMetaAnalysisResult/DisplayMetaAnalysisResult';
@@ -126,6 +127,25 @@ const MetaAnalysisPage: React.FC = (props) => {
return `${selectionKey} ${selectionValue}`;
}, [specification]);
+ const referenceDataset = useMemo(() => {
+ const isMulti = isMultiGroupAlgorithm({
+ label: specification?.estimator?.type || '',
+ description: '',
+ });
+
+ if (isMulti) {
+ return specification?.conditions?.[1] !== undefined
+ ? specification.conditions[1].toString()
+ : specification?.database_studyset;
+ } else {
+ return null;
+ }
+ }, [
+ specification?.conditions,
+ specification?.database_studyset,
+ specification?.estimator?.type,
+ ]);
+
const metaAnalysisTypeDescription = useMemo(() => {
return getAnalysisTypeDescription((metaAnalysis?.specification as Specification)?.type);
}, [metaAnalysis?.specification]);
@@ -296,7 +316,7 @@ const MetaAnalysisPage: React.FC = (props) => {
)}
- {specification?.database_studyset && (
+ {referenceDataset && (
<>
{
}}
/>
- Reference Dataset: {specification.database_studyset}
+ Reference Dataset: {referenceDataset}
>
)}
diff --git a/compose/neurosynth-frontend/src/utils/api.ts b/compose/neurosynth-frontend/src/utils/api.ts
index 3252a7d4c..47095dc77 100644
--- a/compose/neurosynth-frontend/src/utils/api.ts
+++ b/compose/neurosynth-frontend/src/utils/api.ts
@@ -21,6 +21,7 @@ import {
AnnotationsApi as NeurosynthAnnotationApi,
StudysetsApi as NeurosynthStudysetApi,
ProjectsApi,
+ DefaultApi as NeurosynthDefaultApi,
} from '../neurosynth-compose-typescript-sdk';
export type NeurostoreAnnotation = AnnotationBase &
@@ -62,6 +63,7 @@ const NeurosynthServices = {
StudysetsService: new NeurosynthStudysetApi(neurosynthConfig),
AnnotationsService: new NeurosynthAnnotationApi(neurosynthConfig),
ProjectsService: new ProjectsApi(neurosynthConfig),
+ NeurosynthDefaultApi: new NeurosynthDefaultApi(neurosynthConfig),
};
const UpdateServicesWithToken = (token: string) => {