diff --git a/.github/workflows/e2e-test.yaml b/.github/workflows/e2e-test.yaml index 3e0023d4..49e65a0d 100644 --- a/.github/workflows/e2e-test.yaml +++ b/.github/workflows/e2e-test.yaml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-node@v4.0.1 with: node-version: 20 - + - name: Create .env file run: | echo -e "NB_API_QUERY_URL=${{ vars.NB_API_QUERY_URL }}\nNB_IS_FEDERATION_API=${{ vars.NB_IS_FEDERATION_API }}" > .env @@ -32,4 +32,3 @@ jobs: wait-on: http://localhost:5173 start: npm run preview component: false - diff --git a/cypress.config.ts b/cypress.config.ts index c446ee0c..37902fc5 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -4,7 +4,7 @@ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { experimentalStudio: true, - baseUrl: "http://localhost:5173", + baseUrl: 'http://localhost:5173', }, component: { diff --git a/cypress.d.ts b/cypress.d.ts index 52c45320..08e9ac27 100644 --- a/cypress.d.ts +++ b/cypress.d.ts @@ -1,10 +1,10 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import { mount } from 'cypress/react' +import { mount } from 'cypress/react'; declare global { namespace Cypress { interface Chainable { - mount: typeof mount + mount: typeof mount; } } -} \ No newline at end of file +} diff --git a/cypress/e2e/APIRequests.cy.ts b/cypress/e2e/APIRequests.cy.ts index d8aeef74..3aa446e9 100644 --- a/cypress/e2e/APIRequests.cy.ts +++ b/cypress/e2e/APIRequests.cy.ts @@ -1,15 +1,26 @@ -import { mixedResponse, nodeOptions, emptyDiagnosisOptions, emptyAssessmentToolOptions } from '../fixtures/mocked-responses'; +import { + mixedResponse, + nodeOptions, + emptyDiagnosisOptions, + emptyAssessmentToolOptions, +} from '../fixtures/mocked-responses'; describe('API request', () => { it('Intercepts the request sent to the API and asserts over the request url', () => { - cy.intercept({ - method: 'GET', - url: 'query/?*', - }, mixedResponse).as('call'); - cy.intercept({ - method: 'GET', - url: '/nodes/', - }, nodeOptions).as('getNodes'); + cy.intercept( + { + method: 'GET', + url: 'query/?*', + }, + mixedResponse + ).as('call'); + cy.intercept( + { + method: 'GET', + url: '/nodes/', + }, + nodeOptions + ).as('getNodes'); cy.visit('/?node=OpenNeuro'); // We need to wait for the fetch to complete and populate the // dropdown with nodes and selecting OpenNeuro before making the request @@ -20,32 +31,53 @@ describe('API request', () => { cy.wait('@call').its('request.url').should('contains', '&min_age=10&max_age=30'); }); it('Empty responses for diagnosis and Assessment make a toast appear', () => { - cy.intercept({ - method: 'GET', - url: '/attributes/nb:Diagnosis', - }, emptyDiagnosisOptions).as('getDiagnosisOptions'); - cy.intercept({ - method: 'GET', - url: '/attributes/nb:Assessment', - }, emptyAssessmentToolOptions).as('getAssessmentToolOptions'); + cy.intercept( + { + method: 'GET', + url: '/attributes/nb:Diagnosis', + }, + emptyDiagnosisOptions + ).as('getDiagnosisOptions'); + cy.intercept( + { + method: 'GET', + url: '/attributes/nb:Assessment', + }, + emptyAssessmentToolOptions + ).as('getAssessmentToolOptions'); cy.visit('/'); cy.wait('@getDiagnosisOptions'); cy.get('.notistack-SnackbarContainer').should('contain', 'No Diagnosis options were available'); - cy.get('.notistack-SnackbarContainer').should('contain', 'No Assessment tool options were available'); + cy.get('.notistack-SnackbarContainer').should( + 'contain', + 'No Assessment tool options were available' + ); }); it('Failed responses for diagnosis and assessment make an error toast appear', () => { - cy.intercept({ - method: 'GET', - url: '/attributes/nb:Diagnosis', - }, { statusCode: 500 }).as('getDiagnosisOptions'); - cy.intercept({ - method: 'GET', - url: '/attributes/nb:Assessment', - }, { statusCode: 500 }).as('getAssessmentToolOptions'); + cy.intercept( + { + method: 'GET', + url: '/attributes/nb:Diagnosis', + }, + { statusCode: 500 } + ).as('getDiagnosisOptions'); + cy.intercept( + { + method: 'GET', + url: '/attributes/nb:Assessment', + }, + { statusCode: 500 } + ).as('getAssessmentToolOptions'); cy.visit('/'); cy.wait('@getDiagnosisOptions'); - cy.get('.notistack-SnackbarContainer').should('contain', 'Failed to retrieve Diagnosis options'); + cy.get('.notistack-SnackbarContainer').should( + 'contain', + 'Failed to retrieve Diagnosis options' + ); cy.wait('@getAssessmentToolOptions'); - cy.get('.notistack-SnackbarContainer').should('contain', 'Failed to retrieve Assessment tool options'); + cy.get('.notistack-SnackbarContainer').should( + 'contain', + 'Failed to retrieve Assessment tool options' + ); }); }); diff --git a/cypress/e2e/Alert.cy.ts b/cypress/e2e/Alert.cy.ts index b06ba78b..72dd0e86 100644 --- a/cypress/e2e/Alert.cy.ts +++ b/cypress/e2e/Alert.cy.ts @@ -1,27 +1,32 @@ describe('Alert', () => { - it('Correctly displays and dismisses the alert', () => { - cy.intercept({ - method: 'GET', - url: '/nodes/', - }).as('getNodes'); - cy.visit('/?node=All'); - // We need to wait for the fetch to complete and populate the - // dropdown with nodes before searching for OpenNeuro - cy.wait('@getNodes'); - cy.get('[data-cy="openneuro-alert"]').should('be.visible').should('contain', 'The OpenNeuro node is being actively annotated at the participant'); + it('Correctly displays and dismisses the alert', () => { + cy.intercept({ + method: 'GET', + url: '/nodes/', + }).as('getNodes'); + cy.visit('/?node=All'); + // We need to wait for the fetch to complete and populate the + // dropdown with nodes before searching for OpenNeuro + cy.wait('@getNodes'); + cy.get('[data-cy="openneuro-alert"]') + .should('be.visible') + .should('contain', 'The OpenNeuro node is being actively annotated at the participant'); - cy.get('[data-cy="Neurobagel graph-categorical-field"]').type('Quebec Parkinson Network{downarrow}{enter}'); - cy.get('[data-cy="openneuro-alert"]').should('not.exist'); - - cy.get('[data-cy="Neurobagel graph-categorical-field"]').should('not.contain', 'All'); - cy.get('[data-cy="Neurobagel graph-categorical-field"]').find('[data-testid="CloseIcon"]').click(); - cy.get('[data-cy="Neurobagel graph-categorical-field"]').should('contain', 'All'); + cy.get('[data-cy="Neurobagel graph-categorical-field"]').type( + 'Quebec Parkinson Network{downarrow}{enter}' + ); + cy.get('[data-cy="openneuro-alert"]').should('not.exist'); - cy.get('[data-cy="Neurobagel graph-categorical-field"]').type('OpenNeuro{downarrow}{enter}'); - cy.get('[data-cy="openneuro-alert"]').should('be.visible'); + cy.get('[data-cy="Neurobagel graph-categorical-field"]').should('not.contain', 'All'); + cy.get('[data-cy="Neurobagel graph-categorical-field"]') + .find('[data-testid="CloseIcon"]') + .click(); + cy.get('[data-cy="Neurobagel graph-categorical-field"]').should('contain', 'All'); - cy.get('[data-cy="openneuro-alert"]').find('[data-testid="CloseIcon"]').click(); - cy.get('[data-cy="openneuro-alert"]').should('not.exist'); - }); + cy.get('[data-cy="Neurobagel graph-categorical-field"]').type('OpenNeuro{downarrow}{enter}'); + cy.get('[data-cy="openneuro-alert"]').should('be.visible'); + + cy.get('[data-cy="openneuro-alert"]').find('[data-testid="CloseIcon"]').click(); + cy.get('[data-cy="openneuro-alert"]').should('not.exist'); }); - \ No newline at end of file +}); diff --git a/cypress/e2e/Checkbox.cy.ts b/cypress/e2e/Checkbox.cy.ts index b71ff11a..ba605c97 100644 --- a/cypress/e2e/Checkbox.cy.ts +++ b/cypress/e2e/Checkbox.cy.ts @@ -16,9 +16,13 @@ describe('Dataset result checkbox', () => { cy.visit('/'); cy.get('[data-cy="submit-query"]').click(); cy.wait('@call'); - cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"]').find('input').check(); + cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"]') + .find('input') + .check(); cy.get('[data-cy="submit-query"]').click(); cy.wait('@call'); - cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"]').should('not.be.checked'); + cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"]').should( + 'not.be.checked' + ); }); }); diff --git a/cypress/fixtures/mocked-responses.ts b/cypress/fixtures/mocked-responses.ts index e802cfb0..b3c58cce 100644 --- a/cypress/fixtures/mocked-responses.ts +++ b/cypress/fixtures/mocked-responses.ts @@ -14,13 +14,9 @@ export const unprotectedresponse1 = [ num_sessions: '1', age: '10.4', sex: 'http://purl.bioontology.org/ontology/SNOMEDCT/248152002', - diagnosis: [ - null, - ], + diagnosis: [null], subject_group: null, - assessment: [ - null, - ], + assessment: [null], image_modal: [ 'http://purl.org/nidash/nidm#FlowWeighted', 'http://purl.org/nidash/nidm#T2Weighted', @@ -33,13 +29,9 @@ export const unprotectedresponse1 = [ num_sessions: '1', age: '10.4', sex: 'http://purl.bioontology.org/ontology/SNOMEDCT/248152002', - diagnosis: [ - null, - ], + diagnosis: [null], subject_group: null, - assessment: [ - null, - ], + assessment: [null], image_modal: [ 'http://purl.org/nidash/nidm#FlowWeighted', 'http://purl.org/nidash/nidm#T2Weighted', @@ -64,7 +56,10 @@ export const protectedResponse1 = [ records_protected: true, num_matching_subjects: 2, subject_data: 'protected', - image_modals: ['http://purl.org/nidash/nidm#T1Weighted', 'http://purl.org/nidash/nidm#T2Weighted'], + image_modals: [ + 'http://purl.org/nidash/nidm#T1Weighted', + 'http://purl.org/nidash/nidm#T2Weighted', + ], }, ]; @@ -78,7 +73,10 @@ export const protectedResponse2 = [ records_protected: true, num_matching_subjects: 2, subject_data: 'protected', - image_modals: ['http://purl.org/nidash/nidm#T1Weighted', 'http://purl.org/nidash/nidm#T2Weighted'], + image_modals: [ + 'http://purl.org/nidash/nidm#T1Weighted', + 'http://purl.org/nidash/nidm#T2Weighted', + ], }, { node_name: 'another-node-name', @@ -89,9 +87,12 @@ export const protectedResponse2 = [ records_protected: true, num_matching_subjects: 2, subject_data: 'protected', - image_modals: ['http://purl.org/nidash/nidm#T2Weighted', 'http://purl.org/nidash/nidm#FlowWeighted', 'http://purl.org/nidash/nidm#T1Weighted'], + image_modals: [ + 'http://purl.org/nidash/nidm#T2Weighted', + 'http://purl.org/nidash/nidm#FlowWeighted', + 'http://purl.org/nidash/nidm#T1Weighted', + ], }, - ]; // Protected Response with a dataset name containing a newline @@ -105,7 +106,10 @@ export const mixedResponse = [ dataset_total_subjects: 10, num_matching_subjects: 3, subject_data: 'protected', - image_modals: ['http://purl.org/nidash/nidm#FlowWeighted', 'http://purl.org/nidash/nidm#T1Weighted'], + image_modals: [ + 'http://purl.org/nidash/nidm#FlowWeighted', + 'http://purl.org/nidash/nidm#T1Weighted', + ], }, { records_protected: false, @@ -121,15 +125,9 @@ export const mixedResponse = [ num_sessions: '1', age: '35.0', sex: 'http://purl.bioontology.org/ontology/SNOMEDCT/248153007', - diagnosis: [ - null, - null, - null, - ], + diagnosis: [null, null, null], subject_group: null, - assessment: [ - null, - ], + assessment: [null], image_modal: [ 'http://purl.org/nidash/nidm#T2Weighted', 'http://purl.org/nidash/nidm#T1Weighted', @@ -138,21 +136,23 @@ export const mixedResponse = [ session_file_path: '/ds000011/sub-04', }, ], - image_modals: ['http://purl.org/nidash/nidm#FlowWeighted', 'http://purl.org/nidash/nidm#T1Weighted'], + image_modals: [ + 'http://purl.org/nidash/nidm#FlowWeighted', + 'http://purl.org/nidash/nidm#T1Weighted', + ], }, - ]; export const nodeOptions = [ { - "NodeName": "OpenNeuro", - "ApiURL": "https://someurl/" + NodeName: 'OpenNeuro', + ApiURL: 'https://someurl/', }, { - "NodeName": "Quebec Parkinson Network", - "ApiURL": "http://anotherurl/" - } -] + NodeName: 'Quebec Parkinson Network', + ApiURL: 'http://anotherurl/', + }, +]; export const emptyDiagnosisOptions = { 'nb:Diagnosis': [], diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 698b01a4..95857aea 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -34,4 +34,4 @@ // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable // } // } -// } \ No newline at end of file +// } diff --git a/cypress/support/component-index.html b/cypress/support/component-index.html index ac6e79fd..faf3b5f4 100644 --- a/cypress/support/component-index.html +++ b/cypress/support/component-index.html @@ -1,12 +1,12 @@ - + - - - + + + Components App
- \ No newline at end of file + diff --git a/cypress/support/component.ts b/cypress/support/component.ts index 37f59edb..395d4075 100644 --- a/cypress/support/component.ts +++ b/cypress/support/component.ts @@ -14,12 +14,12 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands' +import './commands'; // Alternatively you can use CommonJS syntax: // require('./commands') -import { mount } from 'cypress/react18' +import { mount } from 'cypress/react18'; // Augment the Cypress namespace to include type definitions for // your custom command. @@ -28,12 +28,12 @@ import { mount } from 'cypress/react18' declare global { namespace Cypress { interface Chainable { - mount: typeof mount + mount: typeof mount; } } } -Cypress.Commands.add('mount', mount) +Cypress.Commands.add('mount', mount); // Example use: -// cy.mount() \ No newline at end of file +// cy.mount() diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index f80f74f8..598ab5f0 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands' +import './commands'; // Alternatively you can use CommonJS syntax: -// require('./commands') \ No newline at end of file +// require('./commands') diff --git a/src/App.tsx b/src/App.tsx index feb6bc94..66e47c2e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,7 +20,7 @@ import './App.css'; function App() { const [diagnosisOptions, setDiagnosisOptions] = useState([]); const [assessmentOptions, setAssessmentOptions] = useState([]); - const [nodeOptions, setNodeOptions] = useState([ + const [availableNodes, setAvailableNodes] = useState([ { NodeName: 'All', ApiURL: 'allNodes' }, ]); @@ -30,7 +30,6 @@ function App() { const [result, setResult] = useState(null); - const [node, setNode] = useState([{ label: 'All', id: 'allNodes' }]); const [minAge, setMinAge] = useState(null); const [maxAge, setMaxAge] = useState(null); const [sex, setSex] = useState(null); @@ -41,6 +40,10 @@ function App() { const [imagingModality, setImagingModality] = useState(null); const [searchParams, setSearchParams] = useSearchParams(); + const selectedNode: FieldInputOption[] = availableNodes + .filter((option) => searchParams.getAll('node').includes(option.NodeName)) + .map((filteredOption) => ({ label: filteredOption.NodeName, id: filteredOption.ApiURL })); + useEffect(() => { async function getAttributes(dataElementURI: string) { try { @@ -48,13 +51,12 @@ function App() { `${attributesURL}${dataElementURI}` ); return response.data[dataElementURI]; - } - catch (err) { + } catch (err) { return null; } } - getAttributes('nb:Diagnosis').then(diagnosisResponse => { + getAttributes('nb:Diagnosis').then((diagnosisResponse) => { if (diagnosisResponse === null) { enqueueSnackbar('Failed to retrieve Diagnosis options', { variant: 'error' }); } else if (diagnosisResponse.length === 0) { @@ -64,7 +66,7 @@ function App() { } }); - getAttributes('nb:Assessment').then(assessmentResponse => { + getAttributes('nb:Assessment').then((assessmentResponse) => { if (assessmentResponse === null) { enqueueSnackbar('Failed to retrieve Assessment tool options', { variant: 'error' }); } else if (assessmentResponse.length === 0) { @@ -78,67 +80,50 @@ function App() { try { const response: AxiosResponse = await axios.get(fetchURL); return response.data; - } - catch (err) { + } catch (err) { return null; } } if (isFederationAPI) { - getNodeOptions(nodesURL).then(nodeResponse => { + getNodeOptions(nodesURL).then((nodeResponse) => { if (nodeResponse === null) { enqueueSnackbar('Failed to retrieve Node options', { variant: 'error' }); } else if (nodeResponse.length === 0) { enqueueSnackbar('No options found for Node', { variant: 'info' }); } else { - setNodeOptions([...nodeResponse, { NodeName: 'All', ApiURL: 'allNodes' }]); + setAvailableNodes([...nodeResponse, { NodeName: 'All', ApiURL: 'allNodes' }]); } }); } - }, []); - function arraysEqual(a: FieldInputOption[], b: FieldInputOption[]) { - return a.length === b.length && a.every((val, index) => val.id === b[index].id && val.label === b[index].label); - } - - // TODO: Refactor this to address the duplicated state and the loop of doom useEffect(() => { - if (nodeOptions.length > 1) { + if (availableNodes.length > 1) { const searchParamNodes: string[] = searchParams.getAll('node'); + if (searchParamNodes) { - const matchedOptions: FieldInputOption[] = searchParamNodes - .map((nodeName) => { - const foundOption = nodeOptions.find((option) => option.NodeName === nodeName); - return foundOption ? { label: nodeName, id: foundOption.ApiURL } : { label: nodeName, id: '' }; - }) - .filter((option) => option.id !== ''); + const matchedNodeNames: string[] = searchParamNodes.filter((nodeName) => + availableNodes.some((option) => option.NodeName === nodeName) + ); + // If there is no node in the search params, set it to All - if (matchedOptions.length === 0) { + if (matchedNodeNames.length === 0) { setSearchParams({ node: ['All'] }); - setNode([{ label: 'All', id: 'allNodes' }]); } // If there is any node besides All selected, remove All from the list - else if ( - matchedOptions.length > 1 && - matchedOptions.some((option) => option.id === 'allNodes') - ) { - const filteredNode: FieldInputOption[] = matchedOptions.filter( - (n) => n.id !== 'allNodes' - ); - setNode(filteredNode); - setSearchParams({ node: filteredNode.map((n) => n.label) }); - } else if (Array.isArray(node) && !arraysEqual(node, matchedOptions)) { - setNode(matchedOptions); + else if (matchedNodeNames.length > 1 && matchedNodeNames.includes('All')) { + const filteredNodeNames = matchedNodeNames.filter((nodeName) => nodeName !== 'All'); + setSearchParams({ node: filteredNodeNames }); } } } - }, [searchParams, setSearchParams, nodeOptions, node]); + }, [searchParams, setSearchParams, availableNodes]); function showAlert() { - if (node && Array.isArray(node)) { - const openNeuroIsAnOption = nodeOptions.find((n) => n.NodeName === 'OpenNeuro'); - const isOpenNeuroSelected = node.find( + if (selectedNode && Array.isArray(selectedNode)) { + const openNeuroIsAnOption = availableNodes.find((n) => n.NodeName === 'OpenNeuro'); + const isOpenNeuroSelected = selectedNode.find( (n) => n.label === 'OpenNeuro' || (n.label === 'All' && openNeuroIsAnOption) ); return isOpenNeuroSelected && !alertDismissed; @@ -149,9 +134,16 @@ function App() { function updateCategoricalQueryParams(fieldLabel: string, value: FieldInput) { switch (fieldLabel) { case 'Neurobagel graph': - setNode(value); if (Array.isArray(value)) { - setSearchParams({ node: value.map((n) => n.label) }); + // If no option is selected default to All + if (value.length === 0) { + setSearchParams({ node: ['All'] }); + // If any option beside All is selected, remove All + } else if (value.length > 1) { + setSearchParams({ node: value.filter((n) => n.label !== 'All').map((n) => n.label) }); + } else { + setSearchParams({ node: value.map((n) => n.label) }); + } } break; case 'Sex': @@ -219,7 +211,7 @@ function App() { function constructQueryURL() { const queryParams = new URLSearchParams(); - setQueryParam('node_url', node, queryParams); + setQueryParam('node_url', selectedNode, queryParams); queryParams.set('min_age', minAge ? minAge.toString() : ''); queryParams.set('max_age', maxAge ? maxAge.toString() : ''); setQueryParam('sex', sex, queryParams); @@ -260,7 +252,11 @@ function App() { return ( <> - + {showAlert() && ( <> @@ -293,10 +289,10 @@ function App() {
a.label.localeCompare(b.label))} - isOptionEqualToValue={(option, value) => option.id === value.id} - value={inputValue} - renderInput={(params) => ( - - )} - multiple={multiple} - onChange={(_, value) => onFieldChange(label, value)} - /> + a.label.localeCompare(b.label))} + isOptionEqualToValue={(option, value) => option.id === value.id} + value={inputValue} + renderInput={(params) => ( + + )} + multiple={multiple} + onChange={(_, value) => onFieldChange(label, value)} + /> ); } diff --git a/src/components/DownloadResultButton.tsx b/src/components/DownloadResultButton.tsx index 0f6de54b..0a7524a7 100644 --- a/src/components/DownloadResultButton.tsx +++ b/src/components/DownloadResultButton.tsx @@ -30,7 +30,7 @@ function DownloadResultButton({ {button} ) : ( - button + button ); } diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 69d1e89f..6cfa11c0 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -7,13 +7,15 @@ function Navbar() { const [latestReleaseTag, setLatestReleaseTag] = useState(''); useEffect(() => { - // TODO: replace with react-query-tool once there is a release - const GHApiURL = 'https://api.github.com/repos/neurobagel/query-tool/releases/latest'; - axios.get(GHApiURL) + // TODO: replace with react-query-tool once there is a release + const GHApiURL = 'https://api.github.com/repos/neurobagel/query-tool/releases/latest'; + axios + .get(GHApiURL) .then((response) => { - const {data} = response; + const { data } = response; setLatestReleaseTag(data.tag_name); - }).catch(() => { + }) + .catch(() => { setLatestReleaseTag('beta'); }); }, []); diff --git a/src/components/QueryForm.tsx b/src/components/QueryForm.tsx index bc70e158..ab4e6fd6 100644 --- a/src/components/QueryForm.tsx +++ b/src/components/QueryForm.tsx @@ -48,8 +48,7 @@ function QueryForm({ loading: boolean; onSubmitQuery: () => void; }) { - - function validateContinuousValue (value: number | null) { + function validateContinuousValue(value: number | null) { if (value === null) { // Value is default, user has not entered anything yet return ''; @@ -69,7 +68,10 @@ function QueryForm({ const minAgeExceedsMaxAge: boolean = minAge && maxAge ? minAge > maxAge : false; const disableSubmit: boolean = - minAgeExceedsMaxAge || minAgeHelperText !== '' || maxAgeHelperText !== '' || minNumSessionsHelperText !== ''; + minAgeExceedsMaxAge || + minAgeHelperText !== '' || + maxAgeHelperText !== '' || + minNumSessionsHelperText !== ''; return (
- onCheckboxChange(datasetUUID)} /> + onCheckboxChange(datasetUUID)} + />
{datasetName} diff --git a/src/components/ResultContainer.tsx b/src/components/ResultContainer.tsx index 85161407..5c72df89 100644 --- a/src/components/ResultContainer.tsx +++ b/src/components/ResultContainer.tsx @@ -12,15 +12,15 @@ function ResultContainer({ result }: { result: Result[] | null }) { ? result.length === download.length && result.every((r) => download.includes(r.dataset_uuid)) : false; - let numOfMatchedDatasets = 0; - let numOfMatchedSubjects = 0; - if (result) { - result.forEach((item) => { - numOfMatchedDatasets += 1; - numOfMatchedSubjects += item.num_matching_subjects; - }); - } - const summaryStats = `Summary stats: ${numOfMatchedDatasets} datasets, ${numOfMatchedSubjects} subjects`; + let numOfMatchedDatasets = 0; + let numOfMatchedSubjects = 0; + if (result) { + result.forEach((item) => { + numOfMatchedDatasets += 1; + numOfMatchedSubjects += item.num_matching_subjects; + }); + } + const summaryStats = `Summary stats: ${numOfMatchedDatasets} datasets, ${numOfMatchedSubjects} subjects`; /** * Updates the download array. diff --git a/src/main.tsx b/src/main.tsx index 2b094744..8716b75b 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -16,7 +16,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render( {/* CSS injection order for MUI and tailwind: https://mui.com/material-ui/guides/interoperability/#tailwind-css */} - + ); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 6642faf8..60c2473e 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -10,9 +10,7 @@ export const nodesURL: string = baseAPIURL.endsWith('/') : `${baseAPIURL}/nodes/`; export const isFederationAPI: string = - import.meta.env.NB_IS_FEDERATION_API === undefined - ? true - : import.meta.env.NB_IS_FEDERATION_API; + import.meta.env.NB_IS_FEDERATION_API === undefined ? true : import.meta.env.NB_IS_FEDERATION_API; export const sexes: { [key: string]: string } = { male: 'snomed:248153007', diff --git a/vite.config.ts b/vite.config.ts index b4ce9b62..4dc8f87a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,17 +3,17 @@ import { defineConfig, loadEnv } from 'vite'; import react from '@vitejs/plugin-react-swc'; // https://vitejs.dev/config/ -export default defineConfig(({ mode }) =>{ +export default defineConfig(({ mode }) => { const envVars = loadEnv(mode, process.cwd(), ''); if (!envVars.NB_API_QUERY_URL) { throw new Error(`Environment variable NB_API_QUERY_URL is not defined.`); } return { - preview:{ + preview: { port: 5173, }, plugins: [react()], - envPrefix: 'NB_' - } + envPrefix: 'NB_', + }; });