@visns-studio/visns-components 5.9.12 → 5.9.144
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
CHANGED
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
88
88
|
},
|
|
89
89
|
"name": "@visns-studio/visns-components",
|
|
90
|
-
"version": "5.9.
|
|
90
|
+
"version": "5.9.144",
|
|
91
91
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
92
92
|
"main": "src/index.js",
|
|
93
93
|
"files": [
|
|
@@ -385,7 +385,6 @@ const CellWithTooltip = ({
|
|
|
385
385
|
);
|
|
386
386
|
};
|
|
387
387
|
|
|
388
|
-
|
|
389
388
|
const DataGrid = forwardRef(
|
|
390
389
|
(
|
|
391
390
|
{
|
|
@@ -622,7 +621,6 @@ const DataGrid = forwardRef(
|
|
|
622
621
|
if (ajaxSetting?.groupBy) {
|
|
623
622
|
groupsInitializedRef.current = false;
|
|
624
623
|
setCollapsedGroups({}); // Clear existing state when groupBy changes
|
|
625
|
-
|
|
626
624
|
}
|
|
627
625
|
}, [ajaxSetting?.groupBy]);
|
|
628
626
|
|
|
@@ -746,7 +744,7 @@ const DataGrid = forwardRef(
|
|
|
746
744
|
setTableData(res.data);
|
|
747
745
|
}
|
|
748
746
|
dataRef.current = res.data;
|
|
749
|
-
|
|
747
|
+
|
|
750
748
|
// Force grid to recalculate row heights after data changes
|
|
751
749
|
// This helps with multi-line content timing without interfering with core mechanisms
|
|
752
750
|
setTimeout(() => {
|
|
@@ -1500,7 +1498,9 @@ const DataGrid = forwardRef(
|
|
|
1500
1498
|
CustomFetch(
|
|
1501
1499
|
s.url + '/' + d[form.primaryKey],
|
|
1502
1500
|
s.method,
|
|
1503
|
-
{
|
|
1501
|
+
{
|
|
1502
|
+
...s.data,
|
|
1503
|
+
},
|
|
1504
1504
|
function (result) {
|
|
1505
1505
|
if (result.error === '') {
|
|
1506
1506
|
handleReload();
|
|
@@ -1673,10 +1673,15 @@ const DataGrid = forwardRef(
|
|
|
1673
1673
|
|
|
1674
1674
|
rowProps.onClick = (event) => {
|
|
1675
1675
|
// Check if this is a group row - group rows should only handle expand/collapse, not onRowClick
|
|
1676
|
-
const isGroupRow =
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1676
|
+
const isGroupRow =
|
|
1677
|
+
rowProps.isGroupRow ||
|
|
1678
|
+
rowProps.data?.__group ||
|
|
1679
|
+
event.target.closest(
|
|
1680
|
+
'.InovuaReactDataGrid__group-row'
|
|
1681
|
+
) ||
|
|
1682
|
+
event.target.closest(
|
|
1683
|
+
'.InovuaReactDataGrid__group-cell'
|
|
1684
|
+
);
|
|
1680
1685
|
|
|
1681
1686
|
if (isGroupRow) {
|
|
1682
1687
|
// For group rows, only allow the original onClick handler (for expand/collapse)
|
|
@@ -2274,7 +2279,7 @@ const DataGrid = forwardRef(
|
|
|
2274
2279
|
// Apply immediately and with a conservative delay
|
|
2275
2280
|
applyGroupedStyling();
|
|
2276
2281
|
const timer1 = setTimeout(applyGroupedStyling, 100);
|
|
2277
|
-
|
|
2282
|
+
|
|
2278
2283
|
return () => {
|
|
2279
2284
|
clearTimeout(timer1);
|
|
2280
2285
|
};
|
|
@@ -2296,9 +2301,140 @@ const DataGrid = forwardRef(
|
|
|
2296
2301
|
let allow = true;
|
|
2297
2302
|
|
|
2298
2303
|
if (s.active) {
|
|
2304
|
+
// Helper function to get nested values for main active condition (searches for target value)
|
|
2305
|
+
const getNestedValueForMain = (data, path, targetValue) => {
|
|
2306
|
+
if (Array.isArray(path)) {
|
|
2307
|
+
return path.reduce(
|
|
2308
|
+
(currentValue, key) =>
|
|
2309
|
+
currentValue && currentValue[key] !== undefined
|
|
2310
|
+
? currentValue[key]
|
|
2311
|
+
: undefined,
|
|
2312
|
+
data
|
|
2313
|
+
);
|
|
2314
|
+
} else if (typeof path === 'string' && path.includes('.')) {
|
|
2315
|
+
const keys = path.split('.');
|
|
2316
|
+
let currentValue = data;
|
|
2317
|
+
|
|
2318
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2319
|
+
const key = keys[i];
|
|
2320
|
+
|
|
2321
|
+
if (!currentValue) return undefined;
|
|
2322
|
+
|
|
2323
|
+
// Handle array search pattern like "customers[].pivot.is_primary"
|
|
2324
|
+
if (key.includes('[]')) {
|
|
2325
|
+
const arrayKey = key.replace('[]', '');
|
|
2326
|
+
const remainingPath = keys
|
|
2327
|
+
.slice(i + 1)
|
|
2328
|
+
.join('.');
|
|
2329
|
+
|
|
2330
|
+
if (Array.isArray(currentValue[arrayKey])) {
|
|
2331
|
+
// Search through the array for the target value
|
|
2332
|
+
for (const item of currentValue[arrayKey]) {
|
|
2333
|
+
const result = remainingPath
|
|
2334
|
+
? getNestedValueForMain(
|
|
2335
|
+
item,
|
|
2336
|
+
remainingPath,
|
|
2337
|
+
targetValue
|
|
2338
|
+
)
|
|
2339
|
+
: item;
|
|
2340
|
+
if (result === targetValue) {
|
|
2341
|
+
return result;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
return undefined;
|
|
2346
|
+
} else {
|
|
2347
|
+
currentValue = currentValue[key];
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
return currentValue;
|
|
2352
|
+
} else {
|
|
2353
|
+
// Fallback to simple property access
|
|
2354
|
+
return data[path];
|
|
2355
|
+
}
|
|
2356
|
+
};
|
|
2357
|
+
|
|
2358
|
+
// Helper function to get nested values for additional conditions (returns first valid value)
|
|
2359
|
+
const getNestedValueForAdditional = (data, path) => {
|
|
2360
|
+
if (Array.isArray(path)) {
|
|
2361
|
+
return path.reduce(
|
|
2362
|
+
(currentValue, key) =>
|
|
2363
|
+
currentValue && currentValue[key] !== undefined
|
|
2364
|
+
? currentValue[key]
|
|
2365
|
+
: undefined,
|
|
2366
|
+
data
|
|
2367
|
+
);
|
|
2368
|
+
} else if (typeof path === 'string' && path.includes('.')) {
|
|
2369
|
+
const keys = path.split('.');
|
|
2370
|
+
let currentValue = data;
|
|
2371
|
+
|
|
2372
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2373
|
+
const key = keys[i];
|
|
2374
|
+
|
|
2375
|
+
if (!currentValue) return undefined;
|
|
2376
|
+
|
|
2377
|
+
// Handle array search pattern like "customers[].id"
|
|
2378
|
+
if (key.includes('[]')) {
|
|
2379
|
+
const arrayKey = key.replace('[]', '');
|
|
2380
|
+
const remainingPath = keys
|
|
2381
|
+
.slice(i + 1)
|
|
2382
|
+
.join('.');
|
|
2383
|
+
|
|
2384
|
+
if (Array.isArray(currentValue[arrayKey])) {
|
|
2385
|
+
// Return the first valid result from the array
|
|
2386
|
+
for (const item of currentValue[arrayKey]) {
|
|
2387
|
+
const result = remainingPath
|
|
2388
|
+
? getNestedValueForAdditional(
|
|
2389
|
+
item,
|
|
2390
|
+
remainingPath
|
|
2391
|
+
)
|
|
2392
|
+
: item;
|
|
2393
|
+
if (result !== undefined) {
|
|
2394
|
+
return result;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
return undefined;
|
|
2399
|
+
} else {
|
|
2400
|
+
currentValue = currentValue[key];
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
return currentValue;
|
|
2405
|
+
} else {
|
|
2406
|
+
// Fallback to simple property access
|
|
2407
|
+
return data[path];
|
|
2408
|
+
}
|
|
2409
|
+
};
|
|
2410
|
+
|
|
2411
|
+
// Get the active value using nested path or simple property access
|
|
2412
|
+
const activeValue = getNestedValueForMain(d, s.active.id, s.active.value);
|
|
2413
|
+
const hasActiveProperty = activeValue !== undefined;
|
|
2414
|
+
|
|
2415
|
+
// Check additional conditions if they exist
|
|
2416
|
+
const checkAdditionalConditions = () => {
|
|
2417
|
+
if (
|
|
2418
|
+
!s.active.additional ||
|
|
2419
|
+
!Array.isArray(s.active.additional)
|
|
2420
|
+
) {
|
|
2421
|
+
return true; // No additional conditions, so they pass
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// All additional conditions must be met
|
|
2425
|
+
return s.active.additional.every((condition) => {
|
|
2426
|
+
const conditionValue = getNestedValueForAdditional(d, condition.id);
|
|
2427
|
+
// Type-flexible comparison - convert both to strings for comparison
|
|
2428
|
+
return String(conditionValue) === String(condition.value);
|
|
2429
|
+
});
|
|
2430
|
+
};
|
|
2431
|
+
|
|
2432
|
+
const additionalConditionsMet = checkAdditionalConditions();
|
|
2433
|
+
|
|
2299
2434
|
if (
|
|
2300
|
-
|
|
2301
|
-
|
|
2435
|
+
hasActiveProperty &&
|
|
2436
|
+
String(activeValue) === String(s.active.value) &&
|
|
2437
|
+
additionalConditionsMet &&
|
|
2302
2438
|
s.active.type !== 'greater' &&
|
|
2303
2439
|
s.active.type !== 'not null'
|
|
2304
2440
|
) {
|
|
@@ -2307,14 +2443,16 @@ const DataGrid = forwardRef(
|
|
|
2307
2443
|
};
|
|
2308
2444
|
} else if (
|
|
2309
2445
|
s.active.type === 'greater' &&
|
|
2310
|
-
|
|
2446
|
+
Number(activeValue) > Number(s.active.value) &&
|
|
2447
|
+
additionalConditionsMet
|
|
2311
2448
|
) {
|
|
2312
2449
|
iconStyle = {
|
|
2313
2450
|
color: s.active.colour,
|
|
2314
2451
|
};
|
|
2315
2452
|
} else if (
|
|
2316
2453
|
s.active.type === 'not null' &&
|
|
2317
|
-
|
|
2454
|
+
activeValue !== null &&
|
|
2455
|
+
additionalConditionsMet
|
|
2318
2456
|
) {
|
|
2319
2457
|
iconStyle = {
|
|
2320
2458
|
color: s.active.colour,
|
|
@@ -259,11 +259,13 @@ function Field({
|
|
|
259
259
|
if (Array.isArray(s.child)) {
|
|
260
260
|
s.child.forEach((a) => {
|
|
261
261
|
if (a) {
|
|
262
|
+
console.info(a);
|
|
262
263
|
filter = {
|
|
263
264
|
where: [
|
|
264
265
|
{
|
|
265
266
|
id: s.id,
|
|
266
267
|
value: _inputValue,
|
|
268
|
+
...(a.whereHas && { whereHas: a.whereHas }),
|
|
267
269
|
},
|
|
268
270
|
],
|
|
269
271
|
};
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
// Base layout styles
|
|
2
|
+
.authLayout {
|
|
3
|
+
min-height: 100vh;
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
background: #f9fafb;
|
|
8
|
+
padding: 1rem;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.authContainer {
|
|
12
|
+
width: 100%;
|
|
13
|
+
max-width: 500px;
|
|
14
|
+
|
|
15
|
+
@media (max-width: 768px) {
|
|
16
|
+
max-width: 95%;
|
|
17
|
+
width: 95%;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.authWrapper {
|
|
22
|
+
background: white;
|
|
23
|
+
border-radius: 12px;
|
|
24
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.formContainer {
|
|
29
|
+
padding: 2.5rem;
|
|
30
|
+
|
|
31
|
+
@media (max-width: 768px) {
|
|
32
|
+
padding: 2rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@media (max-width: 480px) {
|
|
36
|
+
padding: 1.5rem;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.formContent {
|
|
41
|
+
width: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Logo styles
|
|
45
|
+
.logo {
|
|
46
|
+
display: block;
|
|
47
|
+
margin: 0 auto 2rem;
|
|
48
|
+
max-width: 150px;
|
|
49
|
+
height: auto;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Typography
|
|
53
|
+
.title {
|
|
54
|
+
text-align: center;
|
|
55
|
+
margin-bottom: 0.5rem;
|
|
56
|
+
color: #111827;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
font-size: 1.75rem;
|
|
59
|
+
line-height: 1.2;
|
|
60
|
+
|
|
61
|
+
@media (max-width: 768px) {
|
|
62
|
+
font-size: 1.5rem;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.subtitle {
|
|
67
|
+
text-align: center;
|
|
68
|
+
margin-bottom: 2rem;
|
|
69
|
+
color: #6b7280;
|
|
70
|
+
font-size: 0.875rem;
|
|
71
|
+
line-height: 1.4;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Form fields wrapper
|
|
75
|
+
.formFields {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
gap: 2rem;
|
|
79
|
+
|
|
80
|
+
@media (max-width: 768px) {
|
|
81
|
+
gap: 1.5rem;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Form group (wrapper for each field)
|
|
86
|
+
.formGroup {
|
|
87
|
+
position: relative;
|
|
88
|
+
width: 100%;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Input wrapper and styles
|
|
92
|
+
.inputWrapper {
|
|
93
|
+
position: relative;
|
|
94
|
+
width: 100%;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.inputLabel {
|
|
98
|
+
display: block;
|
|
99
|
+
margin-bottom: 0.5rem;
|
|
100
|
+
color: #374151;
|
|
101
|
+
font-size: 0.875rem;
|
|
102
|
+
font-weight: 500;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.input {
|
|
106
|
+
width: 100%;
|
|
107
|
+
padding: 1rem 2.5rem 1rem 1rem;
|
|
108
|
+
border: 2px solid #e5e7eb;
|
|
109
|
+
border-radius: 8px;
|
|
110
|
+
font-size: 1.1rem;
|
|
111
|
+
transition: all 0.2s ease-in-out;
|
|
112
|
+
background-color: #ffffff;
|
|
113
|
+
color: #111827;
|
|
114
|
+
min-height: 48px;
|
|
115
|
+
|
|
116
|
+
@media (max-width: 768px) {
|
|
117
|
+
font-size: 16px; /* Prevents zoom on iOS */
|
|
118
|
+
min-height: 52px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
&:focus {
|
|
122
|
+
outline: none;
|
|
123
|
+
border-color: var(--primary-color, #4f46e5);
|
|
124
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&::placeholder {
|
|
128
|
+
color: #9ca3af;
|
|
129
|
+
opacity: 1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&:focus::placeholder {
|
|
133
|
+
opacity: 0.5;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.inputError {
|
|
138
|
+
border-color: #ef4444;
|
|
139
|
+
|
|
140
|
+
&:focus {
|
|
141
|
+
border-color: #ef4444;
|
|
142
|
+
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.inputDisabled {
|
|
147
|
+
background-color: #f9fafb;
|
|
148
|
+
color: #9ca3af;
|
|
149
|
+
cursor: not-allowed;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.labelError {
|
|
153
|
+
color: #ef4444;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.inputIcon {
|
|
157
|
+
position: absolute;
|
|
158
|
+
right: 0.75rem;
|
|
159
|
+
top: 50%;
|
|
160
|
+
transform: translateY(-50%);
|
|
161
|
+
color: #9ca3af;
|
|
162
|
+
pointer-events: none;
|
|
163
|
+
z-index: 2;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Error message styles
|
|
167
|
+
.errorMessage {
|
|
168
|
+
margin-top: 0.5rem;
|
|
169
|
+
color: #ef4444;
|
|
170
|
+
font-size: 0.875rem;
|
|
171
|
+
line-height: 1.4;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Button styles
|
|
175
|
+
.button {
|
|
176
|
+
display: inline-flex;
|
|
177
|
+
align-items: center;
|
|
178
|
+
justify-content: center;
|
|
179
|
+
gap: 0.5rem;
|
|
180
|
+
padding: 1rem 1.5rem;
|
|
181
|
+
border: none;
|
|
182
|
+
border-radius: 8px;
|
|
183
|
+
font-size: 1.1rem;
|
|
184
|
+
font-weight: 600;
|
|
185
|
+
cursor: pointer;
|
|
186
|
+
transition: all 0.2s ease-in-out;
|
|
187
|
+
position: relative;
|
|
188
|
+
text-decoration: none;
|
|
189
|
+
line-height: 1.2;
|
|
190
|
+
min-height: 48px;
|
|
191
|
+
|
|
192
|
+
@media (max-width: 768px) {
|
|
193
|
+
min-height: 52px;
|
|
194
|
+
font-size: 1rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&:focus {
|
|
198
|
+
outline: none;
|
|
199
|
+
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&:disabled {
|
|
203
|
+
cursor: not-allowed;
|
|
204
|
+
opacity: 0.6;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.button--primary {
|
|
209
|
+
background-color: var(--primary-color, #4f46e5);
|
|
210
|
+
color: white;
|
|
211
|
+
|
|
212
|
+
&:hover:not(:disabled) {
|
|
213
|
+
background-color: var(--primary-color-dark, #3730a3);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
&:focus {
|
|
217
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.button--secondary {
|
|
222
|
+
background-color: #6b7280;
|
|
223
|
+
color: white;
|
|
224
|
+
|
|
225
|
+
&:hover:not(:disabled) {
|
|
226
|
+
background-color: #4b5563;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.button--outline {
|
|
231
|
+
background-color: transparent;
|
|
232
|
+
color: var(--primary-color, #4f46e5);
|
|
233
|
+
border: 2px solid var(--primary-color, #4f46e5);
|
|
234
|
+
|
|
235
|
+
&:hover:not(:disabled) {
|
|
236
|
+
background-color: var(--primary-color, #4f46e5);
|
|
237
|
+
color: white;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.button--danger {
|
|
242
|
+
background-color: #ef4444;
|
|
243
|
+
color: white;
|
|
244
|
+
|
|
245
|
+
&:hover:not(:disabled) {
|
|
246
|
+
background-color: #dc2626;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.button--success {
|
|
251
|
+
background-color: #10b981;
|
|
252
|
+
color: white;
|
|
253
|
+
|
|
254
|
+
&:hover:not(:disabled) {
|
|
255
|
+
background-color: #059669;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.button--small {
|
|
260
|
+
padding: 0.5rem 1rem;
|
|
261
|
+
font-size: 0.875rem;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.button--medium {
|
|
265
|
+
padding: 0.75rem 1.5rem;
|
|
266
|
+
font-size: 1rem;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.button--large {
|
|
270
|
+
padding: 1rem 2rem;
|
|
271
|
+
font-size: 1.125rem;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.button--fullWidth {
|
|
275
|
+
width: 100%;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.button--disabled {
|
|
279
|
+
opacity: 0.6;
|
|
280
|
+
cursor: not-allowed;
|
|
281
|
+
pointer-events: none;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.buttonText {
|
|
285
|
+
flex: 1;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.buttonIcon {
|
|
289
|
+
display: flex;
|
|
290
|
+
align-items: center;
|
|
291
|
+
justify-content: center;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.buttonSpinner {
|
|
295
|
+
width: 1rem;
|
|
296
|
+
height: 1rem;
|
|
297
|
+
border: 2px solid transparent;
|
|
298
|
+
border-top: 2px solid currentColor;
|
|
299
|
+
border-radius: 50%;
|
|
300
|
+
animation: spin 1s linear infinite;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@keyframes spin {
|
|
304
|
+
to {
|
|
305
|
+
transform: rotate(360deg);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Checkbox styles
|
|
310
|
+
.checkboxGroup {
|
|
311
|
+
display: flex;
|
|
312
|
+
flex-direction: column;
|
|
313
|
+
gap: 0.5rem;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.checkboxWrapper {
|
|
317
|
+
display: flex;
|
|
318
|
+
align-items: center;
|
|
319
|
+
gap: 0.75rem;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.checkbox {
|
|
323
|
+
width: 1.25rem;
|
|
324
|
+
height: 1.25rem;
|
|
325
|
+
border: 2px solid #d1d5db;
|
|
326
|
+
border-radius: 4px;
|
|
327
|
+
background-color: white;
|
|
328
|
+
cursor: pointer;
|
|
329
|
+
transition: all 0.2s ease-in-out;
|
|
330
|
+
|
|
331
|
+
&:checked {
|
|
332
|
+
background-color: var(--primary-color, #4f46e5);
|
|
333
|
+
border-color: var(--primary-color, #4f46e5);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
&:focus {
|
|
337
|
+
outline: none;
|
|
338
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.checkboxError {
|
|
343
|
+
border-color: #ef4444;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.checkboxDisabled {
|
|
347
|
+
background-color: #f9fafb;
|
|
348
|
+
cursor: not-allowed;
|
|
349
|
+
opacity: 0.6;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.checkboxLabel {
|
|
353
|
+
color: #374151;
|
|
354
|
+
font-size: 0.875rem;
|
|
355
|
+
cursor: pointer;
|
|
356
|
+
user-select: none;
|
|
357
|
+
line-height: 1.4;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.checkboxLabelDisabled {
|
|
361
|
+
color: #9ca3af;
|
|
362
|
+
cursor: not-allowed;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Utility classes
|
|
366
|
+
.divider {
|
|
367
|
+
position: relative;
|
|
368
|
+
margin: 1.5rem 0;
|
|
369
|
+
text-align: center;
|
|
370
|
+
color: #6b7280;
|
|
371
|
+
font-size: 0.875rem;
|
|
372
|
+
|
|
373
|
+
&::before {
|
|
374
|
+
content: '';
|
|
375
|
+
position: absolute;
|
|
376
|
+
top: 50%;
|
|
377
|
+
left: 0;
|
|
378
|
+
right: 0;
|
|
379
|
+
height: 1px;
|
|
380
|
+
background-color: #e5e7eb;
|
|
381
|
+
z-index: 0;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
span {
|
|
385
|
+
background-color: white;
|
|
386
|
+
padding: 0 1rem;
|
|
387
|
+
position: relative;
|
|
388
|
+
z-index: 1;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.linkButton {
|
|
393
|
+
background: none;
|
|
394
|
+
border: none;
|
|
395
|
+
color: var(--primary-color, #4f46e5);
|
|
396
|
+
text-decoration: underline;
|
|
397
|
+
cursor: pointer;
|
|
398
|
+
font-size: 0.875rem;
|
|
399
|
+
padding: 0;
|
|
400
|
+
|
|
401
|
+
&:hover {
|
|
402
|
+
color: var(--primary-color-dark, #3730a3);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
&:focus {
|
|
406
|
+
outline: 2px solid var(--primary-color, #4f46e5);
|
|
407
|
+
outline-offset: 2px;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Responsive design
|
|
412
|
+
@media (max-width: 480px) {
|
|
413
|
+
.authLayout {
|
|
414
|
+
padding: 0.5rem;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.authContainer {
|
|
418
|
+
max-width: 100%;
|
|
419
|
+
width: 100%;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.formContainer {
|
|
423
|
+
padding: 1.5rem;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.title {
|
|
427
|
+
font-size: 1.375rem;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.formFields {
|
|
431
|
+
gap: 1.25rem;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.input {
|
|
435
|
+
padding: 1rem;
|
|
436
|
+
font-size: 16px;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.button {
|
|
440
|
+
padding: 1rem;
|
|
441
|
+
font-size: 1rem;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
@@ -2127,6 +2127,41 @@ function GenericDetail({
|
|
|
2127
2127
|
config.columns &&
|
|
2128
2128
|
config.settings
|
|
2129
2129
|
) {
|
|
2130
|
+
const processUrlParams = (obj) => {
|
|
2131
|
+
if (Array.isArray(obj)) {
|
|
2132
|
+
return obj.map(processUrlParams);
|
|
2133
|
+
} else if (obj && typeof obj === 'object') {
|
|
2134
|
+
const processed = {};
|
|
2135
|
+
for (const [
|
|
2136
|
+
key,
|
|
2137
|
+
value,
|
|
2138
|
+
] of Object.entries(obj)) {
|
|
2139
|
+
if (value === 'urlParam') {
|
|
2140
|
+
processed[key] =
|
|
2141
|
+
routeParams[urlParam];
|
|
2142
|
+
} else if (
|
|
2143
|
+
typeof value === 'object' && value !== null
|
|
2144
|
+
) {
|
|
2145
|
+
processed[key] =
|
|
2146
|
+
processUrlParams(value);
|
|
2147
|
+
} else {
|
|
2148
|
+
processed[key] = value;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
return processed;
|
|
2152
|
+
}
|
|
2153
|
+
return obj;
|
|
2154
|
+
};
|
|
2155
|
+
|
|
2156
|
+
const processedSettings = config.settings
|
|
2157
|
+
? processUrlParams(config.settings)
|
|
2158
|
+
: config.settings;
|
|
2159
|
+
|
|
2160
|
+
const processedConfig = {
|
|
2161
|
+
...config,
|
|
2162
|
+
settings: processedSettings,
|
|
2163
|
+
};
|
|
2164
|
+
|
|
2130
2165
|
return (
|
|
2131
2166
|
<>
|
|
2132
2167
|
{activeTabConfig.dropzone &&
|
|
@@ -2292,7 +2327,7 @@ function GenericDetail({
|
|
|
2292
2327
|
<div className={styles.grid__row}>
|
|
2293
2328
|
<div className={styles.grid__full}>
|
|
2294
2329
|
<Table
|
|
2295
|
-
{...
|
|
2330
|
+
{...processedConfig}
|
|
2296
2331
|
ref={gridRef}
|
|
2297
2332
|
gridHeight={
|
|
2298
2333
|
windowHeight * 0.65
|