@visns-studio/visns-components 6.6.2 → 6.6.3
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/package.json +1 -1
- package/src/components/DataGrid.jsx +11 -1
- package/src/components/Form.jsx +74 -19
- package/src/components/MultiSelect.jsx +8 -60
package/package.json
CHANGED
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
92
92
|
},
|
|
93
93
|
"name": "@visns-studio/visns-components",
|
|
94
|
-
"version": "6.6.
|
|
94
|
+
"version": "6.6.3",
|
|
95
95
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
96
96
|
"main": "src/index.js",
|
|
97
97
|
"files": [
|
|
@@ -711,7 +711,9 @@ const DataGrid = forwardRef(
|
|
|
711
711
|
}
|
|
712
712
|
|
|
713
713
|
if (j - i > 1) {
|
|
714
|
-
const children = rows
|
|
714
|
+
const children = rows
|
|
715
|
+
.slice(i, j)
|
|
716
|
+
.map((child) => ({ ...child }));
|
|
715
717
|
const parent = {
|
|
716
718
|
__treeParent: true,
|
|
717
719
|
id: `tree-group-${value}`,
|
|
@@ -2511,6 +2513,14 @@ const DataGrid = forwardRef(
|
|
|
2511
2513
|
timestamp: new Date().toISOString(),
|
|
2512
2514
|
});
|
|
2513
2515
|
|
|
2516
|
+
// Synthetic tree parent rows are group summaries with a
|
|
2517
|
+
// fabricated string id — they must never open the update modal
|
|
2518
|
+
// or follow links. Their own controls (chevron, group action
|
|
2519
|
+
// icons) stopPropagation before this handler fires.
|
|
2520
|
+
if (rowProps.data?.__treeParent) {
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2514
2524
|
const cellElement = event.target.closest(
|
|
2515
2525
|
'.InovuaReactDataGrid__cell'
|
|
2516
2526
|
);
|
package/src/components/Form.jsx
CHANGED
|
@@ -1310,6 +1310,26 @@ function Form({
|
|
|
1310
1310
|
}
|
|
1311
1311
|
}
|
|
1312
1312
|
|
|
1313
|
+
// A form that never fetched its record (see the columnId > 0
|
|
1314
|
+
// gate on the record GET) has no primary key — submitting
|
|
1315
|
+
// would PUT/DELETE against `${url}/undefined`. Abort loudly
|
|
1316
|
+
// instead.
|
|
1317
|
+
if (
|
|
1318
|
+
['update', 'delete'].includes(formType) &&
|
|
1319
|
+
!bulkEditMode &&
|
|
1320
|
+
!formSettings.json &&
|
|
1321
|
+
!formSettings.customUrl
|
|
1322
|
+
) {
|
|
1323
|
+
const pk = formData?.[formSettings.primaryKey];
|
|
1324
|
+
|
|
1325
|
+
if (pk == null || pk === '' || Number.isNaN(Number(pk))) {
|
|
1326
|
+
toast.error(
|
|
1327
|
+
'This record could not be loaded, so it cannot be saved. Please close the form and reopen it from its row.'
|
|
1328
|
+
);
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1313
1333
|
let fields = formSettings.fields;
|
|
1314
1334
|
let _inputClass = inputClass;
|
|
1315
1335
|
let validation = '';
|
|
@@ -2199,32 +2219,67 @@ function Form({
|
|
|
2199
2219
|
fetchTable(createdItem);
|
|
2200
2220
|
}
|
|
2201
2221
|
} else {
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2222
|
+
// Without a record id the follow-up
|
|
2223
|
+
// would hit `${url}/undefined`, so
|
|
2224
|
+
// skip the request and report it
|
|
2225
|
+
// the same way a failed one is
|
|
2226
|
+
const saveAnotherId =
|
|
2227
|
+
formData?.[saveAnother.dataKey];
|
|
2228
|
+
|
|
2229
|
+
if (
|
|
2230
|
+
saveAnotherId == null ||
|
|
2231
|
+
saveAnotherId === '' ||
|
|
2232
|
+
Number.isNaN(
|
|
2233
|
+
Number(saveAnotherId)
|
|
2234
|
+
)
|
|
2235
|
+
) {
|
|
2236
|
+
saveAnotherFailed = true;
|
|
2237
|
+
toast.error(
|
|
2238
|
+
'Unable to run the follow-up action: the record id is missing.'
|
|
2210
2239
|
);
|
|
2211
2240
|
|
|
2212
|
-
if (resSaveAnother.data.error === '') {
|
|
2213
|
-
toast.success(saveAnother.message);
|
|
2214
2241
|
if (fetchTable) {
|
|
2215
2242
|
const createdItem =
|
|
2216
|
-
res.data.data ||
|
|
2243
|
+
res.data.data ||
|
|
2244
|
+
res.data;
|
|
2217
2245
|
fetchTable(createdItem);
|
|
2218
2246
|
}
|
|
2219
2247
|
} else {
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2248
|
+
const saveAnotherUrl = `${
|
|
2249
|
+
saveAnother.url
|
|
2250
|
+
}/${saveAnotherId}`;
|
|
2251
|
+
const resSaveAnother =
|
|
2252
|
+
await CustomFetch(
|
|
2253
|
+
saveAnotherUrl,
|
|
2254
|
+
saveAnother.method,
|
|
2255
|
+
processedData
|
|
2256
|
+
);
|
|
2257
|
+
|
|
2258
|
+
if (
|
|
2259
|
+
resSaveAnother.data
|
|
2260
|
+
.error === ''
|
|
2261
|
+
) {
|
|
2262
|
+
toast.success(
|
|
2263
|
+
saveAnother.message
|
|
2264
|
+
);
|
|
2265
|
+
if (fetchTable) {
|
|
2266
|
+
const createdItem =
|
|
2267
|
+
res.data.data ||
|
|
2268
|
+
res.data;
|
|
2269
|
+
fetchTable(createdItem);
|
|
2270
|
+
}
|
|
2271
|
+
} else {
|
|
2272
|
+
saveAnotherFailed = true;
|
|
2273
|
+
toast.error(
|
|
2274
|
+
resSaveAnother.data
|
|
2275
|
+
.error
|
|
2276
|
+
);
|
|
2277
|
+
if (fetchTable) {
|
|
2278
|
+
const createdItem =
|
|
2279
|
+
res.data.data ||
|
|
2280
|
+
res.data;
|
|
2281
|
+
fetchTable(createdItem);
|
|
2282
|
+
}
|
|
2228
2283
|
}
|
|
2229
2284
|
}
|
|
2230
2285
|
}
|
|
@@ -36,7 +36,7 @@ const CustomOption = (props) => {
|
|
|
36
36
|
|
|
37
37
|
// Custom MultiValue component to display description for selected values
|
|
38
38
|
const CustomMultiValue = (props) => {
|
|
39
|
-
const { children, data,
|
|
39
|
+
const { children, data, settings, ...rest } = props;
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<components.MultiValue {...rest} data={data}>
|
|
@@ -62,61 +62,18 @@ const CustomMultiValue = (props) => {
|
|
|
62
62
|
);
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
// Custom MultiValueRemove
|
|
65
|
+
// Custom MultiValueRemove: fixed values cannot be deselected — render no
|
|
66
|
+
// × at all (the module SCSS forces `display` on the remove button with
|
|
67
|
+
// !important, so hiding it from the styles function is not enough).
|
|
68
|
+
// Removal itself is react-select's own behaviour: CustomMultiValue
|
|
69
|
+
// forwards removeProps, so innerProps already carries working
|
|
70
|
+
// onClick/onTouchEnd handlers.
|
|
66
71
|
const CustomMultiValueRemove = (props) => {
|
|
67
|
-
// Fixed values cannot be deselected: render no × at all — the module
|
|
68
|
-
// SCSS forces `display` on the remove button with !important, so
|
|
69
|
-
// hiding it from the styles function is not enough.
|
|
70
72
|
if (props.data?.isFixed) {
|
|
71
73
|
return null;
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
e.stopPropagation();
|
|
76
|
-
|
|
77
|
-
// Try to find the data by looking at the DOM structure
|
|
78
|
-
const removeButton = e.currentTarget;
|
|
79
|
-
const multiValueContainer = removeButton.closest('.visns-select__multi-value');
|
|
80
|
-
|
|
81
|
-
if (multiValueContainer) {
|
|
82
|
-
// Get the index of this multi-value item
|
|
83
|
-
const allMultiValues = removeButton.closest('.visns-select__value-container').querySelectorAll('.visns-select__multi-value');
|
|
84
|
-
const index = Array.from(allMultiValues).indexOf(multiValueContainer);
|
|
85
|
-
|
|
86
|
-
console.log('MultiSelect: Found index:', index);
|
|
87
|
-
|
|
88
|
-
// Get current value and remove the item at this index
|
|
89
|
-
const currentValue = props.selectProps?.value || [];
|
|
90
|
-
console.log('MultiSelect: Current value:', currentValue);
|
|
91
|
-
|
|
92
|
-
if (index >= 0 && index < currentValue.length) {
|
|
93
|
-
const itemToRemove = currentValue[index];
|
|
94
|
-
const newValue = currentValue.filter((_, i) => i !== index);
|
|
95
|
-
|
|
96
|
-
console.log('MultiSelect: Removing item at index', index, ':', itemToRemove);
|
|
97
|
-
console.log('MultiSelect: New value:', newValue);
|
|
98
|
-
|
|
99
|
-
// Call onChange with the filtered value and remove action
|
|
100
|
-
if (props.selectProps?.onChange) {
|
|
101
|
-
props.selectProps.onChange(newValue, {
|
|
102
|
-
action: 'remove-value',
|
|
103
|
-
removedValue: itemToRemove
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<components.MultiValueRemove
|
|
112
|
-
{...props}
|
|
113
|
-
innerProps={{
|
|
114
|
-
...props.innerProps,
|
|
115
|
-
onClick: handleRemove,
|
|
116
|
-
onMouseDown: (e) => e.stopPropagation()
|
|
117
|
-
}}
|
|
118
|
-
/>
|
|
119
|
-
);
|
|
76
|
+
return <components.MultiValueRemove {...props} />;
|
|
120
77
|
};
|
|
121
78
|
|
|
122
79
|
// Custom NoOptionsMessage component to guide users about creation capability
|
|
@@ -333,15 +290,6 @@ function MultiSelect({
|
|
|
333
290
|
menuPlacement={menuPlacement}
|
|
334
291
|
onMenuOpen={handleMenuOpen}
|
|
335
292
|
onChange={(inputValue, action) => {
|
|
336
|
-
// Debug logging for delete actions
|
|
337
|
-
if (action.action === 'remove-value') {
|
|
338
|
-
console.log('MultiSelect: Individual item delete:', {
|
|
339
|
-
removedValue: action.removedValue,
|
|
340
|
-
newValue: inputValue,
|
|
341
|
-
action: action
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
|
|
345
293
|
// Values seeded with isFixed represent memberships this
|
|
346
294
|
// field is not allowed to take away (e.g. a tag's existing
|
|
347
295
|
// headers in an add-only group modal): ignore their removal
|