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

@ -3,7 +3,7 @@
<parent>
<groupId>ru.entaxy.esb.ui</groupId>
<artifactId>entaxy-hawtio</artifactId>
<version>1.10.0</version>
<version>1.11.0</version>
</parent>
<groupId>ru.entaxy.esb.ui.hawtio</groupId>
<artifactId>entaxy-management-plugin</artifactId>

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -3,7 +3,7 @@
~~~~~~licensing~~~~~~
entaxy-management-plugin
==========
Copyright (C) 2020 - 2024 EmDev LLC
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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -0,0 +1,314 @@
/*-
* ~~~~~~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~~~~~~
*/
// Distributed under an MIT license: http://codemirror.net/LICENSE
/**
* freemarker
*/
(function(mod) {
if (typeof exports == "object" && typeof module == "object" ) // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd ) // AMD
define([ "../../lib/codemirror" ], mod);
else
// Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror
.defineMode("freemarker", function(config) {
"use strict";
// our default settings; check to see if they're overridden
var settings = {
leftDelimiter : '[', rightDelimiter : ']', tagSyntax : 2
// 1 angle_bracket,2 square_bracket
};
if (config.hasOwnProperty("tagSyntax") ) {
if (config.tagSyntax === 1 ) {
settings.tagSyntax = 1;
settings.leftDelimiter = '<';
settings.rightDelimiter = '>';
}
}
var keyFunctions = [ "assign", "attempt", "autoesc", "break", "case", "compress", "default", "else",
"elseif", "escape", "fallback", "function", "flush", "ftl", "global", "if", "import",
"include", "items", "list", "local", "lt", "macro", "nested","noautoesc", "noescape", "noparse", "nt","outputformat",
"recover", "recurse", "return", "rt", "sep", "setting", "stop", "switch", "t", "visit" ];
var specialVariables = [ "auto_esc" , "caller_template_name", "current_template_name", "data_model", "error", "get_optional_template", "globals", "lang", "locale",
"locale_object", "locals", "main", "main_template_name", "namespace", "node", "now",
"output_encoding " , "output_format" , "template_name" , "time_zone" , "url_escaping_charset", "vars", "version" ];
var freemarkerStartTagArray = [ "#", "@" ];
var freemarkerEndTagArray = [ "/#", "/@", "/>" ];
var last;
var freemarkerMode;
var regs = {
operatorChars : /[+\-*&%=<>!?:;,|&]/, validIdentifier : /[a-zA-Z0-9_]/, stringChar : /['"]/
};
var helpers = {
cont : function(style, lastType, lastFreemarkerMode) {
last = lastType;
freemarkerMode = lastFreemarkerMode;
return style;
}, chain : function(stream, state, parser) {
state.tokenize = parser;
return parser(stream, state);
}
};
// our various parsers
var parsers = {
// the main tokenizer
tokenizer : function(stream, state) {
if (stream.match(settings.leftDelimiter, true) ) {
if (stream.match("#--", true) ) {
return helpers.chain(stream, state, parsers.inBlock("comment", "--"
+ settings.rightDelimiter));
} else {
for (var i = 0; i < freemarkerStartTagArray.length; i++) {
if (stream.match(freemarkerStartTagArray[i], false) ) {
state.tokenize = parsers.freemarkerTemplate;
if (freemarkerStartTagArray[i] == "@" ) {
freemarkerMode = "macro";
} else {
freemarkerMode = "tag";
}
last = "startTag";
return "tag";
}
}
for (var i = 0; i < freemarkerEndTagArray.length; i++) {
if (stream.match(freemarkerEndTagArray[i], false) ) {
state.tokenize = parsers.freemarkerTemplate;
if (freemarkerEndTagArray[i] == "/@" ) {
freemarkerMode = "macro";
} else {
freemarkerMode = "tag";
}
last = "endTag";
return "tag";
}
}
}
} else if (stream.match("${", false) ) {
state.tokenize = parsers.freemarkerTemplate;
last = "startTag";
freemarkerMode = "echo";
return "keyword";
}
stream.next();
return null;
},
// parsing freemarker content
freemarkerTemplate : function(stream, state) {
if (stream.match(settings.rightDelimiter, true) ) {
state.depth--;
if (state.depth <= 0 ) {
state.tokenize = parsers.tokenizer;
}
return helpers.cont("tag", null, null);
} else if ("echo" == state.freemarkerMode && stream.match("}", true) ) {
state.depth--;
if (state.depth <= 0 ) {
state.tokenize = parsers.tokenizer;
}
return helpers.cont("keyword", null, null);
}
if (stream.match(settings.leftDelimiter, true) ) {
for (var i = 0; i < freemarkerStartTagArray.length; i++) {
if (stream.match(freemarkerStartTagArray[i], false) ) {
state.depth++;
if (freemarkerStartTagArray[i] == "@" ) {
return helpers.cont("tag", "startTag", "macro");
} else {
return helpers.cont("tag", "startTag", "tag");
}
}
}
for (var i = 0; i < freemarkerEndTagArray.length; i++) {
if (stream.match(freemarkerEndTagArray[i], false) ) {
state.depth++;
if (freemarkerEndTagArray[i] == "/@" ) {
return helpers.cont("tag", "endTag", "macro");
} else {
return helpers.cont("tag", "endTag", "tag");
}
}
}
} else if (stream.match("${", true) ) {
state.depth++;
return helpers.cont("keyword", "startTag", "echo");
}
var ch = stream.next();
if ("." == ch ) {
if("echo" == state.freemarkerMode || "whitespace" == state.last ||"operator"== state.last){
for (var i = 0; i < specialVariables.length; i++) {
if(stream.match(specialVariables[i],true)){
return helpers.cont("keyword", "variable", state.freemarkerMode);
}
}
}
if("keyword"==state.last && stream.eatWhile(regs.validIdentifier)){
return helpers.cont("keyword", null, state.freemarkerMode);
}else{
return helpers.cont("operator", "childVariable", state.freemarkerMode);
}
} else if (regs.stringChar.test(ch) ) {
state.tokenize = parsers.inAttribute(ch);
return helpers.cont("string", "string", state.freemarkerMode);
} else if (regs.operatorChars.test(ch) ) {
if ("?" === ch ) {
return helpers.cont("operator", "builtin", state.freemarkerMode);
} else {
return helpers.cont("operator", "operator", state.freemarkerMode);
}
} else if ("[" == ch || "{" == ch|| "(" == ch ) {
return helpers.cont("bracket", "bracket", state.freemarkerMode);
} else if ("]" == ch || "}" == ch || ")" == ch ) {
return helpers.cont("bracket", "variable", state.freemarkerMode);
} else if ("/" == ch ) {
return helpers.cont("tag", "endTag", state.freemarkerMode);
} else if ("@" == ch && "macro" == state.freemarkerMode ) {
stream.eatWhile(regs.validIdentifier)
return helpers.cont("keyword", "keyword", state.freemarkerMode);
} else if (/\d/.test(ch) ) {
stream.eat(/x/i)
stream.eatWhile(/\d/);
return helpers.cont("number", "number", state.freemarkerMode);
} else if("tag" == state.freemarkerMode && "whitespace" == state.last && (stream.match("as",true) || stream.match("in",true)|| stream.match("using",true) )) {
return helpers.cont("keyword", "operator", state.freemarkerMode);
} else if("tag" == state.freemarkerMode && "whitespace" == state.last && (stream.match("gte",true) || stream.match("lte",true) || stream.match("gt",true) || stream.match("lt",true) )) {
return helpers.cont("operator", "operator", state.freemarkerMode);
} else {
if ("builtin" == state.last ) {
stream.eat("?");
stream.eatWhile(regs.validIdentifier);
return helpers.cont("builtin", "variable", state.freemarkerMode);
} else if ("whitespace" == state.last||"bracket" == state.last) {
if ("macro" == state.freemarkerMode ) {
stream.eatWhile(regs.validIdentifier);
return helpers.cont("attribute", "attribute", state.freemarkerMode);
} else {
stream.eatWhile(regs.validIdentifier);
return helpers.cont("variable-2", "variable", state.freemarkerMode);
}
} else if ("operator" == state.last ) {
stream.eatWhile(regs.validIdentifier);
return helpers.cont("variable-2", "variable", state.freemarkerMode);
} else if ("childVariable" == state.last ) {
stream.eatWhile(regs.validIdentifier);
return helpers.cont("variable-3", "variable", state.freemarkerMode);
} else if (/\s/.test(ch) ) {
last = "whitespace";
return null;
} else if ("string" == state.last ) {
stream.eatWhile(regs.validIdentifier);
return helpers.cont("attribute", "attribute", state.freemarkerMode);
} else {
if ("startTag" == state.last || "endTag" == state.last ) {
if ("echo" == state.freemarkerMode ) {
stream.eatWhile(regs.validIdentifier)
return helpers.cont("variable-2", "variable", state.freemarkerMode);
}
}
if ("tag" == state.freemarkerMode ) {
var str = "";
if (ch != "/" ) {
str += ch;
}
var c = null;
while (c = stream.eat(regs.validIdentifier)) {
str += c;
}
for (var i = 0 ; i < keyFunctions.length; i++) {
if ("#"+keyFunctions[i] == str ) {
return helpers.cont("keyword", "keyword", state.freemarkerMode);
}
}
}
}
return helpers.cont("error", "tag", state.freemarkerMode);
}
},
inAttribute : function(quote) {
return function(stream, state) {
var prevChar = null;
var currChar = null;
while (!stream.eol()) {
currChar = stream.peek();
if (stream.next() == quote && '\\' !== prevChar ) {
state.tokenize = parsers.freemarkerTemplate;
break;
}
prevChar = currChar;
}
return "string";
};
},
inBlock : function(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator) ) {
state.tokenize = parsers.tokenizer;
break;
}
stream.next();
}
return style;
};
}
};
// the public API for CodeMirror
return {
startState : function() {
return {
tokenize : parsers.tokenizer, mode : "freemarker", last : null, freemarkerMode : null,
depth : 0
};
}, token : function(stream, state) {
state.last = last;
state.freemarkerMode = freemarkerMode;
return state.tokenize(stream, state);
}, electricChars : ""
};
});
CodeMirror.defineMIME("text/freemarker", "freemarker");
});

View File

@ -0,0 +1,229 @@
/*-
* ~~~~~~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~~~~~~
*/
// Distributed under an MIT license: http://codemirror.net/LICENSE
/**
* @file freemarkermixed.js
*/
(function(mod) {
if (typeof exports == "object" && typeof module == "object" ) // CommonJS
mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../freemarker/freemarker"));
else if (typeof define == "function" && define.amd ) // AMD
define([ "../../lib/codemirror", "../htmlmixed/htmlmixed", "../freemarker/freemarker" ], mod);
else
// Plain browser env
mod(CodeMirror);
})
(function(CodeMirror) {
"use strict";
CodeMirror
.defineMode("freemarkermixed", function(config) {
var htmlMixedMode = CodeMirror.getMode(config, "htmlmixed");
var freemarkerMode = CodeMirror.getMode(config, "freemarker");
var settings = {
leftDelimiter : '[', rightDelimiter : ']', tagSyntax : 2
// 1 angle_bracket,2 square_bracket
};
if (config.hasOwnProperty("tagSyntax") ) {
if (config.tagSyntax === 1 ) {
settings.tagSyntax = 1;
settings.leftDelimiter = '<';
settings.rightDelimiter = '>';
}
}
var freemarkerFlagArray = ["#","/#","@","/@"];
function regEsc(str) {
return str.replace(/[^\s\w]/g, "\\$&");
}
var regLeftArray=[],htmlHasLeftDelimeterRegArray=[];
for (var i = 0; i < freemarkerFlagArray.length; i++) {
let futureRegExp = ".*" + regEsc(settings.leftDelimiter + freemarkerFlagArray[i]);
regLeftArray.push( new RegExp(".*" + regEsc(settings.leftDelimiter + freemarkerFlagArray[i])));
htmlHasLeftDelimeterRegArray.push( new RegExp("[^<>]*" + regEsc(settings.leftDelimiter + freemarkerFlagArray[i])));
}
var helpers = {
chain : function(stream, state, parser) {
state.tokenize = parser;
return parser(stream, state);
},
cleanChain : function(stream, state, parser) {
state.tokenize = null;
state.localState = null;
state.localMode = null;
return (typeof parser == "string") ? (parser ? parser : null) : parser(stream, state);
},
maybeBackup : function(stream, pat, style) {
var cur = stream.current();
var close = cur.search(pat) , m;
if (close > -1 ) {
stream.backUp(cur.length - close);
} else if (m = cur.match(/<\/?$/) ) {
stream.backUp(cur.length);
if (!stream.match(pat, false) ) {
stream.match(cur[0]);
}
}
return style;
}
};
var parsers = {
html : function(stream, state) {
if (!state.noparse) {
var htmlTagName = state.htmlMixedState.htmlState.context && state.htmlMixedState.htmlState.context.tagName
? state.htmlMixedState.htmlState.context.tagName
: null;
for (var i = 0; i < freemarkerFlagArray.length; i++) {
if ( (stream.match(htmlHasLeftDelimeterRegArray[i], false) && htmlTagName === null ) || stream.match(settings.leftDelimiter + freemarkerFlagArray[i], false)) {
state.tokenize = parsers.freemarker;
state.localMode = freemarkerMode;
state.localState = freemarkerMode.startState(htmlMixedMode.indent(state.htmlMixedState, "", ""));
return helpers.maybeBackup(stream, regEsc(settings.leftDelimiter) + freemarkerFlagArray[i], freemarkerMode.token(stream, state.localState));
} else if (stream.match("${", false)) {
state.tokenize = parsers.freemarker;
state.localMode = freemarkerMode;
state.localState = freemarkerMode.startState(htmlMixedMode.indent(state.htmlMixedState, "", ""));
return helpers.maybeBackup(stream, "${", freemarkerMode.token(stream, state.localState));
}
}
}
return htmlMixedMode.token(stream, state.htmlMixedState);
},
freemarker : function(stream, state) {
if (stream.match(settings.leftDelimiter + "#--", false) ) {
return helpers.chain(stream, state, parsers.inBlock("comment", "--"
+ settings.rightDelimiter));
} else if (stream.match(settings.rightDelimiter, false) ) {
stream.eat(settings.rightDelimiter);
state.tokenize = parsers.html;
state.localMode = htmlMixedMode;
state.localState = state.htmlMixedState;
return "tag";
} else if (stream.match("}", false) ) {
stream.eat("}");
state.tokenize = parsers.html;
state.localMode = htmlMixedMode;
state.localState = state.htmlMixedState;
return "keyword";
}
return helpers.maybeBackup(stream, regEsc(settings.rightDelimiter), freemarkerMode
.token(stream, state.localState));
},
inBlock : function(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator) ) {
helpers.cleanChain(stream, state, "");
break;
}
stream.next();
}
return style;
};
}
};
return {
startState : function() {
var state = htmlMixedMode.startState();
return {
token : parsers.html, localMode : null, localState : null, htmlMixedState : state,
tokenize : null, noparse : false
};
},
copyState : function(state) {
var local = null , tok = (state.tokenize || state.token);
if (state.localState ) {
local = CodeMirror
.copyState((tok != parsers.html ? freemarkerMode : htmlMixedMode), state.localState);
}
return {
token : state.token, tokenize : state.tokenize, localMode : state.localMode,
localState : local,
htmlMixedState : CodeMirror.copyState(htmlMixedMode, state.htmlMixedState),
noparse : state.noparse
};
},
token : function(stream, state) {
if (stream.match(settings.leftDelimiter+"#", false) ) {
if (!state.noparse && stream.match("#noparse", true)) {
state.noparse = true;
return "keyword";
} else if (state.noparse && stream.match("/#noparse", true)) {
state.noparse = false;
return "keyword";
}
}
if (state.noparse && state.localState != state.htmlMixedState ) {
state.tokenize = parsers.html;
state.localMode = htmlMixedMode;
state.localState = state.htmlMixedState;
}
var style = (state.tokenize || state.token)(stream, state);
return style;
},
indent : function(state, textAfter) {
if (state.localMode == freemarkerMode || (state.noparse && !state.localMode) ) {
for (var i = 0; i < regLeftArray.length; i++) {
if(regLeftArray[i].test(textAfter)){
return CodeMirror.Pass;
}
}
}
return htmlMixedMode.indent(state.htmlMixedState, textAfter, "");
},
innerMode : function(state) {
return {
state : state.localState || state.htmlMixedState,
mode : state.localMode || htmlMixedMode
};
}
};
}, "htmlmixed", "freemarker");
CodeMirror.defineMIME("text/freemarker", "freemarkermixed");
// vim: et ts=2 sts=2 sw=2
});

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
~~~~~~licensing~~~~~~
entaxy-management-plugin
==========
Copyright (C) 2020 - 2024 EmDev LLC
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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
~~~~~~licensing~~~~~~
entaxy-management-plugin
==========
Copyright (C) 2020 - 2024 EmDev LLC
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

View File

@ -2,7 +2,7 @@
~~~~~~licensing~~~~~~
entaxy-management-plugin
==========
Copyright (C) 2020 - 2024 EmDev LLC
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

View File

@ -2,7 +2,7 @@
~~~~~~licensing~~~~~~
entaxy-management-plugin
==========
Copyright (C) 2020 - 2024 EmDev LLC
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

View File

@ -0,0 +1,58 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyCopyToClipboardButton', {
bindings: {
title: '@',
textToCopy: '<'
},
template:
`
<button type="button" class="btn-clipboard" data-toggle="tooltip" title="{{$ctrl.title}}"
ng-click="$ctrl.copyLocationToClipboard($ctrl.textToCopy)">
<span class="fa fa-copy"></span>
</button>
`,
controller: entaxyCopyToClipboardButtonController
})
.name;
function entaxyCopyToClipboardButtonController($timeout) {
'ngInject';
let ctrl = this;
ctrl.copyLocationToClipboard = function(textToCopy) {
let clipboard = new ClipboardJS('.btn-clipboard', {
text: (trigger) => textToCopy
});
setTimeout(() => clipboard.destroy(), 1000);
}
}
entaxyCopyToClipboardButtonController.$inject = ['$timeout'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -0,0 +1,163 @@
/*-
* ~~~~~~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 Entaxy;
(function(Entaxy) {
'use strict';
Entaxy._module.factory('ContextMenuService', function() {
return {
element: null,
menuElement: null
};
}).directive('contextMenu', ['$document', 'ContextMenuService', function($document, ContextMenuService) {
return {
restrict: 'A',
scope: {
'item': '=',
'callback': '&contextMenu',
'contextMenuOptions': '='
},
link: function($scope, $element, $attrs) {
function createMenuElement() {
let contextMenuOptions = $scope.contextMenuOptions;
if (contextMenuOptions && contextMenuOptions.length > 0) {
let menuElementContainer = document.createElement("div");
menuElementContainer.id = "context-menu";
menuElementContainer.className = "dropdown";
menuElementContainer.style.position = "fixed";
let menuElement = menuElementContainer.appendChild(document.createElement("ul"));
menuElement.className = "dropdown-menu";
contextMenuOptions.forEach(option => {
let optionElement = menuElement.appendChild(document.createElement("li"));
if (option.divider) {
optionElement.className = 'divider';
} else {
let optionRefElement = optionElement.appendChild(document.createElement("a"));
optionRefElement.appendChild(document.createTextNode(option.name));
optionRefElement.onclick = (event) => handleAction(event, option.actionFn);
}
});
return menuElementContainer;
}
}
function handleAction(event, actionFn) {
event.preventDefault();
event.stopPropagation();
if (event.button === 0) {
if (actionFn) {
actionFn($scope.item);
}
}
handleClickEvent(event);
}
let opened = false;
function open(event, menuElement) {
menuElement.addClass('open');
let viewportHeight =
Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
let viewportWidth =
Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
let elementHeight = menuElement[0].scrollHeight;
let elementWidth = menuElement[0].scrollWidth;
let top = event.clientY;
let left = event.clientX;
if (top > (viewportHeight - elementHeight)) {
top -= elementHeight;
}
if (left > (viewportWidth - elementWidth)) {
left -= elementWidth;
}
menuElement.css('top', top + 'px');
menuElement.css('left', left + 'px');
opened = true;
}
function close(menuElement) {
menuElement.removeClass('open');
menuElement.remove();
opened = false;
}
$element.bind('contextmenu', function(event) {
if (ContextMenuService.menuElement !== null) {
close(ContextMenuService.menuElement);
}
$element[0].appendChild(createMenuElement());
ContextMenuService.menuElement = angular.element(
document.getElementById("context-menu")
);
ContextMenuService.element = event.target;
event.preventDefault();
event.stopPropagation();
$scope.$apply(function() {
$scope.callback({ $event: event });
});
$scope.$apply(function() {
open(event, ContextMenuService.menuElement);
});
});
function handleKeyUpEvent(event) {
if (opened && event.keyCode === 27) {
$scope.$apply(function() {
close(ContextMenuService.menuElement);
});
}
}
function handleClickEvent(event) {
if (opened && (event.button !== 2 || event.target !== ContextMenuService.element)) {
$scope.$apply(function() {
close(ContextMenuService.menuElement);
});
}
}
$document.bind('keyup', handleKeyUpEvent);
// Firefox treats a right-click as a click and a contextmenu event
// while other browsers just treat it as a contextmenu event
$document.bind('click', handleClickEvent);
$document.bind('contextmenu', handleClickEvent);
$scope.$on('$destroy', function() {
$document.unbind('keyup', handleKeyUpEvent);
$document.unbind('click', handleClickEvent);
$document.unbind('contextmenu', handleClickEvent);
});
}
};
}]).name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,85 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.directive('draggable', function() {
return function(scope, element) {
let el = element[0];
el.draggable = true;
el.addEventListener(
'dragstart',
function(e) {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData("text/html", e.target.id);
this.classList.add('drag');
return false;
},
false
);
el.addEventListener(
'dragend',
function(e) {
this.classList.remove('drag');
return false;
},
false
);
}
})
.directive('droppable', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element[0].addEventListener('drop', scope.handleDrop, false);
element[0].addEventListener('dragover', scope.handleDragOver, false);
scope.handleDropFn = $parse(attrs.handleDropFn);
},
controller: ['$scope', function($scope) {
$scope.handleDrop = function (e) {
e.preventDefault();
e.stopPropagation();
if ($scope.handleDropFn) {
let droppedElementId = e.dataTransfer.getData("text/html");
$scope.droppedElementId = droppedElementId;
$scope.handleDropFn($scope);
}
};
$scope.handleDragOver = function (e) {
e.preventDefault();
return;
};
}]
};
}])
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,54 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.directive('modalDialog', function(){
return {
restrict: 'AC',
link: function($scope, element) {
var draggableStr = "draggableModal";
var header = $(".modal-header", element);
header.on('mousedown', (mouseDownEvent) => {
var modalDialog = element;
var offset = header.offset();
modalDialog.addClass(draggableStr).parents().on('mousemove', (mouseMoveEvent) => {
$("." + draggableStr, modalDialog.parents()).offset({
top: mouseMoveEvent.pageY - (mouseDownEvent.pageY - offset.top),
left: mouseMoveEvent.pageX - (mouseDownEvent.pageX - offset.left)
});
}).on('mouseup', () => {
modalDialog.removeClass(draggableStr);
});
});
}
}
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,109 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.directive('entaxyFileDrop', ['$parse', function ($parse) {
return {
restrict: 'A',
replace: false,
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
let enterTarget = null;
element.on('dragenter', function (e) {
e.preventDefault();
e.stopPropagation();
enterTarget = e.target;
element.addClass('highlighted');
createNotification();
});
element.on('dragover', function (e) {
e.preventDefault();
e.stopPropagation();
});
element.on('dragleave', function (e) {
if (e.target === enterTarget) {
e.preventDefault();
e.stopPropagation();
element.removeClass('highlighted');
removeNotification();
}
});
let notificationContainer = null;
function createNotification() {
if (notificationContainer === null) {
notificationContainer = document.createElement('div');
notificationContainer.className = 'upload-notification';
let span = document.createElement('span');
span.className = 'fa fa-upload';
notificationContainer.appendChild(span);
notificationContainer.appendChild(document.createTextNode('Drop file to upload'));
let elementWidth = element.width();
let offset = 150 + elementWidth/2 + 20;
notificationContainer.style.left = 'calc(100vw - ' + offset + 'px)';
element.append(notificationContainer);
}
}
function removeNotification() {
if (notificationContainer !== null) {
notificationContainer.parentNode.removeChild(notificationContainer);
notificationContainer = null;
}
}
element.on('drop', function (e) {
e.preventDefault();
e.stopPropagation();
element.removeClass('highlighted');
removeNotification();
if (e.originalEvent.dataTransfer && e.originalEvent.dataTransfer.files.length > 0) {
ngModel.$setViewValue(e.originalEvent.dataTransfer.files[0]);
let processFn = $parse(attrs.processFn);
if (processFn) {
processFn(scope);
}
}
return false;
});
}
};
}])
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,46 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.directive("setFileModel", function() {
return {
require: "ngModel",
link: function postLink(scope, element, attrs, ngModel) {
element.on("click", function (e) {
element[0].value = null;
})
element.on("change", function(e) {
if (element[0].files[0]) {
ngModel.$setViewValue(element[0].files[0]);
}
})
}
}
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,39 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.directive('setFocused', function() {
return {
link: function (scope, element, attrs) {
scope.$watch(attrs.setFocused, function (val) {
if (angular.isDefined(val) && val) {
setTimeout(function () { element[0].focus(); });
}}, true);
}
};
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,62 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-atlasmap-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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyEditor', {
bindings: {
sourceDoc: '=',
mode: '<',
readOnly: '<'
},
template:
`
<div hawtio-editor="source" mode="$ctrl.mode" output-editor="editor"></div>
`,
controller: entaxyEditorController
})
.name;
function entaxyEditorController($scope) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function () {
$scope.source = ctrl.sourceDoc;
}
$scope.$watch('source', function (newValue) {
ctrl.sourceDoc = newValue;
});
setTimeout(function() {
if (ctrl.readOnly === true) {
$scope.editor.options.readOnly = true;
}
}, 100);
}
entaxyEditorController.$inject = ['$scope'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,201 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyExpandableList', {
bindings: {
items: '<',
itemsLabel: '@',
itemsLabelPlural: '@',
filter: '<',
actionButtons: '<',
enableButtonForItemFn: '<',
useToolbar: '<',
toolbarActionButtons: '<',
enableToolbarActionButtons: '<',
showSelectBox: '<',
onCheckBoxChangeFn: '<',
emptyStateConfig: '<'
},
template:
`
<div class="expandable-list-toolbar-container" ng-if="$ctrl.useToolbar">
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
</div>
<div class="expandable-list-container">
<pf-list-view class="entaxy-list" items="$ctrl.viewedItems" config="$ctrl.listConfig"
action-buttons="$ctrl.actionButtons" empty-state-config="$ctrl.emptyStateConfig">
<div class="list-view-pf-left ng-if="item.typeIcon">
<span class="{{item.typeIcon}} list-view-pf-icon-sm"></span>
</div>
<div class="list-view-pf-description">
<div class="list-group-item-heading">
{{item.displayName}}
</div>
<div class="list-group-item-text" ng-if="item.text">
{{item.text}}
</div>
</div>
<div class="list-view-pf-additional-info" ng-if="item.additionalInfo">
<div class="list-view-pf-additional-info-item">
{{item.additionalInfo}}
</div>
</div>
<list-expanded-content>
<div class="nested-list">
<pf-list-view class="entaxy-list" items="$parent.item.viewedSublistItems"
config="$ctrl.sublistConfig">
<div class="list-view-pf-left" ng-if="item.typeIcon">
<span class="{{item.typeIcon}} list-view-pf-icon-sm"></span>
</div>
<div class="list-view-pf-description">
<div class="list-group-item-heading">
{{item.displayName}}
</div>
<div class="list-group-item-text" ng-if="item.text">
{{item.text}}
</div>
</div>
<div class="list-view-pf-additional-info" ng-if="item.additionalInfo">
<div class="list-view-pf-additional-info-item">
{{item.additionalInfo}}
</div>
</div>
</pf-list-view>
</div>
</list-expanded-content>
</pf-list-view>
</div>
`,
controller: EntaxyExpandableListController
})
.name;
function EntaxyExpandableListController($scope) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
if (ctrl.useToolbar) {
ctrl.toolbarConfig.filterConfig.itemsLabel = ctrl.itemsLabel ? ctrl.itemsLabel : 'Result';
ctrl.toolbarConfig.filterConfig.itemsLabelPlural = ctrl.itemsLabelPlural ? ctrl.itemsLabelPlural : 'Results';
ctrl.toolbarConfig.actionsConfig = {primaryActions: ctrl.toolbarActionButtons};
$scope.$watch('$ctrl.enableToolbarActionButtons', function (newValue) {
ctrl.toolbarConfig.actionsConfig.primaryActions.forEach(actionButton => {
actionButton.isDisabled = !newValue;
});
});
}
ctrl.listConfig = {
selectionMatchProp: 'name',
selectItems: false,
showSelectBox: false,
useExpandingRows: true
}
let subListConfig = Entaxy.deepCopy(ctrl.listConfig);
if (ctrl.showSelectBox) {
subListConfig.showSelectBox = ctrl.showSelectBox;
subListConfig.onCheckBoxChange = ctrl.onCheckBoxChangeFn;
}
ctrl.sublistConfig = subListConfig;
}
$scope.$watchCollection('$ctrl.items', function (newValue) {
if (newValue && newValue.length > 0) {
ctrl.viewedItems = ctrl.items;
ctrl.viewedItems.forEach(item => {
if (item.sublist) {
item.viewedSublistItems = item.sublist;
}
});
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
ctrl.listConfig.itemsAvailable = true;
} else {
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.toolbarConfig.filterConfig.resultsCount = 0;
ctrl.listConfig.itemsAvailable = false;
}
});
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Name',
placeholder: 'Search...',
filterType: 'text'
}
],
appliedFilters: [],
onFilterChange: filterChange
},
actionsConfig: {},
isTableView: true
};
function filterChange(filters) {
applyFilters(filters);
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
};
function applyFilters(filters) {
ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter, returnSublistsToOriginalState);
};
function matchesFilter(item, filter) {
if (ctrl.filter) {
return ctrl.filter(item, filter);
} else {
let match = true;
if (filter.id === 'displayName') {
match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
if (!match && item.sublist && item.sublist.length > 0) {
let viewedSublistItems = Entaxy.applyFilters(item.sublist, [ filter ], matchesFilter);
item.viewedSublistItems = viewedSublistItems;
match = viewedSublistItems.length > 0;
}
}
return match;
}
}
function returnSublistsToOriginalState(items) {
items.forEach(item => {
if (item.sublist) {
item.viewedSublistItems = item.sublist;
}
});
}
}
EntaxyExpandableListController.$inject = ['$scope'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,163 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyExtendedData', {
template:
`
<div id="entaxy-extended-data" class="entaxy-extended-data" ng-if="$ctrl.messages">
<uib-accordion>
<div uib-accordion-group is-open="$ctrl.isOpen">
<div uib-accordion-heading>
<div class="entaxy-extended-data-short-message {{message.type}}" ng-repeat="message in $ctrl.messages">
{{message.short}}
</div>
</div>
<div class="entaxy-extended-data-messages-container">
<uib-accordion>
<div uib-accordion-group class="entaxy-extended-data-message-container {{message.type}}"
ng-class="{'disabled': !message.extraInfo}"
is-open="message.open" is-disabled="!message.extraInfo"
ng-repeat="message in $ctrl.messages">
<div uib-accordion-heading>
<span class="pficon"
ng-class="{'pficon-edit': !message.type, 'pficon-warning-triangle-o': message.type}"></span>
<span class="entaxy-extended-data-message">{{message.full}}</span>
</div>
<div class="entaxy-extended-data-message-extra-info-container">
<pre>{{message.extraInfo}}</pre>
</div>
</div>
</uib-accordion>
</div>
</div>
</uib-accordion>
</div>
`,
controller: entaxyExtendedDataController
})
.name;
function entaxyExtendedDataController(workspace, $scope, $q, entaxyService, entaxyAttributesCacheService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function () {
readExtendedData();
$scope.$on('jmxTreeClicked', function () {
readExtendedData();
});
}
function readExtendedData() {
ctrl.messages = undefined;
let selectedMbeanName = workspace.getSelectedMBeanName();
let attributes;
if (selectedMbeanName) {
entaxyAttributesCacheService.setToUpdate(selectedMbeanName);
attributes = entaxyAttributesCacheService.getAttributes(selectedMbeanName);
}
if (attributes && attributes.RuntimeType && attributes.RuntimeType !== Entaxy.RUNTIME_TYPE.ROUTE_CONTAINER) {
let messages = [];
let promises = [];
if (attributes.BundleState) {
let status = attributes.BundleState;
if (status === 'Failure') {
promises.push(entaxyService.getBundleDiag(attributes.BundleId).then(result =>
messages.push(getStatusMessage(status, result))));
} else {
messages.push(getStatusMessage(status));
}
}
promises.push(entaxyService.readExtendedData(selectedMbeanName)
.then(result => {
let extendedData = JSON.parse(result);
if (extendedData.cluster) {
messages.push(getClusterMessage(extendedData.cluster));
}
if (extendedData.applications) {
messages.push(getApplicationsMessage(extendedData.applications.application));
}
}));
$q.all(promises).then(() => {
ctrl.messages = messages;
});
}
}
function getStatusMessage(status, extraInfo) {
return {
short: status.toLowerCase(),
full: 'Status: ' + status,
extraInfo: extraInfo,
type: status === 'Failure' ? 'error' : undefined
};
}
function getClusterMessage(cluster) {
let message = {
short: cluster.objectClusterState,
full: 'Cluster: ',
type: cluster.objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED ? 'warning' : undefined
};
if (cluster.groups && cluster.groups.length > 0) {
message.full += cluster.groups.join(', ');
} else {
message.full += message.short;
}
return message;
}
function getApplicationsMessage(applications) {
let message = {
short: 'managed',
full: 'Object is installed as a part of the '
};
message.full += applications.length > 1 ? 'applications: ' : 'application: ';
let lastApplicationIndex = applications.length - 1;
for (let i = 0; i < lastApplicationIndex; i++) {
message.full += getApplicationFullName(applications[i]) + ', ';
}
message.full += getApplicationFullName(applications[lastApplicationIndex]);
return message;
}
function getApplicationFullName(application) {
return application.name + ':' + application.version + '/' + application.revision;
}
}
entaxyExtendedDataController.$inject = ['workspace', '$scope', '$q', 'entaxyService', 'entaxyAttributesCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -29,20 +29,21 @@ var Entaxy;
.component('entaxyFilePanel', {
bindings: {
items: '=',
selectedItem: '<',
selectedItems: '<',
view: '<',
changeSelectionFn: '<',
openFn: '<',
resourceContextMenuOptions: '<',
admResourceContextMenuOptions: '<',
folderContextMenuOptions: '<'
},
template:
`
<div class="file-panel no-selection" ng-class="{'tile-theme': $ctrl.view === 'tiles', 'list-theme': $ctrl.view === 'list'}">
<div ng-class="{'tile': $ctrl.view === 'tiles', 'list': $ctrl.view === 'list', 'active': $ctrl.selectedItem === item}"
ng-repeat="item in $ctrl.items" ng-click="$ctrl.changeSelection(item)" ng-dblclick="$ctrl.open(item)"
context-menu item="item"
context-menu-options="item.isFolder ? $ctrl.folderContextMenuOptions : $ctrl.resourceContextMenuOptions">
<div ng-class="{'tile': $ctrl.view === 'tiles', 'list': $ctrl.view === 'list', 'active': $ctrl.isActive(item)}"
ng-repeat="item in $ctrl.items" ng-click="$ctrl.changeSelection($event, item)" ng-dblclick="$ctrl.open(item)"
context-menu="$ctrl.considerChangingSelection(item)" item="item"
context-menu-options="$ctrl.getContextMenuOptions(item)">
<div class="icon">
<span ng-class="{'fa fa-folder': item.isFolder, 'fa fa-file': !item.isFolder}"></span>
</div>
@ -50,7 +51,7 @@ var Entaxy;
<span class="pficon pficon-info" data-toggle="tooltip" title="{{item.error}}"></span>
</div>
<div class="name" ng-class="{'has-error': item.error}" data-toggle="tooltip" title="{{item.name}}">
{{ $ctrl.view === 'tiles' ? (item.name | limitTo: 22) : item.name }}{{ ($ctrl.view === 'tiles' && item.name.length > 22) ? '...' : '' }}
{{ $ctrl.view === 'tiles' ? (item.name | limitTo: 16) : item.name }}{{ ($ctrl.view === 'tiles' && item.name.length > 16) ? '...' : '' }}
</div>
</div>
<div class="tile empty" ng-if="$ctrl.view === 'tiles'" ng-repeat="item in $ctrl.emptyItems"></div>
@ -67,12 +68,33 @@ var Entaxy;
ctrl.emptyItems = [{},{},{},{},{},{},{},{}];
}
ctrl.changeSelection = function (item) {
ctrl.changeSelectionFn(item);
ctrl.isActive = function (item) {
return ctrl.selectedItems && ctrl.selectedItems.includes(item);
}
ctrl.considerChangingSelection = function (item) {
if (!ctrl.selectedItems.includes(item)) {
ctrl.changeSelectionFn(item);
}
}
ctrl.changeSelection = function (clickEvent, item) {
ctrl.changeSelectionFn(item, clickEvent.ctrlKey);
}
ctrl.open = function (item) {
ctrl.openFn(item);
}
ctrl.getContextMenuOptions = function (item) {
return item.isFolder ?
ctrl.folderContextMenuOptions :
isAdm(item) ? ctrl.admResourceContextMenuOptions : ctrl.resourceContextMenuOptions;
}
function isAdm(item) {
let splitName = item.name.split('.');
return splitName.length > 1 && splitName.pop() === 'adm';
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,61 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyFormFieldExtraInfo', {
bindings: {
type: '<',
message: '<'
},
template:
`
<div class="entaxy-field-extra-info-container {{$ctrl.type}}">
<span class="{{$ctrl.iconClass}}"></span>
<span class="entaxy-field-extra-info-message">{{$ctrl.message}}</span>
</div>
`,
controller: entaxyFormFieldExtraInfoController
})
.name;
function entaxyFormFieldExtraInfoController() {
let ctrl = this;
ctrl.$onInit = function () {
ctrl.iconClass = getIconClassByType();
}
function getIconClassByType() {
switch (ctrl.type) {
case Entaxy.NOTIFICATION_TYPE.INFO:
default:
return 'pficon pficon-info';
}
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,229 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyFormFields', {
bindings: {
items: '<',
setFocusOn: '<',
errors: '<',
mode: '<',
formController: '<',
updateFieldsAfterSelectionChangeFn: '<'
},
template:
`
<div class="form-group"
ng-class="{'has-error': ($ctrl.errors[formField.name] || formField.error) && formField.type !== 'list'}"
ng-repeat="formField in $ctrl.items" ng-if="!formField.isBackRef && !formField.isHidden">
<entaxy-form-field-extra-info class="col-sm-12"
type="formField.ui.fieldExtraInfo.type" message="formField.ui.fieldExtraInfo.message"
ng-if="formField.ui && formField.ui.fieldExtraInfo && formField.ui.fieldExtraInfo.displayOnMode === $ctrl.mode">
</entaxy-form-field-extra-info>
<div class="col-sm-4 label-col" ng-if="!formField.excludeLabel">
<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-html="formField.description" ng-if="formField.description">
<span class="pficon pficon-help"></span>
</button>
</div>
<div ng-class="{'col-sm-7': !formField.excludeLabel, 'col-sm-12': formField.excludeLabel}">
<input type="{{formField.type}}" id="{{formField.name}}" placeholder="{{formField.placeholder}}"
ng-class="{'form-control': formField.type !== 'checkbox'}" ng-model="formField.value"
ng-readonly="formField.readOnly" ng-disabled="formField.type === 'checkbox' && formField.readOnly"
ng-if="$ctrl.isSimpleInput(formField)" ng-keydown="$ctrl.handleEnter($event)"
set-focused="$ctrl.setFocusOn === formField.name">
<textarea id="{{formField.name}}" class="form-control" ng-model="formField.value"
ng-readonly="formField.readOnly" ng-if="$ctrl.isTextarea(formField)"
set-focused="$ctrl.setFocusOn === formField.name"></textarea>
<entaxy-password-input id="{{formField.name}}" name="formField.name" model="formField.value"
confirmation-model="formField.confirmationValue" readonly="formField.readOnly"
ignore-confirmation-value="formField.ignoreConfirmationValue" errors="$ctrl.errors"
ng-if="$ctrl.isPassword(formField)"
set-focused="$ctrl.setFocusOn === formField.name"></entaxy-password-input>
<entaxy-url-input id="{{formField.name}}" model="formField.value" config="formField.typeInfo"
readonly="formField.readOnly" ng-if="$ctrl.isUrl(formField)" form-controller="$ctrl.formController"
set-focused="$ctrl.setFocusOn === formField.name"></entaxy-url-input>
<entaxy-select type="formField.type" id="{{formField.name}}" filter="formField.filter"
model="formField.value" options="formField.options" readonly="formField.readOnly"
update-parent-fn="$ctrl.updateFieldsAfterSelectionChangeFn"
update-parent="formField.typeInfo ? formField.typeInfo.updateParentFields : false"
creation-enabled="formField.typeInfo && formField.typeInfo.enablePrivateObjectCreation"
is-empty-included="formField.typeInfo ? formField.typeInfo.isEmptyIncluded : false"
ng-if="$ctrl.isEntaxySelect(formField)" form-controller="$ctrl.formController"></entaxy-select>
<entaxy-select-from-enum id="{{formField.name}}" values="formField.typeInfo.values"
model="formField.value" readonly="formField.readOnly" multiple="formField.typeInfo.multiple"
is-empty-included="formField.typeInfo.isEmptyIncluded"
empty-option-name="formField.typeInfo.emptyOptionName" ng-if="$ctrl.isSelectFromEnum(formField)"
set-focused="$ctrl.setFocusOn === formField.name"></entaxy-select-from-enum>
<entaxy-xml id="{{formField.name}}" ng-model="formField.value" mode="$ctrl.localMode"
ng-if="$ctrl.isXml(formField)" readonly="formField.readOnly"
form-controller="$ctrl.formController" set-focused="$ctrl.setFocusOn === formField.name"></entaxy-xml>
<entaxy-list-input id="{{formField.name}}" items="formField.value" ng-if="$ctrl.isList(formField)"
creation-enabled="formField.typeInfo && formField.typeInfo.enablePrivateObjectCreation"
creation-types="formField.typeInfo ? formField.typeInfo.privateObjectTypes : undefined"
item-factory-filter="formField.itemFactoryFilter" mode="$ctrl.mode"
readonly="formField.readOnly" validation="formField.validation"
item-title-template="formField.typeInfo ? formField.typeInfo.itemTitle : undefined"
errors="$ctrl.errors[formField.name]" form-controller="$ctrl.formController"></entaxy-list-input>
<entaxy-resource-input id="{{formField.name}}" name="{{formField.name}}" model="formField.value"
ng-if="$ctrl.isResourceInput(formField)"></entaxy-resource-input>
<entaxy-inner-object-input id="{{formField.name}}" readonly="formField.readOnly"
model="formField.value" mode="$ctrl.mode" type="formField.type" form-controller="$ctrl.formController"
object-factory-filter="formField.objectFactoryFilter" field-name="formField.label"
ng-if="$ctrl.isInnerObjectInput(formField)"
set-focused="$ctrl.setFocusOn === formField.name"></entaxy-inner-object-input>
<entaxy-map-input id="{{formField.name}}" model="formField.value" items="formField.mapItems"
duplicate-keys="formField.duplicateKeys" has-errors="formField.hasErrors" readonly="formField.readOnly"
ng-if="$ctrl.isMapInput(formField)" form-controller="$ctrl.formController"
set-focused="$ctrl.setFocusOn === formField.name"></entaxy-map-input>
<span class="help-block" ng-show="$ctrl.errors[formField.name] && formField.type !== 'list'">
{{$ctrl.errors[formField.name]}}
</span>
<span class="help-block"
ng-show="formField.error && !$ctrl.errors[formField.name] && formField.type !== 'list'">
{{formField.error}}
</span>
</div>
<div class="extra-actions" ng-class="{'col-sm-1': !formField.excludeLabel}"
ng-if="$ctrl.shouldShowReset(formField)">
<span class="pficon pficon-history reset-button" data-toggle="tooltip" title="Reset"
ng-click="$ctrl.reset(formField)"></span>
</div>
</div>
`,
controller: entaxyFormFieldsController
})
.name;
function entaxyFormFieldsController(entaxyService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
ctrl.localMode = ctrl.mode === Entaxy.MODAL_MODES.ADD ? Entaxy.MODAL_MODES.EDIT : ctrl.mode;
}
const TYPES = {
PASSWORD: 'password',
ENUM: 'enum',
LIST: 'list',
URL: 'url',
XML_ROUTE: 'xml:route',
RESOURCE: 'resource',
MAP: 'map'
};
ctrl.isSimpleInput = function (formField) {
return !isRuntimeTyped(formField.type)
&& formField.type !== TYPES.PASSWORD
&& formField.type !== TYPES.LIST
&& formField.type !== TYPES.XML_ROUTE
&& formField.type !== TYPES.RESOURCE
&& formField.type !== TYPES.MAP
&& (!formField.typeInfo || (formField.typeInfo && formField.typeInfo.type === 'String'))
&& !formField.useTextarea;
}
ctrl.isTextarea = function (formField) {
return formField.type === 'text' && formField.useTextarea;
}
ctrl.isPassword = function (formField) {
return formField.type === TYPES.PASSWORD;
}
ctrl.isUrl = function (formField) {
return formField.type === TYPES.URL && formField.typeInfo;
}
ctrl.isEntaxySelect = function (formField) {
return isRuntimeTyped(formField.type) && !formField.innerObject;
}
ctrl.isInnerObjectInput = function (formField) {
return isRuntimeTyped(formField.type) && formField.innerObject;
}
ctrl.isSelectFromEnum = function (formField) {
return formField.typeInfo
&& (formField.typeInfo.type === TYPES.ENUM || formField.typeInfo.type === TYPES.LIST)
&& (formField.typeInfo.values || (!formField.typeInfo.values && formField.readOnly));
}
ctrl.isXml = function (formField) {
return formField.type === TYPES.XML_ROUTE;
}
ctrl.isList = function (formField) {
return formField.type === TYPES.LIST;
}
ctrl.isResourceInput = function (formField) {
return formField.type === TYPES.RESOURCE;
}
ctrl.isMapInput = function (formField) {
return formField.type === TYPES.MAP;
}
function isRuntimeTyped(formFieldType) {
return formFieldType.startsWith(Entaxy.RUNTIME_TYPE_PREFIX) ||
formFieldType.startsWith(Entaxy.RUNTIME_TYPE_SECURITY_PREFIX);
}
ctrl.handleEnter = function (event) {
if (event.keyCode == 13) {
event.preventDefault();
}
}
ctrl.shouldShowReset = function (formField) {
return ctrl.isXml(formField) && !formField.readOnly && formField.dependsOn;
}
ctrl.reset = function (formField) {
let title = 'Confirm Reset';
let message = 'Do you want to reset value of ' + formField.label + ' field to its default value?';
entaxyService.openConfirmationWindow(title, message).then(() => {
let definingFormFields = entaxyService.getDefiningFormFields([formField], ctrl.items);
entaxyService.computeDependentFormFieldValue(formField, definingFormFields);
setDirty();
});
}
function setDirty() {
if (ctrl.formController && !ctrl.formController.$dirty) {
ctrl.formController.$setDirty();
}
}
}
entaxyFormFieldsController.$inject = ['entaxyService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,107 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyHeader', {
template:
`
<div class="entaxy-header">
<header>
<h1 id="entaxy-header-title" ng-class="{'changed': $ctrl.isChanged}">{{$ctrl.title}}</h1>
<button type="button" class="btn btn-link label-description-popover"
popover-placement="{{$ctrl.popoverPlacement}}" popover-trigger="'outsideClick'"
popover-class="entaxy-header-popover" popover-is-open="$ctrl.isPopoverOpen"
uib-popover="{{$ctrl.objectName}}" ng-if="$ctrl.objectName">
<span class="pficon pficon-info"></span>
</button>
</header>
</div>
`,
controller: entaxyHeaderController
})
.name;
function entaxyHeaderController(workspace, $scope, entaxyPrivateObjectsCacheService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function () {
let selectedMbean = workspace.getSelectedMBean();
populateData(selectedMbean);
$scope.$on('jmxTreeClicked', function (event, selectedNode) {
populateData(selectedNode);
});
}
$scope.$watch('$ctrl.isPopoverOpen', function (newValue) {
if (newValue) {
let popoverElements = document.getElementsByClassName('entaxy-header-popover');
let popoverElement = popoverElements ? popoverElements[0] : null;
if (popoverElement) {
let infoSpan = document.getElementsByClassName('pficon-info')[0];
let offsetLeft = infoSpan.offsetLeft + 18;
let headerTitle = document.getElementById('entaxy-header-title');
let offsetRight = infoSpan.offsetLeft - headerTitle.offsetLeft + 12;
let header = document.getElementsByClassName('entaxy-header')[0];
let isPositioningLeft = (header.offsetWidth - offsetLeft) >= offsetRight;
ctrl.popoverPlacement = isPositioningLeft ? 'bottom-left' : 'bottom-right';
popoverElement.style.maxWidth = isPositioningLeft ?
'calc(100% - ' + offsetLeft + 'px)' : offsetRight + 'px';
}
}
});
function populateData(selectedNode) {
ctrl.title = selectedNode.title;
ctrl.objectName = selectedNode.objectName;
if (ctrl.objectName) {
ctrl.isChanged = entaxyPrivateObjectsCacheService.isChanged(ctrl.objectName);
} else {
ctrl.isChanged = false;
let parentNode = selectedNode.parent;
if (parentNode && parentNode.objectName &&
entaxyPrivateObjectsCacheService.hasAddedChildren(parentNode.objectName)) {
let addedChildrenInfo = entaxyPrivateObjectsCacheService.getAddedObjectsInfo(parentNode.objectName);
if (addedChildrenInfo.find(addedChildInfo =>
selectedNode.key === parentNode.key + '-' + addedChildInfo.ui.id)) {
ctrl.isChanged = true;
}
}
}
}
}
entaxyHeaderController.$inject = ['workspace', '$scope', 'entaxyPrivateObjectsCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,146 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyInnerObjectInput', {
bindings: {
model: '=',
mode: '<',
type: '<',
objectFactoryFilter: '<',
fieldName: '<',
readonly: '<',
setFocused: '<',
formController: '<'
},
template:
`
<div class="input-with-button">
<input type="text" ng-model="$ctrl.info" ng-class="{'form-control': true}"
ng-keydown="$ctrl.handleEnter($event)" tabindex="-1" readonly>
<span class="pficon pficon-delete" ng-click="$ctrl.clear()" ng-if="$ctrl.model"></span>
<button class="btn-std entaxy-view-resources-form" ng-click="$ctrl.openModal()"
ng-if="!$ctrl.readonly || $ctrl.model" set-focused="$ctrl.setFocused">
{{$ctrl.buttonTitle}}
</button>
</div>
`,
controller: entaxyInnerObjectInputController
})
.name;
function entaxyInnerObjectInputController(workspace, entaxyService, $uibModal) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function () {
if (ctrl.readonly) {
ctrl.mode = Entaxy.MODAL_MODES.VIEW;
}
if (ctrl.model) {
let factory = entaxyService.getFactoryByTitle(ctrl.model.factoryId);
ctrl.info = factory.displayName;
ctrl.buttonTitle = ctrl.mode === Entaxy.MODAL_MODES.VIEW ?
Entaxy.MODAL_MODES.VIEW : Entaxy.MODAL_MODES.EDIT;
} else {
ctrl.mode = Entaxy.MODAL_MODES.ADD;
ctrl.buttonTitle = Entaxy.MODAL_MODES.ADD;
}
}
ctrl.openModal = function() {
$uibModal.open({
component: 'entaxyInnerObjectInputModal',
resolve: {
type: () => ctrl.type,
mode: () => ctrl.mode,
model: () => ctrl.model,
fieldName: () => ctrl.fieldName,
objectFactoryFilter: () => ctrl.objectFactoryFilter,
outerFormController: () => ctrl.formController
},
backdrop: 'static',
size: 'xl',
windowTopClass: 'modal-top-margin-override'
})
.result.then(args => {
changeModelFromArgs(args);
});
}
function changeModelFromArgs(args) {
if (ctrl.model) {
if (ctrl.model.factoryId === args.factoryId.name) {
args.fields.forEach(field => {
if (field.changed) {
ctrl.model.properties[field.name] = field.value;
}
});
} else {
ctrl.model.factoryId = args.factoryId.name;
ctrl.model.properties = {};
args.fields.forEach(field => {
ctrl.model.properties[field.name] = field.value;
});
}
} else {
ctrl.model = {};
ctrl.model.factoryId = args.factoryId.name;
ctrl.model.scope = Entaxy.SCOPE.PRIVATE;
ctrl.model.type = ctrl.type;
ctrl.model.properties = {};
args.fields.forEach(field => {
ctrl.model.properties[field.name] = field.value;
});
ctrl.mode = Entaxy.MODAL_MODES.EDIT;
ctrl.buttonTitle = Entaxy.MODAL_MODES.EDIT;
}
ctrl.info = args.factoryId.displayName;
}
ctrl.handleEnter = function (event) {
if (event.keyCode == 13) {
event.preventDefault();
if (!ctrl.readonly || ctrl.model) {
ctrl.openModal();
}
}
}
ctrl.clear = function () {
ctrl.model = undefined;
ctrl.info = undefined;
ctrl.mode = Entaxy.MODAL_MODES.ADD;
ctrl.buttonTitle = Entaxy.MODAL_MODES.ADD;
}
}
entaxyInnerObjectInputController.$inject = ['workspace', 'entaxyService', '$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,204 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyInnerObjectInputModal', {
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-header">
<h2>{{$ctrl.subTitle}}</h2>
</div>
<div class="modal-body">
<form name="entaxyInnerObjectForm" class="form-horizontal">
<entaxy-form-fields items="$ctrl.viewedFormFields" errors="$ctrl.errors" mode="$ctrl.mode"
form-controller="entaxyInnerObjectForm"></entaxy-form-fields>
</form>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">{{$ctrl.buttonTitle}}</button>
</div>
</div>
`,
controller: entaxyInnerObjectInputModalController
})
.name;
function entaxyInnerObjectInputModalController($uibModal, $scope, workspace, entaxyService, entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.mode = ctrl.resolve.mode;
ctrl.model = ctrl.resolve.model;
let extraInfo = ctrl.resolve.fieldName ? ': ' + ctrl.resolve.fieldName : '';
ctrl.modalTitle = ctrl.mode + ' Inner Object' + extraInfo;
ctrl.subTitle = ctrl.model ?
ctrl.mode + ' properties of inner object' + extraInfo : 'Fill in fields' + extraInfo;
ctrl.buttonTitle = 'Ok';
populateFormFields();
}
function populateFormFields() {
let promise = ctrl.resolve.objectFactoryFilter ?
entaxyService.getFactoriesByFilterSearch(ctrl.resolve.objectFactoryFilter) :
entaxyService.getFactoriesByType(ctrl.resolve.type);
promise.then(factories => {
ctrl.factories = factories;
let factoryId = ctrl.model ? ctrl.model.factoryId : factories[0].name;
ctrl.populatedFactoriesFields = [factoryId];
ctrl.formFields = [{
label: 'Factory',
name: 'factoryId',
type: 'text',
description: factories
.sort(Entaxy.compareBy('displayName'))
.map(factory => factory.displayName + ' - ' + factory.description)
.join('<br/>'),
value: factoryId,
readOnly: ctrl.mode === Entaxy.MODAL_MODES.VIEW ? true : false,
required: ctrl.mode === Entaxy.MODAL_MODES.VIEW ? false : true,
group: 'general',
typeInfo: {
type: 'enum',
values: factories
.map(factory => { return { displayValue: factory.displayName, value: factory.name };})
.sort(Entaxy.compareBy('displayValue')),
isEmptyIncluded: false
}
}];
createFormFields(factoryId);
addWatcher();
});
}
function createFormFields(factoryId) {
let mbeanName = getFactoryById(factoryId).mbeanName;
entaxyService.getFields(mbeanName)
.then((response) => {
let objectId = ctrl.model ? ctrl.model.objectId : undefined;
let properties = ctrl.model ? ctrl.model.properties : undefined;
let configurableOnly = false;
_.forEach(JSON.parse(response), (field) => {
let formField = entaxyService
.makeFormField(field, objectId, properties, configurableOnly, ctrl.mode);
if (formField) {
formField.belongsToFactory = factoryId;
ctrl.formFields.push(formField);
}
});
filterFormFields(factoryId);
});
}
function getFactoryById(factoryId) {
return ctrl.factories.find(factory => factory.name === factoryId);
}
function addWatcher() {
$scope.$watch('$ctrl.formFields[0].value', function (newValue, oldValue) {
if (newValue !== oldValue) {
if (!ctrl.populatedFactoriesFields.includes(newValue)) {
createFormFields(newValue);
ctrl.populatedFactoriesFields.push(newValue);
} else {
filterFormFields(newValue);
}
}
});
}
function filterFormFields(factoryId) {
ctrl.viewedFormFields = ctrl.formFields
.filter(formField =>
formField.name === 'factoryId' || formField.belongsToFactory === factoryId);
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function () {
if (ctrl.mode === Entaxy.MODAL_MODES.VIEW) {
ctrl.cancel();
} else {
let selectedFactory = ctrl.viewedFormFields.find(formField => formField.name === 'factoryId');
entaxyService.validateFields(ctrl.viewedFormFields, selectedFactory)
.then(errors => {
ctrl.errors = errors;
if (Object.keys(ctrl.errors).length === 0) {
if (ctrl.resolve.outerFormController && !ctrl.resolve.outerFormController.$dirty &&
$scope.entaxyInnerObjectForm && $scope.entaxyInnerObjectForm.$dirty) {
ctrl.resolve.outerFormController.$setDirty();
}
let args = entaxyService.getArguments(ctrl.viewedFormFields, ctrl.factories);
ctrl.modalInstance.close(args);
}
});
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save();
}
}
];
}
}
entaxyInnerObjectInputModalController.$inject = ['$uibModal', '$scope', 'workspace', 'entaxyService', 'entaxyHotkeysService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,61 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyInputWithExtension', {
bindings: {
model: '=',
modelWithoutExtension: '=',
extension: '<',
readonly: '<',
setFocused: '<',
formController: '<'
},
template:
`
<div class="input-with-extension">
<input type="text" ng-model="$ctrl.modelWithoutExtension" class="form-control" ng-readonly="$ctrl.readonly"
set-focused="$ctrl.setFocused" />
<input type="text" ng-model="$ctrl.extension" class="form-control extension-input" tabindex="-1" readonly/>
</div>
`,
controller: entaxyInputWithExtensionController
})
.name;
function entaxyInputWithExtensionController(workspace, $scope) {
'ngInject';
let ctrl = this;
$scope.$watch('$ctrl.modelWithoutExtension', function () {
ctrl.model = ctrl.modelWithoutExtension + ctrl.extension;
})
}
entaxyInputWithExtensionController.$inject = ['workspace', '$scope'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,251 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyListInput', {
bindings: {
items: '=',
itemTitleTemplate: '<',
creationEnabled: '<',
creationTypes: '<',
itemFactoryFilter: '<',
readonly: '<',
validation: '<',
mode: '<',
errors: '<',
formController: '<'
},
template:
`
<div class="entaxy-empty-state" ng-if="$ctrl.showEmptyState">
<span>{{$ctrl.emptyStateMessage}}</span>
</div>
<div class="add-item-to-list-block" ng-click="$ctrl.showModal()"
ng-if="$ctrl.creationEnabled && !$ctrl.readonly">
<span class="pficon pficon-add-circle-o"></span>
<span>{{$ctrl.addItemTitle}}</span>
</div>
<div as-sortable="$ctrl.dragControlListeners" ng-model="$ctrl.items"
ng-if="$ctrl.items && $ctrl.items.length > 0">
<div ng-repeat="item in $ctrl.items"
ng-class="{'list-input-item-has-error': item.errors && !item.toDeletion}" as-sortable-item>
<div class="list-input-item" ng-class="{'disabled': item.toDeletion}">
<div class="list-input-item-heading" ng-click="$ctrl.open(item)">
<span class="fa fa-angle-right" ng-if="!item.open"></span>
<span class="fa fa-angle-down" ng-if="item.open"></span>
<label ng-class="{'new-item': item.new}">
{{$ctrl.getItemName(item.formFields)}}
</label>
</div>
<div class="list-input-item-controls" ng-if="!$ctrl.readonly">
<span class="pficon pficon-delete remove-icon"
ng-click="$ctrl.removeItem(item)" ng-if="!item.toDeletion"
data-toggle="tooltip" title="Remove"></span>
<span class="pficon pficon-history restore-icon"
ng-click="$ctrl.restoreItem(item)" ng-if="item.toDeletion"
data-toggle="tooltip" title="Restore"></span>
<span class="glyphicon glyphicon-move move-icon" as-sortable-item-handle
data-toggle="tooltip" title="Move" ng-if="!item.toDeletion"></span>
</div>
</div>
<div class="list-input-item-content" ng-show="item.open">
<entaxy-list-item-content form-fields="item.formFields" errors="item.errors" mode="$ctrl.mode">
</entaxy-list-item-content>
</div>
</div>
</div>
`,
controller: entaxyListInputController
})
.name;
function entaxyListInputController(workspace, $q, $uibModal, entaxyService) {
'ngInject';
let ctrl = this;
ctrl.dragControlListeners = {
itemMoved: function (event) {
event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column.name;
},
orderChanged: function (event) {
setDirty();
},
containment: '#board'
};
ctrl.$onInit = function() {
ctrl.itemTypes = ctrl.creationTypes.map(type => type.displayName);
ctrl.addItemTitle = 'Add ' + ctrl.itemTypes.join(' or ');
ctrl.showEmptyState = (ctrl.mode === Entaxy.MODAL_MODES.VIEW || !ctrl.creationEnabled || ctrl.readOnly)
&& !ctrl.items || (ctrl.items && ctrl.items.length == 0);
ctrl.emptyStateMessage = 'No Items Available';
}
ctrl.getItemName = function (formFields) {
let values = [];
ctrl.itemTitleTemplate.fields.forEach(fieldName => {
let formField = formFields.find(formField => formField.name === fieldName);
values.push(formField.value);
});
return values.join(ctrl.itemTitleTemplate.delimiter);
}
function setDirty() {
if (ctrl.formController && !ctrl.formController.$dirty) {
ctrl.formController.$setDirty();
}
}
ctrl.$onChanges = function (changes) {
if (changes.errors) {
if (ctrl.items && !changes.errors.currentValue
&& (!changes.errors.previousValue || Object.keys(changes.errors.previousValue).length === 0)) {
ctrl.items.forEach(item => item.errors = undefined);
}
if (changes.errors.currentValue) {
let errors = changes.errors.currentValue;
if (typeof errors !== 'string') {
let errorKeys = Object.keys(errors);
errorKeys.forEach(errorKey => {
ctrl.items.filter(item => !item.toDeletion).forEach(item => {
let formField = item.formFields.find(formField => formField.name === errorKey);
if (formField) {
if (errors[errorKey].values) {
if (errors[errorKey].values.includes(formField.value)) {
setError(item, formField.name, errors[errorKey].message);
}
} else {
setError(item, formField.name, errors[errorKey].message);
}
}
});
});
}
}
}
}
function setError(item, formFieldName, message) {
if (!item.errors) {
item.errors = {};
}
item.errors[formFieldName] = message;
}
ctrl.open = function (item) {
if (!item.toDeletion) {
item.open = !item.open;
}
}
ctrl.removeItem = function (item) {
item.toDeletion = true;
item.open = false;
setDirty();
}
ctrl.restoreItem = function (item) {
item.toDeletion = false;
}
ctrl.showModal = function () {
let allFactories = [];
let promises = [];
if (ctrl.itemFactoryFilter) {
promises.push(
entaxyService.getFactoriesByFilterSearch(ctrl.itemFactoryFilter)
.then(factories => allFactories = factories));
} else {
ctrl.creationTypes.forEach(type => {
promises.push(
entaxyService.getFactoriesByType(type.name)
.then(factories => allFactories = allFactories.concat(factories)));
});
}
if (promises.length > 0) {
let checkUniqueness = ctrl.validation && ctrl.validation.rules ?
ctrl.validation.rules.checkChildrenUniqueness : undefined;
let checkUniquenessFields = {};
if (checkUniqueness) {
checkUniqueness.fields.forEach(field => {
checkUniquenessFields[field] = [];
if (ctrl.items) {
ctrl.items.forEach(item => {
let formField = item.formFields.find(formField => formField.name === field);
checkUniquenessFields[field].push(formField.value);
});
}
});
}
$uibModal.open({
component: 'entaxyModal',
resolve: {
mode: () => Entaxy.MODAL_MODES.ADD,
itemType: () => ctrl.itemTypes.join(' or '),
factories: $q.all(promises).then(() => allFactories),
returnFormFields: () => true,
checkUniquenessParentFields: () => checkUniquenessFields
},
size: 'xl',
backdrop: 'static',
windowTopClass: 'modal-top-margin-override'
})
.result.then(formFields => {
addItem(formFields);
},
reason => {
if (reason) {
Entaxy.notificationError(reason);
}
});
}
}
function addItem(formFields) {
if (!ctrl.items) {
ctrl.items = [];
}
ctrl.items.push({
new: true,
formFields: formFields
});
setDirty();
}
}
entaxyListInputController.$inject = ['workspace', '$q', '$uibModal', 'entaxyService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,81 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyListItemContent', {
bindings: {
formFields: '<',
mode: '<',
errors: '<'
},
template:
`
<uib-tabset active="$ctrl.selectedGroupIndex">
<uib-tab ng-repeat="group in $ctrl.groups track by $index"
heading="{{group.displayName}}" select="$ctrl.change()">
<entaxy-form-fields items="group.formFields" errors="$ctrl.errors" mode="$ctrl.mode">
</entaxy-form-fields>
</uib-tab>
</uib-tabset>
`,
controller: EntaxyListItemContentController
})
.name;
function EntaxyListItemContentController() {
let ctrl = this;
ctrl.$onInit = function() {
let groups = new Set();
groups.add('general');
ctrl.formFields.forEach(formField => {
if (!formField.isBackRef && !formField.isHidden) {
groups.add(formField.group);
}
});
ctrl.groups = Array.from(groups).map((group) => {
return {
name: group,
displayName: group,
formFields: ctrl.formFields.filter(formField => formField.group === group)
};
});
if (ctrl.errors) {
let errorFields = Object.keys(ctrl.errors);
for (let i = 0; i < ctrl.groups.length; i++) {
if (ctrl.groups[i].formFields.find(formField => errorFields.includes(formField.name))) {
ctrl.selectedGroupIndex = i;
break;
}
}
}
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,207 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyMapInput', {
bindings: {
model: '=',
items: '=',
duplicateKeys: '=',
hasErrors: '=',
readonly: '<',
setFocused: '<',
formController: '<'
},
template:
`
<div class="entaxy-map-input-table" ng-if="$ctrl.items && $ctrl.items.length > 0">
<table>
<tbody>
<tr role="row" ng-repeat="field in $ctrl.items">
<td class="input-cell">
<input type="text" class="form-control" ng-model="field.key" ng-change="$ctrl.changeKey(field)"
ng-class="{'has-error': field.hasError}" ng-readonly="$ctrl.readonly || field.removed"/>
</td>
<td class="input-cell">
<input type="text" class="form-control" ng-model="field.value" ng-change="$ctrl.changeValue(field)"
ng-readonly="$ctrl.readonly || field.removed"/>
</td>
<td ng-if="!$ctrl.readonly">
<button type="button" class="btn-std btn-std-ignore-error" ng-click="$ctrl.remove(field)"
data-toggle="tooltip" title="Remove" ng-if="!field.removed">
<span class="pficon pficon-delete"></span>
</button>
<button type="button" class="btn-std btn-std-ignore-error" ng-click="$ctrl.restore(field)"
data-toggle="tooltip" title="Restore" ng-if="field.removed">
<span class="pficon pficon-history"></span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<input type="text" class="form-control" ng-model="$ctrl.emptyValueInfo" ng-if="$ctrl.emptyValueInfo" readonly/>
<button type="button" class="btn-std entaxy-map-input-add-button"
ng-class="{'btn-std-ignore-error': $ctrl.items && $ctrl.items.length > 0}"
ng-if="!$ctrl.readonly" ng-click="$ctrl.add()" set-focused="$ctrl.setFocused">
<span class="pficon pficon-add-circle-o"></span>
<span>{{$ctrl.addItemTitle}}</span>
</button>
`,
controller: entaxyMapInputController
})
.name;
function entaxyMapInputController() {
let ctrl = this;
ctrl.$onInit = function () {
ctrl.addItemTitle = 'Add Property';
if (!ctrl.items) {
if (ctrl.model) {
ctrl.items = Object.entries(ctrl.model).map(([key, value]) => {
return {
key: key,
value: value
};
}).sort(Entaxy.compareBy('key'));
} else {
ctrl.items = [];
}
}
if (ctrl.items.length === 0 && ctrl.readonly) {
ctrl.emptyValueInfo = '--Map is empty--';
}
if (!ctrl.duplicateKeys) {
ctrl.duplicateKeys = new Set();
}
}
ctrl.changeKey = function (field) {
validateKey(field);
updateDuplicatesStatus();
updateErrorsState();
updateModel();
}
ctrl.changeValue = function (field) {
updateModel();
}
function validateKey(field) {
if (field.key.trim().length === 0) {
field.hasError = true;
} else {
let duplicates = getItemsByKey(field.key);
if (duplicates.length > 1) {
ctrl.duplicateKeys.add(field.key);
duplicates.forEach(item => item.hasError = true);
} else {
field.hasError = false;
}
}
}
function updateDuplicatesStatus() {
let expiredDuplicateKeys = new Set();
ctrl.duplicateKeys.forEach(duplicateKey => {
let duplicates = getItemsByKey(duplicateKey);
if (duplicates.length <= 1) {
expiredDuplicateKeys.add(duplicateKey);
duplicates.forEach(item => item.hasError = false);
}
});
if (expiredDuplicateKeys.size === ctrl.duplicateKeys.size) {
ctrl.duplicateKeys.clear();
} else {
expiredDuplicateKeys.forEach(expiredDuplicateKey => ctrl.duplicateKeys.delete(expiredDuplicateKey));
}
}
function getItemsByKey(key) {
return ctrl.items.filter(item => !item.removed && item.key === key);
}
function updateErrorsState() {
ctrl.hasErrors = ctrl.items.filter(item => !item.removed && item.hasError).length === 0 ? false : true;
}
function updateModel() {
if (!ctrl.hasErrors) {
ctrl.model = ctrl.items.length > 0 ? {} : undefined;
ctrl.items.forEach(item => {
if (!item.removed && !item.hasError) {
ctrl.model[item.key] = item.value;
}
});
}
}
ctrl.add = function () {
ctrl.items.push({type: 'text', key: '', value: ''});
validateKey(ctrl.items[ctrl.items.length - 1]);
updateErrorsState();
ctrl.setDirty();
}
ctrl.remove = function (field) {
field.removed = true;
field.hasError = false;
updateDuplicatesStatus();
updateErrorsState();
updateModel();
ctrl.setDirty();
}
ctrl.restore = function (field) {
field.removed = false;
validateKey(field);
updateDuplicatesStatus();
updateErrorsState();
updateModel();
ctrl.setDirty();
}
ctrl.setDirty = function () {
if (ctrl.formController && !ctrl.formController.$dirty) {
ctrl.formController.$setDirty();
}
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,111 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyPasswordInput', {
bindings: {
name: '<',
model: '=',
confirmationModel: '=',
ignoreConfirmationValue: '=',
readonly: '<',
setFocused: '<',
errors: '='
},
template:
`
<div class="password-input">
<input type="{{$ctrl.type}}" class="form-control" ng-model="$ctrl.model" ng-readonly="$ctrl.readonly"
autocomplete="new-password" set-focused="$ctrl.setFocused">
<span ng-class="{'fa fa-eye': !$ctrl.isVisible(), 'fa fa-eye-slash': $ctrl.isVisible()}"
ng-click="$ctrl.view()"></span>
</div>
<input type="{{$ctrl.type}}" class="form-control confirmation-password-input"
ng-model="$ctrl.confirmationModel" ng-if="!$ctrl.readonly"
placeholder="confirm password here" ng-show="$ctrl.model && !$ctrl.ignoreConfirmationValue">
`,
controller: entaxyPasswordInputController
})
.name;
function entaxyPasswordInputController($scope) {
'ngInject';
let ctrl = this;
const TYPES = {
PASSWORD: 'password',
TEXT: 'text'
}
ctrl.$onInit = function() {
ctrl.type = TYPES.PASSWORD;
}
ctrl.view = function () {
ctrl.type = ctrl.isVisible() ? TYPES.PASSWORD : TYPES.TEXT;
}
ctrl.isVisible = function () {
return ctrl.type !== TYPES.PASSWORD;
}
$scope.$watch('$ctrl.model', function () {
if (ctrl.ignoreConfirmationValue && ctrl.valueAssigned) {
ctrl.ignoreConfirmationValue = false;
}
if (!ctrl.ignoreConfirmationValue) {
validate();
} else {
ctrl.valueAssigned = true;
}
})
$scope.$watch('$ctrl.confirmationModel', function () {
if (!ctrl.ignoreConfirmationValue) {
validate();
}
});
function validate() {
let message = Entaxy.ERROR_MESSAGE.PASSWORD_CONFIRMATION;
if (ctrl.errors) {
if (ctrl.model && ctrl.model !== ctrl.confirmationModel) {
ctrl.errors[ctrl.name] = message;
} else {
if (ctrl.errors[ctrl.name] === message) {
ctrl.errors[ctrl.name] = undefined;
}
}
} else {
if (ctrl.confirmationModel !== ctrl.model) {
ctrl.errors = {[ctrl.name]: message};
}
}
}
}
entaxyPasswordInputController.$inject = ['$scope'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,72 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyResourceInput', {
bindings: {
name: '@',
model: '=',
formController: '<'
},
template:
`
<div class="entaxy-resource-input" entaxy-file-drop ng-model="$ctrl.file" ng-click="$ctrl.triggerUpload()">
<span class="fa fa-upload"></span>
<span ng-if="!$ctrl.file">Drop file to upload</span>
<span ng-if="$ctrl.file">
File {{($ctrl.file.name | limitTo: 15) + ($ctrl.file.name.length > 15 ? '...' : '')}} is ready to upload
</span>
<input type="file" id="{{$ctrl.name}}-file-input" set-file-model ng-model="$ctrl.file">
</div>
`,
controller: entaxyResourceInputController
})
.name;
function entaxyResourceInputController(workspace, $scope) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function () {
if (ctrl.model) {
ctrl.file = ctrl.model;
}
}
$scope.$watch('$ctrl.file', function () {
ctrl.model = ctrl.file;
});
ctrl.triggerUpload = function () {
document.getElementById(ctrl.name + '-file-input').click();
}
}
entaxyResourceInputController.$inject = ['workspace', '$scope'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,236 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxySelect', {
bindings: {
type: '<',
filter: '<',
model: '=',
readonly: '<',
updateParent: '<',
updateParentFn: '<',
options: '=',
creationEnabled: '<',
isEmptyIncluded: '<',
formController: '<'
},
template:
`
<div class="custom-select" ng-if="!$ctrl.readonly">
<button type="button" class="btn-select form-control dropdown-toggle" id="filter"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="selected-option">{{$ctrl.selectedOption.displayName}}</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li ng-repeat="option in $ctrl.options" id="option.name" ng-click="$ctrl.changeSelection(option)">
{{ option.displayName }}
</li>
<li id="addItem" class="dropdown-option-new" ng-click="$ctrl.showModal()" ng-if="$ctrl.creationEnabled">
<span class="pficon pficon-add-circle-o"></span>
{{$ctrl.createObjectOptionTitle}}
</li>
</ul>
</div>
<input type="text" class="form-control" ng-model="$ctrl.selectedOption.displayName"
ng-if="$ctrl.readonly" readonly>
`,
controller: entaxySelectController
})
.name;
function entaxySelectController(workspace, jolokiaService, jolokia, $q, $uibModal, entaxyService) {
'ngInject';
let ctrl = this;
let emptyValue;
ctrl.$onInit = function() {
if (!ctrl.readonly) {
ctrl.itemType = Entaxy.getItemTypeFromRuntimeType(ctrl.type);
if (ctrl.creationEnabled) {
ctrl.createObjectOptionTitle = 'New private ' + ctrl.itemType + '...';
}
populateOptions();
} else {
let domain = entaxyService.getDomainFolder();
entaxyService.getAllChildMBeansByRuntimeType(domain, ctrl.type).then((mbeans) => {
let mbean = mbeans.find(mbean => mbean.attributes.Name === ctrl.model);
ctrl.selectedOption = mbean ? createOptionFromMbean(mbean) : { displayName: ctrl.model };
});
}
}
function populateOptions() {
if (!ctrl.options) {
let emptyOptionName = '--No ' + ctrl.itemType + ' selected--';
emptyValue = {name: emptyOptionName, displayName: emptyOptionName};
let domain = entaxyService.getDomainFolder();
if (ctrl.filter) {
entaxyService.findObjectsByFilter(ctrl.filter).then(result => {
let objectFullIds = JSON.parse(result);
entaxyService.getMBeansByObjectFullIds(objectFullIds).then((mbeans) => {
populateOptionsFromMbeans(mbeans
.filter(mbean => mbean.attributes.RuntimeType === ctrl.type));
});
}).catch(error => {
Entaxy.notificationError(error);
Entaxy.log.error(error);
});
} else {
entaxyService.getAllChildMBeansByRuntimeType(domain, ctrl.type).then((mbeans) => {
populateOptionsFromMbeans(mbeans);
});
}
} else {
if (ctrl.isEmptyIncluded) {
emptyValue = ctrl.options[0];
}
ctrl.selectedOption = getOptionByModel();
}
}
function populateOptionsFromMbeans(mbeans) {
let items = mbeans.map(mbean => createOptionFromMbean(mbean));
if (items && items.length > 0) {
ctrl.options = items.sort(Entaxy.compareBy('displayName'));
if (ctrl.isEmptyIncluded) {
ctrl.options.unshift(emptyValue);
}
ctrl.changeSelection(ctrl.model ? getOptionByModel() : items[0]);
} else {
ctrl.options = [];
let notificationType = ctrl.creationEnabled ?
Entaxy.NOTIFICATION_TYPE.WARNING : Entaxy.NOTIFICATION_TYPE.DANGER;
Core.notification(notificationType, 'There is no suitable ' + ctrl.itemType.toLowerCase(),
Entaxy.configuration[Entaxy.CONFIGURATION_KEYS.NOTIFICATION_TIMEOUT_ERROR]);
// todo close the modal if creation is disabled
}
}
function createOptionFromMbean(mbean) {
let displayName = mbean.attributes.DisplayName;
let name = mbean.attributes.Name;
return {
name: name,
displayName: createDisplayName(displayName, name),
mbeanName: mbean.mbean.objectName
};
}
function createDisplayName(displayName, name) {
return displayName && displayName !== name ? displayName + ' [' + name + ']' : name;
}
function getOptionByModel() {
return ctrl.options.find((option) => option.name === ctrl.model || option.value === ctrl.model);
}
ctrl.changeSelection = function (option) {
if (ctrl.selectedOption !== option) {
let previousOption = ctrl.selectedOption;
ctrl.selectedOption = option;
ctrl.model = option.name === emptyValue.name ? undefined : (option.value ? option.value : option.name);
if (previousOption && ctrl.formController && !ctrl.formController.$dirty) {
ctrl.formController.$setDirty();
}
if (ctrl.updateParent) {
if (previousOption) {
Entaxy.changingFieldValueNotification(ctrl.itemType);
}
ctrl.updateParentFn(previousOption, option);
}
}
}
ctrl.showModal = function() {
$uibModal.open({
component: 'entaxyModal',
resolve: {
mode: () => Entaxy.MODAL_MODES.ADD,
itemType: () => Entaxy.capitalize(ctrl.itemType),
factories: entaxyService.getFactoriesByType(ctrl.type, ctrl.filter).then(factories => factories)
},
size: 'xl',
backdrop: 'static',
windowTopClass: 'modal-top-margin-override'
})
.result.then(args => {
addItem(args);
},
reason => {
if (reason) {
Entaxy.notificationError(reason);
}
});
}
function addItem(args) {
let factoryId = args.factoryId.name;
let objectId = args.fields.find((field) => field.name === 'objectId').value;
let fields = objectId ? args.fields.filter((field) => field.name !== 'objectId') : args.fields;
let properties = fields.reduce((obj, cur) => ({ ...obj, [cur.name] : cur.value }), {});
let newObjectProperties = {
factoryId: factoryId,
objectId: objectId,
scope: 'private',
properties: properties
};
let newObjectOption = {
name: objectId ? objectId : ('private-' + ctrl.itemType),
value: newObjectProperties
};
ctrl.options.push(newObjectOption);
ctrl.changeSelection(newObjectOption);
}
}
entaxySelectController.$inject = ['workspace', 'jolokiaService', 'jolokia', '$q', '$uibModal', 'entaxyService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,119 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxySelectFromEnum', {
bindings: {
values: '<',
isEmptyIncluded: '<',
emptyOptionName: '<',
model: '=',
readonly: '<',
setFocused: '<',
multiple: '<',
sortNeeded: '<'
},
template:
`
<select class="form-control" ng-options="option.displayName for option in $ctrl.options"
ng-model="$ctrl.selectedOption" ng-change="$ctrl.changeSelection()" ng-disabled="$ctrl.readonly"
set-focused="$ctrl.setFocused" />
`,
controller: entaxySelectFromEnumController
})
.name;
function entaxySelectFromEnumController($scope) {
'ngInject';
let ctrl = this;
let emptyValue = { name: '--Empty value--' };
ctrl.$onInit = function() {
emptyValue.displayName = ctrl.emptyOptionName ? ctrl.emptyOptionName : emptyValue.name;
populateOptions();
if (ctrl.options.length == 1 || (!ctrl.isEmptyIncluded && !ctrl.model)) {
ctrl.selectedOption = ctrl.options[0];
ctrl.changeSelection();
}
}
function populateOptions() {
let options = (ctrl.values && ctrl.values.length > 0) ?
ctrl.values.map(value => {
return angular.isObject(value) ?
{ displayName: value.displayValue ? value.displayValue : value.value, name: value.value } :
{ displayName: value, name: value }
}) : [];
ctrl.options = options.length > 1 && ctrl.sortNeeded ?
options.sort(Entaxy.compareBy('displayName')) : options;
if (ctrl.isEmptyIncluded !== false) {
ctrl.options.unshift(emptyValue);
}
}
$scope.$watchCollection('$ctrl.values', function(newValue, oldValue) {
if (newValue !== oldValue) {
populateOptions();
let currentSelectedOption = ctrl.options.find((option) => option.name === ctrl.selectedOption.name);
ctrl.selectedOption = currentSelectedOption ? currentSelectedOption : ctrl.options[0];
ctrl.changeSelection();
}
});
$scope.$watch('$ctrl.model', function() {
if (ctrl.multiple) {
if (ctrl.model && ctrl.model.length > 0) {
if (!ctrl.selectedOption || ctrl.selectedOption.name !== ctrl.model[0]) {
ctrl.selectedOption = ctrl.options.find((option) => option.name === ctrl.model[0]);
}
} else {
if (!ctrl.selectedOption || ctrl.selectedOption.name !== ctrl.options[0].name) {
ctrl.selectedOption = ctrl.options[0];
}
}
} else {
ctrl.selectedOption = ctrl.model ?
ctrl.options.find((option) => option.name === ctrl.model) : ctrl.options[0];
}
});
ctrl.changeSelection = function () {
if (ctrl.selectedOption.name === emptyValue.name) {
ctrl.model = ctrl.multiple ? [] : undefined;
} else {
ctrl.model = ctrl.multiple ? [ctrl.selectedOption.name] : ctrl.selectedOption.name;
}
}
}
entaxySelectFromEnumController.$inject = ['$scope'];
})(Entaxy || (Entaxy = {}));

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~~~~~~
*/
var Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyUrlInput', {
bindings: {
model: '=',
config: '<',
readonly: '<',
setFocused: '<',
formController: '<'
},
template:
`
<div class="input-with-button">
<input type="text" ng-model="$ctrl.model" ng-class="{'form-control': true}"
ng-keydown="$ctrl.handleEnter($event)" tabindex="-1" readonly>
<span class="pficon pficon-delete" ng-click="$ctrl.clear()" ng-if="$ctrl.model"></span>
<button class="btn-std entaxy-view-resources-form" ng-click="$ctrl.openViewer()" ng-if="!$ctrl.readonly"
set-focused="$ctrl.setFocused">
Select...
</button>
</div>
`,
controller: entaxyUrlInputController
})
.name;
function entaxyUrlInputController(workspace, $uibModal) {
'ngInject';
let ctrl = this;
ctrl.openViewer = function() {
$uibModal.open({
component: 'entaxyResourceViewerModal',
resolve: {
location: () => ctrl.model,
config: () => ctrl.config
},
size: 'xl',
backdrop: 'static',
windowTopClass: 'modal-top-margin-override'
})
.result.then(location => {
if (ctrl.model !== location && ctrl.formController && !ctrl.formController.$dirty) {
ctrl.formController.$setDirty();
}
ctrl.model = location;
});
}
ctrl.handleEnter = function (event) {
if (event.keyCode == 13) {
event.preventDefault();
if (!ctrl.readonly) {
ctrl.openViewer();
}
}
}
ctrl.clear = function () {
ctrl.model = undefined;
}
}
entaxyUrlInputController.$inject = ['workspace', '$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,81 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyXml', {
bindings: {
ngModel: '=',
mode: '<',
readonly: '<',
setFocused: '<',
formController: '<'
},
template:
`
<button class="btn-std entaxy-xml-form" ng-click="$ctrl.openEditor()" ng-disabled="$ctrl.disabled"
set-focused="$ctrl.setFocused">
{{$ctrl.buttonTitle}}
</button>
`,
controller: entaxyXmlController
})
.name;
function entaxyXmlController(workspace, $scope, $uibModal) {
'ngInject';
let ctrl = this;
$scope.$watch('$ctrl.readonly', function () {
ctrl.buttonTitle = ctrl.readonly ? Entaxy.MODAL_MODES.VIEW : ctrl.mode;
ctrl.disabled = ctrl.readonly &&
(ctrl.ngModel === undefined || (angular.isString(ctrl.ngModel) && ctrl.ngModel.trim().length === 0));
});
ctrl.openEditor = function() {
$uibModal.open({
component: 'entaxyXmlModal',
resolve: {
xml: () => ctrl.ngModel,
mode: () => ctrl.readonly ? Entaxy.MODAL_MODES.VIEW : ctrl.mode
},
size: 'xl',
backdrop: 'static',
windowTopClass: 'modal-top-margin-override'
})
.result.then(xml => {
if (ctrl.ngModel !== xml && ctrl.formController && !ctrl.formController.$dirty) {
ctrl.formController.$setDirty();
}
ctrl.ngModel = xml;
});
}
}
entaxyXmlController.$inject = ['workspace', '$scope', '$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -47,7 +47,7 @@ var Entaxy;
<form name="entaxyObjectForm" class="form-horizontal">
<entaxy-form-fields items="$ctrl.viewedFormFields" errors="$ctrl.errors" mode="$ctrl.mode"
update-fields-after-selection-change-fn="$ctrl.updateFieldsAfterSelectionChange"
form-controller="entaxyObjectForm"></entaxy-form-fields>
form-controller="entaxyObjectForm" set-focus-on="$ctrl.setFocusOn"></entaxy-form-fields>
</form>
</div>
</div>
@ -105,6 +105,11 @@ var Entaxy;
ctrl.change = function(group) {
ctrl.viewedFormFields = ctrl.fields.filter((formField) => formField.group === group.name);
ctrl.selectedGroup = group;
let setFocusOn = ctrl.viewedFormFields
.find(formField => !formField.isBackRef && !formField.isHidden && !formField.readOnly);
if (setFocusOn) {
ctrl.setFocusOn = setFocusOn.name;
}
}
ctrl.matchesFilter = function(group, filter) {
@ -134,11 +139,15 @@ var Entaxy;
if (ctrl.fields && ctrl.fields.length > 1) {
ctrl.fields.forEach(formField => {
if (formField.ui && formField.ui.displayBlocks) {
let managedBy = formField.ui.displayBlocksManagedBy;
if (!displayBlocks[managedBy]) {
displayBlocks[managedBy] = {};
}
formField.ui.displayBlocks.forEach(displayBlock => {
if (!displayBlocks[displayBlock]) {
displayBlocks[displayBlock] = [formField];
if (!displayBlocks[managedBy][displayBlock]) {
displayBlocks[managedBy][displayBlock] = [formField];
} else {
displayBlocks[displayBlock].push(formField);
displayBlocks[managedBy][displayBlock].push(formField);
}
});
if (!formField.ui.originProperties) {
@ -154,37 +163,87 @@ var Entaxy;
function manageDisplayBlocks() {
if (Object.keys(displayBlocks).length > 0) {
ctrl.managingFields = ctrl.fields.filter(formField =>
formField.ui && formField.ui.manageDisplayBlocksByValue);
ctrl.managingFields = getSortedManagingFields();
for (let i = 0; i < ctrl.managingFields.length; i++) {
$scope.$watch('$ctrl.managingFields[' + i + '].value', function (newValue) {
Object.keys(displayBlocks)
Object.keys(displayBlocks[ctrl.managingFields[i].name])
.filter(displayBlock => displayBlock !== newValue)
.forEach(displayBlock => {
let fieldsToHide = displayBlocks[displayBlock]
let fieldsToHide = displayBlocks[ctrl.managingFields[i].name][displayBlock]
.filter(fieldToHide => fieldToHide.group === ctrl.managingFields[i].group);
fieldsToHide.forEach(formField => {
formField.required = false;
formField.isHidden = true;
if (!formField.ui.transmitAlways) {
formField.ignored = true;
}
});
hideFields(fieldsToHide);
});
if (displayBlocks[newValue]) {
let fieldsToDisplay = displayBlocks[newValue]
if (displayBlocks[ctrl.managingFields[i].name][newValue]) {
let fieldsToDisplay = displayBlocks[ctrl.managingFields[i].name][newValue]
.filter(fieldToDisplay => fieldToDisplay.group === ctrl.managingFields[i].group);
fieldsToDisplay.forEach(formField => {
formField.required = formField.ui.originProperties.required;
formField.isHidden = formField.ui.originProperties.isHidden;
delete formField.ignored;
});
displayFields(fieldsToDisplay);
}
});
}
}
}
function getSortedManagingFields () {
let managingFields = ctrl.fields.filter(formField =>
formField.ui && formField.ui.manageDisplayBlocksByValue);
let managingTrees = {};
let topManagingFields = managingFields.filter(formField => !formField.ui.displayBlocksManagedBy);
topManagingFields.forEach(topManagingField => {
managingTrees[topManagingField.name] = getManagingTree(topManagingField.name, managingFields);
});
let sorted = [];
sortManagingFields(managingTrees, managingFields, sorted);
return sorted;
}
function getManagingTree(topManagingFieldName, managingFields) {
let tree = {};
managingFields
.filter(formField => formField.ui && formField.ui.displayBlocksManagedBy === topManagingFieldName)
.forEach(formField => {
tree[formField.name] = getManagingTree(formField.name, managingFields);
});
return tree;
}
function sortManagingFields(managingTrees, managingFields, sorted) {
Object.keys(managingTrees)
.forEach(managingFieldName => {
sorted.unshift(managingFields.find(formField => formField.name === managingFieldName));
sortManagingFields(managingTrees[managingFieldName], managingFields, sorted);
});
}
function hideFields(fieldsToHide) {
fieldsToHide.forEach(formField => {
formField.required = false;
formField.isHidden = true;
if (!formField.ui.transmitAlways) {
formField.ignored = true;
}
if (formField.ui.manageDisplayBlocksByValue) {
let extraFieldsToHide = displayBlocks[formField.name][formField.value];
if (extraFieldsToHide && extraFieldsToHide.length > 0) {
hideFields(extraFieldsToHide);
}
}
});
}
function displayFields(fieldsToDisplay) {
fieldsToDisplay.forEach(formField => {
formField.required = formField.ui.originProperties.required;
formField.isHidden = formField.ui.originProperties.isHidden;
delete formField.ignored;
if (formField.ui.manageDisplayBlocksByValue) {
let extraFieldsToDisplay = displayBlocks[formField.name][formField.value];
if (extraFieldsToDisplay && extraFieldsToDisplay.length > 0) {
displayFields(extraFieldsToDisplay);
}
}
});
}
ctrl.updateFieldsAfterSelectionChange = function (oldItem, newItem) {
if (oldItem) {

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -0,0 +1,214 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyAddConnectorModal', {
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 ng-if="$ctrl.step1 && $ctrl.profiles">
<div class="modal-body-header">
<h2>Choose profile to attach connector to</h2>
</div>
<div class="modal-body" style="height:433px; max-height:433px">
<entaxy-modal-list items="$ctrl.profiles" selected="$ctrl.selectedProfile"
change-selection="$ctrl.changeProfileSelection" enable-dbl-click="true"></entaxy-modal-list>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.next()"
ng-disabled="!$ctrl.selectedProfile">Next</button>
</div>
</div>
<div ng-if="$ctrl.step2">
<div class="modal-body-header">
<h2>Choose connector template</h2>
</div>
<div class="modal-body" style="height:433px; max-height:433px">
<entaxy-modal-list items="$ctrl.templates" selected="$ctrl.selectedTemplate"
change-selection="$ctrl.changeTemplateSelection" enable-dbl-click="true"></entaxy-modal-list>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.back()" ng-if="$ctrl.profiles">Back</button>
<button type="button" class="btn btn-default" ng-click="$ctrl.next()"
ng-disabled="!$ctrl.selectedTemplate">Next</button>
</div>
</div>
<form name="connectorForm" class="form-horizontal" ng-if="$ctrl.step3" ng-submit="$ctrl.saveConnector($ctrl.formFields)">
<div class="modal-body" style="height:503px; max-height:503px;">
<div class="modal-body-header">
<h2>Fill in connector template parameters</h2>
</div>
<div class="form-group" ng-class="{'has-error': $ctrl.errors[formField.name]}"
ng-repeat="formField in $ctrl.formFields" style="margin:15px;">
<label class="col-sm-3 control-label" ng-class="{'required-pf': formField.isRequired}" for="{{formField.name}}">{{formField.label}}</label>
<div class="col-sm-8">
<input type="{{formField.type}}" id="{{formField.name}}" ng-class="{'form-control': formField.type !== 'checkbox'}"
ng-model="formField.value" ng-readonly="formField.isReadOnly" ng-if="!formField.typeInfo">
<span class="help-block" ng-show="$ctrl.errors[formField.name]">{{$ctrl.errors[formField.name]}}</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.back()">Back</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</form>
</div>
`,
controller: EntaxyAddConnectorModalController
})
.name;
function EntaxyAddConnectorModalController(workspace, jolokia) {
'ngInject';
var ctrl = this;
ctrl.$onInit = function() {
let templates = Entaxy.getConnectorTemplates();
ctrl.templates = templates.map(template => { return { name: template, displayName: template }});
ctrl.profiles = ctrl.resolve.profiles;
if (ctrl.profiles) {
ctrl.step1 = true;
ctrl.step2 = false;
ctrl.step3 = false;
} else {
ctrl.step1 = false;
ctrl.step2 = true;
ctrl.step3 = false;
}
ctrl.modalTitle = ctrl.resolve.profileName ?
'Add Legacy Connector to ' + ctrl.resolve.profileName : 'Add Legacy Connector';
}
ctrl.changeProfileSelection = function(item, isDblClicked) {
ctrl.selectedProfile = item;
if (isDblClicked) {
ctrl.next();
}
}
ctrl.changeTemplateSelection = function(item, isDblClicked) {
ctrl.selectedTemplate = item;
if (isDblClicked) {
ctrl.next();
}
}
ctrl.next = function() {
if (ctrl.step1 === true) {
ctrl.step1 = false;
ctrl.step2 = true;
} else if (ctrl.step2 === true) {
ctrl.step2 = false;
ctrl.step3 = true;
}
if (ctrl.step3 === true) {
defineFormFields();
}
}
function defineFormFields() {
if (!ctrl.formFields || ctrl.selectedTemplate.name !== ctrl.formFields[0].value) {
ctrl.formFields = Entaxy.getConnectorTemplateParams(ctrl.selectedTemplate.name);
ctrl.formFields.unshift({
label: 'templateName',
displayName: 'Template Name',
type: 'java.lang.String',
helpText: null,
value: ctrl.selectedTemplate.name,
isReadOnly: true
});
ctrl.formFields.forEach(formField => {
formField.name = formField.label;
if (formField.displayName) {
formField.label = formField.displayName;
}
formField.type = Entaxy.convertToHtmlInputType(formField.type);
});
}
}
ctrl.back = function() {
if (ctrl.step2 === true) {
ctrl.step1 = true;
ctrl.step2 = false;
} else if (ctrl.step3 === true) {
ctrl.step2 = true;
ctrl.step3 = false;
}
}
ctrl.cancel = function() {
ctrl.modalInstance.dismiss();
}
ctrl.saveConnector = function(fields) {
ctrl.errors = validateFields(fields);
if (Object.keys(ctrl.errors).length === 0) {
let connectorArgs = {
profile: ctrl.selectedProfile,
connectorTemplateName: ctrl.formFields.shift().value,
connectorFields: ctrl.formFields.map(formField => { return { label: formField.name, value: formField.value }; })
};
ctrl.modalInstance.close(connectorArgs);
}
}
function validateFields(fields) {
let errors = {};
_.forEach(fields, (field) => {
if (field.isRequired &&
(!field.value || (field.type !== 'checkbox' ? field.value.toString().trim().length === 0 : false))) {
errors[field.name] = Entaxy.ERROR_MESSAGE.EMPTY;
}
});
return errors;
}
}
EntaxyAddConnectorModalController.$inject = ['workspace', 'jolokia'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,77 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyConfirmationModal', {
bindings: {
modalInstance: '<',
resolve: '<'
},
template:
`
<div class="entaxy-simple-modal-container message-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.title}}</h4>
</div>
<div class="modal-body-small">
<span class="simple-modal-message">
{{$ctrl.message}}
</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.cancel()">Cancel</button>
<button type="submit" class="btn btn-primary" ng-click="$ctrl.confirm()">Confirm</button>
</div>
</div>
`,
controller: entaxyConfirmationModalController
})
.name;
function entaxyConfirmationModalController($uibModal) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
ctrl.title = ctrl.resolve.title;
ctrl.message = ctrl.resolve.message;
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.confirm = function() {
ctrl.modalInstance.close(true);
}
}
entaxyConfirmationModalController.$inject = ['$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,156 @@
/*-
* ~~~~~~licensing~~~~~~
* entaxy-atlasmap-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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyCreateResourceModal', {
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-without-header">
<div class="entaxy-create-resource-fields-container">
<div class="entaxy-create-resource-name-field-container" ng-class="{'has-error': $ctrl.errors.name}">
<label class="control-label required-pf" for="contentName">Name</label>
<input type="text" id="contentName" class="form-control" ng-model="$ctrl.name" set-focused="true">
</div>
<entaxy-select-from-enum id="contentType" ng-class="{'has-error': $ctrl.errors.type}"
values="$ctrl.selectValues" model="$ctrl.editorMode"
is-empty-included="false" sort-needed="true">
</entaxy-select-from-enum>
</div>
<div class="entaxy-resource-editor-container">
<entaxy-editor class="entaxy-editor" ng-class="{'has-error': $ctrl.errors.content}"
mode="$ctrl.editorMode" source-doc="$ctrl.source">
</entaxy-editor>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">{{$ctrl.btnTitle}}</button>
</div>
</div>
`,
controller: entaxyCreateResourceModalController
})
.name;
function entaxyCreateResourceModalController($uibModal, $scope, entaxyService, entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.mode = Entaxy.MODAL_MODES.EDIT;
ctrl.modalTitle = ctrl.resolve.modalTitle ? ctrl.resolve.modalTitle : 'Create resource';
ctrl.btnTitle = 'Save';
ctrl.selectValues = [
'xml',
{
displayValue: 'json',
value: { name: 'javascript', json: true }
}
];
if (ctrl.resolve.extraTypes) {
ctrl.selectValues = ctrl.selectValues.concat(ctrl.resolve.extraTypes);
}
ctrl.name = ctrl.resolve.resourceName ? ctrl.resolve.resourceName : '';
ctrl.source = '';
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function() {
if (validate()) {
ctrl.modalInstance.close({
name: ctrl.name,
text: ctrl.source,
type: getType().toUpperCase()
});
} else {
let fieldName = ctrl.errors.name ? 'Name' : 'Content';
let message = ctrl.errors.type ?
'Selected type should match the content' : fieldName + ' value should not be empty';
Entaxy.notificationError(message);
}
}
function validate() {
ctrl.errors = {};
if (!ctrl.name || ctrl.name.trim().length == 0) {
ctrl.errors.name = true;
return false;
}
if (angular.isString(ctrl.source) && ctrl.source.trim().length == 0) {
ctrl.errors.content = true;
}
if (!ctrl.errors.content && !isTypeFitContent()) {
ctrl.errors.type = true;
}
return Object.keys(ctrl.errors).length == 0;
}
function getType() {
let selectedValue = ctrl.selectValues.find(selectValue => selectValue.value === ctrl.editorMode);
return selectedValue !== undefined ? selectedValue.displayValue : ctrl.editorMode;
}
function isTypeFitContent() {
if (ctrl.editorMode === 'xml') {
return entaxyService.isSupposedlyXml(ctrl.source);
} else if (angular.isObject(ctrl.editorMode) && ctrl.editorMode.json) {
return entaxyService.isSupposedlyJson(ctrl.source);
} else {
return true;
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save();
}
}
];
}
}
entaxyCreateResourceModalController.$inject = ['$uibModal', '$scope', 'entaxyService', 'entaxyHotkeysService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,188 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyEditorModal', {
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-without-header">
<div class="syntax-highlighting-container">
<label class="control-label" for="syntaxHighlighting">Syntax highlighting</label>
<entaxy-select-from-enum id="syntaxHighlighting"
values="$ctrl.selectValues" model="$ctrl.editorMode"
is-empty-included="false" sort-needed="true"></entaxy-select-from-enum>
</div>
<div class="entaxy-resource-editor-container">
<entaxy-editor class="entaxy-editor" mode="$ctrl.editorMode" source-doc="$ctrl.resourceContent">
</entaxy-editor>
</div>
</div>
<div class="modal-footer">
<div class="btn-group" uib-dropdown>
<button id="split-button" type="button" class="btn btn-primary" ng-click="$ctrl.save(true)">
Save
</button>
<button type="button" class="btn btn-primary" uib-dropdown-toggle>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="split-button">
<li role="menuitem"><a ng-click="$ctrl.save(false)">Save as...</a></li>
</ul>
</div>
</div>
</div>
`,
controller: entaxyEditorModalController
})
.name;
function entaxyEditorModalController($uibModal, $scope, entaxyService, entaxyResourcesService, entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
let ftlType = {
displayValue: 'ftl',
value: 'freemarkermixed'
};
let jsonType = {
displayValue: 'json',
value: { name: 'javascript', json: true }
};
ctrl.selectValues = [ ftlType, jsonType, 'xml', 'yaml', 'txt' ];
ctrl.modalTitle = 'Edit resource: ' + ctrl.resolve.resourceName;
ctrl.resourceContent = ctrl.resolve.resourceContent;
ctrl.editorMode = getEditorMode(ctrl.resolve.extension);
}
function getEditorMode(extension) {
switch (extension) {
case 'xml':
case 'xsd':
case 'xsl':
case 'xslt':
case 'wsdl':
return 'xml';
case 'json':
case 'ftl':
return ctrl.selectValues.find(value => value.displayValue === extension).value;
case 'yaml':
case 'txt':
return extension;
default:
return 'txt';
}
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function(writeIntoSource) {
if (validate()) {
if (writeIntoSource) {
ctrl.modalInstance.close({
writeIntoSource: writeIntoSource,
content: ctrl.resourceContent
});
} else {
entaxyResourcesService.openResourceNameInputModal(
{ name: ctrl.resolve.resourceName, isFolder: false },
ctrl.resolve.names,
true,
false)
.then((name) => {
ctrl.modalInstance.close({
writeIntoSource: writeIntoSource,
content: ctrl.resourceContent,
name: name
});
});
}
} else {
let message = ctrl.errors.type ? 'Content value is invalid' : 'Content value should not be empty';
Entaxy.notificationError(message);
}
}
function validate() {
ctrl.errors = {};
if (angular.isString(ctrl.resourceContent) && ctrl.resourceContent.trim().length > 0 &&
!isTypeFitContent()) {
ctrl.errors.type = true;
}
return Object.keys(ctrl.errors).length == 0;
}
function isTypeFitContent() {
if (ctrl.resolve.extension === 'xml') {
return entaxyService.isSupposedlyXml(ctrl.resourceContent);
} else if (ctrl.resolve.extension === 'json') {
return entaxyService.isSupposedlyJson(ctrl.resourceContent);
} else {
return true;
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save(true);
}
},
{
...Entaxy.getSaveAsHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save(false);
}
}
];
}
}
entaxyEditorModalController.$inject = ['$uibModal', '$scope', 'entaxyService', 'entaxyResourcesService',
'entaxyHotkeysService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,395 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyModal', {
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 ng-if="$ctrl.step1">
<div class="modal-body-header">
<h2>{{$ctrl.firstStepTitle}}</h2>
</div>
<div class="modal-body">
<entaxy-modal-list items="$ctrl.containers" selected="$ctrl.selectedContainer"
change-selection="$ctrl.changeContainerSelection" enable-dbl-click="true"></entaxy-modal-list>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.next()"
ng-disabled="!$ctrl.selectedContainer">Next</button>
</div>
</div>
<div ng-if="$ctrl.step2">
<div class="modal-body-header">
<h2>{{$ctrl.secondStepTitle}}</h2>
</div>
<div class="modal-body">
<entaxy-modal-list-with-description items="$ctrl.factories" selected-item="$ctrl.selectedFactory"
change-selection="$ctrl.changeFactorySelection" show-deprecated="$ctrl.showDeprecated">
</entaxy-modal-list-with-description>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-if="$ctrl.containers"
ng-click="$ctrl.back()">Back</button>
<button type="button" class="btn btn-default" ng-click="$ctrl.next()"
ng-disabled="!$ctrl.selectedFactory">Next</button>
</div>
</div>
<div ng-if="$ctrl.step3">
<div class="modal-body-header form-header">
<h2>{{$ctrl.thirdStepTitle}}</h2>
<span ng-if="$ctrl.shouldShowChangesNote()">
There are unsaved changes
</span>
</div>
<div class="modal-body">
<entaxy-modal-group-fields groups="$ctrl.groups" fields="$ctrl.formFields"
use-form-dirty="true" is-form-dirty="$ctrl.isFormDirty"
errors="$ctrl.errors" mode="$ctrl.mode"></entaxy-modal-group-fields>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-if="$ctrl.factories.length > 1 || $ctrl.containers"
ng-click="$ctrl.back()">Back</button>
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">{{$ctrl.submitBtnTitle}}</button>
</div>
<div>
</div>
`,
controller: entaxyModalController
})
.name;
function entaxyModalController($scope, entaxyService, entaxyHotkeysService,
entaxyPrivateObjectsCacheService, entaxyProfileDiagramService) {
'ngInject';
var ctrl = this;
ctrl.$onInit = function() {
ctrl.mode = ctrl.resolve.mode;
if (!ctrl.mode) {
ctrl.cancel('Mode is not defined');
}
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.hasChangedPrivateObjects = ctrl.mode !== Entaxy.MODAL_MODES.ADD ?
entaxyPrivateObjectsCacheService.isChanged(ctrl.resolve.itemMbeanName) : false;
ctrl.hasChangesFromDiagram = ctrl.mode === Entaxy.MODAL_MODES.EDIT ?
entaxyProfileDiagramService.hasChanges(ctrl.resolve.itemMbeanName) : false;
ctrl.itemType = ctrl.resolve.itemType ? ctrl.resolve.itemType : 'Item';
let extraToTitle = ctrl.resolve.parentName ? (' to ' + ctrl.resolve.parentName) : '';
ctrl.modalTitle = ctrl.mode + ' ' + ctrl.itemType + extraToTitle;
ctrl.submitBtnTitle = Entaxy.getButtonTitleByMode(ctrl.mode);
let containerType = ctrl.resolve.containerType ? ctrl.resolve.containerType : 'Container';
ctrl.firstStepTitle = ctrl.resolve.firstStepTitle ?
ctrl.resolve.firstStepTitle :
'Choose ' + containerType.toLowerCase() + ' to attach ' + ctrl.itemType.toLowerCase() + ' to';
ctrl.secondStepTitle = ctrl.resolve.secondStepTitle ? ctrl.resolve.secondStepTitle : 'Choose factory';
ctrl.thirdStepTitle = ctrl.resolve.itemName ? ctrl.mode + ' properties for ' + ctrl.resolve.itemName
: ctrl.resolve.thirdStepTitle ? ctrl.resolve.thirdStepTitle : 'Fill in fields';
if (ctrl.mode !== Entaxy.MODAL_MODES.ADD || ctrl.resolve.useTemplate) {
ctrl.properties = ctrl.resolve.info.properties;
ctrl.configurableOnly = !ctrl.resolve.useTemplate ? ctrl.resolve.info.configurableOnly : false;
}
ctrl.containers = ctrl.resolve.containers;
ctrl.factories = ctrl.resolve.factories ? ctrl.resolve.factories : null;
if (!ctrl.factories || ctrl.factories.length === 0) {
ctrl.cancel('Factories are not found');
} else if (ctrl.factories.length === 1) {
ctrl.selectedFactory = ctrl.factories[0];
}
ctrl.factories.sort(Entaxy.compareBy('displayName'));
if (ctrl.containers) {
ctrl.step1 = true;
ctrl.step2 = false;
ctrl.step3 = false
} else {
if (ctrl.factories.length > 1) {
ctrl.step1 = false;
ctrl.step2 = true;
ctrl.step3 = false;
} else if (ctrl.factories.length === 1) {
ctrl.next();
}
}
}
ctrl.next = function() {
if (ctrl.step1 === true) {
if (ctrl.factories.length > 1) {
ctrl.step1 = false;
ctrl.step2 = true;
} else if (ctrl.factories.length === 1) {
defineFormFields();
}
} else {
defineFormFields();
}
}
function defineFormFields() {
let container = ctrl.formFields ?
ctrl.formFields.find(field => field.name === '__entaxyContainerId') : undefined;
if (!ctrl.formFields || ctrl.selectedFactory.name !== ctrl.formFields[0].value
|| (ctrl.containers && container.value !== ctrl.selectedContainer.name)) {
ctrl.formFields = [];
ctrl.formFields.push({
label: 'Factory',
name: 'factoryId',
type: 'text',
description: ctrl.selectedFactory.description,
value: ctrl.selectedFactory.displayName,
originalValue: ctrl.selectedFactory.name,
readOnly: true,
required: ctrl.mode === Entaxy.MODAL_MODES.VIEW ? false : true,
group: 'general'
});
entaxyService.getFields(ctrl.selectedFactory.mbeanName)
.then((response) => {
let groups = new Set();
groups.add('general');
_.forEach(JSON.parse(response), (field) => {
let objectId = undefined;
if (ctrl.mode !== Entaxy.MODAL_MODES.ADD) {
objectId = ctrl.resolve.info['objectId'];
}
let profileName = ctrl.selectedContainer ?
ctrl.selectedContainer.name : ctrl.resolve.parentName;
let formField = entaxyService.makeFormField(field, objectId, ctrl.properties,
ctrl.configurableOnly, ctrl.mode, ctrl.resolve.itemMbeanName, profileName);
if (formField) {
ctrl.formFields.push(formField);
if (!formField.isBackRef && !formField.isHidden) {
groups.add(formField.group);
}
}
});
if (ctrl.mode !== Entaxy.MODAL_MODES.VIEW) {
processDependencies();
}
ctrl.groups = Array.from(groups).map((group) => { return { name: group, displayName: group }; });
ctrl.step1 = false;
ctrl.step2 = false;
ctrl.step3 = true;
});
} else {
ctrl.step1 = false;
ctrl.step2 = false;
ctrl.step3 = true;
}
}
let watchers = [];
function processDependencies() {
let dependentFormFields = entaxyService.getDependentFormFields(ctrl.formFields, ctrl.configurableOnly);
ctrl.definingFormFields = entaxyService.getDefiningFormFields(dependentFormFields, ctrl.formFields);
for (let i = 0; i < ctrl.definingFormFields.length; i++) {
if (ctrl.definingFormFields[i].value) {
let initialRunDependentFormFields = ctrl.mode === Entaxy.MODAL_MODES.ADD ?
dependentFormFields :
dependentFormFields.filter(field => (field.typeInfo && field.typeInfo.type === 'list'));
entaxyService.processDependencies(initialRunDependentFormFields,
ctrl.definingFormFields,
ctrl.definingFormFields[i].name,
ctrl.definingFormFields[i].value,
undefined);
}
watchers.push(
$scope.$watch('$ctrl.definingFormFields[' + i + '].value', function(newValue, oldValue) {
if (newValue !== oldValue) {
Entaxy.changingFieldValueNotification('defining');
entaxyService.processDependencies(dependentFormFields,
ctrl.definingFormFields,
ctrl.definingFormFields[i].name,
newValue,
oldValue);
}
})
);
}
}
ctrl.back = function() {
if (ctrl.step2 === true) {
ctrl.step1 = true;
ctrl.step2 = false;
} else if (ctrl.step3 === true) {
ctrl.errors = undefined;
clearWatchers();
if (ctrl.factories.length > 1) {
ctrl.step2 = true;
} else if (ctrl.factories.length === 1) {
ctrl.step1 = true;
}
ctrl.step3 = false;
}
}
function clearWatchers() {
if (watchers && watchers.length > 0) {
watchers.forEach(watcher => {
watcher();
});
}
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.changeContainerSelection = function(item, isDblClicked) {
ctrl.selectedContainer = item;
if (isDblClicked) {
ctrl.next();
}
}
ctrl.changeFactorySelection = function(item, isDblClicked) {
ctrl.selectedFactory = item;
if (isDblClicked) {
ctrl.next();
}
}
ctrl.shouldShowChangesNote = function () {
return ctrl.mode !== Entaxy.MODAL_MODES.ADD &&
(ctrl.isFormDirty || ctrl.hasChangedPrivateObjects || ctrl.hasChangesFromDiagram);
}
ctrl.save = function() {
if (ctrl.mode === Entaxy.MODAL_MODES.VIEW) {
ctrl.cancel();
}
let isConfirmationNeeded = ctrl.mode === Entaxy.MODAL_MODES.EDIT &&
!ctrl.isFormDirty && !ctrl.hasChangedPrivateObjects && !ctrl.hasChangesFromDiagram;
entaxyService.requestConfirmationForSavingIfNeededAndProceed(isConfirmationNeeded, save);
}
function save () {
let profileMBeanName = ctrl.selectedContainer ? ctrl.selectedContainer.mbeanName : undefined;
entaxyService.validateFields(ctrl.formFields, ctrl.selectedFactory,
profileMBeanName, ctrl.resolve.checkUniquenessParentFields)
.then(errors => {
ctrl.errors = errors;
if (Object.keys(ctrl.errors).length === 0) {
if (ctrl.resolve.returnFormFields) {
ctrl.modalInstance.close(Entaxy.deepCopy(ctrl.formFields));
} else {
let args = entaxyService.getArguments(ctrl.formFields, ctrl.factories);
args.configProperties = ctrl.properties;
args.configurableOnly = ctrl.configurableOnly;
ctrl.modalInstance.close(args);
}
}
});
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
if (ctrl.mode === Entaxy.MODAL_MODES.EDIT ||
(ctrl.mode === Entaxy.MODAL_MODES.ADD && ctrl.step3)) {
ctrl.save();
}
}
},
{
...Entaxy.getBackHotkeyDescription(),
callback: function (event) {
event.preventDefault();
if ((ctrl.step2 && ctrl.containers) ||
(ctrl.step3 && (ctrl.factories.length > 1 || ctrl.containers))) {
ctrl.back();
}
}
},
{
...Entaxy.getNextHotkeyDescription(),
callback: function (event) {
event.preventDefault();
if ((ctrl.step1 && ctrl.selectedContainer) || (ctrl.step2 && ctrl.selectedFactory)) {
ctrl.next();
}
}
}
];
}
}
entaxyModalController.$inject = ['$scope', 'entaxyService', 'entaxyHotkeysService',
'entaxyPrivateObjectsCacheService', 'entaxyProfileDiagramService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,86 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyOperationTableRequestModal', {
bindings: {
modalInstance: '<',
resolve: '<'
},
template:
`
<div class="entaxy-modal-container simple-modal-content operation-table-request-modal">
<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">
<p>{{$ctrl.message}}</p>
<div class="operation-affected-table-container">
<entaxy-operation-affected-table items="$ctrl.affectedObjects"></entaxy-operation-affected-table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.cancel()">Cancel</button>
<button type="button" class="btn btn-primary" ng-click="$ctrl.apply('current')">Apply only to current</button>
<button type="button" class="btn btn-primary" ng-click="$ctrl.apply('all')">Apply to all</button>
</div>
</div>
`,
controller: entaxyOperationTableRequestModalController
})
.name;
function entaxyOperationTableRequestModalController($uibModal) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
ctrl.operationType = ctrl.resolve.operationType.toUpperCase();
ctrl.modalTitle = 'Confirm operation ' + ctrl.operationType;
ctrl.message = 'To execute operation ' + ctrl.operationType + ' on '
+ ctrl.resolve.objectDisplayName + ' [' + ctrl.resolve.objectFullId + '] '
+ 'corresponding operations should be applied to the following affected objects:';
ctrl.affectedObjects = ctrl.resolve.affectedObjects;
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.apply = function (flag) {
ctrl.modalInstance.close(flag);
}
}
entaxyOperationTableRequestModalController.$inject = ['$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,395 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyResourceViewerModal', {
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-without-header" ng-class="{'entaxy-resource-save-mode': $ctrl.saveMode}">
<div class="modal-resources-viewer-container">
<div class="modal-resources-viewer-header-container">
<div class="provider-selector" ng-if="$ctrl.providers">
<span>Provider:</span>
<select class="form-control" ng-options="provider for provider in $ctrl.providers"
ng-model="$ctrl.newProtocol" ng-change="$ctrl.onProviderSelectionChange()" />
</div>
<div class="navigation-creation">
<entaxy-crumbs root-crumb="$ctrl.protocol" crumbs="$ctrl.crumbs"></entaxy-crumbs>
<button type="button" data-toggle="tooltip" title="Create folder"
ng-click="$ctrl.addFolder()" ng-if="$ctrl.folderAddingEnabled">
<span class="pficon pficon-add-circle-o"></span>
</button>
</div>
</div>
<entaxy-file-panel items="$ctrl.items" selected-items="$ctrl.selectedItems" view="$ctrl.view"
change-selection-fn="$ctrl.changeSelection" open-fn="$ctrl.open"></entaxy-file-panel>
</div>
</div>
<div class="modal-footer"
ng-class="{'has-error': $ctrl.error, 'entaxy-resource-save-mode': $ctrl.saveMode}">
<div class="entaxy-resource-save-mode-labelled-field-container" ng-if="$ctrl.saveMode">
<label class="control-label">Name</label>
<div class="entaxy-resource-save-mode-field-container">
<entaxy-input-with-extension model="$ctrl.name" set-focused="true"
model-without-extension="$ctrl.nameWithoutExtension" extension="$ctrl.extension">
</entaxy-input-with-extension>
<span class="help-block" ng-if="$ctrl.error">
{{$ctrl.error}}
</span>
</div>
</div>
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">{{$ctrl.btnTitle}}</button>
</div>
</div>
`,
controller: entaxyResourceViewerModalController
})
.name;
function entaxyResourceViewerModalController($uibModal, $scope, hotkeys, entaxyHotkeysService,
entaxyResourcesService, entaxyService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
ctrl.saveMode = ctrl.resolve.config.saveMode;
ctrl.btnTitle = ctrl.saveMode ? 'Save' : 'Select';
ctrl.modalTitle = ctrl.saveMode ? 'Save Resource' : 'Select Resources';
if (ctrl.saveMode) {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
} else {
hotkeys.pause();
}
ctrl.view = 'tiles';
ctrl.protocol = ctrl.resolve.config.resourceProvider;
setProviderMbeanName();
if (ctrl.resolve.config.providersSelectionEnabled) {
ctrl.newProtocol = ctrl.protocol;
populateProviders();
}
ctrl.filter = ctrl.resolve.config.filter;
ctrl.folderSelectionEnabled = ctrl.resolve.config.folderSelectionEnabled;
ctrl.folderAddingEnabled = ctrl.resolve.config.folderAddingEnabled;
ctrl.multipleSelectionEnabled = ctrl.resolve.config.multipleSelectionEnabled;
if (ctrl.saveMode) {
ctrl.extension = ctrl.filter.slice(1);
}
let location = ctrl.resolve.location;
ctrl.useShortUrl = ctrl.resolve.config.useShortUrl;
if (location && location.includes(':')) {
let path = ctrl.useShortUrl ? location.split(':')[1] : location.slice(18);
if (path.length > 0) {
let splitPath = path.split('/');
if (!ctrl.useShortUrl) {
splitPath.shift();
}
if (ctrl.saveMode) {
let lastPathItem = splitPath[splitPath.length - 1];
if (lastPathItem.endsWith(ctrl.extension)) {
ctrl.nameWithoutExtension = lastPathItem
.substring(0, lastPathItem.lastIndexOf(ctrl.extension));
splitPath.pop();
}
}
if (!ctrl.folderSelectionEnabled) {
splitPath.pop();
}
// todo else check if the last item in path is folder or not
ctrl.crumbs = splitPath;
} else {
ctrl.crumbs = [];
}
} else {
ctrl.crumbs = [];
}
}
function populateProviders() {
entaxyResourcesService.getProviders()
.then(result => {
ctrl.providers = JSON.parse(result);
})
.catch(error => {
Entaxy.log.error(error);
Entaxy.notificationError(error)
});
}
function setProviderMbeanName() {
let provider = entaxyResourcesService.getProviderMbean(ctrl.protocol);
ctrl.providerMBeanName = provider.objectName;
}
ctrl.providerCrumbsCache = {};
ctrl.onProviderSelectionChange = function () {
ctrl.providerCrumbsCache[ctrl.protocol] = ctrl.crumbs;
let forceUpdate = entaxyResourcesService.getPath(ctrl.providerCrumbsCache[ctrl.protocol]) ===
entaxyResourcesService.getPath(ctrl.providerCrumbsCache[ctrl.newProtocol]);
ctrl.protocol = ctrl.newProtocol;
setProviderMbeanName();
ctrl.crumbs = ctrl.providerCrumbsCache[ctrl.newProtocol] ? ctrl.providerCrumbsCache[ctrl.newProtocol] : [];
if (forceUpdate) {
onCrumbsUpdated();
}
}
$scope.$watchCollection('$ctrl.crumbs', function(newValue, oldValue) {
onCrumbsUpdated();
});
function onCrumbsUpdated() {
ctrl.selectedItems = [];
updateItems();
}
$scope.$watch('$ctrl.name', function () {
if (ctrl.saveMode && ctrl.selectedItems.length == 1 && ctrl.name !== ctrl.selectedItems[0].name) {
ctrl.selectedItems = [];
}
});
ctrl.changeSelection = function (item, isMultiple) {
if (!item.error) {
if (!isMultiple) {
ctrl.selectedItems = [ item ];
if (ctrl.saveMode && !item.isFolder) {
ctrl.nameWithoutExtension = item.name.substring(0, item.name.lastIndexOf(ctrl.extension));
}
} else {
if (ctrl.multipleSelectionEnabled && ctrl.selectedItems && ctrl.selectedItems.length > 0) {
if (ctrl.selectedItems.includes(item)) {
ctrl.selectedItems = ctrl.selectedItems.filter(it => it.name !== item.name);
} else {
ctrl.selectedItems.push(item);
}
} else {
ctrl.selectedItems = [ item ];
}
}
} else {
Entaxy.notificationError('Cannot select the resource containing an error');
}
}
ctrl.open = function (item) {
if (item.isFolder === true) {
ctrl.crumbs.push(item.name);
} else {
ctrl.changeSelection(item);
if (!item.error) {
ctrl.save();
}
}
}
let clientFolders = [];
ctrl.addFolder = function () {
entaxyResourcesService.addFolder(ctrl.items, clientFolders, ctrl.crumbs);
}
function updateItems() {
let path = entaxyResourcesService.getPath(ctrl.crumbs);
getItems(path).then(originItems => {
if (ctrl.folderAddingEnabled && ctrl.crumbs.length > 0 &&
originItems.length == 0 && clientFolders.length == 0) {
populateAddedFoldersFromLocation(ctrl.crumbs);
}
let items = originItems
.concat(entaxyResourcesService.getClientFoldersToAdd(clientFolders, originItems, ctrl.crumbs));
if (ctrl.filter === 'foldersOnly') {
items = items.filter(item => item.isFolder);
} else if (Array.isArray(ctrl.filter) && ctrl.filter.length > 0) {
items = items.filter(item => {
let match = false;
if (item.isFolder) {
return true;
}
ctrl.filter.forEach(filter => {
if (filter.startsWith('*') && item.name.endsWith(filter.substring(1, filter.length))) {
match = true;
}
});
return match;
});
} else if (ctrl.filter && ctrl.filter.startsWith('*')) {
items = items.filter(item => item.isFolder || item.name.endsWith(ctrl.filter.substring(1, ctrl.filter.length)));
}
ctrl.items = items.sort(Entaxy.compareBy('name')).sort((a, b) => b.isFolder - a.isFolder);
})
}
function populateAddedFoldersFromLocation(originCrumbs) {
let crumbs = Entaxy.deepCopy(originCrumbs);
if (crumbs.length > 0) {
let lastFolderName = crumbs.pop();
let path = entaxyResourcesService.getPath(crumbs);
getItems(path).then(result => {
let items = JSON.parse(result);
if (items.length == 0) {
let addedFolder = entaxyResourcesService.createFolder(lastFolderName, crumbs);
clientFolders.push(addedFolder);
populateAddedFoldersFromLocation(crumbs);
} else {
if (!items.map(item => item.name).includes(lastFolderName)) {
let addedFolder = entaxyResourcesService.createFolder(lastFolderName, crumbs);
clientFolders.push(addedFolder);
}
}
});
}
}
function getItems(path) {
return entaxyResourcesService.getResourcesInfo(ctrl.providerMBeanName, path);
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function() {
if (ctrl.saveMode) {
if (ctrl.items.find(item => item.name === ctrl.name)) {
let title = 'Confirm Saving';
let message = 'Resource with name ' + ctrl.name + ' already exists.' +
' Do you want to replace it?';
entaxyService.openConfirmationWindow(title, message).then(() => {
save();
});
} else {
save();
}
} else {
save();
}
}
function save() {
if (!validate()) {
return;
}
if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
let locations = [];
ctrl.selectedItems.forEach(selectedItem => {
if (!selectedItem.isFolder || ctrl.folderSelectionEnabled) {
let path = entaxyResourcesService.getPath(ctrl.crumbs);
let folderLocation = getFolderLocation(path);
let separator = path.length > 0 ? '/' : '';
let location = folderLocation + separator + selectedItem.name;
locations.push(location);
}
});
if (locations.length > 0) {
ctrl.modalInstance.close(ctrl.multipleSelectionEnabled ? locations : locations[0]);
}
} else {
if (ctrl.folderSelectionEnabled) {
let path = entaxyResourcesService.getPath(ctrl.crumbs);
let folderLocation = getFolderLocation(path);
if (ctrl.saveMode) {
if (!folderLocation.endsWith(ctrl.extension)) {
folderLocation += '/' + ctrl.name;
}
}
ctrl.modalInstance.close(ctrl.multipleSelectionEnabled ? [ folderLocation ] : folderLocation);
} else {
Entaxy.notificationError('There is no selected resource');
}
}
}
function getFolderLocation(path) {
return ctrl.useShortUrl ? ctrl.protocol + ':' + path : 'entaxy-resource://' + ctrl.protocol + '/' + path;
}
function validate() {
ctrl.error = undefined;
if (ctrl.saveMode) {
if (!ctrl.nameWithoutExtension || ctrl.nameWithoutExtension.trim().length == 0) {
ctrl.error = Entaxy.ERROR_MESSAGE.EMPTY;
}
if (!ctrl.error) {
['/', '\\', ':', '*', '?', '<', '>', '|'].forEach((symbol) => {
if (ctrl.nameWithoutExtension.indexOf(symbol) >= 0) {
ctrl.error = 'Must not include symbols /\\:*?<>|';
}
});
}
}
return ctrl.error ? false : true;
}
$scope.$on('$destroy', function() {
if (!ctrl.saveMode) {
hotkeys.unpause();
}
});
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save();
}
}
];
}
}
entaxyResourceViewerModalController.$inject = ['$uibModal', '$scope', 'hotkeys', 'entaxyHotkeysService',
'entaxyResourcesService', 'entaxyService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,137 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxySimpleResourceNameInputModal', {
bindings: {
modalInstance: '<',
resolve: '<'
},
template:
`
<div class="entaxy-simple-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.title}}</h4>
</div>
<div class="modal-body-small">
<div class="form-group" ng-class="{'has-error': $ctrl.error}">
<div class="col-sm-12">
<input type="text" class="form-control" ng-model="$ctrl.getSetName" ng-if="!$ctrl.extension"
ng-model-options="{getterSetter: true}" ng-trim="false" set-focused="true">
<entaxy-input-with-extension model="$ctrl.name" ng-if="$ctrl.extension" set-focused="true"
model-without-extension="$ctrl.nameWithoutExtension" extension="$ctrl.extension">
</entaxy-input-with-extension>
<span class="help-block" ng-show="$ctrl.error">{{$ctrl.error}}</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$ctrl.cancel()">Cancel</button>
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">Save</button>
</div>
</div>
`,
controller: entaxySimpleResourceNameInputModalController
})
.name;
function entaxySimpleResourceNameInputModalController($scope, $uibModal, entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.title = ctrl.resolve.title;
ctrl.type = ctrl.resolve.type ? ctrl.resolve.type : 'Resource';
ctrl.name = ctrl.resolve.name;
if (ctrl.name && ctrl.type === 'Resource') {
let dotIndex = ctrl.name.lastIndexOf('.');
if (dotIndex > -1) {
ctrl.nameWithoutExtension = ctrl.name.slice(0, dotIndex);
ctrl.extension = ctrl.name.slice(dotIndex);
}
}
ctrl.names = ctrl.resolve.names;
}
ctrl.getSetName = function (newName) {
return angular.isDefined(newName) ?
(ctrl.name = ctrl.resolve.replaceSpaces ? newName.replace(' ', '_') : newName) : ctrl.name;
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function() {
ctrl.error = validate();
if (!ctrl.error) {
ctrl.modalInstance.close(ctrl.resolve.replaceSpaces ? ctrl.name : ctrl.name.trim());
}
}
function validate() {
let error;
if (isEmpty(ctrl.name) || (ctrl.extension && isEmpty(ctrl.nameWithoutExtension))) {
return ctrl.type + ' name must not be empty';
}
['/', '\\', ':', '*', '?', '<', '>', '|'].forEach((symbol) => {
if (ctrl.name.indexOf(symbol) >= 0) {
error = ctrl.type + ' name must not include symbols /\\:*?<>|';
}
});
ctrl.names.forEach((name) => {
if (name === ctrl.name) {
error = ctrl.type + ' name must be unique';
}
});
return error;
}
function isEmpty(value) {
return !value || value.length == 0 || value.trim().length == 0;
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save();
}
}
];
}
}
entaxySimpleResourceNameInputModalController.$inject = ['$scope', '$uibModal', 'entaxyHotkeysService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,103 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyXmlModal', {
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-without-header">
<div class="entaxy-editor-container">
<entaxy-xml-editor class="entaxy-editor" source-doc="$ctrl.xml" read-only="$ctrl.readOnly">
</entaxy-xml-editor>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="$ctrl.save()">{{$ctrl.btnTitle}}</button>
</div>
</div>
`,
controller: entaxyXmlModalController
})
.name;
function entaxyXmlModalController($uibModal, $scope, entaxyHotkeysService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.mode = ctrl.resolve.mode;
ctrl.modalTitle = ctrl.mode + ' XML';
ctrl.btnTitle = ctrl.resolve.defineButtonTitleByMode ? Entaxy.getButtonTitleByMode(ctrl.mode) : 'Ok';
ctrl.readOnly = ctrl.mode === Entaxy.MODAL_MODES.VIEW;
ctrl.xml = ctrl.resolve.xml;
}
ctrl.cancel = function(reason) {
ctrl.modalInstance.dismiss(reason);
}
ctrl.save = function() {
if (ctrl.readOnly) {
ctrl.cancel();
} else {
if ((ctrl.xml && angular.isString(ctrl.xml) && ctrl.xml.trim().length > 0) ||
!angular.isString(ctrl.xml)) {
ctrl.modalInstance.close(ctrl.xml);
} else {
Entaxy.notificationError('Value should not be empty');
}
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
ctrl.save();
}
}
];
}
}
entaxyXmlModalController.$inject = ['$uibModal', '$scope', 'entaxyHotkeysService'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -379,9 +379,12 @@ var Entaxy;
when(TAB_CONFIG.routeProperties.route,
{ template: '<entaxy-properties item-name="Route"></entaxy-properties>' }).
when(TAB_CONFIG.resources.route,
{ template: '<entaxy-resources></entaxy-resources>' }).
{
template: '<entaxy-resources></entaxy-resources>',
reloadOnSearch: false
}).
when(TAB_CONFIG.services.route,
{ template: '<entaxy-services page-title="Services"></entaxy-services>' }).
{ template: '<entaxy-services page-title="Services and Clients"></entaxy-services>' }).
when(TAB_CONFIG.serviceProperties.route,
{ template: '<entaxy-properties item-name="Service"></entaxy-properties>' }).
when(TAB_CONFIG.realms.route,
@ -483,7 +486,7 @@ var TAB_CONFIG = {
route: '/entaxy-management/resources'
},
services: {
title: 'Services',
title: 'Services and Clients',
route: '/entaxy-management/services'
},
serviceProperties: {

View File

@ -0,0 +1,57 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyConnectorBlock', {
transclude: true,
bindings: {
direction: '<',
connector: '<',
editConnectorPropertiesFn: '<',
saveConnectorFn: '<'
},
template:
`
<div class="connector-block" ng-class="{'has-changes': $ctrl.connector.isChanged}"
ng-click="$ctrl.editConnectorPropertiesFn($ctrl.connector, $event)">
<div class="connector-info">
<div class="connector-title-container">
<span class="profile-diagram-support-span" ng-if="$ctrl.connector.isChanged"></span>
<span class="bold connector-title" data-toggle="tooltip" title="{{$ctrl.connector.displayName}}">
{{$ctrl.connector.displayName}}
</span>
<span class="pficon pficon-save" ng-click="$ctrl.saveConnectorFn($ctrl.connector, $event)"
data-toggle="tooltip" title="Save connector changes" ng-if="$ctrl.connector.isChanged"></span>
</div>
<span class="connector-classifier">{{$ctrl.connector.classifier}}</span>
</div>
<ng-transclude></ng-transclude>
</div>
`
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,148 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyConnectorsWithFlow', {
bindings: {
direction: '@',
connectors: '<',
profileName: '<',
editCustomizationPointFn: '<',
editProfilePropertiesFn: '<',
editPropertiesFn: '<',
saveConnectorFn: '<',
updateFn: '<'
},
template:
`
<div class="connectors-group-container">
<span class="connectors-group-title">{{$ctrl.connectorsGroupTitle}}</span>
<div class="connectors-with-flow-container">
<div class="connectors-container">
<entaxy-normal-connector-block ng-repeat="connector in $ctrl.connectors"
ng-if="!connector.isCustom" direction="$ctrl.direction" connector="connector"
edit-connector-properties-fn="$ctrl.editConnectorProperties"
save-connector-fn="$ctrl.saveConnector"
edit-connector-customization-point-fn="$ctrl.editConnectorCustomizationPoint">
</entaxy-normal-connector-block>
<entaxy-custom-connector-block ng-repeat="connector in $ctrl.connectors"
ng-if="connector.isCustom" direction="$ctrl.direction" connector="connector"
edit-connector-properties-fn="$ctrl.editConnectorProperties"
save-connector-fn="$ctrl.saveConnector"
edit-connector-customization-point-fn="$ctrl.editConnectorCustomizationPoint">
</entaxy-custom-connector-block>
</div>
<entaxy-in-flow-block ng-if="$ctrl.isDirectionIn"
edit-profile-properties-fn="$ctrl.editProfileProperties"
edit-flow-customization-point-fn="$ctrl.editFlowCustomizationPoint"></entaxy-in-flow-block>
<entaxy-out-flow-block ng-if="!$ctrl.isDirectionIn"
edit-profile-properties-fn="$ctrl.editProfileProperties"
edit-flow-customization-point-fn="$ctrl.editFlowCustomizationPoint"></entaxy-out-flow-block>
</div>
</div>
`,
controller: entaxyConnectorsWithFlowController
})
.name;
function entaxyConnectorsWithFlowController(workspace) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
if (ctrl.direction) {
ctrl.isDirectionIn = ctrl.direction === 'in';
ctrl.connectorsGroupTitle = '--- ' + ctrl.direction.toUpperCase() + ' ---';
} else {
Entaxy.log.error('Connectors group direction is not defined');
}
}
ctrl.editConnectorProperties = function (connector, event) {
event.stopPropagation();
ctrl.editPropertiesFn(connector, Entaxy.RUNTIME_TYPE.CONNECTOR, 'Connector');
}
ctrl.editConnectorCustomizationPoint = function (connector, customizationPoint, event) {
event.stopPropagation();
let propertyName = getPropertyNameForConnectorCustomizationPoint(customizationPoint);
ctrl.editCustomizationPointFn(connector.mbeanName, propertyName, connector);
}
ctrl.editProfileProperties = function (groupName, event) {
event.stopPropagation();
ctrl.editProfilePropertiesFn(groupName);
}
ctrl.editFlowCustomizationPoint = function (customizationPoint, event) {
event.stopPropagation();
let selectedMbeanName = workspace.getSelectedMBeanName();
let propertyName = getPropertyNameForFlowCustomizationPoint(customizationPoint);
ctrl.editCustomizationPointFn(selectedMbeanName, propertyName);
}
function getPropertyNameForConnectorCustomizationPoint(customizationPointName) {
switch (customizationPointName) {
case 'pre-route':
case 'pre-output':
return customizationPointName;
case 'response':
case 'postprocess':
return 'responseRoute';
case 'custom-route':
return ctrl.isDirectionIn ? 'customInputRoute' : 'customOutputRoute';
};
}
function getPropertyNameForFlowCustomizationPoint(customizationPointName) {
switch (customizationPointName) {
case 'pre-route':
return ctrl.direction + '-flow-' + customizationPointName;
case 'response':
case 'postprocess':
return ctrl.direction + '-flow-response';
case 'connector-selector':
return customizationPointName;
};
}
ctrl.saveConnector = function (connector, event) {
event.stopPropagation();
ctrl.saveConnectorFn(connector.mbeanName, true, false);
}
}
entaxyConnectorsWithFlowController.$inject = ['workspace'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,74 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyCustomConnectorBlock', {
transclude: true,
bindings: {
direction: '<',
connector: '<',
editConnectorPropertiesFn: '<',
saveConnectorFn: '<',
editConnectorCustomizationPointFn: '<'
},
template:
`
<entaxy-connector-block direction="$ctrl.direction" connector="$ctrl.connector"
edit-connector-properties-fn="$ctrl.editConnectorPropertiesFn"
save-connector-fn="$ctrl.saveConnectorFn">
<div class="custom-connector-customization-points-container" ng-if="$ctrl.connector.isCustom">
<div id="{{$ctrl.connector.name}}_{{$ctrl.customConnectorCustomizationPoints[0]}}"
class="customization-point-block"
ng-click="$ctrl.editConnectorCustomizationPointFn($ctrl.connector, $ctrl.customConnectorCustomizationPoints[0], $event)">
{{$ctrl.customConnectorCustomizationPoints[0]}}
</div>
<div id="{{$ctrl.connector.name}}_{{$ctrl.customConnectorCustomizationPoints[1]}}"
class="customization-point-block"
ng-click="$ctrl.editConnectorCustomizationPointFn($ctrl.connector, $ctrl.customConnectorCustomizationPoints[1], $event)">
{{$ctrl.customConnectorCustomizationPoints[1]}}
</div>
</div>
<div id="{{$ctrl.connector.name}}_{{$ctrl.customConnectorCustomizationPoints[2]}}"
class="customization-point-block" ng-if="$ctrl.connector.isCustom"
ng-click="$ctrl.editConnectorCustomizationPointFn($ctrl.connector, $ctrl.customConnectorCustomizationPoints[2], $event)">
{{$ctrl.customConnectorCustomizationPoints[2]}}
</div>
</entaxy-connector-block>
`,
controller: entaxyCustomConnectorBlockController
})
.name;
function entaxyCustomConnectorBlockController() {
let ctrl = this;
ctrl.$onInit = function() {
ctrl.customConnectorCustomizationPoints = ctrl.direction === 'in' ?
['custom-route', 'pre-route', 'response'] : ['custom-route', 'pre-output', 'postprocess'];
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,49 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyProfileDiagramExternalSystemPoints', {
bindings: {
connectors: '<',
type: '@'
},
template:
`
<div ng-repeat="connector in $ctrl.connectors" ng-if="$ctrl.connectors && $ctrl.connectors.length > 0"
id="{{$ctrl.type}}-{{connector.name}}-block" class="external-system-point-block">
<span>{{$ctrl.type}}</span>
<div>
<span class="left-bracket"></span>
<span class="connector-info"
data-toggle="tooltip" title="{{connector.protocol}}">{{connector.protocol}}</span>
<span class="right-bracket"></span>
</div>
</div>
`
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,46 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyFlowBlock', {
transclude: true,
bindings: {
direction: '<',
flowName: '<',
editProfilePropertiesFn: '<'
},
template:
`
<div id="{{$ctrl.direction}}-flow-block" class="flow-block"
ng-click="$ctrl.editProfilePropertiesFn($ctrl.direction + '-flow', $event)">
<span>{{$ctrl.flowName}}</span>
<ng-transclude></ng-transclude>
</div>
`
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,58 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyInFlowBlock', {
bindings: {
editProfilePropertiesFn: '<',
editFlowCustomizationPointFn: '<'
},
template:
`
<entaxy-flow-block direction="$ctrl.direction" flow-name="$ctrl.flowName"
edit-profile-properties-fn="$ctrl.editProfilePropertiesFn">
<div id="{{$ctrl.direction}}-flow_{{customizationPoint}}" class="customization-point-block"
ng-repeat="customizationPoint in $ctrl.inFlowCustomizationPoints"
ng-click="$ctrl.editFlowCustomizationPointFn(customizationPoint, $event)">
{{customizationPoint}}
</div>
</entaxy-flow-block>
`,
controller: entaxyInFlowBlockController
})
.name;
function entaxyInFlowBlockController() {
let ctrl = this;
ctrl.$onInit = function() {
ctrl.direction = 'in';
ctrl.flowName = 'IN-FLOW';
ctrl.inFlowCustomizationPoints = ['pre-route', 'response'];
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,62 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyNormalConnectorBlock', {
transclude: true,
bindings: {
direction: '<',
connector: '<',
editConnectorPropertiesFn: '<',
saveConnectorFn: '<',
editConnectorCustomizationPointFn: '<'
},
template:
`
<entaxy-connector-block direction="$ctrl.direction" connector="$ctrl.connector"
edit-connector-properties-fn="$ctrl.editConnectorPropertiesFn"
save-connector-fn="$ctrl.saveConnectorFn">
<div ng-repeat="customizationPoint in $ctrl.connectorCustomizationPoints"
id="{{$ctrl.connector.name}}_{{customizationPoint}}" class="customization-point-block"
ng-click="$ctrl.editConnectorCustomizationPointFn($ctrl.connector, customizationPoint, $event)">
{{customizationPoint}}
</div>
</entaxy-connector-block>
`,
controller: entaxyNormalConnectorBlockController
})
.name;
function entaxyNormalConnectorBlockController() {
let ctrl = this;
ctrl.$onInit = function() {
ctrl.connectorCustomizationPoints = ctrl.direction === 'in' ?
['pre-route', 'response'] : ['pre-output', 'postprocess'];
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,73 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyOutFlowBlock', {
bindings: {
editProfilePropertiesFn: '<',
editFlowCustomizationPointFn: '<'
},
template:
`
<entaxy-flow-block direction="$ctrl.direction" flow-name="$ctrl.flowName"
edit-profile-properties-fn="$ctrl.editProfilePropertiesFn">
<div class="{{$ctrl.direction}}-flow-customization-points-container">
<div id="{{$ctrl.direction}}-flow_{{$ctrl.connectorSelector}}"
class="customization-point-block {{$ctrl.connectorSelector}}"
ng-click="$ctrl.editFlowCustomizationPointFn($ctrl.connectorSelector, $event)"
data-toggle="tooltip" title="{{$ctrl.connectorSelector}}">
<span class="{{$ctrl.connectorSelector}}-icon"></span>
</div>
<div id="{{$ctrl.direction}}-flow_{{$ctrl.preRoute}}"
class="customization-point-block {{$ctrl.preRoute}}"
ng-click="$ctrl.editFlowCustomizationPointFn($ctrl.preRoute, $event)">
{{$ctrl.preRoute}}
</div>
</div>
<div id="{{$ctrl.direction}}-flow_{{$ctrl.postprocess}}"
class="customization-point-block"
ng-click="$ctrl.editFlowCustomizationPointFn($ctrl.postprocess, $event)">
{{$ctrl.postprocess}}
</div>
</entaxy-flow-block>
`,
controller: entaxyOutFlowBlockController
})
.name;
function entaxyOutFlowBlockController() {
let ctrl = this;
ctrl.$onInit = function() {
ctrl.direction = 'out';
ctrl.flowName = 'OUT-FLOW';
ctrl.connectorSelector = 'connector-selector';
ctrl.preRoute = 'pre-route';
ctrl.postprocess = 'postprocess';
}
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,713 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyProfileDiagram', {
template:
`
<div id="leader-lines-container" class="profile-diagram-with-palette-container">
<div class="profile-diagram-container">
<div class="blocks-container">
<entaxy-profile-diagram-external-system-points connectors="$ctrl.inConnectors" type="source">
</entaxy-profile-diagram-external-system-points>
<entaxy-profile-diagram-external-system-points connectors="$ctrl.outConnectors" type="target">
</entaxy-profile-diagram-external-system-points>
</div>
<div droppable handle-drop-fn="$ctrl.handleDropFn(droppedElementId)" class="profile-block"
ng-class="{'has-changes': $ctrl.isProfileChanged}"
ng-click="$ctrl.editProfileProperties('general')">
<div class="profile-title-container">
<span class="profile-diagram-support-span" ng-if="$ctrl.isProfileChanged"></span>
<span class="profile-title">{{$ctrl.profileTitle}}</span>
<span class="pficon pficon-save" ng-click="$ctrl.saveProfile($event)"
data-toggle="tooltip" title="Save profile changes" ng-if="$ctrl.isProfileChanged"></span>
</div>
<entaxy-connectors-with-flow direction="in" connectors="$ctrl.inConnectors"
profile-name="$ctrl.profileName" edit-customization-point-fn="$ctrl.editCustomizationPoint"
ng-if="$ctrl.inConnectors && $ctrl.inConnectors.length > 0" update-fn="$ctrl.update"
edit-profile-properties-fn="$ctrl.editProfileProperties"
edit-properties-fn="$ctrl.editProperties" save-connector-fn="$ctrl.save">
</entaxy-connectors-with-flow>
<entaxy-connectors-with-flow direction="out" connectors="$ctrl.outConnectors"
profile-name="$ctrl.profileName" edit-customization-point-fn="$ctrl.editCustomizationPoint"
ng-if="$ctrl.outConnectors && $ctrl.outConnectors.length > 0" update-fn="$ctrl.update"
edit-profile-properties-fn="$ctrl.editProfileProperties"
edit-properties-fn="$ctrl.editProperties" save-connector-fn="$ctrl.save">
</entaxy-connectors-with-flow>
</div>
<div class="blocks-container">
<div id="integrations-in-block" class="integrations-block"
ng-if="$ctrl.inConnectors && $ctrl.inConnectors.length > 0">
<span>integrations</span>
</div>
<div id="default-route-block" class="default-route-block"
ng-class="{'has-changes': $ctrl.isDefaultRouteChanged}"
ng-click="$ctrl.editDefaultRouteProperties()"
ng-if="$ctrl.inConnectors && $ctrl.inConnectors.length > 0">
<div class="default-route-title-container">
<span class="default-route-title">default-route</span>
<span class="pficon pficon-save" ng-click="$ctrl.saveDefaultRoute($event)"
data-toggle="tooltip" title="Save default route changes"
ng-if="$ctrl.isDefaultRouteChanged"></span>
</div>
<div class="customization-point-block"
ng-click="$ctrl.editDefaultRouteCustomizationPoint($event)">
route
</div>
</div>
<div id="integrations-out-block" class="integrations-block"
ng-if="$ctrl.outConnectors && $ctrl.outConnectors.length > 0">
<span>integrations</span>
</div>
</div>
</div>
<entaxy-profile-diagram-palette></entaxy-profile-diagram-palette>
</div>
`,
controller: entaxyProfileDiagramController
})
.name;
function entaxyProfileDiagramController($scope, workspace, jolokia, $location, $q,
entaxyService, entaxyProfileDiagramService, entaxyAttributesCacheService,
entaxyPrivateObjectsCacheService, $uibModal, $route, $cookies) {
'ngInject';
let ctrl = this;
let selectedMBean = workspace.getSelectedMBean();
let defaultRouteMbean = selectedMBean.findDescendant(child =>
child.objectName && child.objectName.endsWith('route=default'));
ctrl.$onInit = function () {
ctrl.profileName = jolokia.getAttribute(selectedMBean.objectName, 'Name')
ctrl.profileTitle = 'Profile: ' + ctrl.profileName;
ctrl.isProfileChanged = entaxyProfileDiagramService.isProfileChanged();
ctrl.isDefaultRouteChanged = entaxyProfileDiagramService.isDefaultRouteChanged();
populateConnectors();
}
setTimeout(function () {
let contentElement = document.getElementsByClassName("contents")[0];
contentElement.style.setProperty("padding", "0", "important");
}, 10);
function populateConnectors() {
let inConnectors = [];
let outConnectors = [];
if (selectedMBean && selectedMBean.isFolder) {
entaxyService.getAllChildMBeansByRuntimeType(selectedMBean, Entaxy.RUNTIME_TYPE.CONNECTOR)
.then((mbeans) => {
mbeans.forEach((mbean) => {
let direction = mbean.attributes.Direction;
let connectorMbeanName = mbean.mbean.objectName;
let isConnectorChanged = entaxyProfileDiagramService.isConnectorChanged(connectorMbeanName);
let connector = {
name: mbean.attributes.Name,
displayName: mbean.attributes.DisplayName,
classifier: mbean.attributes.Classifier,
protocol: mbean.attributes.Protocol,
mbeanName: connectorMbeanName,
isChanged: isConnectorChanged,
isCustom: mbean.attributes.ObjectLabel ? // fixme object label is bad attr for this purpose
mbean.attributes.ObjectLabel.split(',').includes('custom') : false
};
if (direction === 'in') {
inConnectors.push(connector);
} else if (direction === 'out') {
outConnectors.push(connector);
}
if (isConnectorChanged) {
entaxyProfileDiagramService.getChanges(connectorMbeanName).connector = connector;
}
});
ctrl.inConnectors = inConnectors.sort(Entaxy.compareBy('name'));
ctrl.outConnectors = outConnectors.sort(Entaxy.compareBy('name'));
setMarginForAdditionalBlocks();
if (ctrl.inConnectors.length > 0) {
drawLinesForInDirectedConnectors();
}
if (ctrl.outConnectors.length > 0) {
drawLinesForOutDirectedConnectors();
}
});
}
}
ctrl.handleDropFn = function (factoryName) {
let factory = entaxyService.getFactoryByTitle(factoryName);
let selectedMbeanName = workspace.getSelectedMBeanName();
let parentName = jolokia.getAttribute(selectedMbeanName, 'Name');
let resolve = {
mode: () => Entaxy.MODAL_MODES.ADD,
itemType: () => 'Connector',
parentName: () => parentName,
factories: () => [ factory ]
};
entaxyService.openModalAndProcessResults(resolve, false, null, () => ctrl.connectorAdded = true);
}
// sets top margin for source, target, default-route and integration blocks
function setMarginForAdditionalBlocks() {
setTimeout(function () {
let sourceBlocksOccupiedHeight = 0;
let defaultRouteBlockMarginPlusHeight = 0;
let padding = 10;
if (ctrl.inConnectors && ctrl.inConnectors.length > 0) {
let integrationsInBlock = document.getElementById("integrations-in-block");
let inFlowBlock = document.getElementById("in-flow-block");
let inFlowPreRouteBlock = document.getElementById("in-flow_pre-route");
let defaultRouteBlock = document.getElementById("default-route-block");
let integrationsInBlockHeight = integrationsInBlock.offsetHeight;
let integrationsInBlockMarginTop = inFlowBlock.offsetTop -
integrationsInBlockHeight - padding;
let defaultRouteBlockMarginTop = inFlowPreRouteBlock.offsetTop -
integrationsInBlockMarginTop - integrationsInBlockHeight - padding;
integrationsInBlock.style.marginTop = integrationsInBlockMarginTop + 'px';
defaultRouteBlock.style.marginTop = defaultRouteBlockMarginTop + 'px';
defaultRouteBlockMarginPlusHeight = integrationsInBlockMarginTop + integrationsInBlockHeight +
defaultRouteBlockMarginTop + defaultRouteBlock.offsetHeight;
sourceBlocksOccupiedHeight =
setMarginForSourceOrTargetBlocks(ctrl.inConnectors, true, sourceBlocksOccupiedHeight, padding);
}
if (ctrl.outConnectors && ctrl.outConnectors.length > 0) {
let outFlowPreRouteBlock = document.getElementById("out-flow_pre-route");
let integrationsBlock = document.getElementById("integrations-out-block");
let integrationsBlockMarginTop = outFlowPreRouteBlock.offsetTop -
defaultRouteBlockMarginPlusHeight - padding;
integrationsBlock.style.marginTop = integrationsBlockMarginTop + 'px';
setMarginForSourceOrTargetBlocks(ctrl.outConnectors, false, sourceBlocksOccupiedHeight, padding);
}
});
};
function setMarginForSourceOrTargetBlocks(connectors, isSource, previousBlocksOccupiedHeight, padding) {
connectors.forEach(connector => {
let manageableBlock = isSource ?
document.getElementById("source-" + connector.name + "-block") :
document.getElementById("target-" + connector.name + "-block");
let connectorCustomizationPointBlock = isSource ?
document.getElementById(connector.name + "_pre-route") :
document.getElementById(connector.name + "_pre-output");
let manageableBlockMarginTop = connectorCustomizationPointBlock.offsetTop -
previousBlocksOccupiedHeight - padding;
manageableBlock.style.marginTop = manageableBlockMarginTop + 'px';
previousBlocksOccupiedHeight += manageableBlockMarginTop + manageableBlock.offsetHeight;
});
return previousBlocksOccupiedHeight;
}
let lines = [];
// draws lines for in-directed connector block
function drawLinesForInDirectedConnectors () {
setTimeout(function () {
if (ctrl.inConnectors) {
ctrl.inConnectors.forEach((connector) => {
if (connector.isCustom) {
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('source-' + connector.name + '-block'),
{x: '100%', y: 11}
),
document.getElementById(connector.name + '_custom-route'),
{color: 'green', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
document.getElementById(connector.name + '_custom-route'),
document.getElementById(connector.name + '_pre-route'),
{color: 'green', size: 2, path: 'straight'}
));
} else {
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('source-' + connector.name + '-block'),
{x: '100%', y: 11}
),
document.getElementById(connector.name + '_pre-route'),
{color: 'green', size: 2, path: 'straight'}
));
}
lines.push(new LeaderLine(
document.getElementById(connector.name + '_pre-route'),
document.getElementById('in-flow_pre-route'),
{color: 'green', size: 2, path: 'grid', startSocketGravity: [10, 0]}
));
lines.push(new LeaderLine(
document.getElementById(connector.name + '_response'),
LeaderLine.pointAnchor(
document.getElementById('source-' + connector.name + '-block'),
{x: '100%', y: 43}
),
{color: 'blue', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('in-flow_response'),
{x: 0, y: '50%'}
),
document.getElementById(connector.name + '_response'),
{color: 'blue', size: 2, path: 'grid', startSocketGravity: [-10, 0]}
));
});
lines.push(new LeaderLine(
document.getElementById('in-flow_pre-route'),
LeaderLine.pointAnchor(
document.getElementById('default-route-block'),
{x: 0, y: 11}
),
{color: 'green', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('default-route-block'),
{x: 0, y: 43}
),
document.getElementById('in-flow_response'),
{color: 'blue', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('default-route-block'),
{x: 32.5, y: 0}
),
LeaderLine.pointAnchor(
document.getElementById('integrations-in-block'),
{x: 32.5, y: '100%'}
),
{color: 'green', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('integrations-in-block'),
{x: 64.5, y: '100%'}
),
LeaderLine.pointAnchor(
document.getElementById('default-route-block'),
{x: 64.5, y: 0}
),
{color: 'blue', size: 2, path: 'straight'}
));
}
}, 50);
}
// draws lines for out-directed connector block
function drawLinesForOutDirectedConnectors() {
setTimeout(function () {
if (ctrl.outConnectors) {
ctrl.outConnectors.forEach((connector) => {
if (connector.isCustom) {
lines.push(new LeaderLine(
document.getElementById(connector.name + '_custom-route'),
LeaderLine.pointAnchor(
document.getElementById('target-' + connector.name + '-block'),
{x: '100%', y: 11}
),
{color: 'green', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
document.getElementById(connector.name + '_pre-output'),
document.getElementById(connector.name + '_custom-route'),
{color: 'green', size: 2, path: 'straight'}
));
} else {
lines.push(new LeaderLine(
document.getElementById(connector.name + '_pre-output'),
LeaderLine.pointAnchor(
document.getElementById('target-' + connector.name + '-block'),
{x: '100%', y: 11}
),
{color: 'green', size: 2, path: 'straight'}
));
}
lines.push(new LeaderLine(
document.getElementById('out-flow_pre-route'),
document.getElementById('out-flow_connector-selector'),
{color: 'green', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('out-flow_connector-selector'),
{x: 0, y: '50%'}
),
document.getElementById(connector.name + '_pre-output'),
{color: 'green', size: 2, path: 'grid', startSocketGravity: [-10, 0]}
));
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('target-' + connector.name + '-block'),
{x: '100%', y: 43}
),
document.getElementById(connector.name + '_postprocess'),
{color: 'blue', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
document.getElementById(connector.name + '_postprocess'),
document.getElementById('out-flow_postprocess'),
{color: 'blue', size: 2, path: 'grid', startSocketGravity: [10, 0]}
));
})
lines.push(new LeaderLine(
LeaderLine.pointAnchor(
document.getElementById('integrations-out-block'),
{x: 0, y: 11}
),
document.getElementById('out-flow_pre-route'),
{color: 'green', size: 2, path: 'straight'}
));
lines.push(new LeaderLine(
document.getElementById('out-flow_postprocess'),
LeaderLine.pointAnchor(
document.getElementById('integrations-out-block'),
{x: 0, y: 43}
),
{color: 'blue', size: 2, path: 'straight'}
));
}
}, 50);
}
// reposition of lines while container size is changed without changing window size
let resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target.handleResize) {
entry.target.handleResize(entry);
}
}
});
setTimeout(function () {
document.querySelector('#leader-lines-container').handleResize = entry => {
lines.forEach(line => line.position());
}
resizeObserver.observe(document.querySelector('#leader-lines-container'));
}, 10);
// reposition of lines on scroll event
setTimeout(function () {
let leaderLinesContainerElement = document.getElementById("leader-lines-container");
leaderLinesContainerElement.onscroll = (event) => {
lines.forEach(line => line.position());
};
}, 10);
$scope.$on(Jmx.TreeEvent.Updated, () => {
if (ctrl.connectorAdded) {
$route.reload();
}
});
$scope.$on('$destroy', function () {
lines.forEach(line => line.remove());
resizeObserver.disconnect();
$cookies.remove('profile-properties-group');
});
ctrl.editProfileProperties = function (groupName) {
$cookies.putObject('profile-properties-group', groupName);
let selectedMbeanName = workspace.getSelectedMBeanName();
let profile = createItem(selectedMbeanName);
ctrl.editProperties(profile, Entaxy.RUNTIME_TYPE.PROFILE, 'Profile');
}
ctrl.editDefaultRouteProperties = function () {
let defaultRouteMbeanName = defaultRouteMbean.objectName;
let defaultRoute = createItem(defaultRouteMbeanName);
ctrl.editProperties(defaultRoute, Entaxy.RUNTIME_TYPE.DEFAULT_ROUTE, 'Default Route');
}
function createItem(mbeanName) {
let attributes = entaxyAttributesCacheService.getAttributes(mbeanName);
return {
name: attributes.Name,
mbeanName: mbeanName
};
}
ctrl.editProperties = function (item, runtimeType, itemType) {
entaxyService.readObjectClusterState(item.mbeanName).then(objectClusterState => {
let isNonClustered = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED;
if (isNonClustered) {
Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.EDITING);
}
let mode = isNonClustered ? Entaxy.MODAL_MODES.VIEW : Entaxy.MODAL_MODES.EDIT;
item.isLocal = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
let args = entaxyProfileDiagramService.hasChanges(item.mbeanName) ?
entaxyProfileDiagramService.getArgs(item.mbeanName) : undefined;
let properties = args ? args.fields.filter(field => field.name !== 'routes') : undefined;
entaxyService.openEditItemModalAndProcessResults(item, itemType, runtimeType, mode,
properties, ctrl.update);
}).catch(e => Entaxy.notificationError(e));
}
ctrl.editDefaultRouteCustomizationPoint = function (event) {
event.stopPropagation();
if (defaultRouteMbean) {
ctrl.editCustomizationPoint(defaultRouteMbean.objectName, 'routeContent');
} else {
Entaxy.notificationError('Default route is not found.');
}
}
ctrl.editCustomizationPoint = function (mbeanName, propertyName, connector) {
if (entaxyProfileDiagramService.hasChanges(mbeanName)) {
let changes = entaxyProfileDiagramService.getChanges(mbeanName);
processPropertyAndOpenXmlEditor(changes, propertyName, mbeanName, true);
} else {
entaxyService.readConfiguration(mbeanName)
.then(objectInfo => {
let args = entaxyService.getArgumentsFromConfig(objectInfo);
let changes = entaxyProfileDiagramService.createChangesConfig(mbeanName, objectInfo.objectId,
args, objectInfo.configurableOnly, connector);
processPropertyAndOpenXmlEditor(changes, propertyName, mbeanName);
}).catch(error => {
Entaxy.notificationError(error);
Entaxy.log.error(error);
});
}
}
function processPropertyAndOpenXmlEditor(changes, propertyName, mbeanName, isRoutesFieldResolved) {
let args = changes.args;
let property = args.fields.find(property => property.name === propertyName);
if (property.value) {
if (isRoutesFieldResolved) {
resolveConfirmationAndOpenXmlEditor(changes, property, propertyName, mbeanName);
} else {
let selectedMbean = workspace.getSelectedMBean();
let mbean = selectedMbean.objectName === mbeanName ?
selectedMbean : selectedMbean.findDescendant(child => child.objectName === mbeanName);
entaxyService.resolveRoutesFieldValueAndAddNew(args, mbean)
.then(() => {
resolveConfirmationAndOpenXmlEditor(changes, property, propertyName, mbeanName);
});
}
} else {
Entaxy.notificationError('Content is not found');
}
}
function resolveConfirmationAndOpenXmlEditor(changes, property, propertyName, mbeanName) {
entaxyService.readObjectClusterState(mbeanName).then(objectClusterState => {
let isNonClustered = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED;
if (isNonClustered) {
Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.EDITING);
}
if (changes.configurableOnly || isNonClustered) {
getXmlAndOpenEditor(property, mbeanName, true, changes);
} else {
let args = changes.args;
let factoryMbeanName = args.factoryId.mbeanName;
entaxyService.getFields(factoryMbeanName).then(response => {
let fields = JSON.parse(response);
let currentField = fields.find(field => field.name === propertyName);
const UI = '@UI';
let managedByFieldName = currentField[UI] ? currentField[UI].managedBy : undefined;
if (managedByFieldName) {
let managingFieldProperty = args.fields
.find(field => field.name === managedByFieldName);
if (managingFieldProperty.value) {
getXmlAndOpenEditor(property, mbeanName, changes.configurableOnly, changes);
} else {
let managingField = fields.find(field => field.name === managedByFieldName);
let title = 'Confirm editing';
let message = managingField.displayName + ' is currently disabled. ' +
'Do you want to enable it and edit the ' + currentField.displayName + '?';
entaxyService.openConfirmationWindow(title, message).then(() => {
managingFieldProperty.value = true;
getXmlAndOpenEditor(property, mbeanName, changes.configurableOnly, changes);
});
}
} else {
getXmlAndOpenEditor(property, mbeanName, changes.configurableOnly, changes);
}
});
}
}).catch(e => Entaxy.notificationError(e));
}
function getXmlAndOpenEditor(property, mbeanName, readOnly, changes) {
entaxyService.getXmlFromConfigPropertyValue(property.value)
.then(xml => openXmlEditor(xml, property, mbeanName, readOnly, changes));
}
function openXmlEditor(originXml, property, mbeanName, readOnly, changes) {
$uibModal.open({
component: 'entaxyXmlModal',
resolve: {
xml: () => originXml,
mode: () => readOnly ? Entaxy.MODAL_MODES.VIEW : Entaxy.MODAL_MODES.EDIT
},
size: 'xl',
backdrop: 'static',
windowTopClass: 'modal-top-margin-override'
})
.result.then(xml => {
if (xml && xml.trim().length > 0) { // fixme
property.value = Entaxy.stringToBase64(xml);
if (!entaxyProfileDiagramService.hasChanges(mbeanName)) {
entaxyProfileDiagramService.setChanges(mbeanName, changes);
}
if (entaxyProfileDiagramService.hasType(mbeanName, Entaxy.RUNTIME_TYPE.PROFILE)) {
entaxyProfileDiagramService.setProfileChanged();
ctrl.isProfileChanged = entaxyProfileDiagramService.isProfileChanged();
} else if (entaxyProfileDiagramService.hasType(mbeanName, Entaxy.RUNTIME_TYPE.DEFAULT_ROUTE)) {
entaxyProfileDiagramService.setDefaultRouteChanged();
ctrl.isDefaultRouteChanged = entaxyProfileDiagramService.isDefaultRouteChanged();
} else if (entaxyProfileDiagramService.hasType(mbeanName, Entaxy.RUNTIME_TYPE.CONNECTOR)) {
entaxyProfileDiagramService.setConnectorChanged(mbeanName, true);
}
entaxyProfileDiagramService.setDirty();
} else {
Entaxy.notificationError('Value cannot be empty');
}
});
}
ctrl.saveProfile = function (event) {
event.stopPropagation();
ctrl.save(selectedMBean.objectName, true, true);
}
ctrl.saveDefaultRoute = function (event) {
event.stopPropagation();
ctrl.save(defaultRouteMbean.objectName, false);
}
ctrl.save = function (mbeanName, isConfirmationNeeded, isProfile) {
if (entaxyPrivateObjectsCacheService.isChanged(mbeanName) && isConfirmationNeeded) {
let title = 'Confirm Saving';
let type = isProfile ? 'Profile' : 'Connector';
let message = type + ' has unsaved changes of routes which will also be applied. ' +
'Do you want to continue?';
entaxyService.openConfirmationWindow(title, message).then(() => save(mbeanName));
} else {
save(mbeanName);
}
}
function save(mbeanName) {
let args = entaxyProfileDiagramService.getArgs(mbeanName);
entaxyService.resolveResourceRefFields(args.fields)
.then(() => entaxyService.saveItem(args, false, ctrl.update));
}
ctrl.update = function (properties, objectId) {
entaxyProfileDiagramService.resetChanges(objectId);
ctrl.isProfileChanged = entaxyProfileDiagramService.isProfileChanged();
ctrl.isDefaultRouteChanged = entaxyProfileDiagramService.isDefaultRouteChanged();
}
setTimeout( function () {
ctrl.activeTabIndex = entaxyService.getActiveTabIndex();
})
$scope.$on("$locationChangeStart", function(event) {
if (entaxyProfileDiagramService.isDirty()) {
if (!confirm(Entaxy.CONFIRMATION.UNSAVED_CHANGES)) {
event.preventDefault();
ctrl.isTreeOrTabSelectionUpdateNeeded = true;
} else {
entaxyProfileDiagramService.clear();
}
} else {
entaxyProfileDiagramService.clear();
}
});
$scope.$watch('$ctrl.isTreeOrTabSelectionUpdateNeeded', function (newValue) {
if (newValue) {
setTimeout(function () {
entaxyService.updateTabSelection(ctrl.activeTabIndex);
});
Jmx.updateTreeSelectionFromURL($location, $(entaxyTreeElementId));
ctrl.isTreeOrTabSelectionUpdateNeeded = false;
}
});
}
entaxyProfileDiagramController.$inject = ['$scope', 'workspace', 'jolokia', '$location', '$q',
'entaxyService', 'entaxyProfileDiagramService', 'entaxyAttributesCacheService',
'entaxyPrivateObjectsCacheService', '$uibModal', '$route', '$cookies'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,156 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyProfileDiagramPalette', {
template:
`
<div class="profile-diagram-palette">
<div class="profile-diagram-palette-title">
<span>
Connectors Palette
</span>
<input type="search" class="form-control" placeholder="Search..." ng-model="$ctrl.filter"
ng-keypress="$ctrl.onValueKeyPress($event)">
</div>
<uib-accordion>
<div class="profile-diagram-palette-group-container">
<entaxy-profile-diagram-palette-group heading="---IN---" is-open="$ctrl.isInGroupOpened"
factories="$ctrl.viewedInFactories"></entaxy-profile-diagram-palette-group>
<entaxy-profile-diagram-palette-group heading="---OUT---" is-open="$ctrl.isOutGroupOpened"
factories="$ctrl.viewedOutFactories"></entaxy-profile-diagram-palette-group>
</div>
</uib-accordion>
</div>
`,
controller: entaxyProfileDiagramPaletteController
})
.component('entaxyProfileDiagramPaletteGroup', {
bindings: {
heading: '@',
isOpen: '=',
factories: '<'
},
template:
`
<div uib-accordion-group class="panel-default" heading="{{$ctrl.heading}}" is-open="$ctrl.isOpen">
<div class="profile-diagram-palette-items-container">
<div draggable class="profile-diagram-palette-item" id="{{factory.name}}"
ng-repeat="factory in $ctrl.factories"
data-toggle="tooltip" title="{{factory.description}}">
<span>{{ factory.displayName }}</span>
</div>
</div>
</div>
`
})
.name;
function entaxyProfileDiagramPaletteController($scope, jolokia, entaxyService, $cookies) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function () {
populateConnectorFactories();
ctrl.isInGroupOpened = $cookies.getObject('diagram-palette-in-group-opened');
ctrl.isOutGroupOpened = $cookies.getObject('diagram-palette-out-group-opened');
}
function populateConnectorFactories() {
let factories = [];
let factoryFolder = entaxyService.getFolderByTitle(Entaxy.RUNTIME_TYPE.CONNECTOR);
if (factoryFolder && factoryFolder.children) {
factoryFolder.children.forEach((child) => {
let attributes = jolokia.getAttribute(child.objectName);
if (!attributes.Abstract) {
factories.push({
name: attributes.Id,
displayName: attributes.ShortName ? attributes.ShortName : attributes.Id,
mbeanName: child.objectName,
description: attributes.Description ?
attributes.Description.replace(/(<([^>]+)>)/ig, '') :
'There is no description for this factory.',
direction: attributes.TypeInfo.direction,
label: attributes.Label
});
}
});
}
ctrl.inFactories = factories.filter(factory => factory.direction === 'in')
.sort(Entaxy.compareBy('displayName'));
ctrl.outFactories = factories.filter(factory => factory.direction === 'out')
.sort(Entaxy.compareBy('displayName'));
ctrl.viewedInFactories = ctrl.inFactories;
ctrl.viewedOutFactories = ctrl.outFactories;
}
$scope.$watch('$ctrl.isInGroupOpened', function (newValue) {
$cookies.putObject('diagram-palette-in-group-opened', newValue);
});
$scope.$watch('$ctrl.isOutGroupOpened', function (newValue) {
$cookies.putObject('diagram-palette-out-group-opened', newValue);
});
ctrl.onValueKeyPress = function (keyEvent) {
if (keyEvent.key === 'Enter') {
keyEvent.stopPropagation();
keyEvent.preventDefault();
if (ctrl.filter && ctrl.filter.length > 0) {
filter(ctrl.filter);
} else {
ctrl.viewedInFactories = ctrl.inFactories;
ctrl.viewedOutFactories = ctrl.outFactories;
}
}
}
function filter(filter) {
ctrl.viewedInFactories = ctrl.inFactories.filter(factory => matchesFilter(factory, filter));
ctrl.viewedOutFactories = ctrl.outFactories.filter(factory => matchesFilter(factory, filter));
}
function matchesFilter(factory, filter) {
let match = false;
if (factory.displayName.toLowerCase().match(filter.toLowerCase()) !== null &&
(factory.label && factory.label.toLowerCase().match(filter.toLowerCase()) !== null)) {
match = true
}
return match;
}
}
entaxyProfileDiagramPaletteController.$inject = ['$scope', 'jolokia', 'entaxyService', '$cookies'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -61,13 +61,14 @@ var Entaxy;
})
.name;
function entaxyPropertiesController($scope, workspace, entaxyService, jolokia, $location, $route,
function entaxyPropertiesController($scope, workspace, entaxyService, jolokia, $location, $route, entaxyHotkeysService,
entaxyAttributesCacheService, entaxyPrivateObjectsCacheService) {
'ngInject';
let ctrl = this;
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.mode = Entaxy.MODAL_MODES.EDIT;
@ -100,13 +101,19 @@ var Entaxy;
ctrl.hasChangedPrivateObjects = true;
}
entaxyService.readObjectClusterState(mbeanName).then(objectClusterState => {
if (objectClusterState !== Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
ctrl.local = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
} else {
ctrl.mode = Entaxy.MODAL_MODES.VIEW;
}
}).catch(e => Entaxy.notificationError(e));
if (attributes.RuntimeType === Entaxy.RUNTIME_TYPE.CONNECTION && attributes.Platform) {
ctrl.mode = Entaxy.MODAL_MODES.VIEW;
}
if (ctrl.mode !== Entaxy.MODAL_MODES.VIEW) {
entaxyService.readObjectClusterState(mbeanName).then(objectClusterState => {
if (objectClusterState !== Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
ctrl.local = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
} else {
ctrl.mode = Entaxy.MODAL_MODES.VIEW;
}
}).catch(e => Entaxy.notificationError(e));
}
if (!ctrl.itemInfo) {
entaxyService.readConfiguration(mbeanName)
@ -174,7 +181,9 @@ var Entaxy;
ctrl.itemInfo.configurableOnly, ctrl.mode);
if (formField) {
ctrl.formFields.push(formField);
groups.add(formField.group);
if (!formField.isBackRef && !formField.isHidden) {
groups.add(formField.group);
}
}
});
@ -203,6 +212,8 @@ var Entaxy;
}
$scope.$watch('$ctrl.definingFormFields[' + i + '].value', function(newValue, oldValue) {
if (newValue !== oldValue) {
Entaxy.changingFieldValueNotification('defining');
entaxyService.processDependencies(dependentFormFields,
ctrl.definingFormFields,
ctrl.definingFormFields[i].name,
@ -244,7 +255,7 @@ var Entaxy;
}
function save() {
entaxyService.validateFields(ctrl.formFields, ctrl.factories[0], ctrl.itemName)
entaxyService.validateFields(ctrl.formFields, ctrl.factories[0])
.then(errors => {
ctrl.errors = errors;
@ -284,7 +295,7 @@ var Entaxy;
}
function saveAll() {
entaxyService.validateFields(ctrl.formFields, ctrl.factories[0], ctrl.itemName)
entaxyService.validateFields(ctrl.formFields, ctrl.factories[0])
.then(errors => {
ctrl.errors = errors;
@ -384,8 +395,31 @@ var Entaxy;
$scope.$on(Jmx.TreeEvent.Updated, () => {
$route.reload();
});
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
if (!ctrl.isReadOnly()) {
ctrl.save();
}
}
},
{
...Entaxy.getSaveAllHotkeyDescription(),
callback: function(event) {
event.preventDefault();
if (ctrl.private && !ctrl.isReadOnly() && (ctrl.isOwnerChanged || ctrl.isFormDirty)) {
ctrl.saveAll();
}
}
}
];
}
}
entaxyPropertiesController.$inject = ['$scope', 'workspace', 'entaxyService', 'jolokia', '$location', '$route',
'entaxyAttributesCacheService', 'entaxyPrivateObjectsCacheService'];
'entaxyHotkeysService', 'entaxyAttributesCacheService', 'entaxyPrivateObjectsCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -61,15 +61,16 @@ var Entaxy;
<div class="resources-file-drop-zone" entaxy-file-drop ng-model="$ctrl.file"
process-fn="$ctrl.upload($ctrl.file)">
<div class="file-panel-container" context-menu context-menu-options="$ctrl.contextMenuOptions">
<entaxy-file-panel items="$ctrl.items" selected-item="$ctrl.selectedItem" view="$ctrl.view"
<entaxy-file-panel items="$ctrl.items" selected-items="$ctrl.selectedItems" view="$ctrl.view"
change-selection-fn="$ctrl.changeSelection" open-fn="$ctrl.open"
resource-context-menu-options="$ctrl.resourceContextMenuOptions"
adm-resource-context-menu-options="$ctrl.admResourceContextMenuOptions"
folder-context-menu-options="$ctrl.folderContextMenuOptions"></entaxy-file-panel>
</div>
<div class="meta-info" resizable r-directions="['left']"
ng-if="$ctrl.selectedItem && $ctrl.selectedItem.metadata">
ng-if="$ctrl.selectedItems && $ctrl.selectedItems.length == 1 && $ctrl.selectedItems[0].metadata">
<uib-tabset active="$ctrl.activeTab" class="meta-tabs">
<uib-tab ng-repeat="(section, info) in $ctrl.selectedItem.metadata track by $index"
<uib-tab ng-repeat="(section, info) in $ctrl.selectedItems[0].metadata track by $index"
heading="{{section}}">
<div class="json-formatter">
<json-formatter json="info" open="1"></json-formatter>
@ -83,8 +84,8 @@ var Entaxy;
})
.name;
function entaxyResourcesController(workspace, $scope, jolokia, entaxyService, entaxyResourcesService,
$timeout, $uibModal, $cookies) {
function entaxyResourcesController(workspace, $scope, jolokia, entaxyService, entaxyResourcesService, $timeout,
$uibModal, $cookies, entaxyHotkeysService, $q, $window, $location, $route) {
'ngInject';
let ctrl = this;
@ -98,62 +99,79 @@ var Entaxy;
name: 'Create folder',
actionFn: createFolder
},
{
name: 'Create resource',
actionFn: createResource
},
{
name: 'Upload',
actionFn: uploadResource
},
{
name: 'Paste',
actionFn: pasteResource
actionFn: pasteResources
}
];
ctrl.resourceContextMenuOptions = [
{
name: 'Download',
actionFn: downloadResource
},
let commonContextMenuOptions = [
{
name: 'Copy',
actionFn: copyResource
actionFn: copyResources
},
{
name: 'Cut',
actionFn: cutResource
actionFn: cutResources
},
{
name: 'Remove',
actionFn: removeResource
actionFn: removeResources
},
{
divider: true
}
].concat(ctrl.contextMenuOptions);
];
ctrl.resourceContextMenuOptions = [
{
name: 'Download',
actionFn: downloadResources
}
].concat(commonContextMenuOptions).concat(ctrl.contextMenuOptions);
ctrl.admResourceContextMenuOptions = [
{
name: 'Open in new tab',
actionFn: openTransformationEditorInTab
}
].concat(ctrl.resourceContextMenuOptions);
ctrl.folderContextMenuOptions = [
{
name: 'Paste to folder',
actionFn: pasteResourceToFolder
},
{
name: 'Remove',
actionFn: removeResource
},
{
divider: true
}
].concat(ctrl.contextMenuOptions);
].concat(commonContextMenuOptions).concat(ctrl.contextMenuOptions);
ctrl.$onInit = function () {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
ctrl.view = 'list';
ctrl.protocol = jolokia.getAttribute(selectedMbeanName, 'Protocol');
let path = $cookies.getObject(ctrl.protocol);
ctrl.crumbs = path ? path.split('/') : [];
}
let locationNid = $location.search() ? $location.search().nid : undefined;
$scope.$on('jmxTreeClicked', function () {
const currentLocationNid = $location.search() ? $location.search().nid : undefined;
if (locationNid !== currentLocationNid) {
locationNid = currentLocationNid;
$route.reload();
}
});
$scope.$watchCollection('$ctrl.crumbs', function() {
ctrl.selectedItem = null;
ctrl.selectedItems = [];
ctrl.location = ctrl.isFullLocationView ? getFullLocation() : getLocation();
$cookies.putObject(ctrl.protocol, getPath());
@ -170,40 +188,179 @@ var Entaxy;
ctrl.isFullLocationView = !ctrl.isFullLocationView;
}
ctrl.changeSelection = function (item) {
ctrl.selectedItem = item;
ctrl.changeSelection = function (item, isMultiple) {
if (!isMultiple) {
ctrl.selectedItems = [ item ];
} else {
if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
if (ctrl.selectedItems.includes(item)) {
ctrl.selectedItems = ctrl.selectedItems.filter(it => it.name !== item.name);
} else {
ctrl.selectedItems.push(item);
}
} else {
ctrl.selectedItems = [ item ];
}
}
ctrl.location = ctrl.isFullLocationView ? getFullLocation() : getLocation();
$timeout(function () {
ctrl.activeTab = 0;
});
}
function createResource () {
entaxyResourcesService.openResourceNameInputModal({ isFolder: false },
ctrl.items.map((item) => item.name), false, false)
.then((name) => {
saveResource(
getPath() + '/' + name,
'',
'Resource ' + name + ' was successfully added',
true,
name);
});
}
ctrl.open = function (item) {
if (item.isFolder === true) {
ctrl.crumbs.push(item.name);
} else {
let splitName = item.name.split('.');
let extension = splitName.length > 1 ? splitName.pop() : undefined;
if (extension === 'adm') {
openTransformationEditor(item);
} else {
openEditor(item, extension);
}
}
}
function updateItems() {
function openEditor(item, extension) {
let location = getFullLocation();
entaxyResourcesService.getResource(location, true).then(resourceContent => {
$uibModal.open({
component: 'entaxyEditorModal',
resolve: {
resourceName: () => item.name,
resourceContent: () => resourceContent,
extension: () => extension,
names: () => ctrl.items.map((item) => item.name)
},
size: 'xl',
backdrop: 'static'
})
.result.then(data => {
if (data.writeIntoSource) {
saveResource(
getLocationWithoutProtocol(),
data.content,
'Resource ' + item.name + ' was successfully edited',
false);
} else {
let path = getPath();
let separator = path.length > 0 ? '/' : '';
saveResource(
path + separator + data.name,
data.content,
'Resource ' + data.name + ' was successfully added',
true,
data.name);
}
});
});
}
function openTransformationEditor(item) {
let location = getLocation();
$location.search('location', location);
$uibModal.open({
component: 'entaxyAtlasmapConsoleModal',
resolve: {
resourceName: () => item.name,
names: () => ctrl.items.map((item) => item.name),
location: () => location
},
size: 'xxl',
backdrop: 'static'
}).result
.then((newName) => {
$location.search('location', null);
if (newName) {
Entaxy.notificationSuccess('Resource ' + newName + ' was successfully added');
updateItems(newName);
} else {
Entaxy.notificationSuccess('Resource ' + item.name + ' was successfully edited');
}
})
.catch((reason) => {
$location.search('location', null);
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function openTransformationEditorInTab() {
let currentLocation = $location.absUrl();
let finalLocation = currentLocation.substring(0, currentLocation.indexOf('entaxy-management'))
.concat('entaxy-transformation?location=').concat(getLocation());
$window.open(finalLocation, '_blank');
}
function saveResource(path, content, notificationMessage, isUpdateNeeded, selectAfterSavingByName) {
entaxyResourcesService
.saveResource(selectedMbeanName, path, content)
.then(() => {
Entaxy.notificationSuccess(notificationMessage);
if (isUpdateNeeded) {
updateItems(selectAfterSavingByName);
}
}).catch(error => {
Entaxy.notificationError(error);
Entaxy.log.error(error);
});
}
function updateItems(selectByName) {
let path = getPath();
entaxyResourcesService.getResourcesInfo(selectedMbeanName, path)
.then(originItems => {
items = originItems
let items = originItems
.concat(entaxyResourcesService.getClientFoldersToAdd(clientFolders, originItems, ctrl.crumbs));
ctrl.items = items.sort(Entaxy.compareBy('name')).sort((a, b) => b.isFolder - a.isFolder);
if (selectByName) {
let itemToSelect = ctrl.items.find(item => item.name === selectByName);
ctrl.changeSelection(itemToSelect);
scrollToItem();
}
})
}
function scrollToItem() {
setTimeout(function () {
let element = ctrl.view === 'tiles' ?
document.getElementsByClassName('tile active')[0] :
document.getElementsByClassName('list active')[0];
element.scrollIntoView();
});
}
function getPath() {
return entaxyResourcesService.getPath(ctrl.crumbs);
}
function getLocationWithoutProtocol(folderSelectionEnabled) {
let isItemSelected = ctrl.selectedItem &&
(!ctrl.selectedItem.isFolder || (folderSelectionEnabled && ctrl.selectedItem.isFolder));
let isItemSelected = ctrl.selectedItems && ctrl.selectedItems.length == 1 &&
(!ctrl.selectedItems[0].isFolder || (folderSelectionEnabled && ctrl.selectedItems[0].isFolder));
let separator = getPath().length > 0 && isItemSelected ? '/' : '';
let selectedItemName = isItemSelected ? ctrl.selectedItem.name : '';
let selectedItemName = isItemSelected ? ctrl.selectedItems[0].name : '';
return getPath() + separator + selectedItemName;
}
@ -223,48 +380,57 @@ var Entaxy;
ctrl.triggerUpload();
}
function downloadResource(item) {
function downloadResources() {
let path = getLocationWithoutProtocol(true);
let path = isItemSelected(item) ?
getLocationWithoutProtocol(true) :
getLocationWithoutProtocol(true) + '/' + item.name;
entaxyResourcesService.downloadResource(selectedMbeanName, path)
.then(result => {
entaxyService.downloadFileFromBase64StringContent(result, item.name);
}).catch(error => {
Entaxy.notificationError(error);
Entaxy.log.error(error);
ctrl.selectedItems.forEach(item => {
let fullPath = ctrl.selectedItems.length > 1 ? path + '/' + item.name : path;
entaxyResourcesService.downloadResource(selectedMbeanName, fullPath)
.then(result => {
entaxyService.downloadFileFromBase64StringContent(result, item.name);
}).catch(error => {
Entaxy.notificationError(error);
Entaxy.log.error(error);
});
});
}
function copyResource(item) {
setCopyConfig(item, false);
function copyResources() {
processCopyCut(false);
}
function cutResource(item) {
setCopyConfig(item, true);
function cutResources() {
processCopyCut(true);
}
function processCopyCut(removeSource) {
if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
Entaxy.resourceCopyConfigs = {};
ctrl.selectedItems.forEach(item => {
setCopyConfig(item, removeSource);
});
}
}
function setCopyConfig(item, removeSource) {
Entaxy.resourceCopyConfig.sourceResourcePath = isItemSelected(item) ?
let sourceResourcePath = ctrl.selectedItems && ctrl.selectedItems.length == 1 ?
getLocation(true) : getLocation(true) + '/' + item.name;
Entaxy.resourceCopyConfig.sourceResourceName = item.name;
Entaxy.resourceCopyConfig.removeSource = removeSource;
Entaxy.resourceCopyConfigs[item.name] = {
sourceResourcePath: sourceResourcePath,
removeSource: removeSource
};
}
function pasteResource() {
if (Entaxy.resourceCopyConfig.sourceResourcePath) {
function pasteResources() {
if (Object.keys(Entaxy.resourceCopyConfigs).length > 0) {
let path = getPath();
pasteWithUniquenessCheck(ctrl.items, path);
}
}
function pasteResourceToFolder(item) {
if (Entaxy.resourceCopyConfig.sourceResourcePath) {
let path = isItemSelected(item) ?
getLocationWithoutProtocol(true) :
getLocationWithoutProtocol(true) + '/' + item.name;
function pasteResourceToFolder() {
if (Object.keys(Entaxy.resourceCopyConfigs).length > 0) {
let path = getLocationWithoutProtocol(true);
entaxyResourcesService.getResourcesInfo(selectedMbeanName, path)
.then(items => {
@ -278,40 +444,43 @@ var Entaxy;
}
function pasteWithUniquenessCheck(items, path) {
let copiedDuplicateItem = items.find(item => item.name === Entaxy.resourceCopyConfig.sourceResourceName);
if (copiedDuplicateItem && !copiedDuplicateItem.isFolder) {
$uibModal.open({
component: 'entaxySimpleResourceNameInputModal',
resolve: {
title: () => 'Change resource name',
names: () => items.filter((item) => !item.isFolder).map((item) => item.name),
name: () => Entaxy.resourceCopyConfig.sourceResourceName,
type: () => 'Resource'
},
size: 'sm-custom',
backdrop: 'static',
windowTopClass: 'modal-top-margin-center-override'
})
.result.then(name => {
paste(Entaxy.resourceCopyConfig.sourceResourcePath, path, name);
});
} else {
paste(Entaxy.resourceCopyConfig.sourceResourcePath, path, Entaxy.resourceCopyConfig.sourceResourceName);
let copiedDuplicateItems = [];
let namesToPaste = Object.keys(Entaxy.resourceCopyConfigs);
items.forEach(item => {
if (namesToPaste.includes(item.name)) {
copiedDuplicateItems.push(item);
}
});
if (copiedDuplicateItems.length > 0) {
for (let i = copiedDuplicateItems.length - 1; i >= 0; i--) {
renameResourceAndPaste(copiedDuplicateItems[i], path);
}
}
let copiedDuplicateItemsNames = copiedDuplicateItems.map(item => item.name);
namesToPaste.filter(name => !copiedDuplicateItemsNames.includes(name)).forEach(name => {
paste(Entaxy.resourceCopyConfigs[name].sourceResourcePath, path, name,
Entaxy.resourceCopyConfigs[name].removeSource);
});
}
function paste(from, to, name) {
function renameResourceAndPaste(item, path) {
entaxyResourcesService.openResourceNameInputModal(item, ctrl.items.map((item) => item.name), true, false)
.then(name => {
paste(Entaxy.resourceCopyConfigs[item.name].sourceResourcePath, path, name,
Entaxy.resourceCopyConfigs[item.name].removeSource);
});
}
function paste(from, to, name, removeSource) {
const fullToPath = to + '/' + name;
entaxyResourcesService.pasteResource(selectedMbeanName, from, fullToPath)
.then(result => {
if (Entaxy.resourceCopyConfig.removeSource) {
entaxyResourcesService.removeResource(selectedMbeanName,
Entaxy.resourceCopyConfig.sourceResourcePath)
if (removeSource) {
entaxyResourcesService.removeResource(selectedMbeanName, from)
.then(result => {
Entaxy.resourceCopyConfig.sourceResourcePath = ctrl.protocol + ':' + fullToPath;
Entaxy.resourceCopyConfig.sourceResourceName = name;
Entaxy.resourceCopyConfig.removeSource = false;
let configToRemove = Object.entries(Entaxy.resourceCopyConfigs)
.find(([name, config]) => config.sourceResourcePath === from);
delete Entaxy.resourceCopyConfigs[configToRemove[0]];
updateItems();
}).catch(error => {
Entaxy.notificationError(error);
@ -326,33 +495,50 @@ var Entaxy;
});
}
function removeResource(item) {
let title = 'Confirm Removing Resource';
let resourceType = item.isFolder ? 'folder' : 'resource';
let message = 'Do you want to remove ' + resourceType + ' ' + item.name + '?';
function removeResources() {
if (ctrl.selectedItems && ctrl.selectedItems.length > 0) {
removeSelectedResources();
}
}
function removeSelectedResources() {
let title = 'Confirm Removing Resources';
let message = 'Do you want to remove selected resources?';
entaxyService.openConfirmationWindow(title, message)
.then(() => {
let path = isItemSelected(item) ?
getLocationWithoutProtocol(true) :
getLocationWithoutProtocol(true) + '/' + item.name;
entaxyResourcesService.removeResource(selectedMbeanName, path)
.then((result) => {
Entaxy.notificationSuccess('Resource ' + item.name + ' was successfully removed');
if (isItemSelected(item)) {
ctrl.selectedItem = undefined;
let promises = [];
let failedResources = [];
let path = getLocationWithoutProtocol(true);
ctrl.selectedItems.forEach(item => {
let fullPath = ctrl.selectedItems.length > 1 ? path + '/' + item.name : path;
promises.push(
entaxyResourcesService
.removeResource(selectedMbeanName, fullPath)
.catch((error) => {
failedResources.push(fullPath);
Entaxy.log.error(error);
})
);
});
$q.all(promises).then(result => {
if (failedResources.length > 0) {
let message = 'Errors occurred while removing resources';
Entaxy.notificationError(message);
} else {
Entaxy.notificationSuccess('Resources were successfully removed');
}
ctrl.selectedItems = [];
updateItems();
})
.catch((error) => {
Entaxy.log.error(error);
Entaxy.notificationError('An error occurred while removing resource ' + item.name);
}).catch(error => {
Entaxy.notificationError(error);
EntaxyCICD.log.error(error);
});
});
}
function isItemSelected(item) {
return ctrl.selectedItem && ctrl.selectedItem.name === item.name;
return ctrl.selectedItems && ctrl.selectedItems.includes(item);
}
ctrl.triggerUpload = function () {
@ -375,8 +561,41 @@ var Entaxy;
});
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getCopyHotkeyDescription(),
callback: function (event) {
event.preventDefault();
copyResources();
}
},
{
...Entaxy.getCutHotkeyDescription(),
callback: function(event) {
event.preventDefault();
cutResources();
}
},
{
...Entaxy.getPasteHotkeyDescription(),
callback: function(event) {
event.preventDefault();
pasteResources();
}
},
{
...Entaxy.getRemoveHotkeyDescription(),
callback: function(event) {
event.preventDefault();
removeResources();
}
}
];
}
}
entaxyResourcesController.$inject = ['workspace', '$scope', 'jolokia', 'entaxyService', 'entaxyResourcesService',
'$timeout', '$uibModal', '$cookies'];
'$timeout', '$uibModal', '$cookies', 'entaxyHotkeysService', '$q', '$window', '$location', '$route'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -49,7 +49,7 @@ var Entaxy;
</div>
<div ng-if="$ctrl.isContentReady">
<div class="xml-route-source-container">
<entaxy-xml-editor class="xml-editor" source-doc="$ctrl.xml" read-only="$ctrl.readOnly">
<entaxy-xml-editor class="entaxy-editor" source-doc="$ctrl.xml" read-only="$ctrl.readOnly">
</entaxy-xml-editor>
</div>
</div>
@ -59,7 +59,7 @@ var Entaxy;
})
.name;
function entaxySourceController(workspace, $location, operationsService, $scope,
function entaxySourceController(workspace, $location, operationsService, $scope, entaxyHotkeysService,
entaxyService, entaxyAttributesCacheService, entaxyPrivateObjectsCacheService) {
'ngInject';
@ -67,6 +67,7 @@ var Entaxy;
ctrl.errorMessage = 'Value cannot be empty';
ctrl.$onInit = function() {
entaxyHotkeysService.setHotkeys($scope, getHotkeysConfigs());
let selectedMbean = workspace.getSelectedMBean();
let selectedMbeanName = selectedMbean.objectName;
@ -278,8 +279,32 @@ var Entaxy;
.isOwnerChanged(workspace.getSelectedMBean(), ctrl.owner);
}
}
function getHotkeysConfigs() {
return [
{
...Entaxy.getSaveHotkeyDescription(),
callback: function (event) {
event.preventDefault();
if (ctrl.isContentPresent && !ctrl.readOnly) {
ctrl.save();
}
}
},
{
...Entaxy.getSaveAllHotkeyDescription(),
callback: function(event) {
event.preventDefault();
if (ctrl.isContentPresent && !ctrl.readOnly && ctrl.private &&
(ctrl.isOwnerChanged || ctrl.isDirty)) {
ctrl.saveAll();
}
}
}
];
}
}
entaxySourceController.$inject = ['workspace', '$location', 'operationsService', '$scope',
entaxySourceController.$inject = ['workspace', '$location', 'operationsService', '$scope', 'entaxyHotkeysService',
'entaxyService', 'entaxyAttributesCacheService', 'entaxyPrivateObjectsCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,185 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyAliases', {
bindings: {
objectType: '@'
},
template:
`
<h2>Aliases</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>
`,
controller: entaxyAliasesController
})
.name;
function entaxyAliasesController(workspace, operationsService, $uibModal) {
'ngInject';
let ctrl = this;
let selectedMBeanName = workspace.getSelectedMBeanName();
const OBJECT_TYPE = {
KEYSTORE: 'keystore'
}
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' }
];
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;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function () {
populateTable();
let primaryActions = [
{ name: 'Add Alias', actionFn: () => ctrl.showAddKeyModal() }
];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
ctrl.tableActionButtons = [
{ name: 'Remove', title: 'Remove Alias', actionFn: removeAlias }
];
}
function populateTable() {
operationsService.executeOperation(selectedMBeanName, { name: 'listAliases' }, [])
.then(aliases => {
let items = JSON.parse(aliases);
ctrl.items = items.map(item => { return { name: item }; });
ctrl.viewedItems = ctrl.items;
let filters = ctrl.toolbarConfig.filterConfig.appliedFilters;
if (filters.length > 0) {
filterChange(filters);
} else {
ctrl.toolbarConfig.filterConfig.resultsCount = items.length;
}
});
}
ctrl.showAddKeyModal = function () {
$uibModal.open({
component: 'entaxyUserManagementModal',
resolve: {
modalTitle: () => 'Add Alias',
formFields: () => [
{
label: 'Alias',
name: 'alias',
type: 'text',
required: true,
setFocused: true
},
{
label: ctrl.objectType === OBJECT_TYPE.KEYSTORE ? 'Key Content' : 'Value',
name: ctrl.objectType === OBJECT_TYPE.KEYSTORE ? 'keyContent' : 'value',
type: 'textarea',
required: true
}
]
},
backdrop: 'static'
}).result.then((args) => {
processOperation(ctrl.objectType === OBJECT_TYPE.KEYSTORE ? 'addKey' : 'writeValue', args);
},
reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function removeAlias(action, item) {
processOperation(ctrl.objectType === OBJECT_TYPE.KEYSTORE ? 'removeKey' : 'removeValue', [item.name]);
}
function processOperation (operationName, properties) {
operationsService.executeOperation(selectedMBeanName, { name: operationName }, properties)
.then(result => {
Entaxy.notificationSuccess(result);
populateTable();
})
.catch(error => {
Entaxy.notificationError(error);
Entaxy.log.error(error);
});
}
}
entaxyAliasesController.$inject = ['workspace', 'operationsService', '$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,364 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyAllConnectorsTable', {
template:
`
<h2>
Connectors
</h2>
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
menu-actions="$ctrl.menuActions"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyAllConnectorsTableController
})
.name;
function EntaxyAllConnectorsTableController($q, workspace, $scope, operationsService,
jolokia, jolokiaService, entaxyService,
entaxyLegacyConnectorService, entaxyAttributesCacheService) {
'ngInject';
let ctrl = this;
ctrl.workspace = workspace;
ctrl.itemName = 'Connector';
ctrl.statusName = 'BundleState';
const CONTAINER_TYPE_PROFILE = 'Profile';
let filterValues = Entaxy.getAllBundleStates();
ctrl.tableConfig = {
selectionMatchProp: 'displayName',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
},
{
id: 'direction',
title: 'Direction',
placeholder: 'Filter by Direction...',
filterType: 'select',
filterValues: ['in', 'out']
},
{
id: 'type',
title: 'Type',
placeholder: 'Filter by Type...',
filterType: 'text'
},
{
id: 'profile',
title: 'Profile',
placeholder: 'Filter by Profile...',
filterType: 'select',
filterValues: []
},
{
id: 'status',
title: 'Status',
placeholder: 'Filter by Status...',
filterType: 'select',
filterValues: filterValues
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Direction', itemField: 'direction' },
{ header: 'Name', itemField: 'displayName' },
{ header: 'Type', itemField: 'type' },
{ header: 'Profile', itemField: 'profile' },
{ header: 'Status', itemField: 'status' }
];
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 === 'direction') {
match = item.direction === filter.value;
} else if (filter.id === 'displayName') {
match = item.displayName.match(filter.value) !== null;
} else if (filter.id === 'type') {
match = item.type.match(filter.value) !== null;
} else if (filter.id === 'profile') {
match = item.profile === filter.value;
} else if (filter.id === 'status') {
match = item.status === filter.value;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
entaxyService.getProfiles().then(profiles => {
ctrl.profiles = profiles.sort(Entaxy.compareBy('name'));
populateTable();
let toolbarConfigFilterProfile = ctrl.toolbarConfig.filterConfig.fields
.find(field => field.id === 'profile');
toolbarConfigFilterProfile.filterValues = ctrl.profiles.map(profile => profile.name);
let primaryActions = [
{
name: 'Add Connector',
actionFn: () => ctrl.showModal(Entaxy.MODAL_MODES.ADD),
isDisabled: ctrl.profiles.length === 0
}//,
// {
// name: 'Add Legacy Connector',
// actionFn: () => ctrl.showAddLegacyConnectorModal(),
// isDisabled: ctrl.profiles.length === 0
// }
];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
});
ctrl.tableActionButtons = [
{ name: 'Start', title: 'Start ' + ctrl.itemName, actionFn: checkAndProcess },
{ name: 'Stop', title: 'Stop ' + ctrl.itemName, actionFn: checkAndProcess },
{ name: 'Edit', title: 'Edit ' + ctrl.itemName + ' Properties', actionFn: showPropertiesModal },
{ name: 'Use As Template', title: 'Use As Template', actionFn: addConnectorFromTemplate }
];
ctrl.menuActions = [
{ name: 'Uninstall', title: 'Uninstall ' + ctrl.itemName, actionFn: checkAndProcess },
{ name: 'View Properties', title: 'View ' + ctrl.itemName + ' Properties', actionFn: showPropertiesModal }
];
}
function showPropertiesModal(action, item) {
if (action.name === 'View Properties') {
ctrl.showModal(Entaxy.MODAL_MODES.VIEW, item);
} else if (action.name === 'Edit') {
entaxyService.readObjectClusterState(item.mbeanName).then(objectClusterState => {
if (objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.OPERATIONS);
} else {
item.isLocal = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
ctrl.showModal(Entaxy.MODAL_MODES.EDIT, item);
}
}).catch(e => Entaxy.notificationError(e));
}
}
function populateTable() {
let items = [];
let profilesFolder = entaxyService.getDomainFolder()
.findDescendant(child => child.objectName && child.objectName.endsWith('category=profiles'));
entaxyService.getAllChildMBeansByRuntimeType(profilesFolder, Entaxy.RUNTIME_TYPE.CONNECTOR)
.then((mbeans) => {
mbeans.forEach(mbean => {
let connectorSystemName = mbean.attributes.System;
let profile = ctrl.profiles.find(profile => profile.name === connectorSystemName);
let displayName =
mbean.attributes.DisplayName && mbean.attributes.DisplayName.trim().length > 0 ?
mbean.attributes.DisplayName : mbean.attributes.Name;
let factoryId = mbean.attributes.FactoryId;
let factoryFolder = entaxyService.getFolderByTitle(factoryId);
if (factoryFolder) {
jolokiaService.getAttribute(factoryFolder.objectName, 'TypeInfo')
.then(typeInfo => {
items.push({
name: mbean.attributes.Name,
displayName: displayName,
direction: mbean.attributes.Direction ? mbean.attributes.Direction : '-',
type: typeInfo.type,
status: mbean.attributes[ctrl.statusName],
mbeanName: mbean.mbean.objectName,
profileMBeanName: profile.mbeanName,
profile: profile.name
});
});
}
});
ctrl.items = items;
ctrl.viewedItems = items;
let filters = ctrl.toolbarConfig.filterConfig.appliedFilters;
if (filters.length > 0) {
filterChange(filters);
} else {
ctrl.toolbarConfig.filterConfig.resultsCount = items.length;
}
});
}
ctrl.showModal = function(mode, item) {
let runtimeType = Entaxy.RUNTIME_TYPE.CONNECTOR;
if (mode === Entaxy.MODAL_MODES.ADD) {
let resolve = {
mode: () => mode,
itemType: () => ctrl.itemName,
containerType: () => CONTAINER_TYPE_PROFILE,
containers: () => ctrl.profiles
};
entaxyService.openAddItemModalAndProcessResults(resolve, runtimeType);
} else {
entaxyService.openEditItemModalAndProcessResults(item, ctrl.itemName, runtimeType, mode);
}
}
function addConnectorFromTemplate(action, item) {
let resolve = {
itemType: () => ctrl.itemName,
containerType: () => CONTAINER_TYPE_PROFILE,
containers: () => ctrl.profiles
};
entaxyService.openAddItemFromTemplateModalAndProcessResults(resolve, item, Entaxy.RUNTIME_TYPE.CONNECTOR);
}
ctrl.showAddLegacyConnectorModal = function() {
let resolve = {
profiles: () => ctrl.profiles
};
entaxyLegacyConnectorService.openAddLegacyConnectorModal(resolve).then(connectorArgs => {
addLegacyConnector(connectorArgs);
});
}
function addLegacyConnector(connectorArgs) {
let args = entaxyLegacyConnectorService.getArguments(connectorArgs);
let mbeanName = connectorArgs.profile.mbeanName;
operationsService.executeOperation(mbeanName, { name: 'addConnector' }, args)
.then(result => {
Entaxy.notificationSuccess(result);
}).catch(error => {
Entaxy.notificationError(error);
});
}
$scope.$on(Jmx.TreeEvent.Updated, () => {
populateTable();
});
function checkAndProcess(action, item) {
entaxyService.readObjectClusterState(item.mbeanName).then(objectClusterState => {
if (objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL) {
Entaxy.notificationInfo('Local ' + ctrl.itemName.toLowerCase() + ' cannot be ' +
action.name.toLowerCase() +
(action.name.toLowerCase() === Entaxy.OPERATION_TYPE.STOP ? 'ped' : 'ed'));
} else if (objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.OPERATIONS);
} else {
switch (action.name.toLowerCase()) {
case Entaxy.OPERATION_TYPE.START:
startItem(action, item);
return;
case Entaxy.OPERATION_TYPE.STOP:
stopItem(action, item);
return;
case Entaxy.OPERATION_TYPE.UNINSTALL:
uninstallItem(action, item);
return;
}
}
}).catch(e => Entaxy.notificationError(e));
}
function startItem(action, item) {
if (item.status !== 'Active') {
entaxyAttributesCacheService.setToUpdate(item.mbeanName);
entaxyService.processTableOperation(Entaxy.OPERATION_TYPE.START,
item.name, Entaxy.RUNTIME_TYPE.CONNECTOR, item.displayName);
} else {
Entaxy.notificationInfo(ctrl.itemName + ' has been already started');
}
}
function stopItem(action, item) {
if (item.status !== 'Resolved') {
entaxyAttributesCacheService.setToUpdate(item.mbeanName);
entaxyService.processTableOperation(Entaxy.OPERATION_TYPE.STOP,
item.name, Entaxy.RUNTIME_TYPE.CONNECTOR, item.displayName);
} else {
Entaxy.notificationInfo(ctrl.itemName + ' has been already stopped');
}
}
function uninstallItem(action, item) {
let title = 'Confirm Uninstalling';
let message = 'Do you want to uninstall ' + ctrl.itemName.toLowerCase() + ' ' + item.displayName + '?';
entaxyService.openConfirmationWindow(title, message).then(() => {
entaxyService.processTableOperation(Entaxy.OPERATION_TYPE.UNINSTALL,
item.name, Entaxy.RUNTIME_TYPE.CONNECTOR, item.displayName);
entaxyAttributesCacheService.removeFromCache(item.mbeanName);
});
}
ctrl.dismissAlert = () => ctrl.alert = null;
}
EntaxyAllConnectorsTableController.$inject = ['$q', 'workspace', '$scope', 'operationsService', 'jolokia',
'jolokiaService', 'entaxyService', 'entaxyLegacyConnectorService', 'entaxyAttributesCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,130 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyConfigProperties', {
template:
`
<h2>
Configuration Properties
</h2>
<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: EntaxyConfigPropertiesController
})
.name;
function EntaxyConfigPropertiesController(workspace, $location, $scope, $q, jolokia, jolokiaService, operationsService,
entaxyService) {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'displayName',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Property', itemField: 'name' },
{ header: 'Name', itemField: 'displayName' },
{ header: 'Type', itemField: 'type' },
{ header: 'Value', itemField: '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) {
return item.displayName.match(filter.value) !== null;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
populateTable();
}
function populateTable() {
let items = [];
let selectedMbeanName = workspace.getSelectedMBeanName();
entaxyService.readConfiguration(selectedMbeanName).then(config => {
let itemKeys = Object.keys(config.properties);
let configHint = JSON.parse(Entaxy.base64ToString(config.properties.__entaxy_config_hint));
itemKeys.forEach(key => {
let fieldDescription = configHint.fields[key];
if (!fieldDescription.isInternal) {
items.push({
name: key,
displayName: fieldDescription.displayName,
type: fieldDescription.type,
value: config.properties[key]
});
}
});
ctrl.items = items;
ctrl.viewedItems = items;
ctrl.toolbarConfig.filterConfig.resultsCount = items.length;
});
}
}
EntaxyConfigPropertiesController.$inject = ['workspace', '$location', '$scope', '$q', 'jolokia', 'jolokiaService',
'operationsService', 'entaxyService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,49 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyConnections', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="Status" object-name="name"></entaxy-table>
`,
controller: EntaxyConnectionsController
})
.name;
function EntaxyConnectionsController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.CONNECTION;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,99 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyConnectors', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}"
status-name="BundleState" object-name="systemName"
is-parent-dependent="true" skip-location-update="true"
population-parent-mbean-name="$ctrl.populationParentMbeanName"></entaxy-table>
`,
controller: EntaxyConnectorsController
})
.name;
function EntaxyConnectorsController(workspace, operationsService, jolokia, entaxyLegacyConnectorService) {
'ngInject';
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.CONNECTOR;
ctrl.workspace = workspace;
let primaryActions = [ { name: 'Add Legacy Connector', actionFn: () => ctrl.showAddConnectorModal() } ];
ctrl.config = {
primaryActions: primaryActions,
isTableUpdateNeeded: true
}
ctrl.$onInit = function () {
let selectedMbean = workspace.getSelectedMBean();
ctrl.populationParentMbeanName = selectedMbean.objectName ?
selectedMbean.objectName : selectedMbean.parent.objectName;
}
ctrl.showAddConnectorModal = function() {
let parentMBeanName = ctrl.populationParentMbeanName ?
ctrl.populationParentMbeanName : workspace.getSelectedMBeanName();
let resolve = {
profileName: () => jolokia.getAttribute(parentMBeanName, 'Name')
};
entaxyLegacyConnectorService.openAddLegacyConnectorModal(resolve).then(connectorArgs => {
addConnector(connectorArgs);
});
}
function addConnector(connectorArgs) {
let args = entaxyLegacyConnectorService.getArguments(connectorArgs);
let mbeanName = ctrl.populationParentMbeanName ?
ctrl.populationParentMbeanName : workspace.getSelectedMBeanName();
operationsService.executeOperation(mbeanName, { name: 'addConnector' }, args)
.then(result => {
Entaxy.notificationSuccess(result);
}).catch(error => {
Entaxy.notificationError(error);
});
}
ctrl.dismissAlert = () => ctrl.alert = null;
}
EntaxyConnectorsController.$inject = ['workspace', 'operationsService', 'jolokia', 'entaxyLegacyConnectorService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,49 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyKeyStores', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyKeyStoresController
})
.name;
function EntaxyKeyStoresController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE_SECURITY.KEY_STORE;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,61 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyOperationAffectedTable', {
bindings: {
items: '<'
},
template:
`
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
items="$ctrl.items">
</pf-table-view>
`,
controller: EntaxyOperationAffectedTableController
})
.name;
function EntaxyOperationAffectedTableController() {
'ngInject';
let ctrl = this;
ctrl.tableConfig = {
selectionMatchProp: 'objectId',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'Object', itemField: 'objectId' },
{ header: 'Operation', itemField: 'action' }
];
}
EntaxyOperationAffectedTableController.$inject = [];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,51 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyProfiles', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyProfilesController
})
.name;
function EntaxyProfilesController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.PROFILE;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,49 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyRealms', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyRealmsController
})
.name;
function EntaxyRealmsController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE_SECURITY.JAAS_REALM;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,51 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyRepositories', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyRepositoriesController
})
.name;
function EntaxyRepositoriesController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.REPOSITORY;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,50 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyRouteLibraries', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyRouteLibrariesController
})
.name;
function EntaxyRouteLibrariesController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.ROUTE_LIBRARY;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,43 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyRoutes', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-routes-table></entaxy-routes-table>
`
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,366 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyRoutesTable', {
template:
`
<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"
ng-if="$ctrl.ready">
</pf-table-view>
`,
controller: EntaxyRoutesTableController
})
.name;
function EntaxyRoutesTableController(workspace, $location, $scope, $uibModal, entaxyService,
entaxyAttributesCacheService, entaxyPrivateObjectsCacheService) {
'ngInject';
let ctrl = this;
ctrl.workspace = workspace;
const STATUS = {
NEW: 'New',
TO_REMOVAL: 'To Removal'
};
let filterValues = Entaxy.getAllBundleStates();
filterValues.push(STATUS.NEW);
filterValues.push(STATUS.TO_REMOVAL);
ctrl.tableConfig = {
selectionMatchProp: 'displayName',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
},
{
id: 'status',
title: 'Status',
placeholder: 'Filter by Status...',
filterType: 'select',
filterValues: filterValues
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Name', itemField: 'displayName' },
{ header: 'Status', itemField: 'status' }
];
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 === 'displayName') {
match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'status') {
match = item.status.match(filter.value) !== null;
}
return match;
}
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.ROUTE;
populateTable();
ctrl.itemType = Entaxy.getItemTypeFromRuntimeType(ctrl.runtimeType);
populateActionButtons();
}
function populateActionButtons() {
let selectedMbean = workspace.getSelectedMBean();
let ownerMbean = selectedMbean.parent;
entaxyService.readExtendedData(ownerMbean.objectName)
.then(result => {
let extendedData = JSON.parse(result);
if (!extendedData.applications) {
let primaryActions = [ { name: 'Add ' + ctrl.itemType, actionFn: () => ctrl.showModal() } ];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
ctrl.tableActionButtons = [
{ name: 'Remove', title: 'Remove ' + ctrl.itemType, actionFn: removeItem },
{ name: 'Restore', title: 'Restore ' + ctrl.itemType, actionFn: restoreItem }
];
}
ctrl.ready = true;
});
}
function populateTable() {
let selectedMBean = workspace.getSelectedMBean();
if (selectedMBean && selectedMBean.isFolder) {
let items = [];
let children = selectedMBean.children;
if (children && children.length > 0) {
let mbeans = [];
children.forEach(child => {
if (child.objectName) {
let attributes = entaxyAttributesCacheService.getAttributes(child.objectName);
if (attributes.RuntimeType === ctrl.runtimeType) {
mbeans.push({ mbean: child, attributes: attributes });
}
}
});
items = createItemsFromMbeans(mbeans);
}
if (entaxyPrivateObjectsCacheService.hasAddedChildren(selectedMBean.objectName)) {
items = items.concat(createItemsFromAddedObjectsInfo(selectedMBean.objectName));
}
ctrl.items = items;
filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
}
}
function createItemsFromMbeans(mbeans) {
let items = [];
mbeans.forEach((mbean) => {
let displayName = mbean.attributes.DisplayName &&
mbean.attributes.DisplayName.trim().length > 0 ?
mbean.attributes.DisplayName : mbean.attributes.Name;
let changedObjectInfo = entaxyPrivateObjectsCacheService
.getChangedObjectInfo(mbean.attributes.ObjectFullId);
items.push({
id: mbean.attributes.Name,
routeId: mbean.attributes.RouteId,
displayName: displayName,
status: changedObjectInfo && changedObjectInfo.toRemoval ?
mbean.attributes.BundleState + ' [' + STATUS.TO_REMOVAL + ']' :
mbean.attributes.BundleState,
mbeanName: mbean.mbean.objectName,
objectFullId: mbean.attributes.ObjectFullId,
toRemoval: changedObjectInfo && changedObjectInfo.toRemoval
});
});
return items;
}
function createItemsFromAddedObjectsInfo(selectedMBeanMame) {
let items = [];
entaxyPrivateObjectsCacheService.getAddedObjectsInfo(selectedMBeanMame).forEach(addedObject => {
items.push({
id: addedObject.ui.id,
routeId: addedObject.properties.routeId,
displayName: addedObject.properties.displayName ?
addedObject.properties.displayName : addedObject.ui.id,
status: addedObject.toRemoval ? STATUS.NEW + ' [' + STATUS.TO_REMOVAL + ']' : STATUS.NEW,
added: true,
toRemoval: addedObject.toRemoval
});
});
return items;
}
ctrl.showModal = function() {
let selectedMbeanName = workspace.getSelectedMBeanName();
let attributes = entaxyAttributesCacheService.getAttributes(selectedMbeanName);
let ownerRuntimeType = attributes.ObjectType;
let ownerFactoryId = attributes.FactoryId;
let factoryMbean = entaxyService.getFolderByTitle(ownerRuntimeType).get(ownerFactoryId);
entaxyService.getFields(factoryMbean.objectName).then(result => {
let fields = JSON.parse(result);
let routesField = fields.find(field => field.name === 'routes');
let factoryFilter = routesField && routesField.itemFactory ?
routesField.itemFactory.filter : undefined;
entaxyService.getFactoriesByFilterSearch(factoryFilter, true).then(factories => {
let typeInfo = routesField['@TYPEINFO'];
let validation = typeInfo ? typeInfo.validation : undefined;
let checkUniqueness = validation && validation.rules ?
validation.rules.checkChildrenUniqueness : undefined;
let checkUniquenessFields = {};
if (checkUniqueness) {
checkUniqueness.fields.forEach(field => {
checkUniquenessFields[field] = [];
if (ctrl.items) {
ctrl.items.forEach(item => {
if (item[field]) {
checkUniquenessFields[field].push(item[field]);
}
});
}
});
}
let itemTypes = typeInfo && typeInfo.privateObjectTypes ?
typeInfo.privateObjectTypes.map(type => type.displayName).join(' or ') : 'Route';
$uibModal.open({
component: 'entaxyModal',
resolve: {
mode: () => Entaxy.MODAL_MODES.ADD,
itemType: () => itemTypes,
factories: () => factories,
returnFormFields: () => true,
checkUniquenessParentFields: () => checkUniquenessFields
},
size: 'xl',
backdrop: 'static',
windowTopClass: 'modal-top-margin-override'
})
.result.then(formFields => {
// object full id of route-container actually has object full id of its owner
let ownerFullId = attributes.ObjectFullId;
addItem(formFields, routesField, factories, ownerFullId, typeInfo.useAsIdentifier);
},
reason => {
if (reason) {
Entaxy.notificationError(reason);
}
});
});
});
}
function addItem(formFields, routesField, factories, ownerFullId, identifierFieldName) {
let args = entaxyService.getArguments(formFields, factories);
let objectId = args.fields.find(field => field.name === 'objectId').value;
let argFields = args.fields.filter(field => field.name !== 'objectId');
let properties = argFields.reduce((obj, cur) => ({ ...obj, [cur.name] : cur.value }), {});
if (!identifierFieldName) {
identifierFieldName = 'routeId';
}
let routeType = args.factoryId.attributes['typeinfo.routeType'];
let itemInfo = {
objectId: objectId,
factoryId: args.factoryId.name,
scope: routesField.itemScope,
type: routesField.itemType,
properties: properties,
ui: {
id: properties[identifierFieldName],
identifierFieldName: identifierFieldName,
formFields: formFields,
owner: ownerFullId,
routeType: routeType
}
};
let selectedMbean = workspace.getSelectedMBean();
entaxyPrivateObjectsCacheService.addNew(selectedMbean, itemInfo);
workspace.loadTree();
changeLocation(itemInfo.ui.id);
}
function changeLocation(itemName) {
let currentLocation = $location.search();
$location.search('nid', currentLocation.nid + '-' + itemName);
}
$scope.$on(Jmx.TreeEvent.Updated, () => {
populateTable();
});
function removeItem(action, item) {
if (!item.toRemoval) {
let selectedMbean = workspace.getSelectedMBean();
if (item.added) {
entaxyPrivateObjectsCacheService.setAddedObjectToRemoval(selectedMbean.objectName, item.id);
} else {
entaxyService.readConfiguration(item.mbeanName).then(config => {
entaxyPrivateObjectsCacheService.setObjectToRemoval(item.objectFullId, item.mbeanName, config);
});
}
workspace.loadTree();
Entaxy.notificationSuccess('Operation Succeeded');
} else {
Entaxy.notificationInfo(ctrl.itemType + ' has been already set to removal');
}
}
function restoreItem (action, item) {
if (item.toRemoval) {
if (item.added) {
let selectedMbeanName = workspace.getSelectedMBeanName();
entaxyPrivateObjectsCacheService.restoreAddedObject(selectedMbeanName, item.id);
} else {
entaxyPrivateObjectsCacheService.restoreObject(item.objectFullId);
}
workspace.loadTree();
Entaxy.notificationSuccess('Operation Succeeded');
} else {
Entaxy.notificationInfo(ctrl.itemType + ' has been already restored');
}
}
ctrl.dismissAlert = () => ctrl.alert = null;
}
EntaxyRoutesTableController.$inject = ['workspace', '$location', '$scope', '$uibModal', 'entaxyService',
'entaxyAttributesCacheService', 'entaxyPrivateObjectsCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,51 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyServices', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyServicesController
})
.name;
function EntaxyServicesController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE.SERVICE;
}
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,311 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module
.component('entaxyTable', {
bindings: {
runtimeType: '@',
statusName: '@',
objectName: '@',
isParentDependent: '<',
extraPrimaryActionsConfig: '<',
populationParentMbeanName: '<',
skipLocationUpdate: '<'
},
template:
`
<pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
menu-actions="$ctrl.menuActions"
page-config="$ctrl.pageConfig"
items="$ctrl.viewedItems">
</pf-table-view>
`,
controller: EntaxyTableController
})
.name;
function EntaxyTableController(workspace, $location, $scope, $q, jolokia, jolokiaService, operationsService,
entaxyService, entaxyAttributesCacheService) {
'ngInject';
var ctrl = this;
ctrl.workspace = workspace;
let filterValues = Entaxy.getAllBundleStates();
ctrl.tableConfig = {
selectionMatchProp: 'displayName',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'displayName',
title: 'Name',
placeholder: 'Filter by Name...',
filterType: 'text'
},
{
id: 'status',
title: 'Status',
placeholder: 'Filter by Status...',
filterType: 'select',
filterValues: filterValues
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Name', itemField: 'displayName' },
{ header: 'Status', itemField: 'status' }
];
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 === 'displayName') {
match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
} else if (filter.id === 'status') {
match = item.status === filter.value;
}
return match;
}
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
populateTable();
ctrl.itemType = Entaxy.getItemTypeFromRuntimeType(ctrl.runtimeType);
let primaryActions = [ { name: 'Add ' + ctrl.itemType, actionFn: () => ctrl.showModal(Entaxy.MODAL_MODES.ADD) } ];
if (ctrl.extraPrimaryActionsConfig) {
let extraPrimaryActions = ctrl.extraPrimaryActionsConfig.primaryActions;
primaryActions = primaryActions.concat(extraPrimaryActions);
if (ctrl.extraPrimaryActionsConfig.isTableUpdateNeeded) {
ctrl.extraPrimaryActionsConfig.updateTableFn = populateTable;
}
}
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
ctrl.tableActionButtons = [
{ name: 'Start', title: 'Start ' + ctrl.itemType, actionFn: checkAndProcess },
{ name: 'Stop', title: 'Stop ' + ctrl.itemType, actionFn: checkAndProcess },
{ name: 'Edit', title: 'Edit ' + ctrl.itemType + ' Properties', actionFn: showPropertiesModal }
];
ctrl.menuActions = [
{ name: 'Uninstall', title: 'Uninstall ' + ctrl.itemType, actionFn: checkAndProcess },
{ name: 'View Properties', title: 'View ' + ctrl.itemType + ' Properties', actionFn: showPropertiesModal }
];
}
function showPropertiesModal(action, item) {
if (action.name === 'View Properties') {
ctrl.showModal(Entaxy.MODAL_MODES.VIEW, item);
} else if (action.name === 'Edit') {
if (ctrl.runtimeType === Entaxy.RUNTIME_TYPE.CONNECTION && item.isPlatform) {
ctrl.showModal(Entaxy.MODAL_MODES.VIEW, item);
return;
}
entaxyService.readObjectClusterState(item.mbeanName).then(objectClusterState => {
if (objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.OPERATIONS);
} else {
item.isLocal = objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL;
ctrl.showModal(Entaxy.MODAL_MODES.EDIT, item);
}
}).catch(e => Entaxy.notificationError(e));
}
}
function populateTable() {
let items = [];
let selectedMBean = ctrl.populationParentMbeanName ?
entaxyService.getDomainFolder()
.findDescendant(child => child.objectName === ctrl.populationParentMbeanName) :
workspace.getSelectedMBean();
if (selectedMBean && selectedMBean.isFolder) {
entaxyService.getAllChildMBeansByRuntimeType(selectedMBean, ctrl.runtimeType).then((mbeans) => {
mbeans.forEach((mbean) => {
let displayName = mbean.attributes.DisplayName &&
mbean.attributes.DisplayName.trim().length > 0 ?
mbean.attributes.DisplayName : mbean.attributes.Name;
items.push({
name: mbean.attributes.Name,
displayName: displayName,
status: mbean.attributes[ctrl.statusName],
mbeanName: mbean.mbean.objectName,
isPlatform: mbean.attributes.Platform
});
});
ctrl.items = items;
ctrl.viewedItems = items;
let filters = ctrl.toolbarConfig.filterConfig.appliedFilters;
if (filters.length > 0) {
filterChange(filters);
} else {
ctrl.toolbarConfig.filterConfig.resultsCount = items.length;
}
});
}
}
ctrl.showModal = function(mode, item) {
if (mode === Entaxy.MODAL_MODES.ADD) {
let parentMBeanName = ctrl.populationParentMbeanName ?
ctrl.populationParentMbeanName : workspace.getSelectedMBeanName();
let parentName = ctrl.isParentDependent === true ?
jolokia.getAttribute(parentMBeanName, 'Name') : undefined;
let resolve = {
mode: () => mode,
itemType: () => ctrl.itemType,
parentName: () => parentName
};
entaxyService.openAddItemModalAndProcessResults(resolve, ctrl.runtimeType, updateLocation);
} else {
entaxyService.openEditItemModalAndProcessResults(item, ctrl.itemType, ctrl.runtimeType, mode);
}
}
function updateLocation(properties, objectId) {
if (!ctrl.skipLocationUpdate) {
let itemName =
ctrl.runtimeType === Entaxy.RUNTIME_TYPE.REPOSITORY ||
ctrl.runtimeType === Entaxy.RUNTIME_TYPE.ROUTE_LIBRARY ?
objectId + '_' + ctrl.runtimeType :
properties[ctrl.objectName] ? properties[ctrl.objectName] : objectId;
changeLocation(itemName);
}
}
function changeLocation(itemName) {
let currentLocation = $location.search();
$location.search('nid', currentLocation.nid + '-' + itemName);
}
$scope.$on(Jmx.TreeEvent.Updated, () => {
populateTable();
});
function checkAndProcess(action, item) {
entaxyService.readObjectClusterState(item.mbeanName).then(objectClusterState => {
if (objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.LOCAL) {
Entaxy.notificationInfo('Local ' + ctrl.itemType.toLowerCase() + ' cannot be ' +
action.name.toLowerCase() +
(action.name.toLowerCase() === Entaxy.OPERATION_TYPE.STOP ? 'ped' : 'ed'));
} else if (objectClusterState === Entaxy.OBJECT_CLUSTER_STATE.NON_CLUSTERED) {
Entaxy.notificationInfo(Entaxy.NON_CLUSTERED_MESSAGE.OPERATIONS);
} else {
switch (action.name.toLowerCase()) {
case Entaxy.OPERATION_TYPE.START:
startItem(action, item);
return;
case Entaxy.OPERATION_TYPE.STOP:
stopItem(action, item);
return;
case Entaxy.OPERATION_TYPE.UNINSTALL:
uninstallItem(action, item);
return;
}
}
}).catch(e => Entaxy.notificationError(e));
}
function startItem(action, item) {
if (item.status !== 'Active') {
entaxyAttributesCacheService.setToUpdate(item.mbeanName);
entaxyService.processTableOperation(Entaxy.OPERATION_TYPE.START,
item.name, ctrl.runtimeType, item.displayName);
} else {
Entaxy.notificationInfo(ctrl.itemType + ' has been already started');
}
}
function stopItem(action, item) {
if (item.status !== 'Resolved') {
entaxyAttributesCacheService.setToUpdate(item.mbeanName);
entaxyService.processTableOperation(Entaxy.OPERATION_TYPE.STOP,
item.name, ctrl.runtimeType, item.displayName);
} else {
Entaxy.notificationInfo(ctrl.itemType + ' has been already stopped');
}
}
function uninstallItem(action, item) {
let title = 'Confirm Uninstalling';
let message = 'Do you want to uninstall ' + ctrl.itemType.toLowerCase() + ' ' + item.displayName + '?';
entaxyService.openConfirmationWindow(title, message).then(() => {
let selectedFolder = entaxyService.getDomainFolder()
.findDescendant(child => child.objectName === item.mbeanName);
let children = Entaxy.getChildrenRecursive(selectedFolder);
entaxyAttributesCacheService.removeFromCache(item.mbeanName);
if (children) {
children.forEach(child => entaxyAttributesCacheService.removeFromCache(child.objectName));
}
entaxyService.processTableOperation(Entaxy.OPERATION_TYPE.UNINSTALL,
item.name, ctrl.runtimeType, item.displayName);
});
}
ctrl.dismissAlert = () => ctrl.alert = null;
}
EntaxyTableController.$inject = ['workspace', '$location', '$scope', '$q', 'jolokia', 'jolokiaService',
'operationsService', 'entaxyService', 'entaxyAttributesCacheService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,49 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyVaults', {
bindings: {
pageTitle: '@'
},
template:
`
<h2>
{{$ctrl.pageTitle}}
</h2>
<entaxy-table runtime-type="{{$ctrl.runtimeType}}" status-name="BundleState" object-name="systemName">
</entaxy-table>
`,
controller: EntaxyVaultsController
})
.name;
function EntaxyVaultsController() {
let ctrl = this;
ctrl.runtimeType = Entaxy.RUNTIME_TYPE_SECURITY.VAULT;
}
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -0,0 +1,110 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyAssociatedProfileSelect', {
bindings: {
username: '<'
},
template:
`
<entaxy-select-from-enum id="{{$ctrl.formField.name}}" values="$ctrl.formField.values"
model="$ctrl.formField.value" readonly="$ctrl.formField.readOnly"
is-empty-included="true" empty-option-name="'--No Profile--'"></entaxy-select-from-enum>
`,
controller: EntaxyAssociatedProfileSelectController
})
.name;
function EntaxyAssociatedProfileSelectController(workspace, operationsService, entaxyService, $scope) {
'ngInject';
let ctrl = this;
let selectedMbeanName = workspace.getSelectedMBeanName();
ctrl.$onInit = function() {
entaxyService.getProfiles().then(profiles => {
ctrl.formField = {
readOnly: true,
values: profiles.sort(Entaxy.compareBy('name')).map(profile => profile.name)
}
});
}
$scope.$watch('$ctrl.username', function (newValue, oldValue) {
if (newValue) {
getAssociatedProfile();
}
})
function getAssociatedProfile() {
operationsService
.executeOperation(selectedMbeanName, { name: 'getAssociatedProfile' }, [ ctrl.username ])
.then(profileName => {
if (profileName === 'Empty string') {
ctrl.formField.value = undefined;
ctrl.associatedProfile = undefined;
ctrl.formField.readOnly = false;
} else {
entaxyService.getProfiles().then(profiles => {
let profile = profiles.find(profile => profile.name === profileName);
if (profile) {
ctrl.formField.value = profileName;
ctrl.associatedProfile = profileName;
} else {
Entaxy.notificationError('Associated profile ' + profileName + ' not found');
}
ctrl.formField.readOnly = false;
});
}
});
}
$scope.$watch('$ctrl.formField.value', function (newValue) {
if (newValue !== ctrl.associatedProfile) {
ctrl.associatedProfile = newValue;
associateProfile();
}
})
function associateProfile() {
let parameters = [ ctrl.username, ctrl.associatedProfile ];
operationsService
.executeOperation(selectedMbeanName, { name: 'associateProfile' }, parameters)
.then(() => {
Entaxy.notificationSuccess('Profile ' + ctrl.associatedProfile +
' was successfully associated with user ' + ctrl.username);
})
.catch(error => {
Entaxy.notificationError('An error occurred while associating profile ' + ctrl.associatedProfile +
' to user ' + ctrl.username);
Entaxy.log.error(error);
})
}
}
EntaxyAssociatedProfileSelectController.$inject = ['workspace', 'operationsService', 'entaxyService', '$scope'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,211 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyGroupsAndRolesList', {
bindings: {
username: '<',
reloadFn: '<'
},
template:
`
<entaxy-expandable-list items="$ctrl.items" action-buttons="$ctrl.actionButtons" use-toolbar="true"
toolbar-action-buttons="$ctrl.toolbarActionButtons"
enable-toolbar-action-buttons="$ctrl.username ? true : false"
empty-state-config="$ctrl.emptyStateConfig">
</entaxy-expandable-list>
`,
controller: EntaxyGroupsAndRolesListController
})
.name;
function EntaxyGroupsAndRolesListController(workspace, operationsService, entaxyService, $q, $scope, $uibModal) {
'ngInject';
let ctrl = this;
let selectedMbeanName = workspace.getSelectedMBeanName();
let ITEM_TYPES = {
ROLE: 'Role',
GROUP: 'Group'
}
ctrl.toolbarActionButtons = [
{ name: 'Add Group', actionFn: () => showAddGroupModal(), isDisabled: ctrl.username ? false : true },
{ name: 'Add Role', actionFn: () => showAddRoleModal(), isDisabled: ctrl.username ? false : true }
];
ctrl.emptyStateConfig = {
title: 'There is no selected user'
};
ctrl.actionButtons = [{
name: 'Delete',
actionFn: deleteRoleOrGroup
}];
$scope.$watch('$ctrl.username', function (newValue, oldValue) {
if (newValue) {
populateItems();
} else {
ctrl.items = [];
}
})
function populateItems() {
let promises = [];
promises.push(listRolesOrGroups(ctrl.username, 'listRolesForUser'));
promises.push(listRolesOrGroups(ctrl.username, 'listGroupsForUser'));
promises.push(operationsService.executeOperation(selectedMbeanName, { name: 'listGroups'}, []));
$q.all(promises).then(result => {
let roles = JSON.parse(result[0]);
ctrl.roles = JSON.parse(result[0]).map(role => role.name);
let items = [];
let userGroups = JSON.parse(result[1]);
let allGroups = JSON.parse(result[2]);
userGroups.forEach(group => {
let groupWithRoles = allGroups.find(groupWithRoles => group.name === groupWithRoles.name);
groupWithRoles.roles = groupWithRoles.roles.split(',').sort(Entaxy.compare());
groupWithRoles.isGroup = true;
roles = roles.filter(role => !groupWithRoles.roles.includes(role.name));
items.push(groupWithRoles);
});
items.push(...roles);
items.map(item => {
item.displayName = item.name;
if (item.roles) {
item.sublist = item.roles.map(role => {
return {
displayName: role,
typeIcon: 'pf pficon-user',
disableRowExpansion: true
};
});
} else {
item.disableRowExpansion = true;
}
item.typeIcon = item.isGroup ? 'pf pficon-users' : 'pf pficon-user';
return item;
});
ctrl.items = items.sort(Entaxy.compareBy('displayName'));
});
}
function listRolesOrGroups(username, operationName) {
return operationsService.executeOperation(selectedMbeanName, { name: operationName }, [ username ]);
}
function showAddRoleModal() {
openUserManagementModalAndProcess(ITEM_TYPES.ROLE);
}
function showAddGroupModal() {
operationsService.executeOperation(selectedMbeanName, {name: 'listGroups'}, [])
.then(list => {
let items = JSON.parse(list);
let values = items
.filter(item => !includesGroup(item.name))
.map(item => item.name)
.sort(Entaxy.compare());
openUserManagementModalAndProcess(ITEM_TYPES.GROUP, values);
});
}
function openUserManagementModalAndProcess(itemType, values) {
if (itemType === ITEM_TYPES.GROUP && values.length === 0) {
Entaxy.notificationInfo('There are no groups that can be added');
return;
}
$uibModal.open({
component: 'entaxyUserManagementModal',
resolve: {
modalTitle: () => 'Add ' + itemType + ' to ' + ctrl.username,
formFields: () => getFormFields(itemType, values)
},
backdrop: 'static'
}).result.then((args) => {
entaxyService.processUserManagementOperation('add' + itemType, args, populateItems);
}, reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function getFormFields(itemType, values) {
let formFields = [
{
label: 'Username',
name: 'username',
type: 'text',
required: true,
value: ctrl.username,
readOnly: true
},
{
label: itemType + ' Name',
name: Entaxy.uncapitalize(itemType),
type: 'text',
required: true,
enum: itemType === ITEM_TYPES.GROUP ? true : false,
values: itemType === ITEM_TYPES.GROUP ? values : undefined,
validation: itemType === ITEM_TYPES.ROLE ? {
checkUniqueness: true,
values: ctrl.roles
} : undefined,
setFocused: itemType === ITEM_TYPES.ROLE ? true : undefined
}
];
return formFields;
}
function includesGroup(itemName) {
let item = ctrl.items.find(item => item.name === itemName);
return item && item.isGroup;
}
function deleteRoleOrGroup(action, item) {
let operationName = item.isGroup ? 'deleteGroup' : 'deleteRole';
let postProcessFn = item.isGroup ? ctrl.reloadFn : populateItems;
entaxyService.processUserManagementOperation(operationName, [ ctrl.username, item.name ], postProcessFn);
}
}
EntaxyGroupsAndRolesListController.$inject = ['workspace', 'operationsService', 'entaxyService', '$q', '$scope',
'$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,228 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyGroupsTable', {
bindings: {
reloadFn: '<'
},
template:
`
<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>
`,
controller: EntaxyGroupsTableController
})
.name;
function EntaxyGroupsTableController(workspace, operationsService, entaxyService, $uibModal) {
'ngInject';
let ctrl = this;
let selectedMbeanName = workspace.getSelectedMBeanName();
let delimeter = ', ';
ctrl.tableConfig = {
selectionMatchProp: 'name',
showCheckboxes: false
};
ctrl.toolbarConfig = {
filterConfig: {
fields: [
{
id: 'name',
title: 'Group',
placeholder: 'Filter by Group...',
filterType: 'text'
},
{
id: 'roles',
title: 'Roles',
placeholder: 'Filter by Roles...',
filterType: 'text'
}
],
appliedFilters: [],
onFilterChange: filterChange
},
isTableView: true
};
ctrl.tableColumns = [
{ header: 'Group', itemField: 'name' },
{ header: 'Roles', itemField: 'roles' }
];
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.match(filter.value) !== null;
} else if (filter.id === 'roles') {
match = item.roles.match(filter.value) !== null;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
populateTable();
let primaryActions = [ { name: 'Create Group', actionFn: () => showCreateGroupModal() } ];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
ctrl.tableActionButtons = [
{ name: 'Add Role', title: 'Add Role', actionFn: addRole },
{ name: 'Delete Role', title: 'Delete Role', actionFn: deleteRole }
];
}
function populateTable() {
operationsService.executeOperation(selectedMbeanName, { name: 'listGroups' }, [])
.then(list => {
ctrl.items = JSON.parse(list).map(item => {
item.roles = item.roles.replaceAll(',', delimeter);
return item;
});
ctrl.viewedItems = ctrl.items;
let filters = ctrl.toolbarConfig.filterConfig.appliedFilters;
if (filters.length > 0) {
filterChange(filters);
} else {
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.items.length;
}
})
}
function showCreateGroupModal() {
let resolve = {
modalTitle: () => 'Create Group',
formFields: () => [
{
label: 'Group Name',
name: 'group',
type: 'text',
required: true,
setFocused: true
}
]
};
openModalAndProcessResults(resolve, 'createGroup');
}
function addRole(action, item) {
let resolve = {
modalTitle: () => 'Add Role to Group ' + item.name,
formFields: () => [
{
label: 'Group Name',
name: 'group',
type: 'text',
required: true,
value: item.name,
readOnly: true
},
{
label: 'Role Name',
name: 'role',
type: 'text',
required: true,
validation: {
checkUniqueness: true,
values: item.roles.split(delimeter)
},
setFocused: true
}
]
};
openModalAndProcessResults(resolve, 'addGroupRole');
}
function deleteRole(action, item) {
let roles = item.roles.split(delimeter);
roles.shift();
if (roles.length > 0) {
let resolve = {
modalTitle: () => 'Delete Role from Group ' + item.name,
formFields: () => [
{
name: 'group',
type: 'text',
required: true,
value: item.name,
isHidden: true
},
{
label: 'Role Name',
name: 'role',
type: 'text',
required: true,
enum: true,
values: roles.sort(Entaxy.compare())
}
]
};
openModalAndProcessResults(resolve, 'deleteGroupRole');
} else {
Entaxy.notificationInfo('Group ' + item.name + ' doesn\'t have roles that can be deleted');
}
}
function openModalAndProcessResults(resolve, operationName) {
$uibModal.open({
component: 'entaxyUserManagementModal',
resolve: resolve,
backdrop: 'static'
}).result.then((args) => {
entaxyService.processUserManagementOperation(operationName, args, ctrl.reloadFn);
}, reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
}
EntaxyGroupsTableController.$inject = ['workspace', 'operationsService', 'entaxyService', '$uibModal'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,68 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyUserManagement', {
template:
`
<entaxy-users change-selection="$ctrl.changeSelection" selected-username="$ctrl.selectedUsername"
reload-fn="$ctrl.reload"></entaxy-users>
<h2>Groups</h2>
<entaxy-groups-table reload-fn="$ctrl.reload"></entaxy-groups-table>
`,
controller: EntaxyUserManagementController
})
.name;
function EntaxyUserManagementController($cookies, $route) {
'ngInject';
let ctrl = this;
const SELECTED_USER_KEY = 'selectedUser';
ctrl.$onInit = function () {
let selectedUser = $cookies.getObject(SELECTED_USER_KEY);
if (selectedUser) {
ctrl.selectedUsername = selectedUser;
$cookies.remove(SELECTED_USER_KEY);
}
}
ctrl.changeSelection = function (itemName) {
ctrl.selectedUsername = itemName;
}
ctrl.reload = function (username) {
if (ctrl.selectedUsername !== username) {
$cookies.putObject(SELECTED_USER_KEY, ctrl.selectedUsername);
}
$route.reload();
}
}
EntaxyUserManagementController.$inject = ['$cookies', '$route'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,149 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyUserManagementModal', {
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.type !== 'password' && formField.type !== 'textarea'"
set-focused="formField.setFocused">
<entaxy-password-input id="{{formField.name}}" name="formField.name" model="formField.value"
confirmation-model="formField.confirmationValue" readonly="formField.readOnly"
ng-if="formField.type === 'password'" errors="$ctrl.errors"
set-focused="formField.setFocused"></entaxy-password-input>
<entaxy-select-from-enum id="{{formField.name}}" values="formField.values"
model="formField.value" readonly="formField.readOnly" is-empty-included="false"
ng-if="formField.enum"></entaxy-select-from-enum>
<textarea type="{{formField.type}}" id="{{formField.name}}" class="form-control"
ng-model="formField.value" ng-readonly="formField.readOnly"
ng-if="formField.type === 'textarea'" set-focused="formField.setFocused"/>
<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: entaxyUserManagementModalController
})
.name;
function entaxyUserManagementModalController($scope, $uibModal, 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.type === 'password' && ctrl.errors && ctrl.errors[formField.name]) {
errors[formField.name] = ctrl.errors[formField.name];
}
if (!errors[formField.name] && formField.required
&& (!formField.value || formField.value.trim().length === 0)) {
errors[formField.name] = Entaxy.ERROR_MESSAGE.EMPTY;
}
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();
}
}
];
}
}
entaxyUserManagementModalController.$inject = ['$scope', '$uibModal', 'entaxyHotkeysService'];
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,62 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyUsers', {
bindings: {
changeSelection: '<',
selectedUsername: '<',
reloadFn: '<'
},
template:
`
<div class="entaxy-users-container">
<div class="entaxy-users-table-container">
<h2>Users</h2>
<entaxy-users-table change-selection="$ctrl.changeSelection" reload-fn="$ctrl.reloadFn">
</entaxy-users-table>
</div>
<div class="entaxy-user-details-container">
<h2>
User Details
<span ng-if="$ctrl.selectedUsername">for {{$ctrl.selectedUsername}}</span>
</h2>
<label>Associated Profile</label>
<entaxy-associated-profile-select username="$ctrl.selectedUsername">
</entaxy-associated-profile-select>
<label>Groups and Roles</label>
<entaxy-groups-and-roles-list username="$ctrl.selectedUsername" reload-fn="$ctrl.reloadFn">
</entaxy-groups-and-roles-list>
</div>
</div>
`
})
.name;
})(Entaxy || (Entaxy = {}));

View File

@ -0,0 +1,179 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
Entaxy._module.component('entaxyUsersTable', {
bindings: {
changeSelection: '<',
reloadFn: '<'
},
template:
`
<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>
`,
controller: EntaxyUsersTableController
})
.name;
function EntaxyUsersTableController(workspace, operationsService, entaxyService, $uibModal, $templateCache) {
'ngInject';
let ctrl = this;
let selectedMbeanName = workspace.getSelectedMBeanName();
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: 'users-table/name-template.html',
colActionFn: (itemName) => ctrl.changeSelection(itemName)
}
];
$templateCache.put(
'users-table/name-template.html',
'<a href="" ng-click="$ctrl.handleColAction(key, value)">{{value}}</a>'
);
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;
}
return match;
};
ctrl.items = [];
ctrl.viewedItems = [];
ctrl.$onInit = function() {
populateTable();
let primaryActions = [ { name: 'Add User', actionFn: () => showAddUserModal() } ];
ctrl.toolbarConfig.actionsConfig = {
primaryActions: primaryActions
};
ctrl.tableActionButtons = [
{ name: 'Delete', title: 'Delete User', actionFn: deleteUser }
];
}
function populateTable() {
operationsService.executeOperation(selectedMbeanName, { name: 'listUsers' }, [])
.then(list => {
ctrl.items = JSON.parse(list);
ctrl.viewedItems = ctrl.items;
let filters = ctrl.toolbarConfig.filterConfig.appliedFilters;
if (filters.length > 0) {
filterChange(filters);
} else {
ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.items.length;
}
})
}
function showAddUserModal() {
$uibModal.open({
component: 'entaxyUserManagementModal',
resolve: {
modalTitle: () => 'Add User',
formFields: () => [
{
label: 'Username',
name: 'username',
type: 'text',
required: true,
setFocused: true
},
{
label: 'Password',
name: 'password',
type: 'password',
required: true
}
]
},
backdrop: 'static'
}).result.then((args) => {
entaxyService.processUserManagementOperation('addUser', args, populateTable);
},
reason => {
if (reason && reason !== Entaxy.MODAL_CANCEL_REASON.ESCAPE_KEY_PRESS) {
Entaxy.notificationError(reason);
}
});
}
function deleteUser(action, item) {
ctrl.deletedUsername = item.name;
entaxyService.processUserManagementOperation('deleteUser', [ item.name ], reload);
}
function reload() {
ctrl.reloadFn(ctrl.deletedUsername);
}
}
EntaxyUsersTableController.$inject = ['workspace', 'operationsService', 'entaxyService', '$uibModal',
'$templateCache'];
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -80,12 +80,18 @@ var Entaxy;
Entaxy.NON_CLUSTERED_MESSAGE = NON_CLUSTERED_MESSAGE;
const ERROR_MESSAGE = {
INVALID: 'Invalid value',
UNIQUE: 'Value must be unique',
EMPTY: 'Please fill out this field',
PASSWORD_CONFIRMATION: 'Password and confirmation password do not match'
}
Entaxy.ERROR_MESSAGE = ERROR_MESSAGE;
const MODAL_CANCEL_REASON = {
ESCAPE_KEY_PRESS: 'escape key press'
}
Entaxy.MODAL_CANCEL_REASON = MODAL_CANCEL_REASON;
const CONFIRMATION = {
UNSAVED_CHANGES: 'You have unsaved changes. Do you want to proceed anyway?'
}
@ -119,10 +125,8 @@ var Entaxy;
}
Entaxy.getItemTypeFromRuntimeType = getItemTypeFromRuntimeType;
let resourceCopyConfig = {
removeSource: false
}
Entaxy.resourceCopyConfig = resourceCopyConfig;
let resourceCopyConfigs = {};
Entaxy.resourceCopyConfigs = resourceCopyConfigs;
function deepCopy(object) {
return JSON.parse(JSON.stringify(object));
@ -327,6 +331,24 @@ var Entaxy;
}
Entaxy.createTableFromOperationAffectedObjects = createTableFromOperationAffectedObjects;
function createStatusResultTable(result, header) {
let tableHtml = `<table class="entaxy-result-table">`;
tableHtml += `
<tr>
<th>` + header + `</th>
<th>Status</th>
</tr>
`;
result.forEach(res => {
let iconName = res.failed ? 'error-circle-o' : 'ok';
tableHtml += `<tr><td style="padding-right: 5px;">` + res.id +
`</td><td><span class="pficon pficon-${iconName}"></span></td></tr>`;
});
tableHtml += `</table>`;
return tableHtml;
}
Entaxy.createStatusResultTable = createStatusResultTable;
function notificationWithDetails(type, mainMessage, message, duration) {
let toastHtml = `
<div class="toast-pf alert alert-${type} alert-dismissable">
@ -439,6 +461,15 @@ var Entaxy;
}
Entaxy.notificationError = notificationError;
function changingFieldValueNotification(fieldDescriptor) {
Core.notification(Entaxy.NOTIFICATION_TYPE.WARNING,
'Changing ' + fieldDescriptor +
' field value may lead to changes in other fields of the current object. ' +
'Please, make sure to revise all fields before accepting.',
Entaxy.configuration[Entaxy.CONFIGURATION_KEYS.NOTIFICATION_TIMEOUT_INFO]);
}
Entaxy.changingFieldValueNotification = changingFieldValueNotification;
function setDefaultConfiguration() {
Entaxy.configuration = getDefaultConfiguration();
}

View File

@ -0,0 +1,106 @@
/*-
* ~~~~~~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 Entaxy;
(function (Entaxy) {
function getSaveHotkeyDescription() {
return {
combo: 'ctrl+s',
description: 'Saves the current object',
allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
};
}
Entaxy.getSaveHotkeyDescription = getSaveHotkeyDescription;
function getSaveAsHotkeyDescription() {
return {
combo: 'ctrl+shift+s',
description: 'Saves the current object with different name',
allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
};
}
Entaxy.getSaveAsHotkeyDescription = getSaveAsHotkeyDescription;
function getSaveAllHotkeyDescription() {
return {
combo: 'ctrl+shift+s',
description: 'Saves the current and related objects',
allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
};
}
Entaxy.getSaveAllHotkeyDescription = getSaveAllHotkeyDescription;
function getBackHotkeyDescription() {
return {
combo: 'alt+left',
description: 'Moves to the previous step of the modal',
allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
};
}
Entaxy.getBackHotkeyDescription = getBackHotkeyDescription;
function getNextHotkeyDescription() {
return {
combo: 'alt+right',
description: 'Moves to the next step of the modal',
allowIn: ['INPUT', 'SELECT', 'TEXTAREA']
};
}
Entaxy.getNextHotkeyDescription = getNextHotkeyDescription;
function getCopyHotkeyDescription() {
return {
combo: 'ctrl+c',
description: 'Copies the item'
};
}
Entaxy.getCopyHotkeyDescription = getCopyHotkeyDescription;
function getCutHotkeyDescription() {
return {
combo: 'ctrl+x',
description: 'Cuts the item'
};
}
Entaxy.getCutHotkeyDescription = getCutHotkeyDescription;
function getPasteHotkeyDescription() {
return {
combo: 'ctrl+v',
description: 'Pastes the item'
};
}
Entaxy.getPasteHotkeyDescription = getPasteHotkeyDescription;
function getRemoveHotkeyDescription() {
return {
combo: 'del',
description: 'Removes the item'
};
}
Entaxy.getRemoveHotkeyDescription = getRemoveHotkeyDescription;
})(Entaxy || (Entaxy = {}));

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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
@ -47,7 +47,8 @@ var Entaxy = (function (Entaxy) {
Entaxy._module = angular.module(Entaxy.pluginName, [
'angularResizable',
'jsonFormatter',
'ui.sortable'
'ui.sortable',
'cfp.hotkeys'
])
.component('entaxy', {
template:
@ -147,7 +148,7 @@ var Entaxy = (function (Entaxy) {
});
angular.forEach(
['factories', 'search', 'route-component-libraries',
['factories', 'search', 'route-component-libraries', 'data-management',
'resource', 'connectors', 'security', 'configs', 'objects'],
(folderName) => {
addClassRecursive(
@ -352,7 +353,8 @@ var Entaxy = (function (Entaxy) {
}
});
});
Entaxy.setChildrenToEntaxyTags(topChildrenTags);
Entaxy.enrichEntaxyTags(topChildrenTags);
Entaxy.enrichCamelTags(topChildrenTags);
})
.catch(error => Entaxy.log.error(error));
}
@ -389,12 +391,14 @@ const L10N = {
routes: 'Маршруты',
bound: 'Связанные',
resource: 'Ресурсы',
services: 'Сервисы',
services: 'Сервисы и Клиенты',
security: 'Безопасность',
repositories: 'Репозитории',
objects: 'Объекты',
configs: 'Конфигурации',
search: 'Поиск',
['route-libraries']: 'Библиотеки маршрутов',
['route-component-libraries']: 'Библиотеки компонентов маршрутов'
['route-component-libraries']: 'Библиотеки компонентов маршрутов',
['data-management']: 'Управление данными',
['data-mappers']: 'Маппинг данных'
};

View File

@ -2,7 +2,7 @@
* ~~~~~~licensing~~~~~~
* entaxy-management-plugin
* ==========
* Copyright (C) 2020 - 2024 EmDev LLC
* 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

Some files were not shown because too many files have changed in this diff Show More