-
Notifications
You must be signed in to change notification settings - Fork 30
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
Classifier: load specific workflows and subject sets #1793
Conversation
382cd2c
to
e8b0c92
Compare
This works locally, which is promising. Tested in the standalone classifier and in the project app, using both server-side and client-side rendering of the classify page. However, the tests for EDIT:
should be
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming this is ready for review with the change from being a draft PR... is there a project to test this with in the project app using routes? This works with the dev classifier testing between loading different workflows with staging project 1754 (ASM testing) and using query param.
I've tested with the Classic vs. Enhanced workflows for Galaxy Zoo, though it's hard to tell exactly which one is loaded in the classifier. I've also got a staging project with a bunch of different workflows. https://master.pfe-preview.zooniverse.org/projects/eatyourgreens/-project-testing-ground |
0e2f8b3
to
c9b8904
Compare
@@ -22,8 +22,6 @@ const WorkflowStore = types | |||
const validProjectReference = isValidReference(() => getRoot(self).projects?.active) | |||
if (validProjectReference) { | |||
self.reset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this reset move into the selectWorkflow
action, so that we always reset the store before setting a new workflow?
@@ -35,25 +33,11 @@ const WorkflowStore = types | |||
const validWorkflowReference = isValidReference(() => self.active) | |||
if (validUPPReference && !validWorkflowReference) { | |||
self.reset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question about resetting the store here.
7587667
to
96e9e42
Compare
9c6d9db
to
3a940b0
Compare
12f12f5
to
64fb48d
Compare
This seems to work for anonymous users but I'm seeing an error from the state tree if I try to load the classifier while logged in.
I'm also finding that the project app dies with an MST error if I run
with the dev tools open. It runs fine with the dev tools closed (which isn't very useful) or if I run a production build with dev tools:
EDIT: removing the WorkflowStores's Project and UPP observers, which reset the store on change, seems to fix this. I'm not sure what those observers are intended to do but nothing seems broken without them. |
I'm testing on a staging project withe the project and UPP observers removed: I see workflow selection happen while the classifier is still loading the UPP, but I don't see that make any difference to the subject selection request, so it seems like the changes here load the correct workflow and subject queue for a volunteer, even if the UPP hasn't loaded in the classifier yet. |
Move WorkflowStore files into their own directory.
Remove the workflow query param from the workflow store. Pass in workflowID as a prop instead.
Use the workflowID prop to select a workflow on mount. Fallback to the project default selection if no workflow ID is specified. Remove the selectWorkflow() that automatically ran on project change and UPP change.
Get the dev classifier workflow, if any, from window.location and pass it into the App component as a prop.
Set a subject set ID with workflow.selectSubjectSet(subjectSetID) and return the selected subject set from the subjectSetId view. Add an optional subject set ID to workflowStore.selectWorkflow. If present, select that subject set for the active workflow. store.setActive(id) will make an API request if a resource isn't already stored, so make workflowStore.selectWorkflow asynchronous. Fetch the workflow, then set any selected subject set ID, then set the active workflow in order to initiate subject selection from the API. Add resourceStore.getResource(id). Sometimes we want to get a resource by ID without setting it as the active resource. `getResource(id)` will return any existing, stored resource, or fetch from the API for new resources. Add workflow.subjectSets, which is a SubjectSetStore. Use workflow.subjectSets.active for subject selection. Add subject sets to the workflow factory. Add a subject set factory. Add subjectSet as a query param for the dev classifier.
Check subject set ID against workflow.links.subject_sets and error if the subject set isn't linked to the workflow.
Only set the selected subject set ID if a subject set has been explicitly set in the classifier's props.
Remove the WorkflowStore's project and UPP observers. They reset the store on change, removing any stored workflow and subject sets.
Add workflows.project, which returns the active project or undefined.
133654a
to
f1c1f27
Compare
Check any supplied workflow ID against the project's active workflows before loading it.
One potential enhancement of this (but outside the scope of this PR): fetch the workflow and subject set in Lines 3 to 7 in d8f1071
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: removing the WorkflowStores's Project and UPP observers, which reset the store on change, seems to fix this. I'm not sure what those observers are intended to do but nothing seems broken without them.
- To be able to use the classifier as stand-alone from the project app, the workflow should request a new workflow if the project changes
- To setup to be able to validate a workflow that is requested against the workflow id stored in the UPP. Therefore, if the UPP changes, request a new workflow. This part isn't finished yet.
Removing these observers limits what the classifier lib can do independently now. However, since neither of these are required by the Engaging Crowds feature, I would suggest we leave in the observers, but with todo comments on future enhancement and don't have them reactively do anything yet:
function createProjectObserver() {
const projectDisposer = autorun(() => {
const project = self.project
const workflow = tryReference(() => self.active)
if (project && !workflow) {
// TODO request for the workflow if project has changed and there isn't one already
// self.reset()
// selectWorkflow(workflowID, workflow.subjectSetID)
}
}, { name: 'Workflow Store Project Observer autorun' })
addDisposer(self, projectDisposer)
}
function createUPPObserver() {
const uppDisposer = autorun(() => {
const upp = tryReference(() => getRoot(self).userProjectPreferences?.active)
const workflow = tryReference(() => self.active)
if (upp && !workflow) {
// TODO validate and get workflow id from UPP to select
// self.reset()
// selectWorkflow()
}
}, { name: 'Workflow Store UPP Observer autorun' })
addDisposer(self, uppDisposer)
}
One potential enhancement of this (but outside the scope of this PR): fetch the workflow and subject set in getServerSideProps so that the workflow and subject set titles can be added to the page title (useful for bookmarking and for SEO.) The full workflow and subject set objects could then be passed into the classifier as props, similar to how projects are handled at the moment.
Agreed that this is out of scope, but again, I think I'd prefer we lean toward taking a snapshot (from prop or somewhere else?), which could be used in the constructor of the Classifier where the store is initialized. The snapshot could be defined to have full resources or to just have ids that the classifier could then use to make requests as needed. I don't want to have to depend a whole lot on logic happening in either a componentDidMount
or hooks to setup the classifier.
Anyway, I've tested this using the production project app starting with this URL:
http://localhost.zooniverse.org:3000/projects/darkeshard/engaging-the-crowds-2020/classify/workflow/15652/subject-set/85773?env=production
And confirmed that the requested workflow matched 15652, subject set matched 85773, and the queued endpoint correctly added those as query params.
Then I navigated to the home page and selected a new workflow and subject set:
http://localhost.zooniverse.org:3000/projects/darkeshard/engaging-the-crowds-2020/classify/workflow/16106/subject-set/85771
And I confirmed the requested workflow id is 16106, subject set is 85771, and the queued endpoint correctly added those query params.
Then back to the homepage and selected a non-grouped workflow, id 15651 aka "Drawing Workflow", and it correctly requested it and used it for the queued endpoint, but the route in the URL did not have the id. This is out of scope here, but I would expect the URL to have this workflow id as well.
this.setProject(project) | ||
this.classifierStore.setOnAddToCollection(onAddToCollection) | ||
this.classifierStore.classifications.setOnComplete(onCompleteClassification) | ||
this.classifierStore.setOnToggleFavourite(onToggleFavourite) | ||
this.classifierStore.workflows.selectWorkflow(workflowID, subjectSetID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would prefer on continuing to rely the reactive paradigm we have setup using observers in the stores for asynchronous request or setup of resources in the store. However, I think that will take some additional refactoring that is out of scope here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't come up with a good way to pass the classifier props down into the workflow store, except by calling an action directly. If this block could be replaced with store.create(snapshot)
, that would be great.
I think 15651 might be the default workflow. Those are routed to Lines 26 to 31 in d8f1071
|
I'm going to open a PR to restore the observers. One scenario I tested here in the project app was to log in, check that the subject queue refreshed with my personal subject queue, then log out and check that it refreshed using the random subject selector. I can see a case for observing user changes in order to handle that inside the standalone classifier. |
Restore the workflow store observers, which reload workflows when the stored project or user project preferences change. These were deleted in #1793 because they either override the stored workflow with the project default, or throw reference errors in the store.
Restore the workflow store observers, which reload workflows when the stored project or user project preferences change. These were deleted in #1793 because they either override the stored workflow with the project default, or throw reference errors in the store. Co-authored-by: srallen <[email protected]>
Package:
lib-classifier
Closes #1792
Explicitly call the
workflows.selectWorkflow(workflowID)
action when the classifier mounts. Pass in anyworkflowID
prop that was passed to the classifier, otherwise fallback to default project workflow selection. Remove theselectWorkflow()
actions that automatically run when the project or UPP loads.Add an optional
subjectSetID
parameter, which will restrict subject selection to that subject set:workflows.selectWorkflow(workflowID, subjectSetID)
.Workflow and subject set IDs are validated against a project's linked active workflows and a workflow's linked subject sets before being loaded.
Review Checklist
General
Components
Apps
yarn panic && yarn bootstrap
ordocker-compose up --build
and app works as expected?Publishing
Post-merging