cob-cli 2.6.2 → 2.8.0
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 +12 -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 +6 -6
- package/templates/keywords/audit/frontend/js/cob/_audit.js +4 -3
- package/templates/keywords/calc/backend/scripts/_calc.groovy +1 -2
- 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,12 @@
|
|
|
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
|
+
}
|
|
@@ -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
|
|
|
@@ -30,7 +31,7 @@ def getAuditFieldsUpdates(auditFields,instanceFields) {
|
|
|
30
31
|
auditFields.each { auditField ->
|
|
31
32
|
if( auditField.op == "creator" && msg.action == "update" && msg.value(auditField.name) != null) return // 'creator' fields are only changed in 'update' if the previous value was empty (meaning it was a field that was not visible)
|
|
32
33
|
if( msg.action == 'update' && !msg.diff) return // Only continues if there is at least one change
|
|
33
|
-
if( auditField.args == "
|
|
34
|
+
if( auditField.args == "uri") {
|
|
34
35
|
updates << [(auditField.name) : actionPacks.get("userm").getUser(msg.user).data._links.self]
|
|
35
36
|
|
|
36
37
|
} else if( auditField.args == "username") {
|
|
@@ -46,8 +47,7 @@ def getAuditFieldsUpdates(auditFields,instanceFields) {
|
|
|
46
47
|
|
|
47
48
|
// ========================================================================================================
|
|
48
49
|
def getAuditFields(definitionName) {
|
|
49
|
-
|
|
50
|
-
/**/log.info("[\$audit] Update 'auditFields' for '$definitionName'... ");
|
|
50
|
+
log.info("[\$audit] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
|
51
51
|
|
|
52
52
|
// Obtém detalhes da definição
|
|
53
53
|
def definitionEncoded = URLEncoder.encode(definitionName, "utf-8").replace("+", "%20")
|
|
@@ -68,14 +68,14 @@ def getAuditFields(definitionName) {
|
|
|
68
68
|
// Finalmente obtém a lista de campos que é necessário calcular
|
|
69
69
|
def auditFields = [];
|
|
70
70
|
fields.each { fieldId,field ->
|
|
71
|
-
def matcher = field.description =~ /[$]audit\.(creator|updater)\.(username|
|
|
71
|
+
def matcher = field.description.toString() =~ /[$]audit\.(creator|updater)\.(username|uri|time)/
|
|
72
72
|
if(matcher) {
|
|
73
73
|
def op = matcher[0][1]
|
|
74
74
|
def arg = matcher[0][2]
|
|
75
75
|
auditFields << [fieldId: fieldId, name:field.name, op : op, args: arg]
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
log.info("[\$audit]
|
|
79
|
-
|
|
78
|
+
log.info("[\$audit] Update 'auditFields' for '$definitionName': $auditFields");
|
|
79
|
+
log.info("[\$audit] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
|
80
80
|
return auditFields
|
|
81
81
|
}
|
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
cob.custom.customize.push(function (core, utils, ui) {
|
|
3
3
|
core.customizeAllInstances((instance, presenter) =>
|
|
4
4
|
{
|
|
5
|
-
let userFPs = presenter.findFieldPs( fp => /[$]audit\.(creator|updater)\.(username|
|
|
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(!instance.isNew() || presenter.isGroupEdit()) return //
|
|
8
|
+
if(fp.getValue() && (!instance.isNew() || presenter.isGroupEdit())) return //Don't do nothing if field is not empty AND it's an update interface (updates will only be changed by the backend)
|
|
9
9
|
if(/[$]audit\.(creator|updater)\.username/.exec(fp.field.fieldDefinition.description)) {
|
|
10
10
|
fp.setValue(core.getCurrentLoggedInUser())
|
|
11
11
|
}
|
|
12
|
-
if(/[$]audit\.(creator|updater)\.
|
|
12
|
+
if(/[$]audit\.(creator|updater)\.uri/.exec(fp.field.fieldDefinition.description)) {
|
|
13
13
|
fp.setValue(core.getCurrentLoggedInUserUri())
|
|
14
14
|
}
|
|
15
15
|
if(/[$]audit\.(creator|updater)\.time/.exec(fp.field.fieldDefinition.description)) {
|
|
16
16
|
fp.setValue(Date.now())
|
|
17
|
+
setInterval(() => fp.setValue(Date.now()),15000)
|
|
17
18
|
}
|
|
18
19
|
})
|
|
19
20
|
})
|
|
@@ -119,7 +119,6 @@ def getAllAplicableValuesForVarName(fieldId,varName,varFieldIds,instanceFields,t
|
|
|
119
119
|
// ========================================================================================================
|
|
120
120
|
def getAllCalculationFields(definitionName) {
|
|
121
121
|
log.info("[\$calc] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
|
122
|
-
log.info("[\$calc] update 'calculationFields' for '$definitionName'... ");
|
|
123
122
|
|
|
124
123
|
// Obtém detalhes da definição
|
|
125
124
|
def definitionEncoded = URLEncoder.encode(definitionName, "utf-8").replace("+", "%20")
|
|
@@ -156,7 +155,7 @@ def getAllCalculationFields(definitionName) {
|
|
|
156
155
|
}
|
|
157
156
|
previousId = fieldId
|
|
158
157
|
}
|
|
159
|
-
log.info("[\$calc]
|
|
158
|
+
log.info("[\$calc] Update 'calculationFields' for '$definitionName': $calculationFields");
|
|
160
159
|
log.info("[\$calc] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
|
|
161
160
|
return calculationFields
|
|
162
161
|
}
|
|
@@ -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";
|