diff --git a/app/pages/lab-pages-editor/components/TasksPage/TasksPage.jsx b/app/pages/lab-pages-editor/components/TasksPage/TasksPage.jsx
index 403f68dea0..a49900fa43 100644
--- a/app/pages/lab-pages-editor/components/TasksPage/TasksPage.jsx
+++ b/app/pages/lab-pages-editor/components/TasksPage/TasksPage.jsx
@@ -4,7 +4,6 @@ import createStep from '../../helpers/createStep.js';
import createTask from '../../helpers/createTask.js';
import getNewStepKey from '../../helpers/getNewStepKey.js';
import getNewTaskKey from '../../helpers/getNewTaskKey.js';
-import linkStepsInWorkflow from '../../helpers/linkStepsInWorkflow.js';
import moveItemInArray from '../../helpers/moveItemInArray.js';
import cleanupTasksAndSteps from '../../helpers/cleanupTasksAndSteps.js';
import getPreviewEnv from '../../helpers/getPreviewEnv.js';
@@ -39,7 +38,7 @@ export default function TasksPage() {
...workflow.tasks,
[newTaskKey]: newTask
};
- const steps = linkStepsInWorkflow([...workflow.steps, newStep]);
+ const steps = [...workflow.steps, newStep];
await update({ tasks, steps });
return steps.length - 1;
@@ -57,9 +56,9 @@ export default function TasksPage() {
tasks: {
'T0': {
answers: [
- {next: "P1", label: "Animals"},
- {next: "P2", label: "Fruits"},
- {label: "Neither"}
+ {next: 'P1', label: 'Animals'},
+ {next: 'P2', label: 'Fruits'},
+ {label: 'Neither'}
],
help: '',
question: 'Do you like Animals or Fruits?',
@@ -70,18 +69,56 @@ export default function TasksPage() {
'T2': { help: '', type: 'text', required: false, instruction: 'Which fruit?' }
},
steps: [
- ['P0', { next: 'P1', stepKey: 'P0', taskKeys: ["T0"] }],
+ ['P0', { stepKey: 'P0', taskKeys: ["T0"] }],
['P1', { next: 'P2', stepKey: 'P1', taskKeys: ["T1"] }],
['P2', { stepKey: 'P2', taskKeys: ["T2"] }]
]
});
}
+ function experimentalQuickSetupBranching() {
+ update({
+ tasks: {
+ 'T1.1': {
+ answers: [
+ {next: 'P2', label: 'Go to the 🔴 RED page'},
+ {next: 'P3', label: 'Go to the 🔵 BLUE page'},
+ ],
+ help: '',
+ question: 'Oh dear, this page has multiple branching tasks. Let\'s see what happens',
+ required: false,
+ type: 'single'
+ },
+ 'T1.2': {
+ answers: [
+ {next: 'P4', label: 'Go to the 🟡 YELLOW page'},
+ {next: 'P5', label: 'Go to the 🟢 GREEN page'},
+ ],
+ help: '',
+ question: 'This is the second branching task. If you answer both on the page, where do you branch to?',
+ required: false,
+ type: 'single'
+ },
+ 'T2': { help: '', type: 'text', required: false, instruction: 'Welcome to the 🔴 RED page! How do you feel?' },
+ 'T3': { help: '', type: 'text', required: false, instruction: 'Welcome to the 🔵 BLUE page! How do you feel?' },
+ 'T4': { help: '', type: 'text', required: false, instruction: 'Welcome to the 🟡 YELLOW page! How do you feel?' },
+ 'T5': { help: '', type: 'text', required: false, instruction: 'Welcome to the 🟢 GREEN page! How do you feel?' },
+ },
+ steps: [
+ ['P1', { stepKey: 'P1', taskKeys: ['T1.1', 'T1.2'] }],
+ ['P2', { stepKey: 'P2', taskKeys: ['T2'] }],
+ ['P3', { stepKey: 'P3', taskKeys: ['T3'] }],
+ ['P4', { stepKey: 'P4', taskKeys: ['T4'] }],
+ ['P5', { stepKey: 'P5', taskKeys: ['T5'] }],
+ ]
+ });
+ }
+
function moveStep(from, to) {
const oldSteps = workflow?.steps || [];
if (from < 0 || to < 0 || from >= oldSteps.length || to >= oldSteps.length) return;
- const steps = linkStepsInWorkflow(moveItemInArray(oldSteps, from, to));
+ const steps = moveItemInArray(oldSteps, from, to);
update({ steps });
}
@@ -124,8 +161,21 @@ export default function TasksPage() {
update({tasks});
}
+ // Changes the optional "next page" of a step/page
+ function updateNextStepForStep(stepKey, next = undefined) {
+ // Check if input is valid
+ const stepIndex = workflow?.steps?.findIndex(step => step[0] === stepKey);
+ const stepBody = workflow?.steps?.[stepIndex]?.[1];
+ if (!stepBody) return;
+
+ const newSteps = workflow.steps.slice();
+ newSteps[stepIndex] = [stepKey, { ...stepBody, next }];
+
+ update({ steps: newSteps });
+ }
+
// Changes the optional "next page" of a branching answer/choice
- function updateAnswerNext(taskKey, answerIndex, next = undefined) {
+ function updateNextStepForTaskAnswer(taskKey, answerIndex, next = undefined) {
// Check if input is valid
const task = workflow?.tasks?.[taskKey];
const answer = task?.answers[answerIndex];
@@ -185,7 +235,8 @@ export default function TasksPage() {
step={step}
stepKey={step[0]}
stepIndex={index}
- updateAnswerNext={updateAnswerNext}
+ updateNextStepForStep={updateNextStepForStep}
+ updateNextStepForTaskAnswer={updateNextStepForTaskAnswer}
/>
))}
@@ -225,7 +276,15 @@ export default function TasksPage() {
type="button"
style={{ margin: '0 4px' }}
>
- QUICK SETUP
+ QUICK SETUP (simple)
+
+
diff --git a/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/BranchingControls.jsx b/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/BranchingNextControls.jsx
similarity index 54%
rename from app/pages/lab-pages-editor/components/TasksPage/components/StepItem/BranchingControls.jsx
rename to app/pages/lab-pages-editor/components/TasksPage/components/StepItem/BranchingNextControls.jsx
index d0a33c334c..9ca96a5248 100644
--- a/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/BranchingControls.jsx
+++ b/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/BranchingNextControls.jsx
@@ -1,10 +1,13 @@
+import PropTypes from 'prop-types';
+import NextStepArrow from './NextStepArrow.jsx';
+
const DEFAULT_HANDLER = () => {};
-export default function BranchingControls({
+export default function BranchingNextControls({
allSteps = [],
task,
taskKey,
- updateAnswerNext = DEFAULT_HANDLER
+ updateNextStepForTaskAnswer = DEFAULT_HANDLER
}) {
if (!task || !taskKey) return null;
@@ -13,13 +16,13 @@ export default function BranchingControls({
function onChange(e) {
const next = e.target?.value;
const index = e?.target?.dataset.index;
- updateAnswerNext(taskKey, index, next);
+ updateNextStepForTaskAnswer(taskKey, index, next);
}
return (
-
+
{answers.map((answer, index) => (
- -
+
-
{answer.label}
- {branchingTask && (
-
)}
@@ -163,7 +166,8 @@ StepItem.propTypes = {
setActiveDragItem: PropTypes.func,
step: PropTypes.array,
stepIndex: PropTypes.number,
- updateAnswerNext: PropTypes.func
+ updateNextStepForStep: PropTypes.func,
+ updateNextStepForTaskAnswer: PropTypes.func
};
export default StepItem;
diff --git a/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/TaskItem.jsx b/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/TaskItem.jsx
index f3413fa3dd..fa6d2ecdc0 100644
--- a/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/TaskItem.jsx
+++ b/app/pages/lab-pages-editor/components/TasksPage/components/StepItem/TaskItem.jsx
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
// import strings from '../../../strings.json'; // TODO: move all text into strings
import TaskIcon from '../../../../icons/TaskIcon.jsx';
+import BranchingNextControls from './BranchingNextControls.jsx';
const TaskLabels = {
'drawing': 'Drawing Task',
@@ -9,9 +10,14 @@ const TaskLabels = {
'text': 'Text Task'
};
+const DEFAULT_HANDLER = () => {};
+
function TaskItem({
+ allSteps = [],
+ isBranchingTask = false,
task,
- taskKey
+ taskKey,
+ updateNextStepForTaskAnswer = DEFAULT_HANDLER
}) {
if (!task || !taskKey) return - ERROR: could not render Task
;
@@ -32,13 +38,58 @@ function TaskItem({
{taskText}
+ {isBranchingTask && (
+
+ )}
+ {!isBranchingTask && (
+
+ )}
);
}
TaskItem.propTypes = {
+ allSteps: PropTypes.arrayOf(PropTypes.array),
+ isBranchingTask: PropTypes.bool,
task: PropTypes.object,
- taskKey: PropTypes.string
+ taskKey: PropTypes.string,
+ updateNextStepForTaskAnswer: PropTypes.func
};
export default TaskItem;
+
+function PlaceholderAnswers({
+ task,
+ taskKey
+}) {
+ if (!task || !taskKey) return null;
+
+ if (task.type === 'single') {
+ const answers = task.answers || [];
+
+ return (
+
+ {answers.map((answer, index) => (
+ -
+
{answer.label}
+
+ ))}
+
+ );
+ }
+
+ if (task.type === 'text') {
+ return (
+
+
Participant text here
+
+ );
+ }
+
+ return null;
+}
diff --git a/app/pages/lab-pages-editor/helpers/cleanupTasksAndSteps.js b/app/pages/lab-pages-editor/helpers/cleanupTasksAndSteps.js
index 7f8c5fe105..039801be69 100644
--- a/app/pages/lab-pages-editor/helpers/cleanupTasksAndSteps.js
+++ b/app/pages/lab-pages-editor/helpers/cleanupTasksAndSteps.js
@@ -3,15 +3,14 @@ Clean up tasks and steps.
- TODO: Remove steps without tasks.
- TODO: Remove tasks not associated with any step.
- Remove orphaned references in branching tasks.
+- Remove orphaned references in steps.
- Returns { tasks, steps }
*/
-import linkStepsInWorkflow from './linkStepsInWorkflow.js';
-
export default function cleanupTasksAndSteps(tasks = {}, steps = []) {
const newTasks = structuredClone(tasks); // Copy tasks
- const newSteps = steps.slice(); // Copy steps
+ let newSteps = steps.slice(); // Copy steps
const taskKeys = Object.keys(newTasks);
const stepKeys = newSteps.map(step => step[0]);
@@ -25,9 +24,19 @@ export default function cleanupTasksAndSteps(tasks = {}, steps = []) {
}
})
});
+
+ // Remove orphaned references in steps.
+ newSteps = newSteps.map(step => {
+ const [stepKey, stepBody] = step;
+ const newStepBody = { ...stepBody };
+
+ // If the stepBody points to a non-existent Task Key or Step Key, remove the 'next'.
+ if (newStepBody.next && !taskKeys.includes(newStepBody.next) && !stepKeys.includes(newStepBody.next)) {
+ delete newStepBody.next;
+ }
+
+ return [ stepKey, newStepBody ]
+ })
- // Remember to re-link steps to close gaps created by missing Steps.
- const newStepsLinked = linkStepsInWorkflow(newSteps, newTasks);
-
- return { tasks: newTasks, steps: newStepsLinked };
+ return { tasks: newTasks, steps: newSteps };
}
diff --git a/css/lab-pages-editor.styl b/css/lab-pages-editor.styl
index 54c64c8bbc..384b245c16 100644
--- a/css/lab-pages-editor.styl
+++ b/css/lab-pages-editor.styl
@@ -479,32 +479,9 @@ $fontWeightBoldPlus = 700
&:active
cursor: grabbing
-
- ul.branching-controls
- display: flex
- flex-direction: row
- flex-wrap: wrap
- justify-content: center
- list-style: none
- margin: 0
- padding: 0
-
- li
- display: flex
- flex-direction: column
- margin: 0 $sizeM $sizeL $sizeM
- padding: 0
-
- .fake-button
- background: $white
- border: 1px solid $grey1
- border-radius: 2px
- color: $black
- font-family: $fontFamilies
- font-size: $fontSizeXS
- padding: $sizeS $sizeM
- text-align: center
-
+
+ .next-controls
+
.next-arrow
color: $yellow
display: block
@@ -519,6 +496,30 @@ $fontWeightBoldPlus = 700
&.next-is-submit
background: $white
border: 2px solid $yellow
+
+ &.simple-next-controls
+ display: flex
+ flex-direction: column
+
+ ul.horizontal-list
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: center
+ list-style: none
+ margin: 0
+ padding: 0
+
+ li
+ display: flex
+ flex-direction: column
+ margin: 0 $sizeM $sizeL $sizeM
+ padding: 0
+
+ div.vertical-layout
+ display: flex
+ flex-direction: column
+ align-items: center
.task-key
.step-key
@@ -527,6 +528,26 @@ $fontWeightBoldPlus = 700
color: $white
font-size: $fontSizeXS
padding: 0 $sizeS
+
+ .fake-button
+ background: $white
+ border: 1px solid $grey1
+ border-radius: 2px
+ color: $black
+ font-family: $fontFamilies
+ font-size: $fontSizeXS
+ padding: $sizeS $sizeM
+ text-align: center
+
+ .fake-text-input
+ background: $white
+ border: 1px solid $grey1
+ border-radius: 2px
+ color: $grey4
+ font-family: $fontFamilies
+ font-size: $fontSizeS
+ padding: $sizeS $sizeM
+ box-shadow: 1px 1px 4px 0px $shadowColour inset
.debug-0
width: 6em