diff --git a/Makefile b/Makefile
index 5f33742acf2..8c2c016cb60 100755
--- a/Makefile
+++ b/Makefile
@@ -77,6 +77,9 @@ mri_violations:
issue_tracker:
target=issue_tracker npm run compile
+candidate_list:
+ target=candidate_list npm run compile
+
candidate_parameters:
target=candidate_parameters npm run compile
diff --git a/modules/candidate_list/jsx/candidateListIndex.js b/modules/candidate_list/jsx/candidateListIndex.js
index c11de28810e..d141c0dab62 100644
--- a/modules/candidate_list/jsx/candidateListIndex.js
+++ b/modules/candidate_list/jsx/candidateListIndex.js
@@ -6,6 +6,7 @@ import Loader from 'Loader';
import FilterableDataTable from 'FilterableDataTable';
import Modal from 'Modal';
+import fetchDataStream from 'jslib/fetchDataStream';
import OpenProfileForm from './openProfileForm';
/**
@@ -25,10 +26,11 @@ class CandidateListIndex extends Component {
super(props);
this.state = {
- data: {},
+ data: [],
error: false,
isLoaded: false,
hideFilter: true,
+ fieldOptions: {},
show: {profileForm: false},
};
@@ -63,8 +65,18 @@ class CandidateListIndex extends Component {
* Called by React when the component has been rendered on the page.
*/
componentDidMount() {
- this.fetchData()
- .then(() => this.setState({isLoaded: true}));
+ fetch('options',
+ {credentials: 'same-origin'}).then(
+ (resp) => resp.json()
+ ).then(
+ (json) => {
+ this.setState({
+ fieldOptions: json,
+ });
+ }
+ );
+
+ this.fetchData();
const searchParams = new URLSearchParams(location.search);
if (searchParams.has('hide')) {
@@ -80,23 +92,15 @@ class CandidateListIndex extends Component {
* @return {object}
*/
fetchData() {
- return fetch(this.props.dataURL, {credentials: 'same-origin'})
- .then((resp) => resp.json())
- .then((data) => {
- // Convert concatenated string of cohort and visit labels to array
- data.Data = data.Data.map((row) => {
- // Visit label
- row[2] = (row[2]) ? row[2].split(',') : null;
- // Cohort
- row[4] = (row[4]) ? row[4].split(',') : null;
- return row;
- });
- this.setState({data});
- })
- .catch((error) => {
- this.setState({error: true});
- console.error(error);
- });
+ fetchDataStream(this.props.dataURL,
+ (row) => this.state.data.push(row),
+ (end) => {
+ this.setState({data: this.state.data});
+ },
+ () => {
+ this.setState({isLoaded: true});
+ },
+ );
}
/**
@@ -149,8 +153,7 @@ class CandidateListIndex extends Component {
}
if (column === 'Cohort') {
- // If user has multiple cohorts, join array into string
- let result = (cell) ?
{cell.join(', ')} | : | ;
+ let result = (cell) ? {cell} | : | ;
return result;
}
@@ -178,7 +181,8 @@ class CandidateListIndex extends Component {
* XXX: Currently, the order of these fields MUST match the order of the
* queried columns in _setupVariables() in candidate_list.class.inc
*/
- const options = this.state.data.fieldOptions;
+ // const options = this.state.data.fieldOptions;
+ const options = this.state.fieldOptions;
const fields = [
{
label: 'PSCID',
@@ -371,7 +375,7 @@ class CandidateListIndex extends Component {
{profileForm}
{
document.getElementById('lorisworkspace')
).render(
+ * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
+ * @link https://www.github.com/aces/Loris/
+ */
+class Options extends \LORIS\Http\Endpoint
+{
+ /**
+ * Overloading this method to allow access to site users (their own site only)
+ * and users w/ multisite privs
+ *
+ * @param \User $user The user whose access is being checked
+ *
+ * @return bool true if user has access, false otherwise
+ */
+ function _hasAccess(\User $user) : bool
+ {
+ return (
+ $user->hasPermission('access_all_profiles')
+ || ($user->hasStudySite() && $user->hasPermission('data_entry'))
+
+ );
+ }
+
+ /**
+ * Return the list of field options required to be serialized to JSON
+ * in order to render the frontend.
+ *
+ * @return array
+ */
+ function getFieldOptions() : array
+ {
+ $this->loris->getModule('candidate_parameters')->registerAutoloader();
+
+ // create user object
+ $factory = \NDB_Factory::singleton();
+ $user = $factory->user();
+ $config = $factory->config();
+
+ // get the list of visit labels
+ $visit_label_options = \Utility::getVisitList();
+
+ // get the list of sites available for the user
+ if ($user->hasPermission('access_all_profiles')) {
+ $list_of_sites = \Utility::getSiteList();
+ } else {
+ $list_of_sites = $user->getStudySites();
+ }
+ $site_options = [];
+ foreach (array_values($list_of_sites) as $name) {
+ $site_options[$name] = $name;
+ }
+
+ // get the list of projects
+ $list_of_projects = \Utility::getProjectList();
+ $project_options = [];
+ foreach (array_values($list_of_projects) as $name) {
+ $project_options[$name] = $name;
+ }
+
+ // get the list of cohorts
+ $list_of_cohorts = \Utility::getCohortList();
+ $cohort_options = [];
+ foreach (array_values($list_of_cohorts) as $name) {
+ $cohort_options[$name] = $name;
+ }
+
+ // get the list participant status options
+ $list_of_participant_status
+ = \Candidate::getParticipantStatusOptions();
+ $participant_status_options = [];
+ foreach (array_values($list_of_participant_status) as $name) {
+ $participant_status_options[$name] = $name;
+ }
+
+ return [
+ 'visitlabel' => $visit_label_options,
+ 'site' => $site_options,
+ 'project' => $project_options,
+ 'cohort' => $cohort_options,
+ 'participantstatus' => $participant_status_options,
+ 'useedc' => $config->getSetting("useEDC"),
+ 'Sex' => \Utility::getSexList(),
+ ];
+ }
+
+ /**
+ * An Endpoint acts as middleware which will calculate ETag if applicable.
+ *
+ * @param ServerRequestInterface $request The incoming PSR7 request
+ *
+ * @return ResponseInterface The outgoing PSR7 response
+ */
+ public function handle(
+ ServerRequestInterface $request,
+ ): ResponseInterface {
+ return new \LORIS\Http\Response\JSON\OK($this->getFieldOptions());
+ }
+}
+