@visns-studio/visns-components 5.7.18 → 5.8.0

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
@@ -82,7 +82,7 @@
82
82
  "react-dom": "^17.0.0 || ^18.0.0"
83
83
  },
84
84
  "name": "@visns-studio/visns-components",
85
- "version": "5.7.18",
85
+ "version": "5.8.0",
86
86
  "description": "Various packages to assist in the development of our Custom Applications.",
87
87
  "main": "src/index.js",
88
88
  "files": [
@@ -32,6 +32,7 @@ import {
32
32
  ArrowCounterClockwise,
33
33
  ArrowCycle,
34
34
  Backspace,
35
+ BookOpen,
35
36
  Check,
36
37
  CircleCheck,
37
38
  CircleX,
@@ -537,27 +538,43 @@ const DataGrid = forwardRef(
537
538
  s[obj.id] = obj;
538
539
  });
539
540
  setSelected(s);
541
+ // Update parent component's rowsSelected state
542
+ if (setRowsSelected) {
543
+ setRowsSelected(s);
544
+ }
540
545
  } else if (typeof param.selected === 'object') {
541
546
  const selectedKey = Object.keys(param.selected)[0];
542
547
  const isSelectedAlready =
543
548
  selected.hasOwnProperty(selectedKey);
544
549
 
550
+ let newSelected;
545
551
  if (isSelectedAlready) {
546
- setSelected({});
552
+ newSelected = {};
553
+ setSelected(newSelected);
547
554
  } else {
548
- setSelected((prevSelected) => ({
549
- ...prevSelected,
555
+ newSelected = {
556
+ ...selected,
550
557
  [selectedKey]: param.selected[selectedKey],
551
- }));
558
+ };
559
+ setSelected(newSelected);
560
+ }
561
+
562
+ // Update parent component's rowsSelected state
563
+ if (setRowsSelected) {
564
+ setRowsSelected(newSelected);
552
565
  }
553
566
  }
554
567
  } else {
555
568
  // Handle deselection directly without confirmation
556
569
  setSelected(param.selected);
570
+ // Update parent component's rowsSelected state
571
+ if (setRowsSelected) {
572
+ setRowsSelected(param.selected);
573
+ }
557
574
  }
558
575
  },
559
- [selected]
560
- ); // Including selected in the dependency array
576
+ [selected, setRowsSelected]
577
+ ); // Including selected and setRowsSelected in the dependency array
561
578
 
562
579
  const findUpdatedFilter = (filters, currentValues) => {
563
580
  for (const filter of filters) {
@@ -1442,19 +1459,42 @@ const DataGrid = forwardRef(
1442
1459
  const addIcon = (src, icon, alt, tooltipContent, key) => {
1443
1460
  if (src && src !== '') {
1444
1461
  icons.push(
1445
- <img
1446
- src={`${assetPath}${src}`}
1447
- alt={alt}
1448
- data-tooltip-id="system-tooltip"
1449
- data-tooltip-content={tooltipContent}
1462
+ <div
1450
1463
  key={key}
1451
- />
1464
+ style={{
1465
+ display: 'inline-flex',
1466
+ alignItems: 'center',
1467
+ justifyContent: 'center',
1468
+ backgroundColor:
1469
+ 'var(--light-bg-color, #f5f5f5)',
1470
+ borderRadius: '4px',
1471
+ padding: '4px',
1472
+ width: '22px',
1473
+ height: '22px',
1474
+ boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
1475
+ margin: '0 1px',
1476
+ }}
1477
+ >
1478
+ <img
1479
+ src={`${assetPath}${src}`}
1480
+ alt={alt}
1481
+ data-tooltip-id="system-tooltip"
1482
+ data-tooltip-content={tooltipContent}
1483
+ style={{
1484
+ maxHeight: '16px',
1485
+ maxWidth: '16px',
1486
+ objectFit: 'contain',
1487
+ }}
1488
+ />
1489
+ </div>
1452
1490
  );
1453
1491
  } else {
1454
1492
  let IconComponent = null;
1455
1493
 
1456
1494
  if (icon === 'archive') {
1457
1495
  IconComponent = ShippingBoxV1;
1496
+ } else if (icon === 'bookOpen') {
1497
+ IconComponent = BookOpen;
1458
1498
  } else if (icon === 'folder') {
1459
1499
  IconComponent = Folder;
1460
1500
  } else if (icon === 'inbox') {
@@ -1467,14 +1507,33 @@ const DataGrid = forwardRef(
1467
1507
 
1468
1508
  if (IconComponent) {
1469
1509
  icons.push(
1470
- <IconComponent
1471
- data-tooltip-id="system-tooltip"
1472
- data-tooltip-content={tooltipContent}
1473
- strokeWidth={2}
1474
- size={18}
1475
- className={styles.tdaction}
1510
+ <div
1476
1511
  key={key}
1477
- />
1512
+ style={{
1513
+ display: 'inline-flex',
1514
+ alignItems: 'center',
1515
+ justifyContent: 'center',
1516
+ backgroundColor:
1517
+ 'var(--light-bg-color, #f5f5f5)',
1518
+ borderRadius: '4px',
1519
+ padding: '4px',
1520
+ width: '22px',
1521
+ height: '22px',
1522
+ boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
1523
+ margin: '0 1px',
1524
+ }}
1525
+ >
1526
+ <IconComponent
1527
+ data-tooltip-id="system-tooltip"
1528
+ data-tooltip-content={tooltipContent}
1529
+ strokeWidth={2}
1530
+ size={18}
1531
+ className={styles.tdaction}
1532
+ style={{
1533
+ color: 'var(--primary-color, #4a90e2)',
1534
+ }}
1535
+ />
1536
+ </div>
1478
1537
  );
1479
1538
  }
1480
1539
  }
@@ -1509,7 +1568,30 @@ const DataGrid = forwardRef(
1509
1568
  }
1510
1569
  });
1511
1570
 
1512
- return icons;
1571
+ // Return icons wrapped in a flex container for better layout
1572
+ return (
1573
+ <div
1574
+ style={{
1575
+ display: 'inline-flex', // Changed to inline-flex to keep icons in a single row
1576
+ flexWrap: 'nowrap', // Prevent wrapping
1577
+ alignItems: 'center',
1578
+ justifyContent: 'flex-start',
1579
+ gap: '1px', // Reduced gap since we have margins on the icons
1580
+ padding: '2px 0',
1581
+ minHeight: '24px',
1582
+ maxWidth: '100%',
1583
+ overflow: 'hidden', // Hide overflow if too many icons
1584
+ }}
1585
+ >
1586
+ {icons.length > 0 ? (
1587
+ icons
1588
+ ) : (
1589
+ <span style={{ color: '#999', fontSize: '12px' }}>
1590
+ -
1591
+ </span>
1592
+ )}
1593
+ </div>
1594
+ );
1513
1595
  };
1514
1596
 
1515
1597
  /** Table Hooks */
@@ -3022,6 +3104,287 @@ const DataGrid = forwardRef(
3022
3104
  }
3023
3105
  },
3024
3106
  };
3107
+ case 'stageCounter':
3108
+ return {
3109
+ ...commonProps,
3110
+ name: column.id,
3111
+ sortable: false,
3112
+ render: ({ data }) => {
3113
+ if (
3114
+ data &&
3115
+ column.stageConfig &&
3116
+ column.stageConfig.key
3117
+ ) {
3118
+ // Check if the data has the specified key and it's an array
3119
+ const stageData =
3120
+ data[column.stageConfig.key];
3121
+
3122
+ if (
3123
+ stageData &&
3124
+ Array.isArray(stageData)
3125
+ ) {
3126
+ const stageCount =
3127
+ stageData.length;
3128
+
3129
+ // Create a clickable element if link is provided
3130
+ const handleClick = (e) => {
3131
+ e.stopPropagation();
3132
+ e.preventDefault();
3133
+
3134
+ if (
3135
+ column.link &&
3136
+ column.link.url &&
3137
+ column.link.key
3138
+ ) {
3139
+ navigate(
3140
+ `${
3141
+ column.link.url
3142
+ }${
3143
+ data[
3144
+ column.link
3145
+ .key
3146
+ ]
3147
+ }`
3148
+ );
3149
+ }
3150
+ };
3151
+
3152
+ // Create an array of squares based on the stage data
3153
+ const squares = [];
3154
+ for (
3155
+ let i = 0;
3156
+ i < stageCount;
3157
+ i++
3158
+ ) {
3159
+ // Get the stage item
3160
+ const stageItem =
3161
+ stageData[i];
3162
+
3163
+ // Get the label value from the stage item using stageLabelKey if provided
3164
+ let labelValue = '';
3165
+ if (
3166
+ column.stageConfig
3167
+ .stageLabelKey &&
3168
+ stageItem &&
3169
+ stageItem[
3170
+ column.stageConfig
3171
+ .stageLabelKey
3172
+ ] !== undefined
3173
+ ) {
3174
+ // Get the value from the stage item
3175
+ const rawValue =
3176
+ stageItem[
3177
+ column
3178
+ .stageConfig
3179
+ .stageLabelKey
3180
+ ];
3181
+
3182
+ // If it's an object with a name property, use that
3183
+ if (
3184
+ rawValue &&
3185
+ typeof rawValue ===
3186
+ 'object' &&
3187
+ rawValue.name
3188
+ ) {
3189
+ labelValue =
3190
+ rawValue.name.charAt(
3191
+ 0
3192
+ );
3193
+ }
3194
+ // If it's a string, use the first character
3195
+ else if (
3196
+ typeof rawValue ===
3197
+ 'string' &&
3198
+ rawValue.length > 0
3199
+ ) {
3200
+ labelValue =
3201
+ rawValue.charAt(
3202
+ 0
3203
+ );
3204
+ }
3205
+ // Otherwise use the raw value if it can be converted to string
3206
+ else if (
3207
+ rawValue !== null &&
3208
+ rawValue !==
3209
+ undefined
3210
+ ) {
3211
+ labelValue =
3212
+ String(
3213
+ rawValue
3214
+ ).charAt(0);
3215
+ }
3216
+ }
3217
+ // If no stageLabelKey is provided or no value is found, leave it blank
3218
+
3219
+ // Create tooltip content from the full value if available
3220
+ let tooltipContent = `Stage ${
3221
+ i + 1
3222
+ }`;
3223
+ if (
3224
+ column.stageConfig
3225
+ .stageLabelKey &&
3226
+ stageItem &&
3227
+ stageItem[
3228
+ column.stageConfig
3229
+ .stageLabelKey
3230
+ ]
3231
+ ) {
3232
+ const rawValue =
3233
+ stageItem[
3234
+ column
3235
+ .stageConfig
3236
+ .stageLabelKey
3237
+ ];
3238
+ if (
3239
+ rawValue &&
3240
+ typeof rawValue ===
3241
+ 'object' &&
3242
+ rawValue.name
3243
+ ) {
3244
+ tooltipContent = `${
3245
+ rawValue.name
3246
+ } (Stage ${i + 1})`;
3247
+ } else if (
3248
+ rawValue !== null &&
3249
+ rawValue !==
3250
+ undefined
3251
+ ) {
3252
+ tooltipContent = `Stage ${
3253
+ i + 1
3254
+ })`;
3255
+ }
3256
+ }
3257
+
3258
+ // Determine the background color based on stageColour configuration
3259
+ let backgroundColor =
3260
+ 'var(--primary-color, #4a90e2)';
3261
+
3262
+ if (
3263
+ column.stageConfig
3264
+ .stageColour &&
3265
+ column.stageConfig
3266
+ .stageColour.key &&
3267
+ column.stageConfig
3268
+ .stageColour
3269
+ .options &&
3270
+ stageItem
3271
+ ) {
3272
+ const colourKey =
3273
+ column.stageConfig
3274
+ .stageColour
3275
+ .key;
3276
+ const colourOptions =
3277
+ column.stageConfig
3278
+ .stageColour
3279
+ .options;
3280
+
3281
+ // Get the value for the color key
3282
+ if (
3283
+ stageItem[
3284
+ colourKey
3285
+ ] !== undefined
3286
+ ) {
3287
+ const keyValue =
3288
+ stageItem[
3289
+ colourKey
3290
+ ];
3291
+
3292
+ // Find matching option
3293
+ const matchingOption =
3294
+ colourOptions.find(
3295
+ (
3296
+ option
3297
+ ) => {
3298
+ // Handle both direct value and object with id
3299
+ if (
3300
+ typeof keyValue ===
3301
+ 'object' &&
3302
+ keyValue !==
3303
+ null
3304
+ ) {
3305
+ // Use loose equality (==) to handle type coercion between string and number
3306
+ return (
3307
+ keyValue.id ==
3308
+ option.id
3309
+ );
3310
+ }
3311
+ // Use loose equality (==) to handle type coercion between string and number
3312
+ return (
3313
+ keyValue ==
3314
+ option.id
3315
+ );
3316
+ }
3317
+ );
3318
+
3319
+ // Use the color from the matching option if found
3320
+ if (
3321
+ matchingOption &&
3322
+ matchingOption.colour
3323
+ ) {
3324
+ backgroundColor =
3325
+ matchingOption.colour;
3326
+ }
3327
+ }
3328
+ }
3329
+
3330
+ squares.push(
3331
+ <div
3332
+ key={i}
3333
+ style={{
3334
+ width: '20px',
3335
+ height: '20px',
3336
+ backgroundColor:
3337
+ backgroundColor,
3338
+ borderRadius:
3339
+ '3px',
3340
+ margin: '0 2px',
3341
+ display: 'flex',
3342
+ justifyContent:
3343
+ 'center',
3344
+ alignItems:
3345
+ 'center',
3346
+ color: 'white',
3347
+ fontSize:
3348
+ '11px',
3349
+ fontWeight:
3350
+ 'bold',
3351
+ }}
3352
+ data-tooltip-id="system-tooltip"
3353
+ data-tooltip-content={
3354
+ tooltipContent
3355
+ }
3356
+ >
3357
+ {labelValue}
3358
+ </div>
3359
+ );
3360
+ }
3361
+
3362
+ return (
3363
+ <div
3364
+ onClick={handleClick}
3365
+ style={{
3366
+ display: 'flex',
3367
+ flexWrap: 'wrap',
3368
+ justifyContent:
3369
+ 'center',
3370
+ alignItems:
3371
+ 'center',
3372
+ cursor: column.link
3373
+ ? 'pointer'
3374
+ : 'default',
3375
+ gap: '4px',
3376
+ padding: '2px 0',
3377
+ maxWidth: '100%',
3378
+ }}
3379
+ >
3380
+ {squares}
3381
+ </div>
3382
+ );
3383
+ }
3384
+ }
3385
+ return null;
3386
+ },
3387
+ };
3025
3388
  case 'url':
3026
3389
  return {
3027
3390
  ...commonProps,
@@ -410,6 +410,8 @@ function GenericIndex({
410
410
 
411
411
  const { data, method, message, url } = checkboxUpdateConfig;
412
412
 
413
+ console.info('Selected rows:', rowsSelectedRef.current);
414
+
413
415
  if (!Object.keys(rowsSelectedRef.current).length) {
414
416
  toast.warning(message.warning);
415
417
  return;
@@ -553,6 +555,7 @@ function GenericIndex({
553
555
  setConfig={setConfig}
554
556
  setTableData={setTableData}
555
557
  setTotal={setTotal}
558
+ setRowsSelected={setRowsSelected}
556
559
  style={userProfile?.settings?.style || {}}
557
560
  userProfile={userProfile}
558
561
  />
@@ -570,7 +573,15 @@ function GenericIndex({
570
573
  }
571
574
 
572
575
  return null;
573
- }, [config, subnav, windowHeight, userProfile, setConfig, setTotal]);
576
+ }, [
577
+ config,
578
+ subnav,
579
+ windowHeight,
580
+ userProfile,
581
+ setConfig,
582
+ setTotal,
583
+ setRowsSelected,
584
+ ]);
574
585
 
575
586
  const renderContentBasedOnType = useCallback(() => {
576
587
  switch (config.type) {
@@ -742,6 +753,7 @@ function GenericIndex({
742
753
  <button className={styles.btn} onClick={handleCustomAction}>
743
754
  {getFunctionConfig('customAction').label ||
744
755
  'Custom Action'}
756
+ aa
745
757
  </button>
746
758
  )}
747
759