From 3a357f66ff43d1806c8a632c6d8115283f3dc866 Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Tue, 7 Jul 2020 23:54:30 +0530 Subject: [PATCH 1/8] added new search api for navigation purposes --- backend/routes/projects.py | 103 +++++++++++++++++++++++++++++++++ frontend/src/pages/annotate.js | 54 ++++++++++++++++- 2 files changed, 154 insertions(+), 3 deletions(-) diff --git a/backend/routes/projects.py b/backend/routes/projects.py index 539580e..fc0e5f9 100644 --- a/backend/routes/projects.py +++ b/backend/routes/projects.py @@ -516,6 +516,109 @@ def update_data(project_id, data_id): ) +@api.route("/projects//search/", methods=["GET"]) +@jwt_required +def search_data(project_id, data_id): + """Returns the next and the prior in the queue for the category + """ + identity = get_jwt_identity() + + try: + request_user = User.query.filter_by( + username=identity["username"]).first() + project = Project.query.get(project_id) + + if request_user not in project.users: + return jsonify(message="Unauthorized access!"), 401 + + # The data whose neighbours we want + currdata = Data.query.filter_by( + id=data_id, project_id=project_id).first() + + if currdata.segmentations: + pagetype = "Annotated" + else: + pagetype = "Yet To annotate" + + # if currdata.is_marked_for_review: + # pagetype = "Review" + + + # if pagetype == "All": + # data = ( + # db.session.query(Data) + # .filter(Data.project_id == project_id) + # # .filter(Data.id.in_(segmentations)) + # # .filter(Data.id.notin_(segmentations)) + # .distinct() + # .order_by(Data.created_at.desc())) + if pagetype == "Review": + data = ( + db.session.query(Data) + .filter(Data.project_id == project_id) + .filter(Data.is_marked_for_review) + .distinct() + .order_by(Data.created_at.desc())) + + elif pagetype == "Annotated": + segmentations = db.session.query( + Segmentation.data_id).distinct().subquery() + data = ( + db.session.query(Data) + .filter(Data.project_id == project_id) + .filter(Data.id.in_(segmentations)) + .distinct() + .order_by(Data.created_at.desc())) + + elif pagetype == "Yet To annotate": + segmentations = db.session.query( + Segmentation.data_id).distinct().subquery() + data = ( + db.session.query(Data) + .filter(Data.project_id == project_id) + .filter(Data.id.notin_(segmentations)) + .distinct() + .order_by(Data.created_at.desc())) + + else: + raise Exception("This is not the right way of using this API") + + before, after = data[0], data[-1] + index = list(data).index(currdata) + # Bottom is an alternative of above + # nextctr = 0 + # for dat in data: + # app.logger.info(f"interation {dat.id}") + # if nextctr == 1: + # nextdata = dat + # break + # if dat == currdata: + # nextctr = 1 + # else: + # lastone = dat + + before, after = data[index-1], data[index+1] + + except Exception as e: + app.logger.error(f"Error searching data") + app.logger.error(e) + return ( + jsonify(message=f"Error searching data", + type="DATA_SEARCHED_FAILED"), + 500, + ) + + return ( + jsonify( + after_id=after.id, + before_id=before.id, + message=f"Data Searched", + type="DATA_SEARCHED", + ), + 200, + ) + + @api.route( "/projects//data//segmentations", methods=["POST"] ) diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index f529fcb..8bafc2c 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -13,6 +13,7 @@ import { faBackward, faForward, faPlayCircle, + faCoffee, faPauseCircle, } from "@fortawesome/free-solid-svg-icons"; import Alert from "../components/alert"; @@ -30,9 +31,13 @@ class Annotate extends React.Component { isPlaying: false, projectId, dataId, + after_id: -1, + before_id: -1, labels: {}, labelsUrl: `/api/projects/${projectId}/labels`, + searchUrl: `/api/projects/${projectId}/search/${dataId}`, dataUrl: `/api/projects/${projectId}/data/${dataId}`, + annotationUrl: `projects/${projectId}/data/${dataId}/annotate`, segmentationUrl: `/api/projects/${projectId}/data/${dataId}/segmentations`, isDataLoading: false, wavesurfer: null, @@ -50,7 +55,7 @@ class Annotate extends React.Component { } componentDidMount() { - const { labelsUrl, dataUrl } = this.state; + const { labelsUrl, dataUrl, searchUrl } = this.state; this.setState({ isDataLoading: true }); const wavesurfer = WaveSurfer.create({ container: "#waveform", @@ -96,7 +101,8 @@ class Annotate extends React.Component { }); axios - .all([axios.get(labelsUrl), axios.get(dataUrl)]) + .all([axios.get(labelsUrl), axios.get(dataUrl), axios.get(searchUrl)]) + // .all([axios.get(labelsUrl), axios.get(dataUrl)]) .then((response) => { this.setState({ isDataLoading: false, @@ -122,7 +128,14 @@ class Annotate extends React.Component { }; }); + const { + after_id, + before_id + } = response[2].data; + this.setState({ + after_id, + before_id, isDataLoading: false, referenceTranscription: reference_transcription, isMarkedForReview: is_marked_for_review, @@ -179,6 +192,21 @@ class Annotate extends React.Component { wavesurfer.skipBackward(5); } + handleNextAnnotation() { + const { projectId, after_id } = this.state; + let path = `/projects/${projectId}/data/${after_id}/annotate`; + this.props.history.push(path); + window.location.reload(); + // this.props.history.push("https://stackoverflow.com/questions/50644976/react-button-onclick-redirect-page"); + } + + handlePreviousAnnotation() { + const { projectId, before_id } = this.state; + let path = `/projects/${projectId}/data/${before_id}/annotate`; + this.props.history.push(path); + window.location.reload(); + } + handleZoom(e) { const { wavesurfer } = this.state; const zoom = Number(e.target.value); @@ -391,6 +419,16 @@ class Annotate extends React.Component { {!isDataLoading ? (
+
+ { + this.handlePreviousAnnotation(); + }} + /> +
+
+ { + this.handleNextAnnotation(); + }} + /> +
@@ -573,7 +621,7 @@ class Annotate extends React.Component { className="form-check-label" htmlFor="isMarkedForReview" > - Mark for review + Mark for review
From 5565344114d245c7fe29c9a3dcd06ab2d3d34d40 Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Wed, 8 Jul 2020 19:51:04 +0530 Subject: [PATCH 2/8] temp --- backend/routes/data.py | 58 +++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/backend/routes/data.py b/backend/routes/data.py index 0984c0b..d55b253 100644 --- a/backend/routes/data.py +++ b/backend/routes/data.py @@ -9,7 +9,7 @@ from werkzeug.utils import secure_filename from backend import app, db -from backend.models import Data, Project, User +from backend.models import Data, Project, User, Segmentation from . import api @@ -60,17 +60,50 @@ def add_data(): try: - data = Data( - project_id=project.id, - filename=filename, - original_filename=original_filename, - reference_transcription=reference_transcription, - is_marked_for_review=is_marked_for_review, - assigned_user_id=user.id, + segmentations = db.session.query( + Segmentation.data_id).distinct().subquery() + + currdata = Data.query.filter_by(id="82", project_id="4").first() + data = {} + data = ( + db.session.query(Data) + # .filter(Data.assigned_user_id == "1") + .filter(Data.project_id == "4") + # .filter(Data.id.in_(segmentations)) + .filter(Data.id.notin_(segmentations)) + .distinct() + .order_by(Data.created_at.desc()) ) - db.session.add(data) - db.session.commit() - db.session.refresh(data) + before, after = data[0], data[-1] + index = list(data).index(currdata) + before, after = data[index-1], data[index+1] + + # nextctr = 0 + # for dat in data: + # app.logger.info(f"interation {dat.id}") + # if nextctr == 1: + # nextdata = dat + # break + # if dat == currdata: + # nextctr = 1 + # else: + # lastone = dat + + app.logger.info(f"Total numer of data is {currdata}") + app.logger.info( + f"Total numer of segmentations is {currdata.is_marked_for_review}") + # app.logger.info(f"Total numer of segmentations is {len(segmentations)}") + # data = Data( + # project_id=project.id, + # filename=filename, + # original_filename=original_filename, + # reference_transcription=reference_transcription, + # is_marked_for_review=is_marked_for_review, + # assigned_user_id=user.id, + # ) + # db.session.add(data) + # db.session.commit() + # db.session.refresh(data) except Exception as e: app.logger.error(f"Error adding data to project: {project.name}") app.logger.error(e) @@ -84,7 +117,8 @@ def add_data(): return ( jsonify( - data_id=data.id, + data_id="69", + # data_id=data.id, message=f"Data uploaded, created and assigned successfully", type="DATA_CREATED", ), From 5ecbd2bc15088bd419ae055b13c1764874c5c75f Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Wed, 8 Jul 2020 21:04:05 +0530 Subject: [PATCH 3/8] added icons and dep code from backend --- backend/routes/projects.py | 20 -------------------- frontend/src/pages/annotate.js | 7 ++++--- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/backend/routes/projects.py b/backend/routes/projects.py index fc0e5f9..df31826 100644 --- a/backend/routes/projects.py +++ b/backend/routes/projects.py @@ -544,14 +544,6 @@ def search_data(project_id, data_id): # pagetype = "Review" - # if pagetype == "All": - # data = ( - # db.session.query(Data) - # .filter(Data.project_id == project_id) - # # .filter(Data.id.in_(segmentations)) - # # .filter(Data.id.notin_(segmentations)) - # .distinct() - # .order_by(Data.created_at.desc())) if pagetype == "Review": data = ( db.session.query(Data) @@ -585,18 +577,6 @@ def search_data(project_id, data_id): before, after = data[0], data[-1] index = list(data).index(currdata) - # Bottom is an alternative of above - # nextctr = 0 - # for dat in data: - # app.logger.info(f"interation {dat.id}") - # if nextctr == 1: - # nextdata = dat - # break - # if dat == currdata: - # nextctr = 1 - # else: - # lastone = dat - before, after = data[index-1], data[index+1] except Exception as e: diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index 8bafc2c..9befbc5 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -13,7 +13,8 @@ import { faBackward, faForward, faPlayCircle, - faCoffee, + faArrowRight, + faArrowLeft, faPauseCircle, } from "@fortawesome/free-solid-svg-icons"; import Alert from "../components/alert"; @@ -421,7 +422,7 @@ class Annotate extends React.Component {
{ @@ -473,7 +474,7 @@ class Annotate extends React.Component {
{ From 7217e4616cf165fc2e218f44575586a750ea84fc Mon Sep 17 00:00:00 2001 From: Manraj Singh Date: Sat, 11 Jul 2020 19:14:09 +0530 Subject: [PATCH 4/8] Update frontend/src/pages/annotate.js --- frontend/src/pages/annotate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index 9befbc5..8f94996 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -622,7 +622,7 @@ class Annotate extends React.Component { className="form-check-label" htmlFor="isMarkedForReview" > - Mark for review + Mark for review
From a29202e5616f41582d7e1d3d1993b96d9d83ad89 Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Sat, 12 Sep 2020 19:50:16 +0530 Subject: [PATCH 5/8] better navigation support --- backend/routes/data.py | 71 +++++----------------------------- backend/routes/projects.py | 27 +++++++------ frontend/src/pages/annotate.js | 11 +++--- 3 files changed, 30 insertions(+), 79 deletions(-) diff --git a/backend/routes/data.py b/backend/routes/data.py index 7aa3312..aaf88d0 100644 --- a/backend/routes/data.py +++ b/backend/routes/data.py @@ -68,10 +68,12 @@ def generate_segmentation( values = [] for label_name, val in annotations.items(): - label = Label.query.filter_by(name=label_name, project_id=project_id).first() + label = Label.query.filter_by( + name=label_name, project_id=project_id).first() if label is None: - raise NotFound(description=f"Label not found with name: `{label_name}`") + raise NotFound( + description=f"Label not found with name: `{label_name}`") if "values" not in val: raise BadRequest( @@ -116,7 +118,8 @@ def add_data(): api_key = request.headers.get("Authorization", None) if not api_key: - raise BadRequest(description="API Key missing from `Authorization` Header") + raise BadRequest( + description="API Key missing from `Authorization` Header") project = Project.query.filter_by(api_key=api_key).first() @@ -131,7 +134,8 @@ def add_data(): segmentations = request.form.get("segmentations", "[]") reference_transcription = request.form.get("reference_transcription", None) - is_marked_for_review = bool(request.form.get("is_marked_for_review", False)) + is_marked_for_review = bool( + request.form.get("is_marked_for_review", False)) audio_file = request.files["audio_file"] original_filename = secure_filename(audio_file.filename) @@ -163,61 +167,6 @@ def add_data(): for segment in segmentations: validated = validate_segmentation(segment) -<<<<<<< HEAD - segmentations = db.session.query( - Segmentation.data_id).distinct().subquery() - - currdata = Data.query.filter_by(id="82", project_id="4").first() - data = {} - data = ( - db.session.query(Data) - # .filter(Data.assigned_user_id == "1") - .filter(Data.project_id == "4") - # .filter(Data.id.in_(segmentations)) - .filter(Data.id.notin_(segmentations)) - .distinct() - .order_by(Data.created_at.desc()) - ) - before, after = data[0], data[-1] - index = list(data).index(currdata) - before, after = data[index-1], data[index+1] - - # nextctr = 0 - # for dat in data: - # app.logger.info(f"interation {dat.id}") - # if nextctr == 1: - # nextdata = dat - # break - # if dat == currdata: - # nextctr = 1 - # else: - # lastone = dat - - app.logger.info(f"Total numer of data is {currdata}") - app.logger.info( - f"Total numer of segmentations is {currdata.is_marked_for_review}") - # app.logger.info(f"Total numer of segmentations is {len(segmentations)}") - # data = Data( - # project_id=project.id, - # filename=filename, - # original_filename=original_filename, - # reference_transcription=reference_transcription, - # is_marked_for_review=is_marked_for_review, - # assigned_user_id=user.id, - # ) - # db.session.add(data) - # db.session.commit() - # db.session.refresh(data) - except Exception as e: - app.logger.error(f"Error adding data to project: {project.name}") - app.logger.error(e) - return ( - jsonify( - message=f"Error adding data to project: {project.name}", - type="DATA_CREATION_FAILED", - ), - 500, -======= if not validated: raise BadRequest(description=f"Segmentations have missing keys.") @@ -228,7 +177,6 @@ def add_data(): start_time=segment["start_time"], annotations=segment.get("annotations", {}), transcription=segment["transcription"], ->>>>>>> upstream/master ) new_segmentations.append(new_segment) @@ -240,8 +188,7 @@ def add_data(): return ( jsonify( - data_id="69", - # data_id=data.id, + data_id=data.id, message=f"Data uploaded, created and assigned successfully", type="DATA_CREATED", ), diff --git a/backend/routes/projects.py b/backend/routes/projects.py index ad6911d..6d54c30 100644 --- a/backend/routes/projects.py +++ b/backend/routes/projects.py @@ -515,10 +515,11 @@ def update_data(project_id, data_id): ) -@api.route("/projects//search/", methods=["GET"]) +@api.route("/projects//neighbours/", methods=["GET"]) @jwt_required -def search_data(project_id, data_id): - """Returns the next and the prior in the queue for the category +def neighbours_data(project_id, data_id): + """ + Returns dataId s for the next and previous data """ identity = get_jwt_identity() @@ -530,7 +531,6 @@ def search_data(project_id, data_id): if request_user not in project.users: return jsonify(message="Unauthorized access!"), 401 - # The data whose neighbours we want currdata = Data.query.filter_by( id=data_id, project_id=project_id).first() @@ -538,7 +538,7 @@ def search_data(project_id, data_id): pagetype = "Annotated" else: pagetype = "Yet To annotate" - + # if currdata.is_marked_for_review: # pagetype = "Review" @@ -562,21 +562,24 @@ def search_data(project_id, data_id): .order_by(Data.created_at.desc())) elif pagetype == "Yet To annotate": - segmentations = db.session.query( - Segmentation.data_id).distinct().subquery() + # segmentations = db.session.query( + # Segmentation.data_id).distinct().subquery() data = ( db.session.query(Data) .filter(Data.project_id == project_id) - .filter(Data.id.notin_(segmentations)) .distinct() - .order_by(Data.created_at.desc())) + # .order_by(Data.id) + ) + # .filter(Data.id.notin_(segmentations)) else: raise Exception("This is not the right way of using this API") - before, after = data[0], data[-1] - index = list(data).index(currdata) - before, after = data[index-1], data[index+1] + if currdata.id == data[0].id or currdata.id == data[-1].id: + before, after = data[0], data[-1] + else: + index = list(data).index(currdata) + before, after = data[index-1], data[index+1] except Exception as e: app.logger.error(f"Error searching data") diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index 9f8a82c..d2a4f36 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -36,7 +36,7 @@ class Annotate extends React.Component { before_id: -1, labels: {}, labelsUrl: `/api/projects/${projectId}/labels`, - searchUrl: `/api/projects/${projectId}/search/${dataId}`, + searchUrl: `/api/projects/${projectId}/neighbours/${dataId}`, dataUrl: `/api/projects/${projectId}/data/${dataId}`, annotationUrl: `projects/${projectId}/data/${dataId}/annotate`, segmentationUrl: `/api/projects/${projectId}/data/${dataId}/segmentations`, @@ -103,7 +103,6 @@ class Annotate extends React.Component { axios .all([axios.get(labelsUrl), axios.get(dataUrl), axios.get(searchUrl)]) - // .all([axios.get(labelsUrl), axios.get(dataUrl)]) .then((response) => { this.setState({ isDataLoading: false, @@ -117,6 +116,8 @@ class Annotate extends React.Component { filename, } = response[1].data; + console.log("This was the reponse from the thing: ", response) + const regions = segmentations.map((segmentation) => { return { start: segmentation.start_time, @@ -206,7 +207,7 @@ class Annotate extends React.Component { let path = `/projects/${projectId}/data/${before_id}/annotate`; this.props.history.push(path); window.location.reload(); - } + } handleZoom(e) { const { wavesurfer } = this.state; @@ -429,7 +430,7 @@ class Annotate extends React.Component { this.handlePreviousAnnotation(); }} /> -
+
-
+
From 0957849d66dbaccc1694cd27b47f86c0fdb760d6 Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Sat, 12 Sep 2020 19:55:20 +0530 Subject: [PATCH 6/8] default to currentId and better edge-case handling --- backend/routes/projects.py | 12 ++++++------ frontend/src/pages/annotate.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/routes/projects.py b/backend/routes/projects.py index 6d54c30..18d59c3 100644 --- a/backend/routes/projects.py +++ b/backend/routes/projects.py @@ -562,25 +562,25 @@ def neighbours_data(project_id, data_id): .order_by(Data.created_at.desc())) elif pagetype == "Yet To annotate": - # segmentations = db.session.query( - # Segmentation.data_id).distinct().subquery() data = ( db.session.query(Data) .filter(Data.project_id == project_id) .distinct() - # .order_by(Data.id) ) - # .filter(Data.id.notin_(segmentations)) else: raise Exception("This is not the right way of using this API") - if currdata.id == data[0].id or currdata.id == data[-1].id: - before, after = data[0], data[-1] + if currdata.id == data[-1].id: + # if currdata.id == data[0].id or currdata.id == data[-1].id: + index = list(data).index(currdata) + before, after = data[index-1], data[0] else: index = list(data).index(currdata) before, after = data[index-1], data[index+1] + app.logger.info(f"The nieghbours are: {before, after}") + except Exception as e: app.logger.error(f"Error searching data") app.logger.error(e) diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index d2a4f36..294f142 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -32,8 +32,8 @@ class Annotate extends React.Component { isPlaying: false, projectId, dataId, - after_id: -1, - before_id: -1, + after_id: dataId, + before_id: dataId, labels: {}, labelsUrl: `/api/projects/${projectId}/labels`, searchUrl: `/api/projects/${projectId}/neighbours/${dataId}`, From 731ff647d42813d6e68f608583471355080404ba Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Sat, 12 Sep 2020 19:56:41 +0530 Subject: [PATCH 7/8] renamed to neighbourUrl --- frontend/src/pages/annotate.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index 294f142..f86c591 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -36,7 +36,7 @@ class Annotate extends React.Component { before_id: dataId, labels: {}, labelsUrl: `/api/projects/${projectId}/labels`, - searchUrl: `/api/projects/${projectId}/neighbours/${dataId}`, + neighboursUrl: `/api/projects/${projectId}/neighbours/${dataId}`, dataUrl: `/api/projects/${projectId}/data/${dataId}`, annotationUrl: `projects/${projectId}/data/${dataId}/annotate`, segmentationUrl: `/api/projects/${projectId}/data/${dataId}/segmentations`, @@ -56,7 +56,7 @@ class Annotate extends React.Component { } componentDidMount() { - const { labelsUrl, dataUrl, searchUrl } = this.state; + const { labelsUrl, dataUrl, neighboursUrl } = this.state; this.setState({ isDataLoading: true }); const wavesurfer = WaveSurfer.create({ container: "#waveform", @@ -102,7 +102,7 @@ class Annotate extends React.Component { }); axios - .all([axios.get(labelsUrl), axios.get(dataUrl), axios.get(searchUrl)]) + .all([axios.get(labelsUrl), axios.get(dataUrl), axios.get(neighboursUrl)]) .then((response) => { this.setState({ isDataLoading: false, From ceeb9213fe9ef430fa8cfe54e8f8bb6d288fb9db Mon Sep 17 00:00:00 2001 From: dumbmachine Date: Sat, 12 Sep 2020 20:04:09 +0530 Subject: [PATCH 8/8] minor refactor and removed window.location.reload --- frontend/src/pages/annotate.js | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/frontend/src/pages/annotate.js b/frontend/src/pages/annotate.js index f86c591..8a7afb8 100644 --- a/frontend/src/pages/annotate.js +++ b/frontend/src/pages/annotate.js @@ -32,8 +32,8 @@ class Annotate extends React.Component { isPlaying: false, projectId, dataId, - after_id: dataId, - before_id: dataId, + afterId: -1, + beforeId: -1, labels: {}, labelsUrl: `/api/projects/${projectId}/labels`, neighboursUrl: `/api/projects/${projectId}/neighbours/${dataId}`, @@ -136,8 +136,8 @@ class Annotate extends React.Component { } = response[2].data; this.setState({ - after_id, - before_id, + afterId: after_id, + beforeId: before_id, isDataLoading: false, referenceTranscription: reference_transcription, isMarkedForReview: is_marked_for_review, @@ -195,18 +195,23 @@ class Annotate extends React.Component { } handleNextAnnotation() { - const { projectId, after_id } = this.state; - let path = `/projects/${projectId}/data/${after_id}/annotate`; - this.props.history.push(path); - window.location.reload(); - // this.props.history.push("https://stackoverflow.com/questions/50644976/react-button-onclick-redirect-page"); + const { history } = this.props; + const { projectId, afterId } = this.state; + const path = `/projects/${projectId}/data/${afterId}/annotate`; + history.replace({ pathname: "/empty" }); + setTimeout(() => { + history.replace({ pathname: path }); + }); } handlePreviousAnnotation() { - const { projectId, before_id } = this.state; - let path = `/projects/${projectId}/data/${before_id}/annotate`; - this.props.history.push(path); - window.location.reload(); + const { history } = this.props; + const { projectId, beforeId } = this.state; + const path = `/projects/${projectId}/data/${beforeId}/annotate`; + history.replace({ pathname: "/empty" }); + setTimeout(() => { + history.replace({ pathname: path }); + }); } handleZoom(e) {