diff --git a/editor/js/main.js b/editor/js/main.js index 9baa14d47..bd41a2ca4 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -217,6 +217,7 @@ menuOptions.push({id:"menu-item-projects-menu",label:"NLS: Projects",options:[ {id:"menu-item-projects-new",label:"New...",disabled:false,onselect:"core:new-project"}, {id:"menu-item-projects-open",label:"Open...",disabled:false,onselect:"core:open-project"}, + {id:"menu-item-projects-delete",label:"Delete...",disabled:false,onselect:"core:delete-project"}, ]}); diff --git a/editor/js/ui/projects.js b/editor/js/ui/projects.js index 68d5aee3e..0493bad0a 100644 --- a/editor/js/ui/projects.js +++ b/editor/js/ui/projects.js @@ -505,6 +505,9 @@ RED.projects = (function() { canSelectActive: false, dblclick: function() { $("#projects-dialog-open").click(); + }, + select: function() { + $("#projects-dialog-open").prop('disabled',false).removeClass('disabled ui-button-disabled ui-state-disabled'); } }) }, @@ -536,6 +539,49 @@ RED.projects = (function() { } } ] + }, + + 'delete': { + content: function() { + return createProjectList({ + canSelectActive: false, + dblclick: function() { + $("#projects-dialog-delete").click(); + }, + select: function() { + $("#projects-dialog-delete").prop('disabled',false).removeClass('disabled ui-button-disabled ui-state-disabled'); + } + }) + }, + buttons: [ + { + // id: "clipboard-dialog-cancel", + text: RED._("common.label.cancel"), + click: function() { + $( this ).dialog( "close" ); + } + }, + { + id: "projects-dialog-delete", + text: "Delete project", // TODO: nls + class: "primary disabled", + disabled: true, + click: function() { + deleteProject(selectedProject.name,function(err,data) { + if (err) { + if (err.error === 'credentials_load_failed') { + dialog.dialog( "close" ); + } else { + console.log("unexpected_error",err) + } + } else { + dialog.dialog( "close" ); + } + }) + } + } + ] + } } } @@ -565,6 +611,23 @@ RED.projects = (function() { }) } + function deleteProject(name,done) { + sendRequest({ + url: "projects/"+name, + type: "DELETE", + responses: { + 200: function(data) { + done(null,data); + }, + 400: { + 'unexpected_error': function(error) { + done(error,null); + } + } + } + }); + } + function show(s,options) { if (!dialog) { RED.projects.init(); @@ -607,7 +670,6 @@ RED.projects = (function() { row.click(function(evt) { $('.projects-dialog-project-list-entry').removeClass('selected'); header.addClass('selected'); - $("#projects-dialog-open").prop('disabled',false).removeClass('disabled ui-button-disabled ui-state-disabled'); selectedProject = entry; if (options.select) { options.select(entry); @@ -947,6 +1009,7 @@ RED.projects = (function() { RED.actions.add("core:new-project",RED.projects.newProject); RED.actions.add("core:open-project",RED.projects.selectProject); + RED.actions.add("core:delete-project",RED.projects.deleteProject); var projectsAPI = { sendRequest:sendRequest, createBranchList:createBranchList, @@ -990,6 +1053,9 @@ RED.projects = (function() { selectProject: function() { show('open') }, + deleteProject: function() { + show('delete') + }, showCredentialsPrompt: function() { //TODO: rename this function RED.projects.settings.show('settings'); }, diff --git a/red/api/editor/projects/index.js b/red/api/editor/projects/index.js index 8faab61df..33576a0a5 100644 --- a/red/api/editor/projects/index.js +++ b/red/api/editor/projects/index.js @@ -117,6 +117,13 @@ module.exports = { // Delete project - tbd app.delete("/:id", needsPermission("projects.write"), function(req,res) { + runtime.storage.projects.deleteProject(req.user, req.params.id).then(function() { + res.status(204).end(); + }) + .catch(function(err) { + console.log(err.stack); + res.status(400).json({error:"unexpected_error", message:err.toString()}) + }); }); diff --git a/red/runtime/storage/localfilesystem/projects/Project.js b/red/runtime/storage/localfilesystem/projects/Project.js index ec7944102..67aaaadf9 100644 --- a/red/runtime/storage/localfilesystem/projects/Project.js +++ b/red/runtime/storage/localfilesystem/projects/Project.js @@ -583,6 +583,11 @@ function createProjectDirectory(project) { return fs.ensureDir(projectPath); } +function deleteProjectDirectory(project) { + var projectPath = fspath.join(projectsDir,project); + return fs.remove(projectPath); +} + function createDefaultProject(user, project) { var projectPath = fspath.join(projectsDir,project.name); // Create a basic skeleton of a project @@ -710,6 +715,23 @@ function createProject(user, metadata) { }) } +function deleteProject(user, name) { + return checkProjectExists(name).then(function() { + if (currentProject && currentProject.name === name) { + var e = new Error("NLS: Can't delete the active project"); + e.code = "cannot_delete_active_project"; + throw e; + } + else { + return deleteProjectDirectory(name).then(function() { + var projects = settings.get('projects'); + delete projects.projects[name]; + return settings.set('projects', projects); + }); + } + }); +} + var currentProject; function getProject(name) { @@ -749,6 +771,7 @@ module.exports = { init: init, get: getProject, create: createProject, + delete: deleteProject, list: listProjects } diff --git a/red/runtime/storage/localfilesystem/projects/index.js b/red/runtime/storage/localfilesystem/projects/index.js index 8e2600e51..15003f4d5 100644 --- a/red/runtime/storage/localfilesystem/projects/index.js +++ b/red/runtime/storage/localfilesystem/projects/index.js @@ -141,6 +141,10 @@ function getProject(user, name) { }); } +function deleteProject(user, name) { + return Projects.delete(user, name); +} + function checkActiveProject(project) { if (!activeProject || activeProject.name !== project) { //TODO: throw better err @@ -398,6 +402,7 @@ module.exports = { getActiveProject: getActiveProject, setActiveProject: setActiveProject, getProject: getProject, + deleteProject: deleteProject, createProject: createProject, updateProject: updateProject, getFiles: getFiles,