Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pages Editor: organise Steps and Tasks in UI #6898

Merged
merged 10 commits into from
Nov 3, 2023
2 changes: 1 addition & 1 deletion app/pages/lab-pages-editor/PagesEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import PropTypes from 'prop-types';

import DataManager from './DataManager.jsx';
import WorkflowHeader from './components/WorkflowHeader.jsx';
import TasksPage from './components/TasksPage.jsx';
import TasksPage from './components/TasksPage';
import WorkflowSettingsPage from './components/WorkflowSettingsPage.jsx';
import strings from './strings.json';

Expand Down
148 changes: 0 additions & 148 deletions app/pages/lab-pages-editor/components/TasksPage.jsx

This file was deleted.

94 changes: 94 additions & 0 deletions app/pages/lab-pages-editor/components/TasksPage/TasksPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* eslint-disable no-console */
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react/require-default-props */
/* eslint-disable radix */
/* eslint-disable react/jsx-boolean-value */
Comment on lines +1 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add these to the ESLint config, rather than add them to every file.


import { useWorkflowContext } from '../../context.js';
import getNewTaskKey from '../../helpers/getNewTaskKey.js';
import getNewStepKey from '../../helpers/getNewStepKey.js';
import createTask from '../../helpers/createTask.js';
import createStep from '../../helpers/createStep.js';
// import strings from '../../strings.json'; // TODO: move all text into strings

import StepItem from './components/StepItem.jsx';

export default function TasksPage() {
const { workflow, update } = useWorkflowContext();
const isActive = true; // TODO

// Automatically adds one pre-built Text Task
function experimentalAddNewTaskWithStep() {
const newTaskKey = getNewTaskKey(workflow?.tasks);
const newStepKey = getNewStepKey(workflow?.steps);
const newTask = createTask('text');
const newStep = createStep(newStepKey, [newTaskKey]);

if (!newTaskKey || !newStepKey || !newTask || !newStep) {
console.error('TasksPage: could not create Task');
return;
}

const tasks = {
...workflow.tasks,
[newTaskKey]: newTask
};
const steps = [...workflow.steps, newStep];

update({ tasks, steps });
}

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

if (!workflow) return null;

return (
<div className="tasks-page">
<div className="workflow-title flex-row">
<h2 className="flex-item">{workflow?.display_name}</h2>
<span className="workflow-id">{`#${workflow?.id}`}</span>
{(isActive) ? <span className="status-active">Active</span> : <span className="status-inactive">Inactive</span>}
</div>
<section aria-labelledby="workflow-tasks-heading">
<h3 id="workflow-tasks-heading">Tasks</h3>
<div className="flex-row">
<button
className="flex-item big primary"
onClick={experimentalAddNewTaskWithStep}
type="button"
>
Add a new Task +
</button>
{/* Dev observation: the <select> should have some label to indicate it's for choosing the starting task. */}
<select
aria-label="Choose starting page"
className="flex-item"
>
<option disabled>Choose starting Page</option>
</select>
</div>
<ul className="steps-list" aria-label="Pages/Steps">
{workflow.steps.map(([stepKey, step]) => (
<StepItem
allTasks={workflow.tasks}
step={step}
stepKey={stepKey}
/>
))}
</ul>
<button
className="big primary"
onClick={experimentalReset}
type="button"
>
RESET
</button>
</section>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* eslint-disable no-console */
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react/require-default-props */
/* eslint-disable radix */
/* eslint-disable react/jsx-boolean-value */
/* eslint-disable react/forbid-prop-types */

import PropTypes from 'prop-types';

// import strings from '../../../strings.json'; // TODO: move all text into strings
import TaskItem from './TaskItem.jsx';
import GripIcon from '../../../icons/GripIcon.jsx';

function StepItem({
allTasks,
step,
stepKey
}) {
if (!step || !stepKey || !allTasks) return <li className="step-item">ERROR: could not render Step</li>;

const taskKeys = step.taskKeys || [];

return (
<li className="step-item">
<div className="step-controls flex-row spacing-bottom-XS">
<span className="step-controls-left" />
<div className="step-controls-center">
<button aria-label={`Rearrange Page ${stepKey} upwards`} className="plain" type="button">
<span className="fa fa-caret-up" />
</button>
{/* TODO: add drag/drop functionality. Perhaps this needs to be wider, too. */}
<GripIcon className="grab-handle" color="#A6A7A9" />
<button aria-label={`Rearrange Page/Step ${stepKey} downwards`} className="plain" type="button">
<span className="fa fa-caret-down" />
</button>
</div>
<div className="step-controls-right">
<button aria-label={`Delete Page/Step ${stepKey}`} className="plain" type="button">
<span className="fa fa-trash" />
</button>
<button aria-label={`Copy Page/Step ${stepKey}`} className="plain" type="button">
<span className="fa fa-copy" />
</button>
<button aria-label={`Edit Page/Step ${stepKey}`} className="plain" type="button">
<span className="fa fa-pencil" />
</button>
</div>
</div>
<ul className="tasks-list" aria-label={`Tasks for Page/Step ${stepKey}`}>
{taskKeys.map((taskKey) => {
const task = allTasks[taskKey];
return (
<TaskItem task={task} taskKey={taskKey} />
);
})}
</ul>
</li>
);
}

StepItem.propTypes = {
allTasks: PropTypes.object,
step: PropTypes.object,
stepKey: PropTypes.string
};

export default StepItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable no-console */
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react/require-default-props */
/* eslint-disable radix */
/* eslint-disable react/jsx-boolean-value */
/* eslint-disable react/forbid-prop-types */

import PropTypes from 'prop-types';

// import strings from '../../../strings.json'; // TODO: move all text into strings

function TaskItem({
task,
taskKey
}) {
if (!task || !taskKey) return <li className="task-item">ERROR: could not render Task</li>;

// TODO: use Panoptes Translations API.
// e.g. pull from workflow.strings['tasks.T0.instruction']
// Task.instruction/question isn't particularly standardised across different task types.
const text = task.instruction || task.question || '';

return (
<li className="task-item">
<div className="flex-row spacing-bottom-M">
<span className="task-key">{taskKey}</span>
<span className="task-icon">
{/* TODO: change icon and aria label depending on task type */}
<span
aria-label="Task type: text"
className="fa fa fa-file-text-o fa-fw"
role="img"
/>
</span>
<span className="task-text flex-item">{text}</span>
</div>
</li>
);
}

TaskItem.propTypes = {
task: PropTypes.object,
taskKey: PropTypes.string
};

export default TaskItem;
3 changes: 3 additions & 0 deletions app/pages/lab-pages-editor/components/TasksPage/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TasksPage from './TasksPage.jsx';

export default TasksPage;
Loading