@steedos-labs/plugin-workflow 3.0.16 → 3.0.19

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.
@@ -27,6 +27,21 @@ nav_schema: {
27
27
  "size": "none",
28
28
  "className": "instances-sidebar-wrapper mt-1 bg-white",
29
29
  "body": [
30
+ {
31
+ "type": "button",
32
+ "label": "刷新",
33
+ "className": "instance-nav-reload hidden",
34
+ "onEvent": {
35
+ "click": {
36
+ "actions": [
37
+ {
38
+ "actionType": "rebuild",
39
+ "componentId": "u:instanceNav"
40
+ }
41
+ ]
42
+ }
43
+ }
44
+ },
30
45
  {
31
46
  "type": "service",
32
47
  "id": "u:instanceNav",
@@ -41,117 +56,16 @@ nav_schema: {
41
56
  }
42
57
  },
43
58
  "body": [
44
- {
45
- "type": "button",
46
- "label": "刷新",
47
- "className": "instance-nav-reload hidden",
48
- "onEvent": {
49
- "click": {
50
- "actions": [
51
- {
52
- "actionType": "reload",
53
- "componentId": "u:instanceNav"
54
- }
55
- ]
56
- }
57
- }
58
- },
59
- {
60
- "type": "input-tree",
61
- "name": "tree",
62
- "treeContainerClassName": "h-full bg-white",
63
- "className": "instance-box-tree h-full w-full p-0 bg-white",
64
- "id": "u:9f3dd961ca12",
65
- "stacked": true,
66
- "multiple": false,
67
- "enableNodePath": false,
68
- "hideRoot": true,
69
- "showIcon": true,
70
- "initiallyOpen": false,
71
- "virtualThreshold": 100000,
72
- "value": "${value}",
73
- "size": "md",
74
- "onEvent": {
75
- "change": {
76
- "actions": [
77
- {
78
- "actionType": "setValue",
79
- "componentId": "instances_list_service",
80
- "args": {
81
- "value": {
82
- "isFlowDataDone": false
83
- }
84
- }
85
- },
86
- {
87
- "actionType": "custom",
88
- "script": "//获取上一次的flowId和categoryId\nconst lastFlowId = event.data.flowId;\nconst lastCategoryId = event.data.categoryId;\n//从value中获取最新的flowId\nvar flowIdRegex = /&flowId=([^&]+)/;\nvar flowIdMatch = event.data.value.match(flowIdRegex);\nconst flowId = flowIdMatch && flowIdMatch.length > 0 ? flowIdMatch[1] : \"\";\n//从value中获取最新的categoryId\nvar categoryIdRegex = /&categoryId=([^&]+)/;\nvar categoryIdMatch = event.data.value.match(categoryIdRegex);\nconst categoryId = categoryIdMatch && categoryIdMatch.length > 0 ? categoryIdMatch[1] : \"\";\n//获取上一次的listname和最新的listname\nconst lastListName = event.data.listName;\nconst listName = event.data.value.split('?')[0].split('instances/grid/')[1];\n//切换流程时清除过滤条件\nif (lastListName == \"monitor\" && listName == \"monitor\" && (flowId != lastFlowId || categoryId != lastCategoryId)) {\n listViewPropsStoreKey = window.location.pathname + \"/crud\";\n sessionStorage.removeItem(listViewPropsStoreKey);\n sessionStorage.removeItem(listViewPropsStoreKey + \"/query\");\n}"
89
- },
90
- {
91
- "actionType": "setValue",
92
- "componentId": "instances_list_service",
93
- "args": {
94
- "value": {
95
- "additionalFilters": [
96
- "${event.data.options.name}",
97
- "=",
98
- "${event.data.options.value}"
99
- ]
100
- }
101
- },
102
- "expression": "${event.data.options.level>=10}"
103
- },
104
- {
105
- "args": {
106
- "link": "${event.data.value}",
107
- "blank": false
108
- },
109
- "actionType": "link"
110
- }
111
- ]
112
- }
113
- },
114
- "menuTpl": {
115
- "type": "wrapper",
116
- "className": "flex items-center py-1.5 px-3 m-0 rounded-md transition-colors duration-150",
117
- "body": [
118
- {
119
- "type": "tpl",
120
- "className": "flex-1 leading-6 truncate instance-menu-label",
121
- "tpl": "${label}",
122
- "id": "u:9dee51f00db4"
123
- },
124
- {
125
- "type": "tpl",
126
- "className": "ml-auto",
127
- "tpl": "",
128
- "badge": {
129
- "className": "h-0",
130
- "offset": [
131
- -5,
132
- 0
133
- ],
134
- "mode": "text",
135
- "text": "${tag | toInt}",
136
- "overflowCount": 999
137
- },
138
- "id": "u:2329cd1fecc2"
139
- }
140
- ],
141
- "id": "u:545154bcc334"
142
- },
143
- "unfoldedLevel": 2,
144
- "source": "${options}"
145
- }
146
59
  ],
147
- "api": {
60
+ "schemaApi": {
148
61
  "method": "get",
149
62
  "url": "${context.rootUrl}/api/${appId}/workflow/nav",
150
63
  "headers": {
151
64
  "Authorization": "Bearer ${context.tenantId},${context.authToken}"
152
65
  },
153
66
  "messages": {},
154
- "adaptor": "payload.data.value = window.location.pathname + decodeURIComponent(window.location.search); return payload;"
67
+ "adaptor": "payload.data.value = window.location.pathname + decodeURIComponent(window.location.search);\n// return payload;\n\n\nreturn {\n \"type\": \"service\",\n \"data\": payload.data,\n \"body\": [{\n \"type\": \"input-tree\",\n \"name\": \"tree\",\n \"treeContainerClassName\": \"h-full bg-white\",\n \"className\": \"instance-box-tree h-full w-full p-0 bg-white\",\n \"id\": \"u:9f3dd961ca12\",\n \"stacked\": true,\n \"multiple\": false,\n \"enableNodePath\": false,\n \"hideRoot\": true,\n \"showIcon\": true,\n \"initiallyOpen\": false,\n \"virtualThreshold\": 100000,\n \"value\": \"${value}\",\n \"size\": \"md\",\n \"onEvent\": {\n \"change\": {\n \"actions\": [\n {\n \"actionType\": \"setValue\",\n \"componentId\": \"instances_list_service\",\n \"args\": {\n \"value\": {\n \"isFlowDataDone\": false\n }\n }\n },\n {\n \"actionType\": \"custom\",\n \"script\": \"//获取上一次的flowId和categoryId\\nconst lastFlowId = event.data.flowId;\\nconst lastCategoryId = event.data.categoryId;\\n//从value中获取最新的flowId\\nvar flowIdRegex = /&flowId=([^&]+)/;\\nvar flowIdMatch = event.data.value.match(flowIdRegex);\\nconst flowId = flowIdMatch && flowIdMatch.length > 0 ? flowIdMatch[1] : \\\"\\\";\\n//从value中获取最新的categoryId\\nvar categoryIdRegex = /&categoryId=([^&]+)/;\\nvar categoryIdMatch = event.data.value.match(categoryIdRegex);\\nconst categoryId = categoryIdMatch && categoryIdMatch.length > 0 ? categoryIdMatch[1] : \\\"\\\";\\n//获取上一次的listname和最新的listname\\nconst lastListName = event.data.listName;\\nconst listName = event.data.value.split('?')[0].split('instances/grid/')[1];\\n//切换流程时清除过滤条件\\nif (lastListName == \\\"monitor\\\" && listName == \\\"monitor\\\" && (flowId != lastFlowId || categoryId != lastCategoryId)) {\\n listViewPropsStoreKey = window.location.pathname + \\\"/crud\\\";\\n sessionStorage.removeItem(listViewPropsStoreKey);\\n sessionStorage.removeItem(listViewPropsStoreKey + \\\"/query\\\");\\n}\"\n },\n {\n \"actionType\": \"setValue\",\n \"componentId\": \"instances_list_service\",\n \"args\": {\n \"value\": {\n \"additionalFilters\": [\n \"${event.data.options.name}\",\n \"=\",\n \"${event.data.options.value}\"\n ]\n }\n },\n \"expression\": \"${event.data.options.level>=10}\"\n },\n {\n \"args\": {\n \"link\": \"${event.data.value}\",\n \"blank\": false\n },\n \"actionType\": \"link\"\n }\n ]\n }\n },\n \"menuTpl\": {\n \"type\": \"wrapper\",\n \"className\": \"flex items-center py-1.5 px-3 m-0 rounded-md transition-colors duration-150\",\n \"body\": [\n {\n \"type\": \"tpl\",\n \"className\": \"flex-1 leading-6 truncate instance-menu-label\",\n \"tpl\": \"${label}\",\n \"id\": \"u:9dee51f00db4\"\n },\n {\n \"type\": \"tpl\",\n \"className\": \"ml-auto\",\n \"tpl\": \"\",\n \"badge\": {\n \"className\": \"h-0\",\n \"offset\": [\n -5,\n 0\n ],\n \"mode\": \"text\",\n \"text\": \"${tag | toInt}\",\n \"overflowCount\": 999\n },\n \"id\": \"u:2329cd1fecc2\"\n }\n ],\n \"id\": \"u:545154bcc334\"\n },\n \"unfoldedLevel\": 2,\n \"source\": \"${options}\"\n }]\n}"
68
+ # "adaptor": "payload.data.value = window.location.pathname + decodeURIComponent(window.location.search); return payload;"
155
69
  },
156
70
  "messages": {},
157
71
  "dsType": "api"
@@ -117,22 +117,30 @@ async function insert_many_instance_tasks(insId, traceId, approveIds) {
117
117
  * @returns 更新后的instance_tasks
118
118
  */
119
119
  async function update_instance_tasks(insId, traceId, approveId, doc) {
120
+ console.time(`update_instance_tasks ${approveId}`);
120
121
  let taskDoc = doc
121
122
  if (!taskDoc) {
123
+ console.time(`update_instance_tasks_makeTaskDoc ${approveId}`);
122
124
  taskDoc = await _makeTaskDoc(insId, traceId, approveId)
123
125
  delete taskDoc._id
126
+ console.timeEnd(`update_instance_tasks_makeTaskDoc ${approveId}`);
124
127
  }
128
+ console.time(`update_instance_tasks_update ${approveId}`);
125
129
  const result = await _update(approveId, taskDoc)
130
+ console.timeEnd(`update_instance_tasks_update ${approveId}`);
126
131
 
127
132
  // 如果任务已完成,更新相关通知为已读
128
133
  if (taskDoc.is_finished) {
134
+ console.time(`update_instance_tasks_notifications ${approveId}`);
129
135
  const instance = taskDoc.instance || insId
130
136
  const handler = taskDoc.handler
131
137
  if (instance && handler) {
132
138
  await _updateNotificationsAsRead(instance, handler)
133
139
  }
140
+ console.timeEnd(`update_instance_tasks_notifications ${approveId}`);
134
141
  }
135
142
 
143
+ console.timeEnd(`update_instance_tasks ${approveId}`);
136
144
  return result
137
145
  }
138
146
 
@@ -265,6 +273,9 @@ async function direct_remove_many_instance_tasks(approveIds) {
265
273
  * @returns 1
266
274
  */
267
275
  async function count_instance_tasks(query) {
276
+ if(process.env.STEEDOS_WORKFLOW_DISABLE_BADGE === 'true'){
277
+ return 0;
278
+ }
268
279
  const result = await _count(query)
269
280
  return result
270
281
  }
@@ -55,6 +55,9 @@ const settings = require('@steedos/objectql').getSteedosConfig();
55
55
 
56
56
 
57
57
  async function count_instance_tasks(query) {
58
+ if(process.env.STEEDOS_WORKFLOW_DISABLE_BADGE === 'true'){
59
+ return 0;
60
+ }
58
61
  return await getObject('instance_tasks').count(query)
59
62
  }
60
63
 
@@ -539,7 +542,7 @@ pushManager.send_email_to_SMTP = async function (subject, content, to_user, repl
539
542
  subject: subject, // 主题
540
543
  html: content
541
544
  };
542
- await ctx.broker.call('@builder6/email.send', mailOptions)
545
+ await broker.call('@builder6/email.send', mailOptions)
543
546
 
544
547
  } catch (error) {
545
548
  console.error(error.stack);
@@ -18,7 +18,14 @@ const moment = require('moment')
18
18
  const { getObject } = require('@steedos/objectql');
19
19
  const { evaluate } = require('amis-formula');
20
20
 
21
- const UUFlowManager = {};
21
+ const UUFlowManager = {
22
+ stats: {
23
+ getFlow: 0,
24
+ getFlowVersion: 0,
25
+ getForm: 0,
26
+ getFormVersion: 0
27
+ }
28
+ };
22
29
 
23
30
  /**
24
31
  * Check user authorization
@@ -158,6 +165,7 @@ UUFlowManager.getSpaceUser = async function (space_id, user_id, options = {}) {
158
165
  * @throws {Error} If flow not found
159
166
  */
160
167
  UUFlowManager.getFlow = async function (flow_id, options = {}) {
168
+ UUFlowManager.stats.getFlow++;
161
169
  if (process.env.STEEDOS_DEBUG) {
162
170
  const now = new Date().toISOString();
163
171
  console.time('UUFlowManager.getFlow' + now);
@@ -185,6 +193,7 @@ UUFlowManager.getFlow = async function (flow_id, options = {}) {
185
193
  * @throws {Error} If version not found
186
194
  */
187
195
  UUFlowManager.getFlowVersion = function (flow, flow_version) {
196
+ UUFlowManager.stats.getFlowVersion++;
188
197
  let flow_v = null;
189
198
 
190
199
  if (flow_version === flow.current._id) {
@@ -1079,6 +1088,7 @@ UUFlowManager.getUpdatedValues = function (instance, approve_id) {
1079
1088
  * @throws {Error} If form not found
1080
1089
  */
1081
1090
  UUFlowManager.getForm = async function (form_id, options = {}) {
1091
+ UUFlowManager.stats.getForm++;
1082
1092
  if (process.env.STEEDOS_DEBUG) {
1083
1093
  console.time('UUFlowManager.getForm');
1084
1094
  }
@@ -1105,6 +1115,7 @@ UUFlowManager.getForm = async function (form_id, options = {}) {
1105
1115
  * @throws {Error} If version not found
1106
1116
  */
1107
1117
  UUFlowManager.getFormVersion = function (form, form_version) {
1118
+ UUFlowManager.stats.getFormVersion++;
1108
1119
  let form_v = null;
1109
1120
 
1110
1121
  if (form_version === form.current._id) {
@@ -1292,6 +1303,14 @@ UUFlowManager.getApproveValues = async function (approve_values, permissions, fo
1292
1303
  * @returns {Object} Updated instance
1293
1304
  */
1294
1305
  UUFlowManager.workflow_engine = async function (approve_from_client, current_user_info, current_user, auto_submitted = false) {
1306
+ // Reset stats at the beginning of workflow_engine
1307
+ UUFlowManager.stats = {
1308
+ getFlow: 0,
1309
+ getFlowVersion: 0,
1310
+ getForm: 0,
1311
+ getFormVersion: 0
1312
+ };
1313
+ const t0 = Date.now();
1295
1314
  // Extract data from approve_from_client
1296
1315
  const {
1297
1316
  instance: instance_id,
@@ -1306,21 +1325,24 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1306
1325
 
1307
1326
  // Get instance, space, flow and related data
1308
1327
  const instance = await UUFlowManager.getInstance(instance_id);
1328
+ console.log(`[workflow/engine] [workflow_engine] getInstance took ${Date.now() - t0}ms`);
1309
1329
  const space_id = instance.space;
1310
1330
  const flow_id = instance.flow;
1311
- const space = await UUFlowManager.getSpace(space_id);
1312
- const applicant_id = instance.applicant;
1331
+ const t1 = Date.now();
1313
1332
  const flow = await UUFlowManager.getFlow(flow_id);
1314
1333
  const space_user = await UUFlowManager.getSpaceUser(space_id, current_user);
1315
1334
  const space_user_org_info = await UUFlowManager.getSpaceUserOrgInfo(space_user);
1316
1335
  const trace = await UUFlowManager.getTrace(instance, trace_id);
1317
1336
  const approve = await UUFlowManager.getApprove(trace, approve_id);
1337
+ console.log(`[workflow/engine] [workflow_engine] load related data took ${Date.now() - t1}ms`);
1318
1338
 
1319
1339
  // Validate instance state and permissions
1340
+ const t2 = Date.now();
1320
1341
  UUFlowManager.isTraceNotFinished(trace);
1321
1342
  UUFlowManager.isApproveNotFinished(approve);
1322
1343
  UUFlowManager.isInstancePending(instance);
1323
1344
  UUFlowManager.isHandlerOrAgent(approve, current_user);
1345
+ console.log(`[workflow/engine] [workflow_engine] validate took ${Date.now() - t2}ms`);
1324
1346
 
1325
1347
  // Get current step info
1326
1348
  const step = await UUFlowManager.getStep(instance, flow, trace.step);
@@ -1332,6 +1354,7 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1332
1354
  const setObj = {};
1333
1355
  let key_str = "";
1334
1356
 
1357
+ const t3 = Date.now();
1335
1358
  // Find the approve to update
1336
1359
  for (let i = 0; i < trace_approves.length; i++) {
1337
1360
  if (trace_approves[i]._id === approve_id) {
@@ -1372,18 +1395,24 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1372
1395
  setObj.modified_by = current_user;
1373
1396
 
1374
1397
  // Update instance
1398
+ const t3_1 = Date.now();
1375
1399
  const instancesCollection = await getCollection('instances');
1376
1400
  await instancesCollection.updateOne(
1377
1401
  { _id: instance_id, "traces._id": trace_id },
1378
1402
  { $set: setObj }
1379
1403
  );
1404
+ console.log(`[workflow/engine] [workflow_engine] first updateOne took ${Date.now() - t3_1}ms`);
1380
1405
 
1381
1406
  // Update instance tasks
1407
+ const t3_2 = Date.now();
1382
1408
  await update_instance_tasks(instance_id, trace_id, approve_id);
1409
+ console.log(`[workflow/engine] [workflow_engine] first update_instance_tasks took ${Date.now() - t3_2}ms`);
1383
1410
  break;
1384
1411
  }
1385
1412
  }
1413
+ console.log(`[workflow/engine] [workflow_engine] update instance(first part) took ${Date.now() - t3}ms`);
1386
1414
 
1415
+ const t4 = Date.now();
1387
1416
  // Reload instance and revalidate after update
1388
1417
  const updatedInstance = await UUFlowManager.getInstance(instance_id);
1389
1418
  const updatedTrace = await UUFlowManager.getTrace(updatedInstance, trace_id);
@@ -1393,6 +1422,7 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1393
1422
  UUFlowManager.isApproveNotFinished(updatedApprove);
1394
1423
  UUFlowManager.isInstancePending(updatedInstance);
1395
1424
  UUFlowManager.isHandlerOrAgent(updatedApprove, current_user);
1425
+ console.log(`[workflow/engine] [workflow_engine] reload and revalidate took ${Date.now() - t4}ms`);
1396
1426
 
1397
1427
  // Prepare final update object
1398
1428
  const updateObj = { $set: {} };
@@ -1406,11 +1436,14 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1406
1436
  throw new Error('不能指定多个后续步骤');
1407
1437
  }
1408
1438
 
1439
+ const t5 = Date.now();
1409
1440
  // Validate next step users
1410
1441
  for (const next_step_user of next_steps[0].users || []) {
1411
1442
  await UUFlowManager.getSpaceUser(space_id, next_step_user);
1412
1443
  }
1444
+ console.log(`[workflow/engine] [workflow_engine] validate next step users took ${Date.now() - t5}ms`);
1413
1445
 
1446
+ const t6 = Date.now();
1414
1447
  // Handle different step types
1415
1448
  if (["start", "submit", "condition"].includes(step_type)) {
1416
1449
  Object.assign(updateObj, await UUFlowManager.engine_step_type_is_start_or_submit_or_condition(
@@ -1433,23 +1466,33 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1433
1466
  } else if (step_type === "end") {
1434
1467
  throw new Error('end结点出现approve,服务器错误');
1435
1468
  }
1469
+ console.log(`[workflow/engine] [workflow_engine] engine_step_type_... took ${Date.now() - t6}ms`);
1436
1470
 
1471
+ const t7 = Date.now();
1437
1472
  // Calculate keywords and extras
1438
1473
  const form = await UUFlowManager.getForm(updatedInstance.form);
1439
1474
  updateObj.$set.keywords = await UUFlowManager.caculateKeywords(updateObj.$set.values, form, updatedInstance.form_version);
1440
1475
  updateObj.$set.extras = await UUFlowManager.caculateExtras(updateObj.$set.values, form, updatedInstance.form_version);
1476
+ console.log(`[workflow/engine] [workflow_engine] caculateKeywords and extras took ${Date.now() - t7}ms`);
1441
1477
 
1478
+ const t8 = Date.now();
1442
1479
  // Update instance
1480
+ const t8_1 = Date.now();
1443
1481
  const instancesCollection = await getCollection('instances');
1444
1482
  await instancesCollection.updateOne({ _id: instance_id }, updateObj);
1483
+ console.log(`[workflow/engine] [workflow_engine] second updateOne took ${Date.now() - t8_1}ms`);
1445
1484
 
1446
1485
  // Insert new instance tasks if needed
1447
1486
  if (updateObj.$push?.traces?.approves) {
1487
+ const t8_2 = Date.now();
1448
1488
  const newTrace = updateObj.$push.traces;
1449
1489
  const approveIds = newTrace.approves.map(a => a._id);
1450
1490
  await insert_many_instance_tasks(instance_id, newTrace._id, approveIds);
1491
+ console.log(`[workflow/engine] [workflow_engine] second insert_many_instance_tasks took ${Date.now() - t8_2}ms`);
1451
1492
  }
1493
+ console.log(`[workflow/engine] [workflow_engine] update instance(second part) took ${Date.now() - t8}ms`);
1452
1494
 
1495
+ const t9 = Date.now();
1453
1496
  // Get final updated instance
1454
1497
  const finalInstance = await UUFlowManager.getInstance(instance_id);
1455
1498
  const finalInstanceTrace = _.find(finalInstance.traces, t => t._id === trace_id);
@@ -1480,7 +1523,9 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1480
1523
  await pushManager.send_instance_notification("submit_pending_inbox", finalInstance, description, current_user_info);
1481
1524
  }
1482
1525
  }
1526
+ console.log(`[workflow/engine] [workflow_engine] send_instance_notification took ${Date.now() - t9}ms`);
1483
1527
 
1528
+ const t10 = Date.now();
1484
1529
  // Send message to current user and trigger webhook
1485
1530
  await pushManager.send_message_current_user(current_user_info);
1486
1531
 
@@ -1494,6 +1539,8 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1494
1539
 
1495
1540
  await pushManager.triggerWebhook(flow_id, finalInstance, approve_from_client, 'engine_submit', current_user, to_users);
1496
1541
  await UUFlowManager.distributedInstancesRemind(finalInstance);
1542
+ console.log(`[workflow/engine] [workflow_engine] others took ${Date.now() - t10}ms`);
1543
+ console.log(`[workflow/engine] stats: ${JSON.stringify(UUFlowManager.stats)}`);
1497
1544
 
1498
1545
  return finalInstance;
1499
1546
  };
@@ -1519,11 +1566,14 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1519
1566
  space_user_org_info, judge, instance, flow, step,
1520
1567
  current_user, current_user_info, auto_submitted
1521
1568
  ) {
1569
+ console.time(`engine_step_type_is_start_or_submit_or_condition ${approve_id}`);
1522
1570
  const setObj = {};
1523
1571
  const updateObj = {};
1524
1572
  const setTraceObj = {};
1525
1573
  const space_id = instance.space;
1526
1574
 
1575
+ console.time(`start_submit_validate_next_step ${approve_id}`);
1576
+ const t0 = Date.now();
1527
1577
  // Validate next steps
1528
1578
  const nextSteps = await UUFlowManager.getNextSteps(instance, flow, step, "");
1529
1579
  for (const approve_next_step of next_steps) {
@@ -1537,9 +1587,12 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1537
1587
  const next_step = await UUFlowManager.getStep(instance, flow, next_step_id);
1538
1588
  const next_step_type = next_step.step_type;
1539
1589
  const next_step_name = next_step.name;
1590
+ console.log(`[workflow/engine] [step_start_submit] validate and get next step took ${Date.now() - t0}ms`);
1591
+ console.timeEnd(`start_submit_validate_next_step ${approve_id}`);
1540
1592
 
1541
1593
  // Handle end step
1542
1594
  if (next_step_type === "end") {
1595
+ console.time(`start_submit_handle_end_step ${approve_id}`);
1543
1596
  const instance_traces = instance.traces;
1544
1597
 
1545
1598
  // Update current trace and approve
@@ -1602,7 +1655,10 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1602
1655
  setObj.current_step_name = next_step_name;
1603
1656
  setObj.final_decision = 'approved';
1604
1657
  setObj.current_step_auto_submit = false;
1658
+ console.timeEnd(`start_submit_handle_end_step ${approve_id}`);
1605
1659
  } else {
1660
+ console.time(`start_submit_handle_next_step ${approve_id}`);
1661
+ const t1 = Date.now();
1606
1662
  // Handle non-end steps
1607
1663
  const next_step_users = next_steps[0].users;
1608
1664
 
@@ -1619,6 +1675,7 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1619
1675
  if (!UUFlowManager.checkNestStepUsersIsValid(next_step_users, next_user_ids, next_step)) {
1620
1676
  throw new Error("指定的下一步处理人有误");
1621
1677
  }
1678
+ console.log(`[workflow/engine] [step_start_submit] validate next step users internal took ${Date.now() - t1}ms`);
1622
1679
 
1623
1680
  // Update current trace and approve
1624
1681
  const instance_traces = instance.traces;
@@ -1665,6 +1722,7 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1665
1722
  const usersCollection = await getCollection('users');
1666
1723
  const spaceUsersCollection = await getCollection('space_users');
1667
1724
 
1725
+ let tLoop = Date.now();
1668
1726
  for (let idx = 0; idx < next_step_users.length; idx++) {
1669
1727
  const next_step_user_id = next_step_users[idx];
1670
1728
  const user_info = await usersCollection.findOne(
@@ -1718,6 +1776,7 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1718
1776
  UUFlowManager.setRemindInfo(updated_values, newApprove);
1719
1777
  newTrace.approves.push(newApprove);
1720
1778
  }
1779
+ console.log(`[workflow/engine] [step_start_submit] next_step_users loop took ${Date.now() - tLoop}ms`);
1721
1780
 
1722
1781
  // Prepare instance update
1723
1782
  setObj.state = "pending";
@@ -1739,20 +1798,30 @@ UUFlowManager.engine_step_type_is_start_or_submit_or_condition = async function
1739
1798
  updateObj.$push = { traces: newTrace };
1740
1799
  setObj.current_step_name = next_step_name;
1741
1800
  setObj.current_step_auto_submit = await UUFlowManager.getCurrentStepAutoSubmit(flow.timeout_auto_submit, next_step.lines);
1801
+ console.timeEnd(`start_submit_handle_next_step ${approve_id}`);
1742
1802
  }
1743
1803
 
1744
1804
  // Apply trace updates
1805
+ console.time(`start_submit_trace_updateOne ${approve_id}`);
1806
+ const t2 = Date.now();
1745
1807
  const instancesCollection = await getCollection('instances');
1746
1808
  await instancesCollection.updateOne(
1747
1809
  { _id: instance_id },
1748
1810
  { $set: setTraceObj }
1749
1811
  );
1812
+ console.log(`[workflow/engine] [step_start_submit] trace updateOne took ${Date.now() - t2}ms`);
1813
+ console.timeEnd(`start_submit_trace_updateOne ${approve_id}`);
1750
1814
 
1751
1815
  // Update instance tasks
1816
+ console.time(`start_submit_update_instance_tasks ${approve_id}`);
1817
+ const t3 = Date.now();
1752
1818
  await update_instance_tasks(instance_id, trace_id, approve_id);
1819
+ console.log(`[workflow/engine] [step_start_submit] update_instance_tasks took ${Date.now() - t3}ms`);
1820
+ console.timeEnd(`start_submit_update_instance_tasks ${approve_id}`);
1753
1821
 
1754
1822
  // Combine all updates
1755
1823
  updateObj.$set = setObj;
1824
+ console.timeEnd(`engine_step_type_is_start_or_submit_or_condition ${approve_id}`);
1756
1825
  return updateObj;
1757
1826
  };
1758
1827
 
@@ -32,6 +32,10 @@ amis_schema: |-
32
32
  {
33
33
  "actionType": "custom",
34
34
  "script":"window.$('.list-view-btn-reload').click()"
35
+ },
36
+ {
37
+ "actionType": "custom",
38
+ "script":"window.$('.instance-nav-reload').click()"
35
39
  }
36
40
  ],
37
41
  "weight": 0
@@ -71,6 +71,10 @@ amis_schema: |-
71
71
  {
72
72
  "actionType": "custom",
73
73
  "script":"window.$('.list-view-btn-reload').click()"
74
+ },
75
+ {
76
+ "actionType": "custom",
77
+ "script":"window.$('.instance-nav-reload').click()"
74
78
  }
75
79
  ]
76
80
  }
@@ -350,6 +350,19 @@
350
350
  ".steedos-amis-instance-view .form-control .antd-Table-table tbody tr:last-child td": {
351
351
  "border-right": "0px"
352
352
  },
353
+ ".steedos-instance-related-view-wrapper .instance-form-view": {
354
+ "table-layout": "fixed !important",
355
+ "width": "100% !important"
356
+ },
357
+ ".steedos-instance-related-view-wrapper .steedos-input-table": {
358
+ "width": "100% !important",
359
+ "display": "block !important"
360
+ },
361
+ ".steedos-instance-related-view-wrapper .antd-Table-contentWrap": {
362
+ "overflow-x": "auto !important",
363
+ "display": "block !important",
364
+ "width": "100% !important"
365
+ },
353
366
  ".antd-Table-content-colDragLine": {
354
367
  "display": "none !important"
355
368
  },
@@ -373,10 +386,23 @@
373
386
  "position": "static !important"
374
387
  },
375
388
  ".steedos-instance-related-view-wrapper .instance-form": {
376
- "margin": "0 auto"
389
+ "margin": "0 auto",
390
+ "width": "100% !important",
391
+ "max-width": "100% !important"
392
+ },
393
+ ".steedos-instance-related-view-wrapper .instance-form-view": {
394
+ "table-layout": "fixed !important",
395
+ "width": "100% !important"
396
+ },
397
+ ".steedos-instance-related-view-wrapper .steedos-input-table": {
398
+ "width": "100% !important",
399
+ "display": "block !important"
377
400
  },
378
401
  ".steedos-instance-related-view-wrapper .antd-Table-contentWrap": {
379
- "overflow": "visible !important",
402
+ "overflow-y": "visible !important",
403
+ "overflow-x": "auto !important",
404
+ "display": "block !important",
405
+ "width": "100% !important",
380
406
  "height": "auto !important"
381
407
  },
382
408
  ".steedos-instance-related-view-wrapper .instance-form-view td": {
@@ -44,6 +44,7 @@ router.get('/am/designer/startup', async function (req, res) {
44
44
  let userId = req.user.userId;
45
45
  let queryParams = req.query;
46
46
  let companyId = queryParams["companyId"];
47
+ let flowId = queryParams["flowId"];
47
48
  let isCompanyAdmin = false;
48
49
  let spaceIds = [];
49
50
  let spaces = [];
@@ -71,7 +72,7 @@ router.get('/am/designer/startup', async function (req, res) {
71
72
  spaceIds = _.pluck(spaces, '_id');
72
73
  }
73
74
 
74
- let changeSet = await designerManager.getByAdminSpaceIds(spaceIds, companyId, isCompanyAdmin)
75
+ let changeSet = await designerManager.getByAdminSpaceIds(spaceIds, companyId, isCompanyAdmin, flowId)
75
76
  changeSet['Spaces'] = spaces
76
77
  changeSet['sync_token'] = new Date().getTime() / 1000
77
78
  res.send(changeSet)
@@ -513,7 +513,7 @@ const FlowversionAPI = {
513
513
  <meta name="mobile-web-app-capable" content="yes">
514
514
  <meta name="theme-color" content="#000">
515
515
  <meta name="application-name">
516
- <script type="text/javascript" src="/unpkg.com/jquery@1.11.2/dist/jquery.min.js"></script>
516
+ <script type="text/javascript" src="/unpkg.com/jquery@3.7.1/dist/jquery.min.js"></script>
517
517
  <script type="text/javascript" src="/unpkg.com/mermaid@9.1.2/dist/mermaid.min.js"></script>
518
518
  <style>
519
519
  body {
@@ -54,6 +54,8 @@ const afterHook = require('./afterHook');
54
54
  * }
55
55
  */
56
56
  router.post('/api/workflow/engine', requireAuthentication, afterHook, async function (req, res) {
57
+ const startTime = Date.now();
58
+ console.log(`[workflow/engine] start`);
57
59
  try {
58
60
  let userSession = req.user;
59
61
  const spaceId = userSession.spaceId;
@@ -66,11 +68,17 @@ router.post('/api/workflow/engine', requireAuthentication, afterHook, async func
66
68
 
67
69
  // beforeStepSubmit
68
70
  const insId = approve_from_client.instance;
69
- const instanceDoc = (await objectql.getObject('instances').find({ filters: [['_id', '=', insId]], fields: ['flow', 'flow_version'] }))[0];
71
+ const t1 = Date.now();
72
+ const instanceDoc = await objectql.getObject('instances').findOne(insId, { fields: ['flow', 'flow_version'] });
73
+ console.log(`[workflow/engine] getObject instances took ${Date.now() - t1}ms`);
70
74
  const flowId = instanceDoc.flow;
75
+ const t2 = Date.now();
71
76
  await excuteTriggers({ when: 'beforeStepSubmit', userId, flowId, insId });
77
+ console.log(`[workflow/engine] beforeStepSubmit took ${Date.now() - t2}ms`);
72
78
  // beforeEnd
79
+ const t3 = Date.now();
73
80
  const flowDoc = await objectql.getObject('flows').findOne(flowId);
81
+ console.log(`[workflow/engine] beforeEnd find logic took ${Date.now() - t3}ms`);
74
82
  const next_steps = approve_from_client["next_steps"];
75
83
  const next_step_id = next_steps[0]["step"];
76
84
  const next_step = getStep(instanceDoc, flowDoc, next_step_id);
@@ -78,17 +86,26 @@ router.post('/api/workflow/engine', requireAuthentication, afterHook, async func
78
86
  if (next_step_type == "end") {
79
87
  await excuteTriggers({ when: 'beforeEnd', userId, flowId, insId });
80
88
  }
89
+ console.log(`[workflow/engine] beforeEnd logic took ${Date.now() - t3}ms`);
81
90
 
82
91
  try {
92
+ const t4 = Date.now();
83
93
  const instance = await UUFlowManager.workflow_engine(approve_from_client, userSession, userId);
94
+ console.log(`[workflow/engine] workflow_engine took ${Date.now() - t4}ms`);
84
95
  // afterStepSubmit
96
+ const t5 = Date.now();
85
97
  await excuteTriggers({ when: 'afterStepSubmit', userId, flowId, insId });
98
+ console.log(`[workflow/engine] afterStepSubmit took ${Date.now() - t5}ms`);
86
99
  // afterEnd
87
100
  if (instance.state === 'completed') {
101
+ const t6 = Date.now();
88
102
  await excuteTriggers({ when: 'afterEnd', userId, flowId, insId });
103
+ console.log(`[workflow/engine] afterEnd took ${Date.now() - t6}ms`);
89
104
  }
105
+ console.log(`[workflow/engine] total took ${Date.now() - startTime}ms`);
90
106
  res.status(200).send({});
91
107
  } catch (e) {
108
+ console.log(`[workflow/engine] inner catch total took ${Date.now() - startTime}ms`);
92
109
  console.error(e);
93
110
  res.status(200).send({
94
111
  errors: [{ errorMessage: e.message }]
@@ -96,6 +113,7 @@ router.post('/api/workflow/engine', requireAuthentication, afterHook, async func
96
113
  }
97
114
 
98
115
  } catch (e) {
116
+ console.log(`[workflow/engine] outer catch total took ${Date.now() - startTime}ms`);
99
117
  res.status(200).send({
100
118
  errors: [{ errorMessage: e.message }]
101
119
  });