@visns-studio/visns-components 5.11.1 → 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.
- package/package.json +2 -2
- package/src/components/cms/DataGrid.jsx +8 -8
- package/src/components/cms/DropZone.jsx +1 -1
- package/src/components/cms/Form.jsx +1 -1
- package/src/components/cms/Gallery.jsx +1 -1
- package/src/components/cms/sorting/Item.jsx +1 -1
- package/src/components/crm/AssociationManager.jsx +431 -0
- package/src/components/crm/Autocomplete.jsx +3 -3
- package/src/components/crm/Breadcrumb.jsx +4 -4
- package/src/components/crm/BusinessCardOcr.jsx +681 -95
- package/src/components/crm/ClientAssociationManager.jsx +362 -0
- package/src/components/crm/DataGrid.jsx +34 -32
- package/src/components/crm/Field.jsx +12 -12
- package/src/components/crm/Form.jsx +2 -2
- package/src/components/crm/MergeEntity.jsx +1049 -0
- package/src/components/crm/MultiSelect.jsx +14 -3
- package/src/components/crm/Navigation.jsx +14 -15
- package/src/components/crm/Notification.jsx +2 -2
- package/src/components/crm/QuickAction.jsx +3 -3
- package/src/components/crm/SectionHeader.jsx +1 -1
- package/src/components/crm/SwitchAccount.jsx +4 -4
- package/src/components/crm/auth/ClientLogin.jsx +2 -2
- package/src/components/crm/auth/ClientOTPVerify.jsx +2 -2
- package/src/components/crm/auth/Login.jsx +3 -3
- package/src/components/crm/auth/Reset.jsx +2 -2
- package/src/components/crm/auth/TwoFactorAuth.jsx +2 -2
- package/src/components/crm/cells/CellWithTooltip.jsx +35 -28
- package/src/components/crm/columns/ColumnRenderers.jsx +320 -259
- package/src/components/crm/controls/DataGridSearch.jsx +5 -5
- package/src/components/crm/generic/AlternativeActionModal.jsx +100 -0
- package/src/components/crm/generic/ContactSelectorModal.jsx +59 -16
- package/src/components/crm/generic/DateRangeSelectorModal.jsx +181 -0
- package/src/components/crm/generic/GenericClientPortal.jsx +1 -1
- package/src/components/crm/generic/GenericDashboard.jsx +4 -4
- package/src/components/crm/generic/GenericDetail.jsx +31 -6
- package/src/components/crm/generic/GenericDynamic.jsx +3 -3
- package/src/components/crm/generic/GenericEditableTable.jsx +4 -4
- package/src/components/crm/generic/GenericFormBuilder.jsx +6 -6
- package/src/components/crm/generic/GenericGrid.jsx +1622 -268
- package/src/components/crm/generic/GenericReport.jsx +966 -646
- package/src/components/crm/generic/GenericReportForm.jsx +1 -1
- package/src/components/crm/generic/NotificationList.jsx +1 -1
- package/src/components/crm/generic/ReasonCollectorModal.jsx +194 -0
- package/src/components/crm/generic/SortableQuoteItems.jsx +3 -3
- package/src/components/crm/generic/shared/formatters.js +107 -1
- package/src/components/crm/generic/styles/AlternativeActionModal.css +127 -0
- package/src/components/crm/generic/styles/DateRangeSelectorModal.css +115 -0
- package/src/components/crm/generic/styles/GenericIndex.module.scss +206 -0
- package/src/components/crm/generic/styles/GenericReport.module.scss +96 -0
- package/src/components/crm/generic/styles/ReasonCollectorModal.css +217 -0
- package/src/components/crm/modals/GalleryModal.jsx +2 -2
- package/src/components/crm/sorting/Item.jsx +3 -3
- package/src/components/crm/styles/AssociationManager.module.scss +364 -0
- package/src/components/crm/styles/BusinessCardOcr.module.scss +197 -4
- package/src/components/crm/styles/ClientAssociationManager.module.scss +290 -0
- package/src/components/crm/styles/MergeEntity.module.scss +690 -0
- package/src/components/crm/styles/MultiSelect.module.scss +18 -0
- package/src/components/crm/styles/Navigation.module.scss +68 -8
- package/src/components/crm/styles/global-datagrid.css +9 -0
- package/src/index.js +6 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { toast } from 'react-toastify';
|
|
3
|
+
import CustomFetch from './Fetch';
|
|
4
|
+
import MultiSelect from './MultiSelect';
|
|
5
|
+
import styles from './styles/ClientAssociationManager.module.scss';
|
|
6
|
+
|
|
7
|
+
const ClientAssociationManager = ({
|
|
8
|
+
endpoints,
|
|
9
|
+
config,
|
|
10
|
+
dataId,
|
|
11
|
+
onUpdate = () => {}
|
|
12
|
+
}) => {
|
|
13
|
+
const [associations, setAssociations] = useState([]);
|
|
14
|
+
const [availableOptions, setAvailableOptions] = useState([]);
|
|
15
|
+
const [loading, setLoading] = useState(true);
|
|
16
|
+
|
|
17
|
+
// Dynamic state based on config
|
|
18
|
+
const [newAssociation, setNewAssociation] = useState(() => {
|
|
19
|
+
const initialState = {};
|
|
20
|
+
|
|
21
|
+
// Set up dynamic fields based on config
|
|
22
|
+
if (config.fields) {
|
|
23
|
+
config.fields.forEach(field => {
|
|
24
|
+
initialState[field.id] = field.defaultValue || (field.type === 'boolean' ? false :
|
|
25
|
+
field.type === 'select' ? (field.options?.[0]?.value || '') :
|
|
26
|
+
field.type === 'multi-select' ? [] : '');
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return initialState;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Replace placeholders in endpoint URLs and data
|
|
34
|
+
const processTemplate = (template, data = {}) => {
|
|
35
|
+
let processed = template;
|
|
36
|
+
|
|
37
|
+
// Replace {dataId} with current dataId
|
|
38
|
+
processed = processed.replace(/\{dataId\}/g, dataId);
|
|
39
|
+
|
|
40
|
+
// Replace any other placeholders from provided data
|
|
41
|
+
Object.keys(data).forEach(key => {
|
|
42
|
+
const placeholder = new RegExp(`\\{${key}\\}`, 'g');
|
|
43
|
+
processed = processed.replace(placeholder, data[key]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return processed;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Load existing associations
|
|
50
|
+
const loadAssociations = async () => {
|
|
51
|
+
if (!endpoints.list) return;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
setLoading(true);
|
|
55
|
+
const url = processTemplate(endpoints.list);
|
|
56
|
+
const method = endpoints.listMethod || 'GET';
|
|
57
|
+
const response = await CustomFetch(url, method, endpoints.listParams || {});
|
|
58
|
+
|
|
59
|
+
const dataPath = config.dataPath || 'data';
|
|
60
|
+
const associationsData = dataPath.split('.').reduce((obj, key) => obj?.[key], response);
|
|
61
|
+
|
|
62
|
+
// Ensure associationsData is always an array
|
|
63
|
+
const validAssociations = Array.isArray(associationsData) ? associationsData : [];
|
|
64
|
+
setAssociations(validAssociations);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
toast.error(config.messages?.loadError || 'Failed to load associations');
|
|
67
|
+
console.error('Error loading associations:', error);
|
|
68
|
+
setAssociations([]); // Set empty array on error
|
|
69
|
+
} finally {
|
|
70
|
+
setLoading(false);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Load available options for dropdown/select fields
|
|
75
|
+
const loadAvailableOptions = async () => {
|
|
76
|
+
if (!config.optionsEndpoint) return;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const url = processTemplate(config.optionsEndpoint.url);
|
|
80
|
+
const method = config.optionsEndpoint.method || 'POST';
|
|
81
|
+
const params = config.optionsEndpoint.params || {};
|
|
82
|
+
|
|
83
|
+
const response = await CustomFetch(url, method, params);
|
|
84
|
+
const dataPath = config.optionsEndpoint.dataPath || 'data.data';
|
|
85
|
+
const optionsData = dataPath.split('.').reduce((obj, key) => obj?.[key], response) || [];
|
|
86
|
+
|
|
87
|
+
setAvailableOptions(optionsData);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('Failed to load options:', error);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Generic action handler
|
|
94
|
+
const handleAction = async (actionKey, data = {}) => {
|
|
95
|
+
const endpoint = endpoints[actionKey];
|
|
96
|
+
if (!endpoint) return;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const url = processTemplate(endpoint.url || endpoint, data);
|
|
100
|
+
const method = endpoint.method || 'POST';
|
|
101
|
+
const params = { ...endpoint.params, ...data };
|
|
102
|
+
|
|
103
|
+
await CustomFetch(url, method, params);
|
|
104
|
+
|
|
105
|
+
const successMessage = config.messages?.[`${actionKey}Success`] ||
|
|
106
|
+
endpoint.successMessage ||
|
|
107
|
+
'Action completed successfully';
|
|
108
|
+
toast.success(successMessage);
|
|
109
|
+
|
|
110
|
+
// Reset form if it's an associate action
|
|
111
|
+
if (actionKey === 'associate') {
|
|
112
|
+
const resetState = {};
|
|
113
|
+
if (config.fields) {
|
|
114
|
+
config.fields.forEach(field => {
|
|
115
|
+
resetState[field.id] = field.defaultValue || (field.type === 'boolean' ? false :
|
|
116
|
+
field.type === 'select' ? (field.options?.[0]?.value || '') :
|
|
117
|
+
field.type === 'multi-select' ? [] : '');
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
setNewAssociation(resetState);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
loadAssociations();
|
|
124
|
+
onUpdate();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
const errorMessage = config.messages?.[`${actionKey}Error`] ||
|
|
127
|
+
endpoint.errorMessage ||
|
|
128
|
+
'Action failed';
|
|
129
|
+
toast.error(errorMessage);
|
|
130
|
+
console.error(error);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Associate handler
|
|
135
|
+
const handleAssociate = async () => {
|
|
136
|
+
// Validate required fields
|
|
137
|
+
const requiredField = config.fields?.find(field => field.required);
|
|
138
|
+
const primaryField = config.fields?.find(field => field.isPrimary);
|
|
139
|
+
|
|
140
|
+
if (requiredField && !newAssociation[requiredField.id]) {
|
|
141
|
+
toast.error(`Please select a ${requiredField.label || requiredField.id}`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Prepare data for submission
|
|
146
|
+
const submitData = { ...newAssociation };
|
|
147
|
+
|
|
148
|
+
// Handle complex field values (like objects from MultiSelect)
|
|
149
|
+
Object.keys(submitData).forEach(key => {
|
|
150
|
+
const value = submitData[key];
|
|
151
|
+
if (value && typeof value === 'object' && value.value !== undefined) {
|
|
152
|
+
submitData[key] = value.value;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await handleAction('associate', submitData);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Remove association handler
|
|
160
|
+
const handleDissociate = async (itemId) => {
|
|
161
|
+
const deleteField = config.deleteField || 'id';
|
|
162
|
+
await handleAction('dissociate', { [deleteField]: itemId });
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Set primary handler
|
|
166
|
+
const handleSetPrimary = async (itemId) => {
|
|
167
|
+
if (!endpoints.setPrimary) return;
|
|
168
|
+
|
|
169
|
+
const primaryField = config.fields?.find(field => field.isPrimary);
|
|
170
|
+
const idField = primaryField?.targetField || 'id';
|
|
171
|
+
|
|
172
|
+
await handleAction('setPrimary', { [idField]: itemId });
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (dataId) {
|
|
177
|
+
loadAssociations();
|
|
178
|
+
loadAvailableOptions();
|
|
179
|
+
}
|
|
180
|
+
}, [dataId]);
|
|
181
|
+
|
|
182
|
+
if (loading) {
|
|
183
|
+
return <div className={styles.loading}>{config.messages?.loading || 'Loading associations...'}</div>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<div className={styles.container}>
|
|
188
|
+
<div className={styles.header}>
|
|
189
|
+
<h3>{config.title || 'Associations'}</h3>
|
|
190
|
+
<p>{config.description || 'Manage associations'}</p>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
{/* Existing Associations */}
|
|
194
|
+
<div className={styles.existingAssociations}>
|
|
195
|
+
<h4>{config.labels?.currentAssociations || 'Current Associations'}</h4>
|
|
196
|
+
{associations.length === 0 ? (
|
|
197
|
+
<div className={styles.noAssociations}>
|
|
198
|
+
{config.messages?.noAssociations || 'No associations found.'}
|
|
199
|
+
</div>
|
|
200
|
+
) : (
|
|
201
|
+
<div className={styles.associationsList}>
|
|
202
|
+
{associations.map((association) => {
|
|
203
|
+
const nameField = config.displayFields?.name || 'name';
|
|
204
|
+
const primaryField = config.displayFields?.primary || 'is_primary';
|
|
205
|
+
const relationshipField = config.displayFields?.relationship || 'relationship_type';
|
|
206
|
+
const notesField = config.displayFields?.notes || 'notes';
|
|
207
|
+
const dateField = config.displayFields?.date || 'associated_at';
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
<div
|
|
211
|
+
key={association.id}
|
|
212
|
+
className={`${styles.associationItem} ${association[primaryField] ? styles.primary : ''}`}
|
|
213
|
+
>
|
|
214
|
+
<div className={styles.associationInfo}>
|
|
215
|
+
<div className={styles.companyName}>
|
|
216
|
+
{association[nameField]}
|
|
217
|
+
{association[primaryField] && (
|
|
218
|
+
<span className={styles.primaryBadge}>{config.labels?.primaryBadge || 'Primary'}</span>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
<div className={styles.relationshipInfo}>
|
|
222
|
+
<span className={styles.relationshipType}>
|
|
223
|
+
{association[relationshipField]}
|
|
224
|
+
</span>
|
|
225
|
+
{association[notesField] && (
|
|
226
|
+
<span className={styles.notes}>
|
|
227
|
+
- {association[notesField]}
|
|
228
|
+
</span>
|
|
229
|
+
)}
|
|
230
|
+
</div>
|
|
231
|
+
<div className={styles.associatedAt}>
|
|
232
|
+
{config.labels?.associatedAt || 'Associated'}: {new Date(association[dateField]).toLocaleDateString()}
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
<div className={styles.associationActions}>
|
|
236
|
+
{!association[primaryField] && endpoints.setPrimary && (
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
className={styles.setPrimaryBtn}
|
|
240
|
+
onClick={() => handleSetPrimary(association.id)}
|
|
241
|
+
>
|
|
242
|
+
{config.labels?.setPrimary || 'Set Primary'}
|
|
243
|
+
</button>
|
|
244
|
+
)}
|
|
245
|
+
<button
|
|
246
|
+
type="button"
|
|
247
|
+
className={styles.removeBtn}
|
|
248
|
+
onClick={() => handleDissociate(association.id)}
|
|
249
|
+
>
|
|
250
|
+
{config.labels?.remove || 'Remove'}
|
|
251
|
+
</button>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
);
|
|
255
|
+
})}
|
|
256
|
+
</div>
|
|
257
|
+
)}
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
{/* Add New Association */}
|
|
261
|
+
<div className={styles.newAssociation}>
|
|
262
|
+
<h4>{config.labels?.addNew || 'Add New Association'}</h4>
|
|
263
|
+
<div className={styles.associationForm}>
|
|
264
|
+
{config.fields && config.fields.map((field, index) => {
|
|
265
|
+
const fieldValue = newAssociation[field.id] || '';
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<div key={field.id} className={styles.formRow}>
|
|
269
|
+
<div className={styles.formField}>
|
|
270
|
+
<label>
|
|
271
|
+
{field.label}{field.required && ' *'}
|
|
272
|
+
</label>
|
|
273
|
+
|
|
274
|
+
{field.type === 'multi-select' && (
|
|
275
|
+
<MultiSelect
|
|
276
|
+
settings={{ id: field.id }}
|
|
277
|
+
multi={field.multi || false}
|
|
278
|
+
onChange={(value) => setNewAssociation(prev => ({ ...prev, [field.id]: value }))}
|
|
279
|
+
inputValue={fieldValue}
|
|
280
|
+
options={availableOptions}
|
|
281
|
+
placeholder={field.placeholder || `Select ${field.label}...`}
|
|
282
|
+
/>
|
|
283
|
+
)}
|
|
284
|
+
|
|
285
|
+
{field.type === 'select' && (
|
|
286
|
+
<select
|
|
287
|
+
value={fieldValue}
|
|
288
|
+
onChange={(e) => setNewAssociation(prev => ({
|
|
289
|
+
...prev,
|
|
290
|
+
[field.id]: e.target.value
|
|
291
|
+
}))}
|
|
292
|
+
className={styles.selectField}
|
|
293
|
+
>
|
|
294
|
+
{field.options && field.options.map(option => (
|
|
295
|
+
<option key={option.value || option} value={option.value || option}>
|
|
296
|
+
{option.label || option}
|
|
297
|
+
</option>
|
|
298
|
+
))}
|
|
299
|
+
</select>
|
|
300
|
+
)}
|
|
301
|
+
|
|
302
|
+
{field.type === 'boolean' && (
|
|
303
|
+
<label>
|
|
304
|
+
<input
|
|
305
|
+
type="checkbox"
|
|
306
|
+
checked={fieldValue}
|
|
307
|
+
onChange={(e) => setNewAssociation(prev => ({
|
|
308
|
+
...prev,
|
|
309
|
+
[field.id]: e.target.checked
|
|
310
|
+
}))}
|
|
311
|
+
/>
|
|
312
|
+
{field.checkboxLabel || field.label}
|
|
313
|
+
</label>
|
|
314
|
+
)}
|
|
315
|
+
|
|
316
|
+
{field.type === 'textarea' && (
|
|
317
|
+
<textarea
|
|
318
|
+
value={fieldValue}
|
|
319
|
+
onChange={(e) => setNewAssociation(prev => ({
|
|
320
|
+
...prev,
|
|
321
|
+
[field.id]: e.target.value
|
|
322
|
+
}))}
|
|
323
|
+
placeholder={field.placeholder || ''}
|
|
324
|
+
className={styles.textareaField}
|
|
325
|
+
rows={field.rows || 3}
|
|
326
|
+
/>
|
|
327
|
+
)}
|
|
328
|
+
|
|
329
|
+
{field.type === 'text' && (
|
|
330
|
+
<input
|
|
331
|
+
type="text"
|
|
332
|
+
value={fieldValue}
|
|
333
|
+
onChange={(e) => setNewAssociation(prev => ({
|
|
334
|
+
...prev,
|
|
335
|
+
[field.id]: e.target.value
|
|
336
|
+
}))}
|
|
337
|
+
placeholder={field.placeholder || ''}
|
|
338
|
+
className={styles.textField}
|
|
339
|
+
/>
|
|
340
|
+
)}
|
|
341
|
+
</div>
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
})}
|
|
345
|
+
|
|
346
|
+
<div className={styles.formActions}>
|
|
347
|
+
<button
|
|
348
|
+
type="button"
|
|
349
|
+
className={styles.associateBtn}
|
|
350
|
+
onClick={handleAssociate}
|
|
351
|
+
disabled={!newAssociation[config.fields?.find(f => f.required)?.id || 'id']}
|
|
352
|
+
>
|
|
353
|
+
{config.labels?.addButton || 'Add Association'}
|
|
354
|
+
</button>
|
|
355
|
+
</div>
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
);
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
export default ClientAssociationManager;
|
|
@@ -42,30 +42,31 @@ import { toast } from 'react-toastify';
|
|
|
42
42
|
import fetchUtil from '../../utils/fetchUtil';
|
|
43
43
|
import { confirmDialog } from '../utils/ConfirmDialog';
|
|
44
44
|
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
AlarmClock,
|
|
46
|
+
RotateCcw,
|
|
47
|
+
RefreshCw,
|
|
48
|
+
Trash2,
|
|
49
49
|
BookOpen,
|
|
50
50
|
Check,
|
|
51
|
-
|
|
51
|
+
CheckCircle,
|
|
52
52
|
Clock,
|
|
53
|
-
|
|
53
|
+
Download as DownloadIcon,
|
|
54
|
+
Upload,
|
|
54
55
|
Copy,
|
|
55
56
|
Edit,
|
|
56
|
-
|
|
57
|
+
Mail,
|
|
57
58
|
File,
|
|
58
59
|
Folder,
|
|
59
60
|
Image,
|
|
60
61
|
Inbox,
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
ExternalLink,
|
|
63
|
+
Lock,
|
|
63
64
|
Network,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} from '
|
|
65
|
+
Award,
|
|
66
|
+
Archive,
|
|
67
|
+
Volume2,
|
|
68
|
+
AlertTriangle,
|
|
69
|
+
} from 'lucide-react';
|
|
69
70
|
import styles from './styles/DataGrid.module.scss';
|
|
70
71
|
|
|
71
72
|
import '@visns-studio/visns-datagrid-enterprise/index.css';
|
|
@@ -1710,7 +1711,7 @@ const DataGrid = forwardRef(
|
|
|
1710
1711
|
let IconComponent = null;
|
|
1711
1712
|
|
|
1712
1713
|
if (icon === 'archive') {
|
|
1713
|
-
IconComponent =
|
|
1714
|
+
IconComponent = Archive;
|
|
1714
1715
|
} else if (icon === 'bookOpen') {
|
|
1715
1716
|
IconComponent = BookOpen;
|
|
1716
1717
|
} else if (icon === 'folder') {
|
|
@@ -1720,7 +1721,7 @@ const DataGrid = forwardRef(
|
|
|
1720
1721
|
} else if (icon === 'network') {
|
|
1721
1722
|
IconComponent = Network;
|
|
1722
1723
|
} else if (icon === 'urgent') {
|
|
1723
|
-
IconComponent =
|
|
1724
|
+
IconComponent = AlertTriangle;
|
|
1724
1725
|
}
|
|
1725
1726
|
|
|
1726
1727
|
if (IconComponent) {
|
|
@@ -2185,15 +2186,15 @@ const DataGrid = forwardRef(
|
|
|
2185
2186
|
if (allow) {
|
|
2186
2187
|
switch (s.id) {
|
|
2187
2188
|
case 'activate':
|
|
2188
|
-
return getIconComponent(
|
|
2189
|
+
return getIconComponent(CheckCircle);
|
|
2189
2190
|
case 'archive':
|
|
2190
|
-
return getIconComponent(
|
|
2191
|
+
return getIconComponent(Archive);
|
|
2191
2192
|
case 'arrowCycle':
|
|
2192
|
-
return getIconComponent(
|
|
2193
|
+
return getIconComponent(RefreshCw);
|
|
2193
2194
|
case 'cloudUpload':
|
|
2194
|
-
return getIconComponent(
|
|
2195
|
+
return getIconComponent(Upload);
|
|
2195
2196
|
case 'oauth2':
|
|
2196
|
-
return getIconComponent(
|
|
2197
|
+
return getIconComponent(Lock);
|
|
2197
2198
|
case 'clone':
|
|
2198
2199
|
return getIconComponent(Copy);
|
|
2199
2200
|
case 'complete':
|
|
@@ -2201,9 +2202,9 @@ const DataGrid = forwardRef(
|
|
|
2201
2202
|
case 'copy':
|
|
2202
2203
|
return getIconComponent(Copy);
|
|
2203
2204
|
case 'delete':
|
|
2204
|
-
return getIconComponent(
|
|
2205
|
+
return getIconComponent(Trash2);
|
|
2205
2206
|
case 'envelope':
|
|
2206
|
-
return getIconComponent(
|
|
2207
|
+
return getIconComponent(Mail);
|
|
2207
2208
|
case 'family':
|
|
2208
2209
|
return getIconComponent(Network);
|
|
2209
2210
|
case 'file':
|
|
@@ -2213,17 +2214,17 @@ const DataGrid = forwardRef(
|
|
|
2213
2214
|
case 'image':
|
|
2214
2215
|
return getIconComponent(Image);
|
|
2215
2216
|
case 'link':
|
|
2216
|
-
return getIconComponent(
|
|
2217
|
+
return getIconComponent(ExternalLink);
|
|
2217
2218
|
case 'primary':
|
|
2218
|
-
return getIconComponent(
|
|
2219
|
+
return getIconComponent(Award);
|
|
2219
2220
|
case 'restore':
|
|
2220
|
-
return getIconComponent(
|
|
2221
|
+
return getIconComponent(RotateCcw);
|
|
2221
2222
|
case 'sound':
|
|
2222
|
-
return getIconComponent(
|
|
2223
|
+
return getIconComponent(Volume2);
|
|
2223
2224
|
case 'ssa':
|
|
2224
2225
|
return getIconComponent(Clock);
|
|
2225
2226
|
case 'undo':
|
|
2226
|
-
return getIconComponent(
|
|
2227
|
+
return getIconComponent(RotateCcw);
|
|
2227
2228
|
case 'update':
|
|
2228
2229
|
return getIconComponent(Edit);
|
|
2229
2230
|
default:
|
|
@@ -3078,6 +3079,7 @@ const DataGrid = forwardRef(
|
|
|
3078
3079
|
{...tableSetting}
|
|
3079
3080
|
columns={gridColumns}
|
|
3080
3081
|
dataSource={dataSource}
|
|
3082
|
+
defaultFilterValue={filterValue}
|
|
3081
3083
|
{...(ajaxSetting && ajaxSetting.groupBy
|
|
3082
3084
|
? {
|
|
3083
3085
|
defaultGroupBy: ajaxSetting.groupBy,
|
|
@@ -3258,13 +3260,13 @@ const DataGrid = forwardRef(
|
|
|
3258
3260
|
case 'clock':
|
|
3259
3261
|
return Clock;
|
|
3260
3262
|
case 'alarm':
|
|
3261
|
-
return
|
|
3263
|
+
return AlarmClock;
|
|
3262
3264
|
case 'check':
|
|
3263
3265
|
return Check;
|
|
3264
3266
|
case 'edit':
|
|
3265
3267
|
return Edit;
|
|
3266
3268
|
case 'envelope':
|
|
3267
|
-
return
|
|
3269
|
+
return Mail;
|
|
3268
3270
|
case 'file':
|
|
3269
3271
|
return File;
|
|
3270
3272
|
case 'image':
|
|
@@ -3272,9 +3274,9 @@ const DataGrid = forwardRef(
|
|
|
3272
3274
|
case 'copy':
|
|
3273
3275
|
return Copy;
|
|
3274
3276
|
case 'cloudUpload':
|
|
3275
|
-
return
|
|
3277
|
+
return Upload;
|
|
3276
3278
|
case 'cloudDownload':
|
|
3277
|
-
return
|
|
3279
|
+
return DownloadIcon;
|
|
3278
3280
|
default:
|
|
3279
3281
|
return Clock; // Default fallback
|
|
3280
3282
|
}
|
|
@@ -15,15 +15,15 @@ import {
|
|
|
15
15
|
Edit,
|
|
16
16
|
ChevronRight,
|
|
17
17
|
Circle,
|
|
18
|
-
|
|
18
|
+
Dot,
|
|
19
19
|
CirclePlus,
|
|
20
|
-
|
|
20
|
+
Download,
|
|
21
21
|
Copy,
|
|
22
22
|
Minus,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from '
|
|
23
|
+
ArrowLeft,
|
|
24
|
+
Trash2,
|
|
25
|
+
X,
|
|
26
|
+
} from 'lucide-react';
|
|
27
27
|
import { toast } from 'react-toastify';
|
|
28
28
|
import styles from './styles/Field.module.scss';
|
|
29
29
|
|
|
@@ -835,7 +835,7 @@ function Field({
|
|
|
835
835
|
);
|
|
836
836
|
}}
|
|
837
837
|
>
|
|
838
|
-
<
|
|
838
|
+
<Trash2
|
|
839
839
|
strokeWidth={2}
|
|
840
840
|
size={20}
|
|
841
841
|
/>
|
|
@@ -903,7 +903,7 @@ function Field({
|
|
|
903
903
|
onFileDownload(inputValue);
|
|
904
904
|
}}
|
|
905
905
|
>
|
|
906
|
-
<
|
|
906
|
+
<Download size={24} />
|
|
907
907
|
</div>
|
|
908
908
|
)}
|
|
909
909
|
</div>
|
|
@@ -2142,7 +2142,7 @@ function Field({
|
|
|
2142
2142
|
className={styles.modal__close}
|
|
2143
2143
|
onClick={() => setCanvasPopupOpen(false)}
|
|
2144
2144
|
>
|
|
2145
|
-
<
|
|
2145
|
+
<X size={24} color="#FFF" />
|
|
2146
2146
|
</button>
|
|
2147
2147
|
</div>
|
|
2148
2148
|
<div
|
|
@@ -2157,7 +2157,7 @@ function Field({
|
|
|
2157
2157
|
}}
|
|
2158
2158
|
className={styles['drawactions--save']}
|
|
2159
2159
|
>
|
|
2160
|
-
<
|
|
2160
|
+
<Download size={16} /> Save
|
|
2161
2161
|
</button>
|
|
2162
2162
|
</li>
|
|
2163
2163
|
<li>
|
|
@@ -2218,7 +2218,7 @@ function Field({
|
|
|
2218
2218
|
onClick={() => sketchRef.current.undo()}
|
|
2219
2219
|
className={styles['drawaction-undo']}
|
|
2220
2220
|
>
|
|
2221
|
-
<
|
|
2221
|
+
<ArrowLeft size={16} /> Undo
|
|
2222
2222
|
</button>
|
|
2223
2223
|
</li>
|
|
2224
2224
|
<li>
|
|
@@ -2228,7 +2228,7 @@ function Field({
|
|
|
2228
2228
|
}
|
|
2229
2229
|
className={styles['drawactions--clear']}
|
|
2230
2230
|
>
|
|
2231
|
-
<
|
|
2231
|
+
<Trash2 size={16} /> Clear
|
|
2232
2232
|
</button>
|
|
2233
2233
|
</li>
|
|
2234
2234
|
</ul>
|
|
@@ -9,7 +9,7 @@ import moment from 'moment';
|
|
|
9
9
|
import parse from 'html-react-parser';
|
|
10
10
|
import _ from 'lodash';
|
|
11
11
|
import ReactDataGrid from '@visns-studio/visns-datagrid-enterprise';
|
|
12
|
-
import {
|
|
12
|
+
import { X } from 'lucide-react';
|
|
13
13
|
import imageCompression from 'browser-image-compression';
|
|
14
14
|
import { confirmDialog } from '../utils/ConfirmDialog';
|
|
15
15
|
|
|
@@ -2231,7 +2231,7 @@ function Form({
|
|
|
2231
2231
|
className={styles.modal__close}
|
|
2232
2232
|
onClick={closeModal}
|
|
2233
2233
|
>
|
|
2234
|
-
<
|
|
2234
|
+
<X strokeWidth={2} size={24} />
|
|
2235
2235
|
</button>
|
|
2236
2236
|
</div>
|
|
2237
2237
|
<div className={styles.modal__content}>
|