@steedos-labs/plugin-workflow 3.0.13 → 3.0.14

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/README.md CHANGED
@@ -6,4 +6,27 @@
6
6
  * @Description:
7
7
  -->
8
8
  ## 功能说明
9
- - 审批王服务,包含 流程触发器
9
+ - 审批王服务,包含 流程触发器
10
+
11
+ ## 环境变量配置
12
+
13
+ ### STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER
14
+ - **说明**: 控制是否在"待处理"、"监控箱"视图以及左侧导航菜单中按流程分类进行筛选和显示
15
+ - **默认行为**: 启用分类筛选(当环境变量未设置或设置为除 'false' 以外的任何值时)
16
+ - **可选值**:
17
+ - 不设置或设置为除 `'false'` 以外的任何值: 启用按分类筛选,根据应用(app)显示对应分类的流程
18
+ - `'false'` (字符串): 禁用按分类筛选,显示所有流程
19
+ - **使用场景**: 国产化优化,简化流程展示逻辑
20
+ - **影响范围**:
21
+ - 待处理(Pending)和监控箱(Monitor Box)视图的数据筛选
22
+ - 左侧导航菜单结构:禁用时仅显示box层级(待办箱、监控箱等),不显示分类和流程子菜单
23
+
24
+ **示例配置**:
25
+ ```bash
26
+ # 禁用分类筛选
27
+ STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER=false
28
+
29
+ # 启用分类筛选(以下任一方式)
30
+ # STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER=true
31
+ # 或者不设置该环境变量(默认启用)
32
+ ```
@@ -8,6 +8,7 @@ mobile: true
8
8
  sort: 10
9
9
  # tabs:
10
10
  # - object_instance_tasks
11
+ default_tab: object_instance_tasks
11
12
 
12
13
  showSidebar: true
13
14
  enable_nav_schema: true
@@ -24,12 +25,12 @@ nav_schema: {
24
25
  {
25
26
  "type": "wrapper",
26
27
  "size": "none",
27
- "className": "instances-sidebar-wrapper mt-1",
28
+ "className": "instances-sidebar-wrapper mt-1 bg-white",
28
29
  "body": [
29
30
  {
30
31
  "type": "service",
31
32
  "id": "u:instanceNav",
32
- "className": "bg-none",
33
+ "className": "bg-white",
33
34
  "onEvent": {
34
35
  "@data.changed.instances": {
35
36
  "actions": [
@@ -58,8 +59,8 @@ nav_schema: {
58
59
  {
59
60
  "type": "input-tree",
60
61
  "name": "tree",
61
- "treeContainerClassName": "h-full",
62
- "className": "instance-box-tree h-full w-full p-0",
62
+ "treeContainerClassName": "h-full bg-white",
63
+ "className": "instance-box-tree h-full w-full p-0 bg-white",
63
64
  "id": "u:9f3dd961ca12",
64
65
  "stacked": true,
65
66
  "multiple": false,
@@ -112,23 +113,23 @@ nav_schema: {
112
113
  },
113
114
  "menuTpl": {
114
115
  "type": "wrapper",
115
- "className": "flex flex-row p-0 m-0",
116
+ "className": "flex items-center py-1.5 px-3 m-0 rounded-md transition-colors duration-150",
116
117
  "body": [
117
118
  {
118
119
  "type": "tpl",
119
- "className": "flex-1 w-6/12",
120
+ "className": "flex-1 leading-6 truncate instance-menu-label",
120
121
  "tpl": "${label}",
121
122
  "id": "u:9dee51f00db4"
122
123
  },
123
124
  {
124
125
  "type": "tpl",
125
- "className": "-mx-11 ",
126
+ "className": "ml-auto",
126
127
  "tpl": "",
127
128
  "badge": {
128
129
  "className": "h-0",
129
130
  "offset": [
130
- -20,
131
- 12
131
+ -5,
132
+ 0
132
133
  ],
133
134
  "mode": "text",
134
135
  "text": "${tag | toInt}",
@@ -605,6 +605,7 @@ UUFlowManager.calculateConditionWithAmis = function (values, condition_str) {
605
605
  * @returns {Boolean} Condition result
606
606
  */
607
607
  UUFlowManager.calculateCondition = function (values, condition_str) {
608
+ // console.log('calculateCondition', values, condition_str);
608
609
  try {
609
610
  const __values = values;
610
611
 
@@ -817,10 +818,7 @@ UUFlowManager.initFormulaValues = async function (instance, values) {
817
818
  __values["applicant"] = {
818
819
  roles: await UUFlowManager.getUserRoles(instance.applicant, instance.space),
819
820
  name: instance.applicant_name,
820
- organization: {
821
- fullname: instance.applicant_organization_fullname,
822
- name: instance.applicant_organization_name
823
- },
821
+ organization: await UUFlowManager.getOrganization(instance.applicant_organization),
824
822
  id: instance.applicant
825
823
  };
826
824
 
@@ -23,9 +23,7 @@ module.exports = {
23
23
  },
24
24
  design_form_layoutVisible: function(object_name, record_id, record_permissions, data) {
25
25
  var record = data && data.record;
26
- if (!Steedos.isSpaceAdmin()) {
27
- return false
28
- }
26
+
29
27
  if (!record) {
30
28
  return false;
31
29
  }
@@ -60,6 +60,9 @@ fields:
60
60
  readonly: true
61
61
  visible_on: "{{global.mode !='read' ? false : true}}"
62
62
  name: current_no
63
+ company_id:
64
+ label: Main Division
65
+ visible_on: "{{true}}"
63
66
  description:
64
67
  label: Description
65
68
  type: textarea
@@ -77,8 +80,6 @@ fields:
77
80
  type: textarea
78
81
  is_wide: true
79
82
  name: help_text
80
- company_id:
81
- label: Main Division
82
83
  created_by:
83
84
  label: Created by
84
85
  sort_no: 9999
@@ -906,7 +907,7 @@ permission_set:
906
907
  allowEdit: false
907
908
  allowRead: true
908
909
  modifyAllRecords: false
909
- viewAllRecords: true
910
+ viewAllRecords: false
910
911
  admin:
911
912
  allowCreate: true
912
913
  allowDelete: false
@@ -26,7 +26,7 @@
26
26
  "schemaApi": {
27
27
  "method": "get",
28
28
  "url": "/api/health_check?trace=${recordId}",
29
- "adaptor": "const result = {data: {'type':'wrapper','className':'p-0 h-full','body':[{'type':'steedos-instance-detail','id':'u:40052b3812c1','label':'Instance Detail','instanceId':context.recordId,'boxName':context.side_listview_id}],'id':'u:829a40757f0a'}};console.log('result===>', result); return result;"
29
+ "adaptor": "const urlParams = new URLSearchParams(location.search); const sideListViewId = urlParams.get('side_listview_id'); const result = {data: {'type':'wrapper','className':'p-0 h-full','body':[{'type':'steedos-instance-detail','id':'u:40052b3812c1','label':'Instance Detail','instanceId':context.recordId,'boxName':sideListViewId}],'id':'u:829a40757f0a'}};return result;"
30
30
  },
31
31
  "body": {},
32
32
  "className": "h-full",
@@ -19,6 +19,11 @@ router.post('/api/workflow/v2/instance/upgrade', requireAuthentication, async fu
19
19
  'flow','form','applicant_name','applicant_organization','applicant_organization_fullname','applicant_organization_name',
20
20
  'code', 'flow_version', 'form_version', 'submit_date', 'flow_name', 'code', 'traces', 'state'
21
21
  ]});
22
+ if(!record){
23
+ return res.status(200).send({
24
+ instance: false
25
+ });
26
+ }
22
27
  if(record.state !== 'draft'){
23
28
  return res.status(200).send({
24
29
  instance: true
@@ -56,54 +56,67 @@ const getCategoriesInbox = async (userSession, req, currentUrl) => {
56
56
  fields: ['_id', 'flow', 'category','flow_name','category_name']
57
57
  }, userSession)
58
58
 
59
+ // Check environment variable to control category filtering
60
+ // Default is enabled (when not set or set to any value except 'false')
61
+ // Only the string 'false' will disable the filtering
62
+ const enableCategoryFilter = process.env.STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER !== 'false';
63
+
59
64
  const output = [];
60
- const categoryGroups = lodash.groupBy(data, 'category_name');
61
- lodash.each(categoryGroups, (v, k)=>{
62
- let categoryBadge = 0;
63
- const flowGroups = lodash.groupBy(v, 'flow_name');
64
- const flows = [];
65
- const categoryValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['category','=',${v[0].category?"'" + v[0].category + "'":v[0].category}]&flowId=&categoryId=${v[0].category}`;
66
- let categoryIsUnfolded = false;
67
- lodash.each(flowGroups, (v2, k2)=>{
68
- const flowValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['flow','=','${v2[0].flow}']&flowId=${v2[0].flow}&categoryId=${v[0].category}`;
69
- let flowIsUnfolded = false;
70
- if(currentUrl == flowValue){
71
- flowIsUnfolded = true;
65
+
66
+ if (!enableCategoryFilter) {
67
+ // When category filtering is disabled, return empty array (no sub-navigation)
68
+ // Only box-level items will be shown
69
+ } else {
70
+ // Original logic with category grouping
71
+ const categoryGroups = lodash.groupBy(data, 'category_name');
72
+ lodash.each(categoryGroups, (v, k)=>{
73
+ let categoryBadge = 0;
74
+ const flowGroups = lodash.groupBy(v, 'flow_name');
75
+ const flows = [];
76
+ const categoryValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['category','=',${v[0].category?"'" + v[0].category + "'":v[0].category}]&flowId=&categoryId=${v[0].category}`;
77
+ let categoryIsUnfolded = false;
78
+ lodash.each(flowGroups, (v2, k2)=>{
79
+ const flowValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['flow','=','${v2[0].flow}']&flowId=${v2[0].flow}&categoryId=${v[0].category}`;
80
+ let flowIsUnfolded = false;
81
+ if(currentUrl == flowValue){
82
+ flowIsUnfolded = true;
83
+ categoryIsUnfolded = true;
84
+ }
85
+ categoryBadge += v2.length
86
+ flows.push({
87
+ label: k2,
88
+ flow_name: k2,
89
+ tag:v2.length,
90
+ options:{
91
+ level:3,
92
+ value: v2[0].flow,
93
+ name: 'flow',
94
+ to: flowValue,
95
+ },
96
+ value: flowValue,
97
+ unfolded: flowIsUnfolded
98
+ })
99
+ })
100
+ if(currentUrl == categoryValue){
72
101
  categoryIsUnfolded = true;
73
102
  }
74
- categoryBadge += v2.length
75
- flows.push({
76
- label: k2,
77
- flow_name: k2,
78
- tag:v2.length,
79
- options:{
80
- level:3,
81
- value: v2[0].flow,
82
- name: 'flow',
83
- to: flowValue,
103
+ output.push({
104
+ label: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
105
+ children: flows,
106
+ category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
107
+ tag: v.length,
108
+ options: {
109
+ level: 2,
110
+ value: v[0].category,
111
+ name: 'category',
112
+ to: categoryValue,
84
113
  },
85
- value: flowValue,
86
- unfolded: flowIsUnfolded
114
+ value: categoryValue,
115
+ unfolded: categoryIsUnfolded
87
116
  })
88
117
  })
89
- if(currentUrl == categoryValue){
90
- categoryIsUnfolded = true;
91
- }
92
- output.push({
93
- label: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
94
- children: flows,
95
- category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
96
- tag: v.length,
97
- options: {
98
- level: 2,
99
- value: v[0].category,
100
- name: 'category',
101
- to: categoryValue,
102
- },
103
- value: categoryValue,
104
- unfolded: categoryIsUnfolded
105
- })
106
- })
118
+ }
119
+
107
120
  return {
108
121
  schema: output,
109
122
  count: data.length,
@@ -121,119 +134,130 @@ const getCategoriesMonitor = async (userSession, req, currentUrl) => {
121
134
  let output = [];
122
135
  let monitorIsUnfolded = false;
123
136
 
137
+ // Check environment variable to control category filtering
138
+ // Default is enabled (when not set or set to any value except 'false')
139
+ // Only the string 'false' will disable the filtering
140
+ const enableCategoryFilter = process.env.STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER !== 'false';
141
+
124
142
  try {
125
- // const sa = new Date().getTime();
126
- const apps = await objectql.getObject('apps').find({filters: ['space', '=', userSession.spaceId], fields: ['_id', 'code']});
127
- // console.log(`find apps`, new Date().getTime() - sa)
128
- const appsMap = new Map(Object.entries(lodash.keyBy(apps, '_id')));
129
- // const sc = new Date().getTime();
130
- const categories = await objectql.getObject('categories').find({filters: ["space", "=", `${userSession.spaceId}`], sort: "sort_no desc"})
131
- // console.log(`find categories`, new Date().getTime() - sc)
132
- for (const item of categories) {
133
- if(item.app){
134
- item.app__expand = appsMap.get(item.app)
135
- }else{
136
- item.app__expand = {}
143
+ let flows = [];
144
+
145
+ if (!enableCategoryFilter) {
146
+ // When category filtering is disabled, return empty array (no sub-navigation)
147
+ // Only box-level items will be shown
148
+ // Still need to check permissions for hasFlowsPer (used to control monitor box visibility)
149
+ if (!hasFlowsPer) {
150
+ const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(userSession.spaceId, userSession.userId);
151
+ hasFlowsPer = flowIds && flowIds.length > 0;
152
+ }
153
+ } else {
154
+ // Original logic with category grouping
155
+ const apps = await objectql.getObject('apps').find({filters: ['space', '=', userSession.spaceId], fields: ['_id', 'code']});
156
+ const appsMap = new Map(Object.entries(lodash.keyBy(apps, '_id')));
157
+ const categories = await objectql.getObject('categories').find({filters: ["space", "=", `${userSession.spaceId}`], sort: "sort_no desc"})
158
+ for (const item of categories) {
159
+ if (item.app) {
160
+ item.app__expand = appsMap.get(item.app)
161
+ } else {
162
+ item.app__expand = {}
163
+ }
137
164
  }
138
- }
139
165
 
140
- let currentAppCategories = [];
141
- if(appId == "approve_workflow"){
142
- currentAppCategories = categories;
143
- }else{
144
- currentAppCategories = lodash.filter(categories, (category) => {
145
- if(category.app__expand?.code == appId) return true;
146
- else return false;
147
- })
148
- if(currentAppCategories.length == 0) {
149
- //如果没有任何分类绑定该app,则该app显示所有分类(该规则为审批王规则)
166
+ let currentAppCategories = [];
167
+ if (appId == "approve_workflow") {
150
168
  currentAppCategories = categories;
169
+ } else {
170
+ currentAppCategories = lodash.filter(categories, (category) => {
171
+ if (category.app__expand?.code == appId) return true;
172
+ else return false;
173
+ })
174
+ if (currentAppCategories.length == 0) {
175
+ //如果没有任何分类绑定该app,则该app显示所有分类(该规则为审批王规则)
176
+ currentAppCategories = categories;
177
+ }
151
178
  }
152
- }
153
- let categoriesIds = lodash.map(currentAppCategories, '_id');
154
- // console.log(`getCategoriesMonitor categoriesIds`, categoriesIds)
155
- // console.log(`getCategoriesMonitor hasFlowsPer`, hasFlowsPer)
156
- let flows = [];
157
- if (!hasFlowsPer) {
158
- const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(userSession.spaceId, userSession.userId);
159
- hasFlowsPer = flowIds && flowIds.length > 0;
160
- if (hasFlowsPer) {
179
+ let categoriesIds = lodash.map(currentAppCategories, '_id');
180
+
181
+ if (!hasFlowsPer) {
182
+ const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(userSession.spaceId, userSession.userId);
183
+ hasFlowsPer = flowIds && flowIds.length > 0;
184
+ if (hasFlowsPer) {
185
+ flows = await objectql.getObject('flows').find({
186
+ filters: [["_id","in", flowIds],"and",["category","in", categoriesIds], "and", ["state", "=", "enabled"]],
187
+ fields: ['_id', 'name', 'category', 'sort_no'],
188
+ sort:"sort_no desc"
189
+ });
190
+ }
191
+ } else {
161
192
  flows = await objectql.getObject('flows').find({
162
- filters: [["_id","in", flowIds],"and",["category","in", categoriesIds], "and", ["state", "=", "enabled"]],
193
+ filters:[["space", "=", userSession.spaceId],["category","in", categoriesIds],["state", "=", "enabled"]],
163
194
  fields: ['_id', 'name', 'category', 'sort_no'],
164
195
  sort:"sort_no desc"
165
- });
196
+ })
166
197
  }
167
- } else {
168
- // const s1 = new Date().getTime();
169
- flows = await objectql.getObject('flows').find({
170
- filters:[["space", "=", userSession.spaceId],["category","in", categoriesIds],["state", "=", "enabled"]],
171
- fields: ['_id', 'name', 'category', 'sort_no'],
172
- sort:"sort_no desc"
173
- })
174
- // console.log(`find flows`, new Date().getTime() - s1)
175
- }
176
- if (flows.length > 0) {
177
- const categoriesMap = new Map(Object.entries(lodash.keyBy(categories, '_id')));
198
+
199
+ if (flows.length > 0) {
200
+ const categoriesMap = new Map(Object.entries(lodash.keyBy(categories, '_id')));
178
201
 
179
- for (const item of flows) {
180
- if(item.category){
181
- item.category__expand = categoriesMap.get(item.category)
182
- }else{
183
- item.category__expand = {}
202
+ for (const item of flows) {
203
+ if (item.category) {
204
+ item.category__expand = categoriesMap.get(item.category)
205
+ } else {
206
+ item.category__expand = {}
207
+ }
184
208
  }
185
- }
186
209
 
187
- const categoryGroups = lodash.groupBy(flows, 'category__expand.name');
188
- lodash.each(categoryGroups, (v, k) => {
189
- const flowGroups = lodash.groupBy(v, 'name');
190
- const flows = [];
191
- const categoryValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['category','=',${v[0].category__expand?"'" + v[0].category__expand._id + "'":null}]&flowId=&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
192
- let categoryIsUnfolded = false;
193
- lodash.each(flowGroups, (v2, k2) => {
194
- const flowValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['flow','=','${v2[0]._id}']&flowId=${v2[0]._id}&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
195
- let flowIsUnfolded = false;
196
- if(currentUrl == flowValue){
197
- flowIsUnfolded = true;
210
+ const categoryGroups = lodash.groupBy(flows, 'category__expand.name');
211
+ lodash.each(categoryGroups, (v, k) => {
212
+ const flowGroups = lodash.groupBy(v, 'name');
213
+ const flows = [];
214
+ const categoryValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['category','=',${v[0].category__expand?"'" + v[0].category__expand._id + "'":null}]&flowId=&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
215
+ let categoryIsUnfolded = false;
216
+ lodash.each(flowGroups, (v2, k2) => {
217
+ const flowValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['flow','=','${v2[0]._id}']&flowId=${v2[0]._id}&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
218
+ let flowIsUnfolded = false;
219
+ if (currentUrl == flowValue) {
220
+ flowIsUnfolded = true;
221
+ categoryIsUnfolded = true;
222
+ monitorIsUnfolded = true;
223
+ }
224
+ flows.push({
225
+ label: k2,
226
+ flow_name: k2,
227
+ options: {
228
+ level: 3,
229
+ value: v2[0]._id,
230
+ name: 'flow',
231
+ to: flowValue,
232
+ },
233
+ value: flowValue,
234
+ unfolded: flowIsUnfolded
235
+ })
236
+ })
237
+ if (currentUrl == categoryValue) {
198
238
  categoryIsUnfolded = true;
199
239
  monitorIsUnfolded = true;
200
240
  }
201
- flows.push({
202
- label: k2,
203
- flow_name: k2,
241
+ output.push({
242
+ label: k == 'null' || k == 'undefined' || !k? "未分类" : k,
243
+ children: flows,
244
+ category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
204
245
  options: {
205
- level: 3,
206
- value: v2[0]._id,
207
- name: 'flow',
208
- to: flowValue,
246
+ level: 2,
247
+ value: v[0].category__expand && v[0].category__expand._id,
248
+ name: 'category',
249
+ to: categoryValue,
209
250
  },
210
- value: flowValue,
211
- unfolded: flowIsUnfolded
251
+ value: categoryValue,
252
+ unfolded: categoryIsUnfolded
212
253
  })
213
254
  })
214
- if(currentUrl == categoryValue){
215
- categoryIsUnfolded = true;
216
- monitorIsUnfolded = true;
217
- }
218
- output.push({
219
- label: k == 'null' || k == 'undefined' || !k? "未分类" : k,
220
- children: flows,
221
- category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
222
- options: {
223
- level: 2,
224
- value: v[0].category__expand && v[0].category__expand._id,
225
- name: 'category',
226
- to: categoryValue,
227
- },
228
- value: categoryValue,
229
- unfolded: categoryIsUnfolded
230
- })
231
- })
232
- output = lodash.sortBy(output, [function (o) {
233
- return lodash.findIndex(categories, (e) => {
234
- return e._id == o.options.value;
235
- });
236
- }]);
255
+ output = lodash.sortBy(output, [function (o) {
256
+ return lodash.findIndex(categories, (e) => {
257
+ return e._id == o.options.value;
258
+ });
259
+ }]);
260
+ }
237
261
  }
238
262
  } catch (error) {
239
263
  console.log(error)
@@ -302,7 +302,22 @@
302
302
  tpl.type = "input-text";
303
303
  }
304
304
  if(field.formula){
305
- tpl.value = `$${field.formula}`;
305
+ if(field.formula.startsWith('{') && (field.formula.endsWith('}') || field.formula.indexOf("}") > 0)){
306
+ // {申请人姓名}.organization.fullname 转换为 ${申请人姓名.organization.fullname}
307
+ // {申请人姓名.organization.fullname} 转换为 ${申请人姓名.organization.fullname}
308
+ if(field.formula.indexOf("}.") > 0){
309
+ // {申请人姓名}.organization.fullname
310
+ let formula = field.formula;
311
+ formula = formula.substring(1, formula.indexOf("}"));
312
+ tpl.value = `\${${formula}${field.formula.substring( field.formula.indexOf("}") + 1 )}}`;
313
+ } else {
314
+ // {申请人姓名.organization.fullname}
315
+ tpl.value = `$${field.formula}`;
316
+ }
317
+ }else{
318
+ // 替换掉所有双引号"
319
+ tpl.value = field.formula.replace(/"/g, '');
320
+ }
306
321
  }
307
322
  break;
308
323
  case "number":
@@ -283,7 +283,16 @@ module.exports = {
283
283
  },
284
284
  getAppCategoriesIds: {
285
285
  async handler(appId) {
286
- if(appId == "approve_workflow"){
286
+ // Check environment variable to control category filtering
287
+ // Default is enabled (when not set or set to any value except 'false')
288
+ // Only the string 'false' will disable the filtering
289
+ const enableCategoryFilter = process.env.STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER !== 'false';
290
+
291
+ if (!enableCategoryFilter) {
292
+ return [];
293
+ }
294
+
295
+ if (appId == "approve_workflow") {
287
296
  return [];
288
297
  }
289
298
  const categories = await objectql.getObject('categories').directFind({ filters: [['app', '=', appId]] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.13",
3
+ "version": "3.0.14",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -52,7 +52,27 @@
52
52
 
53
53
  .instance-box-tree .antd-TreeControl{
54
54
  padding: 0;
55
+ background: #ffffff;
55
56
  }
57
+
58
+ /* Remove default tree styling to allow custom styling */
59
+ .instance-box-tree .antd-Tree-itemLabel-item{
60
+ padding: 0 !important;
61
+ margin: 0 !important;
62
+ display: flex !important;
63
+ align-items: center !important;
64
+ width: 100%; /* Ensure it spans the width */
65
+ }
66
+
67
+ /* Ensure the label container is also flex centered and full width */
68
+ .instance-box-tree .antd-Tree-itemLabel {
69
+ display: flex !important;
70
+ align-items: center !important;
71
+ width: 100%;
72
+ padding-right: 4px;
73
+ }
74
+
75
+ /* Tree item wrapper - removed margin to allow full-row background */
56
76
  /* .instance-box-tree .antd-TreeControl{
57
77
  padding: 0;
58
78
  border-bottom: 0px;
@@ -79,10 +99,20 @@
79
99
  margin-right: 4px;
80
100
  } */
81
101
  .instance-box-tree .antd-Badge-text{
82
- background: #D3D6DD;
102
+ background: #e5e7eb;
103
+ color: #4b5563;
104
+ font-size: 11px;
105
+ padding: 0px 6px;
106
+ border-radius: 10px;
107
+ font-weight: 500;
108
+ line-height: 18px;
109
+ min-width: 18px;
110
+ display: inline-block;
111
+ text-align: center;
83
112
  }
84
113
  .instance-box-tree .antd-Tree-item:nth-child(1) .antd-Badge-text{
85
- background: #DF4D46;
114
+ background: #ef4444;
115
+ color: #ffffff;
86
116
  }
87
117
  /* .instance-box-tree .antd-Tree-itemLabel-item{
88
118
  height: 1.6rem;
@@ -115,12 +145,134 @@
115
145
  border: none !important;
116
146
  }
117
147
 
118
- .instance-box-tree .antd-Tree-item .is-checked{
119
- background-color: rgba(21,137,238,.1);
148
+ /* Base styling for all menu labels - must be specific enough */
149
+ .instance-box-tree .antd-Tree .instance-menu-label {
150
+ font-weight: 400;
151
+ color: #6b7280;
152
+ }
153
+
154
+ /* Tree item spacing for proper layout */
155
+ .instance-box-tree .antd-Tree-item {
156
+ margin: 2px 8px;
157
+ }
158
+
159
+ /* Selected state styling - Using robust pseudo-element strategy for cross-browser support */
160
+
161
+ /* 1. Reset positions to ensure clean background layering */
162
+ .instance-box-tree .antd-Tree-item {
163
+ margin: 2px 8px; /* Maintain standard margin */
164
+ position: relative !important; /* Context for absolute positioning */
165
+ z-index: 0; /* Create stacking context so -1 doesn't go behind the white container */
166
+ }
167
+
168
+ /* 2. Remove ANY positioning from the label so it doesn't trap the pseudo-element */
169
+ .instance-box-tree .antd-Tree-itemLabel.is-checked {
170
+ background-color: transparent !important;
171
+ position: static !important;
172
+ }
173
+
174
+ /* 3. Helper to make label static if checked is on item */
175
+ .instance-box-tree .antd-Tree-item.is-checked > .antd-Tree-itemLabel {
176
+ background-color: transparent !important;
177
+ position: static !important;
178
+ }
179
+
180
+ /* 4. The background pseudo-element */
181
+ .instance-box-tree .antd-Tree-itemLabel.is-checked::before,
182
+ .instance-box-tree .antd-Tree-item.is-checked > .antd-Tree-itemLabel::before {
183
+ content: "";
184
+ position: absolute;
185
+ left: 0;
186
+ right: 0;
187
+ top: 0; /* Cover full height (margin handles the spacing) */
188
+ bottom: 0;
189
+ background-color: var(--color-brand-50, #dbeafe);
190
+ border-radius: 6px;
191
+ z-index: -1; /* Behind text */
192
+ }
193
+
194
+ .instance-box-tree .antd-Tree-itemLabel.is-checked .instance-menu-label,
195
+ .instance-box-tree .antd-Tree-item.is-checked .instance-menu-label {
196
+ color: var(--Menu-light-fontColor-onHover, #1e40af) !important;
120
197
  }
121
198
 
122
- .instance-box-tree .antd-Tree-item .is-checked .antd-Tree-itemLabel-item{
123
- background-color: unset;
199
+ .instance-box-tree .antd-Tree-itemLabel.is-checked .antd-Tree-itemIcon,
200
+ .instance-box-tree .antd-Tree-item.is-checked .antd-Tree-itemIcon {
201
+ color: var(--Menu-light-fontColor-onHover, #1e40af) !important;
202
+ }
203
+
204
+ /* Hover state - entire row with light gray background */
205
+ .instance-box-tree .antd-Tree-item:hover {
206
+ background-color: #f3f4f6;
207
+ border-radius: 6px;
208
+ margin: 2px 8px;
209
+ }
210
+
211
+ .instance-box-tree .antd-Tree-item.is-checked:hover {
212
+ background-color: var(--color-brand-50, #dbeafe) !important;
213
+ }
214
+
215
+ /* Group title styling - larger and bolder */
216
+ .instance-box-tree .antd-Tree .antd-Tree-item[aria-level="1"] .instance-menu-label {
217
+ font-size: 13px !important;
218
+ font-weight: 600;
219
+ color: #374151;
220
+ }
221
+ --isL
222
+ /* Child item (non-leaf) styling - normal size and weight */
223
+ .instance-box-tree .antd-Tree .antd-Tree-item[aria-level="2"]:not(.is-leaf) .instance-menu-label {
224
+ font-size: 13px !important;
225
+ font-weight: 400;
226
+ color: #6b7280;
227
+ }
228
+
229
+ /* Leaf node styling - darker and larger for prominence */
230
+ .instance-box-tree .antd-Tree .antd-Tree-item--isLeaf .instance-menu-label {
231
+ font-size: 14px !important;
232
+ font-weight: 600 !important;
233
+ color: rgb(71 85 105 / var(--tw-text-opacity, 1)) !important;
234
+ }
235
+
236
+ /* Override leaf node color when selected */
237
+ .instance-box-tree .antd-Tree .antd-Tree-item--isLeaf .antd-Tree-itemLabel.is-checked .instance-menu-label {
238
+ color: var(--Menu-light-fontColor-onHover, #1e40af) !important;
239
+ font-weight: 600 !important;
240
+ }
241
+
242
+ /* Fix alignment and spacing for the custom menu template wrapper */
243
+ .instance-box-tree .antd-Tree-itemText > div {
244
+ padding-top: 0px !important; /* Reduced from 4px to fix "text too low" */
245
+ padding-bottom: 0px !important;
246
+ line-height: 24px; /* Explicit line height to ensure centering */
247
+ display: flex;
248
+ align-items: center;
249
+ }
250
+
251
+ /* Ensure the text container takes available width */
252
+ .instance-box-tree .antd-Tree-itemText {
253
+ flex: 1;
254
+ display: flex;
255
+ align-items: center;
256
+ position: relative; /* Ensure z-index works if needed */
257
+ z-index: 1;
258
+ min-width: 0; /* Enable truncation */
259
+ }
260
+
261
+ /* Icon styling */
262
+ .instance-box-tree .antd-Tree-itemIcon{
263
+ color: #6b7280;
264
+ margin-right: 8px;
265
+ }
266
+
267
+ /* Arrow styling */
268
+ .instance-box-tree .antd-Tree-itemArrow{
269
+ color: #9ca3af;
270
+ transition: transform 0.2s ease;
271
+ margin-right: 4px;
272
+ }
273
+
274
+ .instance-box-tree .antd-Tree-item.is-expanded > .antd-Tree-itemArrow{
275
+ transform: rotate(90deg);
124
276
  }
125
277
 
126
278
 
@@ -360,7 +512,7 @@ tbody .color-priority-muted *{
360
512
  }
361
513
 
362
514
  .steedos-instance-detail-wrapper{
363
- height: calc(100vh - 84px);
515
+ height: calc(100vh - 101px);
364
516
  }
365
517
 
366
518
  .steedos-amis-instance-view-body .antd-Panel-title{
@@ -372,10 +524,27 @@ tbody .color-priority-muted *{
372
524
  z-index: 900;
373
525
  }
374
526
 
375
- /* .instances-sidebar-wrapper{
376
- overflow-y: auto;
377
- height: calc(100vh - 50px);
378
- } */
527
+ /* Sidebar wrapper - no scrolling as parent handles it */
528
+ .instances-sidebar-wrapper{
529
+ /* Removed overflow and height - parent layer handles scrolling */
530
+ }
531
+
532
+ .instances-sidebar-wrapper::-webkit-scrollbar {
533
+ width: 6px;
534
+ }
535
+
536
+ .instances-sidebar-wrapper::-webkit-scrollbar-track {
537
+ background: transparent;
538
+ }
539
+
540
+ .instances-sidebar-wrapper::-webkit-scrollbar-thumb {
541
+ background: #d1d5db;
542
+ border-radius: 3px;
543
+ }
544
+
545
+ .instances-sidebar-wrapper::-webkit-scrollbar-thumb:hover {
546
+ background: #9ca3af;
547
+ }
379
548
 
380
549
  .steedos-instance-related-view-wrapper{
381
550
  .antd-Page-header{
@@ -383,6 +552,12 @@ tbody .color-priority-muted *{
383
552
  }
384
553
  }
385
554
 
555
+ .instance-form pre{
556
+ white-space: pre-wrap; /* 保留空白符,允许换行 */
557
+ word-wrap: break-word; /* 长单词或URL换行 */
558
+ overflow-wrap: break-word; /* 更现代的属性 */
559
+ }
560
+
386
561
 
387
562
  /* 公共打印隐藏样式 */
388
563
  @media print {
@@ -408,4 +583,19 @@ tbody .color-priority-muted *{
408
583
  .font-normal{
409
584
  border: none !important;
410
585
  }
411
- }
586
+ }
587
+
588
+ /* .steedos-instance-detail-wrapper{
589
+ height: auto !important;
590
+ }
591
+
592
+ .steedos-amis-instance-view-body{
593
+ height: auto !important;
594
+ }
595
+ .creator-content-wrapper{
596
+ overflow: unset !important;
597
+ }
598
+
599
+ body{
600
+ overflow: auto !important;
601
+ } */