@visns-studio/visns-components 5.11.2 → 5.11.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.
@@ -36,16 +36,27 @@ 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, ...rest } = props;
39
+ const { children, data, removeProps, settings, ...rest } = props;
40
+
40
41
  return (
41
42
  <components.MultiValue {...rest}>
42
43
  <div className={styles.multiValue}>
43
- <div className={styles.multiValueLabel}>{children}</div>
44
+ <div className={styles.multiValueLabel}>
45
+ {children}
46
+ {data.is_primary && settings?.primaryField && (
47
+ <span className={styles.primaryIndicator}>Primary</span>
48
+ )}
49
+ </div>
44
50
  {data.description && (
45
51
  <div className={styles.multiValueDescription}>
46
52
  {data.description}
47
53
  </div>
48
54
  )}
55
+ {data.relationship_type && settings?.relationshipTypes && (
56
+ <div className={styles.relationshipType}>
57
+ {data.relationship_type}
58
+ </div>
59
+ )}
49
60
  </div>
50
61
  </components.MultiValue>
51
62
  );
@@ -218,7 +229,7 @@ function MultiSelect({
218
229
  components={{
219
230
  SelectList,
220
231
  Option: CustomOption,
221
- MultiValue: CustomMultiValue,
232
+ MultiValue: (props) => <CustomMultiValue {...props} settings={settings} />,
222
233
  }}
223
234
  options={selectOptions}
224
235
  menuPortalTarget={document.body}
@@ -289,15 +289,14 @@ function Navigation({
289
289
  const IconComponent = iconComponents[n.icon];
290
290
 
291
291
  return (
292
- <li className={activeClass}>
293
- {' '}
294
- {/* Apply active class to the list item */}
292
+ <li>
295
293
  <Link
296
294
  to={n.url}
297
295
  data-tooltip-id="system-tooltip"
298
296
  data-tooltip-content={n.label}
299
- className={`tooltip ${activeClass}`} // Apply active class to the link
297
+ className={`tooltip ${activeClass}`}
300
298
  target={n.target ? n.target : '_self'}
299
+ title={n.label}
301
300
  >
302
301
  <IconComponent size={19} strokeWidth={2} />
303
302
  </Link>
@@ -1,4 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
+ import { createPortal } from 'react-dom';
2
3
  import { Tooltip } from 'react-tooltip';
3
4
  import moment from 'moment';
4
5
  import numeral from 'numeral';
@@ -103,35 +104,41 @@ const CellWithTooltip = ({
103
104
  width: '100%',
104
105
  };
105
106
 
107
+ // Render tooltip using createPortal to escape stacking contexts
108
+ const tooltipPortal = shouldShowTooltip && createPortal(
109
+ <Tooltip
110
+ id={tooltipId}
111
+ style={{
112
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
113
+ color: 'white',
114
+ borderRadius: '6px',
115
+ padding: '8px 12px',
116
+ fontSize: '13px',
117
+ maxWidth: '500px',
118
+ wordWrap: 'break-word',
119
+ zIndex: 9999, // Slightly lower since we're now at document.body level
120
+ }}
121
+ place="top"
122
+ offset={5}
123
+ />,
124
+ document.body
125
+ );
126
+
106
127
  return (
107
- <div
108
- ref={cellRef}
109
- className={className}
110
- style={cellStyles}
111
- {...(shouldShowTooltip && {
112
- 'data-tooltip-id': tooltipId,
113
- 'data-tooltip-html': tooltipContent,
114
- })}
115
- >
116
- {children}
117
- {shouldShowTooltip && (
118
- <Tooltip
119
- id={tooltipId}
120
- style={{
121
- backgroundColor: 'rgba(0, 0, 0, 0.9)',
122
- color: 'white',
123
- borderRadius: '6px',
124
- padding: '8px 12px',
125
- fontSize: '13px',
126
- maxWidth: '500px',
127
- wordWrap: 'break-word',
128
- zIndex: 1000,
129
- }}
130
- place="top"
131
- offset={5}
132
- />
133
- )}
134
- </div>
128
+ <>
129
+ <div
130
+ ref={cellRef}
131
+ className={className}
132
+ style={cellStyles}
133
+ {...(shouldShowTooltip && {
134
+ 'data-tooltip-id': tooltipId,
135
+ 'data-tooltip-html': tooltipContent,
136
+ })}
137
+ >
138
+ {children}
139
+ </div>
140
+ {tooltipPortal}
141
+ </>
135
142
  );
136
143
  };
137
144
 
@@ -63,10 +63,12 @@ import 'react-big-calendar/lib/css/react-big-calendar.css';
63
63
  import 'react-big-calendar/lib/addons/dragAndDrop/styles.css';
64
64
 
65
65
  import Breadcrumb from '../Breadcrumb';
66
+ import AssociationManager from '../AssociationManager';
66
67
  import CustomFetch from '../Fetch';
67
68
  import Form from '../Form';
68
69
  import GenericDynamic from './GenericDynamic';
69
70
  import GenericEditableTable from './GenericEditableTable';
71
+ import MergeEntity from '../MergeEntity';
70
72
  import MultiSelect from '../MultiSelect';
71
73
  import QrCode from '../QrCode';
72
74
  import Table from '../DataGrid';
@@ -2490,6 +2492,29 @@ function GenericDetail({
2490
2492
  setData={setData}
2491
2493
  />
2492
2494
  );
2495
+ case 'custom':
2496
+ // Handle custom components
2497
+ if (activeTabConfig.component === 'AssociationManager' || activeTabConfig.component === 'ClientAssociationManager') {
2498
+ return (
2499
+ <AssociationManager
2500
+ endpoints={activeTabConfig.endpoints}
2501
+ config={activeTabConfig.config}
2502
+ dataId={routeParams[urlParam]}
2503
+ onUpdate={handleReload}
2504
+ />
2505
+ );
2506
+ }
2507
+ if (activeTabConfig.component === 'MergeEntity') {
2508
+ return (
2509
+ <MergeEntity
2510
+ endpoints={activeTabConfig.endpoints}
2511
+ config={activeTabConfig.config}
2512
+ dataId={routeParams[urlParam]}
2513
+ onUpdate={handleReload}
2514
+ />
2515
+ );
2516
+ }
2517
+ return null;
2493
2518
  default:
2494
2519
  return null;
2495
2520
  }
@@ -0,0 +1,364 @@
1
+ .container {
2
+ padding: 20px;
3
+ background: var(--bg-color);
4
+ border-radius: var(--radius);
5
+ box-shadow: var(--box-shadow-small);
6
+ }
7
+
8
+ .header {
9
+ margin-bottom: 30px;
10
+ border-bottom: 1px solid rgba(var(--paragraph-rgb), 0.15);
11
+ padding-bottom: 15px;
12
+
13
+ h3 {
14
+ margin: 0 0 5px 0;
15
+ color: var(--primary-color);
16
+ font-size: 1.4em;
17
+ font-weight: 600;
18
+ }
19
+
20
+ p {
21
+ margin: 0;
22
+ color: var(--paragraph-color);
23
+ font-size: 0.9em;
24
+ opacity: 0.8;
25
+ }
26
+ }
27
+
28
+ .loading {
29
+ text-align: center;
30
+ padding: 40px;
31
+ color: var(--paragraph-color);
32
+ opacity: 0.7;
33
+ }
34
+
35
+ /* Multiple Primary Warning */
36
+ .multiplePrimaryWarning {
37
+ display: flex;
38
+ align-items: flex-start;
39
+ gap: 12px;
40
+ padding: 16px;
41
+ margin-bottom: 24px;
42
+ background: rgba(255, 193, 7, 0.1);
43
+ border: 1px solid rgba(255, 193, 7, 0.3);
44
+ border-left: 4px solid rgba(255, 193, 7, 1);
45
+ border-radius: var(--radius);
46
+ color: #856404;
47
+
48
+ .warningContent {
49
+ flex: 1;
50
+
51
+ strong {
52
+ display: block;
53
+ margin-bottom: 4px;
54
+ font-size: 0.95em;
55
+ }
56
+
57
+ p {
58
+ margin: 0 0 12px 0;
59
+ font-size: 0.85em;
60
+ line-height: 1.4;
61
+ opacity: 0.9;
62
+ }
63
+ }
64
+ }
65
+
66
+ .clearAllPrimaryBtn {
67
+ padding: 6px 12px;
68
+ background: rgba(255, 193, 7, 1);
69
+ color: #fff;
70
+ border: none;
71
+ border-radius: var(--radius);
72
+ font-size: 0.8em;
73
+ font-weight: 500;
74
+ cursor: pointer;
75
+ transition: all 0.2s ease;
76
+
77
+ &:hover {
78
+ background: rgba(255, 173, 7, 1);
79
+ transform: translateY(-1px);
80
+ }
81
+ }
82
+
83
+ /* Existing Associations */
84
+ .existingAssociations {
85
+ margin-bottom: 40px;
86
+
87
+ h4 {
88
+ margin: 0 0 15px 0;
89
+ color: var(--secondary-color);
90
+ font-size: 1.1em;
91
+ font-weight: 500;
92
+ }
93
+ }
94
+
95
+ .noAssociations {
96
+ padding: 20px;
97
+ text-align: center;
98
+ color: var(--paragraph-color);
99
+ background: rgba(var(--paragraph-rgb), 0.05);
100
+ border-radius: var(--radius);
101
+ font-style: italic;
102
+ opacity: 0.8;
103
+ }
104
+
105
+ .associationsList {
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: 12px;
109
+ }
110
+
111
+ .associationItem {
112
+ display: flex;
113
+ justify-content: space-between;
114
+ align-items: center;
115
+ padding: 15px;
116
+ border: 1px solid rgba(var(--paragraph-rgb), 0.15);
117
+ border-radius: var(--radius);
118
+ background: var(--tertiary-color);
119
+ transition: all 0.2s ease;
120
+
121
+ &:hover {
122
+ background: rgba(var(--paragraph-rgb), 0.05);
123
+ border-color: rgba(var(--paragraph-rgb), 0.25);
124
+ }
125
+
126
+ &.primary {
127
+ border-color: var(--primary-color);
128
+ background: rgba(var(--primary-rgb), 0.1);
129
+
130
+ &:hover {
131
+ background: rgba(var(--primary-rgb), 0.15);
132
+ }
133
+ }
134
+ }
135
+
136
+ .associationInfo {
137
+ flex: 1;
138
+
139
+ .entityName {
140
+ font-weight: 600;
141
+ color: var(--secondary-color);
142
+ margin-bottom: 4px;
143
+ display: flex;
144
+ align-items: center;
145
+ gap: 8px;
146
+ }
147
+
148
+ .primaryBadge {
149
+ background: var(--primary-color);
150
+ color: var(--bg-color);
151
+ padding: 2px 6px;
152
+ border-radius: var(--radius);
153
+ font-size: 0.75em;
154
+ font-weight: 500;
155
+ text-transform: uppercase;
156
+ }
157
+
158
+ .relationshipInfo {
159
+ margin-bottom: 4px;
160
+
161
+ .relationshipType {
162
+ color: var(--paragraph-color);
163
+ font-weight: 500;
164
+ text-transform: capitalize;
165
+ }
166
+
167
+ .notes {
168
+ color: var(--paragraph-color);
169
+ font-size: 0.9em;
170
+ opacity: 0.7;
171
+ }
172
+ }
173
+
174
+ .associatedAt {
175
+ color: var(--paragraph-color);
176
+ font-size: 0.8em;
177
+ opacity: 0.6;
178
+ }
179
+ }
180
+
181
+ .associationActions {
182
+ display: flex;
183
+ gap: 8px;
184
+ align-items: center;
185
+ }
186
+
187
+ .setPrimaryBtn,
188
+ .removePrimaryBtn,
189
+ .removeBtn,
190
+ .associateBtn {
191
+ padding: 6px 12px;
192
+ border: none;
193
+ border-radius: var(--radius);
194
+ font-size: 0.85em;
195
+ cursor: pointer;
196
+ transition: all 0.2s ease;
197
+ font-weight: 500;
198
+
199
+ &:disabled {
200
+ opacity: 0.6;
201
+ cursor: not-allowed;
202
+ }
203
+ }
204
+
205
+ .setPrimaryBtn {
206
+ background: var(--highlight-color);
207
+ color: #ffffff;
208
+
209
+ &:hover:not(:disabled) {
210
+ background: #0056b3;
211
+ color: #ffffff;
212
+ transform: translateY(-1px);
213
+ }
214
+ }
215
+
216
+ .removePrimaryBtn {
217
+ background: rgba(108, 117, 125, 1);
218
+ color: var(--bg-color);
219
+
220
+ &:hover:not(:disabled) {
221
+ background: rgba(90, 98, 104, 1);
222
+ transform: translateY(-1px);
223
+ }
224
+ }
225
+
226
+ .removeBtn {
227
+ background: rgba(220, 53, 69, 1);
228
+ color: var(--bg-color);
229
+
230
+ &:hover:not(:disabled) {
231
+ background: rgba(200, 35, 51, 1);
232
+ transform: translateY(-1px);
233
+ }
234
+ }
235
+
236
+ .associateBtn {
237
+ background: var(--primary-color);
238
+ color: var(--bg-color);
239
+ padding: 10px 20px;
240
+ font-size: 0.9em;
241
+
242
+ &:hover:not(:disabled) {
243
+ background: rgba(var(--primary-rgb), 0.9);
244
+ transform: translateY(-1px);
245
+ }
246
+ }
247
+
248
+ /* New Association Form */
249
+ .newAssociation {
250
+ border-top: 1px solid rgba(var(--paragraph-rgb), 0.15);
251
+ padding-top: 30px;
252
+
253
+ h4 {
254
+ margin: 0 0 20px 0;
255
+ color: var(--secondary-color);
256
+ font-size: 1.1em;
257
+ font-weight: 500;
258
+ }
259
+ }
260
+
261
+ .associationForm {
262
+ background: rgba(var(--paragraph-rgb), 0.05);
263
+ padding: 20px;
264
+ border-radius: var(--radius);
265
+ border: 1px solid rgba(var(--paragraph-rgb), 0.1);
266
+ }
267
+
268
+ .formRow {
269
+ display: flex;
270
+ gap: 20px;
271
+ margin-bottom: 20px;
272
+
273
+ &:last-child {
274
+ margin-bottom: 0;
275
+ }
276
+
277
+ @media (max-width: 768px) {
278
+ flex-direction: column;
279
+ gap: 15px;
280
+ }
281
+ }
282
+
283
+ .formField {
284
+ flex: 1;
285
+
286
+ label {
287
+ display: block;
288
+ margin-bottom: 5px;
289
+ color: var(--secondary-color);
290
+ font-weight: 500;
291
+ font-size: 0.9em;
292
+
293
+ input[type="checkbox"] {
294
+ margin-right: 8px;
295
+ }
296
+ }
297
+ }
298
+
299
+ .selectField,
300
+ .textField {
301
+ width: 100%;
302
+ padding: 8px 12px;
303
+ border: 1px solid rgba(var(--paragraph-rgb), 0.25);
304
+ border-radius: var(--radius);
305
+ background: var(--bg-color);
306
+ font-size: 0.9em;
307
+ color: var(--paragraph-color);
308
+ transition: all 0.2s ease;
309
+
310
+ &:focus {
311
+ outline: none;
312
+ border-color: var(--primary-color);
313
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.25);
314
+ }
315
+ }
316
+
317
+ .textareaField {
318
+ width: 100%;
319
+ padding: 8px 12px;
320
+ border: 1px solid rgba(var(--paragraph-rgb), 0.25);
321
+ border-radius: var(--radius);
322
+ background: var(--bg-color);
323
+ font-size: 0.9em;
324
+ color: var(--paragraph-color);
325
+ resize: vertical;
326
+ min-height: 60px;
327
+ transition: all 0.2s ease;
328
+
329
+ &:focus {
330
+ outline: none;
331
+ border-color: var(--primary-color);
332
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.25);
333
+ }
334
+ }
335
+
336
+ .formActions {
337
+ margin-top: 20px;
338
+ text-align: right;
339
+ }
340
+
341
+ /* Responsive Design */
342
+ @media (max-width: 768px) {
343
+ .container {
344
+ padding: 15px;
345
+ }
346
+
347
+ .associationItem {
348
+ flex-direction: column;
349
+ align-items: flex-start;
350
+ gap: 15px;
351
+ }
352
+
353
+ .associationActions {
354
+ align-self: flex-end;
355
+ }
356
+
357
+ .formActions {
358
+ text-align: center;
359
+ }
360
+
361
+ .associateBtn {
362
+ width: 100%;
363
+ }
364
+ }