diff --git a/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js b/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js index 1ec9ee978b..96839b2425 100644 --- a/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js +++ b/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js @@ -105,8 +105,6 @@ function InteractionLayer({ mark.setSubTaskVisibility(false) // Add a time value for tools that care about time. For most tools, this value is ignored. mark.setVideoTime(timeStamp, duration) - const markIDs = annotation.value?.map((mark) => mark.id) - annotation.update([...markIDs, mark.id]) } function onPointerDown(event) { diff --git a/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.js b/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.js index 908afd700f..2741762a6b 100644 --- a/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.js +++ b/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.js @@ -1,4 +1,5 @@ -import { getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree' +import { autorun } from 'mobx' +import { addDisposer, getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree' import DrawingTask from './DrawingTask' import Annotation from '../../models/Annotation' import * as markTypes from '@plugins/drawingTools/models/marks' @@ -11,33 +12,55 @@ const Drawing = types.model('Drawing', { value: types.array(types.safeReference(GenericMark)) }) .views(self => ({ - toSnapshot () { + /** + Resolve `annotation.task`, which is a task key, to its corresponding task object. + */ + get actualTask() { + return resolveIdentifier(DrawingTask, getRoot(self), self.task) + }, + + /** + Generate a snapshot in the format expected by Panoptes, Caesar etc. + See ADR 25. + https://github.com/zooniverse/front-end-monorepo/blob/master/docs/arch/adr-25.md + */ + toSnapshot() { const snapshot = getSnapshot(self) - // resolve mark references (IDs) in the snapshot to mark snapshots - const actualTask = resolveIdentifier(DrawingTask, getRoot(self), self.task) - const value = actualTask.marks.map(mark => getSnapshot(mark)) - const drawingSnapshot = Object.assign({}, snapshot, { value }) - // flatten subtask annotations into a single annotations array - // then return the flattened array + // Replace mark references (IDs) with mark snapshots. + const markSnapshots = self.value.map(mark => getSnapshot(mark)) + const drawingSnapshot = { ...snapshot, value: markSnapshots } + // Flatten subtask annotations into a single annotations array + // then return the flattened array. const drawingAnnotations = [drawingSnapshot] - drawingSnapshot.value.forEach((markSnapshot, markIndex) => { - const mark = Object.assign({}, markSnapshot) - // map subtask keys to mark.details + markSnapshots.forEach((markSnapshot, markIndex) => { + const mark = { ...markSnapshot } + // `mark.details` is an array of subtask keys. mark.details = mark.annotations.map(annotation => ({ task: annotation.task })) - // push mark.annotations to the returned array + // Push mark subtask annotations to the returned array. mark.annotations.forEach(markAnnotation => { - const finalAnnotation = Object.assign({}, markAnnotation, { markIndex }) - // strip annotation IDs - const { id, ...rest } = finalAnnotation - drawingAnnotations.push(rest) + // Strip annotation IDs and add markIndex. + const { id, ...rest } = markAnnotation + const finalAnnotation = { ...rest, markIndex } + drawingAnnotations.push(finalAnnotation) }) - // remove annotations from individual marks + // Remove annotations from individual marks. const { annotations, ...rest } = mark drawingSnapshot.value[markIndex] = rest }) return drawingAnnotations } })) + .actions(self => ({ + afterAttach() { + function _onMarksChange() { + // A drawing annotation stores an array of mark IDs for the corresponding task. + const newValue = self.actualTask.marks.map(mark => mark.id) + self.update(newValue) + } + + addDisposer(self, autorun(_onMarksChange)) + } + })) const DrawingAnnotation = types.compose('DrawingAnnotation', Annotation, Drawing) diff --git a/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.spec.js b/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.spec.js index 787a7ecaf7..019b17a45e 100644 --- a/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.spec.js +++ b/packages/lib-classifier/src/plugins/tasks/drawing/models/DrawingAnnotation.spec.js @@ -125,7 +125,8 @@ describe('Model > DrawingAnnotation', function () { }) const point2 = pointTool.createMark({ x: 150, - y: 200 + y: 200, + frame: 1 }) const questionTask = pointTool.tasks[0] point1.addAnnotation(questionTask, 0) @@ -181,7 +182,7 @@ describe('Model > DrawingAnnotation', function () { } const point2Snapshot = { details: [{ task: 'T0.0.0' }], - frame: 0, + frame: 1, toolIndex: 0, toolType: 'point', x: 150, diff --git a/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.js b/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.js index 874d04d0d6..ff7642cff3 100644 --- a/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.js +++ b/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.js @@ -1,4 +1,5 @@ -import { getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree' +import { autorun } from 'mobx' +import { addDisposer, getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree' import TranscriptionTask from './TranscriptionTask' import { TranscriptionLine } from '@plugins/drawingTools/models/marks' import Annotation from '../../../models/Annotation' @@ -8,35 +9,55 @@ const Transcription = types.model('Transcription', { value: types.array(types.safeReference(TranscriptionLine)) }) .views(self => ({ - // This is a copy of DrawingAnnotation's toSnapshot with the exception of - // Changing the task type to TranscriptionTask + /** + Resolve `annotation.task`, which is a task key, to its corresponding task object. + */ + get actualTask() { + return resolveIdentifier(TranscriptionTask, getRoot(self), self.task) + }, + + /** + Generate a snapshot in the format expected by Panoptes, Caesar etc. + See ADR 25. + https://github.com/zooniverse/front-end-monorepo/blob/master/docs/arch/adr-25.md + */ toSnapshot() { const snapshot = getSnapshot(self) - // resolve mark references (IDs) in the snapshot to mark snapshots - const actualTask = resolveIdentifier(TranscriptionTask, getRoot(self), self.task) - const value = actualTask.marks.map(mark => getSnapshot(mark)) - const drawingSnapshot = Object.assign({}, snapshot, { value }) - // flatten subtask annotations into a single annotations array - // then return the flattened array + // Replace mark references (IDs) with mark snapshots. + const markSnapshots = self.value.map(mark => getSnapshot(mark)) + const drawingSnapshot = { ...snapshot, value: markSnapshots } + // Flatten subtask annotations into a single annotations array + // then return the flattened array. const drawingAnnotations = [drawingSnapshot] - drawingSnapshot.value.forEach((markSnapshot, markIndex) => { - const mark = Object.assign({}, markSnapshot) - // map subtask keys to mark.details + markSnapshots.forEach((markSnapshot, markIndex) => { + const mark = { ...markSnapshot } + // `mark.details` is an array of subtask keys. mark.details = mark.annotations.map(annotation => ({ task: annotation.task })) - // push mark.annotations to the returned array + // Push mark subtask annotations to the returned array. mark.annotations.forEach(markAnnotation => { - const finalAnnotation = Object.assign({}, markAnnotation, { markIndex }) - // strip annotation IDs - const { id, ...rest } = finalAnnotation - drawingAnnotations.push(rest) + // Strip annotation IDs and add markIndex. + const { id, ...rest } = markAnnotation + const finalAnnotation = { ...rest, markIndex } + drawingAnnotations.push(finalAnnotation) }) - // remove annotations from individual marks + // Remove annotations from individual marks. const { annotations, ...rest } = mark drawingSnapshot.value[markIndex] = rest }) return drawingAnnotations } })) + .actions(self => ({ + afterAttach() { + function _onMarksChange() { + // A drawing annotation stores an array of mark IDs for the corresponding task. + const newValue = self.actualTask.marks.map(mark => mark.id) + self.update(newValue) + } + + addDisposer(self, autorun(_onMarksChange)) + } + })) const TranscriptionAnnotation = types.compose('TranscriptionAnnotation', Annotation, Transcription) diff --git a/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.spec.js b/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.spec.js index 2fb8a84639..3fda35e824 100644 --- a/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.spec.js +++ b/packages/lib-classifier/src/plugins/tasks/experimental/transcription/models/TranscriptionAnnotation.spec.js @@ -77,7 +77,8 @@ describe('Model > TranscriptionAnnotation', function () { x1: 150, x2: 175, y1: 200, - y2: 238 + y2: 238, + frame: 1 }) const textTask = transcriptionLineTool.tasks[0] transcriptionLine1.addAnnotation(textTask, 'foo') @@ -137,7 +138,7 @@ describe('Model > TranscriptionAnnotation', function () { } const transcriptionLine2Snapshot = { details: [{ task: 'T0.0.0' }], - frame: 0, + frame: 1, toolIndex: 0, toolType: 'transcriptionLine', x1: 150,