diff --git a/rdmo/projects/assets/js/interview/actions/interviewActions.js b/rdmo/projects/assets/js/interview/actions/interviewActions.js
index cb3c3851c9..bc93cfe3ad 100644
--- a/rdmo/projects/assets/js/interview/actions/interviewActions.js
+++ b/rdmo/projects/assets/js/interview/actions/interviewActions.js
@@ -18,12 +18,8 @@ import {
NOOP,
FETCH_NAVIGATION_ERROR,
FETCH_NAVIGATION_SUCCESS,
- FETCH_OVERVIEW_ERROR,
- FETCH_OVERVIEW_SUCCESS,
FETCH_PAGE_ERROR,
FETCH_PAGE_SUCCESS,
- FETCH_PROGRESS_ERROR,
- FETCH_PROGRESS_SUCCESS,
FETCH_VALUES_SUCCESS,
FETCH_VALUES_ERROR,
CREATE_VALUE,
@@ -38,73 +34,47 @@ import {
import { updateConfig } from 'rdmo/core/assets/js/actions/configActions'
-export function fetchOverview() {
- return (dispatch) => ProjectApi.fetchOverview(projectId)
- .then((overview) => dispatch(fetchOverviewSuccess(overview)))
- .catch((errors) => dispatch(fetchOverviewError(errors)))
-}
-
-export function fetchOverviewSuccess(overview) {
- return {type: FETCH_OVERVIEW_SUCCESS, overview}
-}
-
-export function fetchOverviewError(errors) {
- return {type: FETCH_OVERVIEW_ERROR, errors}
-}
-
-export function fetchProgress() {
- return (dispatch) => ProjectApi.fetchProgress(projectId)
- .then((progress) => dispatch(fetchProgressSuccess(progress)))
- .catch((errors) => dispatch(fetchProgressError(errors)))
-}
-
-export function fetchProgressSuccess(progress) {
- return {type: FETCH_PROGRESS_SUCCESS, progress}
-}
-
-export function fetchProgressError(errors) {
- return {type: FETCH_PROGRESS_ERROR, errors}
-}
-
-export function fetchNavigation(sectionId) {
- return (dispatch) => ProjectApi.fetchNavigation(projectId, sectionId)
- .then((navigation) => dispatch(fetchNavigationSuccess(navigation)))
- .catch((errors) => dispatch(fetchNavigationError(errors)))
-}
-
-export function fetchNavigationSuccess(navigation) {
- return {type: FETCH_NAVIGATION_SUCCESS, navigation}
-}
-
-export function fetchNavigationError(errors) {
- return {type: FETCH_NAVIGATION_ERROR, errors}
-}
-
export function fetchPage(pageId) {
return (dispatch) => {
const promise = isNil(pageId) ? PageApi.fetchContinue(projectId)
: PageApi.fetchPage(projectId, pageId)
return promise.then((page) => {
updateLocation(page.id)
- dispatch(fetchNavigation(page.section.id))
+ initPage(page)
+ dispatch(fetchNavigation(page))
+ dispatch(fetchValues(page))
dispatch(fetchPageSuccess(page))
- dispatch(fetchValues())
})
}
}
export function fetchPageSuccess(page) {
- return {type: FETCH_PAGE_SUCCESS, page: initPage(page)}
+ return {type: FETCH_PAGE_SUCCESS, page}
}
export function fetchPageError(errors) {
return {type: FETCH_PAGE_ERROR, errors}
}
-export function fetchValues() {
- return (dispatch, getStore) => {
- const page = getStore().interview.page
+export function fetchNavigation(page) {
+ return (dispatch) => {
+ return ProjectApi.fetchNavigation(projectId, page.section.id)
+ .then((navigation) => dispatch(fetchNavigationSuccess(navigation)))
+ .catch((errors) => dispatch(fetchNavigationError(errors)))
+
+ }
+}
+export function fetchNavigationSuccess(navigation) {
+ return {type: FETCH_NAVIGATION_SUCCESS, navigation}
+}
+
+export function fetchNavigationError(errors) {
+ return {type: FETCH_NAVIGATION_ERROR, errors}
+}
+
+export function fetchValues(page) {
+ return (dispatch) => {
return ValueApi.fetchValues(projectId, { attribute: page.attributes })
.then((values) => dispatch(fetchValuesSuccess(values, page)))
.catch((errors) => dispatch(fetchValuesError(errors)))
diff --git a/rdmo/projects/assets/js/interview/actions/projectActions.js b/rdmo/projects/assets/js/interview/actions/projectActions.js
new file mode 100644
index 0000000000..bc011549cd
--- /dev/null
+++ b/rdmo/projects/assets/js/interview/actions/projectActions.js
@@ -0,0 +1,38 @@
+import ProjectApi from '../api/ProjectApi'
+
+import projectId from '../utils/projectId'
+
+import {
+ FETCH_OVERVIEW_ERROR,
+ FETCH_OVERVIEW_SUCCESS,
+ FETCH_PROGRESS_ERROR,
+ FETCH_PROGRESS_SUCCESS,
+} from './actionTypes'
+
+export function fetchOverview() {
+ return (dispatch) => ProjectApi.fetchOverview(projectId)
+ .then((overview) => dispatch(fetchOverviewSuccess(overview)))
+ .catch((errors) => dispatch(fetchOverviewError(errors)))
+}
+
+export function fetchOverviewSuccess(overview) {
+ return {type: FETCH_OVERVIEW_SUCCESS, overview}
+}
+
+export function fetchOverviewError(errors) {
+ return {type: FETCH_OVERVIEW_ERROR, errors}
+}
+
+export function fetchProgress() {
+ return (dispatch) => ProjectApi.fetchProgress(projectId)
+ .then((progress) => dispatch(fetchProgressSuccess(progress)))
+ .catch((errors) => dispatch(fetchProgressError(errors)))
+}
+
+export function fetchProgressSuccess(progress) {
+ return {type: FETCH_PROGRESS_SUCCESS, progress}
+}
+
+export function fetchProgressError(errors) {
+ return {type: FETCH_PROGRESS_ERROR, errors}
+}
diff --git a/rdmo/projects/assets/js/interview/components/main/Breadcrump.js b/rdmo/projects/assets/js/interview/components/main/Breadcrump.js
index 2db7a2cd17..2ba76ab429 100644
--- a/rdmo/projects/assets/js/interview/components/main/Breadcrump.js
+++ b/rdmo/projects/assets/js/interview/components/main/Breadcrump.js
@@ -3,11 +3,11 @@ import PropTypes from 'prop-types'
import baseUrl from 'rdmo/core/assets/js/utils/baseUrl'
-const Breadcrump = ({ overview, currentPage, fetchPage }) => {
+const Breadcrump = ({ overview, page, fetchPage }) => {
const handleClick = (event) => {
event.preventDefault()
- fetchPage(currentPage.section.first)
+ fetchPage(page.section.first)
}
return (
@@ -23,8 +23,8 @@ const Breadcrump = ({ overview, currentPage, fetchPage }) => {
-
- {currentPage.section.title}
+
+ {page.section.title}
@@ -33,7 +33,7 @@ const Breadcrump = ({ overview, currentPage, fetchPage }) => {
Breadcrump.propTypes = {
overview: PropTypes.object.isRequired,
- currentPage: PropTypes.object.isRequired,
+ page: PropTypes.object.isRequired,
fetchPage: PropTypes.func.isRequired
}
diff --git a/rdmo/projects/assets/js/interview/components/main/page/Page.js b/rdmo/projects/assets/js/interview/components/main/page/Page.js
index 2cd32b2be3..75c2f04fa3 100644
--- a/rdmo/projects/assets/js/interview/components/main/page/Page.js
+++ b/rdmo/projects/assets/js/interview/components/main/page/Page.js
@@ -10,7 +10,7 @@ import PageButtons from './PageButtons'
import PageHead from './PageHead'
import PageHelp from './PageHelp'
-const Page = ({ config, templates, page, sets, values, fetchPage,
+const Page = ({ config, templates, project, page, sets, values, fetchPage,
createValue, updateValue, deleteValue,
activateSet, createSet, updateSet, deleteSet }) => {
@@ -50,6 +50,7 @@ const Page = ({ config, templates, page, sets, values, fetchPage,
questionset={element}
sets={sets}
values={values.filter((value) => element.attributes.includes(value.attribute))}
+ disabled={project.overview.read_only}
focus={elementIndex == 0}
parentSet={currentSet}
createSet={createSet}
@@ -71,6 +72,7 @@ const Page = ({ config, templates, page, sets, values, fetchPage,
value.set_prefix == currentSetPrefix &&
value.set_index == currentSetIndex
))}
+ disabled={project.overview.read_only}
focus={elementIndex == 0}
currentSet={currentSet}
createValue={createValue}
@@ -92,6 +94,7 @@ const Page = ({ config, templates, page, sets, values, fetchPage,
Page.propTypes = {
config: PropTypes.object.isRequired,
templates: PropTypes.object.isRequired,
+ project: PropTypes.object.isRequired,
page: PropTypes.object.isRequired,
sets: PropTypes.array.isRequired,
values: PropTypes.array.isRequired,
diff --git a/rdmo/projects/assets/js/interview/components/main/question/Question.js b/rdmo/projects/assets/js/interview/components/main/question/Question.js
index dc3572a431..ae8c94a6b2 100644
--- a/rdmo/projects/assets/js/interview/components/main/question/Question.js
+++ b/rdmo/projects/assets/js/interview/components/main/question/Question.js
@@ -9,7 +9,7 @@ import QuestionText from './QuestionText'
import QuestionWidget from './QuestionWidget'
import QuestionOptional from './QuestionOptional'
-const Question = ({ templates, question, values, focus, currentSet, createValue, updateValue, deleteValue }) => {
+const Question = ({ templates, question, values, disabled, focus, currentSet, createValue, updateValue, deleteValue }) => {
return (
{
@@ -33,6 +33,7 @@ const Question = ({ templates, question, values, focus, currentSet, createValue,
{
+const AddValue = ({ question, values, currentSet, disabled, createValue }) => {
const handleClick = () => {
const lastValue = maxBy(values, (v) => v.collection_index)
const collectionIndex = lastValue ? lastValue.collection_index + 1 : 0
@@ -15,7 +15,7 @@ const AddValue = ({ question, values, currentSet, createValue }) => {
})
}
- return (
+ return !disabled && question.is_collection && (
@@ -26,6 +26,7 @@ AddValue.propTypes = {
question: PropTypes.object.isRequired,
values: PropTypes.array.isRequired,
currentSet: PropTypes.object.isRequired,
+ disabled: PropTypes.bool.isRequired,
createValue: PropTypes.func.isRequired
}
diff --git a/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js b/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js
index 8d70ac94aa..30632f2e28 100644
--- a/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js
+++ b/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js
@@ -1,11 +1,16 @@
import React from 'react'
+import PropTypes from 'prop-types'
-const QuestionDefault = () => {
- return (
+const QuestionDefault = ({ isDefault }) => {
+ return isDefault && (
{gettext('Default')}
)
}
+QuestionDefault.propTypes = {
+ isDefault: PropTypes.bool.isRequired
+}
+
export default QuestionDefault
diff --git a/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js b/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js
index 7648af5bc3..720e30d8ec 100644
--- a/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js
+++ b/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js
@@ -1,12 +1,12 @@
import React from 'react'
import PropTypes from 'prop-types'
-const QuestionEraseValue = ({ value, updateValue }) => {
+const QuestionEraseValue = ({ value, disabled, updateValue }) => {
const handleEraseValue = () => {
updateValue(value, {})
}
- return (
+ return !disabled && (
)
}
diff --git a/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js b/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js
index c31536368a..df94fa0fc8 100644
--- a/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js
+++ b/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js
@@ -11,7 +11,8 @@ import QuestionSetHelp from './QuestionSetHelp'
import QuestionSetAddSet from './QuestionSetAddSet'
import QuestionSetRemoveSet from './QuestionSetRemoveSet'
-const QuestionSet = ({ templates, questionset, sets, values, focus, parentSet, createSet, updateSet, deleteSet,
+const QuestionSet = ({ templates, questionset, sets, values, disabled, focus,
+ parentSet, createSet, updateSet, deleteSet,
createValue, updateValue, deleteValue }) => {
const setPrefix = getChildPrefix(parentSet)
@@ -52,6 +53,7 @@ const QuestionSet = ({ templates, questionset, sets, values, focus, parentSet, c
questionset={element}
sets={sets}
values={values.filter((value) => element.attributes.includes(value.attribute))}
+ disabled={disabled}
focus={focus && (setIndex === 0 && elementIndex === 0)}
parentSet={set}
createSet={createSet}
@@ -73,6 +75,7 @@ const QuestionSet = ({ templates, questionset, sets, values, focus, parentSet, c
value.set_prefix == set.set_prefix &&
value.set_index == set.set_index
))}
+ disabled={disabled}
focus={focus && (setIndex === 0 && elementIndex === 0)}
currentSet={set}
createValue={createValue}
@@ -103,6 +106,7 @@ QuestionSet.propTypes = {
questionset: PropTypes.object.isRequired,
sets: PropTypes.array.isRequired,
values: PropTypes.array.isRequired,
+ disabled: PropTypes.bool.isRequired,
focus: PropTypes.bool.isRequired,
parentSet: PropTypes.object.isRequired,
createSet: PropTypes.func.isRequired,
diff --git a/rdmo/projects/assets/js/interview/components/sidebar/Overview.js b/rdmo/projects/assets/js/interview/components/sidebar/Overview.js
index 57eb814812..1b3211238c 100644
--- a/rdmo/projects/assets/js/interview/components/sidebar/Overview.js
+++ b/rdmo/projects/assets/js/interview/components/sidebar/Overview.js
@@ -17,22 +17,31 @@ const Overview = ({ overview, help }) => {
- -
- {gettext('Project')}: {overview.title}
-
- -
- {/* TODO: get catalog title from catalog api */}
- {gettext('Catalog')}: {overview.catalog.title}
-
+ -
+ {gettext('Project')}: {overview.title}
+
+ -
+ {gettext('Catalog')}: {overview.catalog.title}
+
+ {
+ overview.read_only && (
+
+
+ {gettext('read only')}
+
+
+ )
+ }
+
>
diff --git a/rdmo/projects/assets/js/interview/containers/Main.js b/rdmo/projects/assets/js/interview/containers/Main.js
index 6f4f885b07..da38aefff5 100644
--- a/rdmo/projects/assets/js/interview/containers/Main.js
+++ b/rdmo/projects/assets/js/interview/containers/Main.js
@@ -3,28 +3,29 @@ import PropTypes from 'prop-types'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
+import { isReady } from '../utils/interview'
+
import Breadcrump from '../components/main/Breadcrump'
import Page from '../components/main/page/Page'
-import { showInterview } from '../utils/interview'
-
import * as configActions from 'rdmo/core/assets/js/actions/configActions'
import * as interviewActions from '../actions/interviewActions'
// eslint-disable-next-line no-unused-vars
-const Main = ({ config, settings, templates, user, interview, configActions, interviewActions }) => {
- if (showInterview(interview)) {
+const Main = ({ config, settings, templates, user, project, interview, configActions, interviewActions }) => {
+ if (isReady(interview)) {
return (
{
- if (showInterview(interview)) {
+const Sidebar = ({ config, settings, templates, user, project, interview, configActions, interviewActions }) => {
+ if (isReady(interview)) {
return (
!action.values.includes(value)),
sets: state.sets.filter((set) => !action.sets.includes(set))
}
- case FETCH_OVERVIEW_ERROR:
- case FETCH_PROGRESS_ERROR:
case FETCH_NAVIGATION_ERROR:
case FETCH_PAGE_ERROR:
case FETCH_VALUES_ERROR:
diff --git a/rdmo/projects/assets/js/interview/reducers/projectReducer.js b/rdmo/projects/assets/js/interview/reducers/projectReducer.js
new file mode 100644
index 0000000000..dfd7f90636
--- /dev/null
+++ b/rdmo/projects/assets/js/interview/reducers/projectReducer.js
@@ -0,0 +1,26 @@
+import {
+ FETCH_OVERVIEW_ERROR,
+ FETCH_OVERVIEW_SUCCESS,
+ FETCH_PROGRESS_ERROR,
+ FETCH_PROGRESS_SUCCESS,
+
+} from '../actions/actionTypes'
+
+const initialState = {
+ overview: null,
+ progress: null
+}
+
+export default function interviewReducer(state = initialState, action) {
+ switch(action.type) {
+ case FETCH_OVERVIEW_SUCCESS:
+ return { ...state, overview: action.overview }
+ case FETCH_PROGRESS_SUCCESS:
+ return { ...state, progress: action.progress }
+ case FETCH_OVERVIEW_ERROR:
+ case FETCH_PROGRESS_ERROR:
+ return { errors: action.errors }
+ default:
+ return state
+ }
+}
diff --git a/rdmo/projects/assets/js/interview/store/configureStore.js b/rdmo/projects/assets/js/interview/store/configureStore.js
index 799bb35c3e..6646da1552 100644
--- a/rdmo/projects/assets/js/interview/store/configureStore.js
+++ b/rdmo/projects/assets/js/interview/store/configureStore.js
@@ -10,6 +10,7 @@ import templateReducer from 'rdmo/core/assets/js/reducers/templateReducer'
import userReducer from 'rdmo/core/assets/js/reducers/userReducer'
import interviewReducer from '../reducers/interviewReducer'
+import projectReducer from '../reducers/projectReducer'
import * as configActions from 'rdmo/core/assets/js/actions/configActions'
import * as settingsActions from 'rdmo/core/assets/js/actions/settingsActions'
@@ -17,6 +18,7 @@ import * as templateActions from 'rdmo/core/assets/js/actions/templateActions'
import * as userActions from 'rdmo/core/assets/js/actions/userActions'
import * as interviewActions from '../actions/interviewActions'
+import * as projectActions from '../actions/projectActions'
import { parseLocation } from '../utils/location'
@@ -34,9 +36,10 @@ export default function configureStore() {
const rootReducer = combineReducers({
config: configReducer,
interview: interviewReducer,
+ project: projectReducer,
settings: settingsReducer,
templates: templateReducer,
- user: userReducer
+ user: userReducer,
})
const store = createStore(
@@ -59,8 +62,8 @@ export default function configureStore() {
store.dispatch(settingsActions.fetchSettings()),
store.dispatch(templateActions.fetchTemplates()),
store.dispatch(userActions.fetchCurrentUser()),
- store.dispatch(interviewActions.fetchOverview()),
- store.dispatch(interviewActions.fetchProgress())
+ store.dispatch(projectActions.fetchOverview()),
+ store.dispatch(projectActions.fetchProgress())
]).then(() => fetchPageFromLocation())
})
diff --git a/rdmo/projects/assets/js/interview/utils/interview.js b/rdmo/projects/assets/js/interview/utils/interview.js
index 945ba9cb15..2396067bc5 100644
--- a/rdmo/projects/assets/js/interview/utils/interview.js
+++ b/rdmo/projects/assets/js/interview/utils/interview.js
@@ -1,7 +1,7 @@
-import isUndefined from 'lodash/isUndefined'
+import { isNil } from 'lodash'
-const showInterview = (interview) => {
- return !isUndefined(interview.page) && !isUndefined(interview.navigation) && !isUndefined(interview.values)
+const isReady = (interview) => {
+ return !(isNil(interview.page) || isNil(interview.navigation) || isNil(interview.values))
}
-export { showInterview }
+export { isReady }
diff --git a/rdmo/projects/assets/js/interview/utils/page.js b/rdmo/projects/assets/js/interview/utils/page.js
index 0dd3c93481..48dfb67af5 100644
--- a/rdmo/projects/assets/js/interview/utils/page.js
+++ b/rdmo/projects/assets/js/interview/utils/page.js
@@ -1,26 +1,26 @@
import { isNil } from 'lodash'
const initQuestionSet = (questionset) => {
- questionset.elements = questionset.elements.map((element) => {
+ questionset.elements.forEach((element) => {
if (element.model == 'questions.questionset') {
- return initQuestionSet(element)
+ initQuestionSet(element)
} else {
- return initQuestion(element)
+ initQuestion(element)
}
})
- questionset.attributes = questionset.elements.reduce((agg, cur) => {
- if (cur.model == 'questions.questionset') {
- return agg.concat(cur.attributes)
+ // aggregate attributes from decendant questionsets and questions
+ questionset.attributes = questionset.elements.reduce((attributes, element) => {
+ if (element.model == 'questions.questionset') {
+ return attributes.concat(element.attributes)
} else {
- return [...agg, cur.attribute]
+ return [...attributes, element.attribute]
}
}, [questionset.attribute]).filter((a) => !isNil(a))
-
- return questionset
}
const initQuestion = (question) => {
+ // aggregate options from optionsets
question.options = question.optionsets.reduce((acc, cur) => {
acc = acc.concat(cur.options.map((option) => {
option.optionset = cur.id
@@ -29,8 +29,6 @@ const initQuestion = (question) => {
return acc
}, [])
-
- return question
}
const initPage = (page) => initQuestionSet(page)
diff --git a/rdmo/projects/assets/js/interview/utils/value.js b/rdmo/projects/assets/js/interview/utils/value.js
index 06cf2e9730..1cb5055aab 100644
--- a/rdmo/projects/assets/js/interview/utils/value.js
+++ b/rdmo/projects/assets/js/interview/utils/value.js
@@ -13,9 +13,9 @@ const isDefaultValue = (question, value) => {
} else if (question.default_external_id) {
return question.default_external_id == value.external_id
}
- } else {
- return false
}
+
+ return false
}
const initValues = (sets, values, element, setPrefix) => {
diff --git a/rdmo/projects/assets/scss/interview.scss b/rdmo/projects/assets/scss/interview.scss
index ecd9b5ce1b..c5a9ba01d5 100644
--- a/rdmo/projects/assets/scss/interview.scss
+++ b/rdmo/projects/assets/scss/interview.scss
@@ -214,14 +214,6 @@
.btn-remove-value:focus {
outline: 0;
}
-
- .badge-default {
- cursor: help;
- color: #999;
- border: 1px solid #999;
- background-color: white;
- margin: 7px 0 7px 0;
- }
}
.default {
@@ -233,11 +225,6 @@
opacity: 0.5;
}
}
-
- .badge-optional {
- float: right;
- margin-top: 1px;
- }
}
.interview-question {
@@ -318,3 +305,22 @@
.btn-add-set {
margin-bottom: 20px;
}
+
+.badge-default {
+ cursor: help;
+ color: #999;
+ border: 1px solid #999;
+ background-color: white;
+ margin: 7px 0 7px 0;
+}
+
+.badge-optional {
+ cursor: help;
+ float: right;
+ margin-top: 1px;
+}
+
+.badge-read-only {
+ cursor: help;
+ background-color: black;
+}
diff --git a/rdmo/projects/templates/projects/project_detail_sidebar.html b/rdmo/projects/templates/projects/project_detail_sidebar.html
index b3be4c74bd..ac8dedf720 100644
--- a/rdmo/projects/templates/projects/project_detail_sidebar.html
+++ b/rdmo/projects/templates/projects/project_detail_sidebar.html
@@ -20,13 +20,11 @@ {% trans 'Options' %}
{% endif %}
- {% if can_change_value %}
- {% trans 'Answer questions (new)' %}
+ {% trans 'Interview (new)' %}
- {% endif %}