From 1849889dcc9a6562ada37092d70076639d477e22 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 13:05:00 -0400 Subject: [PATCH 01/10] Added a test to the get_file_list function calls to always exclude files in the trash directory if it exists within the root. --- stochss/handlers/models.py | 6 ++++-- stochss/handlers/util/stochss_folder.py | 3 ++- stochss/handlers/util/stochss_workflow.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index ee9c9284e1..e61f1e4254 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -315,7 +315,8 @@ async def get(self): self.set_header('Content-Type', 'application/json') try: folder = StochSSFolder(path="") - resp = folder.get_file_list(ext=".domn") + test = lambda ext, root, file: bool("trash" in root) + resp = folder.get_file_list(ext=".domn", test=test) log.debug("Response: %s", resp) self.write(resp) except StochSSAPIError as err: @@ -340,7 +341,8 @@ async def get(self): self.set_header('Content-Type', 'application/json') try: folder = StochSSFolder(path="") - resp = folder.get_file_list(ext=".txt") + test = lambda ext, root, file: bool("trash" in root) + resp = folder.get_file_list(ext=".txt", test=test) log.debug("Response: %s", resp) self.write(resp) except StochSSAPIError as err: diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index 8d9200e65b..7293fd9633 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -340,7 +340,8 @@ def get_project_list(self): Attributes ---------- ''' - data = self.get_file_list(ext=".proj", folder=True) + test = lambda ext, root, file: bool("trash" in root) + data = self.get_file_list(ext=".proj", folder=True, test=test) projects = [] for file in data['files']: for path in data['paths'][file[0]]: diff --git a/stochss/handlers/util/stochss_workflow.py b/stochss/handlers/util/stochss_workflow.py index 597707257e..8e372db390 100644 --- a/stochss/handlers/util/stochss_workflow.py +++ b/stochss/handlers/util/stochss_workflow.py @@ -346,7 +346,7 @@ def load(self): self.workflow['model'] = None else: root = StochSSFolder(path="") - test = lambda ext, root, file: ".wkfl" in root or ".proj" in root + test = lambda ext, root, file: ".wkfl" in root or ".proj" in root or "trash" in root models = root.get_file_list(ext=[".mdl"], test=test) if models is not None: self.workflow['models'] = models From 7ad3aff7ca6d1f78d92eefc138760328e096cc91 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 13:34:27 -0400 Subject: [PATCH 02/10] Refined the context menu test to excluded files/directories with trash as a substring of the name when assigning custom context menus. --- client/views/file-browser-view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/views/file-browser-view.js b/client/views/file-browser-view.js index 6a317fbb74..aeb09b808c 100644 --- a/client/views/file-browser-view.js +++ b/client/views/file-browser-view.js @@ -1379,7 +1379,7 @@ module.exports = View.extend({ if (o.text === "trash"){ return refresh } - if (o.original._path.includes("trash")) { + if (o.original._path.includes(".proj/trash/")) { return {"Delete": common.Delete} } if (o.type === 'folder') { From 37b257c82f70e1067f501bbab8f38c5df4f28f4b Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 13:35:29 -0400 Subject: [PATCH 03/10] Disabled double-click functions for file/directories in the trash directory. --- client/views/file-browser-view.js | 42 ++++++++++++++++--------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/client/views/file-browser-view.js b/client/views/file-browser-view.js index aeb09b808c..de8ef0e6d2 100644 --- a/client/views/file-browser-view.js +++ b/client/views/file-browser-view.js @@ -1441,26 +1441,28 @@ module.exports = View.extend({ var file = e.target.text var node = $('#models-jstree-view').jstree().get_node(e.target) var _path = node.original._path; - if(file.endsWith('.mdl') || file.endsWith('.smdl')){ - window.location.href = path.join(app.getBasePath(), "stochss/models/edit")+"?path="+_path; - }else if(file.endsWith('.ipynb')){ - var notebookPath = path.join(app.getBasePath(), "notebooks", _path) - window.open(notebookPath, '_blank') - }else if(file.endsWith('.sbml')){ - var openPath = path.join(app.getBasePath(), "edit", _path) - window.open(openPath, '_blank') - }else if(file.endsWith('.proj')){ - window.location.href = path.join(app.getBasePath(), "stochss/project/manager")+"?path="+_path; - }else if(file.endsWith('.wkfl')){ - window.location.href = path.join(app.getBasePath(), "stochss/workflow/edit")+"?path="+_path+"&type=none"; - }else if(file.endsWith('.domn')) { - let queryStr = "?domainPath=" + _path - window.location.href = path.join(app.getBasePath(), "stochss/domain/edit") + queryStr - }else if(node.type === "folder" && $('#models-jstree-view').jstree().is_open(node) && $('#models-jstree-view').jstree().is_loaded(node)){ - $('#models-jstree-view').jstree().refresh_node(node) - }else if(node.type === "other"){ - var openPath = path.join(app.getBasePath(), "view", _path); - window.open(openPath, "_blank"); + if(!_path.includes(".proj/trash/")){ + if(file.endsWith('.mdl') || file.endsWith('.smdl')){ + window.location.href = path.join(app.getBasePath(), "stochss/models/edit")+"?path="+_path; + }else if(file.endsWith('.ipynb')){ + var notebookPath = path.join(app.getBasePath(), "notebooks", _path) + window.open(notebookPath, '_blank') + }else if(file.endsWith('.sbml')){ + var openPath = path.join(app.getBasePath(), "edit", _path) + window.open(openPath, '_blank') + }else if(file.endsWith('.proj')){ + window.location.href = path.join(app.getBasePath(), "stochss/project/manager")+"?path="+_path; + }else if(file.endsWith('.wkfl')){ + window.location.href = path.join(app.getBasePath(), "stochss/workflow/edit")+"?path="+_path+"&type=none"; + }else if(file.endsWith('.domn')) { + let queryStr = "?domainPath=" + _path + window.location.href = path.join(app.getBasePath(), "stochss/domain/edit") + queryStr + }else if(node.type === "folder" && $('#models-jstree-view').jstree().is_open(node) && $('#models-jstree-view').jstree().is_loaded(node)){ + $('#models-jstree-view').jstree().refresh_node(node) + }else if(node.type === "other"){ + var openPath = path.join(app.getBasePath(), "view", _path); + window.open(openPath, "_blank"); + } } }); }) From c947fa5fb7eb5d3b5c1ed8d7b439ec8d5972492e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 13:48:02 -0400 Subject: [PATCH 04/10] Refactored the test function to only exclude file object that have the trash directory in their path. --- stochss/handlers/models.py | 4 ++-- stochss/handlers/project.py | 2 +- stochss/handlers/util/stochss_folder.py | 2 +- stochss/handlers/util/stochss_workflow.py | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/stochss/handlers/models.py b/stochss/handlers/models.py index e61f1e4254..a55a29a947 100644 --- a/stochss/handlers/models.py +++ b/stochss/handlers/models.py @@ -315,7 +315,7 @@ async def get(self): self.set_header('Content-Type', 'application/json') try: folder = StochSSFolder(path="") - test = lambda ext, root, file: bool("trash" in root) + test = lambda ext, root, file: bool("trash" in root.split("/")) resp = folder.get_file_list(ext=".domn", test=test) log.debug("Response: %s", resp) self.write(resp) @@ -341,7 +341,7 @@ async def get(self): self.set_header('Content-Type', 'application/json') try: folder = StochSSFolder(path="") - test = lambda ext, root, file: bool("trash" in root) + test = lambda ext, root, file: bool("trash" in root.split("/")) resp = folder.get_file_list(ext=".txt", test=test) log.debug("Response: %s", resp) self.write(resp) diff --git a/stochss/handlers/project.py b/stochss/handlers/project.py index 8615d23428..6837604d12 100644 --- a/stochss/handlers/project.py +++ b/stochss/handlers/project.py @@ -171,7 +171,7 @@ def get(self): folder = StochSSFolder(path="") # file will be excluded if test passes test = lambda ext, root, file: bool(".wkfl" in root or f"{path}" in root or \ - "trash" in root) + "trash" in root.split("/")) data = folder.get_file_list(ext=[".mdl", ".smdl"], test=test) log.debug("List of models: %s", data) self.write(data) diff --git a/stochss/handlers/util/stochss_folder.py b/stochss/handlers/util/stochss_folder.py index 7293fd9633..d9dbc44d4c 100644 --- a/stochss/handlers/util/stochss_folder.py +++ b/stochss/handlers/util/stochss_folder.py @@ -340,7 +340,7 @@ def get_project_list(self): Attributes ---------- ''' - test = lambda ext, root, file: bool("trash" in root) + test = lambda ext, root, file: bool("trash" in root.split("/")) data = self.get_file_list(ext=".proj", folder=True, test=test) projects = [] for file in data['files']: diff --git a/stochss/handlers/util/stochss_workflow.py b/stochss/handlers/util/stochss_workflow.py index 8e372db390..c4646e5304 100644 --- a/stochss/handlers/util/stochss_workflow.py +++ b/stochss/handlers/util/stochss_workflow.py @@ -333,7 +333,7 @@ def load(self): if ".proj" in self.path: if "WorkflowGroup1.wkgp" in self.path: proj = StochSSFolder(path=os.path.dirname(self.get_dir_name(full=True))) - test = lambda ext, root, file: ".wkfl" in root or "trash" in root + test = lambda ext, root, file: ".wkfl" in root or "trash" in root.split("/") models = proj.get_file_list(ext=[".mdl"], test=test) else: wkgp = StochSSFolder(path=self.get_dir_name(full=True)) @@ -346,7 +346,8 @@ def load(self): self.workflow['model'] = None else: root = StochSSFolder(path="") - test = lambda ext, root, file: ".wkfl" in root or ".proj" in root or "trash" in root + test = lambda ext, root, file: ".wkfl" in root or ".proj" in root or \ + "trash" in root.split("/") models = root.get_file_list(ext=[".mdl"], test=test) if models is not None: self.workflow['models'] = models From 2d746ac978ef3cb73df80ded30fc9628cb2d827e Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 13:59:43 -0400 Subject: [PATCH 05/10] Added custom context menus for items located in the trash directory and the trash directory. Disabled the double-click function for items in the trash directory. --- client/pages/file-browser.js | 48 +++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/client/pages/file-browser.js b/client/pages/file-browser.js index 3ebc068764..bf25e8a390 100644 --- a/client/pages/file-browser.js +++ b/client/pages/file-browser.js @@ -1268,6 +1268,12 @@ let FileBrowser = PageView.extend({ if (o.type === 'root'){ return folder } + if (o.text === "trash") { + return {"Refresh": folder.Refresh} + } + if (o.original._path.split("/")[0] === "trash") { + return {"Delete": common.Delete} + } if (o.type === 'folder') { return $.extend(folder, common) } @@ -1326,26 +1332,28 @@ let FileBrowser = PageView.extend({ var file = e.target.text var node = $('#models-jstree').jstree().get_node(e.target) var _path = node.original._path; - if(file.endsWith('.mdl') || file.endsWith('.smdl')){ - window.location.href = path.join(app.getBasePath(), "stochss/models/edit")+"?path="+_path; - }else if(file.endsWith('.ipynb')){ - var notebookPath = path.join(app.getBasePath(), "notebooks", _path) - window.open(notebookPath, '_blank') - }else if(file.endsWith('.sbml')){ - var openPath = path.join(app.getBasePath(), "edit", _path) - window.open(openPath, '_blank') - }else if(file.endsWith('.proj')){ - window.location.href = path.join(app.getBasePath(), "stochss/project/manager")+"?path="+_path; - }else if(file.endsWith('.wkfl')){ - window.location.href = path.join(app.getBasePath(), "stochss/workflow/edit")+"?path="+_path+"&type=none"; - }else if(file.endsWith('.domn')) { - let queryStr = "?domainPath=" + _path - window.location.href = path.join(app.getBasePath(), "stochss/domain/edit") + queryStr - }else if(node.type === "folder" && $('#models-jstree').jstree().is_open(node) && $('#models-jstree').jstree().is_loaded(node)){ - $('#models-jstree').jstree().refresh_node(node) - }else if(node.type === "other"){ - var openPath = path.join(app.getBasePath(), "view", _path); - window.open(openPath, "_blank"); + if(!_path.split("/")[0] === "trash") { + if(file.endsWith('.mdl') || file.endsWith('.smdl')){ + window.location.href = path.join(app.getBasePath(), "stochss/models/edit")+"?path="+_path; + }else if(file.endsWith('.ipynb')){ + var notebookPath = path.join(app.getBasePath(), "notebooks", _path) + window.open(notebookPath, '_blank') + }else if(file.endsWith('.sbml')){ + var openPath = path.join(app.getBasePath(), "edit", _path) + window.open(openPath, '_blank') + }else if(file.endsWith('.proj')){ + window.location.href = path.join(app.getBasePath(), "stochss/project/manager")+"?path="+_path; + }else if(file.endsWith('.wkfl')){ + window.location.href = path.join(app.getBasePath(), "stochss/workflow/edit")+"?path="+_path+"&type=none"; + }else if(file.endsWith('.domn')) { + let queryStr = "?domainPath=" + _path + window.location.href = path.join(app.getBasePath(), "stochss/domain/edit") + queryStr + }else if(node.type === "folder" && $('#models-jstree').jstree().is_open(node) && $('#models-jstree').jstree().is_loaded(node)){ + $('#models-jstree').jstree().refresh_node(node) + }else if(node.type === "other"){ + var openPath = path.join(app.getBasePath(), "view", _path); + window.open(openPath, "_blank"); + } } }); } From 69cba20566ca5c93f49c773bda4f8c25b7e28f52 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 14:04:57 -0400 Subject: [PATCH 06/10] Moved the empty trash api handler to file_browser.py. --- client/pages/project-manager.js | 2 +- stochss/handlers/__init__.py | 2 +- stochss/handlers/file_browser.py | 29 +++++++++++++++++++++++++++++ stochss/handlers/project.py | 29 ----------------------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/client/pages/project-manager.js b/client/pages/project-manager.js index fd7b4625ba..67f45073ba 100644 --- a/client/pages/project-manager.js +++ b/client/pages/project-manager.js @@ -229,7 +229,7 @@ let ProjectManager = PageView.extend({ let yesBtn = document.querySelector('#emptyTrashConfirmModal .yes-modal-btn'); yesBtn.addEventListener('click', function (e) { modal.modal('hide'); - let endpoint = path.join(app.getApiPath(), "project/empty-trash")+"?path="+path.join(self.model.directory, "trash"); + let endpoint = path.join(app.getApiPath(), "file/empty-trash")+"?path="+path.join(self.model.directory, "trash"); app.getXHR(endpoint, { success: function (err, response, body) { $(self.queryByHook('empty-project-trash')).prop('disabled', true); diff --git a/stochss/handlers/__init__.py b/stochss/handlers/__init__.py index f52ecc0747..0b9edeee01 100644 --- a/stochss/handlers/__init__.py +++ b/stochss/handlers/__init__.py @@ -57,6 +57,7 @@ def get_page_handlers(route_start): (r"/stochss/api/file/upload\/?", UploadFileAPIHandler), (r"/stochss/api/file/upload-from-link\/?", UploadFileFromLinkAPIHandler), (r"/stochss/api/file/move\/?", MoveFileAPIHandler), + (r"/stochss/api/file/empty-trash\/?", EmptyTrashAPIHandler), (r"/stochss/api/file/delete\/?", DeleteFileAPIHandler), (r"/stochss/api/file/rename\/?", RenameAPIHandler), (r"/stochss/api/file/download\/?", DownloadAPIHandler), @@ -87,7 +88,6 @@ def get_page_handlers(route_start): (r"/stochss/api/project/add-existing-model\/?", AddExistingModelAPIHandler), (r"/stochss/api/project/extract-model\/?", ExtractModelAPIHandler), (r"/stochss/api/project/extract-workflow\/?", ExtractWorkflowAPIHandler), - (r"/stochss/api/project/empty-trash\/?", EmptyTrashAPIHandler), (r"/stochss/api/project/export-combine\/?", ExportAsCombineAPIHandler), (r"/stochss/api/project/meta-data\/?", ProjectMetaDataAPIHandler), (r"/stochss/api/project/save-annotation\/?", UpdateAnnotationAPIHandler), diff --git a/stochss/handlers/file_browser.py b/stochss/handlers/file_browser.py index 7d35d52423..50fbbb523f 100644 --- a/stochss/handlers/file_browser.py +++ b/stochss/handlers/file_browser.py @@ -101,6 +101,35 @@ async def get(self): self.finish() +class EmptyTrashAPIHandler(APIHandler): + ''' + ############################################################################## + Handler for a projects trash directory + ############################################################################## + ''' + @web.authenticated + def get(self): + ''' + Empty the trash directory. + + Attributes + ---------- + ''' + self.set_header('Content-Type', 'application/json') + path = self.get_query_argument(name="path") + log.debug("Path to the trash directory: %s", path) + try: + log.info("Emptying the trash") + folder = StochSSFolder(path=path) + resp = folder.empty() + log.debug("Response message: %s", resp) + log.info("Successfully emptied the trash") + self.write(resp) + except StochSSAPIError as err: + report_error(self, log, err) + self.finish() + + class DeleteFileAPIHandler(APIHandler): ''' ################################################################################################ diff --git a/stochss/handlers/project.py b/stochss/handlers/project.py index 6837604d12..b0b727364a 100644 --- a/stochss/handlers/project.py +++ b/stochss/handlers/project.py @@ -276,35 +276,6 @@ def get(self): self.finish() -class EmptyTrashAPIHandler(APIHandler): - ''' - ############################################################################## - Handler for a projects trash directory - ############################################################################## - ''' - @web.authenticated - def get(self): - ''' - Empty the trash directory. - - Attributes - ---------- - ''' - self.set_header('Content-Type', 'application/json') - path = self.get_query_argument(name="path") - log.debug("Path to the trash directory: %s", path) - try: - log.info("Emptying the trash") - folder = StochSSFolder(path=path) - resp = folder.empty() - log.debug("Response message: %s", resp) - log.info("Successfully emptied the trash") - self.write(resp) - except StochSSAPIError as err: - report_error(self, log, err) - self.finish() - - class ProjectMetaDataAPIHandler(APIHandler): ''' ############################################################################## From a1fb0d491f0b520ed543ae3cc2d93c55489f8eb7 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 14:30:03 -0400 Subject: [PATCH 07/10] Added checks to drag-n-drop to handle miving file in and out of the trash directory. --- client/pages/file-browser.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/pages/file-browser.js b/client/pages/file-browser.js index bf25e8a390..bf5a535127 100644 --- a/client/pages/file-browser.js +++ b/client/pages/file-browser.js @@ -78,7 +78,10 @@ let FileBrowser = PageView.extend({ if(op === 'move_node' && more && more.ref && more.ref.type && !(more.ref.type == 'folder' || more.ref.type == 'root')){ return false } - if(op === 'move_node' && more && more.ref && more.ref.type && more.ref.type === 'folder'){ + if(op === 'move_node' && more && more.ref && more.ref.original && path.dirname(more.ref.original._path).split("/").includes("trash")){ + return false + } + if(op === 'move_node' && more && more.ref && more.ref.type && more.ref.type === 'folder' && more.ref.text !== "trash"){ if(!more.ref.state.loaded){ return false } @@ -110,6 +113,8 @@ let FileBrowser = PageView.extend({ node.original._path = path.join(newDir, file); if(node.type === "folder") { $('#models-jstree').jstree().refresh_node(node); + }else if(newDir.endsWith("trash") || oldPath.split("/").includes("trash")) { + $('#models-jstree').jstree().refresh_node(par); } }, error: function (err, response, body) { From 66f6c24650d27cb6069408b78921d28dcbb65411 Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 15:25:48 -0400 Subject: [PATCH 08/10] Added a confirmation model for moving items to trash via the context menu. Added a button allowing users to empty the trash directory. --- client/pages/file-browser.js | 59 ++++++++++++++++++++++++-- client/templates/pages/fileBrowser.pug | 4 +- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/client/pages/file-browser.js b/client/pages/file-browser.js index bf5a535127..ed8895a707 100644 --- a/client/pages/file-browser.js +++ b/client/pages/file-browser.js @@ -44,6 +44,7 @@ let FileBrowser = PageView.extend({ 'click [data-hook=file-browser-help]' : function () { let modal = $(modals.operationInfoModalHtml('file-browser')).modal(); }, + 'click [data-hook=empty-trash]' : 'emptyTrash' }, initialize: function (attrs, options) { PageView.prototype.initialize.apply(this, arguments) @@ -113,7 +114,10 @@ let FileBrowser = PageView.extend({ node.original._path = path.join(newDir, file); if(node.type === "folder") { $('#models-jstree').jstree().refresh_node(node); - }else if(newDir.endsWith("trash") || oldPath.split("/").includes("trash")) { + }else if(newDir.endsWith("trash")) { + $(self.queryByHook('empty-trash')).prop('disabled', false); + $('#models-jstree').jstree().refresh_node(par); + }else if(oldPath.split("/").includes("trash")) { $('#models-jstree').jstree().refresh_node(par); } }, @@ -775,7 +779,6 @@ let FileBrowser = PageView.extend({ if(o && o.original && o.original.type !== "root"){ parentPath = o.original._path } - console.log(parentPath) if(isModel) { let ext = isSpatial ? ".smdl" : ".mdl" let modelName = o && o.type === "project" ? input.value.trim().split("/").pop() + ext : input.value.trim() + ext; @@ -865,6 +868,43 @@ let FileBrowser = PageView.extend({ } }); }, + moveToTrash: function (o) { + if(document.querySelector('#moveToTrashConfirmModal')) { + document.querySelector('#moveToTrashConfirmModal').remove(); + } + let self = this; + let modal = $(modals.moveToTrashConfirmHtml("model")).modal(); + let yesBtn = document.querySelector('#moveToTrashConfirmModal .yes-modal-btn'); + yesBtn.addEventListener('click', function (e) { + modal.modal('hide'); + let queryStr = "?srcPath=" + o.original._path + "&dstPath=" + path.join("trash", o.text) + let endpoint = path.join(app.getApiPath(), "file/move") + queryStr + app.getXHR(endpoint, { + always: function (err, response, body) { + $(self.queryByHook('empty-trash')).prop('disabled', false); + $('#models-jstree').jstree().refresh(); + } + }); + }); + }, + emptyTrash: function (e) { + if(document.querySelector("#emptyTrashConfirmModal")) { + document.querySelector("#emptyTrashConfirmModal").remove() + } + let self = this; + let modal = $(modals.emptyTrashConfirmHtml()).modal(); + let yesBtn = document.querySelector('#emptyTrashConfirmModal .yes-modal-btn'); + yesBtn.addEventListener('click', function (e) { + modal.modal('hide'); + let endpoint = path.join(app.getApiPath(), "file/empty-trash") + "?path=trash"; + app.getXHR(endpoint, { + success: function (err, response, body) { + self.refreshJSTree(); + $(self.queryByHook('empty-trash')).prop('disabled', true); + } + }); + }); + }, setupJstree: function () { var self = this; $.jstree.defaults.contextmenu.items = (o, cb) => { @@ -910,6 +950,17 @@ let FileBrowser = PageView.extend({ self.duplicateFileOrDirectory(o, null) } }, + "MoveToTrash" : { + "label" : "Move To Trash", + "_disabled" : false, + "separator_before" : false, + "separator_after" : false, + "action" : function (data) { + self.moveToTrash(o); + } + } + } + let delete_node = { "Delete" : { "label" : "Delete", "_disabled" : false, @@ -1277,7 +1328,7 @@ let FileBrowser = PageView.extend({ return {"Refresh": folder.Refresh} } if (o.original._path.split("/")[0] === "trash") { - return {"Delete": common.Delete} + return delete_node } if (o.type === 'folder') { return $.extend(folder, common) @@ -1337,7 +1388,7 @@ let FileBrowser = PageView.extend({ var file = e.target.text var node = $('#models-jstree').jstree().get_node(e.target) var _path = node.original._path; - if(!_path.split("/")[0] === "trash") { + if(!(_path.split("/")[0] === "trash")) { if(file.endsWith('.mdl') || file.endsWith('.smdl')){ window.location.href = path.join(app.getBasePath(), "stochss/models/edit")+"?path="+_path; }else if(file.endsWith('.ipynb')){ diff --git a/client/templates/pages/fileBrowser.pug b/client/templates/pages/fileBrowser.pug index 6446a44c6e..ea87593238 100644 --- a/client/templates/pages/fileBrowser.pug +++ b/client/templates/pages/fileBrowser.pug @@ -35,4 +35,6 @@ section.page button.btn.btn-primary.box-shadow(id="options-for-node" data-hook="options-for-node" disabled) Actions - button.btn.btn-primary.inline.box-shadow(id="refresh-jstree" data-hook="refresh-jstree") Refresh \ No newline at end of file + button.btn.btn-primary.inline.box-shadow(id="refresh-jstree" data-hook="refresh-jstree") Refresh + + button.btn.btn-primary.inline.box-shadow(id="empty-trash" data-hook="empty-trash") Empty Trash \ No newline at end of file From 6f02544efcf2f1a4fd9f2e17999a93bc41e92dae Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 15:37:18 -0400 Subject: [PATCH 09/10] Refactored the remove function of the project browser to move projects to trash instead of deleting them. --- client/views/edit-project.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/client/views/edit-project.js b/client/views/edit-project.js index a0662fccaf..042dddc754 100644 --- a/client/views/edit-project.js +++ b/client/views/edit-project.js @@ -29,7 +29,7 @@ let template = require('../templates/includes/editProject.pug'); module.exports = View.extend({ template: template, events: { - 'click [data-hook=remove-project-btn]' : 'handleRemoveProjectClick' + 'click [data-hook=remove-project-btn]' : 'handleMoveToTrash' }, initialize: function (attrs, options) { View.prototype.initialize.apply(this, arguments); @@ -37,16 +37,17 @@ module.exports = View.extend({ render: function (attrs, options) { View.prototype.render.apply(this, arguments); }, - handleRemoveProjectClick: function (e) { - if(document.querySelector('#deleteFileModal')) { - document.querySelector('#deleteFileModal').remove(); + handleMoveToTrash: function (e) { + if(document.querySelector('#moveToTrashConfirmModal')) { + document.querySelector('#moveToTrashConfirmModal').remove(); } let self = this; - let endpoint = path.join(app.getApiPath(), "file/delete")+"?path="+this.model.directory; - let modal = $(modals.deleteFileHtml("project")).modal(); - let yesBtn = document.querySelector('#deleteFileModal .yes-modal-btn'); + let modal = $(modals.moveToTrashConfirmHtml("model")).modal(); + let yesBtn = document.querySelector('#moveToTrashConfirmModal .yes-modal-btn'); yesBtn.addEventListener('click', function (e) { modal.modal('hide'); + let queryStr = "?srcPath=" + self.model.directory + "&dstPath=" + path.join("trash", self.model.directory.split("/").pop()); + let endpoint = path.join(app.getApiPath(), "file/move") + queryStr app.getXHR(endpoint, { success: function (err, response, body) { self.model.collection.remove(self.model); From 093177705469266b05105594fd25097a6253d6af Mon Sep 17 00:00:00 2001 From: Bryan Rumsey Date: Mon, 31 May 2021 15:51:16 -0400 Subject: [PATCH 10/10] Added check to make the trash directory if the users is moving a file object to trash and the trash directory is missing. --- stochss/handlers/util/stochss_base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stochss/handlers/util/stochss_base.py b/stochss/handlers/util/stochss_base.py index 8b6b7478fb..c17075e87f 100644 --- a/stochss/handlers/util/stochss_base.py +++ b/stochss/handlers/util/stochss_base.py @@ -97,6 +97,8 @@ def get_new_path(self, dst_path): New path for the file object from the users home directory ''' new_path = os.path.join(self.user_dir, dst_path) + if dst_path.startswith("trash/") and not "trash" in os.listdir(self.user_dir): + os.mkdir(os.path.join(self.user_dir, "trash")) if new_path.split().pop().replace('.', '', 5).isdigit(): return new_path.replace(new_path.split().pop(), "").strip() if "trash/" in new_path and os.path.exists(new_path):