All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ide-git.git.git.js Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Copyright (c) 2010-2019 SAP and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   SAP - initial API and implementation
 */
/**
 * Utility URL builder
 */
var UriBuilder = function UriBuilder(){
	this.pathSegments = [];
	return this;
}
UriBuilder.prototype.path = function(_pathSegments){
	if(!Array.isArray(_pathSegments))
		_pathSegments = [_pathSegments];
	_pathSegments = _pathSegments.filter(function(segment){
			return segment;
		})
		.map(function(segment){
			if(segment.length){
				if(segment.charAt(segment.length-1) ==='/')
					segment = segment.substring(0, segment.length-2);
				segment = encodeURIComponent(segment);
			} 
			return segment;
		});
	this.pathSegments = this.pathSegments.concat(_pathSegments);
	return this;
}
UriBuilder.prototype.build = function(){
	return this.pathSegments.join('/');
}

/**
 * Workspace Service API delegate
 */
var WorkspaceService = function($http, workspaceManagerServiceUrl, workspacesServiceUrl, treeCfg){

	this.workspaceManagerServiceUrl = workspaceManagerServiceUrl;
	this.workspacesServiceUrl = workspacesServiceUrl;
	this.typeMapping = treeCfg['types'];
	this.$http = $http;
	
	this.newFileName = function(name, type, siblingFilenames){
		type = type || 'default';
		//check for custom new file name template in the global configuration
		if(type && this.typeMapping[type] && this.typeMapping[type].template_new_name){
			var nameIncrementRegex = this.typeMapping[type].name_increment_regex;
			siblingFilenames = siblingFilenames || [];
			var suffix = nextIncrementSegment(siblingFilenames, name, nameIncrementRegex);
			suffix = suffix < 0 ? " " : suffix;
			var parameters = {
				"{name}": name || 'file',
				"{ext}": this.typeMapping[type].ext,
				"{increment}" : "-"+suffix
			}
			var tmpl = this.typeMapping[type].template_new_name;
			var regex = new RegExp(Object.keys(parameters).join('|'), 'g');
			var fName = tmpl.replace(regex, function(m) {
				return parameters[m]!==undefined?parameters[m]:m;
			});
			name = fName.trim();
		} 
		return name;
	}
			
	var startsWith = function (stringToTest, prefixToTest){
		var startsWithRegEx = new RegExp('^'+prefixToTest);
		var matches = stringToTest.match(startsWithRegEx);
		return matches != null && matches.length > 0;
	}
	
	var strictInt = function(value) {
	  if (/^(\-|\+)?([0-9]+|Infinity)$/.test(value))
		return Number(value);
	  return NaN;
	}
	
	var toInt = function(value){
		if(value ===undefined)
			return;
		var _result = value.trim();
		_result = strictInt(_result);
		if(isNaN(_result))
			_result = undefined;
		return _result;
	}
	
	//processes an array of sibling string filenames to calculate the next incrmeent suffix segment
	var nextIncrementSegment = function(filenames, filenameToMatch, nameIncrementRegex){
		var maxIncrement = filenames.map(function(siblingFilename){
			//find out incremented file name matches (such as {file-name} {i}.{extension} or {file-name}-{i}.{extension})
			var incr = -2;
			//in case we have a regex configured to find out the increment direclty, use it
			if(nameIncrementRegex){
				var regex = new Regex(nameIncrementRegex);
				var result = siblingFilename.match(regex);
				if(result!==null){
					incr = toInt(result[0]);
				}
			} else {
				//try heuristics
				var regex = /(.*?)(\.[^.]*$|$)/;
				var siblingTextSegments = siblingFilename.match(regex);//matches filename and extension segments of a filename
				var siblingTextFileName = siblingTextSegments[1];
				var siblingTextExtension = siblingTextSegments[2];
				var nodeTextSegments = filenameToMatch.match(regex);
				var nodeTextFileName = nodeTextSegments[1];
				var nodeTextExtension = nodeTextSegments[2];
				if(siblingTextExtension === nodeTextExtension){
					if(siblingTextFileName === nodeTextFileName)
						return -1;
					if(startsWith(siblingTextFileName, nodeTextFileName)){
						//try to figure out the increment segment from the name part. Starting backwards, exepcts that the increment is the last numeric segment in the name
						var _inc = "";
						for(var i=siblingTextFileName.length-1; i>-1; i-- ){
							var code = siblingTextFileName.charCodeAt(i);
							if(code<48 || code>57)//decimal numbers only
								break;
							_inc = siblingTextFileName[i] +_inc;
						}
						if(_inc){
							incr = toInt(_inc);
						}	
					}
				}
			}		
			return incr;
		}).sort(function(a, b){
			return a - b;
		}).pop();
		return ++maxIncrement;
	}
};
WorkspaceService.prototype.load = function(wsResourcePath){
	var url = new UriBuilder().path(this.workspacesServiceUrl.split('/')).path(wsResourcePath.split('/')).build();
	return this.$http.get(url, {headers: { 'describe': 'application/json'}})
			.then(function(response){
				return response.data;
			});
}
WorkspaceService.prototype.listWorkspaceNames = function(){
	var url = new UriBuilder().path(this.workspacesServiceUrl.split('/')).build();
	return this.$http.get(url)
			.then(function(response){
				return response.data;
			});
}


/**
 * Workspace Tree Adapter mediating the workspace service REST api and the jst tree componet working with it
 */
var WorkspaceTreeAdapter = function(treeConfig, workspaceSvc, gitService, $messageHub){
	this.treeConfig = treeConfig;
	this.gitService = gitService;
	this.$messageHub = $messageHub;
	this.workspaceSvc = workspaceSvc;

	this._buildTreeNode = function(f){
		var children = [];
		if(f.type=='folder' || f.type=='project'){
			children = f.folders.map(this._buildTreeNode.bind(this));
			var _files = f.files.map(this._buildTreeNode.bind(this))
			children = children.concat(_files);
		}
		f.label = f.name;
		return {
			"text": f.name,
			"children": children,
			"type": f.type,
			"_file": f
		}
	};
	
	this._fnr = function (node, replacement){
		if(node.children){
			var done;
			node.children = node.children.map(function(c){
				if(!done && c._file.path === replacement._file.path){
					done = true;
					return replacement;
				}
				return c;
			});
			if(done)
				return true;
			node.children.forEach(function(c){
				return this._fnr(c, replacement);
			}.bind(this));
		}
		return;
	};
};

WorkspaceTreeAdapter.prototype.init = function(containerEl, workspaceName, workspaceController){
	this.containerEl = containerEl;
	this.workspaceName = workspaceName;
	
	var self = this;
	var jstree = this.containerEl.jstree(this.treeConfig);
	
	//subscribe event listeners
	jstree.on('select_node.jstree', function (e, data) {
		this.clickNode(this.jstree.get_node(data.node));
	}.bind(this))
	.on('dblclick.jstree', function (evt) {
		this.dblClickNode(this.jstree.get_node(evt.target))
	}.bind(this))
	.on('open_node.jstree', function(evt, data) {
		if (data.node.type !== 'project')
			data.instance.set_icon(data.node, 'fa fa-folder-open-o');
	})
	.on('close_node.jstree', function(evt, data) {
		if (data.node.type !== 'project')
			data.instance.set_icon(data.node, 'fa fa-folder-o');
	})
	.on('delete_node.jstree', function (e, data) {
		this.deleteNode(data.node)
	}.bind(this))
	.on('jstree.workspace.pull', function (e, data) {
		workspaceController.selectedProject = (data.type === 'project') ? data.name : null;
		$('#pull').click();
	}.bind(this))
	.on('jstree.workspace.push', function (e, data) {		
		workspaceController.selectedProject = (data.type === 'project') ? data.name : null;
		$('#push').click();
	}.bind(this))
	.on('jstree.workspace.reset', function (e, data) {		
		workspaceController.selectedProject = (data.type === 'project') ? data.name : null;
		$('#reset').click();
	}.bind(this))
	.on('jstree.workspace.share', function (e, data) {		
		workspaceController.selectedProject = (data.type === 'project') ? data.name : null;
		$('#share').click();
	}.bind(this));
	
	this.jstree = $.jstree.reference(jstree);	
	return this;
};

WorkspaceTreeAdapter.prototype.dblClickNode = function(node){
	var type = node.original.type;
	if(['folder','project'].indexOf(type)<0)
		this.$messageHub.announceFileOpen(node.original._file);
}
WorkspaceTreeAdapter.prototype.clickNode = function(node){
	var type = node.original.type;
	this.$messageHub.announceFileSelected(node.original._file);
};
WorkspaceTreeAdapter.prototype.raw = function(){
	return this.jstree;
}
WorkspaceTreeAdapter.prototype.refresh = function(node, keepState){
	//TODO: This is reliable but a bit intrusive. Find out a more subtle way to update on demand
	var resourcepath;
	if(node){
		resourcepath = node.original._file.path;
	} else {
		resourcepath = this.workspaceName;
	}
	return this.workspaceSvc.load(resourcepath)
			.then(function(_data){
				var data = [];
				if(_data.type == 'workspace'){
					data = _data.projects;
				} else if(_data.type == 'folder' || _data.type == 'project'){
					data = [_data];
				}
				
				data = data.map(this._buildTreeNode.bind(this));
				
				if(!this.jstree.settings.core.data || _data.type === 'workspace')
					this.jstree.settings.core.data = data;
				else{
					//find and replace the loaded node
					var self  = this;
					this.jstree.settings.core.data = this.jstree.settings.core.data.map(function(node){
						data.forEach(function(_node, replacement){
							if(self._fnr(_node, replacement))
								return;
						}.bind(self, node));
						return node;
					});
				}
				if(!keepState)
					this.jstree.refresh();
			}.bind(this));
};
WorkspaceTreeAdapter.prototype.pull = function(resource){
	return this.gitService.pull(resource.path)
	.then(function(){
		return this.$messageHub.announcePublish(resource);
	}.bind(this));
};
WorkspaceTreeAdapter.prototype.push = function(resource){
	return this.gitService.push(resource.path)
	.then(function(){
		return this.$messageHub.announcePublish(resource);
	}.bind(this));
};
WorkspaceTreeAdapter.prototype.reset = function(resource){
	return this.gitService.reset(resource.path)
	.then(function(){
		return this.$messageHub.announcePublish(resource);
	}.bind(this));
};
WorkspaceTreeAdapter.prototype.share = function(resource){
	return this.gitService.share(resource.path)
	.then(function(){
		return this.$messageHub.announcePublish(resource);
	}.bind(this));
};



/**
 * Git Service API delegate
 */
var GitService = function($http, gitServiceUrl, treeCfg){
	this.gitServiceUrl = gitServiceUrl;
	this.typeMapping = treeCfg['types'];
	this.$http = $http;
}
GitService.prototype.cloneProject = function(wsTree, workspace, repository, branch, username, password) {
	var gitBranch = branch ? branch : "master";
	var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path("clone").build();
	return this.$http.post(url, {
			"repository": repository,
			"branch": gitBranch,
			"publish": true,
			"username": username,
			"password": btoa(password)})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}
GitService.prototype.pullAllProjects = function(wsTree, workspace, username, password){
    var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path("pull").build();
	return this.$http.post(url, {
			"publish": true,
			"username": username,
			"password": btoa(password)})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}
GitService.prototype.pullProject = function(wsTree, workspace, project, username, password){
    var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path(project).path("pull").build();
	return this.$http.post(url, {
			"publish": true,
			"username": username,
			"password": btoa(password)})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}
GitService.prototype.pushAllProjects = function(wsTree, workspace, commitMessage, username, password, email){
	var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path("push").build();
	return this.$http.post(url, {
			"commitMessage": commitMessage,
			"username": username,
			"password": btoa(password),
			"email": email
			})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}
GitService.prototype.pushProject = function(wsTree, workspace, project, commitMessage, username, password, email){
	var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path(project).path("push").build();
	return this.$http.post(url, {
			"commitMessage": commitMessage,
			"username": username,
			"password": btoa(password),
			"email": email
			})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}
GitService.prototype.resetProject = function(wsTree, workspace, project, username, password){
	var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path(project).path("reset").build();
	return this.$http.post(url, {
			"username": username,
			"password": btoa(password)})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}
GitService.prototype.shareProject = function(wsTree, workspace, project, repository, branch, commitMessage, username, password, email){
	var url = new UriBuilder().path(this.gitServiceUrl.split('/')).path(workspace).path(project).path("share").build();
	return this.$http.post(url, {
			"project": project,
			"repository": repository,
			"branch": branch,
			"commitMessage": commitMessage,
			"username": username,
			"password": btoa(password),
			"email": email
	})
			.then(function(response){
				wsTree.refresh();
				return response.data;
			});
}

/**
 * Env Service API delegate
 */
var EnvService = function($http, envServiceUrl){
	this.envServiceUrl = envServiceUrl;
	this.$http = $http;
};
EnvService.prototype.setEnv = function(env) {
	return this.$http.post(this.envServiceUrl, {
		"env": env,
	});
};

angular.module('workspace.config', [])
	.constant('WS_SVC_URL','../../../../../services/v3/ide/workspaces')
	.constant('WS_SVC_MANAGER_URL','../../../../../services/v3/ide/workspace')
	.constant('GIT_SVC_URL','../../../../../services/v3/ide/git')
	.constant('ENV_SVC_URL','../../../../../services/v3/js/ide-git/services/env.js');
	
angular.module('workspace', ['workspace.config', 'ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.factory('httpRequestInterceptor', function () {
	return {
		request: function (config) {
			config.headers['X-Requested-With'] = 'Fetch';
			return config;
		}
	};
})
.config(['$httpProvider', function($httpProvider) {
	//check if response is error. errors currently are non-json formatted and fail too early
	$httpProvider.defaults.transformResponse.unshift(function(data, headersGetter, status){
		if(status>399){
			data = {
				"error": data
			}
			data = JSON.stringify(data);
		}
		return data;
	});
	$httpProvider.interceptors.push('httpRequestInterceptor');
}])
.factory('$messageHub', [function(){
	var messageHub = new FramesMessageHub();	
	var message = function(evtName, data){
		messageHub.post({data: data}, 'workspace.' + evtName);
	};
	var announceFileSelected = function(fileDescriptor){
		this.message('file.selected', fileDescriptor);
	};
	var announceFileCreated = function(fileDescriptor){
		this.message('file.created', fileDescriptor);
	};
	var announceFileOpen = function(fileDescriptor){
		this.message('file.open', fileDescriptor);
	};
	var announcePull = function(fileDescriptor){
		this.message('file.pull', fileDescriptor);
	};
	return {
		message: message,
		announceFileSelected: announceFileSelected,
		announceFileCreated: announceFileCreated,
		announceFileOpen: announceFileOpen,
		announcePull: announcePull,
		on: function(evt, cb){
			messageHub.subscribe(cb, evt);
		}
	};
}])
.factory('$treeConfig', [function(){
	return {
		'core' : {
			'themes': {
				"name": "default",
				"responsive": false,
				"dots": false,
				"icons": true,
				'variant' : 'small',
				'stripes' : true
			}
		},
		'plugins': ['state','dnd','sort','types','contextmenu','unique'],
		"types": {
			"default": {
				"icon": "fa fa-file-o",
				"default_name": "file",
				"template_new_name": "{name}{counter}"
			},
			'file': {
				"valid_children": []
			},
			'folder': {
				"default_name": "folder",
				'icon': "fa fa-folder-o"
			},
			"project": {
				"icon": "fa fa-clone"
			}
		},
		"contextmenu": {
			"items" : function(node) {
				var ctxmenu = {};
				ctxmenu.pull = {
					"separator_before": false,
					"label": "Pull",
					"action": function(data){
						var tree = $.jstree.reference(data.reference);
						var node = tree.get_node(data.reference);
						tree.element.trigger('jstree.workspace.pull', [node.original._file]);
					}.bind(this)
				};
				ctxmenu.push = {
					"separator_before": false,
					"label": "Push",
					"action": function(data){
						var tree = $.jstree.reference(data.reference);
						var node = tree.get_node(data.reference);
						tree.element.trigger('jstree.workspace.push', [node.original._file]);
					}.bind(this)
				};
				ctxmenu.reset = {
					"separator_before": false,
					"label": "Reset",
					"action": function(data){
						var tree = $.jstree.reference(data.reference);
						var node = tree.get_node(data.reference);
						tree.element.trigger('jstree.workspace.reset', [node.original._file]);
					}.bind(this)
				};
				ctxmenu.share = {
						"separator_before": false,
						"label": "Share",
						"action": function(data){
							var tree = $.jstree.reference(data.reference);
							var node = tree.get_node(data.reference);
							tree.element.trigger('jstree.workspace.share', [node.original._file]);
						}.bind(this)
					};
				
				return ctxmenu;
			}
		}
	}
}])
.factory('gitService', ['$http', 'GIT_SVC_URL', '$treeConfig', function($http, GIT_SVC_URL, $treeConfig){
	return new GitService($http, GIT_SVC_URL, $treeConfig);
}])
.factory('envService', ['$http', 'ENV_SVC_URL', function($http, ENV_SVC_URL){
	return new EnvService($http, ENV_SVC_URL);
}])
.factory('workspaceService', ['$http', 'WS_SVC_MANAGER_URL', 'WS_SVC_URL', '$treeConfig', function($http, WS_SVC_MANAGER_URL, WS_SVC_URL, $treeConfig){
	return new WorkspaceService($http, WS_SVC_MANAGER_URL, WS_SVC_URL, $treeConfig);
}])
.factory('workspaceTreeAdapter', ['$treeConfig', 'workspaceService', 'gitService', '$messageHub', function($treeConfig, WorkspaceService, GitService, $messageHub){
	return new WorkspaceTreeAdapter($treeConfig, WorkspaceService, GitService, $messageHub);
}])
.controller('WorkspaceController', ['workspaceService', 'workspaceTreeAdapter', 'gitService', 'envService', '$messageHub', function (workspaceService, workspaceTreeAdapter, gitService, envService, $messageHub) {

	this.wsTree;
	this.workspaces;
	this.selectedWorkspace;
	
	workspaceService.listWorkspaceNames()
		.then(function(workspaceNames) {
			this.workspaces = workspaceNames;
			var storedWorkspace = JSON.parse(localStorage.getItem('DIRIGIBLE.workspace'));
			if (storedWorkspace !== null) {
				this.selectedWorkspace = storedWorkspace.name;
				this.workspaceSelected();
			} else if(this.workspaces[0]) {
				this.selectedWorkspace = this.workspaces[0];
				this.workspaceSelected();					
			} 
		}.bind(this));
	
	this.workspaceSelected = function(){
		if (this.wsTree) {
			this.wsTree.workspaceName = this.selectedWorkspace;
			localStorage.setItem('DIRIGIBLE.workspace', JSON.stringify({"name": this.selectedWorkspace}));
			this.wsTree.refresh();
			return;
		}
		this.wsTree = workspaceTreeAdapter.init($('.workspace'), this.selectedWorkspace, this);
		if(!workspaceService.typeMapping)
			workspaceService.typeMapping = $treeConfig[types];
		this.wsTree.refresh();
	};
	
	this.okClone = function() {
		if (this.clone.url) {
			gitService.cloneProject(this.wsTree, this.selectedWorkspace, this.clone.url, null, this.username, this.password);
		}
	};

	this.okPullAll = function() {
		gitService.pullAllProjects(this.wsTree, this.selectedWorkspace, this.username, this.password);
	};

	this.okPull = function() {
		gitService.pullProject(this.wsTree, this.selectedWorkspace, this.selectedProject, this.username, this.password);
	};
	
	this.okPushAll = function() {
		gitService.pushAllProjects(this.wsTree, this.selectedWorkspace, this.commitMessage, this.username, this.password, this.email);
	};

	this.okPush = function() {
		gitService.pushProject(this.wsTree, this.selectedWorkspace, this.selectedProject, this.commitMessage, this.username, this.password, this.email);
	};
	
	this.okReset = function() {
		gitService.resetProject(this.wsTree, this.selectedWorkspace, this.selectedProject, this.username, this.password);
	};
	
	this.okShare = function() {
		gitService.shareProject(this.wsTree, this.selectedWorkspace, this.selectedProject, this.repository, this.branch, this.commitMessage, this.username, this.password, this.email);
	};
	
	this.refresh = function(){
		this.wsTree.refresh();
	};
	
	$messageHub.on('git.repository.run', function(msg) {
		if (msg.data.env) {
			envService.setEnv(msg.data.env);
		}
		gitService.cloneProject(this.wsTree, this.selectedWorkspace, msg.data.repository, msg.data.branch, msg.data.username, msg.data.password);
		if (msg.data.uri) {
			run();
		}
		
		function sleep(ms) {
		  return new Promise(resolve => setTimeout(resolve, ms));
		}
			
		async function run() {
		  await sleep(2000);
		  window.open(msg.data.uri, '_parent');
		}
	}.bind(this));
	
}]);




© 2015 - 2025 Weber Informatics LLC | Privacy Policy