diff --git a/htdocs/lib/settings/ProfileList.js b/htdocs/lib/settings/ProfileList.js index 75ea728b..dcf9df9d 100644 --- a/htdocs/lib/settings/ProfileList.js +++ b/htdocs/lib/settings/ProfileList.js @@ -11,8 +11,12 @@ $.fn.profileList = function() { return !!$target.length; } - var moveProfile = function(profileId, index, callback) { - console.info('moving ' + profileId + ' to ' + index); + var moveProfile = function(profileId, index) { + return $.ajax(document.location.href + '/moveprofile', { + data: JSON.stringify({profile_id: profileId, index: index}), + contentType: 'application/json', + method: 'POST' + }); } this.each(function () { @@ -41,15 +45,22 @@ $.fn.profileList = function() { if (!isValidDrag(event)) return; event.preventDefault(); }).on('drop', function(event) { + if (!isValidDrag(event)) return; var $target = $(event.target).closest('.profile'); var index = $profileList.find('.profile').index($target); - moveProfile(event.originalEvent.dataTransfer.getData(dataType), index); - }).on('dragend', function(event) { + moveProfile(event.originalEvent.dataTransfer.getData(dataType), index).done(function() { + // done + }).fail(function() { + // backend reported error, restore original position + $profileEl.remove().insertBefore($profileList.children().eq(originalIndex)); + }).always(function() { + $profileEl = undefined; + }); + }).on('dragend', '.profile', function(event) { if (event.originalEvent.dataTransfer.dropEffect === 'none') { // drag was aborted - restore original position $profileEl.remove().insertBefore($profileList.children().eq(originalIndex)); } - $profileEl = undefined; }); }); } \ No newline at end of file diff --git a/owrx/controllers/settings/sdr.py b/owrx/controllers/settings/sdr.py index 6b1808d5..9440465c 100644 --- a/owrx/controllers/settings/sdr.py +++ b/owrx/controllers/settings/sdr.py @@ -16,6 +16,7 @@ from owrx.breadcrumb import BreadcrumbMixin, Breadcrumb, BreadcrumbItem from owrx.log import HistoryHandler from abc import ABCMeta, abstractmethod from uuid import uuid4 +import json class SdrDeviceBreadcrumb(SettingsBreadcrumb): @@ -258,6 +259,28 @@ class SdrDeviceController(SdrFormControllerWithModal): return return super().processFormData() + def moveProfile(self): + if self.device is None: + self.send_response("{}", content_type="application/json", code=404) + return + try: + data = json.loads(self.get_body().decode("utf-8")) + if "profile_id" not in data or "index" not in data: + self.send_response("{}", content_type="application/json", code=400) + return + profile_id = data["profile_id"] + index = data["index"] + profiles = self.device["profiles"] + profile = next(p for p in profiles if p["id"] == profile_id) + profiles.remove(profile) + profiles.insert(index, profile) + self.store() + self.send_response("{}", content_type="application/json", code=203) + except json.JSONDecodeError: + self.send_response("{}", content_type="application/json", code=400) + except StopIteration: + self.send_response("{}", content_type="application/json", code=404) + def getModalObjectType(self): return "SDR device" diff --git a/owrx/http.py b/owrx/http.py index 050e5ef6..9781033b 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -112,6 +112,12 @@ class Router(object): RegexRoute( "^/settings/sdr/([^/]+)$", SdrDeviceController, method="POST", options={"action": "processFormData"} ), + RegexRoute( + "^/settings/sdr/([^/]+)/moveprofile$", + SdrDeviceController, + method="POST", + options={"action": "moveProfile"} + ), RegexRoute("^/settings/deletesdr/([^/]+)$", SdrDeviceController, options={"action": "deleteDevice"}), RegexRoute("^/settings/sdr/([^/]+)/newprofile$", NewProfileController), RegexRoute(