From 1e13746ce95e06a73660ac13de01bdead8310015 Mon Sep 17 00:00:00 2001 From: Boris Sekachev <40690378+bsekachev@users.noreply.github.com> Date: Mon, 25 Mar 2019 04:15:15 +0300 Subject: [PATCH] Integration of REST/API in client #3 (#357) * Fixed polygon tracks, icons for jstree * Dashboard search * Fixed changing of job status --- .../static/dashboard/js/dashboard.js | 66 ++++++++++++++----- cvat/apps/dextr_segmentation/views.py | 7 +- .../engine/static/engine/js/annotationUI.js | 30 +++++---- .../static/engine/js/shapeCollection.js | 3 +- cvat/apps/engine/static/engine/js/shapes.js | 5 +- 5 files changed, 71 insertions(+), 40 deletions(-) diff --git a/cvat/apps/dashboard/static/dashboard/js/dashboard.js b/cvat/apps/dashboard/static/dashboard/js/dashboard.js index c8bbc6626920..59fa359938d7 100644 --- a/cvat/apps/dashboard/static/dashboard/js/dashboard.js +++ b/cvat/apps/dashboard/static/dashboard/js/dashboard.js @@ -294,17 +294,41 @@ class DashboardView { } _setupTaskSearch() { - function getUrlParameter(name) { - let regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); - let results = regex.exec(window.location.search); - return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); - } + const searchInput = $('#dashboardSearchInput'); + const searchSubmit = $('#dashboardSearchSubmit'); - let searchInput = $('#dashboardSearchInput'); - let searchSubmit = $('#dashboardSearchSubmit'); + searchInput.on('keypress', (e) => { + if (e.keyCode != 13) { + return; + } - let line = getUrlParameter('search') || ''; - searchInput.val(line); + const params = {}; + const search = e.target.value.replace(/\s+/g, ' ').replace(/\s*:+\s*/g, ':').trim(); + for (let field of ['name', 'mode', 'owner', 'assignee', 'status']) { + for (let param of search.split(' and ')) { + if (param.includes(':')) { + param = param.split(':'); + if (param[0] === field && param[1]) { + params[field] = param[1]; + } + } + } + } + + if (!Object.keys(params).length && search.length) { + params['search'] = search; + } + + if (Object.keys(params).length) { + const searchParams = new URLSearchParams(); + for (let key in params) { + searchParams.set(key, params[key]); + } + window.location.search = searchParams.toString(); + } else { + window.location.search = ''; + } + }); searchSubmit.on('click', function() { let e = $.Event('keypress'); @@ -312,12 +336,19 @@ class DashboardView { searchInput.trigger(e); }); - searchInput.on('keypress', function(e) { - if (e.keyCode !== 13) return; - let filter = e.target.value; - if (!filter) window.location.search = ''; - else window.location.search = `search=${filter}`; - }); + const searchParams = new URLSearchParams(window.location.search.substring(1)); + if (searchParams.get('all')) { + searchInput.prop('value', searchParams.get('all')); + } else { + let search = ''; + for (let field of ['name', 'mode', 'owner', 'assignee', 'status']) { + const fieldVal = searchParams.get(field); + if (fieldVal) { + search += `${field}: ${fieldVal} and `; + } + } + searchInput.prop('value', search.slice(0, -5)); + } } _setupCreateDialog() { @@ -471,9 +502,10 @@ class DashboardView { return { id: `${obj.id}/${element.name}`, children: element.type === 'DIR', - text: element.name} + text: element.name, + icon: element.type === 'DIR' ? 'jstree-folder' : 'jstree-file', } - ); + }); callback.call(this, files); } diff --git a/cvat/apps/dextr_segmentation/views.py b/cvat/apps/dextr_segmentation/views.py index de99caeedb5a..b1daee347320 100644 --- a/cvat/apps/dextr_segmentation/views.py +++ b/cvat/apps/dextr_segmentation/views.py @@ -6,9 +6,8 @@ from cvat.apps.authentication.decorators import login_required from rules.contrib.views import permission_required, objectgetter -from cvat.apps.engine.models import Job +from cvat.apps.engine.models import Job, Task from cvat.apps.engine.log import slogger -from cvat.apps.engine.task import get_frame_path from cvat.apps.dextr_segmentation.dextr import DEXTR_HANDLER import django_rq @@ -39,8 +38,8 @@ def create(request, jid): slogger.job[jid].info("create dextr request for the JOB: {} ".format(jid) + "by the USER: {} on the FRAME: {}".format(username, frame)) - tid = Job.objects.select_related("segment__task").get(id=jid).segment.task.id - im_path = os.path.realpath(get_frame_path(tid, frame)) + db_task = Job.objects.select_related("segment__task").get(id=jid).segment.task + im_path = os.path.realpath(db_task.get_frame_path(frame)) queue = django_rq.get_queue(__RQ_QUEUE_NAME) rq_id = "dextr.create/{}/{}".format(jid, username) diff --git a/cvat/apps/engine/static/engine/js/annotationUI.js b/cvat/apps/engine/static/engine/js/annotationUI.js index b93619d38d03..b458b06660b0 100644 --- a/cvat/apps/engine/static/engine/js/annotationUI.js +++ b/cvat/apps/engine/static/engine/js/annotationUI.js @@ -248,7 +248,7 @@ function buildAnnotationUI(jobData, taskData, imageMetaData, annotationData, loa setupHelpWindow(shortkeys); setupSettingsWindow(); - setupMenu(taskData, shapeCollectionModel, annotationParser, aamModel, playerModel, historyModel); + setupMenu(jobData, taskData, shapeCollectionModel, annotationParser, aamModel, playerModel, historyModel); setupFrameFilters(); setupShortkeys(shortkeys, { aam: aamModel, @@ -457,7 +457,7 @@ function setupSettingsWindow() { } -function setupMenu(task, shapeCollectionModel, annotationParser, aamModel, playerModel, historyModel) { +function setupMenu(job, task, shapeCollectionModel, annotationParser, aamModel, playerModel, historyModel) { let annotationMenu = $('#annotationMenu'); let menuButton = $('#menuButton'); @@ -537,18 +537,20 @@ function setupMenu(task, shapeCollectionModel, annotationParser, aamModel, playe $('#statOverlap').text(task.overlap); $('#statZOrder').text(task.z_order); $('#statFlipped').text(task.flipped); - $('#statTaskStatus').prop("value", task.status).on('change', (e) => { - $.ajax({ - type: 'PATCH', - url: '/api/v1/jobs/' + window.cvat.job.id, - data: JSON.stringify({ - status: e.target.value - }), - contentType: "application/json; charset=utf-8", - error: (data) => { - showMessage(`Can not change job status. Code: ${data.status}. Message: ${data.responeText || data.statusText}`); - } - }); + $('#statTaskStatus').prop('value', job.status).on('change', async function(e) { + try { + job.status = e.target.value; + await $.ajax({ + url: `/api/v1/jobs/${window.cvat.job.id}`, + type: 'PATCH', + data: JSON.stringify(job), + contentType: 'application/json', + }); + } catch (errorData) { + const message = `Can not update a job status. Code: ${errorData.status}. ` + + `Message: ${errorData.responseText || errorData.statusText}`; + showMessage(message); + } }); let shortkeys = window.cvat.config.shortkeys; diff --git a/cvat/apps/engine/static/engine/js/shapeCollection.js b/cvat/apps/engine/static/engine/js/shapeCollection.js index 929b65556c9c..6ea6e3fa8029 100644 --- a/cvat/apps/engine/static/engine/js/shapeCollection.js +++ b/cvat/apps/engine/static/engine/js/shapeCollection.js @@ -287,9 +287,8 @@ class ShapeCollectionModel extends Listener { }; for (let shape of this._shapes) { - const exported = shape.export(); - if (!shape.removed) { + const exported = shape.export(); // Conversion from client object format to server object format if (exported.shapes) { for (let attr of exported.attributes) { diff --git a/cvat/apps/engine/static/engine/js/shapes.js b/cvat/apps/engine/static/engine/js/shapes.js index 110d6726f5b9..9aa221b12bb4 100644 --- a/cvat/apps/engine/static/engine/js/shapes.js +++ b/cvat/apps/engine/static/engine/js/shapes.js @@ -1026,12 +1026,11 @@ class PolyShapeModel extends ShapeModel { } } - track.shapes.push({ + track.shapes.push(Object.assign({ frame: +frame, attributes: shapeAttributes, - type: this._type.split('_')[1], - }, this._positions[frame]); + }, this._positions[frame])); } return track;