@gen3/frontend 0.10.95 → 0.10.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +1698 -587
- package/dist/cjs/index.js.map +1 -1
- package/dist/dts/components/Content/LandingPageContent.d.ts +2 -1
- package/dist/dts/components/Content/LandingPageContent.d.ts.map +1 -1
- package/dist/dts/components/Content/LandingPageContent.js.map +1 -1
- package/dist/dts/components/Login/LoginPanel.d.ts.map +1 -1
- package/dist/dts/components/Login/LoginPanel.js +1 -0
- package/dist/dts/components/Login/LoginPanel.js.map +1 -1
- package/dist/dts/components/Login/types.d.ts +2 -1
- package/dist/dts/components/Login/types.d.ts.map +1 -1
- package/dist/dts/components/Login/types.js.map +1 -1
- package/dist/dts/components/MessageCards/index.d.ts +2 -1
- package/dist/dts/components/MessageCards/index.d.ts.map +1 -1
- package/dist/dts/components/MessageCards/index.js +2 -1
- package/dist/dts/components/MessageCards/index.js.map +1 -1
- package/dist/dts/components/Profile/types.d.ts +2 -1
- package/dist/dts/components/Profile/types.d.ts.map +1 -1
- package/dist/dts/components/charts/Charts.d.ts.map +1 -1
- package/dist/dts/components/charts/Charts.js +2 -0
- package/dist/dts/components/charts/Charts.js.map +1 -1
- package/dist/dts/components/charts/echarts/HorizontalBarChart.d.ts +1 -1
- package/dist/dts/components/charts/echarts/HorizontalBarChart.d.ts.map +1 -1
- package/dist/dts/components/charts/echarts/HorizontalBarChart.js +3 -2
- package/dist/dts/components/charts/echarts/HorizontalBarChart.js.map +1 -1
- package/dist/dts/components/charts/types.d.ts +2 -0
- package/dist/dts/components/charts/types.d.ts.map +1 -1
- package/dist/dts/components/facets/FacetControlsHeader.d.ts.map +1 -1
- package/dist/dts/components/facets/FacetControlsHeader.js +1 -1
- package/dist/dts/components/facets/FacetControlsHeader.js.map +1 -1
- package/dist/dts/components/facets/FacetSelector.d.ts.map +1 -1
- package/dist/dts/components/facets/FacetSelector.js +6 -6
- package/dist/dts/components/facets/FacetSelector.js.map +1 -1
- package/dist/dts/features/Analysis/AnalysisCardCompact.stories.d.ts +6 -6
- package/dist/dts/features/Analysis/types.d.ts +2 -1
- package/dist/dts/features/Analysis/types.d.ts.map +1 -1
- package/dist/dts/features/Analysis/types.js.map +1 -1
- package/dist/dts/features/CohortBuilder/CohortBuilder.d.ts.map +1 -1
- package/dist/dts/features/CohortBuilder/CohortBuilder.js +1 -2
- package/dist/dts/features/CohortBuilder/CohortBuilder.js.map +1 -1
- package/dist/dts/features/CohortBuilder/ExplorerTable/ArrayCellRenderer.d.ts +1 -1
- package/dist/dts/features/CohortBuilder/QueryExpression/QueryExpressionSection.js +1 -1
- package/dist/dts/features/CohortBuilder/QueryExpression/QueryExpressionSection.js.map +1 -1
- package/dist/dts/features/CohortBuilder/types.d.ts +2 -2
- package/dist/dts/features/CohortBuilder/types.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/ActionButtons/ActionButtonGroup.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/ActionButtons/ActionButtonGroup.js +18 -2
- package/dist/dts/features/CohortDiscovery/ActionButtons/ActionButtonGroup.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/ActionButtons/SaveActionButton.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/ActionButtons/SaveActionButton.js +10 -4
- package/dist/dts/features/CohortDiscovery/ActionButtons/SaveActionButton.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/ChartsAndFacetsPanel.js +2 -2
- package/dist/dts/features/CohortDiscovery/ChartsAndFacetsPanel.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortDiscovery.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortDiscovery.js +8 -3
- package/dist/dts/features/CohortDiscovery/CohortDiscovery.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManager.d.ts +5 -2
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManager.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManager.js +120 -44
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManager.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSelectors.d.ts +44 -0
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSelectors.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSelectors.js +7 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSelectors.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSlice.d.ts +3 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSlice.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSlice.js +71 -24
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortManagerSlice.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortStorage.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortStorage.js +0 -2
- package/dist/dts/features/CohortDiscovery/CohortManagment/CohortStorage.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortQueryExpression.d.ts +6 -0
- package/dist/dts/features/CohortDiscovery/CohortQueryExpression.d.ts.map +1 -0
- package/dist/dts/features/CohortDiscovery/CohortQueryExpression.js +55 -0
- package/dist/dts/features/CohortDiscovery/CohortQueryExpression.js.map +1 -0
- package/dist/dts/features/CohortDiscovery/CohortSelectors.d.ts +0 -22
- package/dist/dts/features/CohortDiscovery/CohortSelectors.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortSelectors.js +40 -34
- package/dist/dts/features/CohortDiscovery/CohortSelectors.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortSlice.d.ts +0 -90
- package/dist/dts/features/CohortDiscovery/CohortSlice.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/CohortSlice.js +161 -92
- package/dist/dts/features/CohortDiscovery/CohortSlice.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/FacetSelectionPanel.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/FacetSelectionPanel.js +1 -1
- package/dist/dts/features/CohortDiscovery/FacetSelectionPanel.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/FilterPanels/EnumFacetPanel.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/FilterPanels/EnumFacetPanel.js +5 -3
- package/dist/dts/features/CohortDiscovery/FilterPanels/EnumFacetPanel.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/IndexPanel.d.ts +1 -1
- package/dist/dts/features/CohortDiscovery/IndexPanel.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/IndexPanel.js +8 -8
- package/dist/dts/features/CohortDiscovery/IndexPanel.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/RequestManagerSlice.d.ts +14 -28
- package/dist/dts/features/CohortDiscovery/RequestManagerSlice.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/RequestManagerSlice.js +4 -4
- package/dist/dts/features/CohortDiscovery/RequestManagerSlice.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/DataAccessRequestForm.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/DataAccessRequestForm.js +4 -10
- package/dist/dts/features/CohortDiscovery/Requests/DataAccessRequestForm.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/RequestsPanel.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/RequestsPanel.js +2 -1
- package/dist/dts/features/CohortDiscovery/Requests/RequestsPanel.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/RequestsTable.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/RequestsTable.js +76 -13
- package/dist/dts/features/CohortDiscovery/Requests/RequestsTable.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/hooks.d.ts +3 -3
- package/dist/dts/features/CohortDiscovery/Requests/hooks.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/hooks.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/Requests/submitCohortRequestAction.d.ts +9 -0
- package/dist/dts/features/CohortDiscovery/Requests/submitCohortRequestAction.d.ts.map +1 -0
- package/dist/dts/features/CohortDiscovery/Requests/submitCohortRequestAction.js +133 -0
- package/dist/dts/features/CohortDiscovery/Requests/submitCohortRequestAction.js.map +1 -0
- package/dist/dts/features/CohortDiscovery/SavedCohorts/SavedCohortsTable.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/SavedCohorts/SavedCohortsTable.js +25 -99
- package/dist/dts/features/CohortDiscovery/SavedCohorts/SavedCohortsTable.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/TabbedIndex.d.ts +3 -2
- package/dist/dts/features/CohortDiscovery/TabbedIndex.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/TabbedIndex.js +2 -2
- package/dist/dts/features/CohortDiscovery/TabbedIndex.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/appApi.d.ts +2 -4
- package/dist/dts/features/CohortDiscovery/appApi.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/appApi.js +6 -4
- package/dist/dts/features/CohortDiscovery/appApi.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/hooks.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/hooks.js +7 -9
- package/dist/dts/features/CohortDiscovery/hooks.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/queryApi.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/queryApi.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/types.d.ts +47 -19
- package/dist/dts/features/CohortDiscovery/types.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/types.js +16 -6
- package/dist/dts/features/CohortDiscovery/types.js.map +1 -1
- package/dist/dts/features/CohortDiscovery/utils.d.ts +2 -0
- package/dist/dts/features/CohortDiscovery/utils.d.ts.map +1 -1
- package/dist/dts/features/CohortDiscovery/utils.js +9 -0
- package/dist/dts/features/CohortDiscovery/utils.js.map +1 -1
- package/dist/dts/features/Crosswalk/types.d.ts +2 -1
- package/dist/dts/features/Crosswalk/types.d.ts.map +1 -1
- package/dist/dts/features/Dictionary/types.d.ts +5 -1
- package/dist/dts/features/Dictionary/types.d.ts.map +1 -1
- package/dist/dts/features/Discovery/types.d.ts +2 -1
- package/dist/dts/features/Discovery/types.d.ts.map +1 -1
- package/dist/dts/features/Discovery/types.js.map +1 -1
- package/dist/dts/features/Navigation/TopBar/AccountButton.js +1 -1
- package/dist/dts/features/Navigation/TopBar/AccountButton.js.map +1 -1
- package/dist/dts/features/Navigation/TopBar/LoginButton.js +1 -1
- package/dist/dts/features/Navigation/TopBar/LoginButton.js.map +1 -1
- package/dist/dts/features/Workspace/types.d.ts +2 -1
- package/dist/dts/features/Workspace/types.d.ts.map +1 -1
- package/dist/dts/features/Workspace/types.js.map +1 -1
- package/dist/dts/lib/content/types.d.ts +2 -0
- package/dist/dts/lib/content/types.d.ts.map +1 -1
- package/dist/dts/lib/session/session.d.ts.map +1 -1
- package/dist/dts/lib/session/session.js +6 -2
- package/dist/dts/lib/session/session.js.map +1 -1
- package/dist/dts/pages/Crosswalk/Crosswalk.d.ts.map +1 -1
- package/dist/dts/pages/Crosswalk/Crosswalk.js +1 -5
- package/dist/dts/pages/Crosswalk/Crosswalk.js.map +1 -1
- package/dist/dts/pages/DataDictionary/DataDictionary.d.ts.map +1 -1
- package/dist/dts/pages/DataDictionary/DataDictionary.js +12 -5
- package/dist/dts/pages/DataDictionary/DataDictionary.js.map +1 -1
- package/dist/dts/pages/Discovery/Discovery.d.ts.map +1 -1
- package/dist/dts/pages/Discovery/Discovery.js +14 -5
- package/dist/dts/pages/Discovery/Discovery.js.map +1 -1
- package/dist/dts/pages/Explorer/Explorer.d.ts +1 -1
- package/dist/dts/pages/Explorer/Explorer.d.ts.map +1 -1
- package/dist/dts/pages/Explorer/Explorer.js +13 -6
- package/dist/dts/pages/Explorer/Explorer.js.map +1 -1
- package/dist/dts/pages/Explorer/data.d.ts.map +1 -1
- package/dist/dts/pages/Explorer/data.js +4 -4
- package/dist/dts/pages/Explorer/data.js.map +1 -1
- package/dist/dts/pages/Landing/Landing.d.ts.map +1 -1
- package/dist/dts/pages/Landing/Landing.js +12 -5
- package/dist/dts/pages/Landing/Landing.js.map +1 -1
- package/dist/dts/pages/Login/Login.d.ts.map +1 -1
- package/dist/dts/pages/Login/Login.js +1 -5
- package/dist/dts/pages/Login/Login.js.map +1 -1
- package/dist/dts/pages/Profile/Profile.d.ts.map +1 -1
- package/dist/dts/pages/Profile/Profile.js +12 -5
- package/dist/dts/pages/Profile/Profile.js.map +1 -1
- package/dist/dts/pages/Query/Query.d.ts.map +1 -1
- package/dist/dts/pages/Query/Query.js +12 -5
- package/dist/dts/pages/Query/Query.js.map +1 -1
- package/dist/dts/pages/Query/types.d.ts +2 -1
- package/dist/dts/pages/Query/types.d.ts.map +1 -1
- package/dist/dts/pages/Workspace/Workspace.d.ts.map +1 -1
- package/dist/dts/pages/Workspace/Workspace.js +14 -5
- package/dist/dts/pages/Workspace/Workspace.js.map +1 -1
- package/dist/dts/types/icons.d.ts +3 -2
- package/dist/dts/types/icons.d.ts.map +1 -1
- package/dist/dts/types/icons.js +3 -2
- package/dist/dts/types/icons.js.map +1 -1
- package/dist/dts/utils/index.d.ts +2 -3
- package/dist/dts/utils/index.d.ts.map +1 -1
- package/dist/dts/utils/index.js +2 -2
- package/dist/dts/utils/index.js.map +1 -1
- package/dist/dts/utils/tests/values.test.js +0 -1
- package/dist/dts/utils/tests/values.test.js.map +1 -1
- package/dist/esm/index.js +1710 -600
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +186 -172
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/cjs/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var tinycolor = require('tinycolor2');
|
|
|
16
16
|
var lodash = require('lodash');
|
|
17
17
|
var tailwindMerge = require('tailwind-merge');
|
|
18
18
|
var bs = require('react-icons/bs');
|
|
19
|
+
var io = require('react-icons/io');
|
|
19
20
|
var Markdown = require('react-markdown');
|
|
20
21
|
var remarkGfm = require('remark-gfm');
|
|
21
22
|
var reactCookie = require('react-cookie');
|
|
@@ -44,7 +45,6 @@ var lu = require('react-icons/lu');
|
|
|
44
45
|
var tw = require('tailwind-styled-components');
|
|
45
46
|
require('universal-cookie');
|
|
46
47
|
var ri = require('react-icons/ri');
|
|
47
|
-
var io = require('react-icons/io');
|
|
48
48
|
var modals = require('@mantine/modals');
|
|
49
49
|
var GraphiQL = require('graphiql');
|
|
50
50
|
var fs = require('fs');
|
|
@@ -53,6 +53,7 @@ var react$1 = require('redux-persist/integration/react');
|
|
|
53
53
|
var reduxPersist = require('redux-persist');
|
|
54
54
|
var redux = require('redux');
|
|
55
55
|
var toolkit = require('@reduxjs/toolkit');
|
|
56
|
+
var idb = require('idb');
|
|
56
57
|
var createWebStorage = require('redux-persist/lib/storage/createWebStorage');
|
|
57
58
|
var form = require('@mantine/form');
|
|
58
59
|
var dynamic = require('next/dynamic');
|
|
@@ -551,6 +552,47 @@ const create10ColorAccessibleContrast = (pallet)=>{
|
|
|
551
552
|
*/ const convertSecondsToMilliseconds = (seconds)=>seconds * 1000;
|
|
552
553
|
const MinutesToMilliseconds = (minutes)=>minutes * 60 * 1000;
|
|
553
554
|
|
|
555
|
+
const convertPathsToTree = (paths)=>{
|
|
556
|
+
const tree = {};
|
|
557
|
+
paths.forEach((path)=>{
|
|
558
|
+
const parts = path.split('/').filter((part)=>part !== '');
|
|
559
|
+
let current = tree;
|
|
560
|
+
// Build the path through the tree
|
|
561
|
+
for(let i = 0; i < parts.length; i++){
|
|
562
|
+
const part = parts[i];
|
|
563
|
+
const fullPath = parts.slice(0, i + 1).join('/');
|
|
564
|
+
if (!current[part]) {
|
|
565
|
+
current[part] = {
|
|
566
|
+
value: fullPath,
|
|
567
|
+
label: part,
|
|
568
|
+
children: {},
|
|
569
|
+
_hasChildren: false
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
// Mark parent as having children
|
|
573
|
+
if (i < parts.length - 1) {
|
|
574
|
+
current[part]._hasChildren = true;
|
|
575
|
+
}
|
|
576
|
+
current = current[part].children;
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
// Convert to final format
|
|
580
|
+
const convertToFinalFormat = (node)=>{
|
|
581
|
+
const result = {
|
|
582
|
+
value: node.value,
|
|
583
|
+
label: node.label
|
|
584
|
+
};
|
|
585
|
+
const childKeys = Object.keys(node.children);
|
|
586
|
+
if (childKeys.length > 0) {
|
|
587
|
+
result.children = childKeys.map((key)=>convertToFinalFormat(node.children[key]));
|
|
588
|
+
}
|
|
589
|
+
return result;
|
|
590
|
+
};
|
|
591
|
+
// Get the root nodes and convert them
|
|
592
|
+
const rootKeys = Object.keys(tree);
|
|
593
|
+
return rootKeys.map((key)=>convertToFinalFormat(tree[key]));
|
|
594
|
+
};
|
|
595
|
+
|
|
554
596
|
const resourcePathFromProjectID = (projectID)=>{
|
|
555
597
|
const split = projectID.split('-');
|
|
556
598
|
const program = split[0];
|
|
@@ -895,7 +937,7 @@ const UPDATE_SESSION_LIMIT = MinutesToMilliseconds(5);
|
|
|
895
937
|
*/ const SessionProvider = ({ children, updateSessionTime = 5, inactiveTimeLimit = 20, workspaceInactivityTimeLimit = 0, logoutInactiveUsers = true, monitorWorkspace = true })=>{
|
|
896
938
|
const router$1 = router.useRouter();
|
|
897
939
|
const coreDispatch = core.useCoreDispatch();
|
|
898
|
-
core.useGetCSRFQuery();
|
|
940
|
+
const { isSuccess: isGetCSRFSuccess } = core.useGetCSRFQuery();
|
|
899
941
|
useWorkspaceResourceMonitor(monitorWorkspace); // monitor workspaces if any are running or configured
|
|
900
942
|
const [getUserDetails] = core.useLazyFetchUserDetailsQuery(); // Fetch user details
|
|
901
943
|
const userStatus = core.useCoreSelector((state)=>core.selectUserAuthStatus(state));
|
|
@@ -982,10 +1024,14 @@ const UPDATE_SESSION_LIMIT = MinutesToMilliseconds(5);
|
|
|
982
1024
|
updateSession,
|
|
983
1025
|
endSession
|
|
984
1026
|
]);
|
|
985
|
-
return /*#__PURE__*/ jsxRuntime.jsx(SessionContext.Provider, {
|
|
1027
|
+
if (isGetCSRFSuccess) return /*#__PURE__*/ jsxRuntime.jsx(SessionContext.Provider, {
|
|
986
1028
|
value: value,
|
|
987
1029
|
children: children
|
|
988
1030
|
});
|
|
1031
|
+
else return /*#__PURE__*/ jsxRuntime.jsx(core$1.Center, {
|
|
1032
|
+
h: "100vh",
|
|
1033
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Loader, {})
|
|
1034
|
+
});
|
|
989
1035
|
};
|
|
990
1036
|
|
|
991
1037
|
const TooltipStyle = {
|
|
@@ -1116,6 +1162,28 @@ const ErrorCard = ({ message })=>/*#__PURE__*/ jsxRuntime.jsx(MessageCard, {
|
|
|
1116
1162
|
color: "utility.3"
|
|
1117
1163
|
});
|
|
1118
1164
|
|
|
1165
|
+
const EmptyTableMessage = ({ message })=>{
|
|
1166
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
1167
|
+
gap: "xs",
|
|
1168
|
+
justify: "center",
|
|
1169
|
+
classNames: {
|
|
1170
|
+
root: 'w-100 my-4'
|
|
1171
|
+
},
|
|
1172
|
+
children: [
|
|
1173
|
+
/*#__PURE__*/ jsxRuntime.jsx("span", {
|
|
1174
|
+
className: "text-utility-warning",
|
|
1175
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(io.IoMdInformationCircleOutline, {
|
|
1176
|
+
size: "1.5rem"
|
|
1177
|
+
})
|
|
1178
|
+
}),
|
|
1179
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
|
|
1180
|
+
fw: 600,
|
|
1181
|
+
children: message
|
|
1182
|
+
})
|
|
1183
|
+
]
|
|
1184
|
+
});
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1119
1187
|
const LoginProviderMultipleItems = ({ provider, handleLoginSelected })=>{
|
|
1120
1188
|
const [value, setValue] = React.useState(null);
|
|
1121
1189
|
return /*#__PURE__*/ jsxRuntime.jsxs("div", {
|
|
@@ -1550,6 +1618,7 @@ const filterRedirect = (redirect)=>{
|
|
|
1550
1618
|
} else {
|
|
1551
1619
|
redirectPath = redirect ?? '/';
|
|
1552
1620
|
}
|
|
1621
|
+
console.log('redirectPath', redirectPath);
|
|
1553
1622
|
return core.GEN3_REDIRECT_URL ? `${core.GEN3_REDIRECT_URL}/${redirectPath}` : redirectPath;
|
|
1554
1623
|
};
|
|
1555
1624
|
const LoginPanel = (loginConfig)=>{
|
|
@@ -2421,7 +2490,7 @@ const processChartData$2 = (facetData, valueType = 'count', total, maxBins = 100
|
|
|
2421
2490
|
}));
|
|
2422
2491
|
return results;
|
|
2423
2492
|
};
|
|
2424
|
-
const HorizontalBarChart = ({ data, valueType, total })=>{
|
|
2493
|
+
const HorizontalBarChart = ({ data, valueType, total, showLegendInChart = true })=>{
|
|
2425
2494
|
const chartData = processChartData$2(data, valueType, total);
|
|
2426
2495
|
const chartDefinition = React.useMemo(()=>{
|
|
2427
2496
|
return {
|
|
@@ -2436,11 +2505,12 @@ const HorizontalBarChart = ({ data, valueType, total })=>{
|
|
|
2436
2505
|
orient: 'vertical',
|
|
2437
2506
|
left: '73%',
|
|
2438
2507
|
type: 'scroll',
|
|
2439
|
-
right: 15
|
|
2508
|
+
right: 15,
|
|
2509
|
+
show: showLegendInChart
|
|
2440
2510
|
},
|
|
2441
2511
|
grid: {
|
|
2442
2512
|
left: '0%',
|
|
2443
|
-
right: '30%',
|
|
2513
|
+
right: showLegendInChart ? '30%' : '3%',
|
|
2444
2514
|
bottom: '25%',
|
|
2445
2515
|
containLabel: true,
|
|
2446
2516
|
height: '50%'
|
|
@@ -2565,7 +2635,8 @@ const Charts = ({ charts, data, counts, isSuccess, numCols = DEFAULT_COLS, style
|
|
|
2565
2635
|
data: data === undefined ? [] : data,
|
|
2566
2636
|
total: counts ?? 1,
|
|
2567
2637
|
valueType: chart.valueType ?? 'count',
|
|
2568
|
-
label: chart.label
|
|
2638
|
+
label: chart.label,
|
|
2639
|
+
showLegendInChart: chart.showLegendInChart
|
|
2569
2640
|
})
|
|
2570
2641
|
}, "modal-col-1"),
|
|
2571
2642
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.Grid.Col, {
|
|
@@ -2653,7 +2724,8 @@ const Charts = ({ charts, data, counts, isSuccess, numCols = DEFAULT_COLS, style
|
|
|
2653
2724
|
data: data === undefined ? [] : data[field],
|
|
2654
2725
|
total: counts ?? 1,
|
|
2655
2726
|
valueType: charts[field].valueType ?? 'count',
|
|
2656
|
-
label: charts[field].label
|
|
2727
|
+
label: charts[field].label,
|
|
2728
|
+
showLegendInChart: charts[field].showLegendInChart
|
|
2657
2729
|
}),
|
|
2658
2730
|
showLegends && /*#__PURE__*/ jsxRuntime.jsx(core$1.Card.Section, {
|
|
2659
2731
|
inheritPadding: true,
|
|
@@ -3244,7 +3316,7 @@ const AccountButton = ({ leftIcon = undefined, rightIcon = undefined, iconSize =
|
|
|
3244
3316
|
const mergedClassnames = mergeDefaultTailwindClassnames(classNamesDefaults, classNames);
|
|
3245
3317
|
const router$1 = router.useRouter();
|
|
3246
3318
|
const handleSelected = async ()=>{
|
|
3247
|
-
await router$1.push('Profile');
|
|
3319
|
+
await router$1.push('/Profile');
|
|
3248
3320
|
};
|
|
3249
3321
|
const userInfo = core.useCoreSelector((state)=>core.selectUserDetails(state));
|
|
3250
3322
|
const userStatus = core.useCoreSelector((state)=>core.selectUserAuthStatus(state));
|
|
@@ -3262,7 +3334,7 @@ const AccountButton = ({ leftIcon = undefined, rightIcon = undefined, iconSize =
|
|
|
3262
3334
|
};
|
|
3263
3335
|
|
|
3264
3336
|
const handleSelected = async (isAuthenticated, router, referrer, endSession, externalLoginUrl)=>{
|
|
3265
|
-
if (!isAuthenticated) await router.push(externalLoginUrl ||
|
|
3337
|
+
if (!isAuthenticated) await router.push(externalLoginUrl || `/Login?redirect=${referrer}`);
|
|
3266
3338
|
else {
|
|
3267
3339
|
if (endSession) endSession();
|
|
3268
3340
|
}
|
|
@@ -8030,6 +8102,7 @@ flex items-start justify-between items-center flex-nowrap bg-secondary px-1.5 ro
|
|
|
8030
8102
|
if (toggleSettings) toggleSettings();
|
|
8031
8103
|
},
|
|
8032
8104
|
"aria-label": "Search",
|
|
8105
|
+
className: header.iconStyle,
|
|
8033
8106
|
children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
|
|
8034
8107
|
width: 12,
|
|
8035
8108
|
height: 12,
|
|
@@ -8162,7 +8235,7 @@ const DEFAULT_MINIMUM = 0;
|
|
|
8162
8235
|
const DEFAULT_MAXIMUM = 100;
|
|
8163
8236
|
const BAD_DATA_MESSAGE = 'No data for this field';
|
|
8164
8237
|
|
|
8165
|
-
const FacetSelector = ({ category, facetName, hooks, width = 'w-full', description, fields, selectedFields, updateSelectedField, showSearch = true, header = {
|
|
8238
|
+
const FacetSelector = ({ category, facetName, hooks, width = 'w-full', description, fields, selectedFields, updateSelectedField, showSearch = true, showSettings = false, header = {
|
|
8166
8239
|
Panel: FacetHeader,
|
|
8167
8240
|
Label: FacetText,
|
|
8168
8241
|
iconStyle: controlsIconStyle
|
|
@@ -8204,6 +8277,7 @@ const FacetSelector = ({ category, facetName, hooks, width = 'w-full', descripti
|
|
|
8204
8277
|
hooks: hooks,
|
|
8205
8278
|
facetName: facetName,
|
|
8206
8279
|
showSearch: showSearch,
|
|
8280
|
+
showSettings: showSettings,
|
|
8207
8281
|
toggleSearch: toggleSearch,
|
|
8208
8282
|
header: header
|
|
8209
8283
|
})
|
|
@@ -9031,7 +9105,7 @@ const reducer = (state, action)=>{
|
|
|
9031
9105
|
}
|
|
9032
9106
|
}
|
|
9033
9107
|
};
|
|
9034
|
-
const QueryExpressionSection = ({ index, showImportExport = false, displayOnly = false, showTitle =
|
|
9108
|
+
const QueryExpressionSection = ({ index, showImportExport = false, displayOnly = false, showTitle = true })=>{
|
|
9035
9109
|
const [expandedState, setExpandedState] = React.useReducer(reducer, {});
|
|
9036
9110
|
const [filtersSectionCollapsed, setFiltersSectionCollapsed] = React.useState(true);
|
|
9037
9111
|
const filtersRef = React.useRef(null);
|
|
@@ -12035,7 +12109,6 @@ const TabsLayoutToComponentProp = (tabsLayout)=>{
|
|
|
12035
12109
|
};
|
|
12036
12110
|
|
|
12037
12111
|
const CohortBuilder = ({ explorerConfig, sharedFiltersMap = null, tabsLayout = 'left' })=>{
|
|
12038
|
-
core.useGetCSRFQuery();
|
|
12039
12112
|
const dispatch = core.useCoreDispatch();
|
|
12040
12113
|
dispatch(core.setSharedFilters(sharedFiltersMap ?? {}));
|
|
12041
12114
|
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
@@ -13455,15 +13528,15 @@ const FacetSelectionPanel = ({ categories, hooks, selectedFields, updateSelected
|
|
|
13455
13528
|
hooks
|
|
13456
13529
|
]);
|
|
13457
13530
|
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
13458
|
-
className: "w-1/
|
|
13531
|
+
className: "sm:w-40 md:w-80 lg:w-96 xl:w-1/4 flex flex-col flex-shrink-0 p-4 gap-y-6",
|
|
13459
13532
|
children: panels
|
|
13460
13533
|
});
|
|
13461
13534
|
};
|
|
13462
13535
|
|
|
13463
|
-
const initialState$
|
|
13536
|
+
const initialState$3 = {};
|
|
13464
13537
|
const expandSlice = toolkit.createSlice({
|
|
13465
13538
|
name: 'CohortDiscovery/expandedCategory',
|
|
13466
|
-
initialState: initialState$
|
|
13539
|
+
initialState: initialState$3,
|
|
13467
13540
|
reducers: {
|
|
13468
13541
|
toggleCategoryFilter: (state, action)=>{
|
|
13469
13542
|
return {
|
|
@@ -13483,10 +13556,10 @@ const filtersExpandedReducer = expandSlice.reducer;
|
|
|
13483
13556
|
const { toggleCategoryFilter, toggleAllFilters } = expandSlice.actions;
|
|
13484
13557
|
const selectFilterExpanded = (state, field)=>state.filtersExpandedState?.[field];
|
|
13485
13558
|
|
|
13486
|
-
const initialState$
|
|
13559
|
+
const initialState$2 = {};
|
|
13487
13560
|
const selectIndexFacets = toolkit.createSlice({
|
|
13488
13561
|
name: 'CohortDiscovery/selectedFacets',
|
|
13489
|
-
initialState: initialState$
|
|
13562
|
+
initialState: initialState$2,
|
|
13490
13563
|
reducers: {
|
|
13491
13564
|
addFacetSelection: (state, action)=>{
|
|
13492
13565
|
if (!(action.payload.index in state)) {
|
|
@@ -13521,12 +13594,12 @@ const selectedFacetsReducer = selectIndexFacets.reducer;
|
|
|
13521
13594
|
const { addFacetSelection, removeFacetSelection } = selectIndexFacets.actions;
|
|
13522
13595
|
const selectSelectedFacetsFromIndex = (state, index)=>state.selectedIndexFacets[index];
|
|
13523
13596
|
|
|
13524
|
-
const initialState = {};
|
|
13597
|
+
const initialState$1 = {};
|
|
13525
13598
|
/**
|
|
13526
13599
|
* Redux slice for managing facet definitions in CohortDiscovery
|
|
13527
13600
|
*/ const facetDefinitionsSlice = toolkit.createSlice({
|
|
13528
13601
|
name: 'CohortDiscovery/facetDefinitions',
|
|
13529
|
-
initialState,
|
|
13602
|
+
initialState: initialState$1,
|
|
13530
13603
|
reducers: {
|
|
13531
13604
|
addFacetDefinition: (state, action)=>{
|
|
13532
13605
|
const { index, definition } = action.payload;
|
|
@@ -13556,311 +13629,955 @@ const initialState = {};
|
|
|
13556
13629
|
const facetDefinitionsReducer = facetDefinitionsSlice.reducer;
|
|
13557
13630
|
const { addFacetDefinition, addFacetDefinitions } = facetDefinitionsSlice.actions;
|
|
13558
13631
|
|
|
13559
|
-
const initialCohortState = {
|
|
13560
|
-
cohort: {
|
|
13561
|
-
id: 'default',
|
|
13562
|
-
name: 'Discovery',
|
|
13563
|
-
filters: {},
|
|
13564
|
-
modified_datetime: new Date().toISOString()
|
|
13565
|
-
}
|
|
13566
|
-
};
|
|
13567
|
-
/**
|
|
13568
|
-
* Redux slice for cohort filters
|
|
13569
|
-
*/ const cohortSlice = toolkit.createSlice({
|
|
13570
|
-
name: 'CohortDiscovery/cohorts',
|
|
13571
|
-
initialState: initialCohortState,
|
|
13572
|
-
reducers: {
|
|
13573
|
-
// adds a filter to the cohort filter set at the given index
|
|
13574
|
-
updateCohortFilter: (state, action)=>{
|
|
13575
|
-
const { index, field, filter } = action.payload;
|
|
13576
|
-
return {
|
|
13577
|
-
cohort: {
|
|
13578
|
-
...state.cohort,
|
|
13579
|
-
filters: {
|
|
13580
|
-
...state.cohort.filters,
|
|
13581
|
-
[index]: {
|
|
13582
|
-
mode: state.cohort.filters?.[index]?.mode ?? 'and',
|
|
13583
|
-
root: {
|
|
13584
|
-
...state.cohort.filters?.[index]?.root ?? {},
|
|
13585
|
-
[field]: filter
|
|
13586
|
-
}
|
|
13587
|
-
}
|
|
13588
|
-
}
|
|
13589
|
-
}
|
|
13590
|
-
};
|
|
13591
|
-
},
|
|
13592
|
-
setCohortFilter: (state, action)=>{
|
|
13593
|
-
const { index, filters } = action.payload;
|
|
13594
|
-
return {
|
|
13595
|
-
cohort: {
|
|
13596
|
-
...state.cohort,
|
|
13597
|
-
filters: {
|
|
13598
|
-
...state.cohort.filters,
|
|
13599
|
-
[index]: filters
|
|
13600
|
-
}
|
|
13601
|
-
}
|
|
13602
|
-
};
|
|
13603
|
-
},
|
|
13604
|
-
// removes a filter to the cohort filter set at the given index
|
|
13605
|
-
removeCohortFilter: (state, action)=>{
|
|
13606
|
-
const { index, field } = action.payload;
|
|
13607
|
-
const filters = state.cohort?.filters?.[index]?.root;
|
|
13608
|
-
if (!filters) {
|
|
13609
|
-
return;
|
|
13610
|
-
}
|
|
13611
|
-
const { [field]: _a, ...updated } = filters;
|
|
13612
|
-
return {
|
|
13613
|
-
cohort: {
|
|
13614
|
-
...state.cohort,
|
|
13615
|
-
filters: {
|
|
13616
|
-
...state.cohort.filters,
|
|
13617
|
-
[index]: {
|
|
13618
|
-
mode: state.cohort.filters[index].mode,
|
|
13619
|
-
root: updated
|
|
13620
|
-
}
|
|
13621
|
-
}
|
|
13622
|
-
}
|
|
13623
|
-
};
|
|
13624
|
-
},
|
|
13625
|
-
// removes all filters from the cohort filter set at the given index
|
|
13626
|
-
clearCohortFilters: (state, action)=>{
|
|
13627
|
-
const { index } = action.payload;
|
|
13628
|
-
return {
|
|
13629
|
-
cohort: {
|
|
13630
|
-
...state.cohort,
|
|
13631
|
-
filters: {
|
|
13632
|
-
...state.cohort.filters,
|
|
13633
|
-
[index]: {
|
|
13634
|
-
// empty filter set
|
|
13635
|
-
mode: 'and',
|
|
13636
|
-
root: {}
|
|
13637
|
-
}
|
|
13638
|
-
}
|
|
13639
|
-
}
|
|
13640
|
-
};
|
|
13641
|
-
}
|
|
13642
|
-
}
|
|
13643
|
-
});
|
|
13644
|
-
// Filter actions: addFilter, removeFilter, updateFilter
|
|
13645
|
-
const { updateCohortFilter, setCohortFilter, removeCohortFilter, clearCohortFilters } = cohortSlice.actions;
|
|
13646
|
-
const cohortReducer = cohortSlice.reducer;
|
|
13647
|
-
|
|
13648
|
-
/* eslint @typescript-eslint/no-unused-vars: 0 */ // Credit to: https://github.com/vercel/next.js/discussions/15687
|
|
13649
|
-
const createNoopStorage = ()=>{
|
|
13650
|
-
return {
|
|
13651
|
-
getItem (_key) {
|
|
13652
|
-
return Promise.resolve(null);
|
|
13653
|
-
},
|
|
13654
|
-
setItem (_key, value) {
|
|
13655
|
-
return Promise.resolve(value);
|
|
13656
|
-
},
|
|
13657
|
-
removeItem (_key) {
|
|
13658
|
-
return Promise.resolve();
|
|
13659
|
-
}
|
|
13660
|
-
};
|
|
13661
|
-
};
|
|
13662
|
-
const storage = typeof window !== 'undefined' ? createWebStorage('local') : createNoopStorage();
|
|
13663
|
-
typeof window !== 'undefined' ? createWebStorage('session') : createNoopStorage();
|
|
13664
|
-
|
|
13665
13632
|
const createCohortId = ()=>toolkit.nanoid();
|
|
13666
|
-
const
|
|
13667
|
-
const newCohort = (name, filters)=>{
|
|
13633
|
+
const newCohort = (name, filters, id, saved)=>{
|
|
13668
13634
|
const ts = new Date().toISOString();
|
|
13669
13635
|
return {
|
|
13670
|
-
id: createCohortId(),
|
|
13636
|
+
id: id ?? createCohortId(),
|
|
13671
13637
|
name: name,
|
|
13672
13638
|
filters: filters,
|
|
13673
|
-
|
|
13674
|
-
|
|
13639
|
+
modifiedDatetime: ts,
|
|
13640
|
+
createdDatetime: ts,
|
|
13675
13641
|
requestedAccess: false,
|
|
13676
|
-
requestId: 'no_request_id'
|
|
13642
|
+
requestId: 'no_request_id',
|
|
13643
|
+
saved: saved ?? false,
|
|
13644
|
+
modified: false
|
|
13677
13645
|
};
|
|
13678
13646
|
};
|
|
13679
|
-
const newDataAccessRequest = (userInformation, cohortId)=>{
|
|
13647
|
+
const newDataAccessRequest = (requestId, status, userInformation, cohortId, createdTime, updatedTime)=>{
|
|
13648
|
+
const now = new Date().toISOString();
|
|
13680
13649
|
return {
|
|
13681
|
-
id:
|
|
13682
|
-
|
|
13683
|
-
|
|
13650
|
+
id: requestId,
|
|
13651
|
+
createdDatetime: createdTime ?? now,
|
|
13652
|
+
updatedDatetime: updatedTime ?? now,
|
|
13653
|
+
status: status,
|
|
13684
13654
|
cohortId,
|
|
13685
13655
|
...userInformation
|
|
13686
13656
|
};
|
|
13687
13657
|
};
|
|
13658
|
+
const isIndexedFilterSetEmpty = (filters)=>Object.values(filters).every((filterSet)=>Object.keys(filterSet).length === 0);
|
|
13688
13659
|
|
|
13689
|
-
|
|
13690
|
-
const
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13660
|
+
const DATABASE_NAME = 'Gen3CohortDiscovery';
|
|
13661
|
+
const STORE_NAME = 'cohorts';
|
|
13662
|
+
const DB_SCHEMA_VERSION = 1;
|
|
13663
|
+
class CohortStorage {
|
|
13664
|
+
getDb() {
|
|
13665
|
+
try {
|
|
13666
|
+
return idb.openDB(DATABASE_NAME, 1, {
|
|
13667
|
+
upgrade (db) {
|
|
13668
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
13669
|
+
db.createObjectStore(STORE_NAME, {
|
|
13670
|
+
keyPath: 'id'
|
|
13671
|
+
});
|
|
13672
|
+
}
|
|
13673
|
+
}
|
|
13674
|
+
});
|
|
13675
|
+
} catch (error) {
|
|
13676
|
+
let errorMessage = 'Unknown error';
|
|
13677
|
+
if (error instanceof Error) {
|
|
13678
|
+
errorMessage = error.message;
|
|
13679
|
+
}
|
|
13680
|
+
throw new Error(`Database initialization failed: ${errorMessage}`);
|
|
13681
|
+
}
|
|
13710
13682
|
}
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
// Optional: Sort by request_datetime descending (newest first)
|
|
13732
|
-
sortComparer: (a, b)=>new Date(b.request_datetime).getTime() - new Date(a.request_datetime).getTime()
|
|
13733
|
-
});
|
|
13734
|
-
// Create a slice with reducers
|
|
13735
|
-
const dataAccessRequestsSlice = toolkit.createSlice({
|
|
13736
|
-
name: 'dataAccessRequests',
|
|
13737
|
-
initialState: dataAccessRequestsAdapter.getInitialState(),
|
|
13738
|
-
reducers: {
|
|
13739
|
-
addDataAccessRequest: (state, action)=>{
|
|
13740
|
-
const { cohortId, userAccessInformation } = action.payload;
|
|
13741
|
-
const dataAccessRequests = newDataAccessRequest(userAccessInformation, cohortId);
|
|
13742
|
-
dataAccessRequestsAdapter.addOne(state, dataAccessRequests);
|
|
13743
|
-
},
|
|
13744
|
-
// Set a request's status
|
|
13745
|
-
setRequestStatus: (state, action)=>{
|
|
13746
|
-
const { id, status } = action.payload;
|
|
13747
|
-
dataAccessRequestsAdapter.updateOne(state, {
|
|
13748
|
-
id,
|
|
13749
|
-
changes: {
|
|
13750
|
-
status
|
|
13683
|
+
/**
|
|
13684
|
+
* Initialize the IndexedDB database with proper schema
|
|
13685
|
+
*/ async initializeDB() {
|
|
13686
|
+
try {
|
|
13687
|
+
return await idb.openDB(DATABASE_NAME, DB_SCHEMA_VERSION, {
|
|
13688
|
+
upgrade: (db)=>{
|
|
13689
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
13690
|
+
db.createObjectStore(STORE_NAME, {
|
|
13691
|
+
keyPath: 'id'
|
|
13692
|
+
});
|
|
13693
|
+
}
|
|
13694
|
+
},
|
|
13695
|
+
blocked: ()=>{
|
|
13696
|
+
console.warn('CohortDB: Database upgrade blocked by another connection');
|
|
13697
|
+
},
|
|
13698
|
+
blocking: ()=>{
|
|
13699
|
+
console.warn('CohortDB: This connection is blocking a database upgrade');
|
|
13700
|
+
},
|
|
13701
|
+
terminated: ()=>{
|
|
13702
|
+
console.error('CohortDB: Database connection terminated unexpectedly');
|
|
13751
13703
|
}
|
|
13752
13704
|
});
|
|
13705
|
+
} catch (error) {
|
|
13706
|
+
let errorMessage = 'Unknown error';
|
|
13707
|
+
if (error instanceof Error) {
|
|
13708
|
+
errorMessage = error.message;
|
|
13709
|
+
}
|
|
13710
|
+
throw new Error(`Database initialization failed: ${errorMessage}`);
|
|
13753
13711
|
}
|
|
13754
13712
|
}
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
const
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
}
|
|
13768
|
-
//
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13775
|
-
|
|
13776
|
-
}
|
|
13777
|
-
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
})
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
};
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
|
|
13825
|
-
|
|
13826
|
-
|
|
13827
|
-
|
|
13828
|
-
}
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
}
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13713
|
+
// ===== CREATE OPERATIONS =====
|
|
13714
|
+
/**
|
|
13715
|
+
* Save a single cohort to the database
|
|
13716
|
+
*/ async saveCohort(cohort) {
|
|
13717
|
+
try {
|
|
13718
|
+
const db = await this.getDb();
|
|
13719
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
13720
|
+
tx.objectStore(STORE_NAME).put(cohort);
|
|
13721
|
+
await tx.done;
|
|
13722
|
+
return {
|
|
13723
|
+
status: 200,
|
|
13724
|
+
message: 'cohort added'
|
|
13725
|
+
};
|
|
13726
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13727
|
+
} catch (_error) {
|
|
13728
|
+
return {
|
|
13729
|
+
isError: true,
|
|
13730
|
+
status: 500,
|
|
13731
|
+
message: 'unable to save cohort'
|
|
13732
|
+
};
|
|
13733
|
+
}
|
|
13734
|
+
}
|
|
13735
|
+
/**
|
|
13736
|
+
* Save multiple cohorts in a single transaction (bulk operation)
|
|
13737
|
+
*/ async saveCohorts(cohorts) {
|
|
13738
|
+
if (cohorts.length === 0) return {
|
|
13739
|
+
isError: true,
|
|
13740
|
+
status: 400,
|
|
13741
|
+
message: 'cannot add an empty array'
|
|
13742
|
+
};
|
|
13743
|
+
try {
|
|
13744
|
+
const db = await this.getDb();
|
|
13745
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
13746
|
+
// Batch all operations in single transaction for better performance
|
|
13747
|
+
await Promise.all([
|
|
13748
|
+
...cohorts.map((cohort)=>tx.store.put({
|
|
13749
|
+
...cohort,
|
|
13750
|
+
saved: true
|
|
13751
|
+
})),
|
|
13752
|
+
tx.done
|
|
13753
|
+
]);
|
|
13754
|
+
return {
|
|
13755
|
+
status: 200,
|
|
13756
|
+
message: 'cohorts added'
|
|
13757
|
+
};
|
|
13758
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13759
|
+
} catch (_error) {
|
|
13760
|
+
return {
|
|
13761
|
+
isError: true,
|
|
13762
|
+
status: 500,
|
|
13763
|
+
message: 'unable to save cohort'
|
|
13764
|
+
};
|
|
13765
|
+
}
|
|
13766
|
+
}
|
|
13767
|
+
// ===== READ OPERATIONS =====
|
|
13768
|
+
/**
|
|
13769
|
+
* Get a specific cohort by ID
|
|
13770
|
+
*/ async getCohort(id) {
|
|
13771
|
+
try {
|
|
13772
|
+
const db = await this.getDb();
|
|
13773
|
+
const tx = db.transaction(STORE_NAME, 'readonly');
|
|
13774
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13775
|
+
const cohort = await store.get(id);
|
|
13776
|
+
return {
|
|
13777
|
+
status: 200,
|
|
13778
|
+
message: 'success',
|
|
13779
|
+
data: cohort
|
|
13780
|
+
};
|
|
13781
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13782
|
+
} catch (_error) {
|
|
13783
|
+
return {
|
|
13784
|
+
isError: true,
|
|
13785
|
+
status: 401,
|
|
13786
|
+
message: `cannot find cohort ${id}`
|
|
13787
|
+
};
|
|
13788
|
+
}
|
|
13789
|
+
}
|
|
13790
|
+
/**
|
|
13791
|
+
* Get all cohorts from the database
|
|
13792
|
+
*/ async getAllCohorts() {
|
|
13793
|
+
try {
|
|
13794
|
+
const db = await this.getDb();
|
|
13795
|
+
const tx = db.transaction(STORE_NAME, 'readonly');
|
|
13796
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13797
|
+
const savedCohorts = await store.getAll();
|
|
13798
|
+
if (!savedCohorts) {
|
|
13799
|
+
return {
|
|
13800
|
+
isError: true,
|
|
13801
|
+
status: 500,
|
|
13802
|
+
message: 'no cohorts returned'
|
|
13803
|
+
};
|
|
13804
|
+
}
|
|
13805
|
+
const cohorts = savedCohorts.reduce((acc, cohort)=>{
|
|
13806
|
+
const { id } = cohort;
|
|
13807
|
+
acc[id] = cohort;
|
|
13808
|
+
return acc;
|
|
13809
|
+
}, {});
|
|
13810
|
+
return {
|
|
13811
|
+
status: 200,
|
|
13812
|
+
message: 'success',
|
|
13813
|
+
data: cohorts
|
|
13814
|
+
};
|
|
13815
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13816
|
+
} catch (_error) {
|
|
13817
|
+
return {
|
|
13818
|
+
isError: true,
|
|
13819
|
+
status: 401,
|
|
13820
|
+
message: 'cannot return cohorts'
|
|
13821
|
+
};
|
|
13822
|
+
}
|
|
13823
|
+
}
|
|
13824
|
+
/**
|
|
13825
|
+
* Search cohorts by name (case-insensitive partial match)
|
|
13826
|
+
*/ async searchCohortsByName(searchTerm) {
|
|
13827
|
+
try {
|
|
13828
|
+
const db = await this.getDb();
|
|
13829
|
+
const tx = db.transaction(STORE_NAME, 'readonly');
|
|
13830
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13831
|
+
const allCohorts = await store.getAll(STORE_NAME);
|
|
13832
|
+
// Filter in memory for partial name matching
|
|
13833
|
+
const searchLower = searchTerm.toLowerCase();
|
|
13834
|
+
return {
|
|
13835
|
+
status: 200,
|
|
13836
|
+
message: 'success',
|
|
13837
|
+
data: allCohorts.filter((cohort)=>cohort.name.toLowerCase().includes(searchLower)).reduce((acc, cohort)=>{
|
|
13838
|
+
const { id } = cohort;
|
|
13839
|
+
acc[id] = cohort;
|
|
13840
|
+
return acc;
|
|
13841
|
+
}, {})
|
|
13842
|
+
};
|
|
13843
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13844
|
+
} catch (_error) {
|
|
13845
|
+
return {
|
|
13846
|
+
isError: true,
|
|
13847
|
+
status: 401,
|
|
13848
|
+
message: 'cannot find cohorts'
|
|
13849
|
+
};
|
|
13850
|
+
}
|
|
13851
|
+
}
|
|
13852
|
+
/**
|
|
13853
|
+
* Count total number of cohorts
|
|
13854
|
+
*/ async getCohortCount() {
|
|
13855
|
+
try {
|
|
13856
|
+
const db = await this.getDb();
|
|
13857
|
+
const total = await db.count(STORE_NAME);
|
|
13858
|
+
return {
|
|
13859
|
+
status: 200,
|
|
13860
|
+
message: 'success',
|
|
13861
|
+
data: total
|
|
13862
|
+
};
|
|
13863
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13864
|
+
} catch (_error) {
|
|
13865
|
+
return {
|
|
13866
|
+
isError: true,
|
|
13867
|
+
status: 401,
|
|
13868
|
+
message: 'cannot find cohort count'
|
|
13869
|
+
};
|
|
13870
|
+
}
|
|
13871
|
+
}
|
|
13872
|
+
// ===== UPDATE OPERATIONS =====
|
|
13873
|
+
/**
|
|
13874
|
+
* Update an existing cohort (full replacement)
|
|
13875
|
+
*/ async updateCohort(cohort) {
|
|
13876
|
+
try {
|
|
13877
|
+
const db = await this.getDb();
|
|
13878
|
+
// Verify cohort exists before updating
|
|
13879
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
13880
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13881
|
+
const existing = await store.get(cohort.id);
|
|
13882
|
+
if (!existing) {
|
|
13883
|
+
return {
|
|
13884
|
+
isError: true,
|
|
13885
|
+
status: 401,
|
|
13886
|
+
message: 'cohort not found'
|
|
13887
|
+
};
|
|
13888
|
+
}
|
|
13889
|
+
const timestamp = core.getTimestamp();
|
|
13890
|
+
const updated = {
|
|
13891
|
+
...existing,
|
|
13892
|
+
modifiedDatetime: timestamp
|
|
13893
|
+
};
|
|
13894
|
+
store.put(updated);
|
|
13895
|
+
await tx.done;
|
|
13896
|
+
return {
|
|
13897
|
+
status: 200,
|
|
13898
|
+
message: 'success'
|
|
13899
|
+
};
|
|
13900
|
+
} catch (error) {
|
|
13901
|
+
let errorMessage = 'An unknown error occurred';
|
|
13902
|
+
if (error instanceof Error) {
|
|
13903
|
+
errorMessage = error.message;
|
|
13904
|
+
}
|
|
13905
|
+
return {
|
|
13906
|
+
isError: true,
|
|
13907
|
+
status: 500,
|
|
13908
|
+
message: `Unable to update cohort: ${cohort.id}. Error: ${errorMessage}`
|
|
13909
|
+
};
|
|
13910
|
+
}
|
|
13911
|
+
}
|
|
13912
|
+
// ===== DELETE OPERATIONS =====
|
|
13913
|
+
/**
|
|
13914
|
+
* Delete a specific cohort by ID
|
|
13915
|
+
*/ async deleteCohort(id) {
|
|
13916
|
+
try {
|
|
13917
|
+
const db = await this.getDb();
|
|
13918
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
13919
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13920
|
+
// Verify cohort exists before deleting
|
|
13921
|
+
const existing = await db.get(STORE_NAME, id);
|
|
13922
|
+
if (!existing) {
|
|
13923
|
+
return {
|
|
13924
|
+
isError: true,
|
|
13925
|
+
status: 401,
|
|
13926
|
+
message: 'cohort not found'
|
|
13927
|
+
};
|
|
13928
|
+
}
|
|
13929
|
+
store.delete(id);
|
|
13930
|
+
await tx.done;
|
|
13931
|
+
return {
|
|
13932
|
+
status: 200,
|
|
13933
|
+
message: `${id} deleted`
|
|
13934
|
+
};
|
|
13935
|
+
} catch (error) {
|
|
13936
|
+
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
|
13937
|
+
return {
|
|
13938
|
+
isError: true,
|
|
13939
|
+
status: 500,
|
|
13940
|
+
message: `Unable to delete cohort: ${id}. Error: ${errorMessage}`
|
|
13941
|
+
};
|
|
13942
|
+
}
|
|
13943
|
+
}
|
|
13944
|
+
/**
|
|
13945
|
+
* Delete all cohorts from the database
|
|
13946
|
+
*/ async deleteAllCohorts() {
|
|
13947
|
+
try {
|
|
13948
|
+
const db = await this.getDb();
|
|
13949
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
13950
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13951
|
+
store.clear();
|
|
13952
|
+
await tx.done;
|
|
13953
|
+
return {
|
|
13954
|
+
status: 200,
|
|
13955
|
+
message: `all cohorts deleted`
|
|
13956
|
+
};
|
|
13957
|
+
} catch (error) {
|
|
13958
|
+
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
|
13959
|
+
return {
|
|
13960
|
+
isError: true,
|
|
13961
|
+
status: 500,
|
|
13962
|
+
message: `Unable to delete all cohorts. Error: ${errorMessage}`
|
|
13963
|
+
};
|
|
13964
|
+
}
|
|
13965
|
+
}
|
|
13966
|
+
// ===== UTILITY OPERATIONS =====
|
|
13967
|
+
/**
|
|
13968
|
+
* Check if a cohort exists
|
|
13969
|
+
*/ async cohortExists(id) {
|
|
13970
|
+
try {
|
|
13971
|
+
const db = await this.getDb();
|
|
13972
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
13973
|
+
const store = tx.objectStore(STORE_NAME);
|
|
13974
|
+
// Verify cohort exists before deleting
|
|
13975
|
+
const existing = await db.get(STORE_NAME, id);
|
|
13976
|
+
return {
|
|
13977
|
+
status: 200,
|
|
13978
|
+
message: `${id}: ${existing ? 'true' : 'false'}`
|
|
13979
|
+
};
|
|
13980
|
+
} catch (error) {
|
|
13981
|
+
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
|
13982
|
+
return {
|
|
13983
|
+
isError: true,
|
|
13984
|
+
status: 500,
|
|
13985
|
+
message: `Unable search for cohort. Error: ${errorMessage}`
|
|
13986
|
+
};
|
|
13987
|
+
}
|
|
13988
|
+
}
|
|
13989
|
+
/**
|
|
13990
|
+
* Export all cohorts as JSON
|
|
13991
|
+
*/ async exportCohorts() {
|
|
13992
|
+
return await this.getAllCohorts();
|
|
13993
|
+
}
|
|
13994
|
+
/**
|
|
13995
|
+
* Import cohorts from JSON data
|
|
13996
|
+
*/ async importCohorts(cohorts, overwrite = false) {
|
|
13997
|
+
try {
|
|
13998
|
+
if (overwrite) {
|
|
13999
|
+
await this.deleteAllCohorts();
|
|
14000
|
+
}
|
|
14001
|
+
await this.saveCohorts(cohorts);
|
|
14002
|
+
} catch (error) {
|
|
14003
|
+
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
|
14004
|
+
return {
|
|
14005
|
+
isError: true,
|
|
14006
|
+
status: 500,
|
|
14007
|
+
message: `Failed to import cohorts: ${errorMessage}`
|
|
14008
|
+
};
|
|
14009
|
+
}
|
|
14010
|
+
}
|
|
14011
|
+
/**
|
|
14012
|
+
* Close the database connection
|
|
14013
|
+
*/ async close() {
|
|
14014
|
+
try {
|
|
14015
|
+
const db = await this.getDb();
|
|
14016
|
+
db.close();
|
|
14017
|
+
} catch (error) {
|
|
14018
|
+
console.error('Failed to close database:', error);
|
|
14019
|
+
}
|
|
14020
|
+
}
|
|
14021
|
+
}
|
|
14022
|
+
// Export a singleton instance
|
|
14023
|
+
const cohortStorage = new CohortStorage();
|
|
14024
|
+
|
|
14025
|
+
const EmptyFilterSet = {
|
|
14026
|
+
mode: 'and',
|
|
14027
|
+
root: {}
|
|
14028
|
+
};
|
|
14029
|
+
|
|
14030
|
+
const isNameUnique = (state, name, excludeId)=>{
|
|
14031
|
+
const trimmedName = name.trim();
|
|
14032
|
+
if (!trimmedName) return false;
|
|
14033
|
+
return !Object.values(state.entities).some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
14034
|
+
};
|
|
14035
|
+
const generateUniqueName = (state, baseName)=>{
|
|
14036
|
+
const trimmedBaseName = baseName.trim();
|
|
14037
|
+
// If base name is unique, use it
|
|
14038
|
+
if (isNameUnique(state, trimmedBaseName)) {
|
|
14039
|
+
return trimmedBaseName;
|
|
14040
|
+
}
|
|
14041
|
+
// Find a unique name by appending numbers
|
|
14042
|
+
let counter = 1;
|
|
14043
|
+
let uniqueName;
|
|
14044
|
+
do {
|
|
14045
|
+
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
14046
|
+
counter++;
|
|
14047
|
+
}while (!isNameUnique(state, uniqueName))
|
|
14048
|
+
return uniqueName;
|
|
14049
|
+
};
|
|
14050
|
+
const createDefaultCohort = ()=>newCohort(DEFAULT_COHORT_NAME, {}, undefined, false);
|
|
14051
|
+
// Entity adapter
|
|
14052
|
+
const cohortsAdapter = toolkit.createEntityAdapter({
|
|
14053
|
+
selectId: (cohort)=>cohort.id,
|
|
14054
|
+
sortComparer: (a, b)=>{
|
|
14055
|
+
if (a.modifiedDatetime > b.modifiedDatetime) return -1;
|
|
14056
|
+
if (a.modifiedDatetime < b.modifiedDatetime) return 1;
|
|
14057
|
+
return 0;
|
|
14058
|
+
}
|
|
14059
|
+
});
|
|
14060
|
+
//const DEFAULT_COHORT_ID = 'default';
|
|
14061
|
+
const DEFAULT_COHORT_NAME = 'Default';
|
|
14062
|
+
const loadCohortsFromStorage = toolkit.createAsyncThunk('cohorts/loadFromStorage', async ()=>{
|
|
14063
|
+
try {
|
|
14064
|
+
const cohortsMap = await cohortStorage.getAllCohorts();
|
|
14065
|
+
return Object(cohortsMap).values();
|
|
14066
|
+
} catch (error) {
|
|
14067
|
+
console.error('Failed to load cohorts:', error);
|
|
14068
|
+
return [];
|
|
14069
|
+
}
|
|
14070
|
+
});
|
|
14071
|
+
const saveCohortToStorage = toolkit.createAsyncThunk('cohorts/saveToStorage', async (params, { getState })=>{
|
|
14072
|
+
const { cohortId, cohortName } = params;
|
|
14073
|
+
const state = getState();
|
|
14074
|
+
const cohort = state.cohorts.entities[cohortId];
|
|
14075
|
+
if (!cohort) {
|
|
14076
|
+
throw new Error(`Cohort with id ${cohortId} not found`);
|
|
14077
|
+
}
|
|
14078
|
+
const cohortToSave = {
|
|
14079
|
+
...cohort,
|
|
14080
|
+
name: cohortName || cohort.name,
|
|
14081
|
+
saved: true,
|
|
14082
|
+
modified: false,
|
|
14083
|
+
modifiedDatetime: new Date().toISOString()
|
|
14084
|
+
};
|
|
14085
|
+
await cohortStorage.saveCohort(cohortToSave);
|
|
14086
|
+
return cohortToSave;
|
|
14087
|
+
});
|
|
14088
|
+
const autoSaveCohort = toolkit.createAsyncThunk('cohorts/autoSave', async (cohortId, { getState })=>{
|
|
14089
|
+
const state = getState();
|
|
14090
|
+
const cohort = state.cohorts.entities[cohortId];
|
|
14091
|
+
if (!cohort || !cohort.saved) {
|
|
14092
|
+
throw new Error(`Cannot auto-save unsaved cohort ${cohortId}`);
|
|
14093
|
+
}
|
|
14094
|
+
const cohortToSave = {
|
|
14095
|
+
...cohort,
|
|
14096
|
+
modified: false,
|
|
14097
|
+
modifiedDatetime: new Date().toISOString()
|
|
14098
|
+
};
|
|
14099
|
+
await cohortStorage.saveCohort(cohortToSave);
|
|
14100
|
+
return cohortToSave;
|
|
14101
|
+
});
|
|
14102
|
+
const deleteCohortFromStorage = toolkit.createAsyncThunk('cohorts/deleteFromStorage', async (cohortId)=>{
|
|
14103
|
+
await cohortStorage.deleteCohort(cohortId);
|
|
14104
|
+
return cohortId;
|
|
14105
|
+
});
|
|
14106
|
+
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
14107
|
+
currentCohortId: 'empty',
|
|
14108
|
+
loading: false,
|
|
14109
|
+
error: null,
|
|
14110
|
+
autoSaveInProgress: []
|
|
14111
|
+
});
|
|
14112
|
+
const initialState = cohortsAdapter.addOne(emptyInitialState, createDefaultCohort());
|
|
14113
|
+
const updateAutoSave = (cohortId, state)=>{
|
|
14114
|
+
// Add to auto-save queue if not already present
|
|
14115
|
+
if (!state.autoSaveInProgress.includes(cohortId)) {
|
|
14116
|
+
state.autoSaveInProgress.push(cohortId);
|
|
14117
|
+
}
|
|
14118
|
+
};
|
|
14119
|
+
const cohortManagerSlice = toolkit.createSlice({
|
|
14120
|
+
name: 'CohortDiscovery/CohortManager',
|
|
14121
|
+
initialState,
|
|
14122
|
+
reducers: {
|
|
14123
|
+
setCurrentCohortId: (state, action)=>{
|
|
14124
|
+
if (state.entities[action.payload]) {
|
|
14125
|
+
state.currentCohortId = action.payload;
|
|
14126
|
+
}
|
|
14127
|
+
},
|
|
14128
|
+
createNewCohort: (state, action)=>{
|
|
14129
|
+
const baseName = action.payload.name || `New Cohort`;
|
|
14130
|
+
const uniqueName = generateUniqueName(state, baseName);
|
|
14131
|
+
const cohort = newCohort(uniqueName, action.payload.filters || {}, undefined, false);
|
|
14132
|
+
cohortsAdapter.addOne(state, cohort);
|
|
14133
|
+
state.currentCohortId = cohort.id;
|
|
14134
|
+
},
|
|
14135
|
+
removeCohort: (state, action)=>{
|
|
14136
|
+
const cohortId = action.payload;
|
|
14137
|
+
const totalCohorts = Object.keys(state.entities).length;
|
|
14138
|
+
if (totalCohorts <= 1) {
|
|
14139
|
+
cohortsAdapter.removeAll(state);
|
|
14140
|
+
const defaultCohort = createDefaultCohort();
|
|
14141
|
+
cohortsAdapter.addOne(state, defaultCohort);
|
|
14142
|
+
state.currentCohortId = defaultCohort.id;
|
|
14143
|
+
return;
|
|
14144
|
+
}
|
|
14145
|
+
cohortsAdapter.removeOne(state, cohortId);
|
|
14146
|
+
if (state.currentCohortId === cohortId) {
|
|
14147
|
+
const remainingIds = Object.keys(state.entities);
|
|
14148
|
+
state.currentCohortId = remainingIds[0];
|
|
14149
|
+
}
|
|
14150
|
+
state.autoSaveInProgress = state.autoSaveInProgress.filter((id)=>id !== cohortId);
|
|
14151
|
+
},
|
|
14152
|
+
updateCohortName: (state, action)=>{
|
|
14153
|
+
const { id, name } = action.payload;
|
|
14154
|
+
const cohort = state.entities[id];
|
|
14155
|
+
if (!cohort) return;
|
|
14156
|
+
const trimmedName = name.trim();
|
|
14157
|
+
// Don't update if name is empty
|
|
14158
|
+
if (!trimmedName) return;
|
|
14159
|
+
// Don't update if name hasn't changed
|
|
14160
|
+
if (cohort.name === trimmedName) return;
|
|
14161
|
+
// Check if name is unique (excluding current cohort)
|
|
14162
|
+
if (!isNameUnique(state, trimmedName, id)) {
|
|
14163
|
+
// Set error for duplicate name
|
|
14164
|
+
state.error = `A cohort named "${trimmedName}" already exists. Please choose a different name.`;
|
|
14165
|
+
return;
|
|
14166
|
+
}
|
|
14167
|
+
const wasSaved = cohort.saved;
|
|
14168
|
+
cohortsAdapter.updateOne(state, {
|
|
14169
|
+
id,
|
|
14170
|
+
changes: {
|
|
14171
|
+
name: trimmedName,
|
|
14172
|
+
modified: !wasSaved,
|
|
14173
|
+
modifiedDatetime: new Date().toISOString()
|
|
14174
|
+
}
|
|
14175
|
+
});
|
|
14176
|
+
if (wasSaved) {
|
|
14177
|
+
// Add to auto-save queue if not already present
|
|
14178
|
+
updateAutoSave(id, state);
|
|
14179
|
+
}
|
|
14180
|
+
},
|
|
14181
|
+
updateCohortFilter: (state, action)=>{
|
|
14182
|
+
const { index, field, filter } = action.payload;
|
|
14183
|
+
const currentCohort = getCurrentCohort$1(state);
|
|
14184
|
+
const wasSaved = currentCohort.saved;
|
|
14185
|
+
cohortsAdapter.updateOne(state, {
|
|
14186
|
+
id: currentCohort.id,
|
|
14187
|
+
changes: {
|
|
14188
|
+
filters: {
|
|
14189
|
+
...currentCohort.filters,
|
|
14190
|
+
[index]: {
|
|
14191
|
+
mode: currentCohort.filters?.[index]?.mode ?? 'and',
|
|
14192
|
+
root: {
|
|
14193
|
+
...currentCohort.filters?.[index]?.root ?? {},
|
|
14194
|
+
[field]: filter
|
|
14195
|
+
}
|
|
14196
|
+
}
|
|
14197
|
+
},
|
|
14198
|
+
modified: !wasSaved,
|
|
14199
|
+
modifiedDatetime: new Date().toISOString()
|
|
14200
|
+
}
|
|
14201
|
+
});
|
|
14202
|
+
if (wasSaved) {
|
|
14203
|
+
// Add to auto-save queue if not already present
|
|
14204
|
+
updateAutoSave(currentCohort.id, state);
|
|
14205
|
+
}
|
|
14206
|
+
},
|
|
14207
|
+
setCohortFilter: (state, action)=>{
|
|
14208
|
+
const { index, filters } = action.payload;
|
|
14209
|
+
const currentCohort = getCurrentCohort$1(state);
|
|
14210
|
+
const wasSaved = currentCohort.saved;
|
|
14211
|
+
cohortsAdapter.updateOne(state, {
|
|
14212
|
+
id: currentCohort.id,
|
|
14213
|
+
changes: {
|
|
14214
|
+
filters: {
|
|
14215
|
+
...currentCohort.filters,
|
|
14216
|
+
[index]: filters
|
|
14217
|
+
},
|
|
14218
|
+
modified: !wasSaved,
|
|
14219
|
+
modifiedDatetime: new Date().toISOString()
|
|
14220
|
+
}
|
|
14221
|
+
});
|
|
14222
|
+
if (wasSaved) {
|
|
14223
|
+
updateAutoSave(currentCohort.id, state);
|
|
14224
|
+
}
|
|
14225
|
+
},
|
|
14226
|
+
setAllIndexFilters: (state, action)=>{
|
|
14227
|
+
const currentCohort = getCurrentCohort$1(state);
|
|
14228
|
+
const wasSaved = currentCohort.saved;
|
|
14229
|
+
cohortsAdapter.updateOne(state, {
|
|
14230
|
+
id: currentCohort.id,
|
|
14231
|
+
changes: {
|
|
14232
|
+
filters: action.payload,
|
|
14233
|
+
modified: !wasSaved,
|
|
14234
|
+
modifiedDatetime: new Date().toISOString()
|
|
14235
|
+
}
|
|
14236
|
+
});
|
|
14237
|
+
if (wasSaved) {
|
|
14238
|
+
updateAutoSave(currentCohort.id, state);
|
|
14239
|
+
}
|
|
14240
|
+
},
|
|
14241
|
+
removeCohortFilter: (state, action)=>{
|
|
14242
|
+
const { index, field } = action.payload;
|
|
14243
|
+
const currentCohort = getCurrentCohort$1(state);
|
|
14244
|
+
const filters = currentCohort.filters?.[index]?.root;
|
|
14245
|
+
const wasSaved = currentCohort.saved;
|
|
14246
|
+
if (!filters) return;
|
|
14247
|
+
const { [field]: _removed, ...updated } = filters;
|
|
14248
|
+
cohortsAdapter.updateOne(state, {
|
|
14249
|
+
id: currentCohort.id,
|
|
14250
|
+
changes: {
|
|
14251
|
+
filters: {
|
|
14252
|
+
...currentCohort.filters,
|
|
14253
|
+
[index]: {
|
|
14254
|
+
mode: currentCohort.filters[index].mode,
|
|
14255
|
+
root: updated
|
|
14256
|
+
}
|
|
14257
|
+
},
|
|
14258
|
+
modified: !wasSaved,
|
|
14259
|
+
modifiedDatetime: new Date().toISOString()
|
|
14260
|
+
}
|
|
14261
|
+
});
|
|
14262
|
+
if (wasSaved) {
|
|
14263
|
+
updateAutoSave(currentCohort.id, state);
|
|
14264
|
+
}
|
|
14265
|
+
},
|
|
14266
|
+
clearCohortFilters: (state, action)=>{
|
|
14267
|
+
const { index } = action.payload;
|
|
14268
|
+
const currentCohort = getCurrentCohort$1(state);
|
|
14269
|
+
const wasSaved = currentCohort.saved;
|
|
14270
|
+
cohortsAdapter.updateOne(state, {
|
|
14271
|
+
id: currentCohort.id,
|
|
14272
|
+
changes: {
|
|
14273
|
+
filters: {
|
|
14274
|
+
...currentCohort.filters,
|
|
14275
|
+
[index]: EmptyFilterSet
|
|
14276
|
+
},
|
|
14277
|
+
modified: !wasSaved,
|
|
14278
|
+
modifiedDatetime: new Date().toISOString()
|
|
14279
|
+
}
|
|
14280
|
+
});
|
|
14281
|
+
if (wasSaved) {
|
|
14282
|
+
updateAutoSave(currentCohort.id, state);
|
|
14283
|
+
}
|
|
14284
|
+
},
|
|
14285
|
+
clearError: (state)=>{
|
|
14286
|
+
state.error = null;
|
|
14287
|
+
}
|
|
14288
|
+
},
|
|
14289
|
+
extraReducers: (builder)=>{
|
|
14290
|
+
builder.addCase(loadCohortsFromStorage.pending, (state)=>{
|
|
14291
|
+
state.loading = true;
|
|
14292
|
+
state.error = null;
|
|
14293
|
+
}).addCase(loadCohortsFromStorage.fulfilled, (state, action)=>{
|
|
14294
|
+
state.loading = false;
|
|
14295
|
+
if (action.payload.length > 0) {
|
|
14296
|
+
if (Object.keys(state.entities).length === 1) {
|
|
14297
|
+
cohortsAdapter.removeOne(state, state.entities[0].id);
|
|
14298
|
+
}
|
|
14299
|
+
cohortsAdapter.addMany(state, action.payload);
|
|
14300
|
+
const sortedCohorts = action.payload.sort((a, b)=>b.modifiedDatetime.localeCompare(a.modifiedDatetime));
|
|
14301
|
+
state.currentCohortId = sortedCohorts[0].id;
|
|
14302
|
+
}
|
|
14303
|
+
}).addCase(loadCohortsFromStorage.rejected, (state, action)=>{
|
|
14304
|
+
state.loading = false;
|
|
14305
|
+
state.error = action.error.message || 'Failed to load cohorts';
|
|
14306
|
+
}).addCase(saveCohortToStorage.fulfilled, (state, action)=>{
|
|
14307
|
+
cohortsAdapter.updateOne(state, {
|
|
14308
|
+
id: action.payload.id,
|
|
14309
|
+
changes: action.payload
|
|
14310
|
+
});
|
|
14311
|
+
}).addCase(saveCohortToStorage.rejected, (state, action)=>{
|
|
14312
|
+
state.error = action.error.message || 'Failed to save cohort';
|
|
14313
|
+
}).addCase(autoSaveCohort.pending, (state, action)=>{
|
|
14314
|
+
updateAutoSave(action.meta.arg, state);
|
|
14315
|
+
}).addCase(autoSaveCohort.fulfilled, (state, action)=>{
|
|
14316
|
+
state.autoSaveInProgress = state.autoSaveInProgress.filter((id)=>id !== action.payload.id);
|
|
14317
|
+
cohortsAdapter.updateOne(state, {
|
|
14318
|
+
id: action.payload.id,
|
|
14319
|
+
changes: action.payload
|
|
14320
|
+
});
|
|
14321
|
+
}).addCase(autoSaveCohort.rejected, (state, action)=>{
|
|
14322
|
+
state.autoSaveInProgress = state.autoSaveInProgress.filter((id)=>id !== action.meta.arg);
|
|
14323
|
+
console.warn(`Auto-save failed for cohort ${action.meta.arg}:`, action.error.message);
|
|
14324
|
+
}).addCase(deleteCohortFromStorage.fulfilled, (state, action)=>{
|
|
14325
|
+
const cohortId = action.payload;
|
|
14326
|
+
const totalCohorts = Object.keys(state.entities).length;
|
|
14327
|
+
if (totalCohorts <= 1) {
|
|
14328
|
+
cohortsAdapter.removeAll(state);
|
|
14329
|
+
const defaultCohort = createDefaultCohort();
|
|
14330
|
+
cohortsAdapter.addOne(state, defaultCohort);
|
|
14331
|
+
state.currentCohortId = defaultCohort.id;
|
|
14332
|
+
} else {
|
|
14333
|
+
cohortsAdapter.removeOne(state, cohortId);
|
|
14334
|
+
if (state.currentCohortId === cohortId) {
|
|
14335
|
+
const remainingIds = Object.keys(state.entities);
|
|
14336
|
+
state.currentCohortId = remainingIds[0];
|
|
14337
|
+
}
|
|
14338
|
+
}
|
|
14339
|
+
state.autoSaveInProgress = state.autoSaveInProgress.filter((id)=>id !== cohortId);
|
|
14340
|
+
});
|
|
14341
|
+
}
|
|
14342
|
+
});
|
|
14343
|
+
// Helper function
|
|
14344
|
+
const getCurrentCohort$1 = (state)=>{
|
|
14345
|
+
const cohort = state.entities[state.currentCohortId];
|
|
14346
|
+
if (!cohort) {
|
|
14347
|
+
return createDefaultCohort();
|
|
14348
|
+
}
|
|
14349
|
+
return cohort;
|
|
14350
|
+
};
|
|
14351
|
+
// Actions export
|
|
14352
|
+
const { setCurrentCohortId, createNewCohort, removeCohort, updateCohortName, updateCohortFilter, setCohortFilter, setAllIndexFilters, removeCohortFilter, clearCohortFilters } = cohortManagerSlice.actions;
|
|
14353
|
+
const cohortManagerReducer = cohortManagerSlice.reducer;
|
|
14354
|
+
|
|
14355
|
+
const getCurrentCohort = (state)=>{
|
|
14356
|
+
const cohort = state.entities[state.currentCohortId];
|
|
14357
|
+
if (!cohort) {
|
|
14358
|
+
return createDefaultCohort();
|
|
14359
|
+
}
|
|
14360
|
+
return cohort;
|
|
14361
|
+
};
|
|
14362
|
+
const autoSaveMiddleware = (store)=>(next)=>(action)=>{
|
|
14363
|
+
const result = next(action);
|
|
14364
|
+
const autoSaveActions = [
|
|
14365
|
+
'updateCohortName',
|
|
14366
|
+
'updateCohortFilter',
|
|
14367
|
+
'setCohortFilter',
|
|
14368
|
+
'setAllIndexFilters',
|
|
14369
|
+
'removeCohortFilter',
|
|
14370
|
+
'clearCohortFilters'
|
|
14371
|
+
];
|
|
14372
|
+
if (autoSaveActions.some((actionType)=>action.type.includes(actionType))) {
|
|
14373
|
+
const state = store.getState();
|
|
14374
|
+
const currentCohort = getCurrentCohort(state.cohorts);
|
|
14375
|
+
if (currentCohort.saved && !state.cohorts.autoSaveInProgress.has(currentCohort.id)) {
|
|
14376
|
+
setTimeout(()=>{
|
|
14377
|
+
const updatedState = store.getState();
|
|
14378
|
+
const updatedCohort = getCurrentCohort(updatedState.cohorts);
|
|
14379
|
+
if (updatedCohort.saved && !updatedState.cohorts.autoSaveInProgress.has(updatedCohort.id)) {
|
|
14380
|
+
store.dispatch(autoSaveCohort(updatedCohort.id));
|
|
14381
|
+
}
|
|
14382
|
+
}, 1000);
|
|
14383
|
+
}
|
|
14384
|
+
}
|
|
14385
|
+
return result;
|
|
14386
|
+
};
|
|
14387
|
+
|
|
14388
|
+
/* eslint @typescript-eslint/no-unused-vars: 0 */ // Credit to: https://github.com/vercel/next.js/discussions/15687
|
|
14389
|
+
const createNoopStorage = ()=>{
|
|
14390
|
+
return {
|
|
14391
|
+
getItem (_key) {
|
|
14392
|
+
return Promise.resolve(null);
|
|
14393
|
+
},
|
|
14394
|
+
setItem (_key, value) {
|
|
14395
|
+
return Promise.resolve(value);
|
|
14396
|
+
},
|
|
14397
|
+
removeItem (_key) {
|
|
14398
|
+
return Promise.resolve();
|
|
14399
|
+
}
|
|
14400
|
+
};
|
|
14401
|
+
};
|
|
14402
|
+
const storage = typeof window !== 'undefined' ? createWebStorage('local') : createNoopStorage();
|
|
14403
|
+
typeof window !== 'undefined' ? createWebStorage('session') : createNoopStorage();
|
|
14404
|
+
|
|
14405
|
+
// Create the entity adapter
|
|
14406
|
+
const dataAccessRequestsAdapter = toolkit.createEntityAdapter({
|
|
14407
|
+
// Select the id as the primary key
|
|
14408
|
+
selectId: (request)=>request.id,
|
|
14409
|
+
// Optional: Sort by request_datetime descending (newest first)
|
|
14410
|
+
sortComparer: (a, b)=>new Date(b.createdDatetime).getTime() - new Date(a.createdDatetime).getTime()
|
|
14411
|
+
});
|
|
14412
|
+
// Create a slice with reducers
|
|
14413
|
+
const dataAccessRequestsSlice = toolkit.createSlice({
|
|
14414
|
+
name: 'dataAccessRequests',
|
|
14415
|
+
initialState: dataAccessRequestsAdapter.getInitialState(),
|
|
14416
|
+
reducers: {
|
|
14417
|
+
addDataAccessRequest: (state, action)=>{
|
|
14418
|
+
const { cohortId, status, id, name, email, organization, createdDatetime, updatedDatetime } = action.payload;
|
|
14419
|
+
const dataAccessRequests = newDataAccessRequest(id, status, {
|
|
14420
|
+
name,
|
|
14421
|
+
email,
|
|
14422
|
+
organization
|
|
14423
|
+
}, cohortId, createdDatetime, updatedDatetime);
|
|
14424
|
+
dataAccessRequestsAdapter.addOne(state, dataAccessRequests);
|
|
14425
|
+
},
|
|
14426
|
+
// Set a request's status
|
|
14427
|
+
setRequestStatus: (state, action)=>{
|
|
14428
|
+
const { id, status } = action.payload;
|
|
14429
|
+
dataAccessRequestsAdapter.updateOne(state, {
|
|
14430
|
+
id,
|
|
14431
|
+
changes: {
|
|
14432
|
+
status
|
|
14433
|
+
}
|
|
14434
|
+
});
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
});
|
|
14438
|
+
// Export actions
|
|
14439
|
+
const { addDataAccessRequest, setRequestStatus } = dataAccessRequestsSlice.actions;
|
|
14440
|
+
// Export selectors
|
|
14441
|
+
const { selectAll: selectAllDataAccessRequests, selectById: selectDataAccessRequestById, selectIds: selectDataAccessRequestIds, selectEntities: selectDataAccessRequestEntities, selectTotal: selectTotalDataAccessRequests } = dataAccessRequestsAdapter.getSelectors((state)=>state.dataAccessRequests);
|
|
14442
|
+
const selectCohortToRequestId = toolkit.createSelector([
|
|
14443
|
+
selectAllDataAccessRequests
|
|
14444
|
+
], (requests)=>{
|
|
14445
|
+
return requests.reduce((acc, request)=>{
|
|
14446
|
+
acc[request.cohortId] = request.id;
|
|
14447
|
+
return acc;
|
|
14448
|
+
}, {});
|
|
14449
|
+
});
|
|
14450
|
+
// Export reducer
|
|
14451
|
+
const dataAccessRequestsReducer = dataAccessRequestsSlice.reducer;
|
|
14452
|
+
|
|
14453
|
+
const _APP_NAME$3 = 'CohortDiscovery';
|
|
14454
|
+
const persistConfig = {
|
|
14455
|
+
key: _APP_NAME$3,
|
|
14456
|
+
version: 1,
|
|
14457
|
+
storage
|
|
14458
|
+
};
|
|
14459
|
+
// create the store, context and selector for the ProjectsCenter
|
|
14460
|
+
// Note the project app has a local store and context which isolates
|
|
14461
|
+
// the filters and other store/cache values
|
|
14462
|
+
const reducers = redux.combineReducers({
|
|
14463
|
+
selectedIndexFacets: selectedFacetsReducer,
|
|
14464
|
+
filtersExpandedState: filtersExpandedReducer,
|
|
14465
|
+
facetDefinitionState: facetDefinitionsReducer,
|
|
14466
|
+
cohorts: cohortManagerReducer,
|
|
14467
|
+
// savedCohorts: saveCohortPersistenceReducer,
|
|
14468
|
+
dataAccessRequests: dataAccessRequestsReducer
|
|
14469
|
+
});
|
|
14470
|
+
const persistedReducers = reduxPersist.persistReducer(persistConfig, reducers);
|
|
14471
|
+
const { id, AppStore, AppContext, useAppSelector, useAppDispatch } = core.createAppStore({
|
|
14472
|
+
reducers: persistedReducers,
|
|
14473
|
+
middleware: autoSaveMiddleware,
|
|
14474
|
+
name: _APP_NAME$3,
|
|
14475
|
+
version: '0.0.1'
|
|
14476
|
+
});
|
|
14477
|
+
|
|
14478
|
+
// Selectors
|
|
14479
|
+
const { selectAll: selectAllCohorts, selectTotal: selectTotalCohorts, selectById: selectCohortById, selectIds: selectCohortIds } = cohortsAdapter.getSelectors((state)=>state.cohorts);
|
|
14480
|
+
const selectCurrentCohortId = (state)=>state.cohorts.currentCohortId;
|
|
14481
|
+
const selectCurrentCohort = (state)=>{
|
|
14482
|
+
const { currentCohortId, entities } = state.cohorts;
|
|
14483
|
+
const cohort = entities[currentCohortId];
|
|
14484
|
+
if (!cohort) {
|
|
14485
|
+
return createDefaultCohort();
|
|
14486
|
+
}
|
|
14487
|
+
return cohort;
|
|
14488
|
+
};
|
|
14489
|
+
toolkit.createSelector([
|
|
14490
|
+
selectAllCohorts
|
|
14491
|
+
], (cohorts)=>cohorts.filter((cohort)=>cohort.saved));
|
|
14492
|
+
toolkit.createSelector([
|
|
14493
|
+
selectAllCohorts
|
|
14494
|
+
], (cohorts)=>cohorts.filter((cohort)=>!cohort.saved));
|
|
14495
|
+
toolkit.createSelector([
|
|
14496
|
+
selectAllCohorts
|
|
14497
|
+
], (cohorts)=>cohorts.filter((cohort)=>cohort.modified && !cohort.saved));
|
|
14498
|
+
toolkit.createSelector([
|
|
14499
|
+
(state)=>Array.from(state.cohorts.autoSaveInProgress)
|
|
14500
|
+
], (autoSaveArray)=>autoSaveArray);
|
|
14501
|
+
toolkit.createSelector([
|
|
14502
|
+
(state)=>state.cohorts.autoSaveInProgress,
|
|
14503
|
+
(state, cohortId)=>cohortId
|
|
14504
|
+
], (autoSaveArray, cohortId)=>autoSaveArray.includes(cohortId));
|
|
14505
|
+
const selectCurrentCohortName = toolkit.createSelector([
|
|
14506
|
+
selectCurrentCohort
|
|
14507
|
+
], (cohort)=>cohort.name);
|
|
14508
|
+
const selectCurrentCohortFilters = toolkit.createSelector([
|
|
14509
|
+
selectCurrentCohort
|
|
14510
|
+
], (cohort)=>cohort.filters);
|
|
14511
|
+
const selectCurrentCohortIndexFilters = toolkit.createSelector([
|
|
14512
|
+
selectCurrentCohort,
|
|
14513
|
+
(state, index)=>index
|
|
14514
|
+
], (cohort, index)=>{
|
|
14515
|
+
return cohort.filters?.[index] ?? EmptyFilterSet;
|
|
14516
|
+
});
|
|
14517
|
+
toolkit.createSelector([
|
|
14518
|
+
selectAllCohorts,
|
|
14519
|
+
(state, name, excludeId)=>({
|
|
14520
|
+
name,
|
|
14521
|
+
excludeId
|
|
14522
|
+
})
|
|
14523
|
+
], (cohorts, params)=>{
|
|
14524
|
+
const trimmedName = params.name.trim().toLowerCase();
|
|
14525
|
+
return cohorts.some((cohort)=>cohort.id !== params.excludeId && cohort.name.trim().toLowerCase() === trimmedName);
|
|
14526
|
+
});
|
|
14527
|
+
const selectCohortManagerLoading = (state)=>state.cohorts.loading;
|
|
14528
|
+
const selectCohortIdToNameMap = toolkit.createSelector([
|
|
14529
|
+
selectAllCohorts
|
|
14530
|
+
], (cohorts)=>{
|
|
14531
|
+
return cohorts.reduce((acc, cohort)=>{
|
|
14532
|
+
acc[cohort.id] = cohort.name;
|
|
14533
|
+
return acc;
|
|
14534
|
+
}, {});
|
|
14535
|
+
});
|
|
14536
|
+
|
|
14537
|
+
const useToggleExpandFilter = ()=>{
|
|
14538
|
+
const dispatch = useAppDispatch();
|
|
14539
|
+
return (field, expanded)=>{
|
|
14540
|
+
dispatch(toggleCategoryFilter({
|
|
14541
|
+
field,
|
|
14542
|
+
expanded
|
|
14543
|
+
}));
|
|
14544
|
+
};
|
|
14545
|
+
};
|
|
14546
|
+
const useFilterExpandedState = (field)=>{
|
|
14547
|
+
return useAppSelector((state)=>selectFilterExpanded(state, field));
|
|
14548
|
+
};
|
|
14549
|
+
const useCohortFacetFilters = (index)=>{
|
|
14550
|
+
return useAppSelector((state)=>selectCurrentCohortFilters(state)[index]);
|
|
14551
|
+
};
|
|
14552
|
+
const useClearFilters = (index)=>{
|
|
14553
|
+
const dispatch = useAppDispatch();
|
|
14554
|
+
return (field)=>{
|
|
14555
|
+
dispatch(removeCohortFilter({
|
|
14556
|
+
index,
|
|
14557
|
+
field
|
|
14558
|
+
}));
|
|
14559
|
+
};
|
|
14560
|
+
};
|
|
14561
|
+
/**
|
|
14562
|
+
* Update Guppy filters: process nested fields and have the final
|
|
14563
|
+
* leaf be filtered
|
|
14564
|
+
* @param index
|
|
14565
|
+
*/ const useUpdateFilters = (index)=>{
|
|
14566
|
+
const dispatch = useAppDispatch();
|
|
14567
|
+
// update the filter for this facet
|
|
14568
|
+
return (field, filter)=>{
|
|
14569
|
+
dispatch(updateCohortFilter({
|
|
14570
|
+
index: index,
|
|
14571
|
+
field: field,
|
|
14572
|
+
filter: buildNested(field, filter)
|
|
13856
14573
|
}));
|
|
13857
14574
|
};
|
|
13858
14575
|
};
|
|
13859
14576
|
const useGetFacetFilters = (index, field)=>{
|
|
13860
|
-
return useAppSelector((
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
14577
|
+
return useAppSelector(selectCurrentCohortIndexFilters(index, field) ?? {
|
|
14578
|
+
operator: 'and',
|
|
14579
|
+
operands: []
|
|
14580
|
+
});
|
|
13864
14581
|
};
|
|
13865
14582
|
|
|
13866
14583
|
const EnumFacetPanel = ({ facet, hooks, valueLabel, showTotals = false, chartType = 'bar' })=>{
|
|
@@ -13879,12 +14596,12 @@ const EnumFacetPanel = ({ facet, hooks, valueLabel, showTotals = false, chartTyp
|
|
|
13879
14596
|
label,
|
|
13880
14597
|
field
|
|
13881
14598
|
]);
|
|
13882
|
-
//const { data } = hooks.useGetFacetData(field);
|
|
13883
14599
|
const chart = createChart(chartType, {
|
|
13884
14600
|
data: visibleData,
|
|
13885
14601
|
total: 1,
|
|
13886
14602
|
valueType: 'count'
|
|
13887
14603
|
});
|
|
14604
|
+
const clearFilters = hooks.useClearFilter();
|
|
13888
14605
|
return /*#__PURE__*/ jsxRuntime.jsxs("div", {
|
|
13889
14606
|
className: "flex flex-col bg-base-max relative border-base border-1 rounded-b-md transition",
|
|
13890
14607
|
children: [
|
|
@@ -13896,9 +14613,26 @@ const EnumFacetPanel = ({ facet, hooks, valueLabel, showTotals = false, chartTyp
|
|
|
13896
14613
|
fw: 600,
|
|
13897
14614
|
children: facetName
|
|
13898
14615
|
}),
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
14616
|
+
/*#__PURE__*/ jsxRuntime.jsxs("div", {
|
|
14617
|
+
className: "flex nowrap",
|
|
14618
|
+
children: [
|
|
14619
|
+
showTotals ? /*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
|
|
14620
|
+
children: "Todo"
|
|
14621
|
+
}) : null,
|
|
14622
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
14623
|
+
label: "Clear selection",
|
|
14624
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(FacetIconButton, {
|
|
14625
|
+
onClick: ()=>clearFilters(field),
|
|
14626
|
+
"aria-label": "clear selection",
|
|
14627
|
+
color: "accent.4",
|
|
14628
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(fa.FaUndo, {
|
|
14629
|
+
size: "1.0em",
|
|
14630
|
+
"aria-hidden": "true"
|
|
14631
|
+
})
|
|
14632
|
+
})
|
|
14633
|
+
})
|
|
14634
|
+
]
|
|
14635
|
+
})
|
|
13902
14636
|
]
|
|
13903
14637
|
}),
|
|
13904
14638
|
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
@@ -14377,7 +15111,7 @@ const NUM_COLS = 2; // TODO: add to config
|
|
|
14377
15111
|
* @param {Array} facets - The list of facets to be rendered.
|
|
14378
15112
|
* @returns {JSX.Element} The rendered component showing facets.
|
|
14379
15113
|
*/ const ChartsAndFacetsPanel = ({ index, facets })=>{
|
|
14380
|
-
const cohortFilters = useAppSelector((state)=>
|
|
15114
|
+
const cohortFilters = useAppSelector((state)=>selectCurrentCohortIndexFilters(state, index));
|
|
14381
15115
|
const { data, isSuccess} = useRoundedAggsQuery({
|
|
14382
15116
|
type: index,
|
|
14383
15117
|
fields: facets.map((x)=>x.field),
|
|
@@ -14449,105 +15183,483 @@ const NUM_COLS = 2; // TODO: add to config
|
|
|
14449
15183
|
});
|
|
14450
15184
|
};
|
|
14451
15185
|
|
|
14452
|
-
const
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
15186
|
+
const IconSize = {
|
|
15187
|
+
xs: 14,
|
|
15188
|
+
sm: 16,
|
|
15189
|
+
md: 20,
|
|
15190
|
+
lg: 24,
|
|
15191
|
+
xl: 32,
|
|
15192
|
+
'xl-2': 36
|
|
15193
|
+
};
|
|
15194
|
+
|
|
15195
|
+
const DataAccessRequestForm = ({ cohortId, submitFunction, close })=>{
|
|
15196
|
+
const [submitted, setSubmitted] = React.useState(false);
|
|
15197
|
+
const form$1 = form.useForm({
|
|
15198
|
+
initialValues: {
|
|
15199
|
+
name: '',
|
|
15200
|
+
organization: '',
|
|
15201
|
+
email: ''
|
|
15202
|
+
},
|
|
15203
|
+
validate: {
|
|
15204
|
+
name: form.isNotEmpty('Name is required'),
|
|
15205
|
+
email: form.isEmail('Please provide a valid email')
|
|
15206
|
+
}
|
|
15207
|
+
});
|
|
15208
|
+
const handleSubmit = async (values)=>{
|
|
15209
|
+
submitFunction(cohortId, values);
|
|
15210
|
+
setSubmitted(true);
|
|
15211
|
+
};
|
|
15212
|
+
if (submitted) {
|
|
15213
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Paper, {
|
|
15214
|
+
shadow: "md",
|
|
15215
|
+
p: "xl",
|
|
15216
|
+
radius: "md",
|
|
15217
|
+
children: [
|
|
15218
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Title, {
|
|
15219
|
+
order: 2,
|
|
15220
|
+
mb: "md",
|
|
15221
|
+
ta: "center",
|
|
15222
|
+
children: "Request Submitted"
|
|
15223
|
+
}),
|
|
15224
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
|
|
15225
|
+
ta: "center",
|
|
15226
|
+
children: "Thank you for your data access request. We will review your submission and contact you shortly."
|
|
15227
|
+
}),
|
|
15228
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Group, {
|
|
15229
|
+
justify: "center",
|
|
15230
|
+
mt: "xl",
|
|
15231
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15232
|
+
onClick: ()=>close(),
|
|
15233
|
+
children: "Dismiss"
|
|
15234
|
+
})
|
|
15235
|
+
})
|
|
15236
|
+
]
|
|
15237
|
+
});
|
|
15238
|
+
}
|
|
15239
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Paper, {
|
|
15240
|
+
radius: "md",
|
|
14458
15241
|
children: [
|
|
14459
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
|
|
14465
|
-
|
|
14466
|
-
|
|
15242
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
|
|
15243
|
+
c: "dimmed",
|
|
15244
|
+
mb: "lg",
|
|
15245
|
+
children: "Please complete all fields to request access to our research data."
|
|
15246
|
+
}),
|
|
15247
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Divider, {
|
|
15248
|
+
mb: "lg"
|
|
15249
|
+
}),
|
|
15250
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Box, {
|
|
15251
|
+
component: "form",
|
|
15252
|
+
onSubmit: form$1.onSubmit(handleSubmit),
|
|
14467
15253
|
children: /*#__PURE__*/ jsxRuntime.jsxs(core$1.Stack, {
|
|
14468
|
-
|
|
15254
|
+
gap: "md",
|
|
14469
15255
|
children: [
|
|
14470
15256
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
|
|
15257
|
+
label: "Full Name",
|
|
15258
|
+
placeholder: "John Doe",
|
|
15259
|
+
withAsterisk: true,
|
|
15260
|
+
...form$1.getInputProps('name')
|
|
15261
|
+
}),
|
|
15262
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
15263
|
+
label: "Organization",
|
|
15264
|
+
placeholder: "University, Organization, or Company",
|
|
15265
|
+
withAsterisk: true,
|
|
15266
|
+
...form$1.getInputProps('organization')
|
|
15267
|
+
}),
|
|
15268
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
15269
|
+
label: "Email",
|
|
15270
|
+
placeholder: "your.email@institution.edu",
|
|
15271
|
+
withAsterisk: true,
|
|
15272
|
+
...form$1.getInputProps('email')
|
|
14480
15273
|
}),
|
|
14481
15274
|
/*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
14482
15275
|
justify: "flex-end",
|
|
14483
|
-
className: "bg-base-lighter -m-4 p-3 mt-3",
|
|
14484
15276
|
children: [
|
|
14485
15277
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15278
|
+
type: "reset",
|
|
14486
15279
|
variant: "outline",
|
|
14487
|
-
onClick:
|
|
14488
|
-
children: "
|
|
15280
|
+
onClick: ()=>form$1.reset(),
|
|
15281
|
+
children: "Reset"
|
|
14489
15282
|
}),
|
|
14490
15283
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
14491
|
-
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14497
|
-
|
|
14498
|
-
children: "Save"
|
|
15284
|
+
variant: "outline",
|
|
15285
|
+
onClick: ()=>close(),
|
|
15286
|
+
children: submitted ? 'Close' : 'Cancel'
|
|
15287
|
+
}),
|
|
15288
|
+
!submitted && /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15289
|
+
type: "submit",
|
|
15290
|
+
children: "Submit Request"
|
|
14499
15291
|
})
|
|
14500
15292
|
]
|
|
14501
15293
|
})
|
|
14502
15294
|
]
|
|
14503
15295
|
})
|
|
15296
|
+
})
|
|
15297
|
+
]
|
|
15298
|
+
});
|
|
15299
|
+
};
|
|
15300
|
+
|
|
15301
|
+
class QueryAllIndexedError extends Error {
|
|
15302
|
+
constructor(message){
|
|
15303
|
+
super(message);
|
|
15304
|
+
this.name = 'QueryAllIndexedError';
|
|
15305
|
+
}
|
|
15306
|
+
}
|
|
15307
|
+
/**
|
|
15308
|
+
* Queries all resources based on the provided filters and resource fields, executing an aggregation query for each resource type.
|
|
15309
|
+
*
|
|
15310
|
+
* @async
|
|
15311
|
+
* @function
|
|
15312
|
+
* @param {IndexedFilterSet} filters - A set of filters indexed by resource types, used to refine the query results for each resource type.
|
|
15313
|
+
* @param {IndexResourceField} resourceFields - A mapping of resource types to their respective field configurations, including resource paths and field details.
|
|
15314
|
+
* @param {TriggerFunctionType} triggerAggsQuery - A function that triggers the aggregation query for a specific resource type and its associated fields.
|
|
15315
|
+
* @param {string[]} [excludeList=['', 'no data']] - An optional list of strings to exclude from the results, with default values set to an empty string and "no data".
|
|
15316
|
+
* @returns {Promise<string[]>} A promise that resolves to an array of resource paths for all queried and processed resources.
|
|
15317
|
+
* @throws {QueryAllIndexedError} Throws an error if the query operation fails or an unknown error occurs during execution.
|
|
15318
|
+
*/ const queryAllResources = async (filters, resourceFields, triggerAggsQuery, excludeList = [
|
|
15319
|
+
'',
|
|
15320
|
+
'no data'
|
|
15321
|
+
])=>{
|
|
15322
|
+
try {
|
|
15323
|
+
const promises = Object.entries(resourceFields).map(([index, fieldConfig])=>triggerAggsQuery({
|
|
15324
|
+
filters: filters[index],
|
|
15325
|
+
type: index,
|
|
15326
|
+
fields: [
|
|
15327
|
+
fieldConfig.resourceField
|
|
15328
|
+
],
|
|
15329
|
+
accessibility: core.Accessibility.ALL
|
|
15330
|
+
}).unwrap().then((result)=>({
|
|
15331
|
+
index,
|
|
15332
|
+
result
|
|
15333
|
+
})));
|
|
15334
|
+
const resources = await Promise.all(promises);
|
|
15335
|
+
const resultsByIndex = resources.reduce((acc, resource)=>{
|
|
15336
|
+
const filteredResults = Object.values(resource.result).map((hist)=>hist.map((h)=>h.key)).flat().filter((x)=>typeof x === 'string' && !excludeList.includes(x));
|
|
15337
|
+
const uniqueResults = new Set(filteredResults);
|
|
15338
|
+
const stringResults = Array.from(uniqueResults);
|
|
15339
|
+
acc[resource.index] = stringResults;
|
|
15340
|
+
return acc;
|
|
15341
|
+
}, {});
|
|
15342
|
+
return Object.entries(resultsByIndex).reduce((acc, [index, results])=>{
|
|
15343
|
+
const resourcePath = resourceFields[index].resourcePath;
|
|
15344
|
+
if (resourcePath) {
|
|
15345
|
+
acc.push(...results.map((x)=>`${resourcePath}/${x}`));
|
|
15346
|
+
} else {
|
|
15347
|
+
acc.push(...results.map((x)=>`/${x}`));
|
|
15348
|
+
}
|
|
15349
|
+
return acc;
|
|
15350
|
+
}, []);
|
|
15351
|
+
} catch (error) {
|
|
15352
|
+
if (error instanceof Error) {
|
|
15353
|
+
throw new QueryAllIndexedError(error.message);
|
|
15354
|
+
} else {
|
|
15355
|
+
throw new QueryAllIndexedError('Unknown error');
|
|
15356
|
+
}
|
|
15357
|
+
}
|
|
15358
|
+
};
|
|
15359
|
+
|
|
15360
|
+
const REQUESTOR_HTTP_ERROR_MESSAGES = {
|
|
15361
|
+
401: 'You are not authorized to request access to this data. Please contact the site administrator.',
|
|
15362
|
+
403: 'You do not have the correct permissions to request this resource. Please contact the site administrator.'
|
|
15363
|
+
};
|
|
15364
|
+
const submitCohortRequestAction = async (cohort, values, user, indexResources, remoteSupportService, appDispatch, getAggs, createRequestQuery)=>{
|
|
15365
|
+
if (cohort && values) {
|
|
15366
|
+
// need to get the resources requires by the cohort
|
|
15367
|
+
try {
|
|
15368
|
+
// query for resources from
|
|
15369
|
+
const resources = await queryAllResources(cohort.filters, indexResources, getAggs);
|
|
15370
|
+
// now we have the resources, submit a requestor request
|
|
15371
|
+
const request = await createRequestQuery({
|
|
15372
|
+
resource_paths: resources
|
|
15373
|
+
}).unwrap();
|
|
15374
|
+
// followed by a zendesk request
|
|
15375
|
+
const zendeskRequestAction = core.getRemoteSupportServiceRegistry().getSupportService(remoteSupportService.service);
|
|
15376
|
+
await zendeskRequestAction({
|
|
15377
|
+
subject: `Request for access to ${cohort.name}`,
|
|
15378
|
+
fullName: `${values.name}`,
|
|
15379
|
+
email: `${values.email}`,
|
|
15380
|
+
contents: `Requestor: ${values.name} (${values.email})` + `\n\nCohort: ${cohort.name}` + `\n\nResources: ${resources.join(', ')}` + `\n\nRequestor ID: ${user?.username || 'unknown'}` + `\n\nRequest ID: ${request.request_id}` + `\n\nRequest URL: ${window.location.href}` + `\n\nRequestor Email: ${values.email}` + `\n\nRequestor Name: ${values.name}` + `\n\nRequestor Organization: ${values.organization}`
|
|
15381
|
+
}, remoteSupportService.configuration);
|
|
15382
|
+
// update the request store
|
|
15383
|
+
appDispatch(addDataAccessRequest({
|
|
15384
|
+
cohortId: cohort.id,
|
|
15385
|
+
id: request.request_id ?? 'unknown',
|
|
15386
|
+
name: values.name,
|
|
15387
|
+
email: values.email,
|
|
15388
|
+
status: request.status ?? 'unknown',
|
|
15389
|
+
organization: values.organization,
|
|
15390
|
+
createdDatetime: request.created_time ?? 'unknown',
|
|
15391
|
+
updatedDatetime: request.updated_time ?? 'unknown'
|
|
15392
|
+
}));
|
|
15393
|
+
// Close the modal after a successful dispatch
|
|
15394
|
+
close();
|
|
15395
|
+
} catch (error) {
|
|
15396
|
+
if (error instanceof QueryAllIndexedError) {
|
|
15397
|
+
notifications.notifications.show({
|
|
15398
|
+
title: 'Request Cohort',
|
|
15399
|
+
message: `Error while getting resources for cohort: ${error.message}`
|
|
15400
|
+
});
|
|
15401
|
+
} else if (core.isHttpStatusError(error)) {
|
|
15402
|
+
const httpError = error;
|
|
15403
|
+
notifications.notifications.show({
|
|
15404
|
+
title: 'Request Cohort',
|
|
15405
|
+
message: REQUESTOR_HTTP_ERROR_MESSAGES[httpError.status] || `Error while submitting resource request for cohorts`
|
|
15406
|
+
});
|
|
15407
|
+
} else if (error instanceof core.MissingServiceConfigurationError) {
|
|
15408
|
+
notifications.notifications.show({
|
|
15409
|
+
title: 'Request Cohort',
|
|
15410
|
+
message: `Error while submitting resource request for cohorts: ${error.message}`
|
|
15411
|
+
});
|
|
15412
|
+
} else if (error instanceof Error) {
|
|
15413
|
+
notifications.notifications.show({
|
|
15414
|
+
title: 'Request Cohort',
|
|
15415
|
+
message: `Error while submitting resource request for cohorts: ${error.message}`
|
|
15416
|
+
});
|
|
15417
|
+
} else {
|
|
15418
|
+
notifications.notifications.show({
|
|
15419
|
+
title: 'Request Cohort',
|
|
15420
|
+
message: 'Unknown error while submitting resource request for cohorts'
|
|
15421
|
+
});
|
|
15422
|
+
}
|
|
15423
|
+
}
|
|
15424
|
+
}
|
|
15425
|
+
};
|
|
15426
|
+
|
|
15427
|
+
const CohortManager = ({ indexResources, remoteSupportService, size = 'md' })=>{
|
|
15428
|
+
const dispatch = useAppDispatch();
|
|
15429
|
+
const [isEditing, setIsEditing] = React.useState(false);
|
|
15430
|
+
const [editingLabel, setEditingLabel] = React.useState('');
|
|
15431
|
+
const allCohorts = useAppSelector(selectAllCohorts);
|
|
15432
|
+
const currentCohort = useAppSelector(selectCurrentCohort);
|
|
15433
|
+
const loading = useAppSelector(selectCohortManagerLoading);
|
|
15434
|
+
const appDispatch = useAppDispatch();
|
|
15435
|
+
const [getGetAggs] = core.useLazyGetAggsNoFilterSelfQuery();
|
|
15436
|
+
const [requestQuery] = core.useCreateRequestMutation();
|
|
15437
|
+
const user = core.useCoreSelector(core.selectUserDetails);
|
|
15438
|
+
const theme = core$1.useMantineTheme();
|
|
15439
|
+
const iconSize = IconSize[size] || IconSize['sm'];
|
|
15440
|
+
const startEditing = ()=>{
|
|
15441
|
+
setIsEditing(true);
|
|
15442
|
+
setEditingLabel(currentCohort.name);
|
|
15443
|
+
};
|
|
15444
|
+
const hasNoFilters = currentCohort ? isIndexedFilterSetEmpty(currentCohort?.filters) : true;
|
|
15445
|
+
const cancelEditing = ()=>{
|
|
15446
|
+
setIsEditing(false);
|
|
15447
|
+
setEditingLabel('');
|
|
15448
|
+
};
|
|
15449
|
+
const saveEdit = ()=>{
|
|
15450
|
+
if (editingLabel.trim() === '' || !currentCohort.name) return;
|
|
15451
|
+
dispatch(updateCohortName({
|
|
15452
|
+
id: currentCohort.id,
|
|
15453
|
+
name: editingLabel
|
|
15454
|
+
}));
|
|
15455
|
+
setIsEditing(false);
|
|
15456
|
+
setEditingLabel('');
|
|
15457
|
+
};
|
|
15458
|
+
const handleCreateNew = ()=>{
|
|
15459
|
+
dispatch(createNewCohort({
|
|
15460
|
+
name: 'New Cohort'
|
|
15461
|
+
}));
|
|
15462
|
+
};
|
|
15463
|
+
const selectData = React.useMemo(()=>{
|
|
15464
|
+
return allCohorts.map((cohort)=>({
|
|
15465
|
+
label: cohort.name,
|
|
15466
|
+
value: cohort.id
|
|
15467
|
+
}));
|
|
15468
|
+
}, [
|
|
15469
|
+
allCohorts
|
|
15470
|
+
]);
|
|
15471
|
+
const onSelectCohort = React.useCallback((_value, option)=>{
|
|
15472
|
+
if (option) {
|
|
15473
|
+
dispatch(setCurrentCohortId(option.value));
|
|
15474
|
+
}
|
|
15475
|
+
}, [
|
|
15476
|
+
dispatch
|
|
15477
|
+
]);
|
|
15478
|
+
const handleCohortAccessRequest = async (cohortId, values)=>{
|
|
15479
|
+
const cohort = allCohorts.find((obj)=>obj.id === cohortId);
|
|
15480
|
+
if (cohort) await submitCohortRequestAction(cohort, values, user, indexResources, remoteSupportService, appDispatch, getGetAggs, requestQuery);
|
|
15481
|
+
};
|
|
15482
|
+
if (loading) {
|
|
15483
|
+
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
15484
|
+
children: "Loading cohorts..."
|
|
15485
|
+
});
|
|
15486
|
+
}
|
|
15487
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
15488
|
+
gap: "xs",
|
|
15489
|
+
className: "flex pt-4 pl-2",
|
|
15490
|
+
children: [
|
|
15491
|
+
!isEditing ? /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
15492
|
+
children: [
|
|
15493
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Select, {
|
|
15494
|
+
data: selectData,
|
|
15495
|
+
value: currentCohort?.id ?? null,
|
|
15496
|
+
onChange: onSelectCohort
|
|
15497
|
+
}),
|
|
15498
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15499
|
+
label: "Rename selected cohort",
|
|
15500
|
+
position: "bottom",
|
|
15501
|
+
withArrow: true,
|
|
15502
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15503
|
+
variant: "action",
|
|
15504
|
+
color: "secondary.4",
|
|
15505
|
+
onClick: startEditing,
|
|
15506
|
+
title: `Rename ${currentCohort?.name}`,
|
|
15507
|
+
"data-testid": "renameCohort",
|
|
15508
|
+
"aria-label": "Rename cohort",
|
|
15509
|
+
size: `compact-${size}`,
|
|
15510
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
|
|
15511
|
+
icon: "gen3:edit",
|
|
15512
|
+
height: iconSize,
|
|
15513
|
+
width: iconSize
|
|
15514
|
+
})
|
|
15515
|
+
})
|
|
15516
|
+
})
|
|
15517
|
+
]
|
|
15518
|
+
}) : /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
15519
|
+
gap: "xs",
|
|
15520
|
+
children: [
|
|
15521
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
15522
|
+
value: editingLabel,
|
|
15523
|
+
onChange: (e)=>setEditingLabel(e.target.value),
|
|
15524
|
+
placeholder: "Enter new name",
|
|
15525
|
+
onKeyDown: (e)=>{
|
|
15526
|
+
if (e.key === 'Enter' && editingLabel.trim()) saveEdit();
|
|
15527
|
+
if (e.key === 'Escape') cancelEditing();
|
|
15528
|
+
},
|
|
15529
|
+
autoFocus: true,
|
|
15530
|
+
style: {
|
|
15531
|
+
flex: 1
|
|
15532
|
+
}
|
|
15533
|
+
}),
|
|
15534
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15535
|
+
label: "Apply rename",
|
|
15536
|
+
position: "bottom",
|
|
15537
|
+
withArrow: true,
|
|
15538
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15539
|
+
variant: "action",
|
|
15540
|
+
color: "secondary.4",
|
|
15541
|
+
onClick: saveEdit,
|
|
15542
|
+
"data-testid": "completeCohortRenameButton",
|
|
15543
|
+
"aria-label": "Complete rename cohort",
|
|
15544
|
+
disabled: editingLabel.trim() === '' || editingLabel.trim() === currentCohort.name,
|
|
15545
|
+
size: `compact-${size}`,
|
|
15546
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
|
|
15547
|
+
icon: "gen3:check",
|
|
15548
|
+
height: iconSize,
|
|
15549
|
+
width: iconSize
|
|
15550
|
+
})
|
|
15551
|
+
})
|
|
15552
|
+
}),
|
|
15553
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15554
|
+
label: "Cancel rename",
|
|
15555
|
+
position: "bottom",
|
|
15556
|
+
withArrow: true,
|
|
15557
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15558
|
+
variant: "action",
|
|
15559
|
+
"data-testid": "cancelRenameButton",
|
|
15560
|
+
"aria-label": "Cancel rename cohort",
|
|
15561
|
+
color: theme.colors.accent[4],
|
|
15562
|
+
onClick: cancelEditing,
|
|
15563
|
+
size: `compact-${size}`,
|
|
15564
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(md.MdClose, {
|
|
15565
|
+
size: "1.5em",
|
|
15566
|
+
"aria-hidden": "true"
|
|
15567
|
+
})
|
|
15568
|
+
})
|
|
15569
|
+
})
|
|
15570
|
+
]
|
|
15571
|
+
}),
|
|
15572
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15573
|
+
label: "Create a new cohort",
|
|
15574
|
+
position: "bottom",
|
|
15575
|
+
withArrow: true,
|
|
15576
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15577
|
+
size: `compact-${size}`,
|
|
15578
|
+
"data-testid": "addButton",
|
|
15579
|
+
"aria-label": "Add cohort",
|
|
15580
|
+
variant: "action",
|
|
15581
|
+
color: "secondary.4",
|
|
15582
|
+
onClick: handleCreateNew,
|
|
15583
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(md.MdAdd, {
|
|
15584
|
+
size: "1.5em",
|
|
15585
|
+
"aria-hidden": "true"
|
|
15586
|
+
})
|
|
15587
|
+
})
|
|
14504
15588
|
}),
|
|
14505
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14522
|
-
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
15589
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15590
|
+
label: "Delete selected cohort",
|
|
15591
|
+
position: "bottom",
|
|
15592
|
+
withArrow: true,
|
|
15593
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15594
|
+
size: `compact-${size}`,
|
|
15595
|
+
"data-testid": "uploadButton",
|
|
15596
|
+
"aria-label": "Upload cohort",
|
|
15597
|
+
variant: "action",
|
|
15598
|
+
onClick: ()=>{
|
|
15599
|
+
modals.modals.openConfirmModal({
|
|
15600
|
+
title: `Delete Cohort: ${currentCohort?.name}`,
|
|
15601
|
+
centered: true,
|
|
15602
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(core$1.Text, {
|
|
15603
|
+
size: "sm",
|
|
15604
|
+
children: [
|
|
15605
|
+
"Are you sure you want to delete your cohort? Deleted cohorts cannot be restored.",
|
|
15606
|
+
' ',
|
|
15607
|
+
currentCohort?.requests?.length > 0 ? `This cohort has ${currentCohort?.requests?.length} requests. Deleting this cohort will results in not being able to correlate nay pending requests.
|
|
15608
|
+
Are you sure you want to delete this cohort?.` : ''
|
|
15609
|
+
]
|
|
15610
|
+
}),
|
|
15611
|
+
labels: {
|
|
15612
|
+
confirm: 'Delete Cohort',
|
|
15613
|
+
cancel: 'Cancel'
|
|
15614
|
+
},
|
|
15615
|
+
confirmProps: {
|
|
15616
|
+
color: theme.colors.accent[4]
|
|
15617
|
+
},
|
|
15618
|
+
onConfirm: ()=>{
|
|
15619
|
+
dispatch(removeCohort(currentCohort.id));
|
|
15620
|
+
}
|
|
15621
|
+
});
|
|
15622
|
+
},
|
|
15623
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
|
|
15624
|
+
icon: "gen3:delete",
|
|
15625
|
+
height: iconSize,
|
|
15626
|
+
width: iconSize
|
|
15627
|
+
})
|
|
15628
|
+
})
|
|
14527
15629
|
}),
|
|
14528
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.
|
|
14529
|
-
|
|
14530
|
-
|
|
14531
|
-
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
|
|
14535
|
-
|
|
15630
|
+
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15631
|
+
label: hasNoFilters ? 'No Filters defined. Cannot submit request.' : 'Submit Data Access Request',
|
|
15632
|
+
position: "bottom",
|
|
15633
|
+
withArrow: true,
|
|
15634
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
15635
|
+
size: `compact-${size}`,
|
|
15636
|
+
"data-testid": "cohortManager-requestCohortAccessButton",
|
|
15637
|
+
"aria-label": "Request cohort access",
|
|
15638
|
+
variant: "action",
|
|
15639
|
+
disabled: hasNoFilters,
|
|
15640
|
+
onClick: ()=>{
|
|
15641
|
+
const modelId = modals.modals.open({
|
|
15642
|
+
title: 'DATA ACCESS REQUEST',
|
|
15643
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(DataAccessRequestForm, {
|
|
15644
|
+
cohortId: currentCohort.id,
|
|
15645
|
+
submitFunction: handleCohortAccessRequest,
|
|
15646
|
+
close: ()=>modals.modals.close(modelId)
|
|
15647
|
+
})
|
|
15648
|
+
});
|
|
15649
|
+
},
|
|
15650
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(react.Icon, {
|
|
15651
|
+
icon: "gen3:request",
|
|
15652
|
+
height: iconSize,
|
|
15653
|
+
width: iconSize
|
|
15654
|
+
})
|
|
15655
|
+
})
|
|
14536
15656
|
}),
|
|
14537
|
-
|
|
14538
|
-
size: "sm",
|
|
14539
|
-
variant: "outline",
|
|
14540
|
-
color: "secondary.4",
|
|
14541
|
-
classNames: {
|
|
14542
|
-
root: 'bg-base-max'
|
|
14543
|
-
},
|
|
14544
|
-
children: "Import Cohort"
|
|
14545
|
-
})
|
|
15657
|
+
null
|
|
14546
15658
|
]
|
|
14547
15659
|
});
|
|
14548
15660
|
};
|
|
14549
15661
|
|
|
14550
|
-
const
|
|
15662
|
+
const CohortQueryExpression = ({ index })=>{
|
|
14551
15663
|
const currentCohortId = useAppSelector((state)=>selectCurrentCohortId(state));
|
|
14552
15664
|
const currentCohortName = useAppSelector((state)=>selectCurrentCohortName(state));
|
|
14553
15665
|
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
@@ -14594,7 +15706,7 @@ const CohortManager = ({ index })=>{
|
|
|
14594
15706
|
});
|
|
14595
15707
|
};
|
|
14596
15708
|
|
|
14597
|
-
const IndexPanel = ({ dataConfig, tabs, tabTitle, emptySelection })=>{
|
|
15709
|
+
const IndexPanel = ({ dataConfig, tabs, tabTitle, emptySelection, indexResources, remoteSupportService })=>{
|
|
14598
15710
|
const [activeFieldDefinitions, setActiveFieldDefinitions] = React.useState([]);
|
|
14599
15711
|
const appDispatch = useAppDispatch();
|
|
14600
15712
|
const index = dataConfig.dataType;
|
|
@@ -14619,7 +15731,7 @@ const IndexPanel = ({ dataConfig, tabs, tabTitle, emptySelection })=>{
|
|
|
14619
15731
|
selectedFacets,
|
|
14620
15732
|
facetDefinitions
|
|
14621
15733
|
]);
|
|
14622
|
-
const cohortFilters = useAppSelector((state)=>
|
|
15734
|
+
const cohortFilters = useAppSelector((state)=>selectCurrentCohortIndexFilters(state, index));
|
|
14623
15735
|
const queryFields = categories.length === 0 ? fields : activeFieldDefinitions.map((x)=>x.field);
|
|
14624
15736
|
const { data, isSuccess, isError: isAggsQueryError } = useRoundedAggsQuery({
|
|
14625
15737
|
type: index,
|
|
@@ -14686,10 +15798,11 @@ const IndexPanel = ({ dataConfig, tabs, tabTitle, emptySelection })=>{
|
|
|
14686
15798
|
}
|
|
14687
15799
|
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Stack, {
|
|
14688
15800
|
children: [
|
|
14689
|
-
/*#__PURE__*/ jsxRuntime.jsx(
|
|
15801
|
+
/*#__PURE__*/ jsxRuntime.jsx(CohortQueryExpression, {
|
|
14690
15802
|
index: index
|
|
14691
15803
|
}),
|
|
14692
15804
|
/*#__PURE__*/ jsxRuntime.jsxs(core$1.Flex, {
|
|
15805
|
+
wrap: "nowrap",
|
|
14693
15806
|
className: "flex h-full bg-base-light pb-4 ml-4",
|
|
14694
15807
|
children: [
|
|
14695
15808
|
/*#__PURE__*/ jsxRuntime.jsx(FacetSelectionPanel, {
|
|
@@ -14703,10 +15816,11 @@ const IndexPanel = ({ dataConfig, tabs, tabTitle, emptySelection })=>{
|
|
|
14703
15816
|
}
|
|
14704
15817
|
}),
|
|
14705
15818
|
/*#__PURE__*/ jsxRuntime.jsxs(core$1.Stack, {
|
|
14706
|
-
className: "w-
|
|
15819
|
+
className: "w-full md:w-[40rem] lg:w-[50rem] xl:w-[60rem] mr-2 min-h-[500px]",
|
|
14707
15820
|
children: [
|
|
14708
|
-
/*#__PURE__*/ jsxRuntime.jsx(
|
|
14709
|
-
|
|
15821
|
+
/*#__PURE__*/ jsxRuntime.jsx(CohortManager, {
|
|
15822
|
+
indexResources: indexResources,
|
|
15823
|
+
remoteSupportService: remoteSupportService
|
|
14710
15824
|
}),
|
|
14711
15825
|
selectedFacets.length > 0 ? /*#__PURE__*/ jsxRuntime.jsx(ChartsAndFacetsPanel, {
|
|
14712
15826
|
index: index,
|
|
@@ -14741,147 +15855,6 @@ const IndexPanel = ({ dataConfig, tabs, tabTitle, emptySelection })=>{
|
|
|
14741
15855
|
});
|
|
14742
15856
|
};
|
|
14743
15857
|
|
|
14744
|
-
const IconSize = {
|
|
14745
|
-
xs: 14,
|
|
14746
|
-
sm: 16,
|
|
14747
|
-
md: 20,
|
|
14748
|
-
lg: 24,
|
|
14749
|
-
xl: 32,
|
|
14750
|
-
'xl-2': 36
|
|
14751
|
-
};
|
|
14752
|
-
|
|
14753
|
-
const DataAccessRequestForm = ({ cohortId, submitFunction, close })=>{
|
|
14754
|
-
const [submitted, setSubmitted] = React.useState(false);
|
|
14755
|
-
const form$1 = form.useForm({
|
|
14756
|
-
initialValues: {
|
|
14757
|
-
name: '',
|
|
14758
|
-
institution: '',
|
|
14759
|
-
department: '',
|
|
14760
|
-
address: '',
|
|
14761
|
-
email: '',
|
|
14762
|
-
phone: ''
|
|
14763
|
-
},
|
|
14764
|
-
validate: {
|
|
14765
|
-
name: form.isNotEmpty('Name is required'),
|
|
14766
|
-
institution: form.isNotEmpty('Institution is required'),
|
|
14767
|
-
address: form.isNotEmpty('Address is required'),
|
|
14768
|
-
email: form.isEmail('Please provide a valid email'),
|
|
14769
|
-
phone: form.matches(/^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/, 'Please provide a valid phone number')
|
|
14770
|
-
}
|
|
14771
|
-
});
|
|
14772
|
-
const handleSubmit = async (values)=>{
|
|
14773
|
-
submitFunction(cohortId, values);
|
|
14774
|
-
setSubmitted(true);
|
|
14775
|
-
};
|
|
14776
|
-
if (submitted) {
|
|
14777
|
-
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Paper, {
|
|
14778
|
-
shadow: "md",
|
|
14779
|
-
p: "xl",
|
|
14780
|
-
radius: "md",
|
|
14781
|
-
children: [
|
|
14782
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Title, {
|
|
14783
|
-
order: 2,
|
|
14784
|
-
mb: "md",
|
|
14785
|
-
ta: "center",
|
|
14786
|
-
children: "Request Submitted"
|
|
14787
|
-
}),
|
|
14788
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
|
|
14789
|
-
ta: "center",
|
|
14790
|
-
children: "Thank you for your data access request. We will review your submission and contact you shortly."
|
|
14791
|
-
}),
|
|
14792
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Group, {
|
|
14793
|
-
justify: "center",
|
|
14794
|
-
mt: "xl",
|
|
14795
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
14796
|
-
onClick: ()=>close(),
|
|
14797
|
-
children: "Dismiss"
|
|
14798
|
-
})
|
|
14799
|
-
})
|
|
14800
|
-
]
|
|
14801
|
-
});
|
|
14802
|
-
}
|
|
14803
|
-
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Paper, {
|
|
14804
|
-
radius: "md",
|
|
14805
|
-
children: [
|
|
14806
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Text, {
|
|
14807
|
-
c: "dimmed",
|
|
14808
|
-
mb: "lg",
|
|
14809
|
-
children: "Please complete all fields to request access to our research data."
|
|
14810
|
-
}),
|
|
14811
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Divider, {
|
|
14812
|
-
mb: "lg"
|
|
14813
|
-
}),
|
|
14814
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Box, {
|
|
14815
|
-
component: "form",
|
|
14816
|
-
onSubmit: form$1.onSubmit(handleSubmit),
|
|
14817
|
-
children: /*#__PURE__*/ jsxRuntime.jsxs(core$1.Stack, {
|
|
14818
|
-
gap: "md",
|
|
14819
|
-
children: [
|
|
14820
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
14821
|
-
label: "Full Name",
|
|
14822
|
-
placeholder: "John Doe",
|
|
14823
|
-
withAsterisk: true,
|
|
14824
|
-
...form$1.getInputProps('name')
|
|
14825
|
-
}),
|
|
14826
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
14827
|
-
label: "Institution",
|
|
14828
|
-
placeholder: "University, Organization, or Company",
|
|
14829
|
-
withAsterisk: true,
|
|
14830
|
-
...form$1.getInputProps('institution')
|
|
14831
|
-
}),
|
|
14832
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
14833
|
-
label: "Department",
|
|
14834
|
-
placeholder: "Research Department",
|
|
14835
|
-
...form$1.getInputProps('department')
|
|
14836
|
-
}),
|
|
14837
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Textarea, {
|
|
14838
|
-
label: "Address",
|
|
14839
|
-
placeholder: "Full institutional address",
|
|
14840
|
-
withAsterisk: true,
|
|
14841
|
-
autosize: true,
|
|
14842
|
-
minRows: 2,
|
|
14843
|
-
maxRows: 4,
|
|
14844
|
-
...form$1.getInputProps('address')
|
|
14845
|
-
}),
|
|
14846
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
14847
|
-
label: "Email",
|
|
14848
|
-
placeholder: "your.email@institution.edu",
|
|
14849
|
-
withAsterisk: true,
|
|
14850
|
-
...form$1.getInputProps('email')
|
|
14851
|
-
}),
|
|
14852
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.TextInput, {
|
|
14853
|
-
label: "Phone",
|
|
14854
|
-
placeholder: "+1 (123) 456-7890",
|
|
14855
|
-
withAsterisk: true,
|
|
14856
|
-
...form$1.getInputProps('phone')
|
|
14857
|
-
}),
|
|
14858
|
-
/*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
14859
|
-
justify: "flex-end",
|
|
14860
|
-
children: [
|
|
14861
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
14862
|
-
type: "reset",
|
|
14863
|
-
variant: "outline",
|
|
14864
|
-
onClick: ()=>form$1.reset(),
|
|
14865
|
-
children: "Reset"
|
|
14866
|
-
}),
|
|
14867
|
-
/*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
14868
|
-
variant: "outline",
|
|
14869
|
-
onClick: ()=>close(),
|
|
14870
|
-
children: submitted ? 'Close' : 'Cancel'
|
|
14871
|
-
}),
|
|
14872
|
-
!submitted && /*#__PURE__*/ jsxRuntime.jsx(core$1.Button, {
|
|
14873
|
-
type: "submit",
|
|
14874
|
-
children: "Submit Request"
|
|
14875
|
-
})
|
|
14876
|
-
]
|
|
14877
|
-
})
|
|
14878
|
-
]
|
|
14879
|
-
})
|
|
14880
|
-
})
|
|
14881
|
-
]
|
|
14882
|
-
});
|
|
14883
|
-
};
|
|
14884
|
-
|
|
14885
15858
|
/**
|
|
14886
15859
|
* Formats a given date string into a specific format.
|
|
14887
15860
|
*
|
|
@@ -14990,8 +15963,11 @@ const commonTableSettings$1 = (size = 'sm')=>{
|
|
|
14990
15963
|
};
|
|
14991
15964
|
};
|
|
14992
15965
|
|
|
14993
|
-
const SavedCohortsTable = ({ size = 'md' })=>{
|
|
15966
|
+
const SavedCohortsTable = ({ indexResources, remoteSupportService, size = 'md' })=>{
|
|
14994
15967
|
const appDispatch = useAppDispatch();
|
|
15968
|
+
const [getGetAggs] = core.useLazyGetAggsNoFilterSelfQuery();
|
|
15969
|
+
const [requestQuery] = core.useCreateRequestMutation();
|
|
15970
|
+
const user = core.useCoreSelector(core.selectUserDetails);
|
|
14995
15971
|
const columns = React.useMemo(()=>[
|
|
14996
15972
|
{
|
|
14997
15973
|
accessorKey: 'name',
|
|
@@ -15004,7 +15980,7 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15004
15980
|
})
|
|
15005
15981
|
},
|
|
15006
15982
|
{
|
|
15007
|
-
accessorKey: '
|
|
15983
|
+
accessorKey: 'createdDatetime',
|
|
15008
15984
|
header: 'Modified Date',
|
|
15009
15985
|
Cell: ({ cell })=>/*#__PURE__*/ jsxRuntime.jsxs(core$1.Text, {
|
|
15010
15986
|
children: [
|
|
@@ -15014,7 +15990,7 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15014
15990
|
})
|
|
15015
15991
|
},
|
|
15016
15992
|
{
|
|
15017
|
-
accessorKey: '
|
|
15993
|
+
accessorKey: 'modifiedDatetime',
|
|
15018
15994
|
header: 'Created Date',
|
|
15019
15995
|
Cell: ({ cell })=>/*#__PURE__*/ jsxRuntime.jsxs(core$1.Text, {
|
|
15020
15996
|
children: [
|
|
@@ -15045,15 +16021,9 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15045
16021
|
data,
|
|
15046
16022
|
requestByCohortId
|
|
15047
16023
|
]);
|
|
15048
|
-
const
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
cohortId,
|
|
15052
|
-
userAccessInformation: values
|
|
15053
|
-
}));
|
|
15054
|
-
// Close the modal after successful dispatch
|
|
15055
|
-
close();
|
|
15056
|
-
}
|
|
16024
|
+
const handleCohortAccessRequest = async (cohortId, values)=>{
|
|
16025
|
+
const cohort = data.find((obj)=>obj.id === cohortId);
|
|
16026
|
+
if (cohort) await submitCohortRequestAction(cohort, values, user, indexResources, remoteSupportService, appDispatch, getGetAggs, requestQuery);
|
|
15057
16027
|
};
|
|
15058
16028
|
const table = mantineReactTable.useMantineReactTable({
|
|
15059
16029
|
columns,
|
|
@@ -15061,23 +16031,26 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15061
16031
|
getRowId: (originalRow)=>originalRow.id,
|
|
15062
16032
|
...commonTableSettings$1(),
|
|
15063
16033
|
positionActionsColumn: 'last',
|
|
15064
|
-
renderRowActions: ({ row })
|
|
16034
|
+
renderRowActions: ({ row })=>{
|
|
16035
|
+
const hasNoFilters = isIndexedFilterSetEmpty(row.original.filters);
|
|
16036
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(core$1.Group, {
|
|
15065
16037
|
wrap: "nowrap",
|
|
15066
16038
|
gap: "xs",
|
|
15067
16039
|
children: [
|
|
15068
16040
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tooltip, {
|
|
15069
|
-
label:
|
|
16041
|
+
label: hasNoFilters ? 'No Filters defined. Cannot submit request.' : 'Submit Data Access Request',
|
|
15070
16042
|
withArrow: true,
|
|
15071
16043
|
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.ActionIcon, {
|
|
15072
16044
|
color: "accent.4",
|
|
15073
16045
|
variant: "transparent",
|
|
16046
|
+
disabled: hasNoFilters,
|
|
15074
16047
|
"aria-label": "Submit Data Access Request",
|
|
15075
16048
|
onClick: ()=>{
|
|
15076
16049
|
const modelId = modals.modals.open({
|
|
15077
16050
|
title: 'DATA ACCESS REQUEST',
|
|
15078
16051
|
children: /*#__PURE__*/ jsxRuntime.jsx(DataAccessRequestForm, {
|
|
15079
16052
|
cohortId: row.id,
|
|
15080
|
-
submitFunction:
|
|
16053
|
+
submitFunction: handleCohortAccessRequest,
|
|
15081
16054
|
close: ()=>modals.modals.close(modelId)
|
|
15082
16055
|
})
|
|
15083
16056
|
});
|
|
@@ -15117,16 +16090,21 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15117
16090
|
modals.modals.openConfirmModal({
|
|
15118
16091
|
title: 'Delete Cohort',
|
|
15119
16092
|
centered: true,
|
|
15120
|
-
children: /*#__PURE__*/ jsxRuntime.
|
|
16093
|
+
children: /*#__PURE__*/ jsxRuntime.jsxs(core$1.Text, {
|
|
15121
16094
|
size: "sm",
|
|
15122
|
-
children:
|
|
16095
|
+
children: [
|
|
16096
|
+
"Are you sure you want to delete your cohort? Deleted cohorts cannot be restored.",
|
|
16097
|
+
' ',
|
|
16098
|
+
row.original?.requested ? `This cohort has an access request. Deleting this cohort will results in not being able to correlate nay pending requests.
|
|
16099
|
+
Are you sure you want to delete this cohort?.` : ''
|
|
16100
|
+
]
|
|
15123
16101
|
}),
|
|
15124
16102
|
labels: {
|
|
15125
16103
|
confirm: 'Delete Cohort',
|
|
15126
16104
|
cancel: 'Cancel'
|
|
15127
16105
|
},
|
|
15128
16106
|
confirmProps: {
|
|
15129
|
-
color: theme.colors.
|
|
16107
|
+
color: theme.colors.accent[4]
|
|
15130
16108
|
},
|
|
15131
16109
|
onConfirm: ()=>{
|
|
15132
16110
|
appDispatch(removeCohort(row.id));
|
|
@@ -15142,7 +16120,8 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15142
16120
|
})
|
|
15143
16121
|
})
|
|
15144
16122
|
]
|
|
15145
|
-
})
|
|
16123
|
+
});
|
|
16124
|
+
}
|
|
15146
16125
|
});
|
|
15147
16126
|
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
15148
16127
|
children: /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
@@ -15154,20 +16133,95 @@ const SavedCohortsTable = ({ size = 'md' })=>{
|
|
|
15154
16133
|
});
|
|
15155
16134
|
};
|
|
15156
16135
|
|
|
15157
|
-
const SavedCohortsPanel = ()=>{
|
|
16136
|
+
const SavedCohortsPanel = ({ indexResources, remoteSupportService })=>{
|
|
15158
16137
|
return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
15159
16138
|
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Stack, {
|
|
15160
16139
|
className: "w-100 m-2",
|
|
15161
16140
|
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Group, {
|
|
15162
16141
|
className: "w-100 bg-base-light p-4",
|
|
15163
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(SavedCohortsTable, {
|
|
16142
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(SavedCohortsTable, {
|
|
16143
|
+
indexResources: indexResources,
|
|
16144
|
+
remoteSupportService: remoteSupportService
|
|
16145
|
+
})
|
|
15164
16146
|
})
|
|
15165
16147
|
})
|
|
15166
16148
|
});
|
|
15167
16149
|
};
|
|
15168
16150
|
|
|
16151
|
+
const useGetCohortRequests = (resources = [])=>{
|
|
16152
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
16153
|
+
const [cohortRequests, setCohortRequests] = React.useState([]);
|
|
16154
|
+
const localRequests = useAppSelector(selectAllDataAccessRequests);
|
|
16155
|
+
const { data: submittedRequests, isFetching, isError, error } = core.useUserRequestQuery({
|
|
16156
|
+
resource_ids: resources
|
|
16157
|
+
});
|
|
16158
|
+
const cohortIdToNameMap = useAppSelector(selectCohortIdToNameMap);
|
|
16159
|
+
React.useEffect(()=>{
|
|
16160
|
+
// Return early if we're still fetching data
|
|
16161
|
+
if (isFetching) {
|
|
16162
|
+
setIsLoading(true);
|
|
16163
|
+
return;
|
|
16164
|
+
}
|
|
16165
|
+
// Once data is available, merge local and remote requests
|
|
16166
|
+
if (submittedRequests) {
|
|
16167
|
+
// Create a map of local requests by ID
|
|
16168
|
+
const localRequestsMap = localRequests.reduce((acc, localRequest)=>{
|
|
16169
|
+
acc[localRequest.id] = localRequest;
|
|
16170
|
+
return acc;
|
|
16171
|
+
}, {});
|
|
16172
|
+
// Add cohort names to the requests
|
|
16173
|
+
const requestsWithCohorts = submittedRequests.reduce((acc, request)=>{
|
|
16174
|
+
if (request.request_id && Object.hasOwn(localRequestsMap, request.request_id)) {
|
|
16175
|
+
const localRequest = localRequestsMap[request.request_id];
|
|
16176
|
+
acc.push({
|
|
16177
|
+
...localRequest,
|
|
16178
|
+
cohortName: cohortIdToNameMap[localRequest.cohortId] ?? 'Not Found',
|
|
16179
|
+
status: request?.status ?? 'unknown',
|
|
16180
|
+
updatedDatetime: request.created_time ?? localRequest.updatedDatetime,
|
|
16181
|
+
createdDatetime: request.updated_time ?? localRequest.createdDatetime
|
|
16182
|
+
});
|
|
16183
|
+
} else {
|
|
16184
|
+
acc.push({
|
|
16185
|
+
...request,
|
|
16186
|
+
cohortId: 'Not Set',
|
|
16187
|
+
email: request.username ?? 'Not Set',
|
|
16188
|
+
name: 'Not Set',
|
|
16189
|
+
organization: 'Not Set',
|
|
16190
|
+
id: request.request_id ?? 'Not Set',
|
|
16191
|
+
cohortName: 'Not Found',
|
|
16192
|
+
status: request?.status ?? 'unknown',
|
|
16193
|
+
updatedDatetime: request.created_time ?? 'Not Set',
|
|
16194
|
+
createdDatetime: request.updated_time ?? ' Not Set'
|
|
16195
|
+
});
|
|
16196
|
+
}
|
|
16197
|
+
return acc;
|
|
16198
|
+
}, []);
|
|
16199
|
+
setCohortRequests(requestsWithCohorts);
|
|
16200
|
+
} else if (isError) {
|
|
16201
|
+
// If there's an error fetching remote data, use local requests
|
|
16202
|
+
const localRequestsWithCohorts = localRequests.map((request)=>({
|
|
16203
|
+
...request,
|
|
16204
|
+
cohortName: request.id ? cohortIdToNameMap[request.id] : 'Unknown'
|
|
16205
|
+
}));
|
|
16206
|
+
setCohortRequests(localRequestsWithCohorts);
|
|
16207
|
+
}
|
|
16208
|
+
setIsLoading(false);
|
|
16209
|
+
}, [
|
|
16210
|
+
submittedRequests,
|
|
16211
|
+
localRequests,
|
|
16212
|
+
isFetching,
|
|
16213
|
+
isError,
|
|
16214
|
+
cohortIdToNameMap
|
|
16215
|
+
]);
|
|
16216
|
+
return {
|
|
16217
|
+
cohortRequests,
|
|
16218
|
+
isLoading: isLoading || isFetching,
|
|
16219
|
+
isError,
|
|
16220
|
+
error
|
|
16221
|
+
};
|
|
16222
|
+
};
|
|
15169
16223
|
const RequestsTable = ()=>{
|
|
15170
|
-
const
|
|
16224
|
+
const { cohortRequests, isLoading, isError } = useGetCohortRequests(undefined);
|
|
15171
16225
|
const columns = React.useMemo(()=>[
|
|
15172
16226
|
{
|
|
15173
16227
|
accessorKey: 'cohortName',
|
|
@@ -15180,7 +16234,7 @@ const RequestsTable = ()=>{
|
|
|
15180
16234
|
})
|
|
15181
16235
|
},
|
|
15182
16236
|
{
|
|
15183
|
-
accessorKey: '
|
|
16237
|
+
accessorKey: 'createdDatetime',
|
|
15184
16238
|
header: 'Request Date',
|
|
15185
16239
|
Cell: ({ cell })=>/*#__PURE__*/ jsxRuntime.jsxs(core$1.Text, {
|
|
15186
16240
|
children: [
|
|
@@ -15189,6 +16243,16 @@ const RequestsTable = ()=>{
|
|
|
15189
16243
|
]
|
|
15190
16244
|
})
|
|
15191
16245
|
},
|
|
16246
|
+
{
|
|
16247
|
+
accessorKey: 'updatedDatetime',
|
|
16248
|
+
header: 'Last Update',
|
|
16249
|
+
Cell: ({ cell })=>/*#__PURE__*/ jsxRuntime.jsxs(core$1.Text, {
|
|
16250
|
+
children: [
|
|
16251
|
+
formatDate(cell.getValue()),
|
|
16252
|
+
" "
|
|
16253
|
+
]
|
|
16254
|
+
})
|
|
16255
|
+
},
|
|
15192
16256
|
{
|
|
15193
16257
|
accessorKey: 'status',
|
|
15194
16258
|
header: 'Status',
|
|
@@ -15205,21 +16269,26 @@ const RequestsTable = ()=>{
|
|
|
15205
16269
|
}
|
|
15206
16270
|
}
|
|
15207
16271
|
], []);
|
|
15208
|
-
const
|
|
15209
|
-
const requestsWithCohorts = useDeepCompare.useDeepCompareMemo(()=>requests.map((request)=>{
|
|
15210
|
-
return {
|
|
15211
|
-
...request,
|
|
15212
|
-
cohortName: cohortIdToNameMap[request.cohortId] || 'Unknown'
|
|
15213
|
-
};
|
|
15214
|
-
}), [
|
|
15215
|
-
requests,
|
|
15216
|
-
cohortIdToNameMap
|
|
15217
|
-
]);
|
|
16272
|
+
const size = 'sm';
|
|
15218
16273
|
const table = mantineReactTable.useMantineReactTable({
|
|
15219
16274
|
columns,
|
|
15220
|
-
data:
|
|
15221
|
-
|
|
16275
|
+
data: cohortRequests ?? [],
|
|
16276
|
+
renderEmptyRowsFallback: ()=>/*#__PURE__*/ jsxRuntime.jsx(EmptyTableMessage, {
|
|
16277
|
+
message: 'No requests submitted.'
|
|
16278
|
+
}),
|
|
16279
|
+
...commonTableSettings$1(size),
|
|
16280
|
+
state: {
|
|
16281
|
+
isLoading: isLoading
|
|
16282
|
+
}
|
|
15222
16283
|
});
|
|
16284
|
+
if (isError) {
|
|
16285
|
+
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
16286
|
+
className: "w-full mt-24 flex flex-col items-center justify-center",
|
|
16287
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(ErrorCard, {
|
|
16288
|
+
message: `Error retrieving user request`
|
|
16289
|
+
})
|
|
16290
|
+
});
|
|
16291
|
+
}
|
|
15223
16292
|
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
15224
16293
|
className: "inline-block overflow-x-scroll w-full",
|
|
15225
16294
|
children: /*#__PURE__*/ jsxRuntime.jsx(mantineReactTable.MantineReactTable, {
|
|
@@ -15229,16 +16298,18 @@ const RequestsTable = ()=>{
|
|
|
15229
16298
|
};
|
|
15230
16299
|
|
|
15231
16300
|
const RequestsPanel = ()=>{
|
|
15232
|
-
return /*#__PURE__*/ jsxRuntime.jsx(
|
|
15233
|
-
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
|
|
16301
|
+
return /*#__PURE__*/ jsxRuntime.jsx(ProtectedContent, {
|
|
16302
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Stack, {
|
|
16303
|
+
className: "w-100 m-2",
|
|
16304
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(core$1.Group, {
|
|
16305
|
+
className: "w-100 bg-base-light p-4",
|
|
16306
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(RequestsTable, {})
|
|
16307
|
+
})
|
|
15237
16308
|
})
|
|
15238
16309
|
});
|
|
15239
16310
|
};
|
|
15240
16311
|
|
|
15241
|
-
const TabbedIndex = ({ config, tabsLayout = 'left' })=>{
|
|
16312
|
+
const TabbedIndex = ({ config, indexResources, tabsLayout = 'left' })=>{
|
|
15242
16313
|
return /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
15243
16314
|
className: "w-full",
|
|
15244
16315
|
children: /*#__PURE__*/ jsxRuntime.jsxs(core$1.Tabs, {
|
|
@@ -15261,9 +16332,12 @@ const TabbedIndex = ({ config, tabsLayout = 'left' })=>{
|
|
|
15261
16332
|
children: /*#__PURE__*/ jsxRuntime.jsx(IndexPanel, {
|
|
15262
16333
|
dataConfig: panelConfig.dataConfig,
|
|
15263
16334
|
tabTitle: panelConfig.tabTitle,
|
|
16335
|
+
resourceField: panelConfig.resourceField,
|
|
15264
16336
|
tabs: panelConfig.tabs,
|
|
15265
16337
|
emptySelection: config.emptySelection,
|
|
15266
|
-
numColumns: panelConfig.numColumns ?? 2
|
|
16338
|
+
numColumns: panelConfig.numColumns ?? 2,
|
|
16339
|
+
indexResources: indexResources,
|
|
16340
|
+
remoteSupportService: config.remoteSupportService
|
|
15267
16341
|
})
|
|
15268
16342
|
}, `${panelConfig.tabTitle}-tabPanel`))
|
|
15269
16343
|
]
|
|
@@ -15271,8 +16345,20 @@ const TabbedIndex = ({ config, tabsLayout = 'left' })=>{
|
|
|
15271
16345
|
});
|
|
15272
16346
|
};
|
|
15273
16347
|
|
|
16348
|
+
const extractIndexResourceFromConfiguration = (config)=>{
|
|
16349
|
+
return config.dataIndexes.reduce((acc, panelConfig)=>{
|
|
16350
|
+
acc[panelConfig.dataConfig.dataType] = {
|
|
16351
|
+
resourceField: panelConfig.resourceField,
|
|
16352
|
+
resourcePath: panelConfig.resourcePath
|
|
16353
|
+
};
|
|
16354
|
+
return acc;
|
|
16355
|
+
}, {});
|
|
16356
|
+
};
|
|
16357
|
+
|
|
15274
16358
|
const persistor = reduxPersist.persistStore(AppStore);
|
|
15275
16359
|
const CohortDiscovery = (config)=>{
|
|
16360
|
+
const indexResources = extractIndexResourceFromConfiguration(config);
|
|
16361
|
+
useAppDispatch(loadCohortsFromStorage());
|
|
15276
16362
|
return /*#__PURE__*/ jsxRuntime.jsx(React.Fragment, {
|
|
15277
16363
|
children: /*#__PURE__*/ jsxRuntime.jsxs(react$1.PersistGate, {
|
|
15278
16364
|
persistor: persistor,
|
|
@@ -15286,7 +16372,7 @@ const CohortDiscovery = (config)=>{
|
|
|
15286
16372
|
children: "Cohort Discovery"
|
|
15287
16373
|
}),
|
|
15288
16374
|
/*#__PURE__*/ jsxRuntime.jsxs(core$1.Tabs, {
|
|
15289
|
-
keepMounted:
|
|
16375
|
+
keepMounted: false,
|
|
15290
16376
|
defaultValue: "build",
|
|
15291
16377
|
orientation: "vertical",
|
|
15292
16378
|
classNames: {
|
|
@@ -15324,14 +16410,21 @@ const CohortDiscovery = (config)=>{
|
|
|
15324
16410
|
tabTitle: config.dataIndexes[0].tabTitle,
|
|
15325
16411
|
tabs: config.dataIndexes[0].tabs,
|
|
15326
16412
|
emptySelection: config.emptySelection,
|
|
15327
|
-
|
|
16413
|
+
resourceField: config.dataIndexes[0].resourceField,
|
|
16414
|
+
numColumns: config.dataIndexes[0].numColumns ?? 2,
|
|
16415
|
+
indexResources: indexResources,
|
|
16416
|
+
remoteSupportService: config.remoteSupportService
|
|
15328
16417
|
}) : /*#__PURE__*/ jsxRuntime.jsx(TabbedIndex, {
|
|
15329
|
-
config: config
|
|
16418
|
+
config: config,
|
|
16419
|
+
indexResources: indexResources
|
|
15330
16420
|
})
|
|
15331
16421
|
}),
|
|
15332
16422
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tabs.Panel, {
|
|
15333
16423
|
value: "saved",
|
|
15334
|
-
children: /*#__PURE__*/ jsxRuntime.jsx(SavedCohortsPanel, {
|
|
16424
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(SavedCohortsPanel, {
|
|
16425
|
+
indexResources: indexResources,
|
|
16426
|
+
remoteSupportService: config.remoteSupportService
|
|
16427
|
+
})
|
|
15335
16428
|
}),
|
|
15336
16429
|
/*#__PURE__*/ jsxRuntime.jsx(core$1.Tabs.Panel, {
|
|
15337
16430
|
value: "request",
|
|
@@ -17808,7 +18901,8 @@ const DiscoveryPage = ({ headerProps, footerProps, discoveryConfig })=>{
|
|
|
17808
18901
|
headerData: {
|
|
17809
18902
|
title: 'Gen3 Discovery Page',
|
|
17810
18903
|
content: 'Discovery Data',
|
|
17811
|
-
key: 'gen3-discovery-page'
|
|
18904
|
+
key: 'gen3-discovery-page',
|
|
18905
|
+
...discoveryConfig?.headerMetadata ? discoveryConfig.headerMetadata : {}
|
|
17812
18906
|
},
|
|
17813
18907
|
children: /*#__PURE__*/ jsxRuntime.jsx(Discovery, {
|
|
17814
18908
|
discoveryConfig: discoveryConfig
|
|
@@ -17863,7 +18957,8 @@ const QueryPage = ({ headerProps, footerProps, queryProps })=>{
|
|
|
17863
18957
|
headerData: {
|
|
17864
18958
|
title: 'Gen3 Query Page',
|
|
17865
18959
|
content: 'Query page',
|
|
17866
|
-
key: 'gen3-query-page'
|
|
18960
|
+
key: 'gen3-query-page',
|
|
18961
|
+
...queryProps?.headerMetadata ? queryProps.headerMetadata : {}
|
|
17867
18962
|
},
|
|
17868
18963
|
children: /*#__PURE__*/ jsxRuntime.jsx(QueryPanel, {
|
|
17869
18964
|
graphQLEndpoint: queryProps.graphQLEndpoint
|
|
@@ -18035,7 +19130,8 @@ const LandingPage = ({ headerProps, footerProps, landingPage })=>{
|
|
|
18035
19130
|
headerData: {
|
|
18036
19131
|
title: 'Gen3 Home Page',
|
|
18037
19132
|
content: 'Home page',
|
|
18038
|
-
key: 'gen3-home-page'
|
|
19133
|
+
key: 'gen3-home-page',
|
|
19134
|
+
...landingPage?.headerMetadata ? landingPage.headerMetadata : {}
|
|
18039
19135
|
},
|
|
18040
19136
|
children: /*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
18041
19137
|
className: "flex justify-items-center w-full",
|
|
@@ -18058,7 +19154,7 @@ const LandingPageGetServerSideProps = async ()=>{
|
|
|
18058
19154
|
};
|
|
18059
19155
|
};
|
|
18060
19156
|
|
|
18061
|
-
const ExplorerPage = ({ headerProps, footerProps, explorerConfig, tabsLayout, sharedFiltersMap })=>{
|
|
19157
|
+
const ExplorerPage = ({ headerProps, footerProps, explorerConfig, headerMetadata, tabsLayout, sharedFiltersMap })=>{
|
|
18062
19158
|
if (explorerConfig === undefined) {
|
|
18063
19159
|
return /*#__PURE__*/ jsxRuntime.jsx(core$1.Center, {
|
|
18064
19160
|
maw: 400,
|
|
@@ -18075,7 +19171,8 @@ const ExplorerPage = ({ headerProps, footerProps, explorerConfig, tabsLayout, sh
|
|
|
18075
19171
|
headerData: {
|
|
18076
19172
|
title: 'Gen3 Explorer Page',
|
|
18077
19173
|
content: 'Explorer Page',
|
|
18078
|
-
key: 'gen3-explorer-page'
|
|
19174
|
+
key: 'gen3-explorer-page',
|
|
19175
|
+
...headerMetadata ? headerMetadata : {}
|
|
18079
19176
|
},
|
|
18080
19177
|
children: /*#__PURE__*/ jsxRuntime.jsx(CohortBuilder, {
|
|
18081
19178
|
tabsLayout: tabsLayout,
|
|
@@ -18148,7 +19245,10 @@ const ExplorerPageGetServerSideProps = async ()=>{
|
|
|
18148
19245
|
return {
|
|
18149
19246
|
props: {
|
|
18150
19247
|
...await getNavPageLayoutPropsFromConfig(),
|
|
18151
|
-
explorerConfig: cohortBuilderConfiguration
|
|
19248
|
+
explorerConfig: cohortBuilderConfiguration,
|
|
19249
|
+
headerMetadata: {
|
|
19250
|
+
...cohortBuilderConfiguration?.headerMetadata
|
|
19251
|
+
}
|
|
18152
19252
|
}
|
|
18153
19253
|
};
|
|
18154
19254
|
}
|
|
@@ -18159,6 +19259,7 @@ const ExplorerPageGetServerSideProps = async ()=>{
|
|
|
18159
19259
|
sharedFiltersMap: sharedFiltersMap,
|
|
18160
19260
|
tabsLayout: cohortBuilderConfiguration?.tabsLayout ?? 'left',
|
|
18161
19261
|
explorerConfig: cohortBuilderConfiguration.explorerConfig,
|
|
19262
|
+
headerMetadata: cohortBuilderConfiguration.headerMetadata,
|
|
18162
19263
|
accessControl: {
|
|
18163
19264
|
...DefaultAccessControlConfiguration,
|
|
18164
19265
|
...cohortBuilderConfiguration.accessControl ?? {}
|
|
@@ -18187,7 +19288,10 @@ const ExplorerPageGetServerSidePropsForConfigId = async (context)=>{
|
|
|
18187
19288
|
return {
|
|
18188
19289
|
props: {
|
|
18189
19290
|
...await getNavPageLayoutPropsFromConfig(),
|
|
18190
|
-
explorerConfig: cohortBuilderConfiguration
|
|
19291
|
+
explorerConfig: cohortBuilderConfiguration,
|
|
19292
|
+
headerMetadata: {
|
|
19293
|
+
...cohortBuilderConfiguration?.headerMetadata
|
|
19294
|
+
}
|
|
18191
19295
|
}
|
|
18192
19296
|
};
|
|
18193
19297
|
}
|
|
@@ -18198,6 +19302,7 @@ const ExplorerPageGetServerSidePropsForConfigId = async (context)=>{
|
|
|
18198
19302
|
sharedFiltersMap: sharedFiltersMap,
|
|
18199
19303
|
tabsLayout: cohortBuilderConfiguration?.tabsLayout ?? 'left',
|
|
18200
19304
|
explorerConfig: cohortBuilderConfiguration.explorerConfig,
|
|
19305
|
+
headerMetadata: cohortBuilderConfiguration.headerMetadata,
|
|
18201
19306
|
accessControl: {
|
|
18202
19307
|
...DefaultAccessControlConfiguration,
|
|
18203
19308
|
...cohortBuilderConfiguration.accessControl ?? {}
|
|
@@ -19138,7 +20243,8 @@ const ProfilePage = ({ headerProps, footerProps, profileConfig })=>{
|
|
|
19138
20243
|
headerData: {
|
|
19139
20244
|
title: 'Gen3 Profile Page',
|
|
19140
20245
|
content: 'Profile page',
|
|
19141
|
-
key: 'gen3-profile-page'
|
|
20246
|
+
key: 'gen3-profile-page',
|
|
20247
|
+
...profileConfig?.headerMetadata ? profileConfig.headerMetadata : {}
|
|
19142
20248
|
},
|
|
19143
20249
|
children: /*#__PURE__*/ jsxRuntime.jsx(Profile, {
|
|
19144
20250
|
profileConfig: profileConfig
|
|
@@ -19165,7 +20271,8 @@ const LoginPage = ({ headerProps, footerProps, loginConfig })=>{
|
|
|
19165
20271
|
headerData: {
|
|
19166
20272
|
title: 'Gen3 Login Page',
|
|
19167
20273
|
content: 'Login page',
|
|
19168
|
-
key: 'gen3-login-page'
|
|
20274
|
+
key: 'gen3-login-page',
|
|
20275
|
+
...loginConfig?.headerMetadata ? loginConfig.headerMetadata : {}
|
|
19169
20276
|
},
|
|
19170
20277
|
children: /*#__PURE__*/ jsxRuntime.jsx(LoginPanel, {
|
|
19171
20278
|
...loginConfig
|
|
@@ -19195,7 +20302,8 @@ const DictionaryPage = ({ headerProps, footerProps, config })=>{
|
|
|
19195
20302
|
headerData: {
|
|
19196
20303
|
title: 'Gen3 DataDictionary Page',
|
|
19197
20304
|
content: 'Data Dictionary',
|
|
19198
|
-
key: 'gen3-data-dictionary-page'
|
|
20305
|
+
key: 'gen3-data-dictionary-page',
|
|
20306
|
+
...config?.headerMetadata ? config.headerMetadata : {}
|
|
19199
20307
|
},
|
|
19200
20308
|
children: /*#__PURE__*/ jsxRuntime.jsx(DictionaryWithContext, {
|
|
19201
20309
|
config: config
|
|
@@ -20281,7 +21389,8 @@ const WorkspacePage = ({ headerProps, footerProps, workspaceProps })=>{
|
|
|
20281
21389
|
headerData: {
|
|
20282
21390
|
title: 'Gen3 Workspace Page',
|
|
20283
21391
|
content: 'Workspace page',
|
|
20284
|
-
key: 'gen3-workspace-page'
|
|
21392
|
+
key: 'gen3-workspace-page',
|
|
21393
|
+
...workspaceProps?.headerMetadata ? workspaceProps.headerMetadata : {}
|
|
20285
21394
|
},
|
|
20286
21395
|
children: /*#__PURE__*/ jsxRuntime.jsx(Workspace, {
|
|
20287
21396
|
config: workspaceProps
|
|
@@ -23446,7 +24555,8 @@ const CrosswalkPage = ({ headerProps, footerProps, config })=>{
|
|
|
23446
24555
|
headerData: {
|
|
23447
24556
|
title: 'Gen3 Crosswalk Page',
|
|
23448
24557
|
content: 'Crosswalk Data',
|
|
23449
|
-
key: 'gen3-crosswalk-page'
|
|
24558
|
+
key: 'gen3-crosswalk-page',
|
|
24559
|
+
...config?.headerMetadata ? config.headerMetadata : {}
|
|
23450
24560
|
},
|
|
23451
24561
|
children: /*#__PURE__*/ jsxRuntime.jsx(CrosswalkPanel, {
|
|
23452
24562
|
...config
|
|
@@ -23936,6 +25046,7 @@ exports.analysisApiCohortDiscovery = analysisApiCohortDiscovery;
|
|
|
23936
25046
|
exports.capitalize = capitalize;
|
|
23937
25047
|
exports.computeRowSpan = computeRowSpan;
|
|
23938
25048
|
exports.convertMinutesToMilliseconds = convertMinutesToMilliseconds;
|
|
25049
|
+
exports.convertPathsToTree = convertPathsToTree;
|
|
23939
25050
|
exports.convertSecondsToMilliseconds = convertSecondsToMilliseconds;
|
|
23940
25051
|
exports.create10ColorAccessibleContrast = create10ColorAccessibleContrast;
|
|
23941
25052
|
exports.create10ColorPallet = create10ColorPallet;
|