@solidxai/core-ui 0.1.2 → 0.1.4-beta.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.
Files changed (149) hide show
  1. package/dist/components/auth/SolidInitialLoginOtp.d.ts.map +1 -1
  2. package/dist/components/auth/SolidInitialLoginOtp.js +0 -5
  3. package/dist/components/auth/SolidInitialLoginOtp.js.map +1 -1
  4. package/dist/components/auth/SolidInitialLoginOtp.tsx +0 -5
  5. package/dist/components/auth/SolidLogin.d.ts.map +1 -1
  6. package/dist/components/auth/SolidLogin.js +7 -5
  7. package/dist/components/auth/SolidLogin.js.map +1 -1
  8. package/dist/components/auth/SolidLogin.tsx +10 -8
  9. package/dist/components/common/GeneralSettings.d.ts.map +1 -1
  10. package/dist/components/common/GeneralSettings.js +48 -47
  11. package/dist/components/common/GeneralSettings.js.map +1 -1
  12. package/dist/components/common/GeneralSettings.tsx +41 -10
  13. package/dist/components/core/common/FilterComponent.js.map +1 -1
  14. package/dist/components/core/common/FilterComponent.tsx +1 -1
  15. package/dist/components/core/common/GroupingComponent.d.ts +54 -0
  16. package/dist/components/core/common/GroupingComponent.d.ts.map +1 -0
  17. package/dist/components/core/common/GroupingComponent.js +196 -0
  18. package/dist/components/core/common/GroupingComponent.js.map +1 -0
  19. package/dist/components/core/common/GroupingComponent.tsx +452 -0
  20. package/dist/components/core/common/SolidGlobalSearchElement.d.ts +18 -1
  21. package/dist/components/core/common/SolidGlobalSearchElement.d.ts.map +1 -1
  22. package/dist/components/core/common/SolidGlobalSearchElement.js +197 -74
  23. package/dist/components/core/common/SolidGlobalSearchElement.js.map +1 -1
  24. package/dist/components/core/common/SolidGlobalSearchElement.tsx +276 -40
  25. package/dist/components/core/common/SolidImageViewer.d.ts +10 -0
  26. package/dist/components/core/common/SolidImageViewer.d.ts.map +1 -0
  27. package/dist/components/core/common/SolidImageViewer.js +59 -0
  28. package/dist/components/core/common/SolidImageViewer.js.map +1 -0
  29. package/dist/components/core/common/SolidImageViewer.tsx +84 -0
  30. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.d.ts +19 -0
  31. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.d.ts.map +1 -0
  32. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.js +90 -0
  33. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.js.map +1 -0
  34. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.tsx +59 -0
  35. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.d.ts.map +1 -1
  36. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.js +7 -3
  37. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.js.map +1 -1
  38. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.tsx +45 -40
  39. package/dist/components/core/filter/SolidOneToManyFilterElement.d.ts +2 -0
  40. package/dist/components/core/filter/SolidOneToManyFilterElement.d.ts.map +1 -0
  41. package/dist/components/core/filter/SolidOneToManyFilterElement.js +86 -0
  42. package/dist/components/core/filter/SolidOneToManyFilterElement.js.map +1 -0
  43. package/dist/components/core/filter/SolidOneToManyFilterElement.tsx +62 -0
  44. package/dist/components/core/filter/SolidVarInputsFilterElement.d.ts +1 -0
  45. package/dist/components/core/filter/SolidVarInputsFilterElement.d.ts.map +1 -1
  46. package/dist/components/core/filter/SolidVarInputsFilterElement.js +4 -1
  47. package/dist/components/core/filter/SolidVarInputsFilterElement.js.map +1 -1
  48. package/dist/components/core/filter/SolidVarInputsFilterElement.tsx +10 -0
  49. package/dist/components/core/filter/fields/SolidRelationField.d.ts.map +1 -1
  50. package/dist/components/core/filter/fields/SolidRelationField.js +4 -2
  51. package/dist/components/core/filter/fields/SolidRelationField.js.map +1 -1
  52. package/dist/components/core/filter/fields/SolidRelationField.tsx +4 -2
  53. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.d.ts +4 -0
  54. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.d.ts.map +1 -0
  55. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.js +25 -0
  56. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.js.map +1 -0
  57. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.tsx +60 -0
  58. package/dist/components/core/form/SolidFormFooter.js +4 -4
  59. package/dist/components/core/form/SolidFormFooter.js.map +1 -1
  60. package/dist/components/core/form/SolidFormFooter.tsx +4 -4
  61. package/dist/components/core/form/fields/SolidBooleanField.d.ts.map +1 -1
  62. package/dist/components/core/form/fields/SolidBooleanField.js +11 -8
  63. package/dist/components/core/form/fields/SolidBooleanField.js.map +1 -1
  64. package/dist/components/core/form/fields/SolidBooleanField.tsx +20 -8
  65. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.d.ts.map +1 -1
  66. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.js +26 -21
  67. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.js.map +1 -1
  68. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.tsx +27 -17
  69. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.d.ts +1 -0
  70. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.d.ts.map +1 -1
  71. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.js +51 -0
  72. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.js.map +1 -1
  73. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.ts +51 -0
  74. package/dist/components/core/form/fields/widgets/SolidS3FileViewerWidget.d.ts.map +1 -1
  75. package/dist/components/core/form/fields/widgets/SolidS3FileViewerWidget.js +80 -79
  76. package/dist/components/core/form/fields/widgets/SolidS3FileViewerWidget.js.map +1 -1
  77. package/dist/components/core/form/fields/widgets/SolidS3FileViewerWidget.tsx +92 -85
  78. package/dist/components/core/kanban/SolidKanbanView.js +5 -5
  79. package/dist/components/core/kanban/SolidKanbanView.js.map +1 -1
  80. package/dist/components/core/kanban/SolidKanbanView.tsx +5 -5
  81. package/dist/components/core/list/SolidListView.d.ts +12 -7
  82. package/dist/components/core/list/SolidListView.d.ts.map +1 -1
  83. package/dist/components/core/list/SolidListView.js +143 -153
  84. package/dist/components/core/list/SolidListView.js.map +1 -1
  85. package/dist/components/core/list/SolidListView.tsx +89 -94
  86. package/dist/components/core/list/columns/SolidMediaMultipleColumn.d.ts.map +1 -1
  87. package/dist/components/core/list/columns/SolidMediaMultipleColumn.js +16 -17
  88. package/dist/components/core/list/columns/SolidMediaMultipleColumn.js.map +1 -1
  89. package/dist/components/core/list/columns/SolidMediaMultipleColumn.tsx +46 -44
  90. package/dist/components/core/list/columns/SolidMediaSingleColumn.d.ts.map +1 -1
  91. package/dist/components/core/list/columns/SolidMediaSingleColumn.js +6 -4
  92. package/dist/components/core/list/columns/SolidMediaSingleColumn.js.map +1 -1
  93. package/dist/components/core/list/columns/SolidMediaSingleColumn.tsx +7 -5
  94. package/dist/components/core/list/listViewRegistry.js.map +1 -1
  95. package/dist/components/core/list/listViewRegistry.ts +1 -2
  96. package/dist/components/core/tree/SolidTreeView.d.ts +38 -0
  97. package/dist/components/core/tree/SolidTreeView.d.ts.map +1 -0
  98. package/dist/components/core/tree/SolidTreeView.js +1170 -0
  99. package/dist/components/core/tree/SolidTreeView.js.map +1 -0
  100. package/dist/components/core/tree/SolidTreeView.tsx +1603 -0
  101. package/dist/components/core/tree/treeViewRegistry.d.ts +7 -0
  102. package/dist/components/core/tree/treeViewRegistry.d.ts.map +1 -0
  103. package/dist/components/core/tree/treeViewRegistry.js +17 -0
  104. package/dist/components/core/tree/treeViewRegistry.js.map +1 -0
  105. package/dist/components/core/tree/treeViewRegistry.ts +23 -0
  106. package/dist/components/core/users/CreateUser.d.ts.map +1 -1
  107. package/dist/components/core/users/CreateUser.js +19 -6
  108. package/dist/components/core/users/CreateUser.js.map +1 -1
  109. package/dist/components/core/users/CreateUser.tsx +39 -0
  110. package/dist/helpers/fetchS3Url.d.ts +19 -0
  111. package/dist/helpers/fetchS3Url.d.ts.map +1 -0
  112. package/dist/helpers/fetchS3Url.js +60 -0
  113. package/dist/helpers/fetchS3Url.js.map +1 -0
  114. package/dist/helpers/fetchS3Url.ts +33 -0
  115. package/dist/helpers/helpers.d.ts +2 -0
  116. package/dist/helpers/helpers.d.ts.map +1 -1
  117. package/dist/helpers/helpers.js +3 -1
  118. package/dist/helpers/helpers.js.map +1 -1
  119. package/dist/helpers/helpers.ts +4 -1
  120. package/dist/helpers/registry.d.ts.map +1 -1
  121. package/dist/helpers/registry.js +2 -0
  122. package/dist/helpers/registry.js.map +1 -1
  123. package/dist/helpers/registry.ts +3 -1
  124. package/dist/index.d.ts +9 -2
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +6 -1
  127. package/dist/index.js.map +1 -1
  128. package/dist/index.ts +14 -2
  129. package/dist/resources/globals.css +18 -4
  130. package/dist/routes/pages/admin/core/ListPage.d.ts.map +1 -1
  131. package/dist/routes/pages/admin/core/ListPage.js +8 -3
  132. package/dist/routes/pages/admin/core/ListPage.js.map +1 -1
  133. package/dist/routes/pages/admin/core/ListPage.tsx +11 -3
  134. package/dist/routes/pages/admin/core/TreePage.d.ts +2 -0
  135. package/dist/routes/pages/admin/core/TreePage.d.ts.map +1 -0
  136. package/dist/routes/pages/admin/core/TreePage.js +37 -0
  137. package/dist/routes/pages/admin/core/TreePage.js.map +1 -0
  138. package/dist/routes/pages/admin/core/TreePage.tsx +30 -0
  139. package/dist/routes/solidRoutes.d.ts.map +1 -1
  140. package/dist/routes/solidRoutes.js +2 -0
  141. package/dist/routes/solidRoutes.js.map +1 -1
  142. package/dist/routes/solidRoutes.tsx +3 -1
  143. package/dist/routes/types.d.ts +1 -1
  144. package/dist/routes/types.d.ts.map +1 -1
  145. package/dist/routes/types.js.map +1 -1
  146. package/dist/routes/types.ts +1 -0
  147. package/dist/types/index.d.ts +8 -2
  148. package/dist/types/solid-core.d.ts +40 -0
  149. package/package.json +1 -1
@@ -6,7 +6,7 @@ import { Divider } from "primereact/divider";
6
6
  import { usePathname } from "../../../hooks/usePathname";
7
7
  import { useRouter } from "../../../hooks/useRouter";
8
8
  import { useSearchParams } from "../../../hooks/useSearchParams";
9
- import { queryStringToQueryObject } from "../list/SolidListView";
9
+ import { getFilterObjectFromLocalStorage } from "../list/SolidListView";
10
10
  import { InputText } from "primereact/inputtext";
11
11
  import { createSolidEntityApi } from "../../../redux/api/solidEntityApi";
12
12
  import qs from "qs";
@@ -14,6 +14,8 @@ import { SolidSaveCustomFilterForm } from "./SolidSaveCustomFilterForm";
14
14
  import { ERROR_MESSAGES } from "../../../constants/error-messages";
15
15
  import { hydrateRelationRules } from "../../../helpers/hydrateRelationRules";
16
16
  import { useSession } from '../../../hooks/useSession'
17
+ import GroupingComponent, { AggregationRule, GroupingRule, DateGroupingFormat } from "./GroupingComponent";
18
+
17
19
 
18
20
  const getRandomInt = (min: number, max: number) => {
19
21
  return Math.floor(Math.random() * (max - min + 1)) + min;
@@ -25,6 +27,24 @@ interface PredefinedSearch {
25
27
  filters: Record<string, any>;
26
28
  }
27
29
 
30
+ export type SearchableField = {
31
+ fieldName: string;
32
+ displayName: string;
33
+ searchField: string;
34
+ matchMode: string;
35
+ }
36
+
37
+ export type GroupableField = {
38
+ fieldName: string;
39
+ displayName: string;
40
+ searchField: string;
41
+ matchMode: string;
42
+ type: string;
43
+ ormType: string;
44
+ relationType: string;
45
+ computedFieldValueType: string;
46
+ }
47
+
28
48
  const extractFields = (nodes: any[] = []): any[] => {
29
49
  const result: any[] = [];
30
50
 
@@ -354,7 +374,7 @@ export const mergeSearchAndCustomFilters = (transformedFilter: any, newFilter: a
354
374
  }
355
375
 
356
376
 
357
- export const mergeAllDiffFilters = (customFilter: any, searchFilter: any, savedFilter: any, preDefinedFilter?: any) => {
377
+ export const mergeAllDiffFilters = (customFilter: any, searchFilter: any, savedFilter: any, preDefinedFilter?: any, groupingRules?: GroupingRule[], aggregationRules?: AggregationRule[]) => {
358
378
  const filters: any = {};
359
379
 
360
380
  // Add only non-null filters
@@ -370,6 +390,12 @@ export const mergeAllDiffFilters = (customFilter: any, searchFilter: any, savedF
370
390
  if (preDefinedFilter && Object.keys(preDefinedFilter).length > 0) {
371
391
  filters["predefined_search_predicate"] = preDefinedFilter;
372
392
  }
393
+ if (groupingRules && Object.keys(groupingRules).length > 0) {
394
+ filters["grouping_rules"] = groupingRules;
395
+ }
396
+ if (aggregationRules && Object.keys(aggregationRules).length > 0) {
397
+ filters["aggregation_rules"] = aggregationRules;
398
+ }
373
399
  // Return the combined filters object
374
400
  return filters;
375
401
  }
@@ -378,8 +404,14 @@ const SavedFilterList = ({ savedfilter, activeSavedFilter, applySavedFilter, ope
378
404
  return (
379
405
  <div className="flex align-items-center justify-content-between gap-2">
380
406
  <div>
381
- <Button text size="small" className="text-base py-1 w-full" severity={Number(activeSavedFilter) == savedfilter.id ? "secondary" : "contrast"} onClick={() => applySavedFilter(savedfilter)}>{savedfilter.name}</Button>
382
- {savedfilter?.description && <p className="text-xs pl-3">{savedfilter?.description}</p>}
407
+ <Button text
408
+ size="small"
409
+ className="text-base py-1 w-full"
410
+ severity={Number(activeSavedFilter) == savedfilter.id ? "secondary" : "contrast"}
411
+ onClick={() => applySavedFilter(savedfilter)}
412
+ tooltip={savedfilter?.description}>{savedfilter.name}
413
+ </Button>
414
+ {/* {savedfilter?.description && <p className="text-xs pl-3">{savedfilter?.description}</p>} */}
383
415
  </div>
384
416
  <div className="flex align-items-center gap-2">
385
417
  <Button
@@ -422,11 +454,64 @@ const replacePlaceholders = (obj: any, searchValue: string): any => {
422
454
  return obj;
423
455
  };
424
456
 
457
+
458
+ const extractChips = (node: any): any[] => {
459
+ if (!node) return [];
460
+
461
+ // If node has $and
462
+ if (node.$and && Array.isArray(node.$and)) {
463
+ return node.$and.flatMap(extractChips);
464
+ }
465
+
466
+ // If node has $or
467
+ if (node.$or && Array.isArray(node.$or)) {
468
+ return node.$or.flatMap(extractChips);
469
+ }
470
+
471
+ // Leaf condition
472
+ const field = Object.keys(node)[0];
473
+ const operatorObj = node[field];
474
+
475
+ // ✅ Normal case
476
+ if (operatorObj?.$containsi) {
477
+ return [{
478
+ columnName: field,
479
+ value: operatorObj.$containsi,
480
+ columnDisplayName: field.charAt(0).toUpperCase() + field.slice(1),
481
+ searchField: field,
482
+ matchMode: "$containsi"
483
+ }];
484
+ }
485
+ // ✅ Nested case (like city.name)
486
+ else if (typeof operatorObj === "object") {
487
+ const nestedField = Object.keys(operatorObj)[0];
488
+ const nestedOperatorObj = operatorObj[nestedField];
489
+
490
+ const operatorKey = nestedOperatorObj
491
+ ? Object.keys(nestedOperatorObj).find(k => k.startsWith("$"))
492
+ : null;
493
+
494
+ if (operatorKey) {
495
+ return [{
496
+ columnName: field,
497
+ value: nestedOperatorObj[operatorKey],
498
+ columnDisplayName: field.charAt(0).toUpperCase() + field.slice(1),
499
+ searchField: `${field}.${nestedField}`,
500
+ matchMode: operatorKey
501
+ }];
502
+ }
503
+ }
504
+
505
+ return [];
506
+ };
507
+
508
+
509
+
425
510
  type RelationCache = Map<string, { label: string; value: number }>;
426
511
 
427
512
 
428
513
 
429
- export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCustomFilter, showSaveFilterPopup, setShowSaveFilterPopup, filterPredicates }: any, ref) => {
514
+ export const SolidGlobalSearchElement = forwardRef(({ viewData, viewType, handleApplyCustomFilter, showSaveFilterPopup, setShowSaveFilterPopup, filterPredicates }: any, ref) => {
430
515
  const defaultState: FilterRule[] = [
431
516
  {
432
517
  id: 1,
@@ -455,6 +540,20 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
455
540
  ]
456
541
  }
457
542
  ];
543
+
544
+ const defaultAggregationRules: AggregationRule[] = [
545
+ {
546
+ id: 1,
547
+ operator: "count",
548
+ fieldName: "id",
549
+ locked: true
550
+ }
551
+ ];
552
+
553
+ const defaultGroupingRules: GroupingRule[] = [
554
+ { id: 1, fieldName: null, dateGrouping: null }
555
+ ];
556
+
458
557
  const [initialState, setInitialState] = useState(defaultState);
459
558
  const pathname = usePathname();
460
559
 
@@ -473,6 +572,10 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
473
572
 
474
573
  const [fields, setFields] = useState<any[]>([]);
475
574
  const [searchableFields, setSearchableFields] = useState<any[]>([]);
575
+ const [groupableFields, setGroupableFields] = useState<GroupableField[]>([]);
576
+
577
+ const [groupingRules, setGroupingRules] = useState<GroupingRule[]>(defaultGroupingRules);
578
+ const [aggregationRules, setAggregationRules] = useState<AggregationRule[]>(defaultAggregationRules);
476
579
 
477
580
  // used to show the list of predefined searches
478
581
  const [predefinedSearches, setPredefinedSearches] = useState<PredefinedSearch[]>([]);
@@ -480,6 +583,10 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
480
583
  // used to open / close the custom fitler popup
481
584
  const [showGlobalSearchElement, setShowGlobalSearchElement] = useState<boolean>(false);
482
585
 
586
+ // used to open / close the group fitler popup
587
+ const [showGroupFilterElement, setShowGroupFilterElement] = useState<boolean>(false);
588
+
589
+
483
590
  // searchChips maintain the ui to display searched query
484
591
  // searchFilter maintain the transformed filter of the searched query
485
592
  const [searchChips, setSearchChips] = useState<{ columnName?: string; value: string }[]>([]);
@@ -613,7 +720,7 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
613
720
 
614
721
  if (activeSavedFilter && savedFilters.length === 0) return;
615
722
 
616
- const queryObject = queryStringToQueryObject();
723
+ const queryObject = getFilterObjectFromLocalStorage();
617
724
  // const savedQuery = parsedSearchParams?.get("savedQuery");
618
725
  if (activeSavedFilter) {
619
726
  const currentSavedFilterId = Number(activeSavedFilter);
@@ -638,16 +745,19 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
638
745
  }
639
746
  if (searchChips) {
640
747
  setSearchFilter(searchChips);
641
- const formattedChips = searchChips?.$and.map((chip: any, key: any) => {
642
- const chipKey = Object.keys(chip)[0]; // Get the key, e.g., "displayName"
643
- const chipValue = chip[chipKey]?.$containsi; // Get the value of "$containsi"
644
- const chipdata = {
645
- columnName: chipKey,
646
- value: chipValue
647
- };
648
- return chipdata
649
- }
650
- );
748
+ // const formattedChips = searchChips?.$and.map((chip: any, key: any) => {
749
+ // const chipKey = Object.keys(chip)[0]; // Get the key, e.g., "displayName"
750
+ // const chipValue = chip[chipKey]?.$containsi; // Get the value of "$containsi"
751
+ // const chipdata = {
752
+ // columnName: chipKey,
753
+ // value: chipValue
754
+ // };
755
+ // return chipdata
756
+ // }
757
+ // );
758
+ // setSearchChips(formattedChips);
759
+
760
+ const formattedChips = extractChips(searchChips);
651
761
  setSearchChips(formattedChips);
652
762
 
653
763
  }
@@ -657,6 +767,31 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
657
767
  const hydratedRules = await hydrateRelationRules([rules], viewData);
658
768
  setFilterRules(hydratedRules);
659
769
  }
770
+ const hasGroupingRules = (queryObject?.grouping_rules?.some((rule: any) => rule.fieldName !== null));
771
+
772
+ if (hasGroupingRules) {
773
+ setGroupingRules(queryObject?.grouping_rules);
774
+ } else {
775
+ // If no grouping rules in localStorage check layout
776
+ const layoutGroupBy = viewData?.data?.solidView?.layout?.attrs?.groupBy;
777
+
778
+ if (Array.isArray(layoutGroupBy) && layoutGroupBy.length > 0) {
779
+ const initialGroupingRules: GroupingRule[] = layoutGroupBy.map((groupStr: string, index: number) => {
780
+ const [fieldName, dateGrouping] = groupStr.split(":");
781
+ return {
782
+ id: Date.now() + index,
783
+ fieldName: fieldName || null,
784
+ dateGrouping: (dateGrouping as DateGroupingFormat) || null
785
+ };
786
+ });
787
+ setGroupingRules(initialGroupingRules);
788
+ }
789
+ }
790
+
791
+ if (queryObject?.aggregation_rules && queryObject?.aggregation_rules !== aggregationRules) {
792
+ setAggregationRules(queryObject?.aggregation_rules);
793
+ }
794
+
660
795
 
661
796
  setRefreshKey((prev) => prev + 1)
662
797
  setHasSearched(true);
@@ -680,17 +815,20 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
680
815
  }
681
816
  if (filterPredicates?.search_predicate && filterPredicates?.search_predicate !== searchFilter) {
682
817
  setSearchFilter(filterPredicates?.search_predicate);
683
- const formattedChips = filterPredicates.search_predicate?.$and.map((chip: any, key: any) => {
684
- const chipKey = Object.keys(chip)[0]; // Get the key, e.g., "displayName"
685
- const chipValue = chip[chipKey]?.$containsi; // Get the value of "$containsi"
686
- const chipdata = {
687
- columnName: chipKey,
688
- value: chipValue
689
- };
690
- return chipdata
691
- }
692
- );
818
+ // const formattedChips = filterPredicates.search_predicate?.$and.map((chip: any, key: any) => {
819
+ // const chipKey = Object.keys(chip)[0]; // Get the key, e.g., "displayName"
820
+ // const chipValue = chip[chipKey]?.$containsi; // Get the value of "$containsi"
821
+ // const chipdata = {
822
+ // columnName: chipKey,
823
+ // value: chipValue
824
+ // };
825
+ // return chipdata
826
+ // }
827
+ // );
828
+ // setSearchChips(formattedChips);
829
+ const formattedChips = extractChips(filterPredicates.search_predicate);
693
830
  setSearchChips(formattedChips);
831
+
694
832
  }
695
833
  }
696
834
  }
@@ -728,6 +866,7 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
728
866
  matchMode: viewFieldElement?.attrs?.searchMatchMode,
729
867
  searchField: viewFieldElement?.attrs?.searchField ?? null,
730
868
  isSearchable: viewFieldElement?.attrs?.isSearchable ?? false,
869
+ relationType: value?.relationType ?? null,
731
870
  };
732
871
  });
733
872
 
@@ -753,8 +892,30 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
753
892
  }
754
893
  });
755
894
 
756
- // console.log("searchableFieldsList", searchableFieldsList);
757
-
895
+ const groupableFieldsList = fieldsList.filter((field: any) => {
896
+ switch (field.type) {
897
+ case "relation":
898
+ // Only include relation if searchField is present
899
+ if (field.relationType === "many-to-one")
900
+ return true;
901
+ return false;
902
+ case "longText":
903
+ case "shortText":
904
+ case "selectionStatic":
905
+ case "selectionDynamic":
906
+ case "int":
907
+ case "float":
908
+ case "boolean":
909
+ case "date":
910
+ case "datetime":
911
+ return true;
912
+ // case "selectionStatic":
913
+ case "computed":
914
+ return field.ormType === "varchar";
915
+ default:
916
+ return false;
917
+ }
918
+ });
758
919
 
759
920
  // Optionally map to a minimal structure if needed for UI
760
921
  let finalSearchableFieldsList: any = searchableFieldsList.map((field: any) => ({
@@ -764,10 +925,21 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
764
925
  matchMode: field.matchMode
765
926
  }));
766
927
 
767
- // console.log("finalSearchableFieldsList", finalSearchableFieldsList);
768
-
769
928
  setSearchableFields(finalSearchableFieldsList);
770
929
 
930
+ let finalGroupableFieldsList: any = groupableFieldsList.map((field: any) => ({
931
+ fieldName: field.value,
932
+ displayName: field.name,
933
+ searchField: field.searchField ?? "",
934
+ matchMode: field.matchMode,
935
+ type: field.type,
936
+ ormType: field.ormType,
937
+ relationType: field.relationType,
938
+ computedFieldValueType: field.computedFieldValueType
939
+ }));
940
+
941
+ setGroupableFields(finalGroupableFieldsList)
942
+
771
943
  const predefinedSearchesList = viewData?.data?.solidView?.layout?.attrs?.predefinedSearches || [];
772
944
  setPredefinedSearches(predefinedSearchesList);
773
945
  }
@@ -859,10 +1031,16 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
859
1031
 
860
1032
  }
861
1033
 
1034
+ const applyGrouping = (groupingRules: GroupingRule[], aggregationRules: AggregationRule[]) => {
1035
+ setHasSearched(true)
1036
+ setShowGroupFilterElement(false);
1037
+ setGroupingRules(groupingRules);
1038
+ setAggregationRules(aggregationRules);
1039
+ setRefreshKey((prev) => prev + 1)
1040
+ }
1041
+
862
1042
  useEffect(() => {
863
1043
  if (refreshKey > 0 && hasSearched) {
864
- console.log("refres", refreshKey);
865
- console.log("hasSearched", hasSearched);
866
1044
 
867
1045
  const formattedChips = {
868
1046
  $and: searchChips.map((chip: any) => ({
@@ -881,7 +1059,7 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
881
1059
  const finalPredefinedFilter = predefinedSearchBaseFilter
882
1060
 
883
1061
  const finalCustomFilter = customFilter
884
- const finalFilter = mergeAllDiffFilters(finalCustomFilter, finalSearchFilter, finalSavedFilter, finalPredefinedFilter)
1062
+ const finalFilter = mergeAllDiffFilters(finalCustomFilter, finalSearchFilter, finalSavedFilter, finalPredefinedFilter, groupingRules, aggregationRules)
885
1063
  handleApplyCustomFilter(finalFilter, true);
886
1064
  setHasSearched(false)
887
1065
  // }
@@ -943,8 +1121,8 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
943
1121
  } else {
944
1122
  console.error(ERROR_MESSAGES.SAVE_FILTER_UNDEFINED_NULL);
945
1123
  }
946
-
947
1124
  }
1125
+
948
1126
  const deleteSavedFilter = async () => {
949
1127
  // delte the saved filter with id
950
1128
  await deleteEntity(savedFilterTobeDeleted);
@@ -1107,7 +1285,6 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1107
1285
  }
1108
1286
  }
1109
1287
 
1110
-
1111
1288
  const SavedFiltersChip = () => {
1112
1289
 
1113
1290
  return (
@@ -1149,6 +1326,40 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1149
1326
  )
1150
1327
  };
1151
1328
 
1329
+ const removeGrouping = () => {
1330
+ setGroupingRules(defaultGroupingRules);
1331
+ setAggregationRules(defaultAggregationRules);
1332
+ setHasSearched(true);
1333
+ setRefreshKey((prev) => prev + 1)
1334
+ }
1335
+
1336
+ const GroupingChip = () => {
1337
+ return (
1338
+ <li className="solid-global-search-chip">
1339
+ <div className="flex align-items-center gap-2">
1340
+ <div className="flex align-items-center gap-2">
1341
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"
1342
+
1343
+ onClick={() => setShowGroupFilterElement(true)}
1344
+ >
1345
+ <rect width="20" height="20" rx="4" fill="#722ED1" />
1346
+ <path d="M8.66667 15V13.3333H11.3333V15H8.66667ZM6 10.8333V9.16667H14V10.8333H6ZM4 6.66667V5H16V6.66667H4Z"
1347
+ fill="white" />
1348
+ </svg>
1349
+ <span><strong>{groupingRules.length}</strong> Grouping rules applied</span>
1350
+ </div>
1351
+
1352
+ {/* button to clear filter */}
1353
+ <a onClick={removeGrouping}
1354
+ style={{ cursor: "pointer" }}
1355
+ >
1356
+ <i className="pi pi-times ml-1">
1357
+ </i></a>
1358
+ </div>
1359
+ </li>
1360
+ )
1361
+ };
1362
+
1152
1363
 
1153
1364
 
1154
1365
 
@@ -1249,7 +1460,7 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1249
1460
  }
1250
1461
 
1251
1462
  try {
1252
- // Replace {{search}} placeholders with actual search value
1463
+ // Replace {{ search }} placeholders with actual search value
1253
1464
  const processedFilter = replacePlaceholders(predefinedSearch.filters, inputValue.trim());
1254
1465
 
1255
1466
  // Clear all existing filters and searches
@@ -1320,6 +1531,7 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1320
1531
  {currentSavedFilterData && <SavedFiltersChip />}
1321
1532
  {predefinedSearchChip && <PredefinedSearchChip />}
1322
1533
  {customFilter && <CustomChip />}
1534
+ {groupingRules.length > 0 && groupingRules.some(r => r.fieldName !== null) && <GroupingChip />}
1323
1535
  <SearchChip />
1324
1536
  <li ref={chipsRef}>
1325
1537
  <div className="relative solid-global-search-element-wrapper">
@@ -1446,8 +1658,11 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1446
1658
  <Divider className="m-0" />
1447
1659
  </>
1448
1660
  }
1449
- <div className="px-2 py-1">
1661
+ <div className="px-2 py-1 flex justify-content-between">
1450
1662
  <Button text size="small" label="Custom Filter" iconPos="left" icon='pi pi-plus' onClick={() => setShowGlobalSearchElement(true)} className="font-bold" />
1663
+ {viewType === "tree" &&
1664
+ <Button text size="small" label="Grouping" iconPos="left" icon='pi pi-plus' onClick={() => setShowGroupFilterElement(true)} className="font-bold" />
1665
+ }
1451
1666
  </div>
1452
1667
  </div>
1453
1668
  )
@@ -1458,19 +1673,40 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1458
1673
  <Button icon="pi pi-times" rounded text aria-label="Cancel" type="reset" size="small" onClick={() => setShowGlobalSearchElement(false)} />
1459
1674
  </div>
1460
1675
  <Divider className="m-0" />
1461
- <div className="p-3 lg:p-4">
1676
+ <div className="p-2 lg:p-2">
1462
1677
  {fields.length > 0 &&
1463
1678
  <FilterComponent viewData={viewData} fields={fields} filterRules={filterRules} setFilterRules={setFilterRules} transformFilterRules={transformCustomFilterRules} closeDialog={() => setShowGlobalSearchElement(false)}></FilterComponent>
1464
1679
  }
1465
1680
  </div>
1466
1681
  </Dialog>
1682
+ <Dialog header={false} className="solid-global-search-filter" showHeader={false} visible={showGroupFilterElement} style={{ width: '20vw' }} breakpoints={{ '1024px': '75vw', '991px': '90vw', '767px': '94w', '250px': '96vw' }} onHide={() => { if (!showGroupFilterElement) return; setShowGroupFilterElement(false); }}>
1683
+ <div className="flex align-items-center justify-content-between px-3">
1684
+ <h5 className="solid-custom-title m-0"></h5>
1685
+ <Button icon="pi pi-times" rounded text aria-label="Cancel" type="reset" size="small" onClick={() => setShowGroupFilterElement(false)} />
1686
+ </div>
1687
+ <Divider className="m-0" />
1688
+ <div className="p-2 lg:p-2">
1689
+ {groupableFields.length > 0 &&
1690
+ <GroupingComponent
1691
+ viewData={viewData}
1692
+ fields={groupableFields}
1693
+ groupingRules={groupingRules}
1694
+ setGroupingRules={setGroupingRules}
1695
+ aggregationRules={aggregationRules}
1696
+ setAggregationRules={setAggregationRules}
1697
+ applyGrouping={applyGrouping}
1698
+ closeDialog={() => setShowGroupFilterElement(false)}
1699
+ ></GroupingComponent>
1700
+ }
1701
+ </div>
1702
+ </Dialog >
1467
1703
  <Dialog header={false} className="solid-global-search-filter" showHeader={false} visible={showSavedFilterComponent} style={{ width: '65vw' }} breakpoints={{ '1024px': '75vw', '991px': '90vw', '767px': '94w', '250px': '96vw' }} onHide={() => { if (!showSavedFilterComponent) return; setShowSavedFilterComponent(false); }}>
1468
1704
  <div className="flex align-items-center justify-content-between px-3">
1469
1705
  <h5 className="solid-custom-title m-0">Saved Filter</h5>
1470
1706
  <Button icon="pi pi-times" rounded text aria-label="Cancel" type="reset" size="small" onClick={() => setShowSavedFilterComponent(false)} />
1471
1707
  </div>
1472
1708
  <Divider className="m-0" />
1473
- <div className="p-3 lg:p-4">
1709
+ <div className="p-2 lg:p-2">
1474
1710
  {fields.length > 0 &&
1475
1711
  <FilterComponent viewData={viewData} fields={fields} filterRules={currentSavedFilterRules} setFilterRules={setCurrentSavedFilterRules} transformFilterRules={transformSavedFilterRules} closeDialog={() => setShowSavedFilterComponent(false)}></FilterComponent>
1476
1712
  }
@@ -1495,7 +1731,7 @@ export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCusto
1495
1731
  >
1496
1732
  <p>Are you sure you want to delete the {currentSavedFilterData?.name} saved query?</p>
1497
1733
  </Dialog>
1498
- </div>
1734
+ </div >
1499
1735
  {/* <div>
1500
1736
  <Button
1501
1737
  icon="pi pi-save"
@@ -0,0 +1,10 @@
1
+ import Viewer from "viewerjs";
2
+ import "viewerjs/dist/viewer.css";
3
+ export interface SolidImageViewerProps {
4
+ images: string[];
5
+ open: boolean;
6
+ onClose: () => void;
7
+ viewerOptions?: Viewer.Options;
8
+ }
9
+ export declare const SolidImageViewer: ({ images, open, onClose, viewerOptions, }: SolidImageViewerProps) => import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=SolidImageViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SolidImageViewer.d.ts","sourceRoot":"","sources":["../../../../src/components/core/common/SolidImageViewer.tsx"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,0BAA0B,CAAC;AAElC,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;CAClC;AAED,eAAO,MAAM,gBAAgB,8CAK1B,qBAAqB,4CAmEvB,CAAC"}
@@ -0,0 +1,59 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { useEffect, useRef } from "react";
14
+ import Viewer from "viewerjs";
15
+ import "viewerjs/dist/viewer.css";
16
+ export var SolidImageViewer = function (_a) {
17
+ var images = _a.images, open = _a.open, onClose = _a.onClose, viewerOptions = _a.viewerOptions;
18
+ var containerRef = useRef(null);
19
+ var viewerRef = useRef(null);
20
+ // Initialize viewer
21
+ useEffect(function () {
22
+ if (!containerRef.current || images.length === 0)
23
+ return;
24
+ if (viewerRef.current) {
25
+ viewerRef.current.destroy();
26
+ }
27
+ viewerRef.current = new Viewer(containerRef.current, __assign({ navbar: images.length > 1, title: false, transition: true, movable: true, scalable: true, rotatable: true, zoomable: true, zIndex: 9999, hidden: function () {
28
+ onClose();
29
+ }, toolbar: {
30
+ prev: 1,
31
+ next: 1,
32
+ zoomIn: 1,
33
+ zoomOut: 1,
34
+ rotateLeft: 1,
35
+ rotateRight: 1,
36
+ reset: 1,
37
+ } }, viewerOptions));
38
+ return function () {
39
+ if (viewerRef.current) {
40
+ viewerRef.current.destroy();
41
+ viewerRef.current = null;
42
+ }
43
+ };
44
+ }, [images, open]);
45
+ // Show viewer when open becomes true
46
+ useEffect(function () {
47
+ if (open && viewerRef.current) {
48
+ viewerRef.current.show();
49
+ }
50
+ }, [open]);
51
+ return (_jsx("div", { ref: containerRef, style: {
52
+ position: "absolute",
53
+ visibility: "hidden",
54
+ width: 0,
55
+ height: 0,
56
+ overflow: "hidden",
57
+ }, children: images.map(function (src, index) { return (_jsx("img", { src: src, alt: "preview-".concat(index) }, index)); }) }));
58
+ };
59
+ //# sourceMappingURL=SolidImageViewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SolidImageViewer.js","sourceRoot":"","sources":["../../../../src/components/core/common/SolidImageViewer.tsx"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,0BAA0B,CAAC;AASlC,MAAM,CAAC,IAAM,gBAAgB,GAAG,UAAC,EAKT;QAJpB,MAAM,YAAA,EACN,IAAI,UAAA,EACJ,OAAO,aAAA,EACP,aAAa,mBAAA;IAEb,IAAM,YAAY,GAAG,MAAM,CAAwB,IAAI,CAAC,CAAC;IACzD,IAAM,SAAS,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAE9C,oBAAoB;IACpB,SAAS,CAAC;QACN,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEzD,IAAI,SAAS,CAAC,OAAO,EAAE;YACnB,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;SAC/B;QAED,SAAS,CAAC,OAAO,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,OAAO,aAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EACzB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,IAAI,EACb,QAAQ,EAAE,IAAI,EACd,SAAS,EAAE,IAAI,EACf,QAAQ,EAAE,IAAI,EACd,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE;gBACJ,OAAO,EAAE,CAAC;YACd,CAAC,EACD,OAAO,EAAE;gBACL,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,CAAC;gBACT,OAAO,EAAE,CAAC;gBACV,UAAU,EAAE,CAAC;gBACb,WAAW,EAAE,CAAC;gBACd,KAAK,EAAE,CAAC;aACX,IACE,aAAa,EAClB,CAAC;QAEH,OAAO;YACH,IAAI,SAAS,CAAC,OAAO,EAAE;gBACnB,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC5B,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;aAC5B;QACL,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnB,qCAAqC;IACrC,SAAS,CAAC;QACN,IAAI,IAAI,IAAI,SAAS,CAAC,OAAO,EAAE;YAC3B,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;SAC5B;IACL,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACH,cACI,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE;YACH,QAAQ,EAAE,UAAU;YACpB,UAAU,EAAE,QAAQ;YACpB,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,QAAQ,EAAE,QAAQ;SACrB,YAEA,MAAM,CAAC,GAAG,CAAC,UAAC,GAAG,EAAE,KAAK,IAAK,OAAA,CACxB,cAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,kBAAW,KAAK,CAAE,IAAxC,KAAK,CAAuC,CACzD,EAF2B,CAE3B,CAAC,GACA,CACT,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { useEffect, useRef } from \"react\";\nimport Viewer from \"viewerjs\";\nimport \"viewerjs/dist/viewer.css\";\n\nexport interface SolidImageViewerProps {\n images: string[];\n open: boolean;\n onClose: () => void;\n viewerOptions?: Viewer.Options;\n}\n\nexport const SolidImageViewer = ({\n images,\n open,\n onClose,\n viewerOptions,\n}: SolidImageViewerProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const viewerRef = useRef<Viewer | null>(null);\n\n // Initialize viewer\n useEffect(() => {\n if (!containerRef.current || images.length === 0) return;\n\n if (viewerRef.current) {\n viewerRef.current.destroy();\n }\n\n viewerRef.current = new Viewer(containerRef.current, {\n navbar: images.length > 1, // show navbar only if multiple\n title: false,\n transition: true,\n movable: true,\n scalable: true,\n rotatable: true,\n zoomable: true,\n zIndex: 9999,\n hidden: () => {\n onClose();\n },\n toolbar: {\n prev: 1,\n next: 1,\n zoomIn: 1,\n zoomOut: 1,\n rotateLeft: 1,\n rotateRight: 1,\n reset: 1,\n },\n ...viewerOptions,\n });\n\n return () => {\n if (viewerRef.current) {\n viewerRef.current.destroy();\n viewerRef.current = null;\n }\n };\n }, [images, open]);\n\n // Show viewer when open becomes true\n useEffect(() => {\n if (open && viewerRef.current) {\n viewerRef.current.show();\n }\n }, [open]);\n\n return (\n <div\n ref={containerRef}\n style={{\n position: \"absolute\",\n visibility: \"hidden\",\n width: 0,\n height: 0,\n overflow: \"hidden\",\n }}\n >\n {images.map((src, index) => (\n <img key={index} src={src} alt={`preview-${index}`} />\n ))}\n </div>\n );\n};\n"]}