Skip to content

Commit

Permalink
Merge pull request #1188 from rdmorganiser/interview-import-dataset
Browse files Browse the repository at this point in the history
feat(interview): Reuse datasets and values [5]
  • Loading branch information
jochenklar authored Jan 31, 2025
2 parents ad6b993 + 2a95493 commit 4579339
Show file tree
Hide file tree
Showing 48 changed files with 1,476 additions and 299 deletions.
30 changes: 16 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
__pycache__
*.pyc
*~
*.swp
.DS_Store

testing/config/settings/local.py
testing/log/
.pytest*/
Expand All @@ -6,19 +12,12 @@ static_root
media_root
components_root

docs/_build*

__pycache__
*.pyc
*~
*.swp
.DS_Store
.ruff_cache

env
env2
env3

Makefile

.coverage
.coverage.*
htmlcov
Expand All @@ -32,16 +31,19 @@ dist
.imdone/

.pytest_cache
.ruff_cache
.on-save.json

rdmo/management/static

rdmo/core/static/core/js/base*.js
rdmo/core/static/core/js/base.js
rdmo/core/static/core/css/base.css
rdmo/core/static/core/fonts
rdmo/core/static/core/css/base*.css

rdmo/projects/static/projects/js/*.js
rdmo/projects/static/projects/fonts
rdmo/projects/static/projects/css/*.css
rdmo/projects/static/projects/css/interview.css
rdmo/projects/static/projects/css/projects.css
rdmo/projects/static/projects/fonts/
rdmo/projects/static/projects/js/interview.js
rdmo/projects/static/projects/js/projects.js

screenshots
6 changes: 4 additions & 2 deletions rdmo/core/assets/js/components/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Modal as BootstrapModal } from 'react-bootstrap'

const Modal = ({ title, show, modalProps, submitLabel, submitProps, onClose, onSubmit, children }) => {
const Modal = ({ title, show, modalProps, submitLabel, submitProps, onClose, onSubmit, children, buttons }) => {
return (
<BootstrapModal className="element-modal" onHide={onClose} show={show} {...modalProps}>
<BootstrapModal.Header closeButton>
Expand All @@ -19,6 +19,7 @@ const Modal = ({ title, show, modalProps, submitLabel, submitProps, onClose, onS
<button type="button" className="btn btn-default" onClick={onClose}>
{gettext('Close')}
</button>
{buttons}
{
onSubmit && (
<button type="button" className="btn btn-primary" onClick={onSubmit} {...submitProps}>
Expand All @@ -39,7 +40,8 @@ Modal.propTypes = {
submitProps: PropTypes.object,
onClose: PropTypes.func.isRequired,
onSubmit: PropTypes.func,
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
buttons: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
}

export default Modal
46 changes: 46 additions & 0 deletions rdmo/core/assets/js/hooks/useLsState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState } from 'react'
import { isEmpty, isPlainObject, omit as lodashOmit } from 'lodash'

import { checkStoreId } from '../utils/store'

const useLsState = (path, initialValue, omit = []) => {
checkStoreId()

const getLs = (path) => {
const data = JSON.parse(localStorage.getItem(path))
return isPlainObject(data) ? lodashOmit(data, omit) : data
}

const setLs = (path, value) => {
const data = isPlainObject(value) ? lodashOmit(value, omit) : value
localStorage.setItem(path, JSON.stringify(data))
}

const getInitialState = () => {
// get the value from the local storage
const lsValue = getLs(path)

// return the state with the value from the local storage or the provided initialValue
if (isPlainObject(lsValue)) {
return { ...initialValue, ...lsValue }
} else if (isEmpty(lsValue)) {
return initialValue
} else {
return lsValue
}
}

// setup the state
const [value, setValue] = useState(getInitialState())

return [
value,
(value) => {
setLs(path, value)
setValue(value)
},
() => setValue(getInitialState())
]
}

export default useLsState
8 changes: 6 additions & 2 deletions rdmo/core/assets/scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ metadata {
.page h2:nth-child(2) {
margin-top: 0;
}
.sidebar h2:first-child,
.sidebar .import-buttons {
.sidebar > *:first-child {
margin-top: 70px;
}

Expand Down Expand Up @@ -317,6 +316,7 @@ form .yesno label {
/* modals */

.modal-body {
> div:last-child,
> p:last-child,
formgroup:last-child .form-group {
margin-bottom: 0;
Expand Down Expand Up @@ -495,3 +495,7 @@ li.has-warning > a.control-label > i {
color: $link-color;
cursor: pointer;
}

.has-error .react-select__control {
border-color: #a94442;
}
5 changes: 4 additions & 1 deletion rdmo/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@
'projects/project_interview_page_tabs_help.html',
'projects/project_interview_progress_help.html',
'projects/project_interview_question_help.html',
'projects/project_interview_questionset_help.html'
'projects/project_interview_questionset_help.html',
'projects/project_interview_sidebar.html',
]

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Expand Down Expand Up @@ -348,6 +349,8 @@

OPTIONSET_PROVIDERS = []

PROJECT_VALUES_SEARCH_LIMIT = 10

PROJECT_VALUES_VALIDATION = False

PROJECT_VALUES_VALIDATION_URL = True
Expand Down
21 changes: 13 additions & 8 deletions rdmo/projects/assets/js/interview/actions/interviewActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -611,18 +611,20 @@ export function deleteSetError(errors) {
return {type: DELETE_SET_ERROR, errors}
}

export function copySet(currentSet, currentSetValue, attrs) {
const pendingId = `copySet/${currentSet.set_prefix}/${currentSet.set_index}`
export function copySet(currentSet, copySetValue, attrs) {
const pendingId = isNil(currentSet) ? 'copySet' : `copySet/${currentSet.set_prefix}/${currentSet.set_index}`

return (dispatch, getState) => {
dispatch(addToPending(pendingId))
dispatch(copySetInit())

// create a new set
const set = SetFactory.create(attrs)
// create a new set (create) or use the current one (import)
const set = isNil(attrs.id) ? SetFactory.create(attrs) : currentSet

// create a value for the text if the page has an attribute
const value = isNil(attrs.attribute) ? null : ValueFactory.create(attrs)
// create a value for the text if the page has an attribute (create) or use the current one (import)
const value = isNil(attrs.attribute) ? null : (
isNil(attrs.id) ? ValueFactory.create(attrs) : attrs
)

// create a callback function to be called immediately or after saving the value
const copySetCallback = (setValues) => {
Expand All @@ -631,7 +633,10 @@ export function copySet(currentSet, currentSetValue, attrs) {
const state = getState().interview

const page = state.page
const values = [...state.values, ...setValues]
const values = [
...state.values.filter(v => !setValues.some(sv => compareValues(v, sv))), // remove updated values
...setValues
]
const sets = gatherSets(values)

initSets(sets, page)
Expand Down Expand Up @@ -667,7 +672,7 @@ export function copySet(currentSet, currentSetValue, attrs) {
})
)
} else {
promise = ValueApi.copySet(projectId, currentSetValue, value)
promise = ValueApi.copySet(projectId, value, copySetValue)
}

return promise.then((values) => {
Expand Down
4 changes: 4 additions & 0 deletions rdmo/projects/assets/js/interview/api/ProjectApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import BaseApi from 'rdmo/core/assets/js/api/BaseApi'

class ProjectsApi extends BaseApi {

static fetchProjects(params) {
return this.get(`/api/v1/projects/projects/?${encodeParams(params)}`)
}

static fetchOverview(projectId) {
return this.get(`/api/v1/projects/projects/${projectId}/overview/`)
}
Expand Down
12 changes: 9 additions & 3 deletions rdmo/projects/assets/js/interview/api/ValueApi.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import BaseApi from 'rdmo/core/assets/js/api/BaseApi'
import { encodeParams } from 'rdmo/core/assets/js/utils/api'
import isUndefined from 'lodash/isUndefined'
import { isUndefined } from 'lodash'

class ValueApi extends BaseApi {

static fetchValues(projectId, params) {
return this.get(`/api/v1/projects/projects/${projectId}/values/?${encodeParams(params)}`)
}

static searchValues(params) {
return this.get(`/api/v1/projects/values/search/?${encodeParams(params)}`)
}

static storeValue(projectId, value) {
if (isUndefined(value.id)) {
return this.post(`/api/v1/projects/projects/${projectId}/values/`, value)
Expand All @@ -29,8 +33,10 @@ class ValueApi extends BaseApi {
}
}

static copySet(projectId, currentSetValue, setValue) {
return this.post(`/api/v1/projects/projects/${projectId}/values/${currentSetValue.id}/set/`, setValue)
static copySet(projectId, setValue, copySetValue) {
return this.post(`/api/v1/projects/projects/${projectId}/values/set/`, {
...setValue, copy_set_value: copySetValue.id
})
}

static deleteSet(projectId, setValue) {
Expand Down
3 changes: 1 addition & 2 deletions rdmo/projects/assets/js/interview/components/main/Done.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ const Done = ({ templates }) => {
}

Done.propTypes = {
templates: PropTypes.object.isRequired,
overview: PropTypes.object.isRequired
templates: PropTypes.object.isRequired
}

export default Done
Loading

0 comments on commit 4579339

Please sign in to comment.