diff --git a/services/static-webserver/client/source/class/osparc/dashboard/DataBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/DataBrowser.js index 2305feaa8a4..710e2d35d29 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/DataBrowser.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/DataBrowser.js @@ -76,7 +76,7 @@ qx.Class.define("osparc.dashboard.DataBrowser", { reloadButton.addListener("execute", () => this.__reloadTree(), this); const selectedFileLayout = treeFolderView.getChildControl("folder-viewer").getChildControl("selected-file-layout"); - selectedFileLayout.addListener("fileDeleted", e => this.__fileDeleted(e.getData()), this); + selectedFileLayout.addListener("pathsDeleted", e => treeFolderView.pathsDeleted(e.getData()), this); }, __reloadTree: function() { @@ -89,34 +89,5 @@ qx.Class.define("osparc.dashboard.DataBrowser", { const folderViewer = treeFolderView.getChildControl("folder-viewer"); folderViewer.resetFolder(); }, - - __fileDeleted: function(fileMetadata) { - // After deleting a file, try to keep the user in the same folder. - // If the folder doesn't longer exist, open the closest available parent - - const pathParts = fileMetadata["fileUuid"].split("/"); - - const treeFolderView = this.getChildControl("tree-folder-view"); - const foldersTree = treeFolderView.getChildControl("folder-tree"); - const folderViewer = treeFolderView.getChildControl("folder-viewer"); - - const openSameFolder = () => { - // drop last, which is the file - pathParts.pop(); - treeFolderView.openPath(pathParts); - }; - - folderViewer.resetFolder(); - const locationId = fileMetadata["locationId"]; - const path = pathParts[0]; - foldersTree.resetCache(); - foldersTree.populateLocations() - .then(datasetPromises => { - Promise.all(datasetPromises) - .then(() => foldersTree.requestPathItems(locationId, path)) - .then(() => openSameFolder()); - }) - .catch(err => console.error(err)); - } } }); diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index 926d47b667d..2c8cef208ae 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -1190,10 +1190,6 @@ qx.Class.define("osparc.data.Resources", { copy: { method: "PUT", url: statics.API + "/storage/locations/{toLoc}/files/{fileName}?extra_location={fromLoc}&extra_source={fileUuid}" - }, - delete: { - method: "DELETE", - url: statics.API + "/storage/locations/{locationId}/files/{fileUuid}" } } }, @@ -1219,6 +1215,10 @@ qx.Class.define("osparc.data.Resources", { method: "GET", url: statics.API + "/storage/locations/{locationId}/paths?file_filter={path}&cursor={cursor}&size=1000" }, + batchDelete: { + method: "POST", + url: statics.API + "/storage/locations/{locationId}/-/paths:batchDelete" + }, requestSize: { method: "POST", url: statics.API + "/storage/locations/0/paths/{pathId}:size" diff --git a/services/static-webserver/client/source/class/osparc/file/FileLabelWithActions.js b/services/static-webserver/client/source/class/osparc/file/FileLabelWithActions.js index cdd8c0c0e5f..0bc6129a264 100644 --- a/services/static-webserver/client/source/class/osparc/file/FileLabelWithActions.js +++ b/services/static-webserver/client/source/class/osparc/file/FileLabelWithActions.js @@ -21,7 +21,7 @@ * It is used together with a virtual tree of files where the selection is displayed * in the text field and the download and delete are related to that selection. * Download and deleted methods are also provided. - * If a file is deleted it fires "fileDeleted" data event + * If a file is deleted it fires "pathsDeleted" data event * * *Example* * @@ -54,7 +54,7 @@ qx.Class.define("osparc.file.FileLabelWithActions", { }, events: { - "fileDeleted": "qx.event.type.Data" + "pathsDeleted": "qx.event.type.Data", }, properties: { @@ -188,6 +188,13 @@ qx.Class.define("osparc.file.FileLabelWithActions", { } } } + if (toBeDeleted.length === 0) { + return; + } + if (toBeDeleted[0].getLocation() != 0) { + osparc.FlashMessenger.logAs(this.tr("You can only delete files in the local storage"), "WARNING"); + return; + } let msg = this.tr("This action cannot be undone."); msg += isFolderSelected ? ("
"+this.tr("All contents within the folders will be deleted.")) : ""; @@ -207,36 +214,24 @@ qx.Class.define("osparc.file.FileLabelWithActions", { }, __doDeleteSelected: function(toBeDeleted) { - const requests = []; - toBeDeleted.forEach(selection => { - if (selection) { - let request = null; - if (osparc.file.FilesTree.isFile(selection)) { - request = this.__deleteItem(selection.getFileId(), selection.getLocation()); - } else { - request = this.__deleteItem(selection.getPath(), selection.getLocation()); - } - if (request) { - requests.push(request); - } - } - }); - Promise.all(requests) - .then(datas => { - if (datas.length) { - this.fireDataEvent("fileDeleted", datas[0]); - osparc.FlashMessenger.logAs(this.tr("Items successfully deleted"), "INFO"); - } - }); - }, - - __deleteItem: function(itemId, locationId) { - if (locationId !== 0 && locationId !== "0") { - osparc.FlashMessenger.logAs(this.tr("Externally managed items cannot be deleted")); - return null; + if (toBeDeleted.length === 0) { + osparc.FlashMessenger.logAs(this.tr("Nothing to delete"), "ERROR"); + return; + } else if (toBeDeleted.length > 0) { + const paths = toBeDeleted.map(item => item.getPath()); + const dataStore = osparc.store.Data.getInstance(); + const fetchPromise = dataStore.deleteFiles(paths); + const pollTasks = osparc.store.PollTasks.getInstance(); + const interval = 1000; + pollTasks.createPollingTask(fetchPromise, interval) + .then(task => { + task.addListener("resultReceived", e => { + this.fireDataEvent("pathsDeleted", paths); + osparc.FlashMessenger.logAs(this.tr("Items successfully deleted"), "INFO"); + }); + }) + .catch(err => osparc.FlashMessenger.logError(err, this.tr("Unsuccessful files deletion"))); } - const dataStore = osparc.store.Data.getInstance(); - return dataStore.deleteFile(locationId, itemId); }, } }); diff --git a/services/static-webserver/client/source/class/osparc/file/FilePicker.js b/services/static-webserver/client/source/class/osparc/file/FilePicker.js index 65687d4f60a..5371045780a 100644 --- a/services/static-webserver/client/source/class/osparc/file/FilePicker.js +++ b/services/static-webserver/client/source/class/osparc/file/FilePicker.js @@ -152,16 +152,12 @@ qx.Class.define("osparc.file.FilePicker", { getOutputFileMetadata: function(node) { return new Promise((resolve, reject) => { const outValue = osparc.file.FilePicker.getOutput(node.getOutputs()); - const params = { - url: { - locationId: outValue.store, - path: outValue.path - } - }; - osparc.data.Resources.fetch("storagePaths", "getPaths", params) - .then(pagResp => { - if (pagResp["items"]) { - const file = pagResp["items"].find(item => item.path === outValue.path); + const locationId = outValue.store; + const path = outValue.path; + osparc.store.Data.getAllItems(locationId, path) + .then(items => { + if (items && items.length) { + const file = items.find(item => item.path === outValue.path); if (file) { resolve(file["file_meta_data"]); return; diff --git a/services/static-webserver/client/source/class/osparc/file/FolderContent.js b/services/static-webserver/client/source/class/osparc/file/FolderContent.js index 98cd8d94080..45bd8e85451 100644 --- a/services/static-webserver/client/source/class/osparc/file/FolderContent.js +++ b/services/static-webserver/client/source/class/osparc/file/FolderContent.js @@ -261,6 +261,16 @@ qx.Class.define("osparc.file.FolderContent", { } }, + resetSelection: function() { + if (this.getMode() === "list") { + const table = this.getChildControl("table"); + table.getSelectionModel().resetSelection(); + } else if (this.getMode() === "icons") { + const iconsLayout = this.getChildControl("icons-layout"); + iconsLayout.getChildren().forEach(btn => btn.setValue(false)); + } + }, + __selectionChanged: function(selection) { if (this.isMultiSelect()) { this.fireDataEvent("multiSelectionChanged", selection); diff --git a/services/static-webserver/client/source/class/osparc/file/FolderViewer.js b/services/static-webserver/client/source/class/osparc/file/FolderViewer.js index 932c2ed9381..07e14be6b1c 100644 --- a/services/static-webserver/client/source/class/osparc/file/FolderViewer.js +++ b/services/static-webserver/client/source/class/osparc/file/FolderViewer.js @@ -179,6 +179,14 @@ qx.Class.define("osparc.file.FolderViewer", { __applyFolder: function() { this.getChildControl("selected-file-layout").resetSelection(); - } + }, + + resetSelection: function() { + const folderContent = this.getChildControl("folder-content"); + folderContent.resetSelection(); + + const selectedFileLayout = this.getChildControl("selected-file-layout"); + selectedFileLayout.resetSelection(); + }, } }); diff --git a/services/static-webserver/client/source/class/osparc/file/TreeFolderView.js b/services/static-webserver/client/source/class/osparc/file/TreeFolderView.js index 0989438de15..caaa8960913 100644 --- a/services/static-webserver/client/source/class/osparc/file/TreeFolderView.js +++ b/services/static-webserver/client/source/class/osparc/file/TreeFolderView.js @@ -118,12 +118,9 @@ qx.Class.define("osparc.file.TreeFolderView", { if (osparc.file.FilesTree.isDir(selectedModel)) { folderViewer.setFolder(selectedModel); } + // this will trigger the fetching of the content folderTree.openNodeAndParents(selectedModel); folderTree.setSelection(new qx.data.Array([selectedModel])); - if (selectedModel.getPath() && !selectedModel.getLoaded()) { - selectedModel.setLoaded(true); - folderTree.requestPathItems(selectedModel.getLocation(), selectedModel.getPath()); - } } }, this); @@ -139,22 +136,18 @@ qx.Class.define("osparc.file.TreeFolderView", { }, this); }, - openPath: function(path) { - const foldersTree = this.getChildControl("folder-tree"); - const folderViewer = this.getChildControl("folder-viewer"); - let found = false; - while (!found && path.length) { - found = foldersTree.findItemId(path.join("/")); - // look for next parent - path.pop(); - } - if (found) { - foldersTree.openNodeAndParents(found); - foldersTree.setSelection(new qx.data.Array([found])); - foldersTree.fireEvent("selectionChanged"); - } else { - folderViewer.resetFolder(); - } + pathsDeleted: function(paths) { + this.getChildControl("folder-viewer").resetSelection(); + + const folderTree = this.getChildControl("folder-tree"); + const selectedFolder = folderTree.getSelectedItem(); + const children = selectedFolder.getChildren(); + paths.forEach(path => { + const found = children.toArray().find(child => child.getPath() === path); + if (found) { + children.remove(found); + } + }); }, requestSize: function(pathId) { diff --git a/services/static-webserver/client/source/class/osparc/store/Data.js b/services/static-webserver/client/source/class/osparc/store/Data.js index 202a3b4788d..8353c24ab02 100644 --- a/services/static-webserver/client/source/class/osparc/store/Data.js +++ b/services/static-webserver/client/source/class/osparc/store/Data.js @@ -234,29 +234,20 @@ qx.Class.define("osparc.store.Data", { return true; }, - // if folder path is provided as fileUuid, it can also be deleted - deleteFile: function(locationId, fileUuid) { + deleteFiles: function(paths) { if (!osparc.data.Permissions.getInstance().canDo("study.node.data.delete", true)) { return null; } - // Deletes File const params = { url: { - locationId, - fileUuid: encodeURIComponent(fileUuid) + locationId: 0, + }, + data: { + paths, } }; - return osparc.data.Resources.fetch("storageFiles", "delete", params) - .then(files => { - const data = { - data: files, - locationId: locationId, - fileUuid: fileUuid - }; - return data; - }) - .catch(err => osparc.FlashMessenger.logError(err, this.tr("Unsuccessful file deletion"))); - } + return osparc.data.Resources.fetch("storagePaths", "batchDelete", params); + }, } }); diff --git a/services/static-webserver/client/source/class/osparc/widget/StudyDataManager.js b/services/static-webserver/client/source/class/osparc/widget/StudyDataManager.js index 092d04be44c..dc093a1be03 100644 --- a/services/static-webserver/client/source/class/osparc/widget/StudyDataManager.js +++ b/services/static-webserver/client/source/class/osparc/widget/StudyDataManager.js @@ -96,7 +96,7 @@ qx.Class.define("osparc.widget.StudyDataManager", { treeFolderView.getChildControl("folder-tree").setBackgroundColor("window-popup-background"); const selectedFileLayout = treeFolderView.getChildControl("folder-viewer").getChildControl("selected-file-layout"); - selectedFileLayout.addListener("fileDeleted", e => this.__fileDeleted(e.getData()), this); + selectedFileLayout.addListener("pathsDeleted", e => treeFolderView.pathsDeleted(e.getData()), this); }, __reloadTree: function() { @@ -115,36 +115,5 @@ qx.Class.define("osparc.widget.StudyDataManager", { const folderViewer = treeFolderView.getChildControl("folder-viewer"); folderViewer.resetFolder(); }, - - __fileDeleted: function(fileMetadata) { - // After deleting a file, try to keep the user in the same folder. - // If the folder doesn't longer exist, open the closest available parent - - const path = fileMetadata["fileUuid"].split("/"); - - const treeFolderView = this.getChildControl("tree-folder-view"); - const foldersTree = treeFolderView.getChildControl("folder-tree"); - foldersTree.resetCache(); - - const openSameFolder = () => { - if (!this.getStudyId()) { - // drop first, which is the study id - path.shift(); - } - // drop last, which is the file - path.pop(); - treeFolderView.openPath(path); - }; - - if (this.getNodeId()) { - foldersTree.populateNodeTree(this.getStudyId(), this.getNodeId()) - .then(() => openSameFolder()) - .catch(err => console.error(err)); - } else if (this.getStudyId()) { - foldersTree.populateStudyTree(this.getStudyId()) - .then(() => openSameFolder()) - .catch(err => console.error(err)); - } - } } });