ui-soxo-bootstrap-core 2.6.40 → 2.6.42

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.
@@ -0,0 +1,127 @@
1
+ import { Collapse, Checkbox, Tag } from 'antd';
2
+
3
+ import MenuLabel from './menu-label';
4
+
5
+ const { Panel } = Collapse;
6
+
7
+ // ------------------------
8
+ // Recursive Nested Menu Component
9
+ // ------------------------
10
+ const MenuTree = ({ menus, selectedMenus, toggleMenu, parentId = null, searchActive = false }) => {
11
+ // Helper: check if parent should be checked
12
+ const isParentChecked = (menu) => {
13
+ if (!menu.sub_menus || menu.sub_menus.length === 0) {
14
+ return selectedMenus.includes(menu.id);
15
+ }
16
+ const allChildIds = menu.sub_menus.map((c) => c.id);
17
+ return allChildIds.every((id) => selectedMenus.includes(id));
18
+ };
19
+
20
+ // Helper: check if parent is indeterminate
21
+ const isParentIndeterminate = (menu) => {
22
+ if (!menu.sub_menus || menu.sub_menus.length === 0) return false;
23
+ const allChildIds = menu.sub_menus.map((c) => c.id);
24
+ const checkedCount = allChildIds.filter((id) => selectedMenus.includes(id)).length;
25
+ return checkedCount > 0 && checkedCount < allChildIds.length;
26
+ };
27
+
28
+ return (
29
+ <>
30
+ {menus.map((menu) => {
31
+ const children = menu.sub_menus || [];
32
+ const parentChecked = isParentChecked(menu);
33
+ const parentIndeterminate = isParentIndeterminate(menu);
34
+
35
+ const onParentChange = (checked) => {
36
+ toggleMenu(menu.id, checked);
37
+ // toggle children recursively
38
+ children.forEach((c) => toggleMenuRecursive(c, checked));
39
+ };
40
+
41
+ const toggleMenuRecursive = (menu, checked) => {
42
+ toggleMenu(menu.id, checked);
43
+ if (menu.sub_menus && menu.sub_menus.length > 0) {
44
+ menu.sub_menus.forEach((c) => toggleMenuRecursive(c, checked));
45
+ }
46
+ };
47
+
48
+ if (children.length === 0) {
49
+ return (
50
+ <div
51
+ style={{
52
+ justifyContent: 'space-between',
53
+ display: 'flex',
54
+ alignItems: 'center',
55
+ border: '1px solid rgba(198, 195, 195, 0.85)',
56
+ // borderRadius: 6,
57
+ padding: '12px 16px',
58
+ marginBottom: 6,
59
+ background: '#fff',
60
+ }}
61
+ >
62
+ <div
63
+ key={menu.id}
64
+ style={{
65
+ display: 'flex',
66
+ alignItems: 'center',
67
+ gap: 8,
68
+ }}
69
+ >
70
+ <Checkbox
71
+ checked={selectedMenus.includes(menu.id)}
72
+ onChange={(e) => {
73
+ const checked = e.target.checked;
74
+
75
+ toggleMenu(menu.id, checked);
76
+
77
+ // FORCE parent selection
78
+ if (checked && parentId) {
79
+ toggleMenu(parentId, true);
80
+ }
81
+ }}
82
+ />
83
+ <MenuLabel menu={menu} />
84
+ </div>
85
+ <Tag color={menu.is_visible === true ? 'green' : 'blue'}>{menu.is_visible === true ? 'VISIBLE' : 'HIDDEN'}</Tag>{' '}
86
+ </div>
87
+ );
88
+ }
89
+
90
+ return (
91
+ <Collapse
92
+ // remount when search toggles so panels open while searching and collapse when cleared
93
+ key={`${menu.id}-${searchActive}`}
94
+ style={{ marginBottom: 6 }}
95
+ defaultActiveKey={searchActive ? [menu.id] : undefined}
96
+ >
97
+ <Panel
98
+ key={menu.id}
99
+ header={
100
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
101
+ <div
102
+ style={{
103
+ display: 'flex',
104
+ alignItems: 'center',
105
+ gap: 8,
106
+ }}
107
+ onClick={(e) => e.stopPropagation()}
108
+ >
109
+ <Checkbox checked={parentChecked} indeterminate={parentIndeterminate} onChange={(e) => onParentChange(e.target.checked)} />
110
+ <MenuLabel menu={menu} />
111
+ </div>
112
+ <Tag color={menu.is_visible === true ? 'green' : 'blue'}>{menu.is_visible === true ? 'VISIBLE' : 'HIDDEN'}</Tag>{' '}
113
+ </div>
114
+ }
115
+ >
116
+ <div style={{ paddingLeft: 20 }}>
117
+ <MenuTree menus={children} selectedMenus={selectedMenus} toggleMenu={toggleMenu} parentId={menu.id} searchActive={searchActive} />
118
+ </div>
119
+ </Panel>
120
+ </Collapse>
121
+ );
122
+ })}
123
+ </>
124
+ );
125
+ };
126
+
127
+ export default MenuTree;
@@ -1,15 +1,14 @@
1
1
  import React, { useState, useEffect, useContext } from 'react';
2
2
  import { useLocation, useParams } from 'react-router-dom';
3
- import { Skeleton, Typography, message, Form, Input, Collapse, Checkbox, Tag } from 'antd';
3
+ import { Skeleton, Typography, message, Form, Input } from 'antd';
4
4
  import { GlobalContext } from './../../../../lib';
5
- import { Button } from './../../../../lib';
6
5
  import { ModelsAPI, PagesAPI, RolesAPI, MenusAPI } from '../../..';
6
+ import MenuTree from './menu-tree';
7
7
  import './role-add.scss';
8
8
 
9
9
  const { Title } = Typography;
10
- const { Panel } = Collapse;
11
10
 
12
- const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_queries = [] }) => {
11
+ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_queries = [], onSubmittingChange, formRef }) => {
13
12
  let mode = 'Add';
14
13
  if (formContent.id) mode = 'Edit';
15
14
  else if (formContent.copy) mode = 'copy';
@@ -31,8 +30,10 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
31
30
 
32
31
  const isEdit = !!(formContent.id || formContent.copy);
33
32
  const [initialLoading, setInitialLoading] = useState(isEdit);
34
- const [loading, setLoading] = useState(false);
35
33
  const [form] = Form.useForm();
34
+
35
+ // expose the form instance so the Drawer footer Save button can submit it
36
+ if (formRef) formRef.current = form;
36
37
  const [pages, setPages] = useState([]);
37
38
  const [models, setModels] = useState([]);
38
39
  const [menuList, setMenuList] = useState([]);
@@ -43,6 +44,9 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
43
44
  // Selected menus (array of IDs)
44
45
  const [selectedMenus, setSelectedMenus] = useState([]);
45
46
 
47
+ // Search term for filtering the menu list
48
+ const [menuSearch, setMenuSearch] = useState('');
49
+
46
50
  const location = useLocation();
47
51
  const query = new URLSearchParams(location.search);
48
52
  let step = parseInt(query.get('step')) || 1;
@@ -97,40 +101,28 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
97
101
  setSelectedMenus((prev) => (checked ? [...prev, id] : prev.filter((m) => m !== id)));
98
102
  };
99
103
 
100
- // Submit handler
101
- // const onSubmit = (values) => {
102
- // setLoading(true);
103
-
104
- // const payload = {
105
- // ...values,
106
- // menu_ids
107
- // : selectedMenus,
108
- // attributes: JSON.stringify(values.attributes || {}),
109
- // };
110
-
111
- // if (formContent.id) {
112
- // RolesAPI.updateRole({ id: formContent.id, formBody: payload })
113
- // .then(() => {
114
- // message.success('Role Updated');
115
- // setLoading(false);
116
- // callback();
117
- // })
118
- // .catch(() => setLoading(false));
119
- // } else {
120
- // additional_queries.forEach(({ field, value }) => {
121
- // payload[field] = value;
122
- // });
123
- // RolesAPI.createRole(payload)
124
- // .then(() => {
125
- // message.success('Role Added');
126
- // setLoading(false);
127
- // callback();
128
- // })
129
- // .catch(() => setLoading(false));
130
- // }
131
- // };
104
+ // Recursively filter menus by caption. A menu is kept if its caption matches
105
+ // the search term, or if any of its descendants match (ancestors are kept so
106
+ // the matching child stays reachable).
107
+ const filterMenus = (menus, term) => {
108
+ if (!term) return menus;
109
+ const lower = term.toLowerCase();
110
+
111
+ return menus.reduce((acc, menu) => {
112
+ const children = filterMenus(menu.sub_menus || [], term);
113
+ const selfMatch = (menu.caption || '').toLowerCase().includes(lower);
114
+
115
+ if (selfMatch || children.length > 0) {
116
+ acc.push({ ...menu, sub_menus: children });
117
+ }
118
+ return acc;
119
+ }, []);
120
+ };
121
+
122
+ const filteredMenuList = filterMenus(menuList, menuSearch);
123
+
132
124
  const onSubmit = async (values) => {
133
- setLoading(true);
125
+ onSubmittingChange?.(true);
134
126
 
135
127
  // Find menus that were originally selected but now deselected
136
128
  const deselectedMenus = originalMenus.filter((id) => !selectedMenus.includes(id));
@@ -153,13 +145,21 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
153
145
  });
154
146
 
155
147
  try {
156
- await RolesAPI.createRole(payload); // single API
148
+ const res = await RolesAPI.createRole(payload); // single API
149
+
150
+ // it via success: false — show that message as a warning.
151
+ if (res?.success === false) {
152
+ message.warning(res.message || 'Failed to save role');
153
+ return;
154
+ }
155
+
157
156
  message.success(formContent?.id ? 'Role Updated' : 'Role Added');
158
157
  callback();
159
158
  } catch (err) {
160
- // message.error('Something went wrong');
159
+ // Surface any unexpected backend error message as a warning.
160
+ message.warning(err?.message || err?.result?.message || 'Failed to save role');
161
161
  } finally {
162
- setLoading(false);
162
+ onSubmittingChange?.(false);
163
163
  }
164
164
  };
165
165
 
@@ -194,6 +194,7 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
194
194
  display: 'flex',
195
195
  justifyContent: 'space-between',
196
196
  alignItems: 'center',
197
+ gap: 16,
197
198
  marginBottom: 16,
198
199
  }}
199
200
  >
@@ -204,14 +205,20 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
204
205
  <p style={{ color: '#999', marginBottom: 0 }}>Choose menus and set permissions</p>
205
206
  </div>
206
207
 
207
- <Form.Item style={{ marginBottom: 0 }}>
208
- <Button loading={loading} htmlType="submit" type="primary">
209
- Save
210
- </Button>
211
- </Form.Item>
208
+ <Input.Search
209
+ allowClear
210
+ placeholder="Search menus"
211
+ value={menuSearch}
212
+ onChange={(e) => setMenuSearch(e.target.value)}
213
+ style={{ maxWidth: 260 }}
214
+ />
212
215
  </div>
213
216
 
214
- <MenuTree menus={menuList} selectedMenus={selectedMenus} toggleMenu={toggleMenu} />
217
+ {filteredMenuList.length > 0 ? (
218
+ <MenuTree menus={filteredMenuList} selectedMenus={selectedMenus} toggleMenu={toggleMenu} searchActive={!!menuSearch} />
219
+ ) : (
220
+ <p style={{ color: '#999', textAlign: 'center', padding: '16px 0' }}>No menus found</p>
221
+ )}
215
222
  </div>
216
223
  )}
217
224
  </Form>
@@ -221,125 +228,3 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
221
228
  };
222
229
 
223
230
  export default RoleAdd;
224
-
225
- // ------------------------
226
- // Recursive Nested Menu Component
227
- // ------------------------
228
- // ------------------------
229
- // Recursive Nested Menu Component
230
- // ------------------------
231
- const MenuTree = ({ menus, selectedMenus, toggleMenu, parentId = null }) => {
232
- // Helper: check if parent should be checked
233
- const isParentChecked = (menu) => {
234
- if (!menu.sub_menus || menu.sub_menus.length === 0) {
235
- return selectedMenus.includes(menu.id);
236
- }
237
- const allChildIds = menu.sub_menus.map((c) => c.id);
238
- return allChildIds.every((id) => selectedMenus.includes(id));
239
- };
240
-
241
- // Helper: check if parent is indeterminate
242
- const isParentIndeterminate = (menu) => {
243
- if (!menu.sub_menus || menu.sub_menus.length === 0) return false;
244
- const allChildIds = menu.sub_menus.map((c) => c.id);
245
- const checkedCount = allChildIds.filter((id) => selectedMenus.includes(id)).length;
246
- return checkedCount > 0 && checkedCount < allChildIds.length;
247
- };
248
-
249
- return (
250
- <>
251
- {menus.map((menu) => {
252
- const children = menu.sub_menus || [];
253
- const parentChecked = isParentChecked(menu);
254
- const parentIndeterminate = isParentIndeterminate(menu);
255
-
256
- const onParentChange = (checked) => {
257
- toggleMenu(menu.id, checked);
258
- // toggle children recursively
259
- children.forEach((c) => toggleMenuRecursive(c, checked));
260
- };
261
-
262
- const toggleMenuRecursive = (menu, checked) => {
263
- toggleMenu(menu.id, checked);
264
- if (menu.sub_menus && menu.sub_menus.length > 0) {
265
- menu.sub_menus.forEach((c) => toggleMenuRecursive(c, checked));
266
- }
267
- };
268
-
269
- if (children.length === 0) {
270
- return (
271
- <div
272
- style={{
273
- justifyContent: 'space-between',
274
- display: 'flex',
275
- alignItems: 'center',
276
- border: '1px solid rgba(198, 195, 195, 0.85)',
277
- // borderRadius: 6,
278
- padding: '12px 16px',
279
- marginBottom: 6,
280
- background: '#fff',
281
- }}
282
- >
283
- <div
284
- key={menu.id}
285
- style={{
286
- display: 'flex',
287
- alignItems: 'center',
288
- gap: 8,
289
- }}
290
- >
291
- <Checkbox
292
- checked={selectedMenus.includes(menu.id)}
293
- onChange={(e) => {
294
- const checked = e.target.checked;
295
-
296
- toggleMenu(menu.id, checked);
297
-
298
- // FORCE parent selection
299
- if (checked && parentId) {
300
- toggleMenu(parentId, true);
301
- }
302
- }}
303
- />
304
- <span>{menu.caption}</span>
305
- </div>
306
- <Tag color={menu.is_visible === true ? 'green' : 'blue'}>{menu.is_visible === true ? 'VISIBLE' : 'HIDDEN'}</Tag>{' '}
307
- </div>
308
- );
309
- }
310
-
311
- return (
312
- <Collapse
313
- key={menu.id}
314
- style={{ marginBottom: 6 }}
315
- // defaultActiveKey={[menu.id]}
316
- >
317
- <Panel
318
- key={menu.id}
319
- header={
320
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
321
- <div
322
- style={{
323
- display: 'flex',
324
- alignItems: 'center',
325
- gap: 8,
326
- }}
327
- onClick={(e) => e.stopPropagation()}
328
- >
329
- <Checkbox checked={parentChecked} indeterminate={parentIndeterminate} onChange={(e) => onParentChange(e.target.checked)} />
330
- <span>{menu.caption}</span>
331
- </div>
332
- <Tag color={menu.is_visible === true ? 'green' : 'blue'}>{menu.is_visible === true ? 'VISIBLE' : 'HIDDEN'}</Tag>{' '}
333
- </div>
334
- }
335
- >
336
- <div style={{ paddingLeft: 20 }}>
337
- <MenuTree menus={children} selectedMenus={selectedMenus} toggleMenu={toggleMenu} parentId={menu.id} />
338
- </div>
339
- </Panel>
340
- </Collapse>
341
- );
342
- })}
343
- </>
344
- );
345
- };
@@ -40,6 +40,12 @@ const RoleList = ({ model, match, relativeAdd = false, additional_queries = [],
40
40
 
41
41
  const [single, setSingle] = useState({});
42
42
 
43
+ // tracks RoleAdd form submission so the Drawer footer button shows loading
44
+ const [submitting, setSubmitting] = useState(false);
45
+
46
+ // holds the RoleAdd form instance so the Drawer footer Save button can submit it
47
+ const formRef = useRef(null);
48
+
43
49
  var [queryValue, setQueryValue] = useState('');
44
50
 
45
51
  const { Search } = Input;
@@ -360,12 +366,26 @@ const RoleList = ({ model, match, relativeAdd = false, additional_queries = [],
360
366
  destroyOnClose
361
367
  onClose={closeModal}
362
368
  bodyStyle={{ paddingBottom: 80 }}
369
+ footer={
370
+ <div style={{ textAlign: 'right' }}>
371
+ <Space size="small">
372
+ <Button type="default" onClick={closeModal}>
373
+ Cancel
374
+ </Button>
375
+ <Button type="primary" loading={submitting} onClick={() => formRef.current?.submit()}>
376
+ Save
377
+ </Button>
378
+ </Space>
379
+ </div>
380
+ }
363
381
  >
364
382
  <model.ModalAddComponent
365
383
  match={match}
366
384
  model={model}
367
385
  additional_queries={additional_queries}
368
386
  formContent={single}
387
+ formRef={formRef}
388
+ onSubmittingChange={setSubmitting}
369
389
  callback={(event) => {
370
390
  closeModal();
371
391
  getRecords();
@@ -163,6 +163,9 @@ class RolesAPI extends BaseAPI {
163
163
  return ApiUtils.post({
164
164
  url: `core-roles/save-core-role`,
165
165
  formBody,
166
+ // Let the caller surface the backend message (as a warning) instead of
167
+ // the default red error toast from the http layer.
168
+ hideError: true,
166
169
  });
167
170
  };
168
171
 
@@ -160,7 +160,7 @@ export default function AssignRole() {
160
160
  const role_id = role.id;
161
161
  try {
162
162
  const res = await MenusAPI.getCoreMenuByRoleId(role_id);
163
- const allMenus = res.result || [];
163
+ const allMenus = Array.isArray(res?.result) ? res.result : [];
164
164
 
165
165
  setModules(allMenus);
166
166
  } catch (e) {
@@ -264,11 +264,12 @@ export default function AssignRole() {
264
264
  const handleViewAll = async () => {
265
265
  setLoadingMenus(true);
266
266
  setModules([]);
267
- setActiveRole({ name: 'All Roles' });
267
+ setActiveRole({ name: 'All Roles', isViewAll: true });
268
268
 
269
269
  try {
270
270
  const res = await MenusAPI.getMenubyUser(id);
271
- setModules(res?.result?.menus ?? []);
271
+ const userMenus = Array.isArray(res?.result?.menus) ? res.result.menus : [];
272
+ setModules(userMenus);
272
273
  setLoadingMenus(false);
273
274
  } catch (err) {
274
275
  setLoadingMenus(false);
@@ -277,6 +278,18 @@ export default function AssignRole() {
277
278
  }
278
279
  };
279
280
 
281
+ /**
282
+ * Context-specific empty-state message for the right (menus) panel:
283
+ * - View Access for a user with no roles → no role assigned
284
+ * - A selected role with no menus → no menus assigned
285
+ * - Nothing selected yet → prompt to pick a role
286
+ */
287
+ const emptyMenusMessage = !activeRole
288
+ ? 'Select a role to view menus'
289
+ : activeRole.isViewAll
290
+ ? 'No role has been assigned to this user.'
291
+ : 'No menus have been assigned to this role.';
292
+
280
293
  return (
281
294
  <section className="assign-role">
282
295
  {/* LEFT PANEL */}
@@ -383,17 +396,19 @@ export default function AssignRole() {
383
396
  padding: 16,
384
397
  }}
385
398
  >
386
- <div className="menus-header">
387
- <div className="title">Menus {activeRole ? `– ${activeRole.name}` : ''}</div>
388
- <div className="sub-text">You don’t have permission to edit this here. Update it in Role Settings.</div>
389
- </div>
399
+ {modules.length > 0 && (
400
+ <div className="menus-header">
401
+ <div className="title">Menus {activeRole ? `– ${activeRole.name}` : ''}</div>
402
+ <div className="sub-text">You don’t have permission to edit this here. Update it in Role Settings.</div>
403
+ </div>
404
+ )}
390
405
 
391
406
  <div className="menus-content">
392
407
  {loadingMenus ? (
393
408
  <Skeleton active paragraph={{ rows: 6 }} />
394
409
  ) : modules.length === 0 ? (
395
410
  <div className="empty-state">
396
- <Empty description="Select a role to view menus" />
411
+ <Empty description={emptyMenusMessage} />
397
412
  </div>
398
413
  ) : (
399
414
  <MenuTree menus={modules} selectedMenus={selectedMenus} toggleMenu={toggleMenu} showCheckbox={false} />
@@ -1290,7 +1290,27 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
1290
1290
  </div>
1291
1291
  )} */}
1292
1292
 
1293
- <div className="steps-top-bar">
1293
+ <div className={`steps-top-bar${isStepFullscreen ? ' is-fullscreen' : ''}`}>
1294
+ {/*
1295
+ Full-screen toggle is anchored to the far left of the bar so the
1296
+ step tabs can stretch across the middle and the primary CTA sits
1297
+ flush right (see design).
1298
+ */}
1299
+ <Button
1300
+ className="steps-fullscreen-toggle"
1301
+ type="dashed"
1302
+ icon={isStepFullscreen ? <CompressOutlined /> : <ExpandOutlined />}
1303
+ onClick={toggleStepFullscreen}
1304
+ aria-label={isStepFullscreen ? 'Exit Full Screen' : 'Full Screen'}
1305
+ title={isStepFullscreen ? 'Exit Full Screen' : 'Full Screen'}
1306
+ >
1307
+ {isStepFullscreen ? 'Exit Full Screen' : 'Full Screen'}
1308
+ </Button>
1309
+
1310
+ {/*
1311
+ Breadcrumb strip stays visible in fullscreen mode too so the
1312
+ user keeps the step timeline / navigation while presenting.
1313
+ */}
1294
1314
  <div className="steps-breadcrumb-strip">
1295
1315
  {steps.length ? (
1296
1316
  steps.map((stepItem, stepIndex) => {
@@ -1315,10 +1335,6 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
1315
1335
  </div>
1316
1336
 
1317
1337
  <div className="steps-nav-actions">
1318
- <Button type="dashed" icon={isStepFullscreen ? <CompressOutlined /> : <ExpandOutlined />} onClick={toggleStepFullscreen}>
1319
- {isStepFullscreen ? 'Exit Full Screen' : 'Full Screen'}
1320
- </Button>
1321
-
1322
1338
  {/*
1323
1339
  Previous-process button.
1324
1340
  - Only relevant at the start of a process (`activeStep === 0`)
@@ -1333,7 +1349,13 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
1333
1349
  )}
1334
1350
 
1335
1351
  {activeStep > 0 && (
1336
- <Button type="default" icon={<ArrowLeftOutlined />} onClick={handlePrevious}>
1352
+ <Button
1353
+ type="default"
1354
+ icon={<ArrowLeftOutlined />}
1355
+ onClick={handlePrevious}
1356
+ aria-label="Back"
1357
+ title="Back"
1358
+ >
1337
1359
  Back
1338
1360
  </Button>
1339
1361
  )}
@@ -1366,7 +1388,13 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
1366
1388
  )}
1367
1389
  </>
1368
1390
  ) : (
1369
- <Button type="primary" disabled={!isStepCompleted} onClick={handleNext}>
1391
+ <Button
1392
+ type="primary"
1393
+ disabled={!isStepCompleted}
1394
+ onClick={handleNext}
1395
+ aria-label={activeStep === 0 ? (FIRST_STEP_LABELS[processName?.trim().toLowerCase()] ?? 'Next') : 'Next'}
1396
+ title={activeStep === 0 ? (FIRST_STEP_LABELS[processName?.trim().toLowerCase()] ?? 'Next') : 'Next'}
1397
+ >
1370
1398
  {/*
1371
1399
  First-step label is resolved via FIRST_STEP_LABELS using
1372
1400
  the process name (lowercased + trimmed) as the key. Known
@@ -1464,10 +1492,10 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
1464
1492
  </button>
1465
1493
  </>
1466
1494
  ) : null}
1467
- <div
1495
+ {/* <div
1468
1496
  key={`${currentProcessId}_${activeStep}`}
1469
1497
  className={`steps-chat-step-card ${stepSlideDirection === 'backward' ? 'slide-backward' : 'slide-forward'}`}
1470
- >
1498
+ > */}
1471
1499
  {/* <div className="steps-chat-step-top">
1472
1500
  <span className="steps-index-pill">
1473
1501
  Step {Math.min(activeStep + 1, steps.length || 1)} of {steps.length || 1}
@@ -1476,15 +1504,15 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
1476
1504
  {currentStep?.step_description ? <p className="steps-description">{currentStep.step_description}</p> : null}
1477
1505
  </div> */}
1478
1506
 
1479
- <div className="steps-chat-step-component">
1507
+ {/* <div className="steps-chat-step-component"> */}
1480
1508
  {loading ? (
1481
1509
  <div className="steps-chat-loading">
1482
1510
  <Spin />
1483
1511
  </div>
1484
1512
  ) : null}
1485
1513
  {!loading ? renderDynamicStep() : null}
1486
- </div>
1487
- </div>
1514
+ {/* </div> */}
1515
+ {/* </div> */}
1488
1516
  </div>
1489
1517
  </div>
1490
1518