-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pages Editor: Basic Styling & Simple Workflow Settings Page (#6822)
* PagesEditor: rename index.jsx into its own PagesEditor component * PagesEditor: add stylesheet * Lab: add exception for PagesEditor styling * PagesEditor: update README to include notes on other PFE files affected * PagesEditor: attempt to style workflow header * PagesEditor: minor changes to workflowId and projectId use * WorkflowHeader: minor changes to strings and icons * WorkflowHeader: add placeholder onClick buttons * PagesEditor: add WorkflowSettingsPage * PagesEditor: remove Tester * PagesEditor: add styles for workflow config page * PagesEditor: establish structure for styling constants * WorkflowSettingsPage: add first column * WorkflowSettingsPage: add grid layout * WorkflowSettingsPage: style hr * WorkflowSettingsPage: fix font sizes * PagesEditor: refactor layout styles * WorkflowSettingsPage: add Subject Retirement Count update functionality * WorkflowSettingsPage: minor refactors * WorkflowSettingsPage: Subject Viewer selection now works * PagesEditor: refactor styling sizes * WorkflowSettingsPage: add styling for .disabled * WorkflowSettingsPage: add tests for checkboxes and radio * WorkflowSettingsPage: add align-item styles * WorkflowSettingsPage: add accent colour to controls * WorkflowSettingsPage: minor layout width change to compensate for padding * PageEditor: restyle header to match design, add new layout stylings
- Loading branch information
1 parent
52757cd
commit 34f8fab
Showing
12 changed files
with
559 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
Pages Editor | ||
Main component of the Pages Editor feature. | ||
*/ | ||
|
||
// ESLint: don't import global React, and don't use .defaultProps. | ||
/* eslint-disable no-console */ | ||
/* eslint-disable react/react-in-jsx-scope */ | ||
/* eslint-disable react/require-default-props */ | ||
|
||
import { StrictMode } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import DataManager from './DataManager.jsx'; | ||
import Tester from './Tester.jsx'; | ||
import WorkflowHeader from './components/WorkflowHeader.jsx'; | ||
import WorkflowSettingsPage from './components/WorkflowSettingsPage.jsx'; | ||
|
||
function PagesEditor({ params }) { | ||
const { workflowID: workflowId, projectID: projectId } = params; | ||
|
||
return ( | ||
<StrictMode> | ||
<div className="lab-pages-editor"> | ||
<DataManager | ||
key={workflowId || '-'} // | ||
workflowId={workflowId} | ||
> | ||
<WorkflowHeader projectId={projectId} /> | ||
<WorkflowSettingsPage /> | ||
</DataManager> | ||
</div> | ||
</StrictMode> | ||
); | ||
} | ||
|
||
PagesEditor.propTypes = { | ||
params: PropTypes.shape({ | ||
projectID: PropTypes.string, | ||
workflowID: PropTypes.string | ||
}) | ||
}; | ||
|
||
export default PagesEditor; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* eslint-disable no-console */ | ||
/* eslint-disable react/react-in-jsx-scope */ | ||
/* eslint-disable react/require-default-props */ | ||
|
||
import PropTypes from 'prop-types'; | ||
import { Link } from 'react-router'; | ||
|
||
import ReturnIcon from '../icons/ReturnIcon.jsx'; | ||
import { useWorkflowContext } from '../context.js'; | ||
import strings from '../strings.json'; | ||
|
||
export default function WorkflowHeader({ | ||
projectId = '' | ||
}) { | ||
const { workflow } = useWorkflowContext(); | ||
const returnUrl = `/lab/${projectId}/workflows`; | ||
|
||
function onClick() { | ||
console.log('TODO'); | ||
} | ||
|
||
if (!workflow) return null; | ||
|
||
return ( | ||
<div className="workflow-header flex-row"> | ||
<Link to={returnUrl}> | ||
<ReturnIcon /> | ||
{strings.PagesEditor.components.WorkflowHeader.return} | ||
</Link> | ||
<div className="flex-row flex-item justify-around"> | ||
<button className="unselected" type="button" onClick={onClick}> | ||
{strings.PagesEditor.components.WorkflowHeader.tasks} | ||
</button> | ||
<button className="selected" type="button" onClick={onClick}> | ||
{strings.PagesEditor.components.WorkflowHeader.workflow_settings} | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
WorkflowHeader.propTypes = { | ||
projectId: PropTypes.string | ||
}; |
255 changes: 255 additions & 0 deletions
255
app/pages/lab-pages-editor/components/WorkflowSettingsPage.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
/* eslint-disable no-console */ | ||
/* eslint-disable react/react-in-jsx-scope */ | ||
/* eslint-disable react/require-default-props */ | ||
/* eslint-disable radix */ | ||
|
||
import { useWorkflowContext } from '../context.js'; | ||
import strings from '../strings.json'; // TODO: move all text into strings | ||
|
||
export default function WorkflowSettingsPage() { | ||
const { workflow, update } = useWorkflowContext(); | ||
|
||
function onSubmit(e) { | ||
e.preventDefault(); | ||
try { | ||
console.log('+++ onSubmit: ', e); | ||
// TODO: on Submit, run update() on every available field. | ||
// also, make sure the 'data-updaterule' rules are implemented. | ||
} catch (err) { | ||
console.error('WorkflowSettingsPageError: ', err); | ||
} | ||
return false; | ||
} | ||
|
||
function doUpdate(e) { | ||
const key = e.target.name; | ||
let value = e.target.value || ''; | ||
const { updaterule } = e.target.dataset; | ||
|
||
if (updaterule === 'convert_to_number') value = parseInt(value); | ||
if (updaterule === 'undefined_if_empty') value = value || undefined; | ||
|
||
// TODO: due to onBlur={doUpdate}, keyboard navigation may accidentally cause the Workflow to update multiple times. | ||
// One solution is to check if the new value is different from the existing one. | ||
|
||
update({ | ||
[key]: value | ||
// 'configuration.classifier_version': '2.0' // TODO: figure out if this needed. | ||
}); | ||
} | ||
|
||
function testUpdate(e) { | ||
const key = e.target.name; | ||
const value = e.target.value || ''; | ||
console.log('+++ testUpdate: ', key, value); | ||
} | ||
|
||
if (!workflow) return null; | ||
|
||
return ( | ||
<form className="workflow-settings-page" onSubmit={onSubmit}> | ||
<label htmlFor="display_name"> | ||
Workflow Name | ||
<input | ||
type="text" | ||
name="display_name" | ||
defaultValue={workflow?.display_name || ''} | ||
onBlur={doUpdate} | ||
/> | ||
</label> | ||
|
||
<div className="column-group col-1"> | ||
<fieldset> | ||
<legend>Associated Subject Sets</legend> | ||
<p>Choose the set of subjects you want to use for this workflow. Add subject sets in the Subject Sets tab.</p> | ||
<p>TODO</p> | ||
</fieldset> | ||
|
||
<fieldset> | ||
<legend>Associated Tutorial</legend> | ||
<p>Choose the tutorials you want to use for this workflow. Create tutorials in the Tutorial tab.</p> | ||
<p>TODO</p> | ||
</fieldset> | ||
|
||
<hr /> | ||
|
||
<fieldset> | ||
<legend>Subject Retirement</legend> | ||
<p id="subject-retirement-info"> | ||
Set how many people should classify each subject before it is | ||
"done." Once a subject has reached the retirement limit it | ||
will no longer be shown to volunteers. | ||
</p> | ||
<div className="flex-row align-start spacing-bottom"> | ||
<select | ||
aria-label="Retirement criteria" | ||
className="flex-item" | ||
defaultValue={workflow?.retirement?.criteria} | ||
aria-describedby="subject-retirement-info" | ||
name="retirement.criteria" | ||
onChange={doUpdate} | ||
> | ||
<option value="classification_count">Classification count</option> | ||
<option value="never_retire">Never retire</option> | ||
{/* TODO: this is just a POC - never_retire should be removed, even though it's a valid option on the API. */} | ||
</select> | ||
<input | ||
aria-label="Retirement count" | ||
className="small-width" | ||
defaultValue={workflow?.retirement?.options?.count} | ||
data-updaterule="convert_to_number" | ||
max="100" | ||
min="1" | ||
name="retirement.options.count" | ||
onBlur={doUpdate} | ||
placeholder="∞" | ||
type="number" | ||
/> | ||
</div> | ||
<p className="small-info"> | ||
If you'd like more complex retirement rules such as conditional | ||
retirement using Caesar, please get in touch via the Contact Us | ||
page. | ||
</p> | ||
</fieldset> | ||
</div> | ||
|
||
<div className="column-group col-2"> | ||
<fieldset> | ||
<legend>Subject Viewer</legend> | ||
<p id="subject-viewer-info"> | ||
Choose how to display your subjects. | ||
Refer to the Subject Viewer section of the Glossary for more info. | ||
</p> | ||
<div className="flex-row align-start spacing-bottom"> | ||
<select | ||
aria-label="Subject viewer" | ||
className="flex-item" | ||
data-updaterule="undefined_if_empty" | ||
defaultValue={workflow?.configuration?.subject_viewer || ''} | ||
aria-describedby="subject-viewer-info" | ||
name="configuration.subject_viewer" | ||
onChange={doUpdate} | ||
> | ||
<option value="">None selected (default)</option> | ||
<option value="imageAndText">Image and Text</option> | ||
<option value="jsonData">JSON data charts</option> | ||
<option value="multiFrame">Multi-Frame</option> | ||
<option value="singleImage">Single Image</option> | ||
<option value="singleText">Single Text</option> | ||
<option value="subjectGroup">Subject Group</option> | ||
</select> | ||
</div> | ||
</fieldset> | ||
|
||
<fieldset className="disabled"> | ||
<legend>Multi-Image Options</legend> | ||
<p> | ||
Choose how to display subjects with multiple images. | ||
If your subjects are in a sequence, such as camera trap images, | ||
volunteers can play them like a .gif using the Flipbook viewer. | ||
</p> | ||
<p>TODO</p> | ||
</fieldset> | ||
|
||
<hr /> | ||
|
||
<fieldset> | ||
<legend>Classification Tools</legend> | ||
<p>TEST: HTML and styling for checkbox input</p> | ||
<label | ||
htmlFor="placeholder-1" | ||
className="flex-row align-start spacing-bottom" | ||
> | ||
<input | ||
type="checkbox" | ||
id="placeholder-1" | ||
name="placeholder-1" | ||
onChange={testUpdate} | ||
/> | ||
<span>Placeholder 1</span> | ||
</label> | ||
<label | ||
htmlFor="placeholder-2" | ||
className="flex-row align-start spacing-bottom" | ||
> | ||
<input | ||
defaultChecked={true} | ||
type="checkbox" | ||
id="placeholder-2" | ||
name="placeholder-2" | ||
onChange={testUpdate} | ||
/> | ||
<span> | ||
Placeholder 2 - | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vel tellus quam. | ||
</span> | ||
</label> | ||
<label | ||
htmlFor="placeholder-3" | ||
className="flex-row align-start spacing-bottom" | ||
> | ||
<input | ||
type="checkbox" | ||
id="placeholder-3" | ||
name="placeholder-3" | ||
onChange={testUpdate} | ||
/> | ||
<span> | ||
Placeholder 3 - | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vel tellus quam. | ||
Praesent lobortis dapibus nisi, ultricies blandit quam mattis vel. | ||
Nunc consequat sem finibus, facilisis augue quis, euismod velit. | ||
</span> | ||
</label> | ||
</fieldset> | ||
|
||
<fieldset> | ||
<legend>Quicktalk</legend> | ||
<p>TEST: HTML and styling for radio options</p> | ||
<label | ||
className="flex-row align-start spacing-bottom" | ||
htmlFor="placeholder-4-a" | ||
> | ||
<input | ||
type="radio" | ||
id="placeholder-4-a" | ||
name="placeholder-4" | ||
onChange={testUpdate} | ||
value="Option A" | ||
/> | ||
<span>Placeholder 4, Option A</span> | ||
</label> | ||
<label | ||
className="flex-row align-start spacing-bottom" | ||
htmlFor="placeholder-4-b" | ||
> | ||
<input | ||
defaultChecked={true} | ||
type="radio" | ||
id="placeholder-4-b" | ||
name="placeholder-4" | ||
onChange={testUpdate} | ||
value="Option B" | ||
/> | ||
<span>Placeholder 4, Option B</span> | ||
</label> | ||
<label | ||
className="flex-row align-start spacing-bottom" | ||
htmlFor="placeholder-4-c" | ||
> | ||
<input | ||
type="radio" | ||
id="placeholder-4-c" | ||
name="placeholder-4" | ||
onChange={testUpdate} | ||
value="Option C" | ||
/> | ||
<span>Placeholder 4, Option C</span> | ||
</label> | ||
</fieldset> | ||
|
||
</div> | ||
</form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Icons for the Pages Editor | ||
|
||
Icons are organised into this folder, to make them easier should we choose to update them in the future - e.g. replace all FontAwesome icons with Grommet icons. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/* eslint-disable react/react-in-jsx-scope */ | ||
|
||
export default function ReturnIcon() { | ||
return ( | ||
<i className="icon fa fa-chevron-left" /> | ||
); | ||
} |
Oops, something went wrong.