diff --git a/docs/assets/tutorials/home-page.png b/docs/assets/tutorials/home-page.png index 254021257..ed34f87ec 100644 Binary files a/docs/assets/tutorials/home-page.png and b/docs/assets/tutorials/home-page.png differ diff --git a/docs/assets/tutorials/multiple/all-interfaces-added.png b/docs/assets/tutorials/multiple/all-interfaces-added.png new file mode 100644 index 000000000..3d6744eb8 Binary files /dev/null and b/docs/assets/tutorials/multiple/all-interfaces-added.png differ diff --git a/docs/assets/tutorials/multiple/conversion-results-page.png b/docs/assets/tutorials/multiple/conversion-results-page.png new file mode 100644 index 000000000..830741e56 Binary files /dev/null and b/docs/assets/tutorials/multiple/conversion-results-page.png differ diff --git a/docs/assets/tutorials/multiple/fail-name.png b/docs/assets/tutorials/multiple/fail-name.png new file mode 100644 index 000000000..d023efd82 Binary files /dev/null and b/docs/assets/tutorials/multiple/fail-name.png differ diff --git a/docs/assets/tutorials/multiple/format-options.png b/docs/assets/tutorials/multiple/format-options.png new file mode 100644 index 000000000..368d9b79a Binary files /dev/null and b/docs/assets/tutorials/multiple/format-options.png differ diff --git a/docs/assets/tutorials/multiple/formats-page.png b/docs/assets/tutorials/multiple/formats-page.png new file mode 100644 index 000000000..60e0b8384 Binary files /dev/null and b/docs/assets/tutorials/multiple/formats-page.png differ diff --git a/docs/assets/tutorials/multiple/home-page-complete.png b/docs/assets/tutorials/multiple/home-page-complete.png new file mode 100644 index 000000000..0e0863058 Binary files /dev/null and b/docs/assets/tutorials/multiple/home-page-complete.png differ diff --git a/docs/assets/tutorials/multiple/info-page.png b/docs/assets/tutorials/multiple/info-page.png new file mode 100644 index 000000000..3ebbb8ff4 Binary files /dev/null and b/docs/assets/tutorials/multiple/info-page.png differ diff --git a/docs/assets/tutorials/multiple/inspect-page.png b/docs/assets/tutorials/multiple/inspect-page.png new file mode 100644 index 000000000..e138d3253 Binary files /dev/null and b/docs/assets/tutorials/multiple/inspect-page.png differ diff --git a/docs/assets/tutorials/multiple/interface-added.png b/docs/assets/tutorials/multiple/interface-added.png new file mode 100644 index 000000000..9ec18acef Binary files /dev/null and b/docs/assets/tutorials/multiple/interface-added.png differ diff --git a/docs/assets/tutorials/multiple/intro-page.png b/docs/assets/tutorials/multiple/intro-page.png new file mode 100644 index 000000000..fe0915b3a Binary files /dev/null and b/docs/assets/tutorials/multiple/intro-page.png differ diff --git a/docs/assets/tutorials/multiple/metadata-ecephys.png b/docs/assets/tutorials/multiple/metadata-ecephys.png new file mode 100644 index 000000000..306aa9a4e Binary files /dev/null and b/docs/assets/tutorials/multiple/metadata-ecephys.png differ diff --git a/docs/assets/tutorials/multiple/metadata-nwbfile.png b/docs/assets/tutorials/multiple/metadata-nwbfile.png new file mode 100644 index 000000000..fd372c22c Binary files /dev/null and b/docs/assets/tutorials/multiple/metadata-nwbfile.png differ diff --git a/docs/assets/tutorials/multiple/metadata-page.png b/docs/assets/tutorials/multiple/metadata-page.png new file mode 100644 index 000000000..b683f68a6 Binary files /dev/null and b/docs/assets/tutorials/multiple/metadata-page.png differ diff --git a/docs/assets/tutorials/multiple/metadata-subject-complete.png b/docs/assets/tutorials/multiple/metadata-subject-complete.png new file mode 100644 index 000000000..075491e6a Binary files /dev/null and b/docs/assets/tutorials/multiple/metadata-subject-complete.png differ diff --git a/docs/assets/tutorials/multiple/pathexpansion-autocomplete-filled.png b/docs/assets/tutorials/multiple/pathexpansion-autocomplete-filled.png new file mode 100644 index 000000000..39802e9d4 Binary files /dev/null and b/docs/assets/tutorials/multiple/pathexpansion-autocomplete-filled.png differ diff --git a/docs/assets/tutorials/multiple/pathexpansion-autocomplete-open.png b/docs/assets/tutorials/multiple/pathexpansion-autocomplete-open.png new file mode 100644 index 000000000..fe62f406d Binary files /dev/null and b/docs/assets/tutorials/multiple/pathexpansion-autocomplete-open.png differ diff --git a/docs/assets/tutorials/multiple/pathexpansion-autocomplete-submitted.png b/docs/assets/tutorials/multiple/pathexpansion-autocomplete-submitted.png new file mode 100644 index 000000000..8eb2f1a1b Binary files /dev/null and b/docs/assets/tutorials/multiple/pathexpansion-autocomplete-submitted.png differ diff --git a/docs/assets/tutorials/multiple/pathexpansion-basepath.png b/docs/assets/tutorials/multiple/pathexpansion-basepath.png new file mode 100644 index 000000000..74d3ea158 Binary files /dev/null and b/docs/assets/tutorials/multiple/pathexpansion-basepath.png differ diff --git a/docs/assets/tutorials/multiple/pathexpansion-completed.png b/docs/assets/tutorials/multiple/pathexpansion-completed.png new file mode 100644 index 000000000..37bfd3a4c Binary files /dev/null and b/docs/assets/tutorials/multiple/pathexpansion-completed.png differ diff --git a/docs/assets/tutorials/multiple/pathexpansion-page.png b/docs/assets/tutorials/multiple/pathexpansion-page.png new file mode 100644 index 000000000..c8834386c Binary files /dev/null and b/docs/assets/tutorials/multiple/pathexpansion-page.png differ diff --git a/docs/assets/tutorials/multiple/preview-page.png b/docs/assets/tutorials/multiple/preview-page.png new file mode 100644 index 000000000..39da26941 Binary files /dev/null and b/docs/assets/tutorials/multiple/preview-page.png differ diff --git a/docs/assets/tutorials/multiple/search-behavior.png b/docs/assets/tutorials/multiple/search-behavior.png new file mode 100644 index 000000000..368d9b79a Binary files /dev/null and b/docs/assets/tutorials/multiple/search-behavior.png differ diff --git a/docs/assets/tutorials/multiple/sourcedata-page.png b/docs/assets/tutorials/multiple/sourcedata-page.png new file mode 100644 index 000000000..7ce301615 Binary files /dev/null and b/docs/assets/tutorials/multiple/sourcedata-page.png differ diff --git a/docs/assets/tutorials/multiple/subject-complete.png b/docs/assets/tutorials/multiple/subject-complete.png new file mode 100644 index 000000000..1d1f77a38 Binary files /dev/null and b/docs/assets/tutorials/multiple/subject-complete.png differ diff --git a/docs/assets/tutorials/multiple/subject-error.png b/docs/assets/tutorials/multiple/subject-error.png new file mode 100644 index 000000000..09d4dae69 Binary files /dev/null and b/docs/assets/tutorials/multiple/subject-error.png differ diff --git a/docs/assets/tutorials/multiple/subject-invalid.png b/docs/assets/tutorials/multiple/subject-invalid.png new file mode 100644 index 000000000..6f9b44747 Binary files /dev/null and b/docs/assets/tutorials/multiple/subject-invalid.png differ diff --git a/docs/assets/tutorials/multiple/subject-page.png b/docs/assets/tutorials/multiple/subject-page.png new file mode 100644 index 000000000..4e9e5148e Binary files /dev/null and b/docs/assets/tutorials/multiple/subject-page.png differ diff --git a/docs/assets/tutorials/multiple/valid-name.png b/docs/assets/tutorials/multiple/valid-name.png new file mode 100644 index 000000000..6f87a3f2c Binary files /dev/null and b/docs/assets/tutorials/multiple/valid-name.png differ diff --git a/docs/assets/tutorials/multiple/workflow-page.png b/docs/assets/tutorials/multiple/workflow-page.png new file mode 100644 index 000000000..f36a8999a Binary files /dev/null and b/docs/assets/tutorials/multiple/workflow-page.png differ diff --git a/docs/assets/tutorials/single/all-interfaces-added.png b/docs/assets/tutorials/single/all-interfaces-added.png index 6ef05b8d5..bfff82e32 100644 Binary files a/docs/assets/tutorials/single/all-interfaces-added.png and b/docs/assets/tutorials/single/all-interfaces-added.png differ diff --git a/docs/assets/tutorials/single/conversion-results-page.png b/docs/assets/tutorials/single/conversion-results-page.png index 9e04440fa..b2d5d9e6b 100644 Binary files a/docs/assets/tutorials/single/conversion-results-page.png and b/docs/assets/tutorials/single/conversion-results-page.png differ diff --git a/docs/assets/tutorials/single/fail-name.png b/docs/assets/tutorials/single/fail-name.png index af8d0fc2a..d023efd82 100644 Binary files a/docs/assets/tutorials/single/fail-name.png and b/docs/assets/tutorials/single/fail-name.png differ diff --git a/docs/assets/tutorials/single/format-options.png b/docs/assets/tutorials/single/format-options.png index 2b466bbf5..3422f3fcb 100644 Binary files a/docs/assets/tutorials/single/format-options.png and b/docs/assets/tutorials/single/format-options.png differ diff --git a/docs/assets/tutorials/single/formats-page.png b/docs/assets/tutorials/single/formats-page.png index e8a463813..838fbece2 100644 Binary files a/docs/assets/tutorials/single/formats-page.png and b/docs/assets/tutorials/single/formats-page.png differ diff --git a/docs/assets/tutorials/single/home-page-complete.png b/docs/assets/tutorials/single/home-page-complete.png index b804f49e1..b3faca29b 100644 Binary files a/docs/assets/tutorials/single/home-page-complete.png and b/docs/assets/tutorials/single/home-page-complete.png differ diff --git a/docs/assets/tutorials/single/info-page.png b/docs/assets/tutorials/single/info-page.png index 90a466f7e..3ebbb8ff4 100644 Binary files a/docs/assets/tutorials/single/info-page.png and b/docs/assets/tutorials/single/info-page.png differ diff --git a/docs/assets/tutorials/single/inspect-page.png b/docs/assets/tutorials/single/inspect-page.png index fa912aa80..3df51d605 100644 Binary files a/docs/assets/tutorials/single/inspect-page.png and b/docs/assets/tutorials/single/inspect-page.png differ diff --git a/docs/assets/tutorials/single/interface-added.png b/docs/assets/tutorials/single/interface-added.png index 6988b5858..3c07045c7 100644 Binary files a/docs/assets/tutorials/single/interface-added.png and b/docs/assets/tutorials/single/interface-added.png differ diff --git a/docs/assets/tutorials/single/intro-page.png b/docs/assets/tutorials/single/intro-page.png index cf87fbbbe..fe0915b3a 100644 Binary files a/docs/assets/tutorials/single/intro-page.png and b/docs/assets/tutorials/single/intro-page.png differ diff --git a/docs/assets/tutorials/single/metadata-ecephys.png b/docs/assets/tutorials/single/metadata-ecephys.png index 7700d0c1b..5f2420d00 100644 Binary files a/docs/assets/tutorials/single/metadata-ecephys.png and b/docs/assets/tutorials/single/metadata-ecephys.png differ diff --git a/docs/assets/tutorials/single/metadata-nwbfile.png b/docs/assets/tutorials/single/metadata-nwbfile.png index ff4178a39..b4779516b 100644 Binary files a/docs/assets/tutorials/single/metadata-nwbfile.png and b/docs/assets/tutorials/single/metadata-nwbfile.png differ diff --git a/docs/assets/tutorials/single/metadata-page.png b/docs/assets/tutorials/single/metadata-page.png index e422b1e7c..a76f431df 100644 Binary files a/docs/assets/tutorials/single/metadata-page.png and b/docs/assets/tutorials/single/metadata-page.png differ diff --git a/docs/assets/tutorials/single/metadata-subject-complete.png b/docs/assets/tutorials/single/metadata-subject-complete.png index 82e59f8fa..3d4d04582 100644 Binary files a/docs/assets/tutorials/single/metadata-subject-complete.png and b/docs/assets/tutorials/single/metadata-subject-complete.png differ diff --git a/docs/assets/tutorials/single/preview-page.png b/docs/assets/tutorials/single/preview-page.png index 45b0b9900..a000c2a05 100644 Binary files a/docs/assets/tutorials/single/preview-page.png and b/docs/assets/tutorials/single/preview-page.png differ diff --git a/docs/assets/tutorials/single/search-behavior.png b/docs/assets/tutorials/single/search-behavior.png index 41dac8ba6..52b484ac4 100644 Binary files a/docs/assets/tutorials/single/search-behavior.png and b/docs/assets/tutorials/single/search-behavior.png differ diff --git a/docs/assets/tutorials/single/sourcedata-page-specified.png b/docs/assets/tutorials/single/sourcedata-page-specified.png index d9e1b6317..59f9542d0 100644 Binary files a/docs/assets/tutorials/single/sourcedata-page-specified.png and b/docs/assets/tutorials/single/sourcedata-page-specified.png differ diff --git a/docs/assets/tutorials/single/sourcedata-page.png b/docs/assets/tutorials/single/sourcedata-page.png index fbd840b64..331f41a1c 100644 Binary files a/docs/assets/tutorials/single/sourcedata-page.png and b/docs/assets/tutorials/single/sourcedata-page.png differ diff --git a/docs/assets/tutorials/single/valid-name.png b/docs/assets/tutorials/single/valid-name.png index 30974a351..624ece232 100644 Binary files a/docs/assets/tutorials/single/valid-name.png and b/docs/assets/tutorials/single/valid-name.png differ diff --git a/docs/assets/tutorials/single/workflow-page.png b/docs/assets/tutorials/single/workflow-page.png index 36e93d0dc..9bcbc49b8 100644 Binary files a/docs/assets/tutorials/single/workflow-page.png and b/docs/assets/tutorials/single/workflow-page.png differ diff --git a/docs/conf_extlinks.py b/docs/conf_extlinks.py index 6aa93b9d5..89228803d 100644 --- a/docs/conf_extlinks.py +++ b/docs/conf_extlinks.py @@ -5,6 +5,7 @@ "pynwb-docs": ("https://pynwb.readthedocs.io/en/stable/%s", "%s"), "matnwb-src": ("https://github.com/NeurodataWithoutBorders/matnwb/%s", "%s"), "nwb-overview": ("https://nwb-overview.readthedocs.io/en/latest/%s", "%s"), + "path-expansion-guide": ("https://neuroconv.readthedocs.io/en/main/user_guide/expand_path.html%s", "%s"), "conda-install": ( "https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html#regular-installation%s", "%s", diff --git a/docs/tutorials/multiple_sessions.rst b/docs/tutorials/multiple_sessions.rst index 6a446d3eb..cdf528a3e 100644 --- a/docs/tutorials/multiple_sessions.rst +++ b/docs/tutorials/multiple_sessions.rst @@ -1,3 +1,125 @@ Managing Multiple Sessions ========================== -Coming soon... + +Now, let’s say that you’ve already run some of your experiments and now you want to convert them all at the same time. This is where a multi-session workflow will come in handy. + +Workflow Configuration +---------------------- + +On the Workflow page, confirm that this pipeline will be run on multiple sessions. After this, also select that you’d like to locate the source data programmatically and skip dataset publication. + +.. figure:: ../assets/tutorials/multiple/workflow-page.png + :align: center + :alt: Workflow page with multiple sessions and locate data selected + +Complete the first section of the GUIDE as normal until you reach a new **Locate Data** page after the Data Formats page. + +Locate Data +----------- +This page helps you automatically identify source data for multiple subjects / sessions as long as your files are organized consistently. + +.. figure:: ../assets/tutorials/multiple/pathexpansion-page.png + :align: center + :alt: Blank path expansion page + +File locations are specified as **format strings** that define source data paths of each selected data format. + +.. note:: + Format strings are one component of NeuroConv's **path expansion language**, which has some nifty features for manually specifying complex paths. Complete documentation of the path expansion feature of NeuroConv can be found :path-expansion-guide:`here <>` . + +While you don’t have to specify format strings for all of the pipeline’s data formats, we’re going to find all of our data here for this tutorial. You'll always be able to confirm or manually select the final paths on the Source Data page later in the workflow. + +Format strings are specified using two components: the **base directory**, which is the directory to search in, and the **format string path**, where the source data is within that directory. + +Given the structure of the tutorial dataset, we’ll select ``~/NWB_GUIDE/test-data/dataset`` as the **base directory**, where **~** is the home directory of your system. + +We can take advantage of the **Autocomplete** feature of this page. Instead of manually filling out the format string, click the **Autocomplete** button to open a pop-up form that will derive the format string from a single example path. + +.. figure:: ../assets/tutorials/multiple/pathexpansion-autocomplete-open.png + :align: center + :alt: Autocomplete modal on path expansion page + +Provide an example source data path (for example, the ``mouse1_Session1_g0_t0.imec0.lf.bin`` file for SpikeGLX), followed by the Subject (``mouse1``) and Session ID (``Session1``) for this particular path. + +.. figure:: ../assets/tutorials/multiple/pathexpansion-autocomplete-filled.png + :align: center + :alt: Autocomplete modal completed + +When you submit this form, you’ll notice that the Format String Path input has been auto-filled with a pattern for all the sessions. + +.. figure:: ../assets/tutorials/multiple/pathexpansion-autocomplete-submitted.png + :align: center + :alt: Path expansion page with autocompleted format string + +Repeat this process for Phy, where ``mouse1_Session2_phy`` will be the example source data path. + +.. figure:: ../assets/tutorials/multiple/pathexpansion-completed.png + :align: center + :alt: Completed path expansion information + +Advance to the next page when you have entered the data locations for both formats. + +Subject Metadata +---------------- +On this page you’ll edit subject-level metadata across all related sessions. Unlike the previous few pages, you’ll notice that +Sex and Species both have gray asterisks next to their name; this means they are **loose requirements**, which aren’t currently required +but could later block progress if left unspecified. + +.. figure:: ../assets/tutorials/multiple/subject-page.png + :align: center + :alt: Blank subject table + +In this case, we have two subjects with two sessions each. Let’s say that each of their sessions happened close enough in time that they can be identified using the same **age** entry: ``P29W`` for ``mouse1`` and ``P30W`` for ``mouse2``. + +We should also indicate the ``sex`` of each subject since this is a requirement for `uploading to the DANDI Archive `_. + +.. figure:: ../assets/tutorials/multiple/subject-complete.png + :align: center + :alt: Complete subject table + +.. note:: + If you're trying to specify metadata that is shared across sessions, you can use the **Global Metadata** feature. + + Pressing the Edit Global Metadata button at the top of the page will show a pop-up form which allows you to provide a + single default value for each property, as long as it’s expected not to be unique. + + These values will take effect as soon as the pop-up form has been submitted. + + While Global Metadata is less relevant when we’re working with two subjeccts, this feature can be very powerful when you’re working with tens or even hundreds of subjects in one conversion. + + We recommend using Global Metadata to correct issues caught by the **NWB Inspector** that are seen across several sessions. + + You’ll be able to specify Global Metadata on the Source Data and File Metadata pages as well. + + +Source Data Information +----------------------- +Because we used the Locate Data page to programmatically identify our source data, this page should mostly be complete. You can use this opportunity to verify that the identified paths appear as expected for each session. + +.. figure:: ../assets/tutorials/multiple/sourcedata-page.png + :align: center + :alt: Complete source data forms + +One notable difference between this and the single-session workflow, however, is that the next few pages will allow you to toggle between sessions using the **session manager** sidebar on the left. + +Session Metadata +---------------- +Aside from the session manager and global metadata features noted above, the file metadata page in the multi-session workflow is nearly identical to the single-session version. + +.. figure:: ../assets/tutorials/multiple/metadata-nwbfile.png + :align: center + :alt: Complete General Metadata form + + A complete General Metadata form + +Acting as global metadata, the information supplied on the subject metadata page has pre-filled the Subject metadata for each session. + +.. figure:: ../assets/tutorials/multiple/metadata-subject-complete.png + :align: center + :alt: Complete Subject metadata form + + A complete Subject metadata form + +Finish the rest of the workflow as you would for a single session by completing a full conversion after you review the preview files with the NWB Inspector and Neurosift. + +Congratulations on completing your first multi-session conversion! You can now convert multiple sessions at once, saving you time and effort. diff --git a/docs/tutorials/single_session.rst b/docs/tutorials/single_session.rst index 6eabe32d9..727a7e088 100644 --- a/docs/tutorials/single_session.rst +++ b/docs/tutorials/single_session.rst @@ -98,18 +98,18 @@ Session Metadata ^^^^^^^^^^^^^^^^ The file metadata page is a great opportunity to add rich annotations to the file, which will be read by anyone reusing your data in the future! -The Session Start Time in the General Metadata section is already specified because this field was automatically extracted from the SpikeGLX source data. +The Session Start Time in the **General Metadata** section is already specified because this field was automatically extracted from the SpikeGLX source data. .. figure:: ../assets/tutorials/single/metadata-nwbfile.png :align: center :alt: Metadata page with invalid Subject information -However, we still need to add the Subject information—as noted by the red accents around that item. Let’s say that our subject is a male mouse with an age of P30D, which represents 30 days old. +However, we still need to add the Subject information—as noted by the red accents around that item. Let’s say that our subject is a male mouse with an age of P25W, which represents 25 weeks old. .. figure:: ../assets/tutorials/single/metadata-subject-complete.png :align: center - :alt: Metadata page with valid Subject information + :alt: Metadata page with valid **Subject** information The status of the Subject information will update in real-time as you fill out the form. diff --git a/src/renderer/src/stories/Main.js b/src/renderer/src/stories/Main.js index 03ee981f2..172c036b8 100644 --- a/src/renderer/src/stories/Main.js +++ b/src/renderer/src/stories/Main.js @@ -190,10 +190,12 @@ export class Main extends LitElement { } const headerEl = header ? (this.header = new GuidedHeader(header)) : html`
`; // Render for grid + if (!header) delete this.header; // Reset header if (!header) delete this.header; // Reset header const footerEl = footer ? (this.footer = new GuidedFooter(footer)) : html`
`; // Render for grid + if (!footer) delete this.footer; // Reset footer const title = header?.title ?? page.info?.title; diff --git a/src/renderer/src/stories/pages/guided-mode/GuidedFooter.js b/src/renderer/src/stories/pages/guided-mode/GuidedFooter.js index 232513e02..25c245ac5 100644 --- a/src/renderer/src/stories/pages/guided-mode/GuidedFooter.js +++ b/src/renderer/src/stories/pages/guided-mode/GuidedFooter.js @@ -48,7 +48,7 @@ export class GuidedFooter extends LitElement { } updated() { - this.to = (transition) => this.parentElement.to(transition); + this.to = (transition) => this.parentElement.to(transition); // Run main page's transition function } render() { diff --git a/tests/e2e/config.ts b/tests/e2e/config.ts index f7a510e62..86d1cb00b 100644 --- a/tests/e2e/config.ts +++ b/tests/e2e/config.ts @@ -35,6 +35,13 @@ export const alwaysDelete = [ // ------------------------ Configuration Options ------------------------ // ----------------------------------------------------------------------- +const autocompleteOptions = { + subject_id: 'mouse1', + session_id: 'Session1' +} + +const { subject_id, session_id } = autocompleteOptions + export const testInterfaceInfo = { common: { SpikeGLXRecordingInterface: { @@ -46,10 +53,12 @@ export const testInterfaceInfo = { }, multi: { SpikeGLXRecordingInterface: { - format: '{subject_id}/{subject_id}_{session_id}/{subject_id}_{session_id}_g0/{subject_id}_{session_id}_g0_imec0/{subject_id}_{session_id}_g0_t0.imec0.ap.bin' + format: '{subject_id}/{subject_id}_{session_id}/{subject_id}_{session_id}_g0/{subject_id}_{session_id}_g0_imec0/{subject_id}_{session_id}_g0_t0.imec0.ap.bin', + autocomplete: {} }, PhySortingInterface: { - format: '{subject_id}/{subject_id}_{session_id}/{subject_id}_{session_id}_phy' + format: '{subject_id}/{subject_id}_{session_id}/{subject_id}_{session_id}_phy', + autocomplete: {} } }, single: { @@ -62,14 +71,39 @@ export const testInterfaceInfo = { } } +// Add autocomplete options +Object.entries(testInterfaceInfo.multi).forEach(([key, value]) => { + const format = value.format + value.autocomplete = { + path: join(testDatasetPath, format.replace(/{subject_id}/g, subject_id).replace(/{session_id}/g, session_id)), + ...autocompleteOptions, + } +}) + + export const subjectInfo = { - sex: 'M', - species: 'Mus musculus', - age: 'P30D' + common: { + sex: 'M', + species: 'Mus musculus', + }, + + single: { + age: 'P25W' + }, + + multiple: { + mouse1: { + age: 'P29W', + sex: 'F' + }, + mouse2: { + age: 'P30W' + } + } } -// export const regenerateTestData = !existsSync(testDataRootPath) || false // Generate only if doesn't exist -export const regenerateTestData = true // Force regeneration +export const regenerateTestData = !existsSync(testDataRootPath) || false // Generate only if doesn't exist +// export const regenerateTestData = true // Force regeneration export const dandiInfo = { id: '212750', diff --git a/tests/e2e/e2e.test.ts b/tests/e2e/e2e.test.ts index 27f43d4e5..dc8f40327 100644 --- a/tests/e2e/e2e.test.ts +++ b/tests/e2e/e2e.test.ts @@ -98,7 +98,7 @@ describe('E2E Test', () => { }) }) - describe.skip('Complete a multi-session workflow', async () => { + describe('Complete a multi-session workflow', async () => { const subdirectory = 'multiple' await runWorkflow('Multi Session Workflow', { upload_to_dandi: false, multiple_sessions: true, locate_data: true }, subdirectory) diff --git a/tests/e2e/workflow.ts b/tests/e2e/workflow.ts index fc0f84381..29e2ef3ed 100644 --- a/tests/e2e/workflow.ts +++ b/tests/e2e/workflow.ts @@ -17,7 +17,7 @@ export default async function runWorkflow (name, workflow, identifier) { // Advance to instructions page await toNextPage('start') - await takeScreenshot(join(identifier, 'intro-page'), 300) + await takeScreenshot(join(identifier, 'intro-page'), 500) // Advance to general information page await toNextPage('details') @@ -124,29 +124,77 @@ export default async function runWorkflow (name, workflow, identifier) { await takeScreenshot(join(identifier, 'pathexpansion-page')) - // Fill out the path expansion information - await evaluate(({ multi, common }, basePath) => { + // Provide base path for all interfaces + await evaluate(({ common }, basePath) => { const dashboard = document.querySelector('nwb-dashboard') const form = dashboard.page.form Object.entries(common).forEach(([ name, info ]) => { - const id = info.id const baseInput = form.getFormElement([id, 'base_directory']) baseInput.updateData(basePath) + }) - const { format } = multi[name] + dashboard.main.querySelector('main > section').scrollTop = 200 // Scroll down to see all interfaces + + }, + testInterfaceInfo, + testDatasetPath + ) + + await takeScreenshot(join(identifier, 'pathexpansion-basepath'), 300) + + const name = Object.keys(testInterfaceInfo.common)[0] + const interfaceId = testInterfaceInfo.common[name].id + const autocompleteInfo = testInterfaceInfo.multi[name].autocomplete + + await evaluate(id => { + const dashboard = document.querySelector('nwb-dashboard') + const form = dashboard.page.form + const formatInput = form.getFormElement([id, 'format_string_path']) + const autocompleteButton = formatInput.controls[0] + autocompleteButton.onClick() + }, interfaceId) + + await takeScreenshot(join(identifier, 'pathexpansion-autocomplete-open'), 300) + + await evaluate(info => { + const modal = document.querySelector('nwb-modal') as any + const form = modal.querySelector('nwb-jsonschema-form') + + Object.entries(info).forEach(([key, value]) => { + const formatInput = form.getFormElement([ key ]) + formatInput.updateData(value) + }) + + }, autocompleteInfo) + + await takeScreenshot(join(identifier, 'pathexpansion-autocomplete-filled'), 300) + + // Submit the autocomplete information + await evaluate(() => { + const modal = document.querySelector('nwb-modal') as any + modal.footer.onClick() + }, autocompleteInfo) + + await takeScreenshot(join(identifier, 'pathexpansion-autocomplete-submitted'), 1000) + + // Fill out the other path expansion information + await evaluate(({ multi, common }) => { + const dashboard = document.querySelector('nwb-dashboard') + const form = dashboard.page.form + // Fill out the path expansion information for non-autocompleted interfaces + Object.entries(common).slice(1).forEach(([ name, info ]) => { + const id = info.id + const { format } = multi[name] const formatInput = form.getFormElement([id, 'format_string_path']) formatInput.updateData(format) }) dashboard.main.querySelector('main > section').scrollTop = 200 - }, - testInterfaceInfo, - testDatasetPath - ) + }, testInterfaceInfo) await takeScreenshot(join(identifier, 'pathexpansion-completed'), 300) @@ -179,7 +227,7 @@ export default async function runWorkflow (name, workflow, identifier) { await takeScreenshot(join(identifier, 'subject-error'), 500) - await evaluate(( subjectInfo ) => { + await evaluate(( { common, multiple } ) => { const dashboard = document.querySelector('nwb-dashboard') const page = dashboard.page @@ -191,6 +239,7 @@ export default async function runWorkflow (name, workflow, identifier) { for (let name in data) { + const subjectInfo = { ...common, ...( multiple[name] ?? {} )} data[name] = { ...data[name], ...subjectInfo } } @@ -276,12 +325,14 @@ export default async function runWorkflow (name, workflow, identifier) { if (!willProvideSubjectInfo) { // Update for single session - await evaluate((subjectInfo) => { + await evaluate(({ common, single = {} }) => { const dashboard = document.querySelector('nwb-dashboard') const page = dashboard.page const firstSessionForm = page.forms[0].form const form = firstSessionForm.forms['Subject'] + const subjectInfo = { ...common, ...single } + for (let key in subjectInfo) { const input = form.getFormElement([key]) input.updateData(subjectInfo[key]) @@ -309,7 +360,7 @@ export default async function runWorkflow (name, workflow, identifier) { test('Review NWB Inspector output', async () => { - await takeScreenshot(join(identifier, 'inspect-page'), 2000) // Finish file inspection + await takeScreenshot(join(identifier, 'inspect-page'), 5000) // Finish file inspection and allow full load of Neurosift page await toNextPage('preview') })