-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JN-477] admin help for export #481
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import React from 'react' | ||
|
||
/** guide to using the participant export/download function */ | ||
export default function ExportHelp() { | ||
return <div> | ||
<h3>Participant List Export Info</h3> | ||
<p>Participant export enables download of tabular files (.tsv or .xlsx) containing all participants | ||
except those who have withdrawn from the study. | ||
One row will be generated per participant.</p> | ||
|
||
<h4>File format</h4> | ||
<div className="panel"> | ||
<ul> | ||
<li> | ||
<b>.xlsx</b> will create an Excel spreadsheet of the participant data. Empty cells will represent | ||
null values. | ||
</li> | ||
<li> | ||
<b>.tsv</b> (tab-delimited values). Will export a tab-delimited file. This may be useful in | ||
environments where Excel is unavailable, or if the | ||
number of columns to be exported exceeds 16K. In order to have data be compliant, double-quotes will | ||
be replaced by single quotes, and any values including | ||
tabs or line breaks will be surrounded in double-quotes. | ||
</li> | ||
</ul> | ||
|
||
|
||
</div> | ||
|
||
<h4>Human readable / Analysis friendly</h4> | ||
<ul> | ||
<li> | ||
<b>Analysis friendly</b> Each picklist answers will be displayed as a stable id, rather than the | ||
displayed text. For multiselects, each answer option will appear in a separate column. For example, the | ||
question "Which symptoms have you had?" | ||
with options "fever", "nausea", and "persisent cough", | ||
will be exported into 3 columns. | ||
<table className="table table-striped"> | ||
<thead> | ||
<tr> | ||
<td>MEDICAL_HISTORY.SYMTPOMS.FEVER</td> | ||
<td>MEDICAL_HISTORY.SYMPTOMS.NAUSEA</td> | ||
<td>MEDICAL_HISTORY.SYMPTOMS.COUGH</td> | ||
</tr> | ||
<tr> | ||
<td>fever</td> | ||
<td>nausea</td> | ||
<td>persistent cough</td> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>0</td> | ||
<td>1</td> | ||
<td>0</td> | ||
</tr> | ||
<tr> | ||
<td>1</td> | ||
<td>1</td> | ||
<td>0</td> | ||
</tr> | ||
<tr> | ||
<td>0</td> | ||
<td>0</td> | ||
<td>0</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
</li> | ||
<li> | ||
<b>Human readable</b> will use display text where possible, and will show multi-select questions as a | ||
single column, with a comma-delimited string of the answers given. For example, the question "Which | ||
symptoms have you had?" | ||
with options "fever", "nausea", and "persisent cough", | ||
will be exported into 1 column. | ||
<table className="table table-striped"> | ||
<thead> | ||
<tr> | ||
<td>MEDICAL_HISTORY.SYMTPOMS</td> | ||
</tr> | ||
<tr> | ||
<td>symptoms</td> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>nausea</td> | ||
</tr> | ||
<tr> | ||
<td>fever, nausea</td> | ||
</tr> | ||
<tr> | ||
<td></td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</li> | ||
</ul> | ||
<h4>Include all completions of an activity</h4> | ||
This option controls how the export will behave if a participant has completed an activity multiple times. | ||
<ul> | ||
<li> | ||
<b>Yes</b> A new set of columns will be added to the export for each time the activity was completed. | ||
These will be | ||
denoted by _2, _3, etc... Columns will appear in order of *recency*. So e.g. MEDICAL_HISTORY.SYMPTOMS | ||
represents the | ||
most recent completion, while MEDICAL_HISTORY_2.SYMPTOMS represents the next-most recent, and so on. | ||
</li> | ||
<li> | ||
<b>No</b> Only the most recent completion for each activity will be included in the export. | ||
</li> | ||
</ul> | ||
</div> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react' | ||
import { Link } from 'react-router-dom' | ||
|
||
/** shows the root help page. No structure yet */ | ||
export default function HelpPage() { | ||
return <div> | ||
<h1 className="h3 mb-3">Juniper help topics</h1> | ||
<div> | ||
<Link to="export">Participant export</Link> | ||
</div> | ||
</div> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from 'react' | ||
import { Route, Routes } from 'react-router-dom' | ||
import ExportHelp from './ExportHelp' | ||
import HelpPage from './HelpPage' | ||
|
||
/** routes across individual help pages -- catches any unmatched routes to the main index */ | ||
export default function HelpRouter() { | ||
return <div className="container p-4"> | ||
<Routes> | ||
<Route path="export" element={<ExportHelp/>}/> | ||
<Route index element={<HelpPage/>}/> | ||
<Route path="*" element={<HelpPage/>}/> | ||
</Routes> | ||
</div> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,9 @@ import React from 'react' | |
|
||
import { setupRouterTest } from 'test-utils/router-testing-utils' | ||
import { mockStudyEnvContext } from 'test-utils/mocking-utils' | ||
import { render, screen } from '@testing-library/react' | ||
import { render, screen, waitFor } from '@testing-library/react' | ||
import ExportDataControl from './ExportDataControl' | ||
import userEvent from '@testing-library/user-event' | ||
|
||
test('renders the file types', async () => { | ||
const { RoutedComponent } = setupRouterTest( | ||
|
@@ -13,3 +14,12 @@ test('renders the file types', async () => { | |
expect(screen.getByText('Tab-delimted (.tsv)')).toBeInTheDocument() | ||
expect(screen.getByText('Excel (.xlsx)')).toBeInTheDocument() | ||
}) | ||
|
||
test('help page loads', async () => { | ||
const { RoutedComponent } = setupRouterTest( | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
<ExportDataControl studyEnvContext={mockStudyEnvContext()} show={true} setShow={() => {}}/>) | ||
render(RoutedComponent) | ||
userEvent.click(screen.getByText('help page')) | ||
waitFor(() => expect(screen.getByText('Participant List Export Info')).toBeInTheDocument()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. I didn't expect to not need any code to recognize the content opened in a new window. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing that the headless browser just ignores the target="_blank" and opens it in the same window |
||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't really necessary to replace double quotes with single quotes. It's unlikely that the meaning of any responses will be different, but I have to confess to being a little uneasy about any modification of responses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're right that they can be escaped, but other applications handling of escaped quotes in csv files varies enough that it was decided for Pepper that this strategy would result in less user issues (and they can always grab the .xlsx format if quote fidelity is important)