cob-cli 2.6.3 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/customizations/keywords.js +3 -2
- package/customizations/keywords.log.js +17 -0
- package/package.json +1 -1
- package/templates/frontend/common/css/_dualColumn.css +46 -0
- package/templates/frontend/common/css/_global.css +13 -0
- package/templates/frontend/common/css/_mobile.css +3 -11
- package/templates/frontend/common/css/customizations.__MERGE__.css +3 -1
- package/templates/keywords/audit/backend/scripts/_audit.groovy +2 -1
- package/templates/keywords/audit/frontend/js/cob/_audit.js +5 -1
- package/templates/keywords/log/backend/scripts/_log.groovy +99 -0
- package/templates/keywords/log/frontend/css/_log.css +5 -0
- package/templates/keywords/log/frontend/css/customizations.__MERGE__.css +1 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
exports.option = {
|
|
2
|
-
name: 'Keywords - Add a keyword for use in definitions (https://learning.cultofbits.com)',
|
|
2
|
+
name: 'Keywords - Add a keyword for use in definitions (https://learning.cultofbits.com/docs/cob-platform/admins/managing-information/available-customizations/)',
|
|
3
3
|
short: "Keywords",
|
|
4
4
|
followUp: [ {
|
|
5
5
|
type: 'list',
|
|
@@ -7,7 +7,8 @@ exports.option = {
|
|
|
7
7
|
message: 'Select one?',
|
|
8
8
|
choices: [
|
|
9
9
|
require("./keywords.calc").option,
|
|
10
|
-
require("./keywords.audit").option
|
|
10
|
+
require("./keywords.audit").option,
|
|
11
|
+
require("./keywords.log").option
|
|
11
12
|
]}
|
|
12
13
|
]
|
|
13
14
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
exports.option = {
|
|
2
|
+
name: 'Log - Allows for $log in definitions (https://learning.cultofbits.com/docs/cob-platform/admins/managing-information/available-customizations/log/)',
|
|
3
|
+
short: "Log",
|
|
4
|
+
questions: [
|
|
5
|
+
],
|
|
6
|
+
customization: async function (answers) {
|
|
7
|
+
console.log("\nApplying Log keyword customizations ...")
|
|
8
|
+
|
|
9
|
+
const { copy } = require("../lib/task_lists/customize_copy");
|
|
10
|
+
const { mergeFiles } = require("../lib/task_lists/customize_mergeFiles");
|
|
11
|
+
const fe_target = "./recordm/customUI/"
|
|
12
|
+
await copy("../../templates/keywords/log/frontend",fe_target)
|
|
13
|
+
const be_target = "./integrationm/"
|
|
14
|
+
await copy("../../templates/keywords/log/backend",be_target)
|
|
15
|
+
await mergeFiles("Keyword.Log")
|
|
16
|
+
}
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* Overall good practive - not column related but specialy relevant inside columns */
|
|
2
|
+
li.custom-dualColumn ol.fields > li > table > tbody > tr > td:nth-child(1) {
|
|
3
|
+
min-width: 70px;
|
|
4
|
+
}
|
|
5
|
+
li.custom-dualColumn ol.fields > li > table > tbody > tr > td:nth-child(2) {
|
|
6
|
+
min-width: 160px;
|
|
7
|
+
}
|
|
8
|
+
li.custom-dualColumn ol.fields li > table > tbody > tr > td:nth-child(3),
|
|
9
|
+
li.custom-dualColumn ol.fields li > table > tbody > tr > td:nth-child(3) input {
|
|
10
|
+
max-width: 230px !important;
|
|
11
|
+
width: -webkit-fill-available;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* $style[dualColumn] */
|
|
15
|
+
li.custom-dualColumn > ol.fields{
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-wrap: wrap;
|
|
18
|
+
}
|
|
19
|
+
li.custom-dualColumn > ol.fields > li {
|
|
20
|
+
flex-basis:49%;
|
|
21
|
+
}
|
|
22
|
+
li.custom-dualColumn ol.fields > li > table > tbody > tr > td:nth-child(3) {
|
|
23
|
+
width: unset;
|
|
24
|
+
}
|
|
25
|
+
li.custom-dualColumn ol.fields > li > table > tbody > tr > td:nth-child(4) {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* $style[singleColumn] */
|
|
30
|
+
li.custom-dualColumn > ol.fields > li.custom-singleColumn {
|
|
31
|
+
flex-basis:100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* $style[column] */
|
|
35
|
+
li.custom-column > table {
|
|
36
|
+
display: none
|
|
37
|
+
}
|
|
38
|
+
.cob-app .instance-detail-container div.instance-container li.custom-column > ol.fields {
|
|
39
|
+
border:none;
|
|
40
|
+
background-color: unset;
|
|
41
|
+
margin:unset;
|
|
42
|
+
}
|
|
43
|
+
.cob-app .instance-detail-container .instance-container .fields-container li.custom-column.field-group {
|
|
44
|
+
margin:unset;
|
|
45
|
+
padding: unset;
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* Overall good practive - not column related but specialy relevant inside columns */
|
|
2
|
+
.cob-app .instance-detail-container div.instance-container ol.fields > li > table > tbody > tr > td:nth-child(1) {
|
|
3
|
+
min-width: 70px;
|
|
4
|
+
}
|
|
5
|
+
.cob-app .instance-detail-container div.instance-container ol.fields > li > table > tbody > tr > td:nth-child(2) {
|
|
6
|
+
min-width: 160px;
|
|
7
|
+
}
|
|
8
|
+
.cob-app .instance-detail-container div.instance-container ol.fields li > table > tbody > tr > td:nth-child(3),
|
|
9
|
+
.cob-app .instance-detail-container div.instance-container ol.fields li > table > tbody > tr > td:nth-child(3) input {
|
|
10
|
+
max-width: 230px;
|
|
11
|
+
width: -webkit-fill-available;
|
|
12
|
+
z-index: -1;
|
|
13
|
+
}
|
|
@@ -59,12 +59,8 @@
|
|
|
59
59
|
width:30px !important;
|
|
60
60
|
max-width:30px !important;
|
|
61
61
|
}
|
|
62
|
-
ol.fields
|
|
63
|
-
|
|
64
|
-
width:70px !important;
|
|
65
|
-
max-width:70px !important;
|
|
66
|
-
}
|
|
67
|
-
ol.fields table > tbody > tr > td:nth-child(2) {
|
|
62
|
+
ol.fields table > tbody > tr > td:nth-child(2),
|
|
63
|
+
ol.fields table > tbody > tr > td:nth-child(2) label {
|
|
68
64
|
width:100px !important;
|
|
69
65
|
min-width:100px !important;
|
|
70
66
|
}
|
|
@@ -91,11 +87,7 @@
|
|
|
91
87
|
min-width:0px !important;
|
|
92
88
|
max-width:0px !important;
|
|
93
89
|
}
|
|
94
|
-
|
|
95
|
-
.cob-app .instance-detail-container div.instance-container ol.fields > li > table label {
|
|
96
|
-
max-width: 150px !important;
|
|
97
|
-
min-width: 150px !important;
|
|
98
|
-
}
|
|
90
|
+
|
|
99
91
|
/* selects constantes */
|
|
100
92
|
.cob-app .instance-detail-container ol.fields table > tbody > tr > td:nth-child(3) > div.inline > select,
|
|
101
93
|
.cob-app .instance-detail-container select {
|
|
@@ -16,6 +16,7 @@ if (msg.product == "recordm-definition") cacheOfAuditFieldsForDefinition.invalid
|
|
|
16
16
|
// ========================================================================================================
|
|
17
17
|
def auditFields = cacheOfAuditFieldsForDefinition.get(msg.type, { getAuditFields(msg.type) })
|
|
18
18
|
if (auditFields.size() > 0
|
|
19
|
+
&& msg.product == "recordm"
|
|
19
20
|
&& msg.user != "integrationm"
|
|
20
21
|
&& msg.action =~ "add|update" ) {
|
|
21
22
|
|
|
@@ -67,7 +68,7 @@ def getAuditFields(definitionName) {
|
|
|
67
68
|
// Finalmente obtém a lista de campos que é necessário calcular
|
|
68
69
|
def auditFields = [];
|
|
69
70
|
fields.each { fieldId,field ->
|
|
70
|
-
def matcher = field.description =~ /[$]audit\.(creator|updater)\.(username|uri|time)/
|
|
71
|
+
def matcher = field.description.toString() =~ /[$]audit\.(creator|updater)\.(username|uri|time)/
|
|
71
72
|
if(matcher) {
|
|
72
73
|
def op = matcher[0][1]
|
|
73
74
|
def arg = matcher[0][2]
|
|
@@ -5,7 +5,10 @@ cob.custom.customize.push(function (core, utils, ui) {
|
|
|
5
5
|
let userFPs = presenter.findFieldPs( fp => /[$]audit\.(creator|updater)\.(username|uri|time)/.exec(fp.field.fieldDefinition.description) )
|
|
6
6
|
userFPs.forEach( fp => {
|
|
7
7
|
fp.disable()
|
|
8
|
-
if(
|
|
8
|
+
if( presenter.isGroupEdit() ) return; // Don't do nothing in group edit
|
|
9
|
+
if(/[$]audit\.updater\./.exec(fp.field.fieldDefinition.description) && !instance.isNew()) return //Don't do nothing if $audit.updater.* and it's an update interface (updates will only be changed by the backend)
|
|
10
|
+
if(fp.isVisible() && /[$]audit\.creator\./.exec(fp.field.fieldDefinition.description) && !instance.isNew()) return //Se campo visível e é um creator não faz nada
|
|
11
|
+
|
|
9
12
|
if(/[$]audit\.(creator|updater)\.username/.exec(fp.field.fieldDefinition.description)) {
|
|
10
13
|
fp.setValue(core.getCurrentLoggedInUser())
|
|
11
14
|
}
|
|
@@ -14,6 +17,7 @@ cob.custom.customize.push(function (core, utils, ui) {
|
|
|
14
17
|
}
|
|
15
18
|
if(/[$]audit\.(creator|updater)\.time/.exec(fp.field.fieldDefinition.description)) {
|
|
16
19
|
fp.setValue(Date.now())
|
|
20
|
+
setInterval(() => fp.setValue(Date.now()),15000)
|
|
17
21
|
}
|
|
18
22
|
})
|
|
19
23
|
})
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import groovy.transform.Field
|
|
2
|
+
import org.codehaus.jettison.json.JSONObject
|
|
3
|
+
|
|
4
|
+
import com.google.common.cache.*
|
|
5
|
+
import java.util.concurrent.TimeUnit
|
|
6
|
+
|
|
7
|
+
// ========================================================================================================
|
|
8
|
+
if (msg.product != "recordm-definition" && msg.product != "recordm" ) return
|
|
9
|
+
|
|
10
|
+
@Field static cacheOfLogFieldsForDefinition = CacheBuilder.newBuilder()
|
|
11
|
+
.expireAfterWrite(5, TimeUnit.MINUTES)
|
|
12
|
+
.build();
|
|
13
|
+
|
|
14
|
+
if (msg.product == "recordm-definition") cacheOfLogFieldsForDefinition.invalidate(msg.type)
|
|
15
|
+
|
|
16
|
+
// ========================================================================================================
|
|
17
|
+
def logFields = cacheOfLogFieldsForDefinition.get(msg.type, { getLogFields(msg.type) })
|
|
18
|
+
if( logFields.size() > 0
|
|
19
|
+
&& msg.product == "recordm"
|
|
20
|
+
&& msg.user != "integrationm"
|
|
21
|
+
&& msg.action =~ "add|update"
|
|
22
|
+
) {
|
|
23
|
+
def updates = getLogUpdates(logFields)
|
|
24
|
+
def result = recordm.update(messageMap.type, "recordmInstanceId:" + messageMap.instance.id, updates);
|
|
25
|
+
if (updates) log.info("[\$log] UPDATE '${msg.type}' id:${msg.instance.id}, updates: ${updates}, result:${result} ");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ========================================================================================================
|
|
29
|
+
|
|
30
|
+
def getLogUpdates(logFields){
|
|
31
|
+
def updates = [:]
|
|
32
|
+
def currentUser = actionPacks.get("userm").getUser(msg.user).data.name;
|
|
33
|
+
|
|
34
|
+
logFields.each { logField ->
|
|
35
|
+
def commentLogs = msg.value(logField.name);
|
|
36
|
+
def newComment = msg.value(logField.sourceField);
|
|
37
|
+
def fieldMsg = getFieldMessage(logField.stateField);
|
|
38
|
+
|
|
39
|
+
if( newComment != null || msg.field(logField.stateField).changed() ){
|
|
40
|
+
def newLogEntry = "#### " + (new Date()).format('yyyy-MM-dd HH:mm:ss').toString() + " - " + currentUser;
|
|
41
|
+
newLogEntry += " [$fieldMsg] "
|
|
42
|
+
newLogEntry +="\n\n";
|
|
43
|
+
newLogEntry += newComment != null ? newComment : "";
|
|
44
|
+
newLogEntry +="\n\n";
|
|
45
|
+
|
|
46
|
+
if(commentLogs!=null) {
|
|
47
|
+
newLogEntry += "======================================================================\n";
|
|
48
|
+
}
|
|
49
|
+
updates << [(logField.name) : "" + newLogEntry + (commentLogs ?: "")];
|
|
50
|
+
updates << [(logField.sourceField) : ""];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return updates
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
def getFieldMessage(field){
|
|
57
|
+
String newValue = msg.value(field) ?: "";
|
|
58
|
+
if( msg.field(field).changed() ){
|
|
59
|
+
String oldValue = msg.oldInstance.value(field) ?: "";
|
|
60
|
+
return "$field: $oldValue -> $newValue";
|
|
61
|
+
} else {
|
|
62
|
+
return "$field: $newValue";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ========================================================================================================
|
|
67
|
+
def getLogFields(definitionName) {
|
|
68
|
+
log.info("[\$log] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
|
69
|
+
|
|
70
|
+
// Obtém detalhes da definição
|
|
71
|
+
def definitionEncoded = URLEncoder.encode(definitionName, "utf-8").replace("+", "%20")
|
|
72
|
+
def resp = actionPacks.rmRest.get( "recordm/definitions/name/${definitionEncoded}".toString(), [:], "");
|
|
73
|
+
JSONObject definition = new JSONObject(resp);
|
|
74
|
+
|
|
75
|
+
def fieldsSize = definition.fieldDefinitions.length();
|
|
76
|
+
|
|
77
|
+
def fields = [:]
|
|
78
|
+
(0..fieldsSize-1).each { index ->
|
|
79
|
+
def fieldDefinition = definition.fieldDefinitions.getJSONObject(index)
|
|
80
|
+
def fieldDescription = fieldDefinition.get("description")
|
|
81
|
+
def fieldDefId = fieldDefinition.get("id")
|
|
82
|
+
def fieldName = fieldDefinition.get("name");
|
|
83
|
+
fields[fieldDefId] = [name:fieldName, description: fieldDescription]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Finalmente obtém a lista de campos que é necessário calcular
|
|
87
|
+
def auditFields = [];
|
|
88
|
+
fields.each { fieldId,field ->
|
|
89
|
+
def matcher = field.description.toString() =~ /[$]log\(([^(]+),\s*([^(]+)\)/
|
|
90
|
+
if(matcher) {
|
|
91
|
+
def sourceField = matcher[0][1]
|
|
92
|
+
def stateField = matcher[0][2]
|
|
93
|
+
auditFields << [name: field.name, sourceField : sourceField, stateField : stateField]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
log.info("[\$log] Update 'logFields' for '$definitionName': $auditFields");
|
|
97
|
+
log.info("[\$log] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
|
98
|
+
return auditFields
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "_log.css";
|