Viewing File: /usr/local/cpanel/base/frontend/jupiter/version_control/views/listRepositoriesController.js
/*
# version_control/views/listRepositoriesController.js Copyright 2022 cPanel, L.L.C.
# All rights reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/
/* global define, PAGE */
define(
[
"angular",
"lodash",
"cjt/util/locale",
"cjt/util/table",
"uiBootstrap",
"cjt/filters/wrapFilter",
"cjt/services/cpanel/nvDataService",
"app/services/versionControlService",
"app/services/sseAPIService",
"cjt/services/alertService",
"cjt/directives/alert",
"cjt/directives/alertList",
"cjt/directives/actionButtonDirective"
],
function(angular, _, LOCALE, Table) {
"use strict";
var app = angular.module("cpanel.versionControl");
app.value("PAGE", PAGE);
var controller = app.controller(
"ListRepositoriesController",
["$scope", "$window", "$location", "versionControlService", "sseAPIService", "PAGE", "nvDataService", "alertService", "$timeout",
function($scope, $window, $location, versionControlService, sseAPIService, PAGE, nvDataService, alertService, $timeout) {
var repositories = this;
repositories.isLoading = false;
repositories.list = [];
repositories.cloningList = [];
var sseURL = PAGE.securityToken + "/sse/UserTasks";
var SSEObj;
// SSE events and config
var events = [ "task_processing", "task_complete", "task_failed" ];
var config = { json: true };
repositories.homeDirPath = PAGE.homeDir;
repositories.hasFilemanagerAccess = (PAGE.hasFileManagerAccess === "0") ? false : true;
repositories.hasShellAccess = (PAGE.hasShellAccess === "0") ? false : true;
var table = new Table();
table.setSort("name", "asc");
repositories.meta = table.getMetadata();
repositories.filteredList = table.getList();
repositories.paginationMessage = table.paginationMessage;
repositories.meta.pageSize = parseInt(PAGE.reposListPageSize, 10);
/**
* Search repository by name and path
* @method searchByNameOrFolder
* @param {Object} item Item in repositories list
* @param {String} searchText Text to search for
*/
function searchByNameOrFolder(item, searchText) {
searchText = searchText.toLowerCase();
return item.name.toLowerCase().indexOf(searchText) !== -1 ||
item.repository_root.toLowerCase().indexOf(searchText) !== -1;
}
table.setSearchFunction(searchByNameOrFolder);
/**
* Render repository list
* @method render
*/
repositories.render = function() {
repositories.filteredList = table.update();
};
/**
* Sort repository list
* @method sortList
*/
repositories.sortList = function() {
repositories.render();
};
/**
* Select repository page
* @method selectPage
*/
repositories.selectPage = function() {
repositories.render();
};
/**
* Selects page size
* @method selectPageSize
*/
repositories.selectPageSize = function() {
repositories.render();
if (PAGE.reposListPageSize !== repositories.meta.pageSize) {
nvDataService.setObject({ repos_list_page_size: repositories.meta.pageSize })
.then(function() {
PAGE.reposListPageSize = repositories.meta.pageSize;
})
.catch(function(error) {
alertService.add({
type: "danger",
message: error.message,
closeable: true,
replace: false,
group: "versionControl"
});
});
}
};
/**
* Implements search for repository
* @method searchList
*/
repositories.searchList = function() {
repositories.render();
};
/**
* Initialization of the List Repositories page.
* @method init
*/
repositories.init = function() {
var pageErrors = PAGE.repoErrors;
if (pageErrors.length > 0) {
// Potential cache corruption, attempting to load via JS to display error messages.
pageErrors.forEach(function(error) {
alertService.add({
type: "danger",
message: error,
closeable: true,
replace: false,
group: "versionControl"
});
});
} else {
// Updates the list with the current API cache.
repositories.updateRepositoriesList(true);
}
};
/**
* Extend repository object to add few fields to manage state
* @method extendRepositoryObject
* @param {Object} repoObject repository
* @returns {Object} updated repository object
*/
function extendRepositoryObject(repoObject) {
if (repoObject) {
repoObject.isExpanded = false;
repoObject.detailsLoading = false;
repoObject.delete_requested = false;
repoObject.cloneState = "";
}
return repoObject;
}
/**
* Resets clone state of repository
* @method clearCloning
* @param {Object} repoObject repository
* @returns {Object} updated repository object
*/
function clearCloning(repoObject) {
if (repoObject) {
repoObject.cloneState = "";
repoObject.cloneInProgress = false;
delete repoObject.cloneTaskID;
}
return repoObject;
}
/**
* Calls the API to update the repositories list.
* @method updateRepositoriesList
* @param {Boolean} forceLoad Tells the method to pull the data from the API.
*/
repositories.updateRepositoriesList = function(forceLoad) {
repositories.isLoading = true;
var attributeStr = (forceLoad) ? "name,tasks" : null;
return versionControlService.listRepositories(forceLoad, attributeStr)
.then(function(response) {
repositories.list = _.map(response, function(obj) {
return extendRepositoryObject(obj);
});
for (var i = 0, len = repositories.list.length; i < len; i++) {
if (repositories.list[i].cloneInProgress) {
repositories.cloningList.push(
repositories.list[i]
);
}
}
// Initiate SSE when atleast one repository is being cloned
if (repositories.cloningList && repositories.cloningList.length > 0) {
sseAPIService.initialize();
}
table.load(repositories.list);
repositories.render();
repositories.isLoading = false;
}, function(error) {
alertService.add({
type: "danger",
message: error.message,
closeable: true,
replace: false,
group: "versionControl"
});
repositories.isLoading = false;
});
};
/**
* Handles task_processing.
*
* @method
* @param {sse:task_processing} event - Task processing event.
* @param {Object} data - Data
* @listens sse:task_processing
*/
$scope.$on("sse:task_processing", function(event, data) {
var taskID = data.task_id;
var cloneItem = _.find(repositories.cloningList, function(o) {
return o.cloneTaskID === taskID;
});
if (cloneItem) {
var unfilteredIndex = _.indexOf(repositories.list, cloneItem);
if (unfilteredIndex !== -1) {
cloneItem.cloneState = "processing";
_.extend( repositories.list[unfilteredIndex], cloneItem );
$scope.$apply(repositories.render);
}
}
});
/**
* Handles task_complete.
*
* @method
* @param {sse:task_complete} event - Task complete event.
* @param {Object} data - Data
* @listens sse:task_complete
*/
$scope.$on("sse:task_complete", function(event, data) {
var taskID = data.task_id;
var cloneItem = _.find(repositories.cloningList, function(o) {
return o.cloneTaskID === taskID;
});
if (cloneItem) {
var unfilteredIndex = _.indexOf(repositories.list, cloneItem);
if (unfilteredIndex !== -1) {
cloneItem.cloneState = "complete";
_.extend( repositories.list[unfilteredIndex], cloneItem );
$scope.$apply(repositories.render);
// removing object from clonning list because clone is complete
_.remove(repositories.cloningList, cloneItem);
if (repositories.cloningList.length === 0) {
sseAPIService.close(SSEObj);
}
$timeout(function() {
// Using timeout to visually display success on the row and later change it to a normal row.
return versionControlService.getRepositoryInformation(cloneItem.repository_root, "name,tasks")
.then(function(response) {
var repoDetails = extendRepositoryObject(response);
// updating the repository list with new information so that the row is active
_.extend(repositories.list[unfilteredIndex], clearCloning(repoDetails));
// Remove clone information message
alertService.removeById(taskID, "versionControl");
repositories.render();
}, function(error) {
// Remove clone information message
alertService.removeById(taskID, "versionControl");
// display error
alertService.add({
type: "danger",
message: error.message,
closeable: true,
replace: false,
group: "versionControl"
});
});
}, 5000);
}
}
});
/**
* Handles task_failed.
*
* @method
* @param {sse:task_failed} event - Task failed event.
* @param {Object} data - Data
* @listens sse:task_failed
*/
$scope.$on("sse:task_failed", function(event, data) {
var taskID = data.task_id;
var cloneItem = _.find(repositories.cloningList, function(o) {
return o.cloneTaskID === taskID;
});
if (cloneItem) {
var unfilteredIndex = _.indexOf(repositories.list, cloneItem);
_.remove(repositories.cloningList, cloneItem);
if (repositories.cloningList.length === 0) {
sseAPIService.close(SSEObj);
}
if (unfilteredIndex !== -1) {
repositories.list.splice(unfilteredIndex, 1);
alertService.add({
type: "danger",
message: LOCALE.maketext("Error occurred while cloning repository “[_1]”.", cloneItem.name),
closeable: true,
replace: false,
group: "versionControl"
});
$scope.$apply(repositories.render);
}
}
});
/**
* Handles ready.
*
* @method
* @param {sse:ready} event - Task ready event.
* @listens sse:ready
*/
$scope.$on("sse:ready", function(event) {
SSEObj = sseAPIService.connect(sseURL, events, config);
});
/**
* Handles destroy.
*
* @method
* @listens $destroy
*/
$scope.$on("$destroy", function() {
if (SSEObj) {
sseAPIService.close(SSEObj);
}
});
/**
* Opens repository in gitWeb
* @method redirectToGitWeb
* @param {String} gitWebURL gitWebURL for the repository
* @param {String} repoName Repository name
*/
repositories.redirectToGitWeb = function(gitWebURL, repoName) {
if (gitWebURL) {
$window.open(gitWebURL, repoName + "GitWeb");
} else {
alertService.add({
type: "danger",
message: LOCALE.maketext("Unable to find repository web url"),
closeable: true,
replace: false,
group: "versionControl"
});
}
};
/**
* Opens repository path in file manager
* @method redirectToFileManager
* @param {String} fileManagerURL file Manager url for the repository path
* @param {String} repoName Repository name
*/
repositories.redirectToFileManager = function(fileManagerURL, repoName) {
if (fileManagerURL) {
$window.open(fileManagerURL, repoName + "FileManager");
} else {
alertService.add({
type: "danger",
message: LOCALE.maketext("Unable to redirect to File Manager interface"),
closeable: true,
replace: false,
group: "versionControl"
});
}
};
/**
* Copies the repo's clone link to you machine's clipboard
* @method cloneToClipboard
* @param {String} cloneUrl The URL to be used to clone repos.
*/
repositories.cloneToClipboard = function(cloneUrl) {
try {
var result = versionControlService.cloneToClipboard(cloneUrl);
if (result) {
alertService.add({
type: "success",
message: LOCALE.maketext("The system successfully copied the “[_1]” clone [output,acronym,URL,Uniform Resource Locator] to the clipboard.", cloneUrl),
closeable: true,
replace: false,
autoClose: 10000,
group: "versionControl"
});
}
} catch (error) {
alertService.add({
type: "danger",
message: error,
closeable: true,
replace: false,
group: "versionControl"
});
}
};
/**
* Create Repository View
* @method createRepository
*/
repositories.createRepository = function() {
alertService.clear("", "versionControl");
$location.path("/create");
};
/**
* Deletes a repository
* @method delete
* @param {String} repo The repository to delete.
* @return {Promise} Returns a promise from the VersionControlService.deleteRepository method for success/error handling when the user requests to delete a repository.
*/
repositories.delete = function(repo) {
repo.removing = true;
var successMessage;
if (repositories.hasFilemanagerAccess) {
successMessage = LOCALE.maketext("The system successfully removed the “[_1]” repository from the list of [asis,cPanel]-managed repositories. You can use the [output,url,_2,File Manager,target,_3] interface to delete the repository contents.", repo.name, repo.fileManagerRedirectURL, "file-manager");
} else {
successMessage = LOCALE.maketext("The system successfully removed the “[_1]” repository from the list of [asis,cPanel]-managed repositories.", repo.name);
}
return versionControlService.deleteRepository(repo.repository_root)
.then(function() {
table.remove(repo);
repositories.render();
alertService.add({
type: "success",
message: successMessage,
closeable: true,
replace: false,
autoClose: false,
group: "versionControl"
});
}, function(error) {
alertService.add({
type: "danger",
message: LOCALE.maketext("The system could not remove the “[_1]” repository in the “[_2]” directory.", repo.name, repo.repository_root),
closeable: true,
replace: false,
group: "versionControl"
});
repo.removing = false;
repo.delete_requested = false;
});
};
/**
* Delete repository confirmation message.
* @method deleteText
* @param {Object} repo The repository's data representation of the repository that should be deleted.
* @return {String} Returns a dynamic string as a message to the user, that cooresponds to the exact repository within the delete action-scope, to inform/ask the user if they are certain that they would like to permanatly delete a repository from their cPanel instance/account/system.
*/
repositories.deleteText = function(repo) {
return LOCALE.maketext("Are you sure that you want to remove the “[_1]” repository from the list of [asis,cPanel]-managed repositories?", repo.name);
};
/**
* Redirects user to the version control manage page for a specified repo.
* @method manageRepository
* @param {String} repoPath Represents the repository_root of the repo object in the repo list.
*/
repositories.manageRepository = function(repoPath) {
$location.path("/manage/" + encodeURIComponent(repoPath) + "/basic-info");
};
/**
* Get the repository index.
* @method getRepositoryIndex
* @param {String} repositoryRoot Repository root
* @return {Number} return the index
*/
function getRepositoryIndex(repositoryRoot) {
return _.findIndex(repositories.filteredList, function(o) {
return o.repository_root === repositoryRoot;
});
}
/* Gets repository details
* @method repositories.getRepositoryDetails
* @param {Object} repo Repository
* @param {Boolean} expandState Current Expanded state
* @return {Promise} return promise
*/
repositories.getRepositoryDetails = function(repo, expandState) {
repo.detailsLoading = true;
var index;
// When changing from collapse to expand
if (expandState) {
return versionControlService.getRepositoryInformation(repo.repository_root, "name,clone_urls,branch,last_update,source_repository")
.then(function(response) {
index = getRepositoryIndex(repo.repository_root);
if (index !== -1) {
response.detailsLoading = false;
response.isExpanded = true;
// Retrieving back the state of delete
response.delete_requested = repo.delete_requested;
_.assign(repo, response);
}
// Use assign to update the source object in-place
_.assign(repo, response);
}, function(error) {
alertService.add({
type: "danger",
message: error.message,
closeable: true,
replace: false,
group: "versionControl"
});
});
} else {
repo.detailsLoading = false;
repo.isExpanded = false;
}
};
repositories.init();
}
]
);
return controller;
}
);
Back to Directory
File Manager