Skip to content

Commit

Permalink
Pages Editor: add "Add Task to existing Page" functionality (#7065)
Browse files Browse the repository at this point in the history
* pages-editor-pt18: EditStepDialog: refresh design. Add 'Add New Task' button

* Refactor: rearrange/rename code for readability

* TasksPage: addTask() can add to existing Step or create new Step

* Rename editStep() to openEditStepDialog()

* Add ExperimentalPanel

* TasksPage, EditStepDialog: cleaner handling of activeStepIndex

* WIP: EditStepDialog's Add New Task button opens dialog

* WIP: clean up linkages to edit/add task

* TasksPage/NewTasksDialog: implement add Task to new or existing Step

* WorkflowSettingsPage: remove test code

* TasksPage: add notes on addTask

* Update documents. Refactor updateTask()

* Restyle task-items

* Restyle NextArrow - default has no arrowhead

* TasksPage: remove debug code
  • Loading branch information
shaunanoordin authored Apr 25, 2024
1 parent ef9e1d8 commit 2456452
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 154 deletions.
110 changes: 110 additions & 0 deletions app/pages/lab-pages-editor/components/TasksPage/ExperimentalPanel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
const DEFAULT_HANDLER = () => {};

export default function ExperimentalPanel({
update = DEFAULT_HANDLER
}) {
function experimentalReset() {
update({
tasks: {},
steps: []
});
}

function experimentalQuickSetup() {
update({
tasks: {
'T0': {
answers: [
{next: 'P1', label: 'Animals'},
{next: 'P2', label: 'Fruits'},
{label: 'Neither'}
],
help: '',
question: 'Do you like Animals or Fruits?',
required: false,
type: 'single'
},
'T1': { help: '', type: 'text', required: false, instruction: 'Which animal?' },
'T2': { help: '', type: 'text', required: false, instruction: 'Which fruit?' }
},
steps: [
['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'] }],
]
});
}

return (
<div
style={{
padding: '16px',
margin: '8px 0',
border: '2px dashed #c04040'
}}
>
<button
className="big"
onClick={experimentalReset}
type="button"
style={{ margin: '0 4px' }}
>
RESET
</button>
<button
className="big"
onClick={experimentalQuickSetup}
type="button"
style={{ margin: '0 4px' }}
>
QUICK SETUP (simple)
</button>
<button
className="big"
onClick={experimentalQuickSetupBranching}
type="button"
style={{ margin: '0 4px' }}
>
QUICK SETUP (advanced, branching)
</button>
</div>
);
}
181 changes: 59 additions & 122 deletions app/pages/lab-pages-editor/components/TasksPage/TasksPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import cleanupTasksAndSteps from '../../helpers/cleanupTasksAndSteps.js';
import getPreviewEnv from '../../helpers/getPreviewEnv.js';
// import strings from '../../strings.json'; // TODO: move all text into strings

import ExperimentalPanel from './ExperimentalPanel.jsx';
import EditStepDialog from './components/EditStepDialog';
import NewTaskDialog from './components/NewTaskDialog.jsx';
import StepItem from './components/StepItem';
Expand All @@ -20,16 +21,38 @@ export default function TasksPage() {
const newTaskDialog = useRef(null);
const [ activeStepIndex, setActiveStepIndex ] = useState(-1); // Tracks which Step is being edited.
const [ activeDragItem, setActiveDragItem ] = useState(-1); // Keeps track of active item being dragged (StepItem). This is because "dragOver" CAN'T read the data from dragEnter.dataTransfer.getData().
const activeStepKey = workflow?.steps?.[activeStepIndex]?.[0];
const isActive = true; // TODO

// Adds a new Task (with default settings), inside a new Step. Returns the newly created step index.
async function addNewTaskWithStep(taskType) {
/*
Adds a new Task of a specified type (with default settings) to a Step.
If no Step is specified, a new Step is created.
Returns the newly created step index.
*/
async function addTask(taskType, stepIndex = -1) {
const newTaskKey = getNewTaskKey(workflow?.tasks);
const newStepKey = getNewStepKey(workflow?.steps);
const newTask = createTask(taskType);
const newStep = createStep(newStepKey, [newTaskKey]);
const steps = workflow?.steps?.slice() || [];

let step
if (stepIndex < 0) {
// If no step is specified, we create a new one.
const newStepKey = getNewStepKey(workflow?.steps);
step = createStep(newStepKey, [newTaskKey]);
steps.push(step);

} else {
// If a step is specified, we'll add the Task to that one.
step = workflow?.steps?.[stepIndex];
if (step) {
const [stepKey, stepBody] = step;
const stepBodyTaskKeys = stepBody?.taskKeys?.slice() || [];
stepBodyTaskKeys.push(newTaskKey);
steps[stepIndex] = [ stepKey, { ...stepBody, taskKeys: stepBodyTaskKeys } ];
}
}

if (!newTaskKey || !newStepKey || !newTask || !newStep) {
if (!newTaskKey || !newTask || !step) {
console.error('TasksPage: could not create Task');
return;
}
Expand All @@ -38,80 +61,24 @@ export default function TasksPage() {
...workflow.tasks,
[newTaskKey]: newTask
};
const steps = [...workflow.steps, newStep];

await update({ tasks, steps });
return steps.length - 1;
return (stepIndex < 0) ? steps.length - 1 : stepIndex;
}

function experimentalReset() {
update({
tasks: {},
steps: []
});
}

function experimentalQuickSetup() {
update({
tasks: {
'T0': {
answers: [
{next: 'P1', label: 'Animals'},
{next: 'P2', label: 'Fruits'},
{label: 'Neither'}
],
help: '',
question: 'Do you like Animals or Fruits?',
required: false,
type: 'single'
},
'T1': { help: '', type: 'text', required: false, instruction: 'Which animal?' },
'T2': { help: '', type: 'text', required: false, instruction: 'Which fruit?' }
},
steps: [
['P0', { stepKey: 'P0', taskKeys: ["T0"] }],
['P1', { next: 'P2', stepKey: 'P1', taskKeys: ["T1"] }],
['P2', { stepKey: 'P2', taskKeys: ["T2"] }]
]
});
/*
Updates (or adds) a Task
*/
function updateTask(taskKey, task) {
if (!taskKey) return;
const newTasks = structuredClone(workflow?.tasks || {}); // Copy tasks
newTasks[taskKey] = task;
update({ tasks: newTasks });
}

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 deleteTask(taskKey) {
if (!taskKey) return;
// TODO
}

function moveStep(from, to) {
Expand Down Expand Up @@ -139,26 +106,22 @@ export default function TasksPage() {
update(cleanedTasksAndSteps);
}

// aka openEditStepDialog
function editStep(stepIndex) {
function openNewTaskDialog(stepIndex = -1) {
setActiveStepIndex(stepIndex);
editStepDialog.current?.openDialog();
newTaskDialog.current?.openDialog();
}

function openNewTaskDialog() {
newTaskDialog.current?.openDialog();
function openEditStepDialog(stepIndex) {
setActiveStepIndex(stepIndex);
editStepDialog.current?.openDialog();
}

function deleteTask(taskKey) {
if (!taskKey) return;
// TODO
function handleClickAddTaskButton() {
openNewTaskDialog(-1);
}

function updateTask(taskKey, task) {
if (!taskKey) return;
const tasks = JSON.parse(JSON.stringify(workflow?.tasks || {}));
tasks[taskKey] = task
update({tasks});
function handleCloseEditStepDialog() {
setActiveStepIndex(-1);
}

// Changes the optional "next page" of a step/page
Expand Down Expand Up @@ -207,7 +170,7 @@ export default function TasksPage() {
<div className="flex-row">
<button
className="flex-item big primary decoration-plus"
onClick={openNewTaskDialog}
onClick={handleClickAddTaskButton}
type="button"
>
Add a new Task
Expand All @@ -229,8 +192,8 @@ export default function TasksPage() {
allSteps={workflow.steps}
allTasks={workflow.tasks}
deleteStep={deleteStep}
editStep={editStep}
moveStep={moveStep}
openEditStepDialog={openEditStepDialog}
setActiveDragItem={setActiveDragItem}
step={step}
stepKey={step[0]}
Expand All @@ -242,51 +205,25 @@ export default function TasksPage() {
</ul>
<NewTaskDialog
ref={newTaskDialog}
addTaskWithStep={addNewTaskWithStep}
editStep={editStep}
addTask={addTask}
openEditStepDialog={openEditStepDialog}
stepIndex={activeStepIndex}
/>
<EditStepDialog
ref={editStepDialog}
allTasks={workflow.tasks}
onClose={handleCloseEditStepDialog}
openNewTaskDialog={openNewTaskDialog}
step={workflow.steps[activeStepIndex]}
stepIndex={activeStepIndex}
deleteTask={deleteTask}
updateTask={updateTask}
/>

{/* EXPERIMENTAL */}
<div
style={{
padding: '16px',
margin: '8px 0',
border: '2px dashed #c04040'
}}
>
<button
className="big"
onClick={experimentalReset}
type="button"
style={{ margin: '0 4px' }}
>
RESET
</button>
<button
className="big"
onClick={experimentalQuickSetup}
type="button"
style={{ margin: '0 4px' }}
>
QUICK SETUP (simple)
</button>
<button
className="big"
onClick={experimentalQuickSetupBranching}
type="button"
style={{ margin: '0 4px' }}
>
QUICK SETUP (advanced, branching)
</button>
</div>
<ExperimentalPanel
update={update}
/>
</section>
</div>
);
Expand Down
Loading

0 comments on commit 2456452

Please sign in to comment.