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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cob-cli",
3
- "version": "2.6.2",
3
+ "version": "2.8.0",
4
4
  "description": "A command line utility to help Cult of Bits partners develop with higher speed and reusing common code and best practices.",
5
5
  "preferGlobal": true,
6
6
  "repository": {
@@ -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 .custom-comentarios table > tbody > tr > td:nth-child(1) {
63
- min-width:70px !important;
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
- /* labels constantes */
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 {
@@ -1,3 +1,5 @@
1
+ @import "_global.css";
1
2
  @import "_history.css";
2
3
  @import "_hidden.css";
3
- @import "_mobile.css";
4
+ @import "_mobile.css";
5
+ @import "_dualColumn.css";
@@ -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 == "usermURI") {
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
- /**/log.info("[\$audit] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
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|usermURI|time)/
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] fields for '$definitionName': $auditFields");
79
- /**/log.info("[\$audit] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
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|usermURI|time)/.exec(fp.field.fieldDefinition.description) )
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 //Only update if it's on create interface (updates will only be changed by the backend)
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)\.usermURI/.exec(fp.field.fieldDefinition.description)) {
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] fields for '$definitionName': $calculationFields");
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,5 @@
1
+
2
+ /* Aproxima novo comentário do log de comentários */
3
+ .cob-app .instance-detail-container div.instance-container ol.fields > li.custom-reduceDistanceToNextField {
4
+ margin-bottom: -23px;
5
+ }
@@ -0,0 +1 @@
1
+ @import "_log.css";