@gen3/frontend 0.11.32 → 0.11.33

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 (232) hide show
  1. package/dist/cjs/index.js +1507 -120
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.d.ts +1 -1
  4. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.d.ts.map +1 -1
  5. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.js +15 -11
  6. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.js.map +1 -1
  7. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.stories.d.ts +10 -1
  8. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.stories.d.ts.map +1 -1
  9. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.stories.js +4 -0
  10. package/dist/dts/components/AddtoDataLibrary/AddToDataLibrary.stories.js.map +1 -1
  11. package/dist/dts/components/AddtoDataLibrary/types.d.ts +2 -1
  12. package/dist/dts/components/AddtoDataLibrary/types.d.ts.map +1 -1
  13. package/dist/dts/components/Buttons/DownloadButtons/JSONObjectDownloadButton.js +1 -0
  14. package/dist/dts/components/Buttons/DownloadButtons/JSONObjectDownloadButton.js.map +1 -1
  15. package/dist/dts/components/Buttons/DownloadButtons/index.d.ts +2 -0
  16. package/dist/dts/components/Buttons/DownloadButtons/index.d.ts.map +1 -1
  17. package/dist/dts/components/Buttons/DownloadButtons/index.js +2 -0
  18. package/dist/dts/components/Buttons/DownloadButtons/index.js.map +1 -1
  19. package/dist/dts/components/Buttons/FunctionButton.d.ts +32 -0
  20. package/dist/dts/components/Buttons/FunctionButton.d.ts.map +1 -0
  21. package/dist/dts/components/Buttons/FunctionButton.js +99 -0
  22. package/dist/dts/components/Buttons/FunctionButton.js.map +1 -0
  23. package/dist/dts/components/CollapsableSidebar/CollapsableSidebar.stories.d.ts +1 -1
  24. package/dist/dts/components/CollapsableSidebar/CollapsableSidebar.stories.d.ts.map +1 -1
  25. package/dist/dts/components/DataItems/TruncatedStringWithTooltip.stories.d.ts +1 -1
  26. package/dist/dts/components/DataItems/TruncatedStringWithTooltip.stories.d.ts.map +1 -1
  27. package/dist/dts/components/Login/LoginPanel.d.ts.map +1 -1
  28. package/dist/dts/components/Login/LoginPanel.js +10 -4
  29. package/dist/dts/components/Login/LoginPanel.js.map +1 -1
  30. package/dist/dts/components/MessageCards/MessagePage.d.ts +7 -0
  31. package/dist/dts/components/MessageCards/MessagePage.d.ts.map +1 -0
  32. package/dist/dts/components/MessageCards/MessagePage.js +8 -0
  33. package/dist/dts/components/MessageCards/MessagePage.js.map +1 -0
  34. package/dist/dts/components/MessageCards/index.d.ts +2 -1
  35. package/dist/dts/components/MessageCards/index.d.ts.map +1 -1
  36. package/dist/dts/components/MessageCards/index.js +2 -1
  37. package/dist/dts/components/MessageCards/index.js.map +1 -1
  38. package/dist/dts/components/Providers/Gen3Provider.d.ts +12 -12
  39. package/dist/dts/components/SegmentedControl.stories.d.ts +2 -2
  40. package/dist/dts/components/SegmentedControl.stories.d.ts.map +1 -1
  41. package/dist/dts/components/Tables/ColumnOrdering.d.ts +11 -0
  42. package/dist/dts/components/Tables/ColumnOrdering.d.ts.map +1 -0
  43. package/dist/dts/components/Tables/ColumnOrdering.js +92 -0
  44. package/dist/dts/components/Tables/ColumnOrdering.js.map +1 -0
  45. package/dist/dts/components/Tables/ShowingCount.d.ts +12 -0
  46. package/dist/dts/components/Tables/ShowingCount.d.ts.map +1 -0
  47. package/dist/dts/components/Tables/ShowingCount.js +17 -0
  48. package/dist/dts/components/Tables/ShowingCount.js.map +1 -0
  49. package/dist/dts/components/Tables/TableHeader.d.ts +25 -0
  50. package/dist/dts/components/Tables/TableHeader.d.ts.map +1 -0
  51. package/dist/dts/components/Tables/TableHeader.js +84 -0
  52. package/dist/dts/components/Tables/TableHeader.js.map +1 -0
  53. package/dist/dts/components/Tables/TablePagination.d.ts +13 -0
  54. package/dist/dts/components/Tables/TablePagination.d.ts.map +1 -0
  55. package/dist/dts/components/Tables/TablePagination.js +67 -0
  56. package/dist/dts/components/Tables/TablePagination.js.map +1 -0
  57. package/dist/dts/components/Tables/types.d.ts +66 -0
  58. package/dist/dts/components/Tables/types.d.ts.map +1 -1
  59. package/dist/dts/components/Tables/utils.d.ts +16 -0
  60. package/dist/dts/components/Tables/utils.d.ts.map +1 -1
  61. package/dist/dts/components/Tables/utils.js +47 -0
  62. package/dist/dts/components/Tables/utils.js.map +1 -1
  63. package/dist/dts/components/facets/FiltersPanel.d.ts +3 -3
  64. package/dist/dts/components/facets/FiltersPanel.d.ts.map +1 -1
  65. package/dist/dts/components/facets/FiltersPanel.js.map +1 -1
  66. package/dist/dts/components/facets/Panels/DropdownPanel.d.ts +2 -1
  67. package/dist/dts/components/facets/Panels/DropdownPanel.d.ts.map +1 -1
  68. package/dist/dts/components/facets/Panels/DropdownPanel.js +7 -7
  69. package/dist/dts/components/facets/Panels/DropdownPanel.js.map +1 -1
  70. package/dist/dts/components/facets/Panels/types.d.ts +2 -2
  71. package/dist/dts/components/facets/Panels/types.d.ts.map +1 -1
  72. package/dist/dts/features/Analysis/AnalysisCard.stories.d.ts +2 -2
  73. package/dist/dts/features/Analysis/AnalysisCard.stories.d.ts.map +1 -1
  74. package/dist/dts/features/Analysis/AnalysisCardCompact.stories.d.ts +6 -6
  75. package/dist/dts/features/Analysis/AnalysisCardCompact.stories.d.ts.map +1 -1
  76. package/dist/dts/features/Analysis/AnalysisCenterWithSections.stories.d.ts +1 -1
  77. package/dist/dts/features/Analysis/AnalysisCenterWithSections.stories.d.ts.map +1 -1
  78. package/dist/dts/features/Analysis/AnalysisPanel.stories.d.ts +2 -2
  79. package/dist/dts/features/Analysis/AnalysisPanel.stories.d.ts.map +1 -1
  80. package/dist/dts/features/CohortBuilder/CohortPanel.d.ts.map +1 -1
  81. package/dist/dts/features/CohortBuilder/CohortPanel.js +3 -3
  82. package/dist/dts/features/CohortBuilder/CohortPanel.js.map +1 -1
  83. package/dist/dts/features/CohortBuilder/ExplorerTable/AccessCellRenderers.d.ts +3 -0
  84. package/dist/dts/features/CohortBuilder/ExplorerTable/AccessCellRenderers.d.ts.map +1 -0
  85. package/dist/dts/features/CohortBuilder/ExplorerTable/AccessCellRenderers.js +46 -0
  86. package/dist/dts/features/CohortBuilder/ExplorerTable/AccessCellRenderers.js.map +1 -0
  87. package/dist/dts/features/CohortBuilder/ExplorerTable/ArrayCellRenderer.d.ts +1 -2
  88. package/dist/dts/features/CohortBuilder/ExplorerTable/ArrayCellRenderer.d.ts.map +1 -1
  89. package/dist/dts/features/CohortBuilder/ExplorerTable/ArrayCellRenderer.js.map +1 -1
  90. package/dist/dts/features/CohortBuilder/ExplorerTable/CellRenderers.d.ts +1 -3
  91. package/dist/dts/features/CohortBuilder/ExplorerTable/CellRenderers.d.ts.map +1 -1
  92. package/dist/dts/features/CohortBuilder/ExplorerTable/CellRenderers.js +0 -1
  93. package/dist/dts/features/CohortBuilder/ExplorerTable/CellRenderers.js.map +1 -1
  94. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTable.d.ts +1 -1
  95. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTable.d.ts.map +1 -1
  96. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTable.js +43 -13
  97. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTable.js.map +1 -1
  98. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTableCellRenderers.d.ts +1 -3
  99. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTableCellRenderers.d.ts.map +1 -1
  100. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTableCellRenderers.js +64 -0
  101. package/dist/dts/features/CohortBuilder/ExplorerTable/ExplorerTableCellRenderers.js.map +1 -1
  102. package/dist/dts/features/CohortBuilder/ExplorerTable/SubTables/ExpandingSubtable.js +1 -1
  103. package/dist/dts/features/CohortBuilder/ExplorerTable/SubTables/ExpandingSubtable.js.map +1 -1
  104. package/dist/dts/features/CohortBuilder/ExplorerTable/SubTables/SubtableAccordian.d.ts.map +1 -1
  105. package/dist/dts/features/CohortBuilder/ExplorerTable/SubTables/SubtableAccordian.js +1 -1
  106. package/dist/dts/features/CohortBuilder/ExplorerTable/SubTables/SubtableAccordian.js.map +1 -1
  107. package/dist/dts/features/CohortBuilder/ExplorerTable/context.d.ts +5 -0
  108. package/dist/dts/features/CohortBuilder/ExplorerTable/context.d.ts.map +1 -0
  109. package/dist/dts/features/CohortBuilder/ExplorerTable/context.js +5 -0
  110. package/dist/dts/features/CohortBuilder/ExplorerTable/context.js.map +1 -0
  111. package/dist/dts/features/CohortBuilder/ExplorerTable/index.d.ts +3 -2
  112. package/dist/dts/features/CohortBuilder/ExplorerTable/index.d.ts.map +1 -1
  113. package/dist/dts/features/CohortBuilder/ExplorerTable/index.js +3 -1
  114. package/dist/dts/features/CohortBuilder/ExplorerTable/index.js.map +1 -1
  115. package/dist/dts/features/CohortBuilder/ExplorerTable/types.d.ts +12 -2
  116. package/dist/dts/features/CohortBuilder/ExplorerTable/types.d.ts.map +1 -1
  117. package/dist/dts/features/CohortBuilder/ExplorerTable/utils.d.ts +16 -2
  118. package/dist/dts/features/CohortBuilder/ExplorerTable/utils.d.ts.map +1 -1
  119. package/dist/dts/features/CohortBuilder/ExplorerTable/utils.js +17 -3
  120. package/dist/dts/features/CohortBuilder/ExplorerTable/utils.js.map +1 -1
  121. package/dist/dts/features/CohortBuilder/Repository/FileFacetPanel.d.ts +11 -0
  122. package/dist/dts/features/CohortBuilder/Repository/FileFacetPanel.d.ts.map +1 -0
  123. package/dist/dts/features/CohortBuilder/Repository/FileFacetPanel.js +92 -0
  124. package/dist/dts/features/CohortBuilder/Repository/FileFacetPanel.js.map +1 -0
  125. package/dist/dts/features/CohortBuilder/Repository/Repository.d.ts +4 -0
  126. package/dist/dts/features/CohortBuilder/Repository/Repository.d.ts.map +1 -0
  127. package/dist/dts/features/CohortBuilder/Repository/Repository.js +14 -0
  128. package/dist/dts/features/CohortBuilder/Repository/Repository.js.map +1 -0
  129. package/dist/dts/features/CohortBuilder/Repository/RepositoryPanel.d.ts +4 -0
  130. package/dist/dts/features/CohortBuilder/Repository/RepositoryPanel.d.ts.map +1 -0
  131. package/dist/dts/features/CohortBuilder/Repository/RepositoryPanel.js +43 -0
  132. package/dist/dts/features/CohortBuilder/Repository/RepositoryPanel.js.map +1 -0
  133. package/dist/dts/features/CohortBuilder/Repository/Stats.d.ts +9 -0
  134. package/dist/dts/features/CohortBuilder/Repository/Stats.d.ts.map +1 -0
  135. package/dist/dts/features/CohortBuilder/Repository/Stats.js +9 -0
  136. package/dist/dts/features/CohortBuilder/Repository/Stats.js.map +1 -0
  137. package/dist/dts/features/CohortBuilder/Repository/hooks.d.ts +9 -0
  138. package/dist/dts/features/CohortBuilder/Repository/hooks.d.ts.map +1 -0
  139. package/dist/dts/features/CohortBuilder/Repository/hooks.js +53 -0
  140. package/dist/dts/features/CohortBuilder/Repository/hooks.js.map +1 -0
  141. package/dist/dts/features/CohortBuilder/Repository/index.d.ts +4 -0
  142. package/dist/dts/features/CohortBuilder/Repository/index.d.ts.map +1 -0
  143. package/dist/dts/features/CohortBuilder/Repository/index.js +3 -0
  144. package/dist/dts/features/CohortBuilder/Repository/index.js.map +1 -0
  145. package/dist/dts/features/CohortBuilder/Repository/types.d.ts +57 -0
  146. package/dist/dts/features/CohortBuilder/Repository/types.d.ts.map +1 -0
  147. package/dist/dts/features/CohortBuilder/Repository/types.js +2 -0
  148. package/dist/dts/features/CohortBuilder/Repository/types.js.map +1 -0
  149. package/dist/dts/features/CohortBuilder/downloads/downloadActionHook.d.ts.map +1 -1
  150. package/dist/dts/features/CohortBuilder/downloads/downloadActionHook.js +4 -1
  151. package/dist/dts/features/CohortBuilder/downloads/downloadActionHook.js.map +1 -1
  152. package/dist/dts/features/CohortBuilder/index.d.ts +4 -2
  153. package/dist/dts/features/CohortBuilder/index.d.ts.map +1 -1
  154. package/dist/dts/features/CohortBuilder/index.js +4 -2
  155. package/dist/dts/features/CohortBuilder/index.js.map +1 -1
  156. package/dist/dts/features/CohortBuilder/types.d.ts +1 -3
  157. package/dist/dts/features/CohortBuilder/types.d.ts.map +1 -1
  158. package/dist/dts/features/CohortBuilder/types.js.map +1 -1
  159. package/dist/dts/features/Dictionary/Dictionary.d.ts.map +1 -1
  160. package/dist/dts/features/Dictionary/Dictionary.js +5 -2
  161. package/dist/dts/features/Dictionary/Dictionary.js.map +1 -1
  162. package/dist/dts/features/Dictionary/GraphView.d.ts +9 -0
  163. package/dist/dts/features/Dictionary/GraphView.d.ts.map +1 -0
  164. package/dist/dts/features/Dictionary/GraphView.js +99 -0
  165. package/dist/dts/features/Dictionary/GraphView.js.map +1 -0
  166. package/dist/dts/features/Dictionary/graphViewDataUtils.d.ts +114 -0
  167. package/dist/dts/features/Dictionary/graphViewDataUtils.d.ts.map +1 -0
  168. package/dist/dts/features/Dictionary/graphViewDataUtils.js +332 -0
  169. package/dist/dts/features/Dictionary/graphViewDataUtils.js.map +1 -0
  170. package/dist/dts/features/Dictionary/utils.d.ts.map +1 -1
  171. package/dist/dts/features/Dictionary/utils.js.map +1 -1
  172. package/dist/dts/features/Discovery/ActionBar/AddToDataLibrary.stories.d.ts +1 -1
  173. package/dist/dts/features/Discovery/ActionBar/AddToDataLibrary.stories.d.ts.map +1 -1
  174. package/dist/dts/features/Discovery/ActionBar/DataLibraryActionButton.stories.d.ts +1 -1
  175. package/dist/dts/features/Discovery/ActionBar/DataLibraryActionButton.stories.d.ts.map +1 -1
  176. package/dist/dts/features/Navigation/Footer/Footer.stories.d.ts +1 -1
  177. package/dist/dts/features/Navigation/Footer/Footer.stories.d.ts.map +1 -1
  178. package/dist/dts/features/Navigation/TopBar/IconButton.stories.d.ts +1 -1
  179. package/dist/dts/features/Navigation/TopBar/IconButton.stories.d.ts.map +1 -1
  180. package/dist/dts/features/Navigation/TopBar/TopBar.stories.d.ts +1 -1
  181. package/dist/dts/features/Navigation/TopBar/TopBar.stories.d.ts.map +1 -1
  182. package/dist/dts/index.d.ts +3 -2
  183. package/dist/dts/index.d.ts.map +1 -1
  184. package/dist/dts/index.js +5 -5
  185. package/dist/dts/index.js.map +1 -1
  186. package/dist/dts/lib/common/staticProps.d.ts.map +1 -1
  187. package/dist/dts/lib/common/staticProps.js +0 -1
  188. package/dist/dts/lib/common/staticProps.js.map +1 -1
  189. package/dist/dts/pages/404/Custom404Page.stories.d.ts +1 -1
  190. package/dist/dts/pages/404/Custom404Page.stories.d.ts.map +1 -1
  191. package/dist/dts/pages/Repository/Repository.d.ts +4 -0
  192. package/dist/dts/pages/Repository/Repository.d.ts.map +1 -0
  193. package/dist/dts/pages/Repository/Repository.js +25 -0
  194. package/dist/dts/pages/Repository/Repository.js.map +1 -0
  195. package/dist/dts/pages/Repository/data.d.ts +4 -0
  196. package/dist/dts/pages/Repository/data.d.ts.map +1 -0
  197. package/dist/dts/pages/Repository/data.js +93 -0
  198. package/dist/dts/pages/Repository/data.js.map +1 -0
  199. package/dist/dts/pages/Repository/index.d.ts +4 -0
  200. package/dist/dts/pages/Repository/index.d.ts.map +1 -0
  201. package/dist/dts/pages/Repository/index.js +4 -0
  202. package/dist/dts/pages/Repository/index.js.map +1 -0
  203. package/dist/dts/pages/Repository/types.d.ts +6 -0
  204. package/dist/dts/pages/Repository/types.d.ts.map +1 -0
  205. package/dist/dts/pages/Repository/types.js +2 -0
  206. package/dist/dts/pages/Repository/types.js.map +1 -0
  207. package/dist/dts/types/common.d.ts +4 -0
  208. package/dist/dts/types/common.d.ts.map +1 -1
  209. package/dist/dts/types/constants.d.ts +2 -0
  210. package/dist/dts/types/constants.d.ts.map +1 -1
  211. package/dist/dts/types/constants.js +2 -0
  212. package/dist/dts/types/constants.js.map +1 -1
  213. package/dist/dts/types/icons.d.ts +4 -3
  214. package/dist/dts/types/icons.d.ts.map +1 -1
  215. package/dist/dts/types/icons.js +4 -3
  216. package/dist/dts/types/icons.js.map +1 -1
  217. package/dist/dts/utils/RendererFactory.d.ts +1 -14
  218. package/dist/dts/utils/RendererFactory.d.ts.map +1 -1
  219. package/dist/dts/utils/RendererFactory.js.map +1 -1
  220. package/dist/dts/utils/time.d.ts +4 -0
  221. package/dist/dts/utils/time.d.ts.map +1 -1
  222. package/dist/dts/utils/time.js +4 -4
  223. package/dist/dts/utils/time.js.map +1 -1
  224. package/dist/dts/utils/validators.d.ts +2 -0
  225. package/dist/dts/utils/validators.d.ts.map +1 -0
  226. package/dist/dts/utils/validators.js +2 -0
  227. package/dist/dts/utils/validators.js.map +1 -0
  228. package/dist/esm/index.js +1511 -134
  229. package/dist/esm/index.js.map +1 -1
  230. package/dist/index.d.ts +157 -31
  231. package/dist/tsconfig.tsbuildinfo +1 -1
  232. package/package.json +6 -9
package/dist/cjs/index.js CHANGED
@@ -46,6 +46,11 @@ var MiniSearch = require('minisearch');
46
46
  var uniq = require('lodash/uniq');
47
47
  var sum = require('lodash/sum');
48
48
  var lu = require('react-icons/lu');
49
+ var filesize = require('filesize');
50
+ var core$2 = require('@dnd-kit/core');
51
+ var sortable = require('@dnd-kit/sortable');
52
+ var utilities = require('@dnd-kit/utilities');
53
+ var modifiers = require('@dnd-kit/modifiers');
49
54
  var Cookies = require('universal-cookie');
50
55
  var GraphiQL = require('graphiql');
51
56
  var fs = require('fs');
@@ -57,7 +62,6 @@ var toolkit = require('@reduxjs/toolkit');
57
62
  var createWebStorage = require('redux-persist/lib/storage/createWebStorage');
58
63
  var dynamic = require('next/dynamic');
59
64
  var YAML = require('yaml');
60
- var filesize = require('filesize');
61
65
  var dnd = require('@hello-pangea/dnd');
62
66
  var plugin = require('tailwindcss/plugin');
63
67
  var cookie = require('cookie');
@@ -550,6 +554,48 @@ const create10ColorAccessibleContrast = (pallet)=>{
550
554
  * @param {number} seconds - The time in seconds to be converted.
551
555
  * @returns {number} The equivalent time in milliseconds.
552
556
  */ const convertSecondsToMilliseconds = (seconds)=>seconds * 1000;
557
+ // Using the built-in Date object
558
+ const getCurrentTimestamp = ()=>{
559
+ return Date.now(); // Returns milliseconds since Unix epoch
560
+ };
561
+ // Get a readable timestamp for logging/display
562
+ const getFormattedTimestamp = ()=>{
563
+ return new Date().toISOString();
564
+ };
565
+ // Compare two timestamps and get difference in milliseconds
566
+ const getTimeDifferenceMs = (startTime, endTime = Date.now())=>{
567
+ return endTime - startTime;
568
+ };
569
+ // Check if time difference is greater than specified minutes
570
+ const isTimeGreaterThan = (startTime, minutes)=>{
571
+ const diffMs = getTimeDifferenceMs(startTime);
572
+ const diffMinutes = diffMs / (1000 * 60);
573
+ return diffMinutes > minutes;
574
+ };
575
+ // Get human-readable duration
576
+ const getReadableDuration = (milliseconds)=>{
577
+ const seconds = Math.floor(milliseconds / 1000);
578
+ const minutes = Math.floor(seconds / 60);
579
+ const hours = Math.floor(minutes / 60);
580
+ if (hours > 0) {
581
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
582
+ }
583
+ if (minutes > 0) {
584
+ return `${minutes}m ${seconds % 60}s`;
585
+ }
586
+ return `${seconds}s`;
587
+ };
588
+ // Example usage:
589
+ const measureExecutionTime = async (func)=>{
590
+ const startTime = getCurrentTimestamp();
591
+ await func();
592
+ const duration = getTimeDifferenceMs(startTime);
593
+ return getReadableDuration(duration);
594
+ };
595
+ // Performance monitoring with high-resolution timestamps
596
+ const getHighResolutionTimestamp = ()=>{
597
+ return performance.now(); // More precise than Date.now() for performance measurements
598
+ };
553
599
  const MinutesToMilliseconds = (minutes)=>minutes * 60 * 1000;
554
600
 
555
601
  const convertPathsToTree = (paths)=>{
@@ -1246,6 +1292,14 @@ const EmptyTableMessage = ({ message })=>{
1246
1292
  });
1247
1293
  };
1248
1294
 
1295
+ const MessagePage = ({ children })=>{
1296
+ // place children in center of div that is 1/2 the visible height
1297
+ return /*#__PURE__*/ jsxRuntime.jsx("div", {
1298
+ className: "flex justify-center items-center w-full h-vh",
1299
+ children: children
1300
+ });
1301
+ };
1302
+
1249
1303
  const LoginProviderMultipleItems = ({ provider, handleLoginSelected })=>{
1250
1304
  const [value, setValue] = React.useState(null);
1251
1305
  return /*#__PURE__*/ jsxRuntime.jsxs("div", {
@@ -1709,12 +1763,20 @@ const filterRedirect = (redirect)=>{
1709
1763
  } else {
1710
1764
  redirectPath = redirect ?? '/';
1711
1765
  }
1712
- return core.GEN3_REDIRECT_URL ? `${core.GEN3_REDIRECT_URL}/${redirectPath}` : redirectPath;
1766
+ if (!core.GEN3_REDIRECT_URL) {
1767
+ return redirectPath;
1768
+ }
1769
+ // Remove trailing slash from base URL and leading slash from path
1770
+ const baseUrl = core.GEN3_REDIRECT_URL.replace(/\/+$/, '');
1771
+ const cleanPath = redirectPath.replace(/^\/+/, '');
1772
+ // Join with a single slash, ensuring we don't create double slashes
1773
+ return cleanPath ? `${baseUrl}/${cleanPath}` : baseUrl;
1713
1774
  };
1714
1775
  const LoginPanel = (loginConfig)=>{
1715
1776
  const { image, topContent, bottomContent } = loginConfig;
1716
1777
  const router$1 = router.useRouter();
1717
- const { query: { referer } } = router$1;
1778
+ const { query: { referer: refererQuery, redirect: redirectQuery } } = router$1;
1779
+ const referer = redirectQuery || refererQuery; // either referer or redirect query param
1718
1780
  const handleFenceLoginSelected = React.useCallback(async (loginURL)=>{
1719
1781
  router$1.push(`${appendParameterToUrl(loginURL, 'redirect', filterRedirect(referer))}`).catch((e)=>{
1720
1782
  notifications.showNotification({
@@ -5047,61 +5109,65 @@ const DropdownPanel = ({ index, filters, tabTitle, facetDefinitions, facetDataHo
5047
5109
  onChange: onAccessChange,
5048
5110
  accessLevel: accessLevel
5049
5111
  }) : null,
5050
- /*#__PURE__*/ jsxRuntime.jsxs(core$1.Stack, {
5051
- className: "bg-base-max py-4 px-2 h-full w-full",
5052
- children: [
5053
- Object.keys(sharedFilters).length > 0 && /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
5054
- gap: "xs",
5055
- justify: "space-between",
5056
- children: [
5057
- /*#__PURE__*/ jsxRuntime.jsxs("div", {
5058
- className: "flex items-center space-x-1",
5059
- children: [
5060
- /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
5061
- icon: "gen3:share",
5062
- height: 16,
5063
- width: 16,
5064
- color: theme.colors.accent[4]
5065
- }),
5066
- /*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
5067
- size: "sm",
5068
- children: "Set the shared filters for all"
5069
- }),
5070
- /*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
5071
- label: "If enabled any filter set on this tab will be applied to every tab where occurs.",
5072
- position: "top",
5073
- withArrow: true,
5074
- children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
5075
- icon: "gen3:info",
5076
- height: 12,
5077
- width: 12,
5112
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.ScrollArea, {
5113
+ type: "auto",
5114
+ className: "flex-1 min-h-0 w-full",
5115
+ children: /*#__PURE__*/ jsxRuntime.jsxs(core$1.Stack, {
5116
+ className: "bg-base-max py-4 px-2 h-screen w-full",
5117
+ children: [
5118
+ Object.keys(sharedFilters).length > 0 && /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
5119
+ gap: "xs",
5120
+ justify: "space-between",
5121
+ children: [
5122
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
5123
+ className: "flex items-center space-x-1",
5124
+ children: [
5125
+ /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
5126
+ icon: "gen3:share",
5127
+ height: 16,
5128
+ width: 16,
5078
5129
  color: theme.colors.accent[4]
5130
+ }),
5131
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
5132
+ size: "sm",
5133
+ children: "Set the shared filters for all"
5134
+ }),
5135
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
5136
+ label: "If enabled any filter set on this tab will be applied to every tab where occurs.",
5137
+ position: "top",
5138
+ withArrow: true,
5139
+ children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
5140
+ icon: "gen3:info",
5141
+ height: 12,
5142
+ width: 12,
5143
+ color: theme.colors.accent[4]
5144
+ })
5079
5145
  })
5080
- })
5081
- ]
5082
- }),
5083
- /*#__PURE__*/ jsxRuntime.jsx(core$1.Switch, {
5084
- checked: shareFilters,
5085
- onChange: (event)=>handleSharedFiltersChange(event.currentTarget.checked)
5086
- })
5087
- ]
5088
- }),
5089
- filters.tabs.length > 1 && /*#__PURE__*/ jsxRuntime.jsx(core$1.Select, {
5090
- classNames: {
5091
- options: 'border-1 border-base-dark',
5092
- option: 'hover:bg-primary-lightest'
5093
- },
5094
- withCheckIcon: false,
5095
- data: items,
5096
- value: value === null ? '0' : value,
5097
- onChange: setValue
5098
- }),
5099
- Object.keys(facetDefinitions).length > 0 ? /*#__PURE__*/ jsxRuntime.jsx(FiltersPanel, {
5100
- fields: fields,
5101
- dataFunctions: facetDataHooks,
5102
- valueLabel: tabTitle
5103
- }) : null
5104
- ]
5146
+ ]
5147
+ }),
5148
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Switch, {
5149
+ checked: shareFilters,
5150
+ onChange: (event)=>handleSharedFiltersChange(event.currentTarget.checked)
5151
+ })
5152
+ ]
5153
+ }),
5154
+ filters.tabs.length > 1 && /*#__PURE__*/ jsxRuntime.jsx(core$1.Select, {
5155
+ classNames: {
5156
+ options: 'border-1 border-base-dark',
5157
+ option: 'hover:bg-primary-lightest'
5158
+ },
5159
+ withCheckIcon: false,
5160
+ data: items,
5161
+ value: value === null ? '0' : value,
5162
+ onChange: setValue
5163
+ }),
5164
+ Object.keys(facetDefinitions).length > 0 ? /*#__PURE__*/ jsxRuntime.jsx(FiltersPanel, {
5165
+ fields: fields,
5166
+ dataFunctions: facetDataHooks,
5167
+ valueLabel: tabTitle
5168
+ }) : null
5169
+ ]
5170
+ })
5105
5171
  })
5106
5172
  ]
5107
5173
  });
@@ -8187,6 +8253,7 @@ const DataLibraryActionButton = /*#__PURE__*/ React.forwardRef(({ label = undefi
8187
8253
  DataLibraryActionButton.displayName = 'DataLibraryActionButton';
8188
8254
 
8189
8255
  const MANIFEST_FILENAME = 'manifest.json';
8256
+ const XL_BREAKPOINT = 1280;
8190
8257
 
8191
8258
  /**
8192
8259
  * Determines the disabled state and the reason for disabling based on authentication status,
@@ -10511,6 +10578,52 @@ const DetailsDrawer = ({ id, title, panel, panelProps })=>{
10511
10578
  });
10512
10579
  };
10513
10580
 
10581
+ // TODO: refine this to make more general
10582
+ const extractProgramAndProjectNames = (path)=>{
10583
+ // Regular expression to match the pattern /programs/{programName}/projects/{projectName}
10584
+ const regex = /\/programs\/([^/]+)\/projects\/([^/]+)/;
10585
+ const match = path.match(regex);
10586
+ if (match) {
10587
+ return {
10588
+ programName: match[1],
10589
+ projectName: match[2]
10590
+ };
10591
+ }
10592
+ return {
10593
+ programName: null,
10594
+ projectName: null
10595
+ };
10596
+ };
10597
+ const isStringToColorTable = (value)=>{
10598
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
10599
+ return false;
10600
+ }
10601
+ for(const key in value){
10602
+ if (typeof key !== 'string' || typeof value[key] !== 'string') {
10603
+ return false;
10604
+ }
10605
+ }
10606
+ return true;
10607
+ };
10608
+ const ProjectAccessCellRenderer = ({ cell }, params)=>{
10609
+ const value = cell.getValue();
10610
+ if (typeof value !== 'string') return /*#__PURE__*/ jsxRuntime.jsx("span", {
10611
+ children: "Bad Value"
10612
+ });
10613
+ const { projectName } = extractProgramAndProjectNames(value);
10614
+ let color = 'primary.4';
10615
+ if (params && isStringToColorTable(params?.colorTable)) {
10616
+ if (projectName) {
10617
+ color = core.ExtractValueFromObject(params.colorTable, projectName, color);
10618
+ }
10619
+ }
10620
+ return /*#__PURE__*/ jsxRuntime.jsx(core$1.Badge, {
10621
+ fullWidth: true,
10622
+ color: color,
10623
+ children: projectName
10624
+ });
10625
+ };
10626
+
10514
10627
  // TODO need to type this
10515
10628
  const RenderArrayCell = ({ cell })=>{
10516
10629
  const value = cell.getValue();
@@ -10555,6 +10668,11 @@ const ValueCellRenderer = ({ cell })=>{
10555
10668
  children: cell.getValue()
10556
10669
  });
10557
10670
  };
10671
+ const FilesizeRenderer = ({ cell })=>{
10672
+ return /*#__PURE__*/ jsxRuntime.jsx("span", {
10673
+ children: filesize.filesize(cell.getValue())
10674
+ });
10675
+ };
10558
10676
  const ArrayCellFunctionCatalog = {
10559
10677
  NegativePositive: RenderArrayCellNegativePositive,
10560
10678
  default: RenderArrayCell
@@ -10576,6 +10694,66 @@ const RenderLinkCell = ({ cell }, ...args)=>{
10576
10694
  })
10577
10695
  });
10578
10696
  };
10697
+ const isRenderNextLinkCellWithIconParams = (value)=>{
10698
+ if (typeof value !== 'object' || value === null) {
10699
+ return false;
10700
+ }
10701
+ const obj = value;
10702
+ return (obj.baseURL === undefined || typeof obj.baseURL === 'string') && (obj.icon === undefined || typeof obj.icon === 'string') && (obj.size === undefined || typeof obj.size === 'string') && (obj.linkField === undefined || typeof obj.linkField === 'string');
10703
+ };
10704
+ const RenderLinkCellWithIcon = ({ cell }, ...args)=>{
10705
+ let baseURL = '';
10706
+ let icon = null;
10707
+ let size = 'sm';
10708
+ let iconHeight = '1em';
10709
+ let linkField = undefined;
10710
+ let classNames = {
10711
+ text: ''
10712
+ };
10713
+ const params = args[0];
10714
+ if (isRenderNextLinkCellWithIconParams(params)) {
10715
+ baseURL = params.baseURL ?? baseURL;
10716
+ if (params.icon) {
10717
+ icon = params.icon;
10718
+ }
10719
+ size = params.size ?? size;
10720
+ iconHeight = params.iconHeight ?? iconHeight;
10721
+ linkField = params.linkField ?? undefined;
10722
+ classNames = params?.classNames ?? {
10723
+ icon: '',
10724
+ text: ''
10725
+ };
10726
+ }
10727
+ let linkURL = `${baseURL}${cell.getValue()}`;
10728
+ if (linkField) {
10729
+ const value = cell.row.original[linkField];
10730
+ if (typeof value === 'string') {
10731
+ linkURL = `${baseURL}${value}`;
10732
+ }
10733
+ }
10734
+ return /*#__PURE__*/ jsxRuntime.jsx(Link, {
10735
+ href: linkURL,
10736
+ target: "_blank",
10737
+ rel: "noreferrer",
10738
+ children: /*#__PURE__*/ jsxRuntime.jsxs("div", {
10739
+ className: "flex items-center gap-1",
10740
+ children: [
10741
+ icon && /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
10742
+ height: iconHeight,
10743
+ icon: icon
10744
+ }),
10745
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
10746
+ fw: 700,
10747
+ size: size,
10748
+ classNames: {
10749
+ root: classNames?.text
10750
+ },
10751
+ children: cell.getValue()
10752
+ })
10753
+ ]
10754
+ })
10755
+ });
10756
+ };
10579
10757
  const RenderLinkCellUsingValueMap = ({ cell }, ...args)=>{
10580
10758
  let href = null;
10581
10759
  if (typeof args[0] === 'object' && Object.keys(args[0]).includes('valueToURL')) {
@@ -10608,7 +10786,8 @@ const RenderLinkCellUsingValueMap = ({ cell }, ...args)=>{
10608
10786
  };
10609
10787
  const LinkCellFunctionCatalog = {
10610
10788
  default: RenderLinkCell,
10611
- linkWithValueMap: RenderLinkCellUsingValueMap
10789
+ linkWithValueMap: RenderLinkCellUsingValueMap,
10790
+ linkWithIcon: RenderLinkCellWithIcon
10612
10791
  };
10613
10792
  let instance$2;
10614
10793
  const ExplorerTableCellRendererFactory = ()=>{
@@ -10621,7 +10800,13 @@ const ExplorerTableCellRendererFactory = ()=>{
10621
10800
  const registerExplorerDefaultCellRenderers = ()=>{
10622
10801
  ExplorerTableCellRendererFactory().registerRendererCatalog({
10623
10802
  value: {
10624
- default: ValueCellRenderer
10803
+ default: ValueCellRenderer,
10804
+ filesize: FilesizeRenderer
10805
+ }
10806
+ });
10807
+ ExplorerTableCellRendererFactory().registerRendererCatalog({
10808
+ access: {
10809
+ projectAccess: ProjectAccessCellRenderer
10625
10810
  }
10626
10811
  });
10627
10812
  ExplorerTableCellRendererFactory().registerRendererCatalog({
@@ -10661,7 +10846,7 @@ const isRecordAny = (obj)=>{
10661
10846
  return obj !== null && typeof obj === 'object';
10662
10847
  };
10663
10848
  const createTableColumns = (tableConfig)=>{
10664
- return tableConfig.fields.map((field)=>{
10849
+ const tableColumns = tableConfig.fields.map((field)=>{
10665
10850
  const columnDef = tableConfig?.columns?.[field];
10666
10851
  const cellRendererFunc = columnDef?.type ? ExplorerTableCellRendererFactory().getRenderer(columnDef?.type, columnDef?.cellRenderFunction ?? 'default') : undefined;
10667
10852
  const cellRendererFuncParams = columnDef?.params && isRecordAny(columnDef?.params) ? columnDef?.params : {};
@@ -10673,9 +10858,22 @@ const createTableColumns = (tableConfig)=>{
10673
10858
  accessorFn: columnDef?.accessorPath ? jsonPathAccessor(columnDef.accessorPath) : undefined,
10674
10859
  Cell: cellRendererFunc && columnDef?.params ? (cell)=>cellRendererFunc(cell, cellRendererFuncParams) : cellRendererFunc ? cellRendererFunc : undefined,
10675
10860
  size: columnDef?.width,
10676
- enableSorting: columnDef?.sortable ?? undefined
10861
+ enableSorting: columnDef?.sortable ?? undefined,
10862
+ visible: columnDef?.visible ?? true,
10863
+ lockVisible: columnDef?.lockVisible ?? false
10677
10864
  };
10678
- }, []);
10865
+ });
10866
+ const lockedVisibility = tableConfig.fields.reduce((acc, field)=>{
10867
+ const columnDef = tableConfig?.columns?.[field];
10868
+ if (columnDef && columnDef?.lockVisible) {
10869
+ acc[field] = columnDef?.visible ?? true; // assume visible by default
10870
+ }
10871
+ return acc;
10872
+ }, {});
10873
+ return {
10874
+ tableColumns: tableColumns,
10875
+ lockedVisibility: lockedVisibility
10876
+ };
10679
10877
  };
10680
10878
  const createArrayTableColumns = (root, tableConfig)=>{
10681
10879
  return tableConfig.fields.map((field)=>{
@@ -10785,7 +10983,7 @@ const ExpandingSubtable = ({ config, data })=>{
10785
10983
  const [expanded, setExpanded] = React.useState(false);
10786
10984
  const [headerHeight, setHeaderHeight] = React.useState(0);
10787
10985
  const theme = core$1.useMantineTheme();
10788
- const expandedTableColumns = useDeepCompare.useDeepCompareMemo(()=>{
10986
+ const { tableColumns: expandedTableColumns } = useDeepCompare.useDeepCompareMemo(()=>{
10789
10987
  return createTableColumns(config);
10790
10988
  }, [
10791
10989
  config
@@ -10967,6 +11165,350 @@ const QueryRowDetailsPanel = ({ id, index, tableConfig, accessibility })=>{
10967
11165
  });
10968
11166
  };
10969
11167
 
11168
+ function ColumnOrdering({ table, handleColumnOrderingReset, columnOrder, setColumnOrder, noColumnOrdering = [] }) {
11169
+ const [showColumnMenu, setShowColumnMenu] = React.useState(false);
11170
+ const [searchValue, setSearchValue] = React.useState('');
11171
+ const [columesVisible, setColumsnVisible] = React.useState([]);
11172
+ const isBackToDefaults = lodash.isEqual(table.initialState.columnOrder, columnOrder) && lodash.isEqual(table.initialState.columnVisibility, Object.fromEntries(Object.entries(table.getState().columnVisibility).filter(([, value])=>!value)));
11173
+ const sensors = core$2.useSensors(core$2.useSensor(core$2.PointerSensor, {
11174
+ activationConstraint: {
11175
+ distance: 5
11176
+ }
11177
+ }), core$2.useSensor(core$2.KeyboardSensor, {
11178
+ coordinateGetter: sortable.sortableKeyboardCoordinates
11179
+ }));
11180
+ const handleDragEnd = (event)=>{
11181
+ const { active, over } = event;
11182
+ if (active?.id && over?.id && active?.id !== over?.id) {
11183
+ setColumnOrder((items)=>{
11184
+ const oldIndex = items.indexOf(active?.id);
11185
+ const newIndex = items.indexOf(over?.id);
11186
+ return sortable.arrayMove(items, oldIndex, newIndex);
11187
+ });
11188
+ }
11189
+ };
11190
+ return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Menu, {
11191
+ position: "bottom-end",
11192
+ middlewares: {
11193
+ shift: false,
11194
+ flip: false
11195
+ },
11196
+ onChange: setShowColumnMenu,
11197
+ offset: 0,
11198
+ zIndex: 400,
11199
+ withinPortal: true,
11200
+ children: [
11201
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
11202
+ label: "Customize Columns",
11203
+ disabled: showColumnMenu,
11204
+ children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Menu.Target, {
11205
+ children: /*#__PURE__*/ jsxRuntime.jsx(core$1.ActionIcon, {
11206
+ variant: "outline",
11207
+ size: "lg",
11208
+ "aria-label": "Customize Columns",
11209
+ color: "primary",
11210
+ "data-testid": "button-column-selector-box",
11211
+ className: `${showColumnMenu && 'border-2 border-primary'} hover:bg-primary hover:text-base-max`,
11212
+ children: !showColumnMenu ? /*#__PURE__*/ jsxRuntime.jsx(bs.BsList, {
11213
+ size: "1.5rem",
11214
+ "aria-hidden": "true"
11215
+ }) : /*#__PURE__*/ jsxRuntime.jsx(bs.BsX, {
11216
+ size: "2rem",
11217
+ "aria-hidden": "true"
11218
+ })
11219
+ })
11220
+ })
11221
+ }),
11222
+ /*#__PURE__*/ jsxRuntime.jsxs(core$1.Menu.Dropdown, {
11223
+ className: "bg-base-max border-2 border-primary p-2 rounded-md",
11224
+ "data-testid": "column-selector-popover-modal",
11225
+ children: [
11226
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
11227
+ className: "flex justify-between items-center",
11228
+ children: [
11229
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
11230
+ className: "font-bold text-primary-darkest tracking-normal",
11231
+ children: "Customize Columns"
11232
+ }),
11233
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
11234
+ label: "Restore defaults",
11235
+ disabled: isBackToDefaults,
11236
+ zIndex: 400,
11237
+ children: /*#__PURE__*/ jsxRuntime.jsx("span", {
11238
+ children: /*#__PURE__*/ jsxRuntime.jsx(core$1.ActionIcon, {
11239
+ onClick: handleColumnOrderingReset,
11240
+ className: isBackToDefaults ? 'invisible' : 'border-0',
11241
+ "data-testid": "restore-default-icon",
11242
+ "aria-label": "restore default column ordering",
11243
+ children: /*#__PURE__*/ jsxRuntime.jsx(fa.FaUndo, {
11244
+ size: "1rem"
11245
+ })
11246
+ })
11247
+ })
11248
+ })
11249
+ ]
11250
+ }),
11251
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Divider, {
11252
+ color: "base.2",
11253
+ className: "mt-1"
11254
+ }),
11255
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
11256
+ value: searchValue,
11257
+ onChange: (event)=>setSearchValue(event.currentTarget.value.trim()),
11258
+ placeholder: "Filter Columns",
11259
+ "aria-label": "Search input for columns",
11260
+ leftSection: /*#__PURE__*/ jsxRuntime.jsx(md.MdSearch, {
11261
+ "aria-hidden": "true"
11262
+ }),
11263
+ className: "mb-2 mt-4",
11264
+ "data-testid": "textbox-column-selector"
11265
+ }),
11266
+ /*#__PURE__*/ jsxRuntime.jsx(core$2.DndContext, {
11267
+ sensors: sensors,
11268
+ collisionDetection: core$2.closestCenter,
11269
+ onDragEnd: handleDragEnd,
11270
+ modifiers: [
11271
+ modifiers.restrictToVerticalAxis,
11272
+ modifiers.restrictToWindowEdges,
11273
+ modifiers.restrictToParentElement
11274
+ ],
11275
+ children: /*#__PURE__*/ jsxRuntime.jsx(sortable.SortableContext, {
11276
+ items: table.getAllLeafColumns(),
11277
+ strategy: sortable.verticalListSortingStrategy,
11278
+ children: /*#__PURE__*/ jsxRuntime.jsx(List, {
11279
+ columns: table.getAllLeafColumns(),
11280
+ searchValue: searchValue,
11281
+ noColumnOrdering: noColumnOrdering
11282
+ })
11283
+ })
11284
+ })
11285
+ ]
11286
+ })
11287
+ ]
11288
+ });
11289
+ }
11290
+ function List({ columns, searchValue, noColumnOrdering = [] }) {
11291
+ return /*#__PURE__*/ jsxRuntime.jsx("ul", {
11292
+ children: columns.filter((column)=>{
11293
+ if (!noColumnOrdering.includes(column.id)) {
11294
+ return core.humanify({
11295
+ term: column.id
11296
+ }).toLowerCase().includes(searchValue.toLowerCase());
11297
+ } else {
11298
+ return column.id;
11299
+ }
11300
+ }).map((column, index)=>{
11301
+ return !noColumnOrdering.includes(column.id) ? /*#__PURE__*/ jsxRuntime.jsx(DraggableColumnItem, {
11302
+ column: column,
11303
+ isNotLast: index < columns.length - 1
11304
+ }, column.id) : /*#__PURE__*/ jsxRuntime.jsx("li", {
11305
+ className: "hide"
11306
+ }, column.id);
11307
+ })
11308
+ });
11309
+ }
11310
+ function DraggableColumnItem({ column, isNotLast }) {
11311
+ const { attributes, listeners, setNodeRef, transform, transition } = sortable.useSortable({
11312
+ id: column.id
11313
+ });
11314
+ const style = {
11315
+ transform: utilities.CSS.Transform.toString(transform),
11316
+ transition
11317
+ };
11318
+ return /*#__PURE__*/ jsxRuntime.jsx("li", {
11319
+ ref: setNodeRef,
11320
+ style: style,
11321
+ ...listeners,
11322
+ className: ` ${isNotLast ? 'mb-2' : ''}`,
11323
+ "data-testid": `column-selector-row-${column.id}`,
11324
+ children: /*#__PURE__*/ jsxRuntime.jsxs("div", {
11325
+ ...attributes,
11326
+ role: undefined,
11327
+ className: "flex gap-2 items-center bg-nci-violet-lightest px-1 py-1.5 h-6 cursor-move",
11328
+ children: [
11329
+ /*#__PURE__*/ jsxRuntime.jsx(md.MdDragIndicator, {
11330
+ size: "1rem",
11331
+ className: "text-primary"
11332
+ }),
11333
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Switch, {
11334
+ labelPosition: "left",
11335
+ label: typeof column?.columnDef?.header === 'string' ? column.columnDef.header : core.humanify({
11336
+ term: column.id
11337
+ }),
11338
+ classNames: {
11339
+ root: 'w-full',
11340
+ body: 'grow flex justify-between',
11341
+ label: 'text-xs font-medium tracking-normal'
11342
+ },
11343
+ color: "accent",
11344
+ checked: column.getIsVisible(),
11345
+ onChange: ()=>column.toggleVisibility(),
11346
+ onKeyDown: (e)=>{
11347
+ if (e.code === 'Space') {
11348
+ e.preventDefault();
11349
+ column.toggleVisibility();
11350
+ }
11351
+ },
11352
+ size: "xs",
11353
+ "data-testid": "switch-toggle"
11354
+ })
11355
+ ]
11356
+ })
11357
+ });
11358
+ }
11359
+
11360
+ const TitleWrapper = ({ title })=>/*#__PURE__*/ jsxRuntime.jsx("div", {
11361
+ className: "uppercase text-lg text-left ml-0 lg:ml-auto gap-x-2",
11362
+ children: title
11363
+ });
11364
+ const TotalDetailWrapper = ({ detail, className = '' })=>/*#__PURE__*/ jsxRuntime.jsx("div", {
11365
+ className: `self-center uppercase text-lg text-left ml-0 lg:ml-auto ${className}`,
11366
+ children: detail
11367
+ });
11368
+ const TooltipWrapper = ({ children, tooltip, searchFocused, baseZIndex })=>/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
11369
+ multiline: true,
11370
+ label: tooltip,
11371
+ position: "bottom-start",
11372
+ offset: 0,
11373
+ opened: searchFocused,
11374
+ zIndex: baseZIndex + 1,
11375
+ classNames: {
11376
+ tooltip: 'w-72 border border-base-lighter absolute bg-white p-2 text-nci-gray text-sm overflow-wrap break-all rounded-b rounded-t-none font-content'
11377
+ },
11378
+ children: children
11379
+ });
11380
+ const SearchInput = ({ searchTerm, placeholder, tooltip, searchFocused, baseZIndex, onClear, onChange, onFocus, onBlur })=>{
11381
+ const TooltipContainer = tooltip ? TooltipWrapper : React.Fragment;
11382
+ return /*#__PURE__*/ jsxRuntime.jsx(TooltipContainer, {
11383
+ tooltip: tooltip,
11384
+ baseZIndex: baseZIndex,
11385
+ searchFocused: searchFocused,
11386
+ children: /*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
11387
+ leftSection: /*#__PURE__*/ jsxRuntime.jsx(md.MdSearch, {
11388
+ size: 24,
11389
+ "aria-hidden": "true"
11390
+ }),
11391
+ "data-testid": "textbox-table-search-bar",
11392
+ placeholder: placeholder ?? 'Search',
11393
+ "aria-label": "Table Search Input",
11394
+ size: "sm",
11395
+ rightSection: searchTerm.length > 0 && /*#__PURE__*/ jsxRuntime.jsx(core$1.ActionIcon, {
11396
+ onClick: onClear,
11397
+ className: "border-0",
11398
+ children: /*#__PURE__*/ jsxRuntime.jsx(md.MdClose, {
11399
+ "aria-label": "clear search"
11400
+ })
11401
+ }),
11402
+ value: searchTerm,
11403
+ onChange: onChange,
11404
+ onFocus: onFocus,
11405
+ onBlur: onBlur,
11406
+ classNames: {
11407
+ input: `border-base-lighter focus:border-2 focus:border-primary${tooltip ? ' focus:rounded-b-none' : ''}`,
11408
+ wrapper: 'xl:w-72'
11409
+ }
11410
+ })
11411
+ });
11412
+ };
11413
+ function TableHeader({ additionalControls, tableTotalDetail, tableTitle, search, showControls, handleChange, table, columnOrder, setColumnOrder, baseZIndex, customBreakpoint, noColumnOrdering }) {
11414
+ const [searchTerm, setSearchTerm] = React.useState(search?.defaultSearchTerm ?? '');
11415
+ const [searchFocused, setSearchFocused] = React.useState(false);
11416
+ const inputRef = React.useRef(null); // updated apr 10 25 to get build to work
11417
+ const timeoutRef = React.useRef(null); // updated apr 10 25 to get build to work
11418
+ const shouldShowControls = search?.enabled || showControls;
11419
+ const { width } = hooks.useViewportSize();
11420
+ React.useEffect(()=>{
11421
+ if (search?.defaultSearchTerm) {
11422
+ inputRef.current?.focus();
11423
+ }
11424
+ }, [
11425
+ search?.defaultSearchTerm
11426
+ ]);
11427
+ const handleInputChange = (e)=>{
11428
+ const newSearchTerm = e.target.value;
11429
+ setSearchTerm(newSearchTerm);
11430
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
11431
+ timeoutRef.current = setTimeout(()=>{
11432
+ handleChange({
11433
+ newSearch: newSearchTerm.trim()
11434
+ });
11435
+ }, 400);
11436
+ };
11437
+ const handleClearClick = ()=>{
11438
+ setSearchTerm('');
11439
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
11440
+ handleChange({
11441
+ newSearch: ''
11442
+ });
11443
+ };
11444
+ const renderSearchAndControls = ()=>/*#__PURE__*/ jsxRuntime.jsxs("div", {
11445
+ className: "flex items-center gap-2",
11446
+ "data-testid": "table-options-menu",
11447
+ children: [
11448
+ search?.enabled && /*#__PURE__*/ jsxRuntime.jsx(SearchInput, {
11449
+ searchTerm: searchTerm,
11450
+ placeholder: search?.placeholder,
11451
+ tooltip: search?.tooltip,
11452
+ searchFocused: searchFocused,
11453
+ baseZIndex: baseZIndex,
11454
+ onClear: handleClearClick,
11455
+ onChange: handleInputChange,
11456
+ onFocus: ()=>setSearchFocused(true),
11457
+ onBlur: ()=>setSearchFocused(false)
11458
+ }),
11459
+ showControls && /*#__PURE__*/ jsxRuntime.jsx(ColumnOrdering, {
11460
+ table: table,
11461
+ handleColumnOrderingReset: ()=>{
11462
+ table.resetColumnVisibility();
11463
+ table.resetColumnOrder();
11464
+ },
11465
+ columnOrder: columnOrder,
11466
+ setColumnOrder: setColumnOrder,
11467
+ noColumnOrdering: noColumnOrdering
11468
+ })
11469
+ ]
11470
+ });
11471
+ const breakpoint = customBreakpoint ?? XL_BREAKPOINT;
11472
+ let detailClass = '';
11473
+ if (tableTitle !== undefined) {
11474
+ if (width >= breakpoint && shouldShowControls) {
11475
+ detailClass = 'ml-auto';
11476
+ }
11477
+ } else {
11478
+ if (width >= breakpoint && additionalControls) {
11479
+ detailClass = 'ml-auto';
11480
+ } else {
11481
+ detailClass = 'order-first basis-full grow-0 shrink-0 -mb-2';
11482
+ }
11483
+ }
11484
+ return /*#__PURE__*/ jsxRuntime.jsxs("div", {
11485
+ className: `flex flex-wrap gap-4 items-center mb-2 ${!additionalControls && !tableTitle ? 'justify-end' : 'justify-between'}`,
11486
+ children: [
11487
+ tableTitle && /*#__PURE__*/ jsxRuntime.jsx("div", {
11488
+ className: additionalControls || shouldShowControls && width < breakpoint ? 'basis-full grow-0 shrink-0 -mb-2' : '',
11489
+ children: /*#__PURE__*/ jsxRuntime.jsx(TitleWrapper, {
11490
+ title: tableTitle
11491
+ })
11492
+ }),
11493
+ additionalControls && additionalControls,
11494
+ tableTotalDetail && /*#__PURE__*/ jsxRuntime.jsx("div", {
11495
+ className: detailClass,
11496
+ children: /*#__PURE__*/ jsxRuntime.jsx(TotalDetailWrapper, {
11497
+ detail: tableTotalDetail
11498
+ })
11499
+ }),
11500
+ shouldShowControls && renderSearchAndControls()
11501
+ ]
11502
+ });
11503
+ }
11504
+
11505
+ // Provides the bottom X position so components can align themselves with the table
11506
+ function emptyFn() {}
11507
+ const TableXPositionContext = /*#__PURE__*/ React.createContext({
11508
+ xPosition: undefined,
11509
+ setXPosition: emptyFn
11510
+ });
11511
+
10970
11512
  const DEFAULT_PAGE_LIMIT_LABEL = 'Rows per Page (Limited to 10,0000):';
10971
11513
  const DEFAULT_PAGE_LIMIT = 10000;
10972
11514
  /**
@@ -10976,11 +11518,12 @@ const DEFAULT_PAGE_LIMIT = 10000;
10976
11518
  * @param index - Offset to use for fetching/displaying pages of rows
10977
11519
  * @param tableConfig - Inherited from ExplorerPageGetServerSideProps
10978
11520
  * @param accessibility - set the access level for the cohort data
10979
- */ const ExplorerTable = ({ index, tableConfig, accessibility, classNames, size = 'sm' })=>{
11521
+ */ const ExplorerTable = ({ index, tableConfig, accessibility, classNames, size = 'sm', additionalControls, tableTotalDetail, tableTitle })=>{
10980
11522
  const [pagination, setPagination] = React.useState({
10981
11523
  pageIndex: 0,
10982
- pageSize: 10
11524
+ pageSize: 20
10983
11525
  });
11526
+ const ref = React.useRef(null);
10984
11527
  const DetailsComponent = React.useMemo(()=>{
10985
11528
  if (!tableConfig?.detailsConfig || !tableConfig?.detailsConfig?.panel || tableConfig?.detailsConfig?.mode === 'none') return null;
10986
11529
  return tableConfig?.detailsConfig?.panelContainer === 'drawer' ? DetailsDrawer : DetailsModal;
@@ -10988,6 +11531,7 @@ const DEFAULT_PAGE_LIMIT = 10000;
10988
11531
  const [sorting, setSorting] = React.useState([]);
10989
11532
  const [rowSelection, setRowSelection] = React.useState({});
10990
11533
  const [selectedRow, setSelectedRow] = React.useState(undefined);
11534
+ const [columnVisibility, setColumnVisibility] = React.useState({});
10991
11535
  // const DetailsPanel = useMemo(
10992
11536
  // () =>
10993
11537
  // ExplorerTableDetailsPanelFactory().getRenderer(
@@ -10997,11 +11541,23 @@ const DEFAULT_PAGE_LIMIT = 10000;
10997
11541
  // [tableConfig?.detailsConfig?.panel],
10998
11542
  // );
10999
11543
  const DetailsPanel = React.useMemo(()=>QueryRowDetailsPanel, []);
11000
- const tableColumns = useDeepCompare.useDeepCompareMemo(()=>{
11544
+ const handleColumnVisibilityChange = (updater)=>{
11545
+ const newState = typeof updater === 'function' ? updater(columnVisibility) : updater;
11546
+ setColumnVisibility({
11547
+ ...newState,
11548
+ ...{
11549
+ 'mrt-row-expand': false,
11550
+ ...lockedVisibility
11551
+ }
11552
+ });
11553
+ };
11554
+ const { tableColumns, lockedVisibility } = useDeepCompare.useDeepCompareMemo(()=>{
11001
11555
  return createTableColumns(tableConfig);
11002
11556
  }, [
11003
11557
  tableConfig
11004
11558
  ]);
11559
+ const [columnOrder, setColumnOrder] = React.useState(tableColumns.map((column)=>column.id));
11560
+ const handleSearchOrPageChange = React.useCallback((params)=>null, []);
11005
11561
  // TODO: add support for nested fields
11006
11562
  const fields = React.useMemo(()=>tableColumns.map((column)=>column.field), [
11007
11563
  tableColumns
@@ -11023,7 +11579,8 @@ const DEFAULT_PAGE_LIMIT = 10000;
11023
11579
  };
11024
11580
  }, []);
11025
11581
  const cohortFilters = core.useCoreSelector((state)=>core.selectIndexFilters(state, index));
11026
- const { data, isLoading, isError, isFetching } = core.useGetRawDataAndTotalCountsQuery({
11582
+ const { xPosition, setXPosition } = React.useContext(TableXPositionContext);
11583
+ const { data, isLoading, isError, isFetching, isSuccess } = core.useGetRawDataAndTotalCountsQuery({
11027
11584
  type: index,
11028
11585
  fields: fields,
11029
11586
  filters: cohortFilters,
@@ -11079,12 +11636,17 @@ const DEFAULT_PAGE_LIMIT = 10000;
11079
11636
  onSortingChange: setSorting,
11080
11637
  enableTopToolbar: false,
11081
11638
  enableExpandAll: false,
11639
+ enableHiding: true,
11640
+ enableColumnActions: false,
11082
11641
  displayColumnDefOptions: {
11083
11642
  'mrt-row-expand': {
11084
11643
  enableHiding: true
11085
11644
  }
11086
11645
  },
11646
+ onColumnVisibilityChange: handleColumnVisibilityChange,
11087
11647
  enableExpanding: !!tableConfig?.detailsConfig,
11648
+ //enableColumnOrdering: tableConfig?.columnSorting,
11649
+ // enableHiding: tableConfig?.columnHiding,
11088
11650
  getRowId: getRowId(tableConfig),
11089
11651
  rowCount: totalRowCount,
11090
11652
  icons: TableIcons,
@@ -11135,9 +11697,8 @@ const DEFAULT_PAGE_LIMIT = 10000;
11135
11697
  showAlertBanner: isError,
11136
11698
  density: 'xs',
11137
11699
  rowSelection: rowSelection,
11138
- columnVisibility: {
11139
- 'mrt-row-expand': false
11140
- }
11700
+ columnVisibility: columnVisibility,
11701
+ columnOrder: columnOrder
11141
11702
  },
11142
11703
  mantineTableBodyRowProps: tableConfig.detailsConfig?.mode === 'click' ? ({ row })=>({
11143
11704
  onClick: ()=>{
@@ -11169,6 +11730,16 @@ const DEFAULT_PAGE_LIMIT = 10000;
11169
11730
  } else return null;
11170
11731
  } : undefined
11171
11732
  });
11733
+ const rowCount = table.getRowModel().rows.length;
11734
+ React.useLayoutEffect(()=>{
11735
+ if (setXPosition && xPosition === undefined && isSuccess && rowCount > 0 && ref.current) {
11736
+ setXPosition(ref?.current?.getBoundingClientRect()?.bottom);
11737
+ }
11738
+ }, [
11739
+ setXPosition,
11740
+ xPosition,
11741
+ rowCount
11742
+ ]);
11172
11743
  return /*#__PURE__*/ jsxRuntime.jsx(React.Fragment, {
11173
11744
  children: /*#__PURE__*/ jsxRuntime.jsxs(StudyProvider, {
11174
11745
  children: [
@@ -11186,11 +11757,25 @@ const DEFAULT_PAGE_LIMIT = 10000;
11186
11757
  accessibility
11187
11758
  }
11188
11759
  }),
11189
- /*#__PURE__*/ jsxRuntime.jsx("div", {
11190
- className: "inline-block overflow-x-scroll",
11191
- children: /*#__PURE__*/ jsxRuntime.jsx(mantineReactTable.MantineReactTable, {
11192
- table: table
11193
- })
11760
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
11761
+ className: "inline-block overflow-x-scroll ",
11762
+ ref: ref,
11763
+ children: [
11764
+ (tableConfig?.showTableHeaderControls || tableConfig.columnSorting || tableConfig?.columnHiding) && /*#__PURE__*/ jsxRuntime.jsx(TableHeader, {
11765
+ table: table,
11766
+ columnOrder: columnOrder,
11767
+ setColumnOrder: setColumnOrder,
11768
+ handleChange: handleSearchOrPageChange,
11769
+ additionalControls: additionalControls,
11770
+ tableTitle: tableTitle,
11771
+ tableTotalDetail: tableTotalDetail,
11772
+ showControls: tableConfig?.showTableHeaderControls,
11773
+ noColumnOrdering: Object.keys(lockedVisibility)
11774
+ }),
11775
+ /*#__PURE__*/ jsxRuntime.jsx(mantineReactTable.MantineReactTable, {
11776
+ table: table
11777
+ })
11778
+ ]
11194
11779
  })
11195
11780
  ]
11196
11781
  })
@@ -11402,16 +11987,19 @@ const useGuppyActionButton = ({ Modal403 = core.Modals.NoAccessModal, Modal400 =
11402
11987
  modal: Modal400,
11403
11988
  message: errorMessage
11404
11989
  }));
11990
+ console.error(error);
11405
11991
  } else if (errorMessage === 'Your token is invalid or expired. Please get a new token.') {
11406
11992
  dispatch(core.showModal({
11407
11993
  modal: Modal403,
11408
11994
  message: errorMessage
11409
11995
  }));
11996
+ console.error(error);
11410
11997
  } else {
11411
11998
  dispatch(core.showModal({
11412
11999
  modal: Modal400,
11413
12000
  message: customErrorMessage || errorMessage
11414
12001
  }));
12002
+ console.error(error);
11415
12003
  }
11416
12004
  }, [
11417
12005
  Modal400,
@@ -12525,6 +13113,7 @@ const JSONObjectDownloadButton = ({ getData, filename = 'data.json', icon = 'gen
12525
13113
  })
12526
13114
  });
12527
13115
  };
13116
+ JSONObjectDownloadButton.displayName = 'JSONObjectDownloadButton';
12528
13117
 
12529
13118
  const UploadJSONButton = ({ handleFileChange, tooltip, icon = 'gen3:upload' })=>{
12530
13119
  const [file, setFile] = React.useState(null);
@@ -13199,7 +13788,7 @@ const EmptyData = {};
13199
13788
  charts,
13200
13789
  chartsSection
13201
13790
  ]);
13202
- const { data: counts, isFetching: isCountsFetching, isSuccess: isCountSuccess, isError: isCountsError } = core.useGetCountsQuery({
13791
+ const { data: counts, isFetching: isCountsFetching, isError: isCountsError } = core.useGetCountsQuery({
13203
13792
  type: index,
13204
13793
  filters: cohortFilters,
13205
13794
  accessibility: accessLevel,
@@ -13822,53 +14411,341 @@ const TabbedCohortBuilder = ({ index, tabsConfiguration })=>{
13822
14411
  const facetDataHooks = useDeepCompare.useDeepCompareMemo(()=>{
13823
14412
  return {
13824
14413
  // TODO: see if there a better way to do this
13825
- enum: EnumHookInstances,
13826
- exact: EnumHookInstances,
13827
- multiselect: EnumHookInstances,
13828
- range: RangeHookInstances,
13829
- age: RangeHookInstances,
13830
- year: RangeHookInstances,
13831
- years: RangeHookInstances,
13832
- days: RangeHookInstances,
13833
- percent: RangeHookInstances,
13834
- datetime: RangeHookInstances,
13835
- toggle: RangeHookInstances,
13836
- upload: EnumHookInstances
14414
+ enum: EnumHookInstances,
14415
+ exact: EnumHookInstances,
14416
+ multiselect: EnumHookInstances,
14417
+ range: RangeHookInstances,
14418
+ age: RangeHookInstances,
14419
+ year: RangeHookInstances,
14420
+ years: RangeHookInstances,
14421
+ days: RangeHookInstances,
14422
+ percent: RangeHookInstances,
14423
+ datetime: RangeHookInstances,
14424
+ toggle: RangeHookInstances,
14425
+ upload: EnumHookInstances
14426
+ };
14427
+ }, [
14428
+ getEnumFacetData,
14429
+ getRangeFacetData,
14430
+ index
14431
+ ]);
14432
+ return /*#__PURE__*/ jsxRuntime.jsx(core$1.Stack, {
14433
+ gap: "xs",
14434
+ align: "stretch",
14435
+ classNames: {
14436
+ root: 'w-full'
14437
+ },
14438
+ children: /*#__PURE__*/ jsxRuntime.jsx(FacetTabs, {
14439
+ activeTab: activeTab,
14440
+ setActiveTab: setActiveTab,
14441
+ facetDefinitions: facetDefinitions,
14442
+ tabsConfig: tabsConfig,
14443
+ usedFacets: cohortBuilderFilters,
14444
+ hooks: facetDataHooks,
14445
+ customFacetHooks: {
14446
+ useCustomFacets,
14447
+ useAvailableCustomFacets: (usedFacets, onlyFiltersWithValues, queryOptions)=>({
14448
+ data: {},
14449
+ isSuccess: true
14450
+ }),
14451
+ useAddCustomFilter: ()=>(filter)=>{},
14452
+ useRemoveCustomFilter: ()=>(filter)=>{}
14453
+ },
14454
+ getFacetLabel: ()=>'Cases',
14455
+ cardScrollMargin: calculateStickyHeaderHeight(),
14456
+ useFieldNameToTitle: useFieldNameToTitle
14457
+ })
14458
+ });
14459
+ };
14460
+
14461
+ const useGetFacetValuesQuery = (args)=>{
14462
+ const { data, isSuccess, isFetching, isError } = core.useGetAggsQuery(args);
14463
+ return {
14464
+ data: data ?? {},
14465
+ isError,
14466
+ isFetching,
14467
+ isSuccess
14468
+ };
14469
+ };
14470
+ const buildFileStatsdQuery = (type, fileSizeField, cohortItemIdField, fileItemIdField)=>{
14471
+ const fileStatsQuery = `query repositoryTotals ($filter: JSON, $accessibility:Accessibility) {
14472
+ _aggregation {
14473
+ ${type} (accessibility: $accessibility, filter: $filter) {
14474
+ ${core.customQueryStrForField(fileItemIdField, '{_totalCount }')}
14475
+ ${core.customQueryStrForField(fileSizeField, ' { histogram {sum} }')}
14476
+ ${core.customQueryStrForField(cohortItemIdField, '{_cardinalityCount }')}
14477
+ }
14478
+ }
14479
+ }`;
14480
+ return fileStatsQuery;
14481
+ };
14482
+ const useTotalFileSizeQuery = ({ repositoryFilters, repositoryIndex, cohortIndex, fileSizeField, cohortItemIdField, fileItemIdField, accessibility = core.Accessibility.ALL })=>{
14483
+ const [totals, setTotals] = React.useState({
14484
+ totalFileSize: 0,
14485
+ totalCaseCount: 0,
14486
+ totalFileCount: 0
14487
+ });
14488
+ const query = buildFileStatsdQuery(repositoryIndex, fileSizeField, cohortItemIdField, fileItemIdField);
14489
+ const { data, isSuccess, isFetching, isError } = core.useGeneralGQLQuery({
14490
+ query,
14491
+ variables: {
14492
+ accessibility,
14493
+ filter: core.convertFilterSetToGqlFilter(repositoryFilters)
14494
+ }
14495
+ });
14496
+ useDeepCompare.useDeepCompareEffect(()=>{
14497
+ if (isSuccess) {
14498
+ const response = data.data;
14499
+ const totalFileSize = response?._aggregation?.[repositoryIndex]?.[fileSizeField]?.histogram?.[0]?.sum || 0;
14500
+ const totalCaseCount = response?._aggregation?.[repositoryIndex]?.[cohortItemIdField]?._cardinalityCount || 0;
14501
+ const totalFileCount = response?._aggregation?.[repositoryIndex]?.[fileItemIdField]?._totalCount || 0;
14502
+ setTotals({
14503
+ totalFileSize,
14504
+ totalCaseCount,
14505
+ totalFileCount
14506
+ });
14507
+ }
14508
+ }, [
14509
+ data,
14510
+ isSuccess
14511
+ ]);
14512
+ return {
14513
+ data: totals,
14514
+ isError,
14515
+ isFetching,
14516
+ isSuccess
14517
+ };
14518
+ };
14519
+
14520
+ const Stats = ({ totalCaseCount, totalFileSize, totalFileCount, isFetching })=>/*#__PURE__*/ jsxRuntime.jsxs("div", {
14521
+ className: "flex gap-1 text-xl items-center uppercase flex-wrap",
14522
+ children: [
14523
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
14524
+ children: [
14525
+ "Total of",
14526
+ ' ',
14527
+ /*#__PURE__*/ jsxRuntime.jsx("strong", {
14528
+ children: !isFetching ? totalFileCount.toLocaleString() : '--'
14529
+ }),
14530
+ ' ',
14531
+ totalFileCount !== 1 ? 'Files' : 'File'
14532
+ ]
14533
+ }),
14534
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
14535
+ children: [
14536
+ /*#__PURE__*/ jsxRuntime.jsx(md.MdPerson, {
14537
+ className: "ml-2 mr-1 mb-1 inline-block",
14538
+ "aria-hidden": "true"
14539
+ }),
14540
+ /*#__PURE__*/ jsxRuntime.jsx("strong", {
14541
+ className: "mr-1",
14542
+ children: totalCaseCount
14543
+ }),
14544
+ totalCaseCount !== 1 ? 'Cases' : 'Case'
14545
+ ]
14546
+ }),
14547
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
14548
+ children: [
14549
+ /*#__PURE__*/ jsxRuntime.jsx(md.MdSave, {
14550
+ className: "ml-2 mr-1 mb-1 inline-block",
14551
+ "aria-hidden": "true"
14552
+ }),
14553
+ filesize.filesize(totalFileSize)
14554
+ ]
14555
+ })
14556
+ ]
14557
+ });
14558
+
14559
+ const FileFacetPanel = ({ filters, index, tabTitle, fieldMapping })=>{
14560
+ const repositoryFilters = core.useCoreSelector((state)=>core.selectIndexFilters(state, index));
14561
+ const fields = React.useMemo(()=>getAllFieldsFromFilterConfigs(filters?.tabs ?? []), [
14562
+ filters?.tabs
14563
+ ]);
14564
+ const [accessLevel, setAccessLevel] = React.useState(core.Accessibility.ALL);
14565
+ const [facetDefinitions, setFacetDefinitions] = React.useState({});
14566
+ const { data: facetData, isSuccess: isFacetsQuerySuccess, isFetching: isFacetsQueryFetching, isError: isFacetsQueryError } = useGetFacetValuesQuery({
14567
+ type: index,
14568
+ fields: fields,
14569
+ filters: repositoryFilters
14570
+ });
14571
+ // Set the facet definitions based on the data only the first time the data is loaded
14572
+ useDeepCompare.useDeepCompareEffect(()=>{
14573
+ if (isFacetsQuerySuccess && Object.keys(facetDefinitions).length === 0) {
14574
+ const configFacetDefs = filters?.tabs.reduce((acc, tab)=>{
14575
+ return {
14576
+ ...tab.fieldsConfig,
14577
+ ...acc
14578
+ };
14579
+ }, {});
14580
+ const facetDefs = classifyFacets(facetData, index, fieldMapping ?? [], configFacetDefs ?? {});
14581
+ setFacetDefinitions(facetDefs);
14582
+ }
14583
+ }, [
14584
+ isFacetsQuerySuccess,
14585
+ facetData,
14586
+ facetDefinitions,
14587
+ index,
14588
+ fieldMapping
14589
+ ]);
14590
+ const getEnumFacetData = useDeepCompare.useDeepCompareCallback((field)=>{
14591
+ let filters = undefined;
14592
+ let combineMode = 'or';
14593
+ if (field in repositoryFilters.root) {
14594
+ if (core.isIntersection(repositoryFilters.root[field])) {
14595
+ const intersectionFilters = removeIntersectionFromEnum(repositoryFilters.root[field]);
14596
+ if (intersectionFilters) {
14597
+ filters = core.extractEnumFilterValue(intersectionFilters);
14598
+ combineMode = 'and';
14599
+ }
14600
+ } else {
14601
+ filters = core.extractEnumFilterValue(repositoryFilters.root[field]);
14602
+ }
14603
+ }
14604
+ return {
14605
+ data: processBucketData(facetData?.[field]),
14606
+ enumFilters: filters,
14607
+ combineMode: combineMode,
14608
+ isSuccess: isFacetsQuerySuccess,
14609
+ isFetching: isFacetsQueryFetching
14610
+ };
14611
+ }, [
14612
+ repositoryFilters.root,
14613
+ facetData,
14614
+ isFacetsQuerySuccess
14615
+ ]);
14616
+ const facetDataHooks = useDeepCompare.useDeepCompareMemo(()=>{
14617
+ return {
14618
+ // TODO: see if there a better way to do this
14619
+ enum: {
14620
+ useGetFacetData: getEnumFacetData,
14621
+ useUpdateFacetFilters: lodash.partial(useUpdateFilters$1, index),
14622
+ useGetFacetFilters: lodash.partial(useGetFacetFilters$1, index),
14623
+ useClearFilter: lodash.partial(useClearFilters$1, index),
14624
+ useFilterExpanded: lodash.partial(useFilterExpandedState$1, index),
14625
+ useToggleExpandFilter: lodash.partial(useToggleExpandFilter$1, index),
14626
+ useGetCombineMode: lodash.partial(useCohortFilterCombineState, index),
14627
+ useSetCombineMode: lodash.partial(useSetCohortFilterCombineState, index),
14628
+ useFieldNameToTitle: useFieldNameToTitle,
14629
+ useTotalCounts: undefined,
14630
+ useUpdateCombineMode: ()=>null
14631
+ }
13837
14632
  };
13838
14633
  }, [
13839
14634
  getEnumFacetData,
13840
- getRangeFacetData,
13841
14635
  index
13842
14636
  ]);
13843
- return /*#__PURE__*/ jsxRuntime.jsx(core$1.Stack, {
13844
- gap: "xs",
13845
- align: "stretch",
13846
- classNames: {
13847
- root: 'w-full'
14637
+ if (isFacetsQueryError) {
14638
+ return /*#__PURE__*/ jsxRuntime.jsx(ErrorCard, {
14639
+ message: "Unable to fetch data from server"
14640
+ }); // TODO: replace with configurable message
14641
+ }
14642
+ return /*#__PURE__*/ jsxRuntime.jsx(DropdownPanel, {
14643
+ index: index,
14644
+ filters: filters,
14645
+ facetDefinitions: facetDefinitions,
14646
+ facetDataHooks: facetDataHooks,
14647
+ showAccessLevel: false,
14648
+ tabTitle: tabTitle,
14649
+ onAccessChange: setAccessLevel,
14650
+ accessLevel: accessLevel
14651
+ });
14652
+ };
14653
+
14654
+ const RepositoryPanel = ({ guppyConfig, filters, table, dropdowns, buttons, loginForDownload, fileStatsConfiguration })=>{
14655
+ hooks.useMediaQuery('(min-width: 639px)');
14656
+ hooks.useMediaQuery('(min-width: 1373px)');
14657
+ hooks.useMediaQuery('(min-width: 1600px)');
14658
+ const [tableXPosition, setTableXPosition] = React.useState(undefined);
14659
+ const defaultDropdowns = React.useMemo(()=>dropdowns ?? {}, [
14660
+ dropdowns
14661
+ ]);
14662
+ const defaultButtons = React.useMemo(()=>buttons ?? [], [
14663
+ buttons
14664
+ ]);
14665
+ const [accessLevel, setAccessLevel] = React.useState(core.Accessibility.ALL);
14666
+ const index = guppyConfig.dataType;
14667
+ React.useMemo(()=>getAllFieldsFromFilterConfigs(filters?.tabs ?? []), [
14668
+ filters?.tabs
14669
+ ]);
14670
+ const repositoryFilters = core.useCoreSelector((state)=>core.selectIndexFilters(state, index));
14671
+ const { data: fileSizeSliceData, isFetching: isFileSizeFetching } = useTotalFileSizeQuery({
14672
+ repositoryFilters: repositoryFilters,
14673
+ ...fileStatsConfiguration
14674
+ });
14675
+ if (fileStatsConfiguration) return /*#__PURE__*/ jsxRuntime.jsx(TableXPositionContext.Provider, {
14676
+ value: {
14677
+ xPosition: tableXPosition,
14678
+ setXPosition: setTableXPosition
13848
14679
  },
13849
- children: /*#__PURE__*/ jsxRuntime.jsx(FacetTabs, {
13850
- activeTab: activeTab,
13851
- setActiveTab: setActiveTab,
13852
- facetDefinitions: facetDefinitions,
13853
- tabsConfig: tabsConfig,
13854
- usedFacets: cohortBuilderFilters,
13855
- hooks: facetDataHooks,
13856
- customFacetHooks: {
13857
- useCustomFacets,
13858
- useAvailableCustomFacets: (usedFacets, onlyFiltersWithValues, queryOptions)=>({
13859
- data: {},
13860
- isSuccess: true
14680
+ children: /*#__PURE__*/ jsxRuntime.jsx("div", {
14681
+ className: "flex flex-col mt-3 relative px-4 bg-base-lightest w-full",
14682
+ children: /*#__PURE__*/ jsxRuntime.jsxs("div", {
14683
+ className: "flex w-full pt-2",
14684
+ children: [
14685
+ /*#__PURE__*/ jsxRuntime.jsx("div", {
14686
+ id: "cohort-builder-filters",
14687
+ className: "flex-shrink-0 md:w-1/4 lg:w-1/5",
14688
+ children: filters?.tabs && /*#__PURE__*/ jsxRuntime.jsx(FileFacetPanel, {
14689
+ index: index,
14690
+ filters: filters,
14691
+ tabTitle: "Files",
14692
+ fieldMapping: guppyConfig?.fieldMapping ?? []
14693
+ })
13861
14694
  }),
13862
- useAddCustomFilter: ()=>(filter)=>{},
13863
- useRemoveCustomFilter: ()=>(filter)=>{}
13864
- },
13865
- getFacetLabel: ()=>'Cases',
13866
- cardScrollMargin: calculateStickyHeaderHeight(),
13867
- useFieldNameToTitle: useFieldNameToTitle
14695
+ /*#__PURE__*/ jsxRuntime.jsx("div", {
14696
+ id: "cohort-builder-content",
14697
+ className: "flex flex-col md:w-3/4 lg:w-4/5 pl-4",
14698
+ children: table?.enabled && /*#__PURE__*/ jsxRuntime.jsx(ExplorerTable, {
14699
+ index: index,
14700
+ tableConfig: table,
14701
+ accessibility: accessLevel,
14702
+ additionalControls: /*#__PURE__*/ jsxRuntime.jsx(DownloadsPanel, {
14703
+ dropdowns: defaultDropdowns,
14704
+ buttons: defaultButtons,
14705
+ loginForDownload: loginForDownload,
14706
+ index: index,
14707
+ totalCount: fileSizeSliceData.totalCaseCount ?? 0,
14708
+ fields: table?.fields ?? [],
14709
+ filter: repositoryFilters
14710
+ }),
14711
+ tableTotalDetail: /*#__PURE__*/ jsxRuntime.jsx("div", {
14712
+ className: "ml-auto",
14713
+ children: /*#__PURE__*/ jsxRuntime.jsx(Stats, {
14714
+ totalFileCount: fileSizeSliceData.totalFileCount,
14715
+ totalCaseCount: fileSizeSliceData.totalCaseCount,
14716
+ totalFileSize: fileSizeSliceData.totalFileSize,
14717
+ isFetching: isFileSizeFetching
14718
+ })
14719
+ })
14720
+ })
14721
+ })
14722
+ ]
14723
+ })
13868
14724
  })
13869
14725
  });
13870
14726
  };
13871
14727
 
14728
+ const validateObjectHasRequiredFields = (obj, requiredFields)=>requiredFields.every((field)=>obj[field] !== undefined);
14729
+
14730
+ const Repository = ({ filters, guppyConfig, table, buttons, loginForDownload, dropdowns, fileStatsConfiguration })=>{
14731
+ if (!fileStatsConfiguration || !validateObjectHasRequiredFields(fileStatsConfiguration, Object.keys(fileStatsConfiguration))) {
14732
+ return /*#__PURE__*/ jsxRuntime.jsx(MessagePage, {
14733
+ children: /*#__PURE__*/ jsxRuntime.jsx(ErrorCard, {
14734
+ message: "Invalid file stats configuration"
14735
+ })
14736
+ });
14737
+ }
14738
+ return /*#__PURE__*/ jsxRuntime.jsx(RepositoryPanel, {
14739
+ guppyConfig: guppyConfig,
14740
+ filters: filters,
14741
+ table: table,
14742
+ dropdowns: dropdowns,
14743
+ buttons: buttons,
14744
+ loginForDownload: loginForDownload,
14745
+ fileStatsConfiguration: fileStatsConfiguration
14746
+ }, "Repository-Panel");
14747
+ };
14748
+
13872
14749
  /**
13873
14750
  * Fetches graphql data from a graphql endpoint if one is specified, or guppy by default.
13874
14751
  * @param graphQLEndpoint - The location of the graphql endpoint.
@@ -15328,7 +16205,6 @@ var ContentSource$1 = ContentSource.getInstance();
15328
16205
  if (isHeaderMetadata(loadedHeaderMetadata)) {
15329
16206
  headerMetadata = loadedHeaderMetadata;
15330
16207
  } else {
15331
- console.log('loadedHeaderMetadata', loadedHeaderMetadata);
15332
16208
  console.warn('headerMetadata is not a valid HeaderMetadata object');
15333
16209
  }
15334
16210
  } catch (error) {
@@ -19390,6 +20266,428 @@ var CategoryPanel$1 = /*#__PURE__*/ React.memo(CategoryPanel, (prevProps, nextPr
19390
20266
  return prevProps.category === nextProps.category && selectedItems.node === prevProps.category && prevProps.selectedId === nextProps.selectedId && prevProps.scrollToSelection === nextProps.scrollToSelection;
19391
20267
  });
19392
20268
 
20269
+ /**
20270
+ * Get subgroup links from link
20271
+ * @param {object} link - array of links
20272
+ * @param {object} nameToNode - key (node name) value (node object) map
20273
+ * @param {string} sourceId - source id for subgroup links
20274
+ * This function traverse links recursively and return all nested subgroup lnks
20275
+ */ const getSubgroupLinks = (link, nameToNode, sourceId)=>{
20276
+ let subgroupLinks = [];
20277
+ if (link.subgroup) {
20278
+ link.subgroup.forEach((sgLink)=>{
20279
+ if (sgLink.subgroup) {
20280
+ subgroupLinks = subgroupLinks.concat(getSubgroupLinks(sgLink, nameToNode, sourceId));
20281
+ } else {
20282
+ subgroupLinks.push({
20283
+ source: nameToNode[sourceId],
20284
+ target: nameToNode[sgLink.target_type],
20285
+ exists: 1,
20286
+ ...sgLink
20287
+ });
20288
+ }
20289
+ });
20290
+ }
20291
+ return subgroupLinks;
20292
+ };
20293
+ /**
20294
+ * Given a data dictionary that defines a set of nodes
20295
+ * and edges, returns the nodes and edges in correct format
20296
+ *
20297
+ * @method createNodesAndEdges
20298
+ * @param props: Object (normally taken from redux state) that includes dictionary
20299
+ * property defining the dictionary as well as other optional properties
20300
+ * such as counts_search and links_search (created by getCounts) with
20301
+ * information about the number of each type (node) and link (between
20302
+ * nodes with a link's source and target types) that actually
20303
+ * exist in the data
20304
+ * @param createAll: Include all nodes and edges or only those that are populated in
20305
+ * counts_search and links_search
20306
+ * @param nodesToHide: Array of nodes to hide from graph
20307
+ * @returns { nodes, edges } Object containing nodes and edges
20308
+ */ function createNodesAndEdges(props, createAll, nodesToHide = [
20309
+ 'program'
20310
+ ]) {
20311
+ const { dictionary } = props;
20312
+ const nodes = Object.keys(dictionary).filter((key)=>!key.startsWith('_') && dictionary[key].type === 'object' && dictionary[key].category !== 'internal' && !nodesToHide.includes(key)).map((key)=>{
20313
+ let count = 0;
20314
+ if (props.counts_search) {
20315
+ count = props.counts_search[`_${key}_count`];
20316
+ }
20317
+ return {
20318
+ name: dictionary[key].title,
20319
+ count,
20320
+ ...dictionary[key]
20321
+ };
20322
+ }).filter((node)=>createAll);
20323
+ const nameToNode = nodes.reduce((db, node)=>{
20324
+ db[node.id] = node;
20325
+ return db;
20326
+ }, {});
20327
+ const hideDb = nodesToHide.reduce((db, name)=>{
20328
+ db[name] = true;
20329
+ return db;
20330
+ }, {});
20331
+ const edges = nodes.filter((node)=>node.links !== undefined && node.links.length > 0).reduce((list, node)=>{
20332
+ const newLinks = node.links.map((link)=>({
20333
+ source: node,
20334
+ target: nameToNode[link.target_type],
20335
+ exists: 1,
20336
+ ...link
20337
+ }));
20338
+ return list.concat(newLinks);
20339
+ }, []).reduce((list, link)=>{
20340
+ let result = list;
20341
+ if (link.target) {
20342
+ result.push(link);
20343
+ }
20344
+ if (link.subgroup) {
20345
+ const sgLinks = getSubgroupLinks(link, nameToNode, link.source.id);
20346
+ result = result.concat(sgLinks);
20347
+ }
20348
+ return result;
20349
+ }, []).filter(// target type exist and is not in hide list
20350
+ (link)=>link.target && link.target.id in nameToNode && !(link.target.id in hideDb)).map((link)=>{
20351
+ // decorate each link with its "exists" count if available
20352
+ // (number of instances of link between source and target types in the data)
20353
+ const res = link;
20354
+ res.exists = props.links_search ? props.links_search[`${res.source.id}_${res.name}_to_${res.target.id}_link`] : 0;
20355
+ return res;
20356
+ }).filter(// filter out if no instances of this link exists and createAll is not specified
20357
+ (link)=>createAll);
20358
+ return {
20359
+ nodes,
20360
+ edges
20361
+ };
20362
+ }
20363
+ /**
20364
+ * Find the root of the given graph (no edges out)
20365
+ * @method findRoot
20366
+ * @param nodes
20367
+ * @param edges
20368
+ * @return {string} rootName or null if no root
20369
+ */ function findRoot(nodes, edges) {
20370
+ const couldBeRoot = edges.reduce((db, edge)=>{
20371
+ // At some point the d3 force layout converts
20372
+ // edge.source and edge.target into node references ...
20373
+ const sourceName = typeof edge.source === 'object' ? edge.source.id : edge.source;
20374
+ if (db[sourceName]) {
20375
+ db[sourceName] = false;
20376
+ }
20377
+ return db;
20378
+ }, // initialize emptyDb - any node could be the root
20379
+ nodes.reduce((emptyDb, node)=>{
20380
+ const res = emptyDb;
20381
+ res[node.id] = true;
20382
+ return res;
20383
+ }, {}));
20384
+ const rootNode = nodes.find((n)=>couldBeRoot[n.id]);
20385
+ return rootNode ? rootNode.id : null;
20386
+ }
20387
+ /**
20388
+ * Recursive helper function for getTreeHierarchy
20389
+ * Returns the hierarchy of the tree in the form of a map
20390
+ * Each (key, value) consists of (node, node's descendants including the node itself)
20391
+ * @method getTreeHierarchyHelper
20392
+ * @param root
20393
+ * @param name2EdgesIn
20394
+ * @param hierarchy
20395
+ * @return {map}
20396
+ */ function getTreeHierarchyHelper(node, name2EdgesIn, hierarchy) {
20397
+ const descendants = new Set();
20398
+ descendants.add(node);
20399
+ hierarchy.set(node, descendants);
20400
+ name2EdgesIn[node].forEach((edge)=>{
20401
+ const sourceName = typeof edge.source === 'object' ? edge.source.id : edge.source;
20402
+ if (!hierarchy.get(sourceName)) {
20403
+ hierarchy = getTreeHierarchyHelper(sourceName, name2EdgesIn, hierarchy);
20404
+ descendants.add(sourceName);
20405
+ hierarchy.get(sourceName).forEach((n)=>{
20406
+ descendants.add(n);
20407
+ });
20408
+ }
20409
+ });
20410
+ hierarchy.set(node, descendants);
20411
+ return hierarchy;
20412
+ }
20413
+ /**
20414
+ * Returns the hierarchy of the tree in the form of a map
20415
+ * Each (key, value) consists of (node, node's descendants including the node itself)
20416
+ * @method getTreeHierarchy
20417
+ * @param root
20418
+ * @param name2EdgesIn
20419
+ * @return {map}
20420
+ */ function getTreeHierarchy(root, name2EdgesIn) {
20421
+ return getTreeHierarchyHelper(root, name2EdgesIn, new Map());
20422
+ }
20423
+ /**
20424
+ * Arrange nodes in dictionary graph breadth first, and build level database.
20425
+ * If a node links to multiple parents, then place it under the highest parent ...
20426
+ * Exported for testing.
20427
+ *
20428
+ * @param {Array} nodes
20429
+ * @param {Array} edges
20430
+ * @return { nodesBreadthFirst, treeLevel2Names, name2Level } where
20431
+ * nodesBreadthFirst is array of node names, and
20432
+ * treeLevel2Names is an array of arrays of node names,
20433
+ * and name2Level is a mapping of node name to level
20434
+ */ function nodesBreadthFirst(nodes, edges) {
20435
+ const result = {
20436
+ bfOrder: [],
20437
+ treeLevel2Names: [],
20438
+ name2Level: {}
20439
+ };
20440
+ // mapping of node name to edges that point into that node
20441
+ const name2EdgesIn = edges.reduce((db, edge)=>{
20442
+ // At some point the d3 force layout converts edge.source
20443
+ // and edge.target into node references ...
20444
+ const targetName = typeof edge.target === 'object' ? edge.target.id : edge.target;
20445
+ if (db[targetName]) {
20446
+ db[targetName].push(edge);
20447
+ } else {
20448
+ console.error(`Edge points to unknown node: ${targetName}`);
20449
+ }
20450
+ return db;
20451
+ }, // initialize emptyDb - include nodes that have no incoming edges (leaves)
20452
+ nodes.reduce((emptyDb, node)=>{
20453
+ const res = emptyDb;
20454
+ res[node.id] = [];
20455
+ return res;
20456
+ }, {}));
20457
+ // root node has no edges coming out of it, just edges coming in
20458
+ const root = findRoot(nodes, edges);
20459
+ if (!root) {
20460
+ console.log('Could not find root of given graph');
20461
+ return result;
20462
+ }
20463
+ const processedNodes = new Set(); // account for nodes that link to multiple other nodes
20464
+ let queue = [];
20465
+ queue.push({
20466
+ query: root,
20467
+ level: 0
20468
+ });
20469
+ // just 2b safe - could be user gives us a graph without a 'project'
20470
+ if (!name2EdgesIn[root]) {
20471
+ name2EdgesIn[root] = [];
20472
+ }
20473
+ const name2ActualLvl = {};
20474
+ const hierarchy = getTreeHierarchy(root, name2EdgesIn);
20475
+ // Run through this once to determine the actual level of each node
20476
+ for(let head = 0; head < queue.length; head += 1){
20477
+ const { query, level } = queue[head]; // breadth first
20478
+ name2ActualLvl[query] = level;
20479
+ name2EdgesIn[query].forEach((edge)=>{
20480
+ // At some point the d3 force layout converts edge.source
20481
+ // and edge.target into node references ...
20482
+ const sourceName = typeof edge.source === 'object' ? edge.source.id : edge.source;
20483
+ if (name2EdgesIn[sourceName]) {
20484
+ const isAncestor = hierarchy.get(sourceName).has(query);
20485
+ // only push node if it is not an ancestor of the current node, or else --> cycle
20486
+ if (!isAncestor) {
20487
+ queue.push({
20488
+ query: sourceName,
20489
+ level: level + 1
20490
+ });
20491
+ }
20492
+ } else {
20493
+ console.log(`Edge comes from unknown node ${sourceName}`);
20494
+ }
20495
+ });
20496
+ }
20497
+ // Reset and run for real
20498
+ queue = [];
20499
+ queue.push({
20500
+ query: root,
20501
+ level: 0
20502
+ });
20503
+ // queue.shift is O(n), so just keep pushing, and move the head
20504
+ for(let head = 0; head < queue.length; head += 1){
20505
+ const { query, level } = queue[head]; // breadth first
20506
+ result.bfOrder.push(query);
20507
+ processedNodes.add(query);
20508
+ if (result.treeLevel2Names.length <= level) {
20509
+ result.treeLevel2Names.push([]);
20510
+ }
20511
+ result.treeLevel2Names[level].push(query);
20512
+ result.name2Level[query] = level;
20513
+ name2EdgesIn[query].forEach((edge)=>{
20514
+ // At some point the d3 force layout converts edge.source
20515
+ // and edge.target into node references ...
20516
+ const sourceName = typeof edge.source === 'object' ? edge.source.id : edge.source;
20517
+ if (name2EdgesIn[sourceName]) {
20518
+ if (!processedNodes.has(sourceName) && name2ActualLvl[sourceName] === level + 1) {
20519
+ //
20520
+ // edge source has not yet been processed via another link from the source
20521
+ // to a node higher in the graph
20522
+ //
20523
+ processedNodes.add(sourceName); // don't double-queue a node
20524
+ queue.push({
20525
+ query: sourceName,
20526
+ level: level + 1
20527
+ });
20528
+ }
20529
+ } else {
20530
+ console.log(`Edge comes from unknown node ${sourceName}`);
20531
+ }
20532
+ });
20533
+ }
20534
+ return result;
20535
+ }
20536
+ const placeNodesOnGraph = (treeLevel2Names, nodesById)=>{
20537
+ let currentX = 0;
20538
+ let currentY = 0;
20539
+ const xSpacing = 300;
20540
+ const ySpacing = 100;
20541
+ const positions = [];
20542
+ treeLevel2Names.forEach((level)=>{
20543
+ level.forEach((id)=>{
20544
+ positions.push({
20545
+ id: id,
20546
+ name: nodesById[id].name,
20547
+ x: currentX,
20548
+ y: currentY
20549
+ });
20550
+ currentY += ySpacing;
20551
+ });
20552
+ currentY = 0;
20553
+ currentX += xSpacing;
20554
+ });
20555
+ return positions;
20556
+ };
20557
+ const linksForGraph = (edges)=>{
20558
+ return edges.map((edge)=>{
20559
+ return {
20560
+ source: edge.source.id,
20561
+ target: edge.target.id
20562
+ };
20563
+ });
20564
+ };
20565
+ //TODO posably get this from somewhere else
20566
+ // object of nodes by ID for easy lookup
20567
+ const getNodesById = (nodes)=>{
20568
+ return nodes.reduce((db, node)=>{
20569
+ db[node.id] = node;
20570
+ return db;
20571
+ }, {});
20572
+ };
20573
+ const formatDataForGraph = (categories)=>{
20574
+ //TODO cash all this unchanging data
20575
+ const { nodes, edges } = createNodesAndEdges({
20576
+ dictionary: categories
20577
+ }, true, []);
20578
+ const nodeTree = nodesBreadthFirst(nodes, edges);
20579
+ console.log('nodes edges', nodes, edges);
20580
+ console.log('nodesBreadthFirst', nodeTree);
20581
+ const nodesById = getNodesById(nodes);
20582
+ const graphData = placeNodesOnGraph(nodeTree.treeLevel2Names, nodesById);
20583
+ console.log('placeNodesOnGraph', graphData);
20584
+ const graphLinks = linksForGraph(edges);
20585
+ console.log('linksForGraph', graphLinks);
20586
+ return {
20587
+ data: graphData,
20588
+ links: graphLinks
20589
+ };
20590
+ };
20591
+
20592
+ const GraphView = ({ categories, dictionary, selectedId })=>{
20593
+ const [zoomLevel, setZoomLevel] = React.useState(0); // TODO Start here for zoom level
20594
+ const dataAndLinks = formatDataForGraph(dictionary);
20595
+ console.log('GraphView dictionary', dictionary);
20596
+ console.log('GraphView categories', categories);
20597
+ console.log('GraphView selectedId', selectedId);
20598
+ const chartDefinition = React.useMemo(()=>{
20599
+ return {
20600
+ tooltip: {
20601
+ trigger: 'item',
20602
+ triggerOn: 'mousemove'
20603
+ },
20604
+ toolbox: {
20605
+ show: true,
20606
+ left: 'left',
20607
+ orient: 'vertical',
20608
+ itemSize: 30,
20609
+ iconStyle: {
20610
+ borderWidth: 0,
20611
+ opacity: 0.8
20612
+ },
20613
+ emphasis: {
20614
+ iconStyle: {
20615
+ opacity: 1,
20616
+ color: '#3283c8'
20617
+ }
20618
+ },
20619
+ feature: {
20620
+ restore: {
20621
+ show: true,
20622
+ title: 'Reset',
20623
+ icon: 'image://data:image/gif;base64,R0lGODlhHgAeAKEAADKDyP///zKDyDKDyCH5BAEKAAIALAAAAAAeAB4AAAJChI+py+0Powm02irP3TRPfnkAJjZkuZxooq5a57Jw/AY00sY5lO+PjwKWhCKix5hBSpQRJm+2BFmKUueoCr1pt5ICADs='
20624
+ },
20625
+ myZoomIn: {
20626
+ show: true,
20627
+ title: 'Zoom In',
20628
+ icon: 'image://data:image/gif;base64,R0lGODlhHgAeAKEAADKDyP///zKDyDKDyCH5BAEKAAIALAAAAAAeAB4AAAJAhI+py+0PIww0yFnvq1Y37n1ZuICkYp5Iqhps+27cTNfdauc0qvcU79NpYiciyRhCepTDUcvlfDIvU0n1ic2GCgA7',
20629
+ onclick: (params)=>{
20630
+ const series = params?.option?.series;
20631
+ const zoom = series && series[0] ? series[0].zoom : 1;
20632
+ setZoomLevel((zoom || 1) + 0.1);
20633
+ }
20634
+ },
20635
+ myZoomOut: {
20636
+ show: true,
20637
+ title: 'Zoom Out',
20638
+ icon: 'image://data:image/gif;base64,R0lGODlhHgAeAKEAADKDyP///zKDyDKDyCH5BAEKAAIALAAAAAAeAB4AAAIohI+py+0Po5y02ouz3rz7PwXiSJbmqJzqmq4u2b4vSNf2jef6zvd1AQA7',
20639
+ onclick: (params)=>{
20640
+ const series = params?.option?.series;
20641
+ const zoom = series && series[0] ? series[0].zoom : 1;
20642
+ setZoomLevel((zoom || 1) - 0.1);
20643
+ }
20644
+ }
20645
+ }
20646
+ },
20647
+ //https://echarts.apache.org/en/option.html#legend
20648
+ series: {
20649
+ type: 'graph',
20650
+ roam: true,
20651
+ zoom: zoomLevel,
20652
+ label: {
20653
+ show: true,
20654
+ position: 'right',
20655
+ backgroundColor: 'white'
20656
+ },
20657
+ symbol: 'circle',
20658
+ emphasis: {
20659
+ focus: 'adjacency'
20660
+ },
20661
+ //edgeSymbol: ['circle', 'circle'],
20662
+ //edgeSymbolSize: [4, 4],
20663
+ lineStyle: {
20664
+ opacity: 0.9,
20665
+ width: 2,
20666
+ curveness: 0,
20667
+ cap: 'square'
20668
+ },
20669
+ //https://echarts.apache.org/en/option.html#series-tree.data
20670
+ data: dataAndLinks.data,
20671
+ links: dataAndLinks.links,
20672
+ top: '10%',
20673
+ left: '5%'
20674
+ }
20675
+ };
20676
+ }, [
20677
+ dataAndLinks,
20678
+ zoomLevel
20679
+ ]);
20680
+ //TODO: import real data
20681
+ //TODO: connections between nodes
20682
+ //TODO: ZOOM IN AND OUT AND MOVE AROUND controls?
20683
+ return /*#__PURE__*/ jsxRuntime.jsx("div", {
20684
+ className: "w-full h-full min-h-[800px]",
20685
+ children: /*#__PURE__*/ jsxRuntime.jsx(ReactECharts, {
20686
+ option: chartDefinition
20687
+ })
20688
+ });
20689
+ };
20690
+
19393
20691
  const Dictionary = ()=>{
19394
20692
  const [selectedId, setSelectedId] = React.useState('');
19395
20693
  const [view, setView] = React.useState('table');
@@ -19408,6 +20706,11 @@ const Dictionary = ()=>{
19408
20706
  scrollIntoView,
19409
20707
  targetRef
19410
20708
  ]);
20709
+ const categoryPanelTable = Object.keys(categories).length && Object.keys(categories).map((category)=>/*#__PURE__*/ jsxRuntime.jsx(CategoryPanel$1, {
20710
+ category: category,
20711
+ selectedId: selectedId,
20712
+ scrollToSelection: scrollToSelection
20713
+ }, category));
19411
20714
  return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
19412
20715
  children: [
19413
20716
  /*#__PURE__*/ jsxRuntime.jsx("div", {
@@ -19448,11 +20751,26 @@ const Dictionary = ()=>{
19448
20751
  ref: scrollableRef,
19449
20752
  children: /*#__PURE__*/ jsxRuntime.jsx("div", {
19450
20753
  className: "h-full",
19451
- children: Object.keys(categories).length && Object.keys(categories).map((category)=>/*#__PURE__*/ jsxRuntime.jsx(CategoryPanel$1, {
19452
- category: category,
19453
- selectedId: selectedId,
19454
- scrollToSelection: scrollToSelection
19455
- }, category))
20754
+ children: config?.showGraph ? /*#__PURE__*/ jsxRuntime.jsxs(core$1.Tabs, {
20755
+ value: view,
20756
+ keepMounted: false,
20757
+ className: "h-full",
20758
+ children: [
20759
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Tabs.Panel, {
20760
+ value: "table",
20761
+ children: categoryPanelTable
20762
+ }),
20763
+ /*#__PURE__*/ jsxRuntime.jsx(core$1.Tabs.Panel, {
20764
+ value: "graph",
20765
+ className: "h-full",
20766
+ children: /*#__PURE__*/ jsxRuntime.jsx(GraphView, {
20767
+ categories: categories,
20768
+ dictionary: dictionary,
20769
+ selectedId: selectedId
20770
+ })
20771
+ })
20772
+ ]
20773
+ }) : categoryPanelTable
19456
20774
  })
19457
20775
  })
19458
20776
  ]
@@ -20519,7 +21837,7 @@ const GetSharedFieldMapping = async (cohortBuilderConfiguration)=>{
20519
21837
  }
20520
21838
  return sharedFiltersMap;
20521
21839
  };
20522
- const DefaultAccessControlConfiguration = {
21840
+ const DefaultAccessControlConfiguration$1 = {
20523
21841
  dataMode: GuppyDataAccessMode.REGULAR,
20524
21842
  tierLimit: -1,
20525
21843
  showAccessLevelControl: false
@@ -20547,7 +21865,7 @@ const ExplorerPageGetServerSideProps = async ()=>{
20547
21865
  explorerConfig: cohortBuilderConfiguration.explorerConfig,
20548
21866
  // headerMetadata: cohortBuilderConfiguration.headerMetadata,
20549
21867
  accessControl: {
20550
- ...DefaultAccessControlConfiguration,
21868
+ ...DefaultAccessControlConfiguration$1,
20551
21869
  ...cohortBuilderConfiguration.accessControl ?? {}
20552
21870
  }
20553
21871
  }
@@ -20588,7 +21906,7 @@ const ExplorerPageGetServerSidePropsForConfigId = async (context)=>{
20588
21906
  explorerConfig: cohortBuilderConfiguration.explorerConfig,
20589
21907
  // headerMetadata: { ...(cohortBuilderConfiguration?.headerMetadata ? cohortBuilderConfiguration.headerMetadata : {}) },
20590
21908
  accessControl: {
20591
- ...DefaultAccessControlConfiguration,
21909
+ ...DefaultAccessControlConfiguration$1,
20592
21910
  ...cohortBuilderConfiguration.accessControl ?? {}
20593
21911
  }
20594
21912
  }
@@ -25971,6 +27289,65 @@ const TabbedCohortBuilderPageGetServerSideProps = async ()=>{
25971
27289
  }
25972
27290
  };
25973
27291
 
27292
+ const RepositoryPage = ({ headerProps, footerProps, configuration, headerMetadata })=>{
27293
+ if (configuration === undefined) {
27294
+ return /*#__PURE__*/ jsxRuntime.jsx(core$1.Center, {
27295
+ maw: 400,
27296
+ h: 100,
27297
+ mx: "auto",
27298
+ children: /*#__PURE__*/ jsxRuntime.jsx("div", {
27299
+ children: "Repository config is not defined. Page disabled"
27300
+ })
27301
+ });
27302
+ }
27303
+ console.log('RepositoryPage', configuration);
27304
+ return /*#__PURE__*/ jsxRuntime.jsx(NavPageLayout, {
27305
+ headerProps,
27306
+ footerProps,
27307
+ headerMetadata: {
27308
+ title: 'Gen3 Repository Page',
27309
+ content: 'Repository Page',
27310
+ key: 'gen3-repository-page',
27311
+ ...headerMetadata ? headerMetadata : {},
27312
+ ...configuration?.headerMetadata ? configuration.headerMetadata : {}
27313
+ },
27314
+ children: /*#__PURE__*/ jsxRuntime.jsx(Repository, {
27315
+ ...configuration
27316
+ })
27317
+ });
27318
+ };
27319
+
27320
+ const DefaultAccessControlConfiguration = {
27321
+ dataMode: GuppyDataAccessMode.REGULAR,
27322
+ tierLimit: -1,
27323
+ showAccessLevelControl: false
27324
+ };
27325
+ const RepositoryPageGetServerSideProps = async ()=>{
27326
+ try {
27327
+ const repositoryConfiguration = await ContentSource$1.getContentDatabase().get(`${core.GEN3_COMMONS_NAME}/repository.json`);
27328
+ return {
27329
+ props: {
27330
+ ...await getNavPageLayoutPropsFromConfig(),
27331
+ configuration: repositoryConfiguration,
27332
+ // headerMetadata: cohortBuilderConfiguration.headerMetadata,
27333
+ accessControl: {
27334
+ ...DefaultAccessControlConfiguration
27335
+ }
27336
+ }
27337
+ };
27338
+ } catch (err) {
27339
+ if (err instanceof Error) {
27340
+ console.warn('Explorer config cannot be read', err);
27341
+ }
27342
+ return {
27343
+ props: {
27344
+ ...await getNavPageLayoutPropsFromConfig(),
27345
+ configuration: undefined
27346
+ }
27347
+ };
27348
+ }
27349
+ };
27350
+
25974
27351
  const TailwindConfig = (themer)=>{
25975
27352
  return {
25976
27353
  important: '#__next',
@@ -26463,6 +27840,7 @@ exports.DiscoveryIndexPanel = DiscoveryIndexPanel;
26463
27840
  exports.DiscoveryPage = DiscoveryPage;
26464
27841
  exports.DiscoveryPageGetServerSideProps = DiscoveryPageGetServerSideProps;
26465
27842
  exports.DiscoveryRowRendererFactory = DiscoveryRowRendererFactory;
27843
+ exports.DownloadButton = DownloadButton;
26466
27844
  exports.DropdownButton = DropdownButton;
26467
27845
  exports.DropdownPanel = DropdownPanel;
26468
27846
  exports.DropdownWithIcon = DropdownWithIcon;
@@ -26491,6 +27869,7 @@ exports.Gen3Provider = Gen3Provider;
26491
27869
  exports.GqlQueryEditor = GqlQueryEditor$1;
26492
27870
  exports.Header = Header$1;
26493
27871
  exports.HoverLink = HoverLink;
27872
+ exports.JSONObjectDownloadButton = JSONObjectDownloadButton;
26494
27873
  exports.LandingPage = LandingPage;
26495
27874
  exports.LandingPageGetServerSideProps = LandingPageGetServerSideProps;
26496
27875
  exports.LoginButton = LoginButton$1;
@@ -26517,6 +27896,9 @@ exports.QueryPage = QueryPage;
26517
27896
  exports.QueryPageGetServerSideProps = QueryPageGetServerSideProps;
26518
27897
  exports.RangeFacet = RangeFacet;
26519
27898
  exports.ReactECharts = ReactECharts;
27899
+ exports.Repository = Repository;
27900
+ exports.RepositoryPage = RepositoryPage;
27901
+ exports.RepositoryPageGetServerSideProps = RepositoryPageGetServerSideProps;
26520
27902
  exports.ResourcesFilters = ResourcesFilters;
26521
27903
  exports.SPECIAL_CASE_FIELDS = SPECIAL_CASE_FIELDS;
26522
27904
  exports.SegmentedControl = SegmentedControl;
@@ -26534,6 +27916,7 @@ exports.TabbedCohortBuilder = TabbedCohortBuilder;
26534
27916
  exports.TabbedCohortBuilderPage = TabbedCohortBuilderPage;
26535
27917
  exports.TabbedCohortBuilderPageGetServerSideProps = TabbedCohortBuilderPageGetServerSideProps;
26536
27918
  exports.TabbedPanel = TabbedPanel;
27919
+ exports.TableXPositionContext = TableXPositionContext;
26537
27920
  exports.TagCloud = TagCloud;
26538
27921
  exports.TailwindConfig = TailwindConfig;
26539
27922
  exports.TopBar = TopBar;
@@ -26569,6 +27952,8 @@ exports.filterAggregationsDataKeys = filterAggregationsDataKeys;
26569
27952
  exports.focusStyles = focusStyles;
26570
27953
  exports.getAllFieldsFromFilterConfigs = getAllFieldsFromFilterConfigs;
26571
27954
  exports.getCurrentUnixTimestamp = getCurrentUnixTimestamp;
27955
+ exports.getFormattedTimestamp = getFormattedTimestamp;
27956
+ exports.getHighResolutionTimestamp = getHighResolutionTimestamp;
26572
27957
  exports.getNavPageLayoutPropsFromConfig = getNavPageLayoutPropsFromConfig;
26573
27958
  exports.getParamsValueAsString = getParamsValueAsString;
26574
27959
  exports.getTagInfo = getTagInfo;
@@ -26578,7 +27963,9 @@ exports.isEnumFacetResponse = isEnumFacetResponse;
26578
27963
  exports.isHeaderMetadata = isHeaderMetadata;
26579
27964
  exports.isPropertyKey = isPropertyKey;
26580
27965
  exports.isTextTransform = isTextTransform$1;
27966
+ exports.isTimeGreaterThan = isTimeGreaterThan;
26581
27967
  exports.mapFacetSortToSortType = mapFacetSortToSortType;
27968
+ exports.measureExecutionTime = measureExecutionTime;
26582
27969
  exports.processBucketData = processBucketData;
26583
27970
  exports.processLabel = processLabel$1;
26584
27971
  exports.processRangeData = processRangeData;