release version 1.11.0

This commit is contained in:
2025-07-10 23:47:05 +03:00
parent 5cb6857fa1
commit 8dd9cf9cf2
3082 changed files with 278464 additions and 1833 deletions

View File

@ -0,0 +1,80 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
package ru.entaxy.ui.hawtio.cicd;
import io.hawt.web.plugin.HawtioPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* The Plugin Context Listener used to load in the plugin
**/
public class PluginContextListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory.getLogger(PluginContextListener.class);
HawtioPlugin plugin = null;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext context = servletContextEvent.getServletContext();
plugin = new HawtioPlugin();
plugin.setContext(context.getContextPath());
plugin.setName(context.getInitParameter("plugin-name"));
plugin.setScripts(context.getInitParameter("plugin-scripts"));
plugin.setDomain(null);
try {
plugin.init();
} catch (Exception e) {
throw createServletException(e);
}
LOG.info("Initialized {} plugin", plugin.getName());
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
try {
plugin.destroy();
} catch (Exception e) {
throw createServletException(e);
}
LOG.info("Destroyed {} plugin", plugin.getName());
}
protected RuntimeException createServletException(Exception e) {
return new RuntimeException(e);
}
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~~~~~~licensing~~~~~~
entaxy-cicd-plugin
==========
Copyright (C) 2020 - 2025 EmDev LLC
==========
You may not use this file except in accordance with the License Terms of the Copyright
Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
rights to the Software and any copies are the property of the Copyright Holder. Unless
it is explicitly allowed the Copyright Holder, the User is prohibited from using the
Software for commercial purposes to provide services to third parties.
The Copyright Holder hereby declares that the Software is provided on an "AS IS".
Under no circumstances does the Copyright Holder guarantee or promise that the
Software provided by him will be suitable or not suitable for the specific purposes
of the User, that the Software will meet all commercial and personal subjective
expectations of the User, that the Software will work properly, without technical
errors, quickly and uninterruptedly.
Under no circumstances shall the Copyright Holder or its Affiliates is not liable
to the User for any direct or indirect losses of the User, his expenses or actual
damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
or damage to data, property, etc.
~~~~~~/licensing~~~~~~
-->
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>Entaxy HawtIO management plugin</description>
<display-name>entaxy hawt.io management plugin</display-name>
<context-param>
<description>Plugin's path on the server</description>
<param-name>plugin-context</param-name>
<param-value>${plugin-context}</param-value>
</context-param>
<context-param>
<description>Plugin's path on the server</description>
<param-name>plugin-name</param-name>
<param-value>${plugin-name}</param-value>
</context-param>
<context-param>
<description>Plugin's path on the server</description>
<param-name>plugin-domain</param-name>
<param-value>${plugin-domain}</param-value>
</context-param>
<context-param>
<description>Plugin's path on the server</description>
<param-name>plugin-scripts</param-name>
<param-value>${plugin-scripts}</param-value>
</context-param>
<context-param>
<description>Disable listing of directories and files</description>
<param-name>org.eclipse.jetty.servlet.Default.dirAllowed</param-name>
<param-value>false</param-value>
</context-param>
<listener>
<listener-class>ru.entaxy.ui.hawtio.cicd.PluginContextListener</listener-class>
</listener>
</web-app>

View File

@ -0,0 +1,193 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdApplication', {
template:
`
<div class="entaxy-cicd-zero-revision-note" ng-if="$ctrl.isRevisionSelected && $ctrl.revision === '0'">
<entaxy-form-field-extra-info type="'info'" message="$ctrl.zeroRevisionNote"></entaxy-form-field-extra-info>
</div>
<div ng-if="$ctrl.versions || $ctrl.isVersionSelected || $ctrl.isRevisionSelected"
class="entaxy-cicd-header-container">
<div class="entaxy-cicd-title-with-info-container">
<span class="first" ng-class="{'lead': !$ctrl.isVersionSelected && !$ctrl.isRevisionSelected}">
Application: {{$ctrl.application}}
</span>
<span ng-class="{'lead': $ctrl.isVersionSelected}"
ng-if="$ctrl.isVersionSelected || $ctrl.isRevisionSelected">
Version: {{$ctrl.version}}
</span>
<div ng-if="!$ctrl.isVersionSelected && !$ctrl.isRevisionSelected">
<span>Version:</span>
<entaxy-select-from-enum values="$ctrl.versions" model="$ctrl.version"
is-empty-included="false"></entaxy-select-from-enum>
</div>
<span ng-if="$ctrl.isVersionSelected">
Last Revision: {{$ctrl.lastRevision}}
</span>
<span ng-if="$ctrl.isVersionSelected">
Installed Revision: {{$ctrl.installedRevision}}
</span>
<span class="lead" ng-if="$ctrl.isRevisionSelected">
Revision: {{$ctrl.revision}}
</span>
<span ng-if="$ctrl.isRevisionSelected">
Revision Status: {{$ctrl.revisionStatus}}
</span>
</div>
<div ng-if="$ctrl.isRevisionSelected" class="entaxy-cicd-header-buttons-container">
<entaxy-ci-cd-application-management-buttons storage="$ctrl.storage" application="$ctrl.application"
version="$ctrl.version" revision="$ctrl.revision" revision-status="$ctrl.revisionStatus">
</entaxy-ci-cd-application-management-buttons>
</div>
<div class="dropdown primary-action entaxy-cicd-header-buttons-container"
uib-dropdown ng-if="$ctrl.isVersionSelected">
<button class="dropdown-toggle" uib-dropdown-toggle type="button">
Add Revision
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li role="menuitem" ng-click="$ctrl.addRevision()">
<a class="secondary-action">Add Revision</a>
</li>
<li role="menuitem" ng-click="$ctrl.addRevisionFromExistent()">
<a class="secondary-action">Add Revision From Existent</a>
</li>
</ul>
</div>
</div>
<div class="entaxy-cicd-content-container">
<h2 class="first">
Items
</h2>
<entaxy-ci-cd-application-items version="$ctrl.version"></entaxy-ci-cd-application-items>
<h2>
Requirements
</h2>
<entaxy-ci-cd-requirements version="$ctrl.version" type="Application"></entaxy-ci-cd-requirements>
</div>
`,
controller: EntaxyCICDApplicationController
})
.name;
function EntaxyCICDApplicationController(workspace, $uibModal, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.zeroRevisionNote = 'Revision 0 cannot be configured';
ctrl.$onInit = function() {
ctrl.storage = EntaxyCICD.getStorage(workspace.selection);
ctrl.application = EntaxyCICD.getProjectOrApplication(workspace.selection);
ctrl.isVersionSelected = EntaxyCICD.isVersion(workspace.selection);
ctrl.isRevisionSelected = EntaxyCICD.isRevision(workspace.selection);
if (ctrl.isVersionSelected || ctrl.isRevisionSelected) {
ctrl.version = EntaxyCICD.getVersion(workspace.selection);
if (ctrl.isRevisionSelected) {
let revisionInfo = EntaxyCICD.getRevisionInfo(workspace.selection);
ctrl.revision = revisionInfo.revision;
ctrl.revisionStatus = revisionInfo.revisionStatus;
} else {
entaxyCICDService.executeOperation('readApplicationVersionLastAndInstalledRevision',
[ctrl.storage, ctrl.application, ctrl.version])
.then(result => {
let revisionsInfo = JSON.parse(result);
ctrl.lastRevision = revisionsInfo.lastRevision;
ctrl.installedRevision = revisionsInfo.installedRevision;
});
}
} else {
populateVersions();
}
}
function populateVersions() {
ctrl.versions = EntaxyCICD.getVersions(workspace.selection);
if (ctrl.versions.length > 0) {
ctrl.version = ctrl.versions[ctrl.versions.length - 1];
}
}
ctrl.addRevision = function () {
createRevision(-1);
}
ctrl.addRevisionFromExistent = function () {
let formFields = [
{
label: 'Prototype Revision',
name: 'prototypeRevision',
enum: true,
required: true,
values: workspace.selection.children.map(revision => revision.title.split(' ')[0]),
setFocused: true
}
];
openCreateRevisionModal(formFields);
}
function openCreateRevisionModal(formFields) {
$uibModal.open({
component: 'entaxyCiCdSimpleFieldsModal',
resolve: {
modalTitle: () => 'Create Revision',
formFields: () => formFields
},
backdrop: 'static'
}).result.then((args) => {
createRevision(...args);
}, reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function createRevision(prototypeRevision) {
entaxyCICDService.executeOperation('createRevision',
[ctrl.storage, ctrl.application, ctrl.version, prototypeRevision])
.then(result => {
Entaxy.notificationSuccess(result);
entaxyCICDService.treeUpdated();
}).catch(error => {
Entaxy.notificationError(error);
});
}
}
EntaxyCICDApplicationController.$inject = ['workspace', '$uibModal', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,108 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdApplicationManagementButtons', {
bindings: {
storage: '<',
application: '<',
version: '<',
revision: '<',
revisionStatus: '<',
isConfigurationDirty: '<'
},
template:
`
<button type="button" ng-click="$ctrl.configure()"
ng-if="!$ctrl.isInstalled && !$ctrl.isUninstalled">Configure</button>
<button type="button" ng-click="$ctrl.deploy()"
ng-if="!$ctrl.isInstalled && !$ctrl.isUninstalled">Deploy</button>
<button type="button" ng-click="$ctrl.install()" ng-if="!$ctrl.isInstalled">Install</button>
<button type="button" ng-click="$ctrl.uninstall()" ng-if="$ctrl.isInstalled">Uninstall</button>
`,
controller: EntaxyCICDApplicationManagementButtonsController
})
.name;
function EntaxyCICDApplicationManagementButtonsController(workspace, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
ctrl.isConfigured = ctrl.revisionStatus === EntaxyCICD.REVISION_STATUS.CONFIGURED;
ctrl.isDeployed = ctrl.revisionStatus === EntaxyCICD.REVISION_STATUS.DEPLOYED;
ctrl.isInstalled = ctrl.revisionStatus === EntaxyCICD.REVISION_STATUS.INSTALLED;
ctrl.isUninstalled = ctrl.revisionStatus === EntaxyCICD.REVISION_STATUS.UNINSTALLED;
}
const OPERATION_TYPE = {
CONFIGURE: 'configure',
DEPLOY: 'deploy',
INSTALL: 'install',
UNINSTALL: 'uninstall'
}
ctrl.configure = function () {
processOperation(OPERATION_TYPE.CONFIGURE);
}
ctrl.deploy = function () {
processOperation(OPERATION_TYPE.DEPLOY);
}
ctrl.install = function () {
processOperation(OPERATION_TYPE.INSTALL);
}
ctrl.uninstall = function () {
processOperation(OPERATION_TYPE.UNINSTALL);
}
function processOperation(operationType) {
if (!ctrl.isConfigurationDirty || confirm(Entaxy.CONFIRMATION.UNSAVED_CHANGES)) {
entaxyCICDService.executeOperation(operationType + 'Revision',
[ctrl.storage, ctrl.application, ctrl.version, ctrl.revision])
.then(result => {
let message =
operationType === OPERATION_TYPE.INSTALL || operationType === OPERATION_TYPE.UNINSTALL ?
EntaxyCICD.capitalize(operationType) + 'ation started successfully. ' +
'<b>Please notice that operation may take some time.</b>' : result;
Entaxy.notification(Entaxy.NOTIFICATION_TYPE.SUCCESS, message,
Entaxy.configuration[Entaxy.CONFIGURATION_KEYS.NOTIFICATION_TIMEOUT_SUCCESS]);
entaxyCICDService.treeUpdated();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
}
EntaxyCICDApplicationManagementButtonsController.$inject = ['workspace', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,143 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdApplications', {
template:
`
<div class="entaxy-cicd-content-with-title-container">
<h2>
Applications
</h2>
<entaxy-ci-cd-applications-table type="Application"
import-from-file="$ctrl.importFromFile" import-from-repository="$ctrl.importFromRepository">
</entaxy-ci-cd-applications-table>
</div>
`,
controller: EntaxyCICDApplicationsController
})
.name;
function EntaxyCICDApplicationsController(workspace, $uibModal, entaxyCICDService) {
'ngInject';
let ctrl = this;
const isStorageSelected = EntaxyCICD.isStorage(workspace.selection);
ctrl.$onInit = function() {
}
function getFormFields(isFromRepository) {
let formFields = [
{
name: 'storage',
label: 'Storage',
type: 'string',
value: isStorageSelected ? workspace.selection.title : undefined,
enum: isStorageSelected ? undefined : true,
values: isStorageSelected ? undefined : workspace.selection.children.map(child => child.title),
required: true,
readOnly: isStorageSelected ? true : undefined,
setFocused: true
}
];
if (isFromRepository) {
formFields.push({
name: 'mavenUrl',
label: 'Maven Url',
type: 'string',
required: true
});
} else {
formFields.push({
name: 'file',
label: 'File',
resource: true,
required: true
});
}
return formFields;
}
ctrl.importFromFile = function () {
openModalAndProcessResults(false);
}
ctrl.importFromRepository = function () {
openModalAndProcessResults(true);
}
function openModalAndProcessResults(isFromRepository) {
$uibModal.open({
component: 'entaxyCiCdSimpleFieldsModal',
resolve: {
modalTitle: () => 'Import Application From ' + (isFromRepository ? 'Repository' : 'File'),
formFields: () => getFormFields(isFromRepository)
},
backdrop: 'static'
})
.result.then(args => {
if (isFromRepository) {
processOperation('importFromRepository', args);
} else {
importFromFile(args);
}
},
reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function importFromFile(args) {
let file = args[1];
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onloadend = function () {
const base64String = btoa(reader.result);
processOperation('importFromBase64String', [args[0], base64String]);
}
}
function processOperation(operationName, properties) {
entaxyCICDService.executeOperation(operationName, properties)
.then(result => {
Entaxy.notificationSuccess(result);
entaxyCICDService.treeUpdated();
})
.catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
EntaxyCICDApplicationsController.$inject = ['workspace', '$uibModal', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,297 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdConfiguration', {
bindings: {
configurationId: '<',
configured: '<',
isDirty: '='
},
template:
`
<div class="entaxy-cicd-header-container">
<h2>
Configuration: {{$ctrl.configurationId}}
</h2>
</div>
<div class="entaxy-cicd-subtitle-info-container">
<span>Configured Id: {{$ctrl.configuredId}}</span>
<span>Configured Type: {{$ctrl.configuredType}}</span>
</div>
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<form name="entaxyObjectForm" class="form-horizontal">
<div class="entaxy-table-with-inputs" ng-if="$ctrl.viewedItems && $ctrl.viewedItems.length > 0">
<table datatable="ng" dt-options="$ctrl.dtOptions"
class="table-view-container table table-striped table-bordered table-hover dataTable no-footer">
<thead>
<tr role="row">
<th>Name</th>
<th>Display Name</th>
<th>Imported Value</th>
<th>Local Value</th>
</tr>
</thead>
<tbody>
<tr role="row" ng-repeat="field in $ctrl.viewedItems">
<td ng-class="{'red': field.isRed, 'green': field.isGreen, 'bold': field.importedValue !== field.originValue}">
{{ field.name }}
</td>
<td>{{ field.displayName }}</td>
<td class="field-input-cell" ng-class="{'field-input-checkbox-cell': field.type === 'checkbox'}"
ng-if="$ctrl.configured">
<input type="{{field.type}}" ng-class="{'form-control': field.type !== 'checkbox'}"
ng-model="field.importedValue" ng-change="$ctrl.checkDirtiness()"/>
</td>
<td ng-if="!$ctrl.configured">{{ field.importedValue }}</td>
<td>{{ field.localValue }}</td>
</tr>
</tbody>
</table>
</div>
</form>
<pf-empty-state ng-if="!$ctrl.viewedItems || $ctrl.viewedItems.length == 0"></pf-empty-state>
`,
controller: EntaxyCICDConfigurationController
})
.name;
function EntaxyCICDConfigurationController(workspace, $scope, $location, entaxyCICDService, entaxyService,
entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.dtOptions = {
autoWidth: false,
destroy: true,
order: [[0, "asc"]],
dom: "t",
paging: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Display Name',
placeholder: 'Filter by Display Name...',
filterType: 'text'
},
{
id: 'name',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'name') {
match = item.name.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'displayName') {
match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
}
return match;
};
ctrl.checkDirtiness = function () {
if ($scope.entaxyObjectForm.$dirty) {
let isDirty = false;
for (let i = 0; i < ctrl.items.length; i++) {
if (ctrl.items[i].importedValue !== ctrl.items[i].originValue) {
isDirty = true;
break;
}
}
if (!isDirty) {
$scope.entaxyObjectForm.$setPristine();
}
}
}
setTimeout( function () {
ctrl.activeTabIndex = entaxyService.getActiveTabIndex();
});
$scope.$on("$locationChangeStart", function(event) {
if ($scope.entaxyObjectForm.$dirty && !confirm(Entaxy.CONFIRMATION.UNSAVED_CHANGES)) {
event.preventDefault();
ctrl.isTreeOrTabSelectionUpdateNeeded = true;
}
});
$scope.$watch('$ctrl.isTreeOrTabSelectionUpdateNeeded', function (newValue) {
if (newValue) {
setTimeout(function () {
entaxyService.updateTabSelection(ctrl.activeTabIndex);
});
Jmx.updateTreeSelectionFromURL($location, $(entaxyCICDTreeElementId));
ctrl.isTreeOrTabSelectionUpdateNeeded = false;
}
});
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
if (ctrl.configured) {
let primaryActions = [
{ name: 'Clear Changes', actionFn: clearChanges },
{ name: 'Copy Local Values', actionFn: useLocalValues },
{ name: 'Save Changes', actionFn: save }
];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
}
}
const storage = EntaxyCICD.getStorage(workspace.selection);
const application = EntaxyCICD.getProjectOrApplication(workspace.selection);
const version = EntaxyCICD.getVersion(workspace.selection);
const revision = workspace.selection.title.split(' ')[0];
$scope.$watch('entaxyObjectForm.$dirty', function () {
ctrl.isDirty = $scope.entaxyObjectForm.$dirty;
});
$scope.$watch('$ctrl.configurationId', function () {
$scope.entaxyObjectForm.$setPristine();
populateTable();
});
function populateTable() {
entaxyCICDService.executeOperation('readRevisionConfiguration',
[storage, application, version, revision, ctrl.configurationId])
.then(result => {
let config = JSON.parse(result);
ctrl.configuredId = config.id;
ctrl.configuredType = config.type;
let fields = config.fields;
ctrl.items = fields.length === 0 ? [] : fields.map(field => {
field.type = Entaxy.convertToHtmlInputType(field.type);
if (field.importedValue === "" || field.importedValue === null) {
field.isRed = true;
} else if (field.localValue === "" || field.localValue === null) {
field.isGreen = true;
}
if (field.type === 'number') {
field.importedValue = field.importedValue !== null ? JSON.parse(field.importedValue) : null;
}
field.originValue = field.importedValue;
return field;
});
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
}).catch(error => {
Entaxy.notificationError('Can not read configuration: ' + error);
EntaxyCICD.log.error(error);
});
}
function clearChanges() {
if ($scope.entaxyObjectForm.$dirty) {
ctrl.items = ctrl.items.map(item => {
item.importedValue = item.originValue;
return item;
});
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
$scope.entaxyObjectForm.$setPristine();
}
}
function useLocalValues() {
ctrl.items = ctrl.items.map(item => {
item.importedValue = item.localValue;
return item;
});
if (!$scope.entaxyObjectForm.$dirty) {
$scope.entaxyObjectForm.$setDirty();
} else {
ctrl.checkDirtiness();
}
}
function save() {
if ($scope.entaxyObjectForm.$dirty) {
let properties = getProperties();
entaxyCICDService.executeOperation('saveRevisionConfiguration',
[storage, application, version, revision, ctrl.configurationId, properties])
.then(result => {
Entaxy.notificationSuccess(result);
$scope.entaxyObjectForm.$setPristine();
populateTable();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
function getProperties() {
let filteredFields = ctrl.items.filter(field => field.importedValue !== field.originValue);
if (filteredFields && filteredFields.length > 0) {
return filteredFields.reduce((obj, cur) => ({ ...obj, [cur.name] : cur.importedValue }), {});
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
save();
}
}
];
}
}
EntaxyCICDConfigurationController.$inject = ['workspace', '$scope', '$location', 'entaxyCICDService',
'entaxyService', 'entaxyHotkeysService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,189 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdConfigurations', {
bindings: {
changeSelection: '<',
configured: '<'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<div class="entaxy-cicd-objects-table-container">
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
items="$ctrl.viewedItems">
</pf-table-view>
</div>
`,
controller: EntaxyCICDConfigurationsController
})
.name;
function EntaxyCICDConfigurationsController(workspace, $q, entaxyCICDService, $templateCache, $route) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'id'
};
function changeSelected(item) {
if (ctrl.selected[item.id]) {
delete ctrl.selected[item.id];
} else {
ctrl.selected[item.id] = item;
}
}
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'id',
title: 'Id',
placeholder: 'Filter by Id...',
filterType: 'text'
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{
header: 'Id',
itemField: 'id',
htmlTemplate: 'configurations/id.html',
colActionFn: (configurationId) => ctrl.changeSelection(configurationId)
},
{ header: 'Location', itemField: 'location' }
];
$templateCache.put(
'configurations/id.html',
'<a href="" ng-click="$ctrl.handleColAction(key, value)">{{value}}</a>'
);
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'id') {
match = item.id.toLowerCase().match(filter.value.toLowerCase()) !== null;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
ctrl.tableConfig.showCheckboxes = ctrl.configured;
if (ctrl.configured) {
ctrl.selected = {};
ctrl.tableConfig.onCheckBoxChange = (item) => changeSelected(item);
let primaryActions = [
{name: 'Set Local Values', actionFn: useLocalValues}
];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
}
ctrl.storage = EntaxyCICD.getStorage(workspace.selection);
ctrl.application = EntaxyCICD.getProjectOrApplication(workspace.selection);
ctrl.version = EntaxyCICD.getVersion(workspace.selection);
ctrl.revision = workspace.selection.title.split(' ')[0];
populateTable();
}
function populateTable() {
entaxyCICDService.executeOperation('listRevisionConfigurations',
[ctrl.storage, ctrl.application, ctrl.version, ctrl.revision])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
function useLocalValues() {
let selectedIds = Object.keys(ctrl.selected);
if (selectedIds.length > 0) {
let promises = [];
let failedIds = [];
selectedIds.forEach(id => {
promises.push(
entaxyCICDService.executeOperation('fillInRevisionConfigurationWithLocalValues',
[ctrl.storage, ctrl.application, ctrl.version, ctrl.revision, id])
.catch(error => {
failedIds.push(id);
EntaxyCICD.log.error(error);
})
);
});
$q.all(promises).then(result => {
if (failedIds.length > 0) {
let result = selectedIds.map(id => {
return {
id: id,
failed: failedIds.includes(id)
};
});
let tableHtml = Entaxy.createStatusResultTable(result, 'Configuration Id');
let mainMessage = 'Some configurations were skipped ' +
'while setting local values due to errors that have occurred';
Entaxy.notificationWithDetails(Entaxy.NOTIFICATION_TYPE.WARNING, mainMessage, tableHtml,
Entaxy.configuration[Entaxy.CONFIGURATION_KEYS.NOTIFICATION_TIMEOUT_TABLE]);
} else {
Entaxy.notificationSuccess('Values of selected configurations were successfully ' +
'set to values of local configurations');
}
$route.reload();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
}
EntaxyCICDConfigurationsController.$inject = ['workspace', '$q', 'entaxyCICDService', '$templateCache', '$route'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,151 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdApplicationItems', {
bindings: {
version: '<'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view class="entaxy-cicd-table"
config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyCICDApplicationItemsController
})
.name;
function EntaxyCICDApplicationItemsController(workspace, $scope, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'id',
title: 'Id',
placeholder: 'Filter by Id...',
filterType: 'text'
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'select',
filterValues: []
},
{
id: 'revisionable',
title: 'Revisionable',
placeholder: 'Filter by Revisionable...',
filterType: 'select',
filterValues: ['yes', 'no']
},
{
id: 'editable',
title: 'Editable',
placeholder: 'Filter by Editable...',
filterType: 'select',
filterValues: ['yes', 'no']
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Id', itemField: 'id' },
{ header: 'Type', itemField: 'type' },
{ header: 'Revisionable', itemField: 'revisionable',
templateFn: (value) => EntaxyCICD.getStatusTemplate(value) },
{ header: 'Editable', itemField: 'editable',
templateFn: (value) => EntaxyCICD.getStatusTemplate(value) }
];
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'id') {
match = item.id.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'type') {
match = item.type === filter.value;
} else if (filter.id === 'revisionable') {
match = filter.value === 'yes' ? item.revisionable === true : item.revisionable === false;
} else if (filter.id === 'editable') {
match = filter.value === 'yes' ? item.editable === true : item.editable === false;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
entaxyCICDService.setTypesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
}
$scope.$watch('$ctrl.version', function () {
populateTable();
});
function populateTable() {
const storage = EntaxyCICD.getStorage(workspace.selection);
const application = EntaxyCICD.getProjectOrApplication(workspace.selection);
entaxyCICDService.executeOperation('listApplicationItems', [storage, application, ctrl.version])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
}
EntaxyCICDApplicationItemsController.$inject = ['workspace', '$scope', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,95 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdRevision', {
template:
`
<div class="entaxy-cicd-zero-revision-note" ng-if="$ctrl.revision === '0'">
<entaxy-form-field-extra-info type="'info'" message="$ctrl.zeroRevisionNote"></entaxy-form-field-extra-info>
</div>
<div class="entaxy-cicd-header-container">
<div class="entaxy-cicd-title-with-info-container">
<span class="first">Application: {{$ctrl.application}}</span>
<span>Version: {{$ctrl.version}}</span>
<span class="lead">Revision: {{$ctrl.revision}}</span>
<span>Revision Status: {{$ctrl.revisionStatus}}</span>
</div>
<div class="entaxy-cicd-header-buttons-container">
<entaxy-ci-cd-application-management-buttons storage="$ctrl.storage" application="$ctrl.application"
version="$ctrl.version" revision="$ctrl.revision" revision-status="$ctrl.revisionStatus"
is-configuration-dirty="$ctrl.isConfigurationDirty">
</entaxy-ci-cd-application-management-buttons>
</div>
</div>
<div class="entaxy-cicd-content-container">
<h2 class="first">
Configurations
</h2>
<entaxy-ci-cd-configurations change-selection="$ctrl.changeSelection"
configured="$ctrl.isConfigured"></entaxy-ci-cd-configurations>
<div class="entaxy-cicd-configuration-container" ng-if="$ctrl.configuration">
<entaxy-ci-cd-configuration configuration-id="$ctrl.configuration"
configured="$ctrl.isConfigured" is-dirty="$ctrl.isConfigurationDirty"></entaxy-ci-cd-configuration>
</div>
</div>
`,
controller: EntaxyCICDRevisionController
})
.name;
function EntaxyCICDRevisionController(workspace) {
'ngInject';
let ctrl = this;
ctrl.zeroRevisionNote = 'Revision 0 cannot be configured';
ctrl.$onInit = function() {
ctrl.storage = EntaxyCICD.getStorage(workspace.selection);
ctrl.application = EntaxyCICD.getProjectOrApplication(workspace.selection);
ctrl.version = EntaxyCICD.getVersion(workspace.selection);
let revisionInfo = EntaxyCICD.getRevisionInfo(workspace.selection);
ctrl.revision = revisionInfo.revision;
ctrl.revisionStatus = revisionInfo.revisionStatus;
ctrl.isConfigured = ctrl.revisionStatus === EntaxyCICD.REVISION_STATUS.CONFIGURED;
}
ctrl.changeSelection = function (configurationId) {
if (!ctrl.isConfigurationDirty || confirm(Entaxy.CONFIRMATION.UNSAVED_CHANGES)) {
ctrl.configuration = configurationId;
}
}
}
EntaxyCICDRevisionController.$inject = ['workspace'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,181 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdVersionsRevisionsInfo', {
template:
`
<div class="entaxy-cicd-content-with-title-container">
<h2>Versions & Revisions</h2>
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
</div>
`,
controller: EntaxyCICDVersionsRevisionsInfoController
})
.name;
function EntaxyCICDVersionsRevisionsInfoController(workspace, entaxyCICDService, $q, $templateCache, $location) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'version',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'version',
title: 'Version',
placeholder: 'Filter by Version...',
filterType: 'text'
},
{
id: 'installedRevision',
title: 'Installed Revision Presence',
placeholder: 'Filter by Installed Revision Presence...',
filterType: 'select',
filterValues: ['present', 'not present']
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{
header: 'Version',
itemField: 'version',
htmlTemplate: 'application/version.html',
colActionFn: (version) => ctrl.changeLocation(version)
},
{ header: 'Last Revision', itemField: 'lastRevision' },
{ header: 'Installed Revision', itemField: 'installedRevision' }
];
$templateCache.put(
'application/version.html',
'<a href="" ng-click="$ctrl.handleColAction(key, value)">{{value}}</a>'
);
ctrl.changeLocation = function (version) {
let nid = $location.search().nid;
$location.search('nid', nid + '-' + version);
}
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'version') {
match = item.version.match(filter.value) !== null;
} else if (filter.id === 'installedRevision') {
match = filter.value === 'present' ? item.installedRevision !== '-' : item.installedRevision === '-';
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
ctrl.storage = EntaxyCICD.getStorage(workspace.selection);
ctrl.tableActionButtons = [
{ name: 'Remove Version', title: 'Remove Version', actionFn: removeVersion }
];
populateTable();
}
function populateTable() {
const applicationFolder = workspace.selection;
let items = [];
let promises = [];
if (applicationFolder.children && applicationFolder.children.length > 0) {
applicationFolder.children.forEach(versionFolder => {
promises.push(
entaxyCICDService.executeOperation('readApplicationVersionLastAndInstalledRevision',
[ctrl.storage, applicationFolder.title, versionFolder.title])
.then(result => {
let revisionsInfo = JSON.parse(result);
items.push({
version: versionFolder.title,
lastRevision: revisionsInfo.lastRevision,
installedRevision: revisionsInfo.installedRevision
});
})
);
});
}
$q.all(promises).then(() => {
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
function removeVersion(action, item) {
let application = workspace.selection.title;
if (ctrl.items.length > 1) {
let properties = [ctrl.storage, application, item.version];
entaxyCICDService.removeItemWithConfirmation(EntaxyCICD.ITEM_TYPE.VERSION, item.version, properties);
} else {
let properties = [ctrl.storage, application];
let message = 'Removing the last version of the application will lead to removing the application. ' +
'Do you want to proceed?';
entaxyCICDService.removeItemWithConfirmation(EntaxyCICD.ITEM_TYPE.APPLICATION, null, properties,
false, message);
}
}
}
EntaxyCICDVersionsRevisionsInfoController.$inject = ['workspace', 'entaxyCICDService', '$q', '$templateCache',
'$location'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,280 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdApplicationsTable', {
bindings: {
type: '@',
importFromFile: '<',
importFromRepository: '<',
createProject: '<'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig">
<actions>
<span class="dropdown primary-action" uib-dropdown>
<button class="btn btn-default dropdown-toggle" uib-dropdown-toggle type="button">
Import
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li role="menuitem" ng-click="$ctrl.importFromFile()">
<a class="secondary-action">Import From File</a>
</li>
<li role="menuitem" ng-click="$ctrl.importFromRepository()">
<a class="secondary-action">Import From Repository</a>
</li>
</ul>
</span>
</actions>
</pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyCICDApplicationsTableController
})
.name;
function EntaxyCICDApplicationsTableController(workspace, $uibModal, entaxyCICDService, $templateCache, $location) {
'ngInject';
let ctrl = this;
const isStorageSelected = EntaxyCICD.isStorage(workspace.selection);
ctrl.tableConfig = {
selectionMatchProp: 'name',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'name',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{
header: 'Name',
itemField: 'name',
htmlTemplate: 'applications/table/name.html',
colActionFn: (name) => ctrl.changeLocation(name)
}
];
$templateCache.put(
'applications/table/name.html',
'<a href="" ng-click="$ctrl.handleColAction(key, value)">{{value}}</a>'
);
ctrl.changeLocation = function (name) {
let nid = $location.search().nid;
if (isStorageSelected) {
$location.search('nid', nid + '-' + name);
} else {
let item = ctrl.viewedItems.find(viewedItem => viewedItem.name === name);
$location.search('nid', [nid, item.storage, name].join('-'));
}
}
if (!isStorageSelected) {
ctrl.tableColumns.push({ header: 'Storage', itemField: 'storage' });
ctrl.toolbarConfig.filterConfig.fields.push({
id: 'storage',
title: 'Storage',
placeholder: 'Filter by Storage...',
filterType: 'select',
filterValues: EntaxyCICD.getStorages(workspace.selection)
});
}
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'name') {
match = item.name.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'storage') {
match = item.storage === filter.value;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
populateTable();
if (ctrl.type === EntaxyCICD.ITEM_TYPE.APPLICATION) {
ctrl.toolbarConfig.actionsConfig = {
actionsInclude: true
};
ctrl.tableColumns.push({
header: 'Versions & Revisions',
itemField: 'versionsRevisionsInfo',
templateFn: (value) => getVersionsRevisionsColumnTemplate(value)
});
} else if (ctrl.type === EntaxyCICD.ITEM_TYPE.PROJECT) {
let primaryActions = [{name: 'Create ' + ctrl.type, actionFn: () => ctrl.createProject(ctrl.items)}];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
}
ctrl.tableActionButtons = [
{ name: 'Remove', title: 'Remove ' + ctrl.type, actionFn: removeItem }
];
}
function getVersionsRevisionsColumnTemplate(value) {
const DIV = {
OPEN: '<div>',
CLOSE: '</div>'
};
const CLASS_INSTALLED = 'class="entaxy-cicd-installed"';
function insert(string, index, substring) {
return string.slice(0, index) + substring + string.slice(index);
}
const spanOpen = '<span data-toggle="tooltip" title="">';
const SPAN = {
OPEN: {
VERSION: insert(spanOpen, -2, 'Version'),
LAST_REVISION: insert(spanOpen, -2, 'Last Revision'),
INSTALLED_REVISION: insert(spanOpen, -2, 'Installed Revision')
},
CLOSE: '</span>'
};
let result = DIV.OPEN;
value = value.sort(Entaxy.compareBy('version'));
value.forEach(item => {
const versionOpeningSpan = item.installedRevision !== '-' ?
insert(SPAN.OPEN.VERSION, 5, ' ' + CLASS_INSTALLED) :
SPAN.OPEN.VERSION;
const revisionOpeningSpan = item.installedRevision !== '-' ?
insert(SPAN.OPEN.INSTALLED_REVISION, 5, ' ' + CLASS_INSTALLED) :
SPAN.OPEN.INSTALLED_REVISION;
result = result +
DIV.OPEN +
versionOpeningSpan + item.version + SPAN.CLOSE +
SPAN.OPEN.LAST_REVISION + item.lastRevision + SPAN.CLOSE +
revisionOpeningSpan + item.installedRevision + SPAN.CLOSE +
DIV.CLOSE;
});
return result + DIV.CLOSE;
}
function populateTable() {
let items = [];
if (isStorageSelected) {
items = getItemsFromChildren(workspace.selection);
} else {
let storages = workspace.selection.children;
if (storages && storages.length > 0) {
storages.forEach(storage => {
items = getItemsFromChildren(storage);
});
}
}
if (ctrl.type === EntaxyCICD.ITEM_TYPE.APPLICATION) {
items.forEach(item => {
if (item.versions) {
item.versionsRevisionsInfo = [];
item.versions.forEach(version => {
entaxyCICDService.executeOperation('readApplicationVersionLastAndInstalledRevision',
[item.storage, item.name, version])
.then(result => {
let revisionsInfo = JSON.parse(result);
item.versionsRevisionsInfo.push({
version: version,
lastRevision: revisionsInfo.lastRevision,
installedRevision: revisionsInfo.installedRevision
});
});
});
}
});
}
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
}
function getItemsFromChildren(selection) {
let items = [];
if (selection.children && selection.children.length > 0) {
selection.children.forEach(item => {
items.push({
name: item.title,
storage: selection.title,
versions: ctrl.type === EntaxyCICD.ITEM_TYPE.APPLICATION
&& item.children && item.children.length > 0 ?
item.children.map(child => child.title) : undefined
});
});
}
return items;
}
function removeItem(action, item) {
let properties = [item.storage, item.name];
entaxyCICDService.removeItemWithConfirmation(ctrl.type, item.name, properties, true);
}
}
EntaxyCICDApplicationsTableController.$inject = ['workspace', '$uibModal', 'entaxyCICDService',
'$templateCache', '$location'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,51 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdContents', {
template:
`
<div class="contents" ng-view ng-if="$ctrl.isReady" style="padding: 0 !important;"></div>
`,
controller: EntaxyCICDContentsController
})
.name;
function EntaxyCICDContentsController($scope, $route) {
'ngInject';
let ctrl = this;
ctrl.isReady = false;
$scope.$on('jmxTreeClicked', function () {
ctrl.isReady = true;
$route.reload();
});
}
EntaxyCICDContentsController.$inject = ['$scope', '$route'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,237 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD.log.debug("loading navigation");
EntaxyCICD._module
.config(configureRoutes)
.component('entaxyCiCdNavigation', {
template: `<hawtio-tabs tabs="$ctrl.tabs" on-change="$ctrl.goto(tab)"></hawtio-tabs>`,
controller: EntaxyCICDNavigationController
})
.name;
EntaxyCICD.log.debug("loaded navigation " + EntaxyCICD.navigationModule);
function EntaxyCICDNavigationController($scope, $location, workspace, localStorage, jolokia, $rootScope) {
'ngInject';
let ctrl = this;
this.$location = $location;
let selected = workspace.selection;
entaxyCICDJmxDomain = localStorage['entaxyCICDJmxDomain'] || "ru.entaxy.cicd";
$scope.$on('jmxTreeClicked', function (event, selectedNode) {
ctrl.tabs = getTabs();
let tab;
if (!selected) {
selected = selectedNode;
tab = _.find(ctrl.tabs, { path: ctrl.$location.path() });
if (!tab) {
tab = ctrl.tabs[0];
}
} else {
if (JSON.stringify(selected.folderNames) !== JSON.stringify(selectedNode.folderNames)) {
selected = selectedNode;
tab = ctrl.tabs[0];
} else {
tab = _.find(ctrl.tabs, {path: ctrl.$location.path()});
if (!tab) {
tab = ctrl.tabs[0];
}
}
}
ctrl.$location.path(tab.path);
});
EntaxyCICDNavigationController.prototype.$onInit = function () {
if (!workspace.selection) {
this.tabs = [];
} else {
this.tabs = getTabs();
}
};
EntaxyCICDNavigationController.prototype.goto = function (tab) {
this.$location.path(tab.path);
};
function getTabs() {
var tabs = [];
var enabledRoutes = Object.keys(TAB_CONFIG)
.map(function (config) { return TAB_CONFIG[config].route; })
.filter(function (route) { return _.startsWith(route, '/entaxy-cicd'); });
if (enabledRoutes.length > 0) {
if (workspace.getSelectedMBeanName()) {
if (workspace.hasDomainAndProperties(entaxyCICDJmxDomain, { module: 'projects' })) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.projects.title, TAB_CONFIG.projects.route));
} else if (workspace.hasDomainAndProperties(entaxyCICDJmxDomain, { module: 'applications' })) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.applications.title, TAB_CONFIG.applications.route));
}
} else if (shouldShowProjectsTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.projects.title, TAB_CONFIG.projects.route));
} else if (shouldShowVersionsTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.projectVersions.title, TAB_CONFIG.projectVersions.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.project.title, TAB_CONFIG.project.route));
} else if (shouldShowProjectTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.project.title, TAB_CONFIG.project.route));
} else if (shouldShowBuildInfoTabs()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.buildInfoItems.title, TAB_CONFIG.buildInfoItems.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.buildInfoRequirements.title, TAB_CONFIG.buildInfoRequirements.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.buildInfoComponents.title, TAB_CONFIG.buildInfoComponents.route));
} else if (shouldShowApplicationsTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.applications.title, TAB_CONFIG.applications.route));
} else if (shouldShowVersionsRevisionsTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.versionsRevisionsInfo.title, TAB_CONFIG.versionsRevisionsInfo.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.application.title, TAB_CONFIG.application.route));
} else if (shouldShowApplicationTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.application.title, TAB_CONFIG.application.route));
} else if (shouldShowRevisionTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.revision.title, TAB_CONFIG.revision.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.application.title, TAB_CONFIG.application.route));
}
}
return tabs;
}
function shouldShowProjectsTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'projects' &&
(selectionFolderNames.length === 2 || selectionFolderNames.length === 3);
}
function shouldShowVersionsTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'projects' && selectionFolderNames.length === 4;
}
function shouldShowProjectTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'projects' &&
(selectionFolderNames.length === 4 || selectionFolderNames.length === 5);
}
function shouldShowBuildInfoTabs() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'projects' && selectionFolderNames.length === 6;
}
function shouldShowApplicationsTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'applications' &&
(selectionFolderNames.length === 2 || selectionFolderNames.length === 3);
}
function shouldShowApplicationTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'applications' && selectionFolderNames.length === 5;
}
function shouldShowVersionsRevisionsTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'applications' && selectionFolderNames.length === 4;
}
function shouldShowRevisionTab() {
let selectionFolderNames = workspace.selection.folderNames;
return selectionFolderNames[1] === 'applications' && selectionFolderNames.length === 6;
}
// global event for entaxy extras
$rootScope.$emit('entaxyCiCdNavigationInited', $scope);
}
EntaxyCICDNavigationController.$inject = ['$scope', '$location', 'workspace', 'localStorage', 'jolokia', '$rootScope']
function configureRoutes($routeProvider) {
$routeProvider.
when(TAB_CONFIG.projects.route,
{ template: '<entaxy-ci-cd-projects></entaxy-ci-cd-projects>' }).
when(TAB_CONFIG.projectVersions.route,
{ template: '<entaxy-ci-cd-project-versions></entaxy-ci-cd-project-versions>' }).
when(TAB_CONFIG.project.route,
{ template: '<entaxy-ci-cd-project></entaxy-ci-cd-project>' }).
when(TAB_CONFIG.buildInfoItems.route,
{ template: '<entaxy-ci-cd-build-info type="Items"></entaxy-ci-cd-build-info>' }).
when(TAB_CONFIG.buildInfoRequirements.route,
{ template: '<entaxy-ci-cd-build-info type="Requirements"></entaxy-ci-cd-build-info>' }).
when(TAB_CONFIG.buildInfoComponents.route,
{ template: '<entaxy-ci-cd-build-info type="Components"></entaxy-ci-cd-build-info>' }).
when(TAB_CONFIG.applications.route,
{ template: '<entaxy-ci-cd-applications></entaxy-ci-cd-applications>' }).
when(TAB_CONFIG.application.route,
{ template: '<entaxy-ci-cd-application></entaxy-ci-cd-application>' }).
when(TAB_CONFIG.versionsRevisionsInfo.route,
{ template: '<entaxy-ci-cd-versions-revisions-info></entaxy-ci-cd-versions-revisions-info>' }).
when(TAB_CONFIG.revision.route,
{ template: '<entaxy-ci-cd-revision></entaxy-ci-cd-revision>' });
}
configureRoutes.$inject = ['$routeProvider'];
})(EntaxyCICD || (EntaxyCICD = {}));
let TAB_CONFIG = {
projects: {
title: 'Projects',
route: '/entaxy-cicd/projects'
},
project: {
title: 'Project',
route: '/entaxy-cicd/project'
},
projectVersions: {
title: 'Versions',
route: '/entaxy-cicd/project/versions'
},
buildInfoItems: {
title: 'Items',
route: '/entaxy-cicd/project/build-info/items'
},
buildInfoRequirements: {
title: 'Requirements',
route: '/entaxy-cicd/project/build-info/requirements'
},
buildInfoComponents: {
title: 'Components',
route: '/entaxy-cicd/project/build-info/components'
},
applications: {
title: 'Applications',
route: '/entaxy-cicd/applications'
},
application: {
title: 'Application',
route: '/entaxy-cicd/application'
},
versionsRevisionsInfo: {
title: 'Versions & Revisions',
route: '/entaxy-cicd/application/versions-revisions-info'
},
revision: {
title: 'Revision',
route: '/entaxy-cicd/application/revision'
}
};

View File

@ -0,0 +1,110 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdAddObjectsModal', {
bindings: {
modalInstance: '<',
resolve: '<'
},
template:
`
<div class="entaxy-modal-container">
<div class="modal-header">
<button type="button" class="close" aria-label="Close" ng-click="$ctrl.cancel()">
<span class="pficon pficon-close" aria-hidden="true"></span>
</button>
<h4 class="modal-title">{{$ctrl.modalTitle}}</h4>
</div>
<div class="modal-body">
<div ng-if="$ctrl.resolve.objects">
<div class="add-objects-message-container">
{{$ctrl.message}}
</div>
<entaxy-expandable-list items="$ctrl.resolve.objects" use-toolbar="false" show-select-box="true"
on-check-box-change-fn="$ctrl.changeSelected">
</entaxy-expandable-list>
</div>
<entaxy-ci-cd-objects-select change-selected="$ctrl.changeSelected" ng-if="!$ctrl.resolve.objects"
excluded-object-ids="$ctrl.resolve.excludedObjectIds"></entaxy-ci-cd-objects-select>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.cancel()"
ng-if="$ctrl.includeSkip">Skip</button>
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">Add</button>
</div>
</div>
`,
controller: entaxyCICDAddObjectsModalController
})
.name;
function entaxyCICDAddObjectsModalController() {
let ctrl = this;
ctrl.$onInit = function() {
ctrl.modalTitle = 'Add Objects to the Project: ' + ctrl.resolve.project;
ctrl.selected = {};
if (ctrl.resolve.objects) {
ctrl.message = 'You may also want to add optional related objects:';
ctrl.includeSkip = true;
}
}
ctrl.changeSelected = function (item) {
if (ctrl.resolve.objects) {
if (item.relatedTo && item.relatedTo.length > 1) {
let relatedToExcludeParent = item.relatedTo.filter(objectId => objectId !== item.parent);
relatedToExcludeParent.forEach(objectId => {
let object = ctrl.resolve.objects.find(it => it.name === objectId);
let relatedObject = object.sublist.find(it => it.name === item.name);
relatedObject.selected = item.selected;
});
}
}
if (ctrl.selected[item.fullId]) {
delete ctrl.selected[item.fullId];
} else {
ctrl.selected[item.fullId] = item;
}
}
ctrl.save = function () {
ctrl.modalInstance.close(ctrl.selected);
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
}
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,171 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdBuildInfo', {
bindings: {
type: '@'
},
template:
`
<div class="entaxy-cicd-header-container">
<div class="entaxy-cicd-title-with-info-container">
<span class="first lead">Build</span>
<span>Project: {{$ctrl.project}}</span>
<span>Version: {{$ctrl.version}}</span>
<div ng-if="$ctrl.mavenUrl">
<span>Maven URL: {{$ctrl.mavenUrl}}</span>
<entaxy-copy-to-clipboard-button title="Copy maven URL to clipboard"
text-to-copy="$ctrl.mavenUrl"></entaxy-copy-to-clipboard-button>
</div>
</div>
<div class="entaxy-cicd-header-buttons-container">
<div class="btn-group" uib-dropdown>
<button id="single-button" type="button" uib-dropdown-toggle ng-disabled="disabled">
Export
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu
role="menu" aria-labelledby="single-button">
<li role="menuitem"><a ng-click="$ctrl.exportToFile()">Export To File</a></li>
<li role="menuitem"><a ng-click="$ctrl.exportToRepository()">Export To Repository</a></li>
</ul>
</div>
</div>
</div>
<div class="entaxy-cicd-content-container">
<h2 class="first">
{{ $ctrl.type }}
</h2>
<entaxy-ci-cd-project-items ng-if="$ctrl.isItems()"></entaxy-ci-cd-project-items>
<entaxy-ci-cd-requirements ng-if="$ctrl.isRequirements()"
version="$ctrl.version" type="BuiltProject"></entaxy-ci-cd-requirements>
<entaxy-ci-cd-project-components ng-if="$ctrl.isComponents()"></entaxy-ci-cd-project-components>
</div>
`,
controller: entaxyCICDBuildInfoController
})
.name;
function entaxyCICDBuildInfoController(workspace, entaxyCICDService, entaxyService, $uibModal) {
'ngInject';
let ctrl = this;
const storage = EntaxyCICD.getStorage(workspace.selection);
const TYPE = {
ITEMS: 'Items',
REQUIREMENTS: 'Requirements',
COMPONENTS: 'Components'
}
ctrl.isItems = function () {
return ctrl.type === TYPE.ITEMS;
}
ctrl.isRequirements = function () {
return ctrl.type === TYPE.REQUIREMENTS;
}
ctrl.isComponents = function () {
return ctrl.type === TYPE.COMPONENTS;
}
ctrl.$onInit = function() {
ctrl.project = EntaxyCICD.getProjectOrApplication(workspace.selection);
ctrl.version = EntaxyCICD.getVersion(workspace.selection);
entaxyCICDService.executeOperation('readMavenUrl', [storage, ctrl.project, ctrl.version])
.then(result => {
ctrl.mavenUrl = result;
});
}
ctrl.exportToFile = function () {
entaxyCICDService.executeOperation('exportToFile', [storage, ctrl.project, ctrl.version])
.then(result => {
let fileName = ctrl.project + '-' + ctrl.version + '.jar';
entaxyService.downloadFileFromBase64StringContent(result, fileName);
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
ctrl.exportToRepository = function () {
entaxyCICDService.executeOperation('listRepositories', [])
.then(result => {
let formFields = [
{
label: 'Repository',
name: 'repository',
enum: true,
required: true,
values: JSON.parse(result),
setFocused: true
}
];
showExportModal(formFields);
}).catch(error => {
Entaxy.notificationError(error);
});
}
function showExportModal(formFields) {
$uibModal.open({
component: 'entaxyCiCdSimpleFieldsModal',
resolve: {
modalTitle: () => 'Export Project To Repository',
formFields: () => formFields
},
backdrop: 'static'
}).result.then((args) => {
exportToRepository(args[0]);
}, reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function exportToRepository(repository) {
entaxyCICDService.executeOperation('exportToRepository',
[storage, ctrl.project, ctrl.version, repository])
.then(result => {
Entaxy.notificationSuccess(result);
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
entaxyCICDBuildInfoController.$inject = ['workspace', 'entaxyCICDService', 'entaxyService', '$uibModal'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,126 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdProjectComponents', {
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyCICDProjectComponentsController
})
.name;
function EntaxyCICDProjectComponentsController(workspace, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'id',
title: 'Id',
placeholder: 'Filter by Id...',
filterType: 'text'
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'select',
filterValues: []
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Id', itemField: 'id' },
{ header: 'Type', itemField: 'type' },
{ header: 'Priority', itemField: 'priority' }
];
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'id') {
match = item.id.match(filter.value) !== null;
} else if (filter.id === 'type') {
match = item.type === filter.value;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
entaxyCICDService.setTypesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
populateTable();
}
function populateTable() {
const storage = EntaxyCICD.getStorage(workspace.selection);
const project = EntaxyCICD.getProjectOrApplication(workspace.selection);
const version = EntaxyCICD.getVersion(workspace.selection);
entaxyCICDService.executeOperation('listBuiltProjectComponents', [storage, project, version])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
}
EntaxyCICDProjectComponentsController.$inject = ['workspace', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,126 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdProjectItems', {
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyCICDProjectItemsController
})
.name;
function EntaxyCICDProjectItemsController(workspace, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'id',
title: 'Id',
placeholder: 'Filter by Id...',
filterType: 'text'
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'select',
filterValues: []
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Id', itemField: 'id' },
{ header: 'Type', itemField: 'type' },
{ header: 'Component', itemField: 'component' }
];
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'id') {
match = item.id.match(filter.value) !== null;
} else if (filter.id === 'type') {
match = item.type === filter.value;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
entaxyCICDService.setTypesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
populateTable();
}
function populateTable() {
const storage = EntaxyCICD.getStorage(workspace.selection);
const project = EntaxyCICD.getProjectOrApplication(workspace.selection);
const version = EntaxyCICD.getVersion(workspace.selection);
entaxyCICDService.executeOperation('listBuiltProjectItems', [storage, project, version])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
}
EntaxyCICDProjectItemsController.$inject = ['workspace', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,489 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdObjects', {
bindings: {
storage: '<',
project: '<',
version: '<'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig">
<actions>
<button type="button" class="btn btn-default" ng-repeat="action in $ctrl.actions"
ng-click="action.actionFn()">
{{action.name}}
</button>
</actions>
</pf-toolbar>
<div class="entaxy-cicd-objects-table-container">
<pf-table-view class="entaxy-cicd-table"
config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
dt-options="$ctrl.dtOptions"
items="$ctrl.viewedItems">
</pf-table-view>
</div>
`,
controller: EntaxyCICDObjectsController
})
.name;
function EntaxyCICDObjectsController(workspace, $scope, $uibModal, entaxyCICDService, $q, $route) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'id',
onCheckBoxChange: (item) => changeSelected(item)
};
function changeSelected(item) {
if (ctrl.selected[item.id]) {
delete ctrl.selected[item.id];
} else {
ctrl.selected[item.id] = item;
}
}
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Id / Name',
placeholder: 'Filter by Id or Name...',
filterType: 'text'
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'select',
filterValues: []
},
{
id: 'status',
title: 'Status',
placeholder: 'Filter by Status...',
filterType: 'select',
filterValues: []
},
{
id: 'scope',
title: 'Scope',
placeholder: 'Filter by Scope...',
filterType: 'select',
filterValues: []
},
{
id: 'required',
title: 'Required',
placeholder: 'Filter by Required...',
filterType: 'select',
filterValues: ['yes', 'no']
},
{
id: 'ignored',
title: 'Ignored',
placeholder: 'Filter by Ignored...',
filterType: 'select',
filterValues: ['yes', 'no']
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Status', itemField: 'status', templateFn: (value) => getObjectStatusTemplate(value) },
{ header: 'Id / Name', itemField: 'displayName' },
{ header: 'Type', itemField: 'type' },
{ header: 'Scope', itemField: 'scope' },
{ header: 'Required', itemField: 'required',
templateFn: (value) => EntaxyCICD.getStatusTemplate(value) },
{ header: 'Ignored', itemField: 'ignored',
templateFn: (value) => EntaxyCICD.getStatusTemplate(value) },
{ header: 'Id', itemField: 'id' }
];
function getObjectStatusTemplate(value) {
switch (value) {
case 'INCLUDED':
return '<span class="pficon pficon-ok" data-toggle="tooltip" title="Included"></span>';
case 'IGNORED':
return '<span class="pficon pficon-arrow" data-toggle="tooltip" title="Ignored"></span>';
case 'REQUIRED':
return '<span class="pficon pficon-warning-triangle-o" data-toggle="tooltip" title="Required"></span>';
case 'GHOST':
return '<span class="pficon pficon-unknowm" data-toggle="tooltip" title="Ghost"></span>';
case 'DELETED':
return '<span class="pficon pficon-error-circle-o" data-toggle="tooltip" title="Deleted"></span>';
}
}
ctrl.dtOptions = {
order: [[1, "desc"]],
columnDefs: [
{ "targets": [0], "sortable": false },
{ "targets": [7], "class": "hide" }
]
};
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'status') {
match = item.status === filter.value;
} else if (filter.id === 'displayName') {
match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'type') {
match = item.type === filter.value;
} else if (filter.id === 'scope') {
match = item.scope === filter.value;
} else if (filter.id === 'required') {
match = filter.value === 'yes' ? item.required === true : item.required === false;
} else if (filter.id === 'ignored') {
match = filter.value === 'yes' ? item.ignored === true : item.ignored === false;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
ctrl.selected = {};
let primaryActions = [
{ name: 'Add Objects', actionFn: () => ctrl.showAddObjectsModal() },
{ name: 'Add Resources', actionFn: () => ctrl.showAddResourcesModal() }
];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions,
actionsInclude: true
};
ctrl.actions = [
{ name: 'Include Selected', actionFn: ctrl.includeSelected },
{ name: 'Ignore Selected', actionFn: ctrl.ignoreSelected },
{ name: 'Remove Selected', actionFn: ctrl.removeSelected },
{ name: 'Add Related', actionFn: ctrl.addRelatedObjects }
];
entaxyCICDService.setTypesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
entaxyCICDService.setScopesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
let filterConfigFieldStatus = ctrl.toolbarConfig.filterConfig.fields.find(field => field.id === 'status');
entaxyCICDService.executeOperation('readProjectItemStatuses', [])
.then(result => {
filterConfigFieldStatus.filterValues = JSON.parse(result);
});
}
$scope.$watch('$ctrl.version', function () {
populateTable();
});
function populateTable() {
ctrl.selected = {};
entaxyCICDService.executeOperation('listProjectItems', [ctrl.storage, ctrl.project, ctrl.version])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items.map(item => {
if (!item.displayName || item.displayName.trim().length == 0) {
item.displayName = item.id;
}
return item;
});
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
ctrl.showAddObjectsModal = function (objects) {
$uibModal.open({
component: 'entaxyCiCdAddObjectsModal',
resolve: {
project: () => ctrl.project,
objects: () => objects,
excludedObjectIds: () => ctrl.items.length > 0 ? ctrl.items.map(item => item.id) : []
},
size: 'xl',
backdrop: 'static'
})
.result.then(objectsMap => {
addObjects(objectsMap);
},
reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function addObjects(objectsMap) {
let objectsIds = Object.keys(objectsMap);
if (objectsIds.length > 0) {
let promises = [];
objectsIds.forEach(objectId => {
promises.push(
entaxyCICDService.executeOperation('addObject',
[ctrl.storage, ctrl.project, ctrl.version, objectId])
);
});
$q.all(promises).then(result => {
addRelatedObjects(objectsMap, objectsIds, result);
Entaxy.notificationSuccess('Operation Succeeded');
populateTable();
}).catch(error => {
Entaxy.notificationError(error);
});
}
}
function addRelatedObjects(objectsMap, objectsIds, result, showNotification) {
let objectsTree = [];
let relations = {};
let addedItems = ctrl.items.length > 0 ? ctrl.items.map(item => item.id) : [];
for (let i = 0; i < objectsIds.length; i++) {
let relatedObjects = JSON.parse(result[i]);
if (relatedObjects.length > 0) {
let objectsToAdd = relatedObjects.filter(object =>
!objectsIds.includes(object.fullId) && !addedItems.includes(object.fullId));
if (objectsToAdd.length > 0) {
let sublist = objectsToAdd.map(object => {
addRelation(relations, object.fullId, objectsIds[i]);
return {
name: object.fullId,
fullId: object.fullId,
displayName: object.displayName,
additionalInfo: object.type,
parent: objectsIds[i],
disableRowExpansion: true
};
});
objectsTree.push({
name: objectsIds[i],
displayName: objectsMap[objectsIds[i]].displayName,
additionalInfo: objectsMap[objectsIds[i]].type,
isExpanded: true,
sublist: sublist.sort(Entaxy.compareBy('displayName'))
});
}
}
}
if (objectsTree.length > 0) {
setRelated(relations, objectsTree);
ctrl.showAddObjectsModal(objectsTree);
} else {
if (showNotification) {
Entaxy.notificationInfo('There are no related objects that are not included');
}
}
}
function addRelation(relations, relatedObjectId, objectId) {
if (relations[relatedObjectId]) {
relations[relatedObjectId].push(objectId);
} else {
relations[relatedObjectId] = [objectId];
}
}
function setRelated(relations, objectsTree) {
Object.keys(relations).forEach(key => {
if (relations[key].length > 1) {
relations[key].forEach(objectId => {
let object = objectsTree.find(object => object.name === objectId);
let relatedObject = object.sublist.find(object => object.name === key);
relatedObject.relatedTo = relations[key];
})
}
});
}
ctrl.addRelatedObjects = function () {
let objectsIds = Object.keys(ctrl.selected);
if (objectsIds.length == 0) {
Entaxy.notificationInfo('At least one item should be selected');
return;
}
let objectsMap = {};
let promises = [];
objectsIds.forEach(objectId => {
if (ctrl.selected[objectId].type === 'OBJECT') {
objectsMap[objectId] = {
displayName: ctrl.selected[objectId].displayName,
type: ctrl.selected[objectId].runtimeType
};
promises.push(
entaxyCICDService.executeOperation('getRelatedObjects', [objectId])
);
}
});
if (promises.length > 0) {
$q.all(promises).then(result => {
addRelatedObjects(objectsMap, Object.keys(objectsMap), result, true);
}).catch(error => {
Entaxy.notificationError(error);
});
} else {
Entaxy.notificationInfo('Selected items should have OBJECT type');
}
}
ctrl.showAddResourcesModal = function () {
$uibModal.open({
component: 'entaxyResourceViewerModal',
resolve: {
config: {
resourceProvider: 'schemas',
folderSelectionEnabled: true,
multipleSelectionEnabled: true,
providersSelectionEnabled: true
}
},
size: 'xl',
backdrop: 'static'
})
.result.then(locations => {
addResources(locations);
},
reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function addResources(locations) {
let promises = [];
let failedResources = [];
locations.forEach(location => {
promises.push(
entaxyCICDService.executeOperation('addResource',
[ctrl.storage, ctrl.project, ctrl.version, location])
.catch(error => {
failedResources.push(location);
EntaxyCICD.log.error(error);
})
);
});
$q.all(promises).then(result => {
if (failedResources.length > 0) {
let result = locations.map(location => {
return {
id: location,
failed: failedResources.includes(location)
};
});
let tableHtml = Entaxy.createStatusResultTable(result, 'Location');
let mainMessage = 'Errors occurred while adding resources';
Entaxy.notificationWithDetails(Entaxy.NOTIFICATION_TYPE.WARNING, mainMessage, tableHtml,
Entaxy.configuration[Entaxy.CONFIGURATION_KEYS.NOTIFICATION_TIMEOUT_TABLE]);
} else {
Entaxy.notificationSuccess('Operation Succeeded');
}
$route.reload();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
ctrl.includeSelected = function () {
processOperationSelected('addItem', 'Selected items were successfully included into the project');
}
ctrl.ignoreSelected = function () {
processOperationSelected('ignoreItem', 'Selected items were successfully ignored from the project');
}
ctrl.removeSelected = function () {
const operationName = 'removeItems';
const successMessage = 'Selected items were successfully removed from the project';
let selectedIds = Object.keys(ctrl.selected);
if (selectedIds.length > 0) {
entaxyCICDService
.executeOperation(operationName, [ctrl.storage, ctrl.project, ctrl.version, selectedIds])
.then(result => {
let unremovedItems = JSON.parse(result);
if (unremovedItems && Object.keys(unremovedItems).length > 0) {
let message = 'There are items that cannot be removed ' +
'since they are required by some of remaining items';
let table = EntaxyCICD.createTableFromUnremovedItems(unremovedItems);
Entaxy.notificationWithDetails(Entaxy.NOTIFICATION_TYPE.INFO, message, table, 30000);
} else {
Entaxy.notificationSuccess(successMessage);
}
$route.reload();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
function processOperationSelected(operationName, successMessage) {
let selectedIds = Object.keys(ctrl.selected);
if (selectedIds.length > 0) {
let promises = [];
selectedIds.forEach(id => {
promises.push(
entaxyCICDService.executeOperation(operationName,
[ctrl.storage, ctrl.project, ctrl.version, id])
);
});
$q.all(promises).then(result => {
Entaxy.notificationSuccess(successMessage ? successMessage : 'Operation succeeded');
$route.reload();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
}
EntaxyCICDObjectsController.$inject = ['workspace', '$scope', '$uibModal', 'entaxyCICDService', '$q', '$route'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,127 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdObjectsSelect', {
bindings: {
changeSelected: '<',
excludedObjectIds: '<'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<div class="entaxy-cicd-objects-table-container">
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
dt-options="$ctrl.dtOptions"
items="$ctrl.viewedItems">
</pf-table-view>
</div>
`,
controller: EntaxyCICDObjectsSelectController
})
.name;
function EntaxyCICDObjectsSelectController(workspace, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'fullId',
onCheckBoxChange: (item) => ctrl.changeSelected(item)
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'text'
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Name', itemField: 'displayName' },
{ header: 'Type', itemField: 'type' },
{ header: 'Full Id', itemField: 'fullId' }
];
ctrl.dtOptions = {
columnDefs: [
{ "targets": [0], "sortable": false },
{ "targets": [3], "class": "hide" }
]
};
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'displayName') {
match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'type') {
match = item.type.toLowerCase().match(filter.value.toLowerCase()) !== null;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
populateTable();
}
function populateTable() {
entaxyCICDService.executeOperation('listObjects', [])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items.filter(item => !ctrl.excludedObjectIds.includes(item.fullId));
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
}
EntaxyCICDObjectsSelectController.$inject = ['workspace', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,192 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdProject', {
template:
`
<div ng-if="$ctrl.versions || $ctrl.isVersionSelected">
<div class="entaxy-cicd-header-container">
<div class="entaxy-cicd-title-with-info-container">
<span class="first" ng-class="{'lead': !$ctrl.isVersionSelected}">Project: {{$ctrl.project}}</span>
<span class="lead" ng-if="$ctrl.isVersionSelected">Version: {{$ctrl.version}}</span>
<div ng-if="!$ctrl.isVersionSelected">
<span>Version:</span>
<entaxy-select-from-enum values="$ctrl.versions" model="$ctrl.version"
is-empty-included="false"></entaxy-select-from-enum>
<div class="btn-group" uib-dropdown>
<button id="single-button" type="button" uib-dropdown-toggle ng-disabled="disabled">
Add Version
<span class="caret"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
<li role="menuitem"><a ng-click="$ctrl.addVersionFromScratch()">Add Version From Scratch</a></li>
<li role="menuitem"><a ng-click="$ctrl.addVersionFromExistent()">Add Version From Existent</a></li>
</ul>
</div>
</div>
</div>
<div class="entaxy-cicd-header-buttons-container">
<button type="button" ng-click="$ctrl.commit()">Commit</button>
<button type="button" ng-click="$ctrl.build()">Build</button>
</div>
</div>
<div class="entaxy-cicd-content-container">
<entaxy-ci-cd-objects storage="$ctrl.storage" project="$ctrl.project" version="$ctrl.version"
ng-if="$ctrl.version"></entaxy-ci-cd-objects>
</div>
</div>
`,
controller: entaxyCICDProjectController
})
.name;
function entaxyCICDProjectController(workspace, entaxyCICDService, $uibModal) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
ctrl.storage = EntaxyCICD.getStorage(workspace.selection);
ctrl.project = EntaxyCICD.getProjectOrApplication(workspace.selection);
ctrl.isVersionSelected = EntaxyCICD.isVersion(workspace.selection);
if (ctrl.isVersionSelected) {
ctrl.version = workspace.selection.title;
} else {
populateVersions();
}
}
function populateVersions() {
ctrl.versions = EntaxyCICD.getVersions(workspace.selection);
if (ctrl.versions.length > 0) {
ctrl.version = ctrl.versions[ctrl.versions.length - 1];
}
}
function getFormFields() {
return [
{
label: 'Current Version',
name: 'currentVersion',
type: 'text',
value: ctrl.version,
readOnly: true
},
{
label: 'Created Version',
name: 'createdVersion',
type: 'text',
required: true,
validation: {
checkUniqueness: true,
values: ctrl.versions,
content: {
regex: '^([1-9][0-9]*|0)\\.([1-9][0-9]*|0)\\.([1-9][0-9]*|0)$',
errorMessage: 'Value must match the pattern: X.X.X, where X represents a number'
}
},
setFocused: true
}
];
}
ctrl.addVersionFromScratch = function () {
openCreateVersionModal(getFormFields());
}
ctrl.addVersionFromExistent = function () {
let formFields = getFormFields();
formFields.push({
label: 'Prototype Version',
name: 'prototypeVersion',
enum: true,
required: true,
values: ctrl.versions,
value: ctrl.version
});
openCreateVersionModal(formFields);
}
function openCreateVersionModal(formFields) {
$uibModal.open({
component: 'entaxyCiCdSimpleFieldsModal',
resolve: {
modalTitle: () => 'Create Version',
formFields: () => formFields
},
backdrop: 'static'
}).result.then((args) => {
args.shift();
createVersion(...args);
}, reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function createVersion(createdVersion, prototypeVersion) {
entaxyCICDService.executeOperation('createVersion',
[ctrl.storage, ctrl.project, createdVersion, prototypeVersion])
.then(result => {
Entaxy.notificationSuccess(result);
entaxyCICDService.treeUpdated();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
ctrl.commit = function () {
processOperation('saveProjectVersion');
}
ctrl.build = function () {
processOperation('buildProjectVersion');
}
function processOperation(operationName) {
entaxyCICDService.executeOperation(operationName, [ctrl.storage, ctrl.project, ctrl.version])
.then(result => {
Entaxy.notificationSuccess(result);
if (operationName === 'buildProjectVersion') {
workspace.jmxTreeUpdated();
}
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
entaxyCICDProjectController.$inject = ['workspace', 'entaxyCICDService', '$uibModal'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,146 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdProjects', {
template:
`
<div class="entaxy-cicd-content-with-title-container">
<h2>
Projects
</h2>
<entaxy-ci-cd-applications-table type="Project" create-project="$ctrl.showCreateProjectModal">
</entaxy-ci-cd-applications-table>
</div>
`,
controller: EntaxyCICDProjectsController
})
.name;
function EntaxyCICDProjectsController(workspace, $uibModal, entaxyCICDService, $scope, $route) {
'ngInject';
let ctrl = this;
const isStorageSelected = EntaxyCICD.isStorage(workspace.selection);
ctrl.$onInit = function() {
}
ctrl.showCreateProjectModal = function(items) {
$uibModal.open({
component: 'entaxyCiCdSimpleFieldsModal',
resolve: {
modalTitle: () => 'Create Project',
formFields: () => getFormFields(items)
},
backdrop: 'static'
})
.result.then(args => {
createProject(args);
},
reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function getFormFields(items) {
return [
{
name: 'name',
label: 'Name',
type: 'text',
required: true,
validation: {
checkUniqueness: true,
values: items.map(project => project.name),
content: {
regex: '^[a-zA-Z0-9-_]+$',
errorMessage: 'Value must contain only latin letters, numbers, hyphens and underscores'
},
length: {
min: 3
}
},
setFocused: true
},
{
name: 'group',
label: 'Group',
type: 'text',
validation: {
content: {
regex: '^[a-zA-Z0-9-_]*$',
errorMessage: 'Value must contain only latin letters, numbers, hyphens and underscores'
}
},
},
{
name: 'storage',
label: 'Storage',
type: 'string',
value: isStorageSelected ? workspace.selection.title : undefined,
enum: isStorageSelected ? undefined : true,
values: isStorageSelected ? undefined : workspace.selection.children.map(child => child.title),
required: true,
readOnly: isStorageSelected ? true : undefined
},
{
name: 'version',
label: 'Version',
type: 'string',
value: '1.0.0',
required: true,
validation: {
content: {
regex: '^([1-9][0-9]*|0)\.([1-9][0-9]*|0)\.([1-9][0-9]*|0)$',
errorMessage: 'Value must match the pattern: X.X.X, where X represents the number'
}
}
}
];
}
function createProject(args) {
let projectName = args[1] ? args[1] + '/' + args[0] : args[0];
entaxyCICDService.executeOperation('createProject', [projectName, args[2], args[3]])
.then(result => {
Entaxy.notificationSuccess(result);
entaxyCICDService.treeUpdated();
})
.catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
}
EntaxyCICDProjectsController.$inject = ['workspace', '$uibModal', 'entaxyCICDService', '$scope', '$route'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,246 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdProjectVersions', {
template:
`
<div class="entaxy-cicd-content-with-title-container">
<h2>{{$ctrl.title}}</h2>
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig">
<actions>
<span class="dropdown primary-action" uib-dropdown>
<button class="dropdown-toggle" uib-dropdown-toggle type="button">
Add Version
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li role="menuitem" ng-click="$ctrl.addVersionFromScratch()">
<a class="secondary-action">Add Version From Scratch</a>
</li>
<li role="menuitem" ng-click="$ctrl.addVersionFromExistent()">
<a class="secondary-action">Add Version From Existent</a>
</li>
</ul>
</span>
</actions>
</pf-toolbar>
<pf-table-view class="entaxy-cicd-table"
config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
</div>
`,
controller: entaxyCICDProjectVersionsController
})
.name;
function entaxyCICDProjectVersionsController($scope, workspace, entaxyCICDService, $uibModal, $templateCache,
$location) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'name',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'name',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
},
{
id: 'isBuilt',
title: 'Build Available',
placeholder: 'Filter by Built Availability...',
filterType: 'select',
filterValues: ['yes', 'no']
}
],
appliedFilters: [],
onFilterChange: filterChange
},
actionsConfig: {
actionsInclude: true
},
isTableView: true
};
ctrl.tableColumns = [
{
header: 'Name',
itemField: 'name',
htmlTemplate: 'project/version/name.html',
colActionFn: (name) => ctrl.changeLocation(name)
},
{ header: 'Build Available', itemField: 'isBuilt',
templateFn: (value) => EntaxyCICD.getStatusTemplate(value) }
];
$templateCache.put(
'project/version/name.html',
'<a href="" ng-click="$ctrl.handleColAction(key, value)">{{value}}</a>'
);
ctrl.changeLocation = function (name) {
let nid = $location.search().nid;
$location.search('nid', nid + '-' + name);
}
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'name') {
match = item.name.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'isBuilt') {
match = filter.value === 'yes' ? item.isBuilt === true : item.isBuilt === false;
}
return match;
};
ctrl.$onInit = function() {
ctrl.storage = EntaxyCICD.getStorage(workspace.selection);
ctrl.project = workspace.selection.title;
ctrl.title = 'Versions';
ctrl.tableActionButtons = [
{ name: 'Remove', title: 'Remove Version', actionFn: removeVersion }
];
populateTable();
}
ctrl.items = [];
ctrl.viewedItems = [];
function populateTable() {
let selectedProject = workspace.selection;
if (selectedProject.children && selectedProject.children.length > 0) {
let versions = [];
selectedProject.children.forEach(version => {
versions.push({
name: version.title,
isBuilt: version.children && version.children.length === 1 ? true : false
});
});
ctrl.items = versions;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
}
}
function getFormFields() {
return [
{
label: 'Created Version',
name: 'createdVersion',
type: 'text',
required: true,
validation: {
checkUniqueness: true,
values: ctrl.items.map(version => version.name),
content: {
regex: '^([1-9][0-9]*|0)\\.([1-9][0-9]*|0)\\.([1-9][0-9]*|0)$',
errorMessage: 'Value must match the pattern: X.X.X, where X represents a number'
}
},
setFocused: true
}
];
}
ctrl.addVersionFromScratch = function () {
openCreateVersionModal(getFormFields());
}
ctrl.addVersionFromExistent = function () {
let formFields = getFormFields();
formFields.push({
label: 'Prototype Version',
name: 'prototypeVersion',
enum: true,
required: true,
values: ctrl.items.map(version => version.name)
});
openCreateVersionModal(formFields);
}
function openCreateVersionModal(formFields) {
$uibModal.open({
component: 'entaxyCiCdSimpleFieldsModal',
resolve: {
modalTitle: () => 'Create Version',
formFields: () => formFields
},
backdrop: 'static'
}).result.then((args) => {
createVersion(...args);
}, reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function createVersion(createdVersion, prototypeVersion) {
entaxyCICDService.executeOperation('createVersion',
[ctrl.storage, ctrl.project, createdVersion, prototypeVersion])
.then(result => {
Entaxy.notificationSuccess(result);
entaxyCICDService.treeUpdated();
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
}
function removeVersion(action, item) {
let properties = [ctrl.storage, ctrl.project, item.name];
entaxyCICDService.removeItemWithConfirmation(EntaxyCICD.ITEM_TYPE.VERSION, item.name, properties);
}
}
entaxyCICDProjectVersionsController.$inject = ['$scope', 'workspace', 'entaxyCICDService', '$uibModal',
'$templateCache', '$location'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,153 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdRequirements', {
bindings: {
version: '<',
type: '@'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyCICDRequirementsController
})
.name;
function EntaxyCICDRequirementsController(workspace, $scope, $uibModal, entaxyCICDService) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'id',
title: 'Id',
placeholder: 'Filter by Id...',
filterType: 'text'
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'select',
filterValues: []
},
{
id: 'scope',
title: 'Scope',
placeholder: 'Filter by Scope...',
filterType: 'select',
filterValues: []
},
{
id: 'status',
title: 'Status',
placeholder: 'Filter by Status...',
filterType: 'select',
filterValues: ['yes', 'no']
}
],
inlineResults: true,
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Id', itemField: 'id' },
{ header: 'Type', itemField: 'type' },
{ header: 'Scope', itemField: 'scope' },
{ header: 'Status', itemField: 'status', templateFn: (value) => EntaxyCICD.getStatusTemplate(value) }
];
ctrl.pageConfig = Entaxy.getStandardPageConfig();
function filterChange(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function matchesFilter(item, filter) {
let match = true;
if (filter.id === 'id') {
match = item.id.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'type') {
match = item.type === filter.value;
} else if (filter.id === 'scope') {
match = item.scope === filter.value;
} else if (filter.id === 'status') {
match = filter.value === 'yes' ? item.status === true : item.status === false;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
entaxyCICDService.setTypesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
entaxyCICDService.setScopesToFilterConfig(ctrl.toolbarConfig.filterConfig.fields);
}
$scope.$watch('$ctrl.version', function () {
populateTable();
});
function populateTable() {
const storage = EntaxyCICD.getStorage(workspace.selection);
const application = EntaxyCICD.getProjectOrApplication(workspace.selection);
let operationName = 'list' + ctrl.type + 'Requirements';
entaxyCICDService.executeOperation(operationName, [storage, application, ctrl.version])
.then(result => {
let items = JSON.parse(result);
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
});
}
}
EntaxyCICDRequirementsController.$inject = ['workspace', '$scope', '$uibModal', 'entaxyCICDService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,147 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdSimpleFieldsModal', {
bindings: {
modalInstance: '<',
resolve: '<'
},
template:
`
<div class="entaxy-modal-container simple-modal-content">
<div class="modal-header">
<button type="button" class="close" aria-label="Close" ng-click="$ctrl.cancel()">
<span class="pficon pficon-close" aria-hidden="true"></span>
</button>
<h4 class="modal-title">{{$ctrl.resolve.modalTitle}}</h4>
</div>
<div class="modal-body">
<form name="entaxyObjectForm" class="form-horizontal">
<div class="form-group" ng-repeat="formField in $ctrl.formFields"
ng-class="{'has-error': $ctrl.errors[formField.name]}" ng-if="!formField.isHidden">
<div class="col-sm-3 label-col">
<label class="control-label" ng-class="{'required-pf': formField.required}" for="{{formField.name}}">
{{formField.label}}
</label>
<button type="button" class="btn btn-link label-description-popover"
popover-placement="auto top-left" popover-trigger="'outsideClick'"
uib-popover="{{formField.description}}" ng-if="formField.description">
<span class="pficon pficon-help"></span>
</button>
</div>
<div class="col-sm-8">
<input type="{{formField.type}}" id="{{formField.name}}" class="form-control"
ng-model="formField.value" ng-readonly="formField.readOnly"
ng-if="!formField.enum && !formField.resource" set-focused="formField.setFocused">
<entaxy-select-from-enum id="{{formField.name}}" values="formField.values"
model="formField.value" readonly="formField.readOnly" is-empty-included="false"
ng-if="formField.enum" set-focused="formField.setFocused"></entaxy-select-from-enum>
<entaxy-resource-input id="{{formField.name}}" name="{{formField.name}}" model="formField.value"
ng-if="formField.resource"></entaxy-resource-input>
<span class="help-block" ng-show="$ctrl.errors[formField.name]">
{{$ctrl.errors[formField.name]}}
</span>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">Save</button>
</div>
</div>
`,
controller: entaxyCICDSimpleFieldsModalController
})
.name;
function entaxyCICDSimpleFieldsModalController($scope, $uibModal, entaxyService, entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.formFields = ctrl.resolve.formFields;
if (!ctrl.formFields || ctrl.formFields.length === 0) {
ctrl.cancel('Fields can not be found');
}
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function() {
ctrl.errors = validate();
if (Object.keys(ctrl.errors).length === 0) {
let args = ctrl.formFields.map(formField => formField.value);
ctrl.modalInstance.close(args);
}
}
function validate() {
let errors = {};
ctrl.formFields.forEach(formField => {
if (formField.required && (formField.value === undefined ||
(!formField.resource && formField.value.trim().length === 0))) {
errors[formField.name] = Entaxy.ERROR_MESSAGE.EMPTY;
}
if (!errors[formField.name] && formField.validation) {
let validation = { ...formField.validation };
delete validation.checkUniqueness;
delete validation.values;
entaxyService.validateByRules(formField, validation, errors);
}
if (!errors[formField.name] && formField.validation && formField.validation.checkUniqueness
&& formField.validation.values.includes(formField.value)) {
errors[formField.name] = Entaxy.ERROR_MESSAGE.UNIQUE;
}
});
return errors;
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save();
}
}
];
}
}
entaxyCICDSimpleFieldsModalController.$inject = ['$scope', '$uibModal', 'entaxyService', 'entaxyHotkeysService'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,263 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.component('entaxyCiCdTreeHeader', {
template:
`
<div class="tree-nav-sidebar-header">
<form role="form" class="search-pf has-button">
<div class="form-group has-clear">
<div class="search-pf-input-group">
<label for="input-search" class="sr-only">Search Tree:</label>
<input id="input-search" type="search" class="form-control" placeholder="Search tree:"
ng-model="$ctrl.filter">
<button type="button" class="clear" aria-hidden="true"
ng-hide="$ctrl.filter.length === 0"
ng-click="$ctrl.filter = ''">
<span class="pficon pficon-close"></span>
</button>
</div>
</div>
<div class="form-group tree-nav-buttons">
<span class="badge" ng-class="{positive: $ctrl.result.length > 0}"
ng-show="$ctrl.filter.length > 0">
{{$ctrl.result.length}}
</span>
<i class="fa fa-plus-square-o" title="Expand All" ng-click="$ctrl.expandAll()"></i>
<i class="fa fa-minus-square-o" title="Collapse All" ng-click="$ctrl.contractAll()"></i>
</div>
</form>
</div>
`,
controller: EntaxyCICDTreeHeaderController
}).component('entaxyCiCdTree', {
template:
`
<div class="tree-nav-sidebar-content">
<div id="entaxycicdtree" class="treeview-pf-hover treeview-pf-select"></div>
</div>
`,
controller: EntaxyCICDTreeController
})
.name;
entaxyCICDTreeElementId = '#entaxycicdtree';
EntaxyCICD.log.debug("loaded tree" + EntaxyCICD.treeModule);
function EntaxyCICDTreeHeaderController($scope, $element) {
'ngInject';
EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController ");
this.$scope = $scope;
this.$element = $element;
this.filter = '';
this.result = [];
// it's not possible to declare classes to the component host tag in AngularJS
$element.addClass('tree-nav-sidebar-header');
EntaxyCICDTreeHeaderController.prototype.$onInit = function () {
EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController init");
var _this = this;
this.$scope.$watch(angular.bind(this, function () { return _this.filter; }), function (filter, previous) {
if (filter !== previous) {
_this.search(filter);
}
});
};
EntaxyCICDTreeHeaderController.prototype.search = function (filter) {
EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController search");
var _this = this;
var doSearch = function (filter) {
var result = _this.tree().search(filter, {
ignoreCase: true,
exactMatch: false,
revealResults: true
});
_this.result.length = 0;
(_a = _this.result).push.apply(_a, result);
Core.$apply(_this.$scope);
var _a;
};
_.debounce(doSearch, 300, { leading: false, trailing: true })(filter);
};
EntaxyCICDTreeHeaderController.prototype.tree = function () {
EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController tree");
return $(entaxyCICDTreeElementId).treeview(true);
};
EntaxyCICDTreeHeaderController.prototype.expandAll = function () {
EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController expand");
return this.tree()
.expandNode(this.tree().getNodes(), { levels: HawtioTree.getMaxTreeLevel(this.tree()), silent: true });
};
EntaxyCICDTreeHeaderController.prototype.contractAll = function () {
EntaxyCICD.log.debug("EntaxyCICDTreeHeaderController contract");
return this.tree()
.collapseNode(this.tree().getNodes(), { ignoreChildren: true, silent: true });
};
}
EntaxyCICDTreeHeaderController.$inject = ['$scope', '$element'];
function EntaxyCICDTreeController($scope, $location, workspace, $element, operationsService, $q) {
'ngInject';
this.$scope = $scope;
this.$location = $location;
this.workspace = workspace;
this.$element = $element;
// it's not possible to declare classes to the component host tag in AngularJS
$element.addClass('tree-nav-sidebar-content');
EntaxyCICD.log.debug("EntaxyCICDTreeController ");
var entaxyCICDJmxDomain = localStorage['entaxyCICDJmxDomain'] || "ru.entaxy.cicd";
EntaxyCICDTreeController.prototype.$onInit = function () {
EntaxyCICD.log.debug("EntaxyCICDTreeController onInit");
var _this = this;
this.$scope.$on('$destroy', function () { return _this.removeTree(); });
this.$scope.$on('$routeChangeStart', function () {
return Jmx.updateTreeSelectionFromURL(_this.$location, $(entaxyCICDTreeElementId));
});
this.$scope.$on('jmxTreeUpdated', function (event, opts) {
let updateSelectionNode = opts ? opts.updateSelectionNode : false;
return _this.populateTree(updateSelectionNode);
});
this.populateTree();
};
EntaxyCICDTreeController.prototype.updateSelectionFromURL = function () {
Jmx.updateTreeSelectionFromURLAndAutoSelect(this.$location, $(entaxyCICDTreeElementId), null, true);
};
EntaxyCICDTreeController.prototype.populateTree = function (updateSelectionNode) {
let tree = this.workspace.tree;
if (tree) {
let domain = tree.get(entaxyCICDJmxDomain);
if (domain && domain.children && domain.children.length > 0) {
let promises = [];
domain.children.forEach(child => {
child.class = createClassName(child.title);
promises.push(
operationsService.executeOperation(child.objectName, {name: 'readAsTree'}, [])
.then(result => {
let nodes = JSON.parse(result);
let folderNames = child.key.split('-');
folderNames.shift();
let cicdTree = createTree(nodes, child.key, folderNames);
cicdTree.forEach(cicdChild => {
cicdChild.parent = child;
});
child.children = cicdTree;
})
);
});
$q.all(promises).then(() => {
this.removeTree();
Jmx.enableTree(this.$scope, this.$location, this.workspace,
$(entaxyCICDTreeElementId), domain.children);
this.updateSelectionFromURL();
if (updateSelectionNode) {
workspace.updateSelectionNode(workspace.selection);
}
});
}
}
};
function createTree(children, keyPrefix, folderNames) {
let folders = [];
if (children && children.length > 0) {
children.forEach(child => {
let folder = new Jmx.Folder(child.title);
let index = child.title.indexOf('[');
if (index > 0) {
folder.key = keyPrefix + '-' + child.title.slice(0, index - 1).toLowerCase();
} else {
folder.key = keyPrefix + '-' + child.title.toLowerCase();
}
let folderNamesCopy = folderNames.map(folderName => folderName);
folderNamesCopy.push(index > 0 ? child.title.slice(0, index - 1) : child.title);
folder.folderNames = folderNamesCopy;
addClass(folder);
folder.tooltip = folder.title;
folder.domain = entaxyCICDJmxDomain;
folder.children = createTree(child.children, folder.key, folderNamesCopy);
if (folder.children && folder.children.length > 0) {
folder.children.forEach(child => {
child.parent = folder;
})
}
folder.sortChildren();
folders.push(folder);
});
}
return folders;
}
function addClass(folder) {
switch (folder.folderNames.length) {
case 3:
folder.class = createClassName('storages');
break;
case 4:
folder.class = createClassName(folder.folderNames[1]);
break;
case 5:
folder.class = createClassName('versions');
break;
case 6:
folder.class = createClassName(folder.folderNames[1] === 'applications' ?
'revisions' : 'build-info');
break;
}
}
function createClassName(folderName) {
return 'entaxy-cicd-' + folderName + '-icon';
}
EntaxyCICDTreeController.prototype.removeTree = function () {
var tree = $(entaxyCICDTreeElementId).treeview(true);
// There is no exposed API to check whether the tree has already been initialized,
// so let's just check if the methods are present
if (tree.clearSearch) {
tree.clearSearch();
// Bootstrap tree view leaks the node elements into the data structure
// so let's clean this up when the user leaves the view
var cleanTreeFolder_1 = function (node) {
delete node['$el'];
if (node.nodes)
node.nodes.forEach(cleanTreeFolder_1);
};
cleanTreeFolder_1(this.workspace.tree);
// Then call the tree clean-up method
tree.remove();
}
}
}
EntaxyCICDTreeController.$inject = ['$scope', '$location', 'workspace', '$element', 'operationsService', '$q'];
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,155 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
const REVISION_STATUS = {
CONFIGURED: 'CONFIGURED',
DEPLOYED: 'DEPLOYED',
INSTALLED: 'INSTALLED',
UNINSTALLED: 'UNINSTALLED'
}
EntaxyCICD.REVISION_STATUS = REVISION_STATUS;
const ITEM_TYPE = {
APPLICATION: 'Application',
PROJECT: 'Project',
VERSION: 'Version'
}
EntaxyCICD.ITEM_TYPE = ITEM_TYPE;
function isStorage(selection) {
return selection.folderNames && selection.folderNames.length === 3;
}
EntaxyCICD.isStorage = isStorage;
function getStorage(selection) {
if (selection.folderNames) {
switch (selection.folderNames.length) {
case 3:
return selection.title;
case 4:
return selection.parent.title;
case 5:
return selection.parent.parent.title;
case 6:
return selection.parent.parent.parent.title;
}
}
}
EntaxyCICD.getStorage = getStorage;
function getStorages(selection) {
return selection.children && selection.children.length > 0 ? selection.children.map(child => child.title) : [];
}
EntaxyCICD.getStorages = getStorages;
function getProjectOrApplication(selection) {
if (selection.folderNames) {
switch (selection.folderNames.length) {
case 4:
return selection.title;
case 5:
return selection.parent.title;
case 6:
return selection.parent.parent.title;
}
}
}
EntaxyCICD.getProjectOrApplication = getProjectOrApplication;
function isVersion(selection) {
return selection.folderNames && selection.folderNames.length === 5;
}
EntaxyCICD.isVersion = isVersion;
function getVersion(selection) {
if (selection.folderNames) {
switch (selection.folderNames.length) {
case 5:
return selection.title;
case 6:
return selection.parent.title;
}
}
}
EntaxyCICD.getVersion = getVersion;
function getVersions(selection) {
return selection.children && selection.children.length > 0 ? selection.children.map(child => child.title) : [];
}
EntaxyCICD.getVersions = getVersions;
function isRevision(selection) {
return selection.folderNames && selection.folderNames.length === 6;
}
EntaxyCICD.isRevision = isRevision;
function getRevisionInfo(selection) {
let splitTitle = selection.title.split(' ');
return {
revision: splitTitle[0],
revisionStatus: splitTitle[1].replace(/\[|]/g, '')
};
}
EntaxyCICD.getRevisionInfo = getRevisionInfo;
function getStatusTemplate(value) {
if (value) {
return '<span class="pficon pficon-ok"></span>'
} else {
return '<span class="pficon pficon-error-circle-o blue"></span>';
}
}
EntaxyCICD.getStatusTemplate = getStatusTemplate;
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
EntaxyCICD.capitalize = capitalize;
function createTableFromUnremovedItems(unremovedItemsInfo) {
let tableHtml = `<table class="entaxy-cicd-unremoved-info-table">`;
tableHtml += `
<tr>
<th>Item</th>
<th>Required By</th>
</tr>
`;
Object.entries(unremovedItemsInfo).forEach(([itemId, listRequiredBy]) => {
tableHtml += `<tr><td>` + itemId + `</td><td>`;
listRequiredBy.forEach(requiredBy => {
tableHtml += requiredBy + '\n';
});
tableHtml += `</td></tr>`;
});
tableHtml += `</table>`;
return tableHtml;
}
EntaxyCICD.createTableFromUnremovedItems = createTableFromUnremovedItems;
})(EntaxyCICD || (EntaxyCICD = {}));

View File

@ -0,0 +1,93 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
/**
* The main entry point for the Simple module
*/
var EntaxyCICD = (function (EntaxyCICD) {
/**
* The name of this plugin
*/
EntaxyCICD.pluginName = 'entaxy-cicd';
/**
* This plugin's logger instance
*/
EntaxyCICD.log = Logger.get('entaxy-cicd');
/**
* The top level path of this plugin on the server
*/
EntaxyCICD.contextPath = "/entaxy-cicd/";
EntaxyCICD.log.info("loading entaxy cicd plugin")
EntaxyCICD._module = angular.module(EntaxyCICD.pluginName, [
'angularResizable'
])
.component('entaxyCiCd', {
template:
`
<div class="tree-nav-layout">
<div class="sidebar-pf sidebar-pf-left" resizable r-directions="['right']">
<entaxy-ci-cd-tree-header></entaxy-ci-cd-tree-header>
<entaxy-ci-cd-tree></entaxy-ci-cd-tree>
</div>
<div class="tree-nav-main">
<entaxy-ci-cd-navigation></entaxy-ci-cd-navigation>
<entaxy-ci-cd-contents></entaxy-ci-cd-contents>
</div>
</div>
`
})
.run(configurePlugin);
function configurePlugin(mainNavService, workspace, helpRegistry, preferencesRegistry, localStorage) {
var entaxyCICDJmxDomain = localStorage['entaxyCICDJmxDomain'] || "ru.entaxy.cicd";
mainNavService.addItem({
title: 'Entaxy CI/CD',
basePath: '/entaxy-cicd',
template: '<entaxy-ci-cd></entaxy-ci-cd>',
isValid: function () { return workspace.treeContainsDomainAndProperties(entaxyCICDJmxDomain); },
rank: 2
});
// clean up local storage upon logout
/* preLogoutTasks.addTask('CleanupArtemisCredentials', function () {
Artemis.log.debug("Clean up Artemis credentials in local storage");
localStorage.removeItem('artemisUserName');
localStorage.removeItem('artemisPassword');
}); */
}
configurePlugin.$inject = ['mainNavService', 'workspace', 'helpRegistry', 'preferencesRegistry', 'localStorage'];
return EntaxyCICD;
})(EntaxyCICD || {});
// tell the Hawtio plugin loader about our plugin so it can be
// bootstrapped with the rest of AngularJS
hawtioPluginLoader.addModule(EntaxyCICD.pluginName);

View File

@ -0,0 +1,125 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-cicd-plugin
* ==========
* Copyright (C) 2020 - 2025 EmDev LLC
* ==========
* You may not use this file except in accordance with the License Terms of the Copyright
* Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
* rights to the Software and any copies are the property of the Copyright Holder. Unless
* it is explicitly allowed the Copyright Holder, the User is prohibited from using the
* Software for commercial purposes to provide services to third parties.
*
* The Copyright Holder hereby declares that the Software is provided on an "AS IS".
* Under no circumstances does the Copyright Holder guarantee or promise that the
* Software provided by him will be suitable or not suitable for the specific purposes
* of the User, that the Software will meet all commercial and personal subjective
* expectations of the User, that the Software will work properly, without technical
* errors, quickly and uninterruptedly.
*
* Under no circumstances shall the Copyright Holder or its Affiliates is not liable
* to the User for any direct or indirect losses of the User, his expenses or actual
* damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
* or damage to data, property, etc.
* ~~~~~~/licensing~~~~~~
*/
var EntaxyCICD;
(function (EntaxyCICD) {
EntaxyCICD._module.factory('entaxyCICDService', ['$q', 'workspace', 'jolokia', 'jolokiaService', 'operationsService',
'$uibModal', 'entaxyService',
function($q, workspace, jolokia, jolokiaService, operationsService, $uibModal, entaxyService) {
const entaxyCICDJmxDomain = localStorage['entaxyCICDJmxDomain'] || "ru.entaxy.cicd";
return {
executeOperation: function (operationName, properties) {
return executeOperation(operationName, properties);
},
treeUpdated: function () {
return treeUpdated();
},
setTypesToFilterConfig: function (filterFields) {
return setValuesToFilterConfig(filterFields, 'type', 'readApplicationItemTypes');
},
setScopesToFilterConfig: function (filterFields) {
return setValuesToFilterConfig(filterFields, 'scope', 'readApplicationItemScopes');
},
removeItemWithConfirmation: function (itemType, itemName, properties, updateSelectionNode, message) {
return removeItemWithConfirmation(itemType, itemName, properties, updateSelectionNode, message);
}
};
function executeOperation(operationName, properties) {
let mbeanName = getCICDMBeanName();
let operation = { name : operationName };
if (mbeanName) {
return operationsService.executeOperation(mbeanName, operation, properties);
} else {
return $q.reject("Cannot find mbean for CI/CD");
}
}
function treeUpdated () {
let rootScope = workspace.$rootScope;
if (rootScope) {
Core.$apply(rootScope);
rootScope.$broadcast(Jmx.TreeEvent.Updated, { updateSelectionNode: true });
}
}
function setValuesToFilterConfig(filterFields, fieldId, operationName) {
let mbean = workspace.findMBeanWithProperties(entaxyCICDJmxDomain, { module: 'applications' });
let operation = { name: operationName };
operationsService.executeOperation(mbean.objectName, operation, [])
.then(result => {
let toolbarConfigTypeField = filterFields.find(field => field.id === fieldId);
toolbarConfigTypeField.filterValues = JSON.parse(result);
});
}
function removeItemWithConfirmation(itemType, itemName, properties, updateSelectionNode, message) {
let title = 'Confirm Removing';
if (!message) {
message = 'Do you want to remove the ' + itemType.toLowerCase() + ' ' + itemName + '?';
}
entaxyService.openConfirmationWindow(title, message).then(() => {
executeOperation('remove' + itemType, properties)
.then(result => {
Entaxy.notificationSuccess(result);
if (updateSelectionNode) {
treeUpdated();
} else {
workspace.jmxTreeUpdated();
}
})
.catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
});
}
function getCICDMBeanName() {
if (!workspace.hasDomainAndProperties(entaxyCICDJmxDomain)) {
return;
}
let tree = workspace.tree;
if (tree) {
let domain = tree.get(entaxyCICDJmxDomain);
if (domain && domain.children) {
for (let i = 0; i < domain.children.length; i++) {
if (domain.children[i].folderNames[1] === workspace.selection.folderNames[1]) {
return domain.children[i].objectName;
}
}
}
}
}
}
])
})(EntaxyCICD || (EntaxyCICD = {}));