diff --git a/packages/mephisto-task-addons/src/VideoAnnotator/VideoPlayer.jsx b/packages/mephisto-task-addons/src/VideoAnnotator/VideoPlayer.jsx
index e5b10d7ea..9b3b0fb51 100644
--- a/packages/mephisto-task-addons/src/VideoAnnotator/VideoPlayer.jsx
+++ b/packages/mephisto-task-addons/src/VideoAnnotator/VideoPlayer.jsx
@@ -7,13 +7,7 @@
import React, { useEffect, useRef, useState } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
-
-const CHAPTERS_SETTINGS = {
- kind: "chapters",
- label: "Chapters",
- language: "en",
- mode: "showing",
-};
+import { CHAPTERS_SETTINGS } from "./constants";
function VideoPlayer({ chapters, className, onReady, options }) {
const videoRef = useRef(null);
@@ -21,6 +15,7 @@ function VideoPlayer({ chapters, className, onReady, options }) {
const [chaptersTrack, setChaptersTrack] = useState(null);
const [playerIsReady, setPlayerIsReady] = useState(false);
+ const [lastTimePressedPlay, setLastTimePressedPlay] = useState(false);
// ----- Methods -----
@@ -39,7 +34,7 @@ function VideoPlayer({ chapters, className, onReady, options }) {
track.mode = "disabled";
// Remove previously created cues to clear memory (I hope)
- if (track.cues) {
+ if (Array.isArray(track.cues)) {
[...track.cues].forEach((cue) => {
track.removeCue(cue);
});
@@ -89,6 +84,12 @@ function VideoPlayer({ chapters, className, onReady, options }) {
useEffect(() => {
const player = playerRef.current;
+ // Add time of previous pressing on Play button in HTML
+ // for HACK where we pause video in the end of current segment
+ player.on("play", () => {
+ setLastTimePressedPlay(player.currentTime());
+ });
+
return () => {
if (player && !player.isDisposed()) {
player.dispose();
@@ -104,7 +105,11 @@ function VideoPlayer({ chapters, className, onReady, options }) {
}, [chapters]);
return (
-
+
);
diff --git a/packages/mephisto-task-addons/src/VideoAnnotator/constants.js b/packages/mephisto-task-addons/src/VideoAnnotator/constants.js
new file mode 100644
index 000000000..181205909
--- /dev/null
+++ b/packages/mephisto-task-addons/src/VideoAnnotator/constants.js
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) Meta Platforms and its affiliates.
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+export const DELAY_PROGRESSBAR_RESIZING_MSEC = 1000;
+
+export const STORAGE_PRESAVED_ANNOTATION_TRACKS_KEY = "annotation_tracks";
+
+// In case if user does not specify any field
+export const DEFAULT_SEGMENT_FIELDS = [
+ {
+ id: "id_title",
+ label: "Segment name",
+ name: "title",
+ type: "input",
+ },
+];
+
+export const INIT_ANNOTATION_TRACK = {
+ title: "",
+ segments: {},
+};
+
+// When we click on segment, we simulate clicking on track as well, and it must be first,
+// but setting states is async
+export const DELAY_CLICK_ON_SECTION_MSEC = 200;
+
+export const START_NEXT_SECTION_PLUS_SEC = 0;
+
+export const COLORS = [
+ "blue",
+ "green",
+ "orange",
+ "purple",
+ "red",
+ "yellow",
+ "brown",
+];
+
+export const INIT_SECTION = {
+ description: "",
+ end_sec: 0,
+ start_sec: 0,
+ title: "",
+};
+
+export const MIN_SEGMENT_WIDTH_PX = 6;
+
+export const POPOVER_INVALID_SEGMENT_CLASS = "with-segment-validation";
+
+export const POPOVER_INVALID_SEGMENT_PROPS = {
+ "data-html": true,
+ "data-placement": "top",
+ "data-content": "Please fix provided data before continuing",
+ "data-toggle": "popover",
+ "data-trigger": "hover",
+};
+
+export const CHAPTERS_SETTINGS = {
+ kind: "chapters",
+ label: "Segments",
+ language: "en",
+ mode: "showing",
+};
diff --git a/packages/mephisto-task-addons/src/helpers/format.js b/packages/mephisto-task-addons/src/helpers/format.js
new file mode 100644
index 000000000..90b65cee6
--- /dev/null
+++ b/packages/mephisto-task-addons/src/helpers/format.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) Meta Platforms and its affiliates.
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+export function pluralizeString(str, num, str_plural) {
+ if (num !== 1) {
+ if (!!str_plural) {
+ return str_plural;
+ }
+ else{
+ let pluralizedEnding = '';
+ if (str.endsWith('s') || str.endsWith('ch')) {
+ pluralizedEnding = 'es';
+ }
+ else if (str.endsWith('z')) {
+ pluralizedEnding = 'zes';
+ }
+ else {
+ pluralizedEnding = 's';
+ }
+ return `${str}${pluralizedEnding}`;
+ }
+ }
+
+ return str;
+}
diff --git a/packages/mephisto-task-addons/src/helpers/index.js b/packages/mephisto-task-addons/src/helpers/index.js
new file mode 100644
index 000000000..08d121006
--- /dev/null
+++ b/packages/mephisto-task-addons/src/helpers/index.js
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) Meta Platforms and its affiliates.
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+export * from "./format";
diff --git a/packages/mephisto-task-addons/src/index.jsx b/packages/mephisto-task-addons/src/index.jsx
index b1bf69b52..4d1676cae 100644
--- a/packages/mephisto-task-addons/src/index.jsx
+++ b/packages/mephisto-task-addons/src/index.jsx
@@ -11,6 +11,7 @@ import {
TOKEN_START_SYMBOLS,
} from "./FormComposer/constants";
import * as FormComposerFields from "./FormComposer/fields";
+import * as helpers from "./helpers";
import { Errors as ListErrors } from "./FormComposer/fields/Errors";
import { FormComposer } from "./FormComposer/FormComposer";
import {
@@ -39,6 +40,7 @@ export {
VideoAnnotator,
VideoPlayer,
WorkerOpinion,
+ helpers,
prepareFormData,
prepareRemoteProcedures,
prepareVideoAnnotatorData,
diff --git a/test/generators/form_composer/config_validation/test_task_data_config.py b/test/generators/form_composer/config_validation/test_task_data_config.py
index 5df7cceef..97157a07c 100644
--- a/test/generators/form_composer/config_validation/test_task_data_config.py
+++ b/test/generators/form_composer/config_validation/test_task_data_config.py
@@ -23,6 +23,9 @@
from mephisto.generators.form_composer.config_validation.task_data_config import (
collect_unit_config_items_to_extrapolate,
)
+from mephisto.generators.form_composer.config_validation.task_data_config import (
+ verify_form_composer_configs,
+)
from mephisto.generators.generators_utils.config_validation.task_data_config import (
_collect_tokens_from_unit_config,
)
@@ -873,7 +876,7 @@ def test_verify_form_composer_configs_errors(self, *args, **kwargs):
captured_print_output = io.StringIO()
sys.stdout = captured_print_output
- verify_generator_configs(
+ verify_form_composer_configs(
task_data_config_path,
unit_config_path,
token_sets_values_config_path,
@@ -934,7 +937,7 @@ def test_verify_form_composer_configs_errors_task_data_config_only(self, *args,
captured_print_output = io.StringIO()
sys.stdout = captured_print_output
- verify_generator_configs(
+ verify_form_composer_configs(
task_data_config_path,
unit_config_path,
token_sets_values_config_path,
diff --git a/test/review_app/server/api/test_task_export_results_view.py b/test/review_app/server/api/test_task_export_results_view.py
index 3dc3f093a..6defa970b 100644
--- a/test/review_app/server/api/test_task_export_results_view.py
+++ b/test/review_app/server/api/test_task_export_results_view.py
@@ -62,7 +62,22 @@ def test_task_export_result_not_found_error(self, *args, **kwargs):
self.assertEqual(response.status_code, http_status.HTTP_404_NOT_FOUND)
- def test_task_export_result_not_reviews_error(self, *args, **kwargs):
+ @patch(
+ (
+ "mephisto.review_app.server.api.views.task_export_results_view."
+ "ENABLE_INCOMPLETE_TASK_RESULTS_EXPORT"
+ ),
+ False,
+ )
+ @patch("mephisto.review_app.server.api.views.task_export_results_view.check_if_task_reviewed")
+ def test_task_export_result_not_reviews_error(
+ self,
+ mock_check_if_task_reviewed,
+ *args,
+ **kwargs,
+ ):
+ mock_check_if_task_reviewed.return_value = False
+
unit_id = get_test_unit(self.db)
unit: Unit = Unit.get(self.db, unit_id)
unit.set_db_status(AssignmentState.COMPLETED)
diff --git a/test/review_app/server/api/test_tasks_view.py b/test/review_app/server/api/test_tasks_view.py
index c6f22bcc5..679b91809 100644
--- a/test/review_app/server/api/test_tasks_view.py
+++ b/test/review_app/server/api/test_tasks_view.py
@@ -38,7 +38,9 @@ def test_one_task_success(self, *args, **kwargs):
self.assertEqual(first_response_task["name"], task_name)
self.assertTrue("created_at" in first_response_task)
self.assertTrue("is_reviewed" in first_response_task)
- self.assertTrue("unit_count" in first_response_task)
+ self.assertTrue("unit_all_count" in first_response_task)
+ self.assertTrue("unit_completed_count" in first_response_task)
+ self.assertTrue("unit_finished_count" in first_response_task)
self.assertTrue("has_stats" in first_response_task)