@gen-epix/ui-client-casedb 4.0.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/_chunks/AddCasesToEventDialog.js +98 -98
  2. package/dist/_chunks/AddCasesToEventDialog.js.map +1 -1
  3. package/dist/_chunks/CaseContentForm.js +10 -10
  4. package/dist/_chunks/CaseDbDownloadUtil.js +1 -1
  5. package/dist/_chunks/CaseDbDownloadUtil.js.map +1 -1
  6. package/dist/_chunks/CaseInfoDialog.js +222 -222
  7. package/dist/_chunks/CaseInfoDialog.js.map +1 -1
  8. package/dist/_chunks/CaseSetInfoDialog.js +222 -222
  9. package/dist/_chunks/CaseSetInfoDialog.js.map +1 -1
  10. package/dist/_chunks/CasesAlreadyInCaseSetWarning.js.map +1 -1
  11. package/dist/_chunks/Dashboard.js +296 -295
  12. package/dist/_chunks/Dashboard.js.map +1 -1
  13. package/dist/_chunks/FindSimilarCasesDialog.js +81 -81
  14. package/dist/_chunks/FindSimilarCasesDialog.js.map +1 -1
  15. package/dist/_chunks/HomePageTrends.js.map +1 -1
  16. package/dist/_chunks/LegendaItem.js.map +1 -1
  17. package/dist/_chunks/LineListWidget.js +46 -45
  18. package/dist/_chunks/LineListWidget.js.map +1 -1
  19. package/dist/_chunks/PanelSeparator.js +3 -3
  20. package/dist/_chunks/PanelSeparator.js.map +1 -1
  21. package/dist/_chunks/Upload.js +422 -418
  22. package/dist/_chunks/Upload.js.map +1 -1
  23. package/dist/_chunks/UploadUtil.js +44 -40
  24. package/dist/_chunks/UploadUtil.js.map +1 -1
  25. package/dist/_chunks/chunk-BV7QT456.js +1 -1
  26. package/dist/_chunks/chunk-BV7QT456.js.map +1 -1
  27. package/dist/_chunks/cloneDeep.js +1 -1
  28. package/dist/_chunks/cloneDeep.js.map +1 -1
  29. package/dist/_chunks/dashboardStore.js.map +1 -1
  30. package/dist/_chunks/esm.js +3 -3
  31. package/dist/_chunks/esm.js.map +1 -1
  32. package/dist/_chunks/index.module.js +1 -1
  33. package/dist/_chunks/index.module.js.map +1 -1
  34. package/dist/_chunks/react.js +1 -1
  35. package/dist/_chunks/react.js.map +1 -1
  36. package/dist/_chunks/shallow.js +2 -2
  37. package/dist/_chunks/shallow.js.map +1 -1
  38. package/dist/_chunks/vanilla.js +1 -1
  39. package/dist/_chunks/vanilla.js.map +1 -1
  40. package/dist/_chunks/yup.js +24 -24
  41. package/dist/_chunks/yup.js.map +1 -1
  42. package/dist/classes/services/EventBusService/EventBusService.d.ts +9 -2
  43. package/dist/classes/services/EventBusService/index.js.map +1 -1
  44. package/dist/components/form/fields/ArrangementEditor/index.js +30 -30
  45. package/dist/components/ui/CreateEventDialog/index.js +40 -40
  46. package/dist/components/ui/CreateEventDialog/index.js.map +1 -1
  47. package/dist/components/ui/MapWidget/index.js.map +1 -1
  48. package/dist/components/ui/RemoveCasesFromEventDialog/index.js.map +1 -1
  49. package/dist/components/ui/SequenceDownloadDialog/index.js +57 -44
  50. package/dist/components/ui/SequenceDownloadDialog/index.js.map +1 -1
  51. package/dist/components/ui/TreeWidget/index.js +8 -2
  52. package/dist/components/ui/TreeWidget/index.js.map +1 -1
  53. package/dist/locale/en.json +0 -11
  54. package/dist/locale/nl.json +0 -11
  55. package/dist/models/config.d.ts +2 -0
  56. package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js +59 -59
  57. package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js.map +1 -1
  58. package/dist/utils/UploadUtil/UploadUtil.d.ts +1 -0
  59. package/package.json +68 -75
  60. package/dist/_chunks/index.esm.js +0 -1465
  61. package/dist/_chunks/index.esm.js.map +0 -1
  62. package/dist/components/ui/FileSelector/FileSelector.d.ts +0 -7
  63. package/dist/components/ui/FileSelector/index.d.ts +0 -1
  64. package/dist/components/ui/FileSelector/index.js +0 -206
  65. package/dist/components/ui/FileSelector/index.js.map +0 -1
  66. package/dist/utils/FileUtil/FileUtil.d.ts +0 -5
  67. package/dist/utils/FileUtil/index.d.ts +0 -1
  68. package/dist/utils/FileUtil/index.js +0 -15
  69. package/dist/utils/FileUtil/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ui/TreeWidget/TreeWidget.tsx"],"sourcesContent":["import {\n Box,\n Button,\n ListItemIcon,\n ListItemText,\n MenuItem,\n useTheme,\n} from '@mui/material';\nimport ClearIcon from '@mui/icons-material/Clear';\nimport ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';\nimport FilterAltIcon from '@mui/icons-material/FilterAlt';\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';\nimport LinkIcon from '@mui/icons-material/Link';\nimport type { ReactElement } from 'react';\nimport {\n use,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useStore } from 'zustand';\nimport { useDebouncedCallback } from 'use-debounce';\nimport type { CaseDbRetrievePhylogeneticTreeRequestBody } from '@gen-epix/api-casedb';\nimport { CaseDbCaseApi } from '@gen-epix/api-casedb';\nimport type { MenuItemData } from '@gen-epix/ui-core-components/models/nestedMenu';\nimport { ConfigService } from '@gen-epix/ui-client-common/classes/services/ConfigService';\nimport { Spinner } from '@gen-epix/ui-core-components/components/Spinner';\nimport { useQueryMemo } from '@gen-epix/ui-client-common/hooks/useQueryMemo';\nimport { Subject } from '@gen-epix/ui-core/classes/Subject';\nimport { PhylogeneticTree } from '@gen-epix/ui-phylogenetic-tree/components/PhylogeneticTree';\nimport type {\n PhylogeneticTreeHighlightedNodeNamesSubjectValue,\n PhylogeneticTreePathClickEvent,\n PhylogeneticTreeRef,\n PhylogeneticTreeViewState,\n} from '@gen-epix/ui-phylogenetic-tree/components/PhylogeneticTree';\n\nimport { EventBusService } from '../../../classes/services/EventBusService';\nimport type {\n DashboardTreeSettings,\n TreeConfiguration,\n TreeWidgetData,\n TreeWidgetDataPersistable,\n} from '../../../models/dashboard';\nimport type { Highlighting } from '../../../models/caseDb';\nimport { DashboardStoreContext } from '../../../stores/dashboardStore';\nimport { SELECTION_FILTER_GROUP } from '../../../utils/CaseTypeUtil';\nimport { CaseDbDownloadUtil } from '../../../utils/CaseDbDownloadUtil';\nimport { TreeWidgetUtil } from '../../../utils/TreeWidgetUtil';\nimport type { ContextMenuConfigWithPosition } from '../ContextMenu';\nimport { ContextMenu } from '../ContextMenu';\nimport { TreeDescription } from '../TreeDescription';\nimport { WidgetUnavailable } from '../WidgetUnavailable';\nimport { CASEDB_QUERY_KEY } from '../../../constants/query';\nimport type { CaseDbConfig } from '../../../models/config';\nimport { TreeFilter } from '../../../classes/filters/TreeFilter';\nimport { DashboardWidget } from '../Dashboard';\nimport { DASHBOARD_COMPONENT_NAME } from '../../../constants/dashboard';\nimport { DashboardContext } from '../Dashboard/context/DashboardContext';\nimport { UserProfileStoreContext } from '../../../stores/userProfileStore/userProfileStoreContext';\n\ntype ZoomInMenuItemConfig = {\n caseIds?: string[];\n rootId?: string;\n};\n\nexport const TreeWidget = () => {\n const theme = useTheme();\n const { t } = useTranslation();\n const treeConfig = ConfigService.getInstance<CaseDbConfig>().config.tree;\n const [treeCanvas, setTreeCanvas] = useState<HTMLCanvasElement>();\n const [isTreeLinked, setIsTreeLinked] = useState(true);\n const treeRef = useRef<PhylogeneticTreeRef>(null);\n const dashboardStore = use(DashboardStoreContext);\n const dashboardContext = use(DashboardContext);\n const userProfileStore = use(UserProfileStoreContext);\n const setPhylogeneticTreeResponse = useStore(dashboardStore, (state) => state.setPhylogeneticTreeResponse);\n const baseData = useStore(dashboardStore, (state) => state.baseData);\n const sortedData = useStore(dashboardStore, (state) => state.sortedData);\n const filteredCases = useStore(dashboardStore, (state) => state.filteredData[SELECTION_FILTER_GROUP]);\n const setSorting = useStore(dashboardStore, (state) => state.setSorting);\n const tree = useStore(dashboardStore, (state) => state.tree);\n const sortByField = useStore(dashboardStore, (state) => state.sortByField);\n const stratification = useStore(dashboardStore, (state) => state.stratification);\n const completeCaseType = useStore(dashboardStore, (state) => state.completeCaseType);\n const hasActiveTreeFilter = useStore(dashboardStore, (state) => !state.filters.find(filter => filter instanceof TreeFilter).isInitialFilterValue());\n const addTreeFilter = useStore(dashboardStore, (state) => state.addTreeFilter);\n const treeFilterStepOut = useStore(dashboardStore, (state) => state.treeFilterStepOut);\n const updateWidgetData = useStore(dashboardStore, (state) => state.updateWidgetData);\n const updateWidgetDataPersistable = useStore(dashboardStore, (state) => state.updateWidgetDataPersistable);\n const removeTreeFilter = useStore(dashboardStore, (state) => state.removeTreeFilter);\n const isCaseDataLoading = useStore(dashboardStore, (state) => state.isDataLoading);\n const newick = useStore(dashboardStore, (state) => state.newick);\n const resetTreeAddresses = useStore(dashboardStore, (state) => state.resetTreeAddresses);\n const isShowDistancesEnabled = useStore(userProfileStore, (state) => (state.dashboardWidgetSettings[DASHBOARD_COMPONENT_NAME.TREE] as DashboardTreeSettings).isShowDistancesEnabled);\n const isShowSupportLinesWhenUnlinkedEnabled = useStore(userProfileStore, (state) => (state.dashboardWidgetSettings[DASHBOARD_COMPONENT_NAME.TREE] as DashboardTreeSettings).isShowSupportLinesWhenUnlinkedEnabled);\n const [contextMenuConfig, setContextMenuConfig] = useState<ContextMenuConfigWithPosition | null>(null);\n const [zoomInMenuItemConfig, setZoomInMenuItemConfig] = useState<ZoomInMenuItemConfig>(null);\n const [extraLeafInfoId, setExtraLeafInfoId] = useState<string>(null);\n const [treeConfiguration, setTreeConfiguration] = useState<TreeConfiguration>(dashboardStore.getState().getWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE).treeConfiguration);\n const treeHighlightingSubject = useMemo(() => new Subject<Highlighting>({\n caseIds: [],\n origin: null,\n }), []);\n const initialTreeViewState = useMemo<PhylogeneticTreeViewState>(() => {\n const widgetData = dashboardStore.getState().getWidgetData<TreeWidgetData>(DASHBOARD_COMPONENT_NAME.TREE);\n return {\n horizontalScrollPosition: !isNaN(widgetData?.horizontalScrollPosition) ? widgetData.horizontalScrollPosition : 0,\n verticalScrollPosition: !isNaN(widgetData?.verticalScrollPosition) ? widgetData.verticalScrollPosition : 0,\n zoomLevel: !isNaN(widgetData?.zoomLevel) ? widgetData.zoomLevel : 1,\n };\n }, [dashboardStore]);\n\n const sortedLeafNames = useMemo(() => {\n return sortedData.map(c => c.id);\n }, [sortedData]);\n\n const treeConfigurations = useMemo(() => TreeWidgetUtil.getTreeConfigurations(completeCaseType), [completeCaseType]);\n\n const treeCanvasAriaLabel = useMemo(() => {\n if (!treeConfiguration) {\n return t('Phylogenetic tree visualization');\n }\n\n const label = treeConfiguration.col?.label || t('data');\n const geneticDistanceProtocol = treeConfiguration.geneticDistanceProtocol?.name || t('unknown protocol');\n const treeAlgorithm = treeConfiguration.treeAlgorithm?.name || t('unknown algorithm');\n\n return t('Figure of a phylogenetic tree belonging to {{label}}. Generated using {{geneticDistanceProtocol}} and {{treeAlgorithm}}.', {\n geneticDistanceProtocol,\n label,\n treeAlgorithm,\n });\n }, [treeConfiguration, t]);\n\n useEffect(() => {\n const unsubscribeHighlightingManager = dashboardContext.highlightSubject.subscribe((highlighting) => {\n if (highlighting.origin === DASHBOARD_COMPONENT_NAME.TREE) {\n return;\n }\n treeHighlightingSubject.next(highlighting);\n });\n const unsubscribeTreeHighlightingSubject = treeHighlightingSubject.subscribe((highlighting) => {\n if (highlighting.origin !== DASHBOARD_COMPONENT_NAME.TREE) {\n return;\n }\n dashboardContext.highlight(highlighting);\n });\n\n return () => {\n unsubscribeHighlightingManager();\n unsubscribeTreeHighlightingSubject();\n };\n }, [dashboardContext, treeHighlightingSubject]);\n\n const caseIds = useMemo(() => filteredCases.map(c => c.id).sort(), [filteredCases]);\n\n useEffect(() => {\n resetTreeAddresses();\n }, [caseIds, resetTreeAddresses]);\n\n const hasEnoughSequencesToShowTree = useMemo(() => caseIds.length >= 2 && caseIds.every(x => !!x), [caseIds]);\n const hasToManyResultsToShowTree = useMemo(() => caseIds.length > 0 && completeCaseType.props.read_max_tree_size > 0 && caseIds.length > completeCaseType.props.read_max_tree_size, [caseIds, completeCaseType.props.read_max_tree_size]);\n\n const retrievePhylogeneticTreeRequestBody = useMemo<CaseDbRetrievePhylogeneticTreeRequestBody>(() => ({\n case_ids: caseIds,\n case_type_id: completeCaseType.id,\n genetic_distance_col_id: treeConfiguration?.col.id,\n tree_algorithm_code: treeConfiguration?.treeAlgorithm.code,\n }), [caseIds, completeCaseType.id, treeConfiguration]);\n\n const { data: treeData, error: treeError, isLoading: isTreeLoading } = useQueryMemo({\n enabled: hasEnoughSequencesToShowTree && !!treeConfiguration && !hasToManyResultsToShowTree,\n queryFn: async ({ signal }) => {\n const response = await CaseDbCaseApi.getInstance().retrievePhylogeneticTree(retrievePhylogeneticTreeRequestBody, { signal });\n return response.data;\n },\n queryKey: [CASEDB_QUERY_KEY.PHYLOGENETIC_TREE, JSON.stringify(retrievePhylogeneticTreeRequestBody)],\n retry: false,\n staleTime: Infinity,\n });\n\n const onOpenFiltersButtonClick = useCallback(() => {\n EventBusService.getInstance().emit('openFiltersMenu');\n }, []);\n\n const isLoading = !!treeConfiguration && (isCaseDataLoading || (hasEnoughSequencesToShowTree && isTreeLoading));\n const isTreeUnavailable = hasToManyResultsToShowTree || !isCaseDataLoading && ((!isLoading && !!treeError) || !hasEnoughSequencesToShowTree || tree?.maxBranchLength?.toNumber() === 0 || tree?.size === 0 || !treeConfiguration || (!isLoading && tree === null));\n const shouldShowTree = !hasToManyResultsToShowTree && !!treeConfiguration && !isCaseDataLoading && !treeError && !isTreeLoading && tree?.size > 0 && hasEnoughSequencesToShowTree;\n\n const widgetUnavailableReason = useMemo<ReactElement | string>(() => {\n if (!isTreeUnavailable) {\n return null;\n }\n if (!hasEnoughSequencesToShowTree) {\n return t`The phylogenetic tree cannot be displayed because there are not enough sequences available for the shown cases. A minimum of 2 sequences is required to generate a phylogenetic tree.`;\n }\n if (hasEnoughSequencesToShowTree && !tree) {\n return t`The phylogenetic tree cannot be displayed because the tree could not be generated. Either there are no sequences available for the shown cases or the selected tree configuration does not yield a valid tree.`;\n }\n if (hasToManyResultsToShowTree) {\n return (\n (\n <>\n <Box\n sx={{\n marginBottom: 2,\n }}\n >\n {t('The phylogenetic tree cannot be displayed because the number of cases ({{caseCount}}) exceeds the maximum allowed number of cases ({{maxSize}}) to display a phylogenetic tree. Refine your filters to reduce the number of results.', {\n caseCount: caseIds.length,\n maxSize: completeCaseType.props.read_max_tree_size,\n })}\n </Box>\n <Button\n color={'inherit'}\n onClick={onOpenFiltersButtonClick}\n variant={'outlined'}\n >\n {t`Refine filters`}\n </Button>\n </>\n )\n );\n }\n }, [caseIds.length, completeCaseType.props.read_max_tree_size, hasEnoughSequencesToShowTree, hasToManyResultsToShowTree, isTreeUnavailable, onOpenFiltersButtonClick, t, tree]);\n\n useEffect(() => {\n if (treeData) {\n setPhylogeneticTreeResponse(treeData);\n }\n }, [treeData, setPhylogeneticTreeResponse]);\n\n useEffect(() => {\n if (!treeConfigurations?.length) {\n setTreeConfiguration(null);\n updateWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE, {\n treeConfiguration: null,\n });\n return;\n }\n const newConfig = dashboardStore.getState().getWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE)?.treeConfiguration || treeConfigurations[0];\n\n setTreeConfiguration(newConfig);\n updateWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE, {\n treeConfiguration: newConfig,\n });\n }, [dashboardStore, treeConfigurations, updateWidgetDataPersistable]);\n\n useEffect(() => {\n if (sortByField && isTreeLinked && shouldShowTree) {\n treeRef.current?.unlink({\n positionX: 0,\n positionY: 0,\n zoomLevel: ConfigService.getInstance<CaseDbConfig>().config.tree.INITIAL_UNLINKED_ZOOM_LEVEL,\n });\n }\n }, [isTreeLinked, shouldShowTree, sortByField]);\n\n const updateEpiTreeWidgetDataDebounced = useDebouncedCallback((viewState: PhylogeneticTreeViewState) => {\n updateWidgetData<TreeWidgetData>(DASHBOARD_COMPONENT_NAME.TREE, {\n horizontalScrollPosition: viewState.horizontalScrollPosition,\n verticalScrollPosition: viewState.verticalScrollPosition,\n zoomLevel: viewState.zoomLevel,\n });\n }, 500);\n\n const onTreeViewStateChange = useCallback((viewState: PhylogeneticTreeViewState) => {\n updateEpiTreeWidgetDataDebounced(viewState);\n }, [updateEpiTreeWidgetDataDebounced]);\n\n const onTreeCanvasChange = useCallback((canvas?: HTMLCanvasElement) => {\n setTreeCanvas(canvas);\n }, []);\n\n const onEpiContextMenuClose = useCallback(() => {\n setContextMenuConfig(null);\n setZoomInMenuItemConfig(null);\n }, []);\n\n const linkLineListToTree = useCallback(() => {\n const perform = async () => {\n await setSorting(null, null);\n treeRef.current?.syncScrollToVisibleTree();\n };\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n perform();\n\n }, [setSorting]);\n\n const onLinkButtonClick = useCallback(() => {\n linkLineListToTree();\n\n }, [linkLineListToTree]);\n\n const resetZoomLevelAndScrollPosition = useCallback(() => {\n treeRef.current?.link(0);\n }, []);\n\n const onAddTreeFilterMenuItemClick = useCallback(async (onMenuClose: () => void) => {\n await addTreeFilter(zoomInMenuItemConfig.rootId);\n resetZoomLevelAndScrollPosition();\n onMenuClose();\n }, [addTreeFilter, zoomInMenuItemConfig, resetZoomLevelAndScrollPosition]);\n\n const onRemoveTreeFilterButtonClick = useCallback(async () => {\n await removeTreeFilter();\n resetZoomLevelAndScrollPosition();\n }, [removeTreeFilter, resetZoomLevelAndScrollPosition]);\n\n const onTreeFilterStepOutButtonClick = useCallback(async () => {\n await treeFilterStepOut();\n resetZoomLevelAndScrollPosition();\n }, [resetZoomLevelAndScrollPosition, treeFilterStepOut]);\n\n const onTreePathClick = useCallback(({ mouseEvent, pathProperties }: PhylogeneticTreePathClickEvent) => {\n setZoomInMenuItemConfig(null);\n setExtraLeafInfoId(null);\n\n if (pathProperties?.treeNode) {\n const { treeNode } = pathProperties;\n setContextMenuConfig({\n caseIds: treeNode.subTreeLeaveNames ? treeNode.subTreeLeaveNames : [treeNode.name],\n mouseEvent,\n position: {\n left: mouseEvent.clientX,\n top: mouseEvent.clientY,\n },\n });\n if (treeNode.subTreeNames.length && treeNode.name && treeNode.maxBranchLength.toNumber()) {\n setZoomInMenuItemConfig({\n caseIds: treeNode.subTreeLeaveNames,\n rootId: treeNode.name,\n });\n }\n if (treeNode.name && !treeNode.subTreeNames.length) {\n setExtraLeafInfoId(treeNode.name);\n }\n return;\n }\n\n if (pathProperties?.subTreeLeaveNames?.length) {\n setContextMenuConfig({\n caseIds: pathProperties.subTreeLeaveNames,\n mouseEvent,\n position: {\n left: mouseEvent.clientX,\n top: mouseEvent.clientY,\n },\n });\n }\n }, []);\n\n const onShowDetailsSelectionMenuItemClick = useCallback((onMenuClose: () => void) => {\n EventBusService.getInstance().emit('openCaseInfoDialog', {\n caseId: baseData.find(c => c.id === extraLeafInfoId).id,\n caseTypeId: completeCaseType.id,\n });\n onMenuClose();\n }, [extraLeafInfoId, baseData, completeCaseType.id]);\n\n const getEpiContextMenuExtraItems = useCallback((onMenuClose: () => void): ReactElement => {\n if (zoomInMenuItemConfig) {\n return (\n <MenuItem\n divider\n // eslint-disable-next-line @eslint-react/kit/jsx-no-bind\n onClick={async () => onAddTreeFilterMenuItemClick(onMenuClose)}\n >\n <ListItemIcon>\n <FilterAltIcon fontSize={'small'} />\n </ListItemIcon>\n <ListItemText>\n {t`Filter (show only this subtree)`}\n </ListItemText>\n </MenuItem>\n );\n }\n if (extraLeafInfoId) {\n return (\n <MenuItem\n divider\n // eslint-disable-next-line @eslint-react/kit/jsx-no-bind\n onClick={() => onShowDetailsSelectionMenuItemClick(onMenuClose)}\n >\n <ListItemIcon>\n <InfoOutlinedIcon fontSize={'small'} />\n </ListItemIcon>\n <ListItemText>\n {t`Show details`}\n </ListItemText>\n </MenuItem>\n );\n }\n }, [extraLeafInfoId, onShowDetailsSelectionMenuItemClick, onAddTreeFilterMenuItemClick, t, zoomInMenuItemConfig]);\n\n const titleMenu = useMemo<MenuItemData | string>(() => {\n if (!treeConfigurations?.length) {\n return t`Tree`;\n }\n\n const menu: MenuItemData = {\n disabled: !treeConfiguration,\n items: treeConfigurations?.map<MenuItemData>(config => ({\n active: !!treeConfiguration && treeConfiguration.computedId === config.computedId,\n callback: () => {\n const perform = async () => {\n await removeTreeFilter();\n updateWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE, {\n treeConfiguration: config,\n });\n setTreeConfiguration(config);\n };\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n perform();\n },\n label: TreeWidgetUtil.getTreeConfigurationLabel(config),\n tooltip: (\n <TreeDescription\n treeConfiguration={config}\n />\n ),\n })) ?? [],\n label: treeConfiguration ? t('Tree: {{algorithm}}', { algorithm: TreeWidgetUtil.getTreeConfigurationLabel(treeConfiguration) }) : t`Tree`,\n tooltip: treeConfiguration\n ? (\n <TreeDescription\n treeConfiguration={treeConfiguration}\n />\n )\n : undefined,\n };\n\n return menu;\n }, [treeConfigurations, treeConfiguration, t, removeTreeFilter, updateWidgetDataPersistable]);\n\n const primaryMenu = useMemo<MenuItemData[]>(() => {\n return [\n {\n callback: onTreeFilterStepOutButtonClick,\n disabled: !hasActiveTreeFilter,\n label: t`Change tree filter to nearest ancestor`,\n leftIcon: <ArrowUpwardIcon />,\n },\n {\n callback: onRemoveTreeFilterButtonClick,\n disabled: !hasActiveTreeFilter,\n label: t`Remove tree filter`,\n leftIcon: <ClearIcon />,\n },\n {\n callback: onLinkButtonClick,\n label: t`Link and snap the Line List to the Tree (resets tree zoom level and Line List sorting)`,\n leftIcon: (\n <LinkIcon\n sx={{\n color: isTreeLinked ? undefined : theme.palette.error.main,\n }}\n />\n ),\n },\n ];\n }, [hasActiveTreeFilter, isTreeLinked, onLinkButtonClick, onRemoveTreeFilterButtonClick, onTreeFilterStepOutButtonClick, t, theme.palette.error.main]);\n\n useEffect(() => {\n const emitDownloadOptions = () => {\n const baseName = t('Phylogenetic Tree - {{geneticDistanceProtocol}} - {{treeAlgorithm}}',\n {\n geneticDistanceProtocol: treeConfiguration?.geneticDistanceProtocol.name ?? '',\n treeAlgorithm: treeConfiguration?.treeAlgorithm.name ?? '',\n });\n\n EventBusService.getInstance().emit('onDownloadOptionsChanged', {\n disabled: isTreeUnavailable,\n items: [\n {\n callback: () => CaseDbDownloadUtil.downloadNewick(baseName, newick, completeCaseType, t),\n label: t`Save as Newick`,\n },\n {\n callback: () => CaseDbDownloadUtil.downloadCanvasImage(baseName, treeCanvas, 'jpeg', completeCaseType, t),\n label: t`Save as JPEG`,\n },\n {\n callback: () => CaseDbDownloadUtil.downloadCanvasImage(baseName, treeCanvas, 'png', completeCaseType, t),\n label: t`Save as PNG`,\n },\n ],\n zone: DASHBOARD_COMPONENT_NAME.TREE,\n zoneLabel: t`Phylogenetic Tree`,\n });\n };\n\n\n emitDownloadOptions();\n const eventBusService = EventBusService.getInstance();\n eventBusService.addEventListener('onDownloadOptionsRequested', emitDownloadOptions);\n\n return () => {\n eventBusService.emit('onDownloadOptionsChanged', {\n items: null,\n zone: DASHBOARD_COMPONENT_NAME.TREE,\n zoneLabel: t`Tree`,\n });\n eventBusService.removeEventListener('onDownloadOptionsRequested', emitDownloadOptions);\n };\n }, [completeCaseType, isTreeLinked, isTreeUnavailable, newick, t, treeCanvas, treeConfiguration?.geneticDistanceProtocol.name, treeConfiguration?.treeAlgorithm.name]);\n\n\n useEffect(() => {\n // eslint-disable-next-line @eslint-react/web-api-no-leaked-event-listener\n const removeEventListener = EventBusService.getInstance().addEventListener('onLinkLineListAndTree', () => treeRef.current?.link());\n return () => {\n removeEventListener();\n };\n }, []);\n\n\n const onLinkStateChange = useCallback((linked: boolean) => {\n setIsTreeLinked(linked);\n }, [setIsTreeLinked]);\n\n const phylogeneticTreeHighlightedNodeNamesSubject = useMemo(() => {\n const subject = new Subject<PhylogeneticTreeHighlightedNodeNamesSubjectValue>({\n highlightedNodeNames: dashboardContext.highlightSubject.data.caseIds,\n });\n return subject;\n }, [dashboardContext.highlightSubject.data.caseIds]);\n\n useEffect(() => {\n const unsubscribe = phylogeneticTreeHighlightedNodeNamesSubject.subscribe((data) => {\n dashboardContext.highlight({\n caseIds: data.highlightedNodeNames,\n origin: DASHBOARD_COMPONENT_NAME.TREE,\n });\n });\n return () => {\n unsubscribe();\n };\n }, [phylogeneticTreeHighlightedNodeNamesSubject, dashboardContext]);\n\n useEffect(() => {\n const unsubscribe = dashboardContext.highlightSubject.subscribe(data => {\n if (data.origin === DASHBOARD_COMPONENT_NAME.TREE) {\n return;\n }\n phylogeneticTreeHighlightedNodeNamesSubject.next({\n highlightedNodeNames: data.caseIds,\n });\n });\n return () => {\n unsubscribe();\n };\n }, [dashboardContext.highlightSubject, phylogeneticTreeHighlightedNodeNamesSubject]);\n\n return (\n <DashboardWidget\n expandDisabled={isTreeUnavailable}\n primaryMenu={primaryMenu}\n title={titleMenu}\n widgetName={DASHBOARD_COMPONENT_NAME.TREE}\n >\n <Box\n sx={{\n height: '100%',\n overflow: 'clip',\n position: 'relative',\n width: '100%',\n }}\n >\n {isTreeUnavailable && (\n <>\n <WidgetUnavailable\n reason={widgetUnavailableReason}\n widgetLabel={t`phylogenetic tree`}\n />\n </>\n )}\n {(isLoading && !isTreeUnavailable) && (\n <Spinner\n label={t`Loading`}\n takingLongerTimeoutMs={ConfigService.getInstance<CaseDbConfig>().config.tree.TAKING_LONGER_TIMEOUT_MS}\n />\n )}\n {!isTreeUnavailable && shouldShowTree && (\n <PhylogeneticTree\n ancestorDotRadius={treeConfig.ANCESTOR_DOT_RADIUS}\n ariaLabel={treeCanvasAriaLabel}\n backgroundColor={theme.palette.background.paper}\n dimFn={theme['gen-epix-ui-client-casedb'].tree.dimFn}\n fontFamily={theme.typography.fontFamily}\n headerHeight={treeConfig.HEADER_HEIGHT}\n highlightedNodeNamesSubject={phylogeneticTreeHighlightedNodeNamesSubject}\n initialViewState={initialTreeViewState}\n itemHeight={ConfigService.getInstance<CaseDbConfig>().config.lineList.TABLE_ROW_HEIGHT}\n leafDotRadius={treeConfig.LEAF_DOT_RADIUS}\n linkedScrollDebounceDelayMs={treeConfig.LINKED_SCROLL_DEBOUNCE_DELAY_MS}\n maxScaleWidthPx={treeConfig.MAX_SCALE_WIDTH_PX}\n maxZoomLevel={treeConfig.MAX_ZOOM_LEVEL}\n maxZoomSpeed={treeConfig.MAX_ZOOM_SPEED}\n minimumDistancePercentageToShowLabel={treeConfig.MINIMUM_DISTANCE_PERCENTAGE_TO_SHOW_LABEL}\n minScaleWidthPx={treeConfig.MIN_SCALE_WIDTH_PX}\n minZoomLevel={treeConfig.MIN_ZOOM_LEVEL}\n minZoomSpeed={treeConfig.MIN_ZOOM_SPEED}\n nodeNameColors={stratification?.caseIdColors}\n onCanvasChange={onTreeCanvasChange}\n onLinkStateChange={onLinkStateChange}\n onPathClick={onTreePathClick}\n onViewStateChange={onTreeViewStateChange}\n panningThreshold={treeConfig.PANNING_THRESHOLD}\n ref={treeRef}\n regularFillColorSupportLine={treeConfig.REGULAR_FILL_COLOR_SUPPORT_LINE}\n scaleColor={theme.palette.text.primary}\n scaleIncrements={treeConfig.SCALE_INCREMENTS}\n scrollSubject={dashboardContext.linkedScrollSubject}\n shouldShowDistances={isShowDistancesEnabled}\n shouldShowSupportLinesWhenUnlinked={isShowSupportLinesWhenUnlinkedEnabled}\n sortedLeafNames={sortedLeafNames}\n supportLineColorLinked={theme['gen-epix-ui-client-casedb'].tree.supportLineColorLinked}\n supportLineColorUnlinked={theme['gen-epix-ui-client-casedb'].tree.supportLineColorUnlinked}\n tree={tree}\n treeColor={theme['gen-epix-ui-client-casedb'].tree.color}\n treeFont={theme['gen-epix-ui-client-casedb'].tree.font}\n treePadding={treeConfig.TREE_PADDING}\n visibleRangeSubject={dashboardContext.lineListRangeSubject}\n />\n )}\n </Box>\n <ContextMenu\n config={contextMenuConfig}\n getExtraItems={getEpiContextMenuExtraItems}\n onMenuClose={onEpiContextMenuClose}\n />\n </DashboardWidget>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ui/TreeWidget/TreeWidget.tsx"],"sourcesContent":["import {\n Box,\n Button,\n ListItemIcon,\n ListItemText,\n MenuItem,\n useTheme,\n} from '@mui/material';\nimport ClearIcon from '@mui/icons-material/Clear';\nimport ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';\nimport FilterAltIcon from '@mui/icons-material/FilterAlt';\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';\nimport LinkIcon from '@mui/icons-material/Link';\nimport type { ReactElement } from 'react';\nimport {\n use,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useStore } from 'zustand';\nimport { useDebouncedCallback } from 'use-debounce';\nimport type { CaseDbRetrievePhylogeneticTreeRequestBody } from '@gen-epix/api-casedb';\nimport { CaseDbCaseApi } from '@gen-epix/api-casedb';\nimport type { MenuItemData } from '@gen-epix/ui-core-components/models/nestedMenu';\nimport { ConfigService } from '@gen-epix/ui-client-common/classes/services/ConfigService';\nimport { Spinner } from '@gen-epix/ui-core-components/components/Spinner';\nimport { useQueryMemo } from '@gen-epix/ui-client-common/hooks/useQueryMemo';\nimport { Subject } from '@gen-epix/ui-core/classes/Subject';\nimport { PhylogeneticTree } from '@gen-epix/ui-phylogenetic-tree/components/PhylogeneticTree';\nimport type {\n PhylogeneticTreeHighlightedNodeNamesSubjectValue,\n PhylogeneticTreePathClickEvent,\n PhylogeneticTreeRef,\n PhylogeneticTreeViewState,\n} from '@gen-epix/ui-phylogenetic-tree/components/PhylogeneticTree';\n\nimport { EventBusService } from '../../../classes/services/EventBusService';\nimport type {\n DashboardTreeSettings,\n TreeConfiguration,\n TreeWidgetData,\n TreeWidgetDataPersistable,\n} from '../../../models/dashboard';\nimport type { Highlighting } from '../../../models/caseDb';\nimport { DashboardStoreContext } from '../../../stores/dashboardStore';\nimport { SELECTION_FILTER_GROUP } from '../../../utils/CaseTypeUtil';\nimport { CaseDbDownloadUtil } from '../../../utils/CaseDbDownloadUtil';\nimport { TreeWidgetUtil } from '../../../utils/TreeWidgetUtil';\nimport type { ContextMenuConfigWithPosition } from '../ContextMenu';\nimport { ContextMenu } from '../ContextMenu';\nimport { TreeDescription } from '../TreeDescription';\nimport { WidgetUnavailable } from '../WidgetUnavailable';\nimport { CASEDB_QUERY_KEY } from '../../../constants/query';\nimport type { CaseDbConfig } from '../../../models/config';\nimport { TreeFilter } from '../../../classes/filters/TreeFilter';\nimport { DashboardWidget } from '../Dashboard';\nimport { DASHBOARD_COMPONENT_NAME } from '../../../constants/dashboard';\nimport { DashboardContext } from '../Dashboard/context/DashboardContext';\nimport { UserProfileStoreContext } from '../../../stores/userProfileStore/userProfileStoreContext';\n\ntype ZoomInMenuItemConfig = {\n caseIds?: string[];\n rootId?: string;\n};\n\nexport const TreeWidget = () => {\n const theme = useTheme();\n const { t } = useTranslation();\n const treeConfig = ConfigService.getInstance<CaseDbConfig>().config.tree;\n const [treeCanvas, setTreeCanvas] = useState<HTMLCanvasElement>();\n const [isTreeLinked, setIsTreeLinked] = useState(true);\n const treeRef = useRef<PhylogeneticTreeRef>(null);\n const dashboardStore = use(DashboardStoreContext);\n const dashboardContext = use(DashboardContext);\n const userProfileStore = use(UserProfileStoreContext);\n const setPhylogeneticTreeResponse = useStore(dashboardStore, (state) => state.setPhylogeneticTreeResponse);\n const baseData = useStore(dashboardStore, (state) => state.baseData);\n const sortedData = useStore(dashboardStore, (state) => state.sortedData);\n const filteredCases = useStore(dashboardStore, (state) => state.filteredData[SELECTION_FILTER_GROUP]);\n const setSorting = useStore(dashboardStore, (state) => state.setSorting);\n const tree = useStore(dashboardStore, (state) => state.tree);\n const sortByField = useStore(dashboardStore, (state) => state.sortByField);\n const stratification = useStore(dashboardStore, (state) => state.stratification);\n const completeCaseType = useStore(dashboardStore, (state) => state.completeCaseType);\n const hasActiveTreeFilter = useStore(dashboardStore, (state) => !state.filters.find(filter => filter instanceof TreeFilter).isInitialFilterValue());\n const addTreeFilter = useStore(dashboardStore, (state) => state.addTreeFilter);\n const treeFilterStepOut = useStore(dashboardStore, (state) => state.treeFilterStepOut);\n const updateWidgetData = useStore(dashboardStore, (state) => state.updateWidgetData);\n const updateWidgetDataPersistable = useStore(dashboardStore, (state) => state.updateWidgetDataPersistable);\n const removeTreeFilter = useStore(dashboardStore, (state) => state.removeTreeFilter);\n const isCaseDataLoading = useStore(dashboardStore, (state) => state.isDataLoading);\n const newick = useStore(dashboardStore, (state) => state.newick);\n const resetTreeAddresses = useStore(dashboardStore, (state) => state.resetTreeAddresses);\n const isShowDistancesEnabled = useStore(userProfileStore, (state) => (state.dashboardWidgetSettings[DASHBOARD_COMPONENT_NAME.TREE] as DashboardTreeSettings).isShowDistancesEnabled);\n const isShowSupportLinesWhenUnlinkedEnabled = useStore(userProfileStore, (state) => (state.dashboardWidgetSettings[DASHBOARD_COMPONENT_NAME.TREE] as DashboardTreeSettings).isShowSupportLinesWhenUnlinkedEnabled);\n const [contextMenuConfig, setContextMenuConfig] = useState<ContextMenuConfigWithPosition | null>(null);\n const [zoomInMenuItemConfig, setZoomInMenuItemConfig] = useState<ZoomInMenuItemConfig>(null);\n const [extraLeafInfoId, setExtraLeafInfoId] = useState<string>(null);\n const [treeConfiguration, setTreeConfiguration] = useState<TreeConfiguration>(dashboardStore.getState().getWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE).treeConfiguration);\n const treeHighlightingSubject = useMemo(() => new Subject<Highlighting>({\n caseIds: [],\n origin: null,\n }), []);\n const initialTreeViewState = useMemo<PhylogeneticTreeViewState>(() => {\n const widgetData = dashboardStore.getState().getWidgetData<TreeWidgetData>(DASHBOARD_COMPONENT_NAME.TREE);\n return {\n horizontalScrollPosition: !isNaN(widgetData?.horizontalScrollPosition) ? widgetData.horizontalScrollPosition : 0,\n verticalScrollPosition: !isNaN(widgetData?.verticalScrollPosition) ? widgetData.verticalScrollPosition : 0,\n zoomLevel: !isNaN(widgetData?.zoomLevel) ? widgetData.zoomLevel : 1,\n };\n }, [dashboardStore]);\n\n const sortedLeafNames = useMemo(() => {\n return sortedData.map(c => c.id);\n }, [sortedData]);\n\n const treeConfigurations = useMemo(() => TreeWidgetUtil.getTreeConfigurations(completeCaseType), [completeCaseType]);\n\n const treeCanvasAriaLabel = useMemo(() => {\n if (!treeConfiguration) {\n return t('Phylogenetic tree visualization');\n }\n\n const label = treeConfiguration.col?.label || t('data');\n const geneticDistanceProtocol = treeConfiguration.geneticDistanceProtocol?.name || t('unknown protocol');\n const treeAlgorithm = treeConfiguration.treeAlgorithm?.name || t('unknown algorithm');\n\n return t('Figure of a phylogenetic tree belonging to {{label}}. Generated using {{geneticDistanceProtocol}} and {{treeAlgorithm}}.', {\n geneticDistanceProtocol,\n label,\n treeAlgorithm,\n });\n }, [treeConfiguration, t]);\n\n useEffect(() => {\n const unsubscribeHighlightingManager = dashboardContext.highlightSubject.subscribe((highlighting) => {\n if (highlighting.origin === DASHBOARD_COMPONENT_NAME.TREE) {\n return;\n }\n treeHighlightingSubject.next(highlighting);\n });\n const unsubscribeTreeHighlightingSubject = treeHighlightingSubject.subscribe((highlighting) => {\n if (highlighting.origin !== DASHBOARD_COMPONENT_NAME.TREE) {\n return;\n }\n dashboardContext.highlight(highlighting);\n });\n\n return () => {\n unsubscribeHighlightingManager();\n unsubscribeTreeHighlightingSubject();\n };\n }, [dashboardContext, treeHighlightingSubject]);\n\n const caseIds = useMemo(() => filteredCases.map(c => c.id).sort(), [filteredCases]);\n\n useEffect(() => {\n resetTreeAddresses();\n }, [caseIds, resetTreeAddresses]);\n\n const hasEnoughSequencesToShowTree = useMemo(() => caseIds.length >= 2 && caseIds.every(x => !!x), [caseIds]);\n const hasToManyResultsToShowTree = useMemo(() => caseIds.length > 0 && completeCaseType.props.read_max_tree_size > 0 && caseIds.length > completeCaseType.props.read_max_tree_size, [caseIds, completeCaseType.props.read_max_tree_size]);\n\n const retrievePhylogeneticTreeRequestBody = useMemo<CaseDbRetrievePhylogeneticTreeRequestBody>(() => ({\n case_ids: caseIds,\n case_type_id: completeCaseType.id,\n genetic_distance_col_id: treeConfiguration?.col.id,\n tree_algorithm_code: treeConfiguration?.treeAlgorithm.code,\n }), [caseIds, completeCaseType.id, treeConfiguration]);\n\n const { data: treeData, error: treeError, isLoading: isTreeLoading } = useQueryMemo({\n enabled: hasEnoughSequencesToShowTree && !!treeConfiguration && !hasToManyResultsToShowTree,\n queryFn: async ({ signal }) => {\n const response = await CaseDbCaseApi.getInstance().retrievePhylogeneticTree(retrievePhylogeneticTreeRequestBody, { signal });\n return response.data;\n },\n queryKey: [CASEDB_QUERY_KEY.PHYLOGENETIC_TREE, JSON.stringify(retrievePhylogeneticTreeRequestBody)],\n retry: false,\n staleTime: Infinity,\n });\n\n const onOpenFiltersButtonClick = useCallback(() => {\n EventBusService.getInstance().emit('openFiltersMenu');\n }, []);\n\n const isLoading = !!treeConfiguration && (isCaseDataLoading || (hasEnoughSequencesToShowTree && isTreeLoading));\n const isTreeUnavailable = hasToManyResultsToShowTree || !isCaseDataLoading && ((!isLoading && !!treeError) || !hasEnoughSequencesToShowTree || tree?.maxBranchLength?.toNumber() === 0 || tree?.size === 0 || !treeConfiguration || (!isLoading && tree === null));\n const shouldShowTree = !hasToManyResultsToShowTree && !!treeConfiguration && !isCaseDataLoading && !treeError && !isTreeLoading && tree?.size > 0 && hasEnoughSequencesToShowTree;\n\n const widgetUnavailableReason = useMemo<ReactElement | string>(() => {\n if (!isTreeUnavailable) {\n return null;\n }\n if (!hasEnoughSequencesToShowTree) {\n return t`The phylogenetic tree cannot be displayed because there are not enough sequences available for the shown cases. A minimum of 2 sequences is required to generate a phylogenetic tree.`;\n }\n if (hasEnoughSequencesToShowTree && !tree) {\n return t`The phylogenetic tree cannot be displayed because the tree could not be generated. Either there are no sequences available for the shown cases or the selected tree configuration does not yield a valid tree.`;\n }\n if (hasToManyResultsToShowTree) {\n return (\n (\n <>\n <Box\n sx={{\n marginBottom: 2,\n }}\n >\n {t('The phylogenetic tree cannot be displayed because the number of cases ({{caseCount}}) exceeds the maximum allowed number of cases ({{maxSize}}) to display a phylogenetic tree. Refine your filters to reduce the number of results.', {\n caseCount: caseIds.length,\n maxSize: completeCaseType.props.read_max_tree_size,\n })}\n </Box>\n <Button\n color={'inherit'}\n onClick={onOpenFiltersButtonClick}\n variant={'outlined'}\n >\n {t`Refine filters`}\n </Button>\n </>\n )\n );\n }\n }, [caseIds.length, completeCaseType.props.read_max_tree_size, hasEnoughSequencesToShowTree, hasToManyResultsToShowTree, isTreeUnavailable, onOpenFiltersButtonClick, t, tree]);\n\n useEffect(() => {\n if (treeData) {\n setPhylogeneticTreeResponse(treeData);\n }\n }, [treeData, setPhylogeneticTreeResponse]);\n\n useEffect(() => {\n if (!treeConfigurations?.length) {\n setTreeConfiguration(null);\n updateWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE, {\n treeConfiguration: null,\n });\n return;\n }\n const newConfig = dashboardStore.getState().getWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE)?.treeConfiguration || treeConfigurations[0];\n\n setTreeConfiguration(newConfig);\n updateWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE, {\n treeConfiguration: newConfig,\n });\n }, [dashboardStore, treeConfigurations, updateWidgetDataPersistable]);\n\n useEffect(() => {\n if (sortByField && isTreeLinked && shouldShowTree) {\n treeRef.current?.unlink({\n positionX: 0,\n positionY: 0,\n zoomLevel: ConfigService.getInstance<CaseDbConfig>().config.tree.INITIAL_UNLINKED_ZOOM_LEVEL,\n });\n }\n }, [isTreeLinked, shouldShowTree, sortByField]);\n\n const updateEpiTreeWidgetDataDebounced = useDebouncedCallback((viewState: PhylogeneticTreeViewState) => {\n updateWidgetData<TreeWidgetData>(DASHBOARD_COMPONENT_NAME.TREE, {\n horizontalScrollPosition: viewState.horizontalScrollPosition,\n verticalScrollPosition: viewState.verticalScrollPosition,\n zoomLevel: viewState.zoomLevel,\n });\n }, 500);\n\n const onTreeViewStateChange = useCallback((viewState: PhylogeneticTreeViewState) => {\n updateEpiTreeWidgetDataDebounced(viewState);\n }, [updateEpiTreeWidgetDataDebounced]);\n\n const onTreeCanvasChange = useCallback((canvas?: HTMLCanvasElement) => {\n setTreeCanvas(canvas);\n }, []);\n\n const onEpiContextMenuClose = useCallback(() => {\n setContextMenuConfig(null);\n setZoomInMenuItemConfig(null);\n }, []);\n\n const linkLineListToTree = useCallback(() => {\n const perform = async () => {\n await setSorting(null, null);\n treeRef.current?.syncScrollToVisibleTree();\n };\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n perform();\n\n }, [setSorting]);\n\n const onLinkButtonClick = useCallback(() => {\n linkLineListToTree();\n\n }, [linkLineListToTree]);\n\n const resetZoomLevelAndScrollPosition = useCallback(() => {\n treeRef.current?.link(0);\n }, []);\n\n const onAddTreeFilterMenuItemClick = useCallback(async (onMenuClose: () => void) => {\n await addTreeFilter(zoomInMenuItemConfig.rootId);\n resetZoomLevelAndScrollPosition();\n onMenuClose();\n }, [addTreeFilter, zoomInMenuItemConfig, resetZoomLevelAndScrollPosition]);\n\n const onRemoveTreeFilterButtonClick = useCallback(async () => {\n await removeTreeFilter();\n resetZoomLevelAndScrollPosition();\n }, [removeTreeFilter, resetZoomLevelAndScrollPosition]);\n\n const onTreeFilterStepOutButtonClick = useCallback(async () => {\n await treeFilterStepOut();\n resetZoomLevelAndScrollPosition();\n }, [resetZoomLevelAndScrollPosition, treeFilterStepOut]);\n\n const onTreePathClick = useCallback(({ mouseEvent, pathProperties }: PhylogeneticTreePathClickEvent) => {\n setZoomInMenuItemConfig(null);\n setExtraLeafInfoId(null);\n\n if (pathProperties?.treeNode) {\n const { treeNode } = pathProperties;\n setContextMenuConfig({\n caseIds: treeNode.subTreeLeaveNames ? treeNode.subTreeLeaveNames : [treeNode.name],\n mouseEvent,\n position: {\n left: mouseEvent.clientX,\n top: mouseEvent.clientY,\n },\n });\n if (treeNode.subTreeNames.length && treeNode.name && treeNode.maxBranchLength.toNumber()) {\n setZoomInMenuItemConfig({\n caseIds: treeNode.subTreeLeaveNames,\n rootId: treeNode.name,\n });\n }\n if (treeNode.name && !treeNode.subTreeNames.length) {\n setExtraLeafInfoId(treeNode.name);\n }\n return;\n }\n\n if (pathProperties?.subTreeLeaveNames?.length) {\n setContextMenuConfig({\n caseIds: pathProperties.subTreeLeaveNames,\n mouseEvent,\n position: {\n left: mouseEvent.clientX,\n top: mouseEvent.clientY,\n },\n });\n }\n }, []);\n\n const onShowDetailsSelectionMenuItemClick = useCallback((onMenuClose: () => void) => {\n EventBusService.getInstance().emit('openCaseInfoDialog', {\n caseId: baseData.find(c => c.id === extraLeafInfoId).id,\n caseTypeId: completeCaseType.id,\n });\n onMenuClose();\n }, [extraLeafInfoId, baseData, completeCaseType.id]);\n\n const getEpiContextMenuExtraItems = useCallback((onMenuClose: () => void): ReactElement => {\n if (zoomInMenuItemConfig) {\n return (\n <MenuItem\n divider\n // eslint-disable-next-line @eslint-react/kit/jsx-no-bind\n onClick={async () => onAddTreeFilterMenuItemClick(onMenuClose)}\n >\n <ListItemIcon>\n <FilterAltIcon fontSize={'small'} />\n </ListItemIcon>\n <ListItemText>\n {t`Filter (show only this subtree)`}\n </ListItemText>\n </MenuItem>\n );\n }\n if (extraLeafInfoId) {\n return (\n <MenuItem\n divider\n // eslint-disable-next-line @eslint-react/kit/jsx-no-bind\n onClick={() => onShowDetailsSelectionMenuItemClick(onMenuClose)}\n >\n <ListItemIcon>\n <InfoOutlinedIcon fontSize={'small'} />\n </ListItemIcon>\n <ListItemText>\n {t`Show details`}\n </ListItemText>\n </MenuItem>\n );\n }\n }, [extraLeafInfoId, onShowDetailsSelectionMenuItemClick, onAddTreeFilterMenuItemClick, t, zoomInMenuItemConfig]);\n\n const titleMenu = useMemo<MenuItemData | string>(() => {\n if (!treeConfigurations?.length) {\n return t`Tree`;\n }\n\n const menu: MenuItemData = {\n disabled: !treeConfiguration,\n items: treeConfigurations?.map<MenuItemData>(config => ({\n active: !!treeConfiguration && treeConfiguration.computedId === config.computedId,\n callback: () => {\n const perform = async () => {\n await removeTreeFilter();\n updateWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE, {\n treeConfiguration: config,\n });\n setTreeConfiguration(config);\n };\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n perform();\n },\n label: TreeWidgetUtil.getTreeConfigurationLabel(config),\n tooltip: (\n <TreeDescription\n treeConfiguration={config}\n />\n ),\n })) ?? [],\n label: treeConfiguration ? t('Tree: {{algorithm}}', { algorithm: TreeWidgetUtil.getTreeConfigurationLabel(treeConfiguration) }) : t`Tree`,\n tooltip: treeConfiguration\n ? (\n <TreeDescription\n treeConfiguration={treeConfiguration}\n />\n )\n : undefined,\n };\n\n return menu;\n }, [treeConfigurations, treeConfiguration, t, removeTreeFilter, updateWidgetDataPersistable]);\n\n const primaryMenu = useMemo<MenuItemData[]>(() => {\n return [\n {\n callback: onTreeFilterStepOutButtonClick,\n disabled: !hasActiveTreeFilter,\n label: t`Change tree filter to nearest ancestor`,\n leftIcon: <ArrowUpwardIcon />,\n },\n {\n callback: onRemoveTreeFilterButtonClick,\n disabled: !hasActiveTreeFilter,\n label: t`Remove tree filter`,\n leftIcon: <ClearIcon />,\n },\n {\n callback: onLinkButtonClick,\n label: t`Link and snap the Line List to the Tree (resets tree zoom level and Line List sorting)`,\n leftIcon: (\n <LinkIcon\n sx={{\n color: isTreeLinked ? undefined : theme.palette.error.main,\n }}\n />\n ),\n },\n ];\n }, [hasActiveTreeFilter, isTreeLinked, onLinkButtonClick, onRemoveTreeFilterButtonClick, onTreeFilterStepOutButtonClick, t, theme.palette.error.main]);\n\n useEffect(() => {\n const emitDownloadOptions = () => {\n const baseName = t('Phylogenetic Tree - {{geneticDistanceProtocol}} - {{treeAlgorithm}}',\n {\n geneticDistanceProtocol: treeConfiguration?.geneticDistanceProtocol.name ?? '',\n treeAlgorithm: treeConfiguration?.treeAlgorithm.name ?? '',\n });\n\n EventBusService.getInstance().emit('onDownloadOptionsChanged', {\n disabled: isTreeUnavailable,\n items: [\n {\n callback: () => CaseDbDownloadUtil.downloadNewick(baseName, newick, completeCaseType, t),\n label: t`Save as Newick`,\n },\n {\n callback: () => CaseDbDownloadUtil.downloadCanvasImage(baseName, treeCanvas, 'jpeg', completeCaseType, t),\n label: t`Save as JPEG`,\n },\n {\n callback: () => CaseDbDownloadUtil.downloadCanvasImage(baseName, treeCanvas, 'png', completeCaseType, t),\n label: t`Save as PNG`,\n },\n ],\n zone: DASHBOARD_COMPONENT_NAME.TREE,\n zoneLabel: t`Phylogenetic Tree`,\n });\n };\n\n\n emitDownloadOptions();\n const eventBusService = EventBusService.getInstance();\n eventBusService.addEventListener('onDownloadOptionsRequested', emitDownloadOptions);\n\n return () => {\n eventBusService.emit('onDownloadOptionsChanged', {\n items: null,\n zone: DASHBOARD_COMPONENT_NAME.TREE,\n zoneLabel: t`Tree`,\n });\n eventBusService.removeEventListener('onDownloadOptionsRequested', emitDownloadOptions);\n };\n }, [completeCaseType, isTreeLinked, isTreeUnavailable, newick, t, treeCanvas, treeConfiguration?.geneticDistanceProtocol.name, treeConfiguration?.treeAlgorithm.name]);\n\n\n useEffect(() => {\n // eslint-disable-next-line @eslint-react/web-api-no-leaked-event-listener\n const removeEventListener = EventBusService.getInstance().addEventListener('onLinkLineListAndTree', () => treeRef.current?.link());\n return () => {\n removeEventListener();\n };\n }, []);\n\n\n const onLinkStateChange = useCallback((linked: boolean) => {\n setIsTreeLinked(linked);\n }, [setIsTreeLinked]);\n\n const phylogeneticTreeHighlightedNodeNamesSubject = useMemo(() => {\n const subject = new Subject<PhylogeneticTreeHighlightedNodeNamesSubjectValue>({\n highlightedNodeNames: dashboardContext.highlightSubject.data.caseIds,\n persistedHighlightedNodeNames: [],\n });\n return subject;\n }, [dashboardContext.highlightSubject.data.caseIds]);\n\n useEffect(() => {\n const unsubscribe = phylogeneticTreeHighlightedNodeNamesSubject.subscribe((data) => {\n dashboardContext.highlight({\n caseIds: data.highlightedNodeNames,\n origin: DASHBOARD_COMPONENT_NAME.TREE,\n });\n });\n return () => {\n unsubscribe();\n };\n }, [phylogeneticTreeHighlightedNodeNamesSubject, dashboardContext]);\n\n useEffect(() => {\n const unsubscribe = dashboardContext.highlightSubject.subscribe(data => {\n if (data.origin === DASHBOARD_COMPONENT_NAME.TREE) {\n return;\n }\n phylogeneticTreeHighlightedNodeNamesSubject.next({\n highlightedNodeNames: data.caseIds,\n persistedHighlightedNodeNames: [],\n });\n });\n return () => {\n unsubscribe();\n };\n }, [dashboardContext.highlightSubject, phylogeneticTreeHighlightedNodeNamesSubject]);\n\n return (\n <DashboardWidget\n expandDisabled={isTreeUnavailable}\n primaryMenu={primaryMenu}\n title={titleMenu}\n widgetName={DASHBOARD_COMPONENT_NAME.TREE}\n >\n <Box\n sx={{\n height: '100%',\n overflow: 'clip',\n position: 'relative',\n width: '100%',\n }}\n >\n {isTreeUnavailable && (\n <>\n <WidgetUnavailable\n reason={widgetUnavailableReason}\n widgetLabel={t`phylogenetic tree`}\n />\n </>\n )}\n {(isLoading && !isTreeUnavailable) && (\n <Spinner\n label={t`Loading`}\n takingLongerTimeoutMs={ConfigService.getInstance<CaseDbConfig>().config.tree.TAKING_LONGER_TIMEOUT_MS}\n />\n )}\n {!isTreeUnavailable && shouldShowTree && (\n <PhylogeneticTree\n ancestorDotRadius={treeConfig.ANCESTOR_DOT_RADIUS}\n ariaLabel={treeCanvasAriaLabel}\n backgroundColor={theme.palette.background.paper}\n dimFn={theme['gen-epix-ui-client-casedb'].tree.dimFn}\n fontFamily={theme.typography.fontFamily}\n headerHeight={treeConfig.HEADER_HEIGHT}\n highlightedNodeNamesSubject={phylogeneticTreeHighlightedNodeNamesSubject}\n initialViewState={initialTreeViewState}\n itemHeight={ConfigService.getInstance<CaseDbConfig>().config.lineList.TABLE_ROW_HEIGHT}\n leafDotRadius={treeConfig.LEAF_DOT_RADIUS}\n linkedScrollDebounceDelayMs={treeConfig.LINKED_SCROLL_DEBOUNCE_DELAY_MS}\n maxScaleWidthPx={treeConfig.MAX_SCALE_WIDTH_PX}\n maxZoomLevel={treeConfig.MAX_ZOOM_LEVEL}\n maxZoomSpeed={treeConfig.MAX_ZOOM_SPEED}\n minimumDistancePercentageToShowLabel={treeConfig.MINIMUM_DISTANCE_PERCENTAGE_TO_SHOW_LABEL}\n minScaleWidthPx={treeConfig.MIN_SCALE_WIDTH_PX}\n minZoomLevel={treeConfig.MIN_ZOOM_LEVEL}\n minZoomSpeed={treeConfig.MIN_ZOOM_SPEED}\n nodeNameColors={stratification?.caseIdColors}\n onCanvasChange={onTreeCanvasChange}\n onLinkStateChange={onLinkStateChange}\n onPathClick={onTreePathClick}\n onViewStateChange={onTreeViewStateChange}\n panningThreshold={treeConfig.PANNING_THRESHOLD}\n ref={treeRef}\n regularFillColorSupportLine={treeConfig.REGULAR_FILL_COLOR_SUPPORT_LINE}\n scaleColor={theme.palette.text.primary}\n scaleIncrements={treeConfig.SCALE_INCREMENTS}\n scrollSubject={dashboardContext.linkedScrollSubject}\n shouldShowDistances={isShowDistancesEnabled}\n shouldShowSupportLinesWhenUnlinked={isShowSupportLinesWhenUnlinkedEnabled}\n sortedLeafNames={sortedLeafNames}\n supportLineColorLinked={theme['gen-epix-ui-client-casedb'].tree.supportLineColorLinked}\n supportLineColorUnlinked={theme['gen-epix-ui-client-casedb'].tree.supportLineColorUnlinked}\n tree={tree}\n treeColor={theme['gen-epix-ui-client-casedb'].tree.color}\n treeFont={theme['gen-epix-ui-client-casedb'].tree.font}\n treePadding={treeConfig.TREE_PADDING}\n visibleRangeSubject={dashboardContext.lineListRangeSubject}\n />\n )}\n </Box>\n <ContextMenu\n config={contextMenuConfig}\n getExtraItems={getEpiContextMenuExtraItems}\n onMenuClose={onEpiContextMenuClose}\n />\n </DashboardWidget>\n );\n};\n"],"mappings":"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"}
@@ -1,7 +1,5 @@
1
1
  {
2
2
  "translation": {
3
- "(last modified: {{lastModified}})": "(last modified: {{lastModified}})",
4
- "(size: {{size}})": "(size: {{size}})",
5
3
  "{{caseTypeName}} cases": "{{caseTypeName}} cases",
6
4
  "{{columnLabel}}: Identifier issuer": "{{columnLabel}}: Identifier issuer",
7
5
  "{{count}} similar cases can be added to the line list.": "{{count}} similar cases can be added to the line list.",
@@ -103,11 +101,7 @@
103
101
  "Centroid longitude": "Centroid longitude",
104
102
  "Change dashboard layout": "Change dashboard layout",
105
103
  "Change tree filter to nearest ancestor": "Change tree filter to nearest ancestor",
106
- "Clear {{fileName}}": "Clear {{fileName}}",
107
104
  "Clear all {{dimension}} fields": "Clear all {{dimension}} fields",
108
- "Clear all selected files": "Clear all selected files",
109
- "Click or drag to upload file ({{accept}})": "Click or drag to upload file ({{accept}})",
110
- "Click or drag to upload files ({{accept}})": "Click or drag to upload files ({{accept}})",
111
105
  "Close": "Close",
112
106
  "Close download": "Close download",
113
107
  "Close search": "Close search",
@@ -208,8 +202,6 @@
208
202
  "Download Excel template": "Download Excel template",
209
203
  "Download FASTA": "Download FASTA",
210
204
  "Download sequences": "Download sequences",
211
- "Drop file here": "Drop file here",
212
- "Drop files here": "Drop files here",
213
205
  "Dutch": "Dutch",
214
206
  "Edit": "Edit",
215
207
  "Edit case": "Edit case",
@@ -304,7 +296,6 @@
304
296
  "Indicates if the case is owned by the current user (the case is in a private data collection that is owned by the user's organization).": "Indicates if the case is owned by the current user (the case is in a private data collection that is owned by the user's organization).",
305
297
  "Indicates if there are any issues with the case": "Indicates if there are any issues with the case",
306
298
  "Information for the press": "Information for the press",
307
- "Invalid file type. Accepted types: {{accept}}": "Invalid file type. Accepted types: {{accept}}",
308
299
  "Invalid value for pattern \"{{pattern}}\"": "Invalid value for pattern \"{{pattern}}\"",
309
300
  "Is active": "Is active",
310
301
  "Is created in": "Is created in",
@@ -518,7 +509,6 @@
518
509
  "Select rows": "Select rows",
519
510
  "Select sequence files": "Select sequence files",
520
511
  "Selected": "Selected",
521
- "Selected files: {{numFiles}}": "Selected files: {{numFiles}}",
522
512
  "selected rows": "selected rows",
523
513
  "Selected rows": "Selected rows",
524
514
  "Selected tree node ({{nodeName}})": "Selected tree node ({{nodeName}})",
@@ -589,7 +579,6 @@
589
579
  "This will navigate to the \"{{caseSetName}}\"-event. You will loose your current selection of cases and all applied filters. Do you want to continue?": "This will navigate to the \"{{caseSetName}}\"-event. You will loose your current selection of cases and all applied filters. Do you want to continue?",
590
580
  "To Concept": "To Concept",
591
581
  "To Region": "To Region",
592
- "Too many files selected. Maximum allowed: {{numFilesAllowed}}": "Too many files selected. Maximum allowed: {{numFilesAllowed}}",
593
582
  "Tree": "Tree",
594
583
  "Tree algorithm": "Tree algorithm",
595
584
  "Tree algorithm codes": "Tree algorithm codes",
@@ -1,7 +1,5 @@
1
1
  {
2
2
  "translation": {
3
- "(last modified: {{lastModified}})": "(laatst gewijzigd: {{lastModified}})",
4
- "(size: {{size}})": "(grootte: {{size}})",
5
3
  "{{caseTypeName}} cases": "{{caseTypeName}} casussen",
6
4
  "{{columnLabel}}: Identifier issuer": "{{columnLabel}}: Identificatie uitgever",
7
5
  "{{count}} similar cases can be added to the line list.": "{{count}} vergelijkbare casussen kunnen worden toegevoegd aan de lijnlijst.",
@@ -103,11 +101,7 @@
103
101
  "Centroid longitude": "Centroid lengtegraad",
104
102
  "Change dashboard layout": "Dashboard-indeling wijzigen",
105
103
  "Change tree filter to nearest ancestor": "Wijzig boom filter naar dichtstbijzijnde voorouder",
106
- "Clear {{fileName}}": "Wis {{fileName}}",
107
104
  "Clear all {{dimension}} fields": "Wis alle {{dimension}} velden",
108
- "Clear all selected files": "Wis alle geselecteerde bestanden",
109
- "Click or drag to upload file ({{accept}})": "Klik of sleep om bestand te uploaden ({{accept}})",
110
- "Click or drag to upload files ({{accept}})": "Klik of sleep om bestanden te uploaden ({{accept}})",
111
105
  "Close": "Sluiten",
112
106
  "Close download": "Download sluiten",
113
107
  "Close search": "Zoeken sluiten",
@@ -208,8 +202,6 @@
208
202
  "Download Excel template": "Download Excel sjabloon",
209
203
  "Download FASTA": "Download FASTA",
210
204
  "Download sequences": "Download sequenties",
211
- "Drop file here": "Sleep bestand hierheen",
212
- "Drop files here": "Sleep bestanden hierheen",
213
205
  "Dutch": "Nederlands",
214
206
  "Edit": "Bewerken",
215
207
  "Edit case": "Casus bewerken",
@@ -304,7 +296,6 @@
304
296
  "Indicates if the case is owned by the current user (the case is in a private data collection that is owned by the user's organization).": "Geeft aan of de casus eigendom is van de huidige gebruiker (de casus zit in een privégegevensverzameling waarvan de organisatie van de gebruiker eigenaar is).",
305
297
  "Indicates if there are any issues with the case": "Geeft aan of er problemen zijn met de casus",
306
298
  "Information for the press": "Informatie voor de pers",
307
- "Invalid file type. Accepted types: {{accept}}": "Ongeldig bestandstype. Geaccepteerde typen: {{accept}}",
308
299
  "Invalid value for pattern \"{{pattern}}\"": "Ongeldige waarde voor patroon \"{{pattern}}\"",
309
300
  "Is active": "Is actief",
310
301
  "Is created in": "Is aangemaakt in",
@@ -518,7 +509,6 @@
518
509
  "Select rows": "Selecteer rijen",
519
510
  "Select sequence files": "Sequentiebestanden selecteren",
520
511
  "Selected": "Geselecteerd",
521
- "Selected files: {{numFiles}}": "Geselecteerde bestanden: {{numFiles}}",
522
512
  "selected rows": "geselecteerde rijen",
523
513
  "Selected rows": "Geselecteerde rijen",
524
514
  "Selected tree node ({{nodeName}})": "Geselecteerd boom knooppunt ({{nodeName}})",
@@ -589,7 +579,6 @@
589
579
  "This will navigate to the \"{{caseSetName}}\"-event. You will loose your current selection of cases and all applied filters. Do you want to continue?": "Dit navigeert naar de \"{{caseSetName}}\"-event. U verliest uw huidige selectie van casussen en alle toegepaste filters. Wilt u doorgaan?",
590
580
  "To Concept": "Naar Concept",
591
581
  "To Region": "Naar Regio",
592
- "Too many files selected. Maximum allowed: {{numFilesAllowed}}": "Te veel bestanden geselecteerd. Maximum toegestaan: {{numFilesAllowed}}",
593
582
  "Tree": "Boom",
594
583
  "Tree algorithm": "Boom algoritme",
595
584
  "Tree algorithm codes": "Boom algoritme codes",
@@ -3,12 +3,14 @@ import { CaseDbColType } from '@gen-epix/api-casedb';
3
3
  import { ConfigBase } from '@gen-epix/ui-client-common/models/config';
4
4
  import { Range } from 'colorjs.io';
5
5
  import { FieldValues } from 'react-hook-form';
6
+ import { ReactElement } from 'react';
6
7
  import { DashboardArrangement, DashboardArrangementWidgetAssignments, WidgetDataBase, WidgetsConfig } from './dashboard';
7
8
  export interface CaseDbConfig extends ConfigBase {
8
9
  dashboard: {
9
10
  ARRANGEMENT_OPTIONS: {
10
11
  [key: string]: DashboardArrangement;
11
12
  };
13
+ DASHBOARD_INJECTED_COMPONENT?: () => ReactElement;
12
14
  DEFAULT_ARRANGEMENT_KEY: string;
13
15
  DEFAULT_WIDGET_ASSIGNMENTS: {
14
16
  [key: string]: DashboardArrangementWidgetAssignments;
@@ -1,39 +1,39 @@
1
1
  import { h as e } from "../../_chunks/_MapCache.js";
2
2
  import { t } from "../../_chunks/noop.js";
3
3
  import { EffectiveRightsUtil as n } from "../../utils/EffectiveRightsUtil/index.js";
4
- import { c as r, o as i } from "../../_chunks/index.esm.js";
5
- import { t as a } from "../../_chunks/yup.js";
6
- import { useCaseTypeOptionsQuery as o } from "../../dataHooks/useCaseTypesQuery/index.js";
7
- import { useDataCollectionOptionsQuery as s } from "../../dataHooks/useDataCollectionsQuery/index.js";
8
- import { useCaseTypeSetMembersQuery as c } from "../../dataHooks/useCaseTypeSetMembersQuery/index.js";
9
- import { t as l } from "../../_chunks/chunk-BV7QT456.js";
10
- import { useColSetMembersQuery as u } from "../../dataHooks/useColSetMembersQuery/index.js";
11
- import { useOrganizationAccessCasePoliciesQuery as d } from "../../dataHooks/useOrganizationAccessCasePoliciesQuery/index.js";
12
- import { useOrganizationShareCasePoliciesQuery as f } from "../../dataHooks/useOrganizationShareCasePoliciesQuery/index.js";
13
- import { useUserAccessCasePoliciesQuery as p } from "../../dataHooks/useUserAccessCasePoliciesQuery/index.js";
14
- import { useUserShareCasePoliciesQuery as m } from "../../dataHooks/useUserShareCasePoliciesQuery/index.js";
15
- import { object as h, string as g } from "yup";
16
- import { CaseDbOrganizationApi as _ } from "@gen-epix/api-casedb";
17
- import { FORM_FIELD_DEFINITION_TYPE as v } from "@gen-epix/ui-core-form/models/form";
18
- import { COMMON_QUERY_KEY as y } from "@gen-epix/ui-client-common/constants/query";
19
- import { Box as b, Container as ee, Typography as x } from "@mui/material";
20
- import { useId as S, useMemo as C } from "react";
21
- import { useTranslation as w } from "react-i18next";
22
- import { jsx as T, jsxs as E } from "react/jsx-runtime";
23
- import { ResponseHandler as D } from "@gen-epix/ui-client-common/components/ui/ResponseHandler";
24
- import { useItemQuery as O } from "@gen-epix/ui-client-common/hooks/useItemQuery";
25
- import { useArray as k } from "@gen-epix/ui-core/hooks/useArray";
4
+ import { t as r } from "../../_chunks/yup.js";
5
+ import { useCaseTypeOptionsQuery as i } from "../../dataHooks/useCaseTypesQuery/index.js";
6
+ import { useDataCollectionOptionsQuery as a } from "../../dataHooks/useDataCollectionsQuery/index.js";
7
+ import { useCaseTypeSetMembersQuery as o } from "../../dataHooks/useCaseTypeSetMembersQuery/index.js";
8
+ import { t as s } from "../../_chunks/chunk-BV7QT456.js";
9
+ import { useColSetMembersQuery as c } from "../../dataHooks/useColSetMembersQuery/index.js";
10
+ import { useOrganizationAccessCasePoliciesQuery as l } from "../../dataHooks/useOrganizationAccessCasePoliciesQuery/index.js";
11
+ import { useOrganizationShareCasePoliciesQuery as u } from "../../dataHooks/useOrganizationShareCasePoliciesQuery/index.js";
12
+ import { useUserAccessCasePoliciesQuery as d } from "../../dataHooks/useUserAccessCasePoliciesQuery/index.js";
13
+ import { useUserShareCasePoliciesQuery as f } from "../../dataHooks/useUserShareCasePoliciesQuery/index.js";
14
+ import { object as p, string as m } from "yup";
15
+ import { CaseDbOrganizationApi as h } from "@gen-epix/api-casedb";
16
+ import { FORM_FIELD_DEFINITION_TYPE as g } from "@gen-epix/ui-core-form/models/form";
17
+ import { COMMON_QUERY_KEY as _ } from "@gen-epix/ui-client-common/constants/query";
18
+ import { Box as v, Container as y, Typography as b } from "@mui/material";
19
+ import { useId as ee, useMemo as x } from "react";
20
+ import { useTranslation as S } from "react-i18next";
21
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
22
+ import { ResponseHandler as T } from "@gen-epix/ui-client-common/components/ui/ResponseHandler";
23
+ import { useItemQuery as E } from "@gen-epix/ui-client-common/hooks/useItemQuery";
24
+ import { useArray as D } from "@gen-epix/ui-core/hooks/useArray";
25
+ import { useForm as O, useWatch as k } from "react-hook-form";
26
26
  import { GenericForm as A } from "@gen-epix/ui-core-form/components/helpers/GenericForm";
27
27
  import { TestIdUtil as j } from "@gen-epix/ui-core/utils/TestIdUtil";
28
28
  import { PageContainer as M } from "@gen-epix/ui-client-common/components/ui/PageContainer";
29
29
  import { useOrganizationMapQuery as N } from "@gen-epix/ui-client-common/dataHooks/useOrganizationsQuery";
30
30
  //#region src/pages/UserEffectiveRightsTesterAdminPage/UserEffectiveRightsTesterAdminPage.tsx
31
31
  var P = /* @__PURE__ */ e(t(), 1), F = () => {
32
- let { t: e } = w(), t = S(), { userId: F } = l(), I = O({
33
- baseQueryKey: y.USERS,
32
+ let { t: e } = S(), t = ee(), { userId: F } = s(), I = E({
33
+ baseQueryKey: _.USERS,
34
34
  itemId: F,
35
- useQueryOptions: { queryFn: async ({ signal: e }) => (await _.getInstance().usersGetOne(F, { signal: e })).data }
36
- }), L = u(), R = o(), z = N(), B = c(), V = s(), H = d((e) => e.filter((e) => e.is_active && e.organization_id === I.data?.organization_id)), U = f((e) => e.filter((e) => e.is_active && e.organization_id === I.data?.organization_id)), W = p((e) => e.filter((e) => e.is_active && e.user_id === I.data?.id)), G = m((e) => e.filter((e) => e.is_active && e.user_id === I.data?.id)), K = k([
35
+ useQueryOptions: { queryFn: async ({ signal: e }) => (await h.getInstance().usersGetOne(F, { signal: e })).data }
36
+ }), L = c(), R = i(), z = N(), B = o(), V = a(), H = l((e) => e.filter((e) => e.is_active && e.organization_id === I.data?.organization_id)), U = u((e) => e.filter((e) => e.is_active && e.organization_id === I.data?.organization_id)), W = d((e) => e.filter((e) => e.is_active && e.user_id === I.data?.id)), G = f((e) => e.filter((e) => e.is_active && e.user_id === I.data?.id)), K = D([
37
37
  I,
38
38
  L,
39
39
  R,
@@ -44,7 +44,7 @@ var P = /* @__PURE__ */ e(t(), 1), F = () => {
44
44
  W,
45
45
  G,
46
46
  z
47
- ]), q = C(() => {
47
+ ]), q = x(() => {
48
48
  let { data: e } = H, { data: t } = U, { data: r } = W, { data: i } = G, { data: a } = B, { data: o } = L;
49
49
  return n.assembleUserEffectiveRights({
50
50
  caseTypeSetMembers: a,
@@ -63,18 +63,18 @@ var P = /* @__PURE__ */ e(t(), 1), F = () => {
63
63
  W,
64
64
  I.data,
65
65
  G
66
- ]), J = C(() => h().shape({
67
- caseTypeId: g().uuid4().required(),
68
- dataCollectionId: g().uuid4().required(),
69
- fromDataCollectionId: g().uuid4().nullable().notRequired()
70
- }), []), Y = i({
71
- resolver: a(J),
66
+ ]), J = x(() => p().shape({
67
+ caseTypeId: m().uuid4().required(),
68
+ dataCollectionId: m().uuid4().required(),
69
+ fromDataCollectionId: m().uuid4().nullable().notRequired()
70
+ }), []), Y = O({
71
+ resolver: r(J),
72
72
  values: {
73
73
  caseTypeId: null,
74
74
  dataCollectionId: null,
75
75
  fromDataCollectionId: null
76
76
  }
77
- }), { control: X, handleSubmit: Z } = Y, Q = r({ control: X }), $ = C(() => {
77
+ }), { control: X, handleSubmit: Z } = Y, Q = k({ control: X }), $ = x(() => {
78
78
  if (!Q.caseTypeId || !Q.dataCollectionId) return null;
79
79
  let e = q.find((e) => e.data_collection_id === Q.dataCollectionId && e.categorized_case_type_ids.some((e) => e === Q.caseTypeId)), t = Q.fromDataCollectionId && e?.effective_share_case_rights?.find((e) => e.categorized_case_type_ids.some((e) => e === Q.caseTypeId) && e.from_data_collection_id === Q.fromDataCollectionId);
80
80
  return {
@@ -93,23 +93,23 @@ var P = /* @__PURE__ */ e(t(), 1), F = () => {
93
93
  Q.caseTypeId,
94
94
  Q.dataCollectionId,
95
95
  Q.fromDataCollectionId
96
- ]), te = C(() => [
96
+ ]), te = x(() => [
97
97
  {
98
- definition: v.AUTOCOMPLETE,
98
+ definition: g.AUTOCOMPLETE,
99
99
  label: e`Case type`,
100
100
  loading: R.isLoading,
101
101
  name: "caseTypeId",
102
102
  options: R.options
103
103
  },
104
104
  {
105
- definition: v.AUTOCOMPLETE,
105
+ definition: g.AUTOCOMPLETE,
106
106
  label: e`Data collection`,
107
107
  loading: V.isLoading,
108
108
  name: "dataCollectionId",
109
109
  options: V.options
110
110
  },
111
111
  {
112
- definition: v.AUTOCOMPLETE,
112
+ definition: g.AUTOCOMPLETE,
113
113
  disabled: !$?.has_share_case_rights,
114
114
  label: e`From data collection`,
115
115
  loading: V.isLoading,
@@ -124,63 +124,63 @@ var P = /* @__PURE__ */ e(t(), 1), F = () => {
124
124
  $?.has_share_case_rights,
125
125
  e
126
126
  ]);
127
- return /* @__PURE__ */ T(M, {
127
+ return /* @__PURE__ */ C(M, {
128
128
  fullWidth: !0,
129
129
  showBreadcrumbs: !0,
130
130
  testIdAttributes: j.createAttributes("UserEffectiveRightsTesterAdminPage"),
131
131
  title: e`Users effective rights`,
132
- children: /* @__PURE__ */ T(b, {
132
+ children: /* @__PURE__ */ C(v, {
133
133
  sx: {
134
134
  height: "100%",
135
135
  position: "relative"
136
136
  },
137
- children: /* @__PURE__ */ T(D, {
137
+ children: /* @__PURE__ */ C(T, {
138
138
  inlineSpinner: !0,
139
139
  loadables: K,
140
- children: /* @__PURE__ */ E(ee, {
140
+ children: /* @__PURE__ */ w(y, {
141
141
  maxWidth: "md",
142
142
  children: [
143
- /* @__PURE__ */ E(b, {
143
+ /* @__PURE__ */ w(v, {
144
144
  sx: { marginY: 2 },
145
145
  children: [
146
- /* @__PURE__ */ T(x, {
146
+ /* @__PURE__ */ C(b, {
147
147
  component: "h2",
148
148
  variant: "h4",
149
149
  children: e("Testing effective rights for user: {{userEmail}}", { userEmail: I.data?.email })
150
150
  }),
151
- /* @__PURE__ */ T(x, { children: e("Organization: {{organizationName}}", { organizationName: z.map.get(I.data?.organization_id)?.name }) }),
152
- /* @__PURE__ */ T(x, { children: e("Roles: {{roles}}", { roles: I.data?.roles.join(", ") }) })
151
+ /* @__PURE__ */ C(b, { children: e("Organization: {{organizationName}}", { organizationName: z.map.get(I.data?.organization_id)?.name }) }),
152
+ /* @__PURE__ */ C(b, { children: e("Roles: {{roles}}", { roles: I.data?.roles.join(", ") }) })
153
153
  ]
154
154
  }),
155
- /* @__PURE__ */ T(A, {
155
+ /* @__PURE__ */ C(A, {
156
156
  formFieldDefinitions: te,
157
157
  formId: t,
158
158
  formMethods: Y,
159
159
  onSubmit: Z(P.default),
160
160
  schema: J
161
161
  }),
162
- typeof $ == "object" && !!$ && /* @__PURE__ */ E(b, {
162
+ typeof $ == "object" && !!$ && /* @__PURE__ */ w(v, {
163
163
  sx: { marginY: 2 },
164
164
  children: [
165
- /* @__PURE__ */ T(x, {
165
+ /* @__PURE__ */ C(b, {
166
166
  variant: "h6",
167
167
  children: e("Effective rights result:")
168
168
  }),
169
- !Q.fromDataCollectionId && $.has_share_case_rights && /* @__PURE__ */ T(b, {
169
+ !Q.fromDataCollectionId && $.has_share_case_rights && /* @__PURE__ */ C(v, {
170
170
  sx: { marginY: 2 },
171
- children: /* @__PURE__ */ T(x, {
171
+ children: /* @__PURE__ */ C(b, {
172
172
  sx: { fontStyle: "italic" },
173
173
  children: e`Note: The user has share case rights that may affect the result when a 'From data collection' is selected.`
174
174
  })
175
175
  }),
176
- /* @__PURE__ */ T(x, { children: e("Add case: {{addCase}}", { addCase: $?.add_case ? e`Yes` : e`No` }) }),
177
- /* @__PURE__ */ T(x, { children: e("Remove case: {{removeCase}}", { removeCase: $?.remove_case ? e`Yes` : e`No` }) }),
178
- /* @__PURE__ */ T(x, { children: e("Add case set: {{addCaseSet}}", { addCaseSet: $?.add_case_set ? e`Yes` : e`No` }) }),
179
- /* @__PURE__ */ T(x, { children: e("Remove case set: {{removeCaseSet}}", { removeCaseSet: $?.remove_case_set ? e`Yes` : e`No` }) }),
180
- /* @__PURE__ */ T(x, { children: e("Read case set: {{readCaseSet}}", { readCaseSet: $?.read_case_set ? e`Yes` : e`No` }) }),
181
- /* @__PURE__ */ T(x, { children: e("Write case set: {{writeCaseSet}}", { writeCaseSet: $?.write_case_set ? e`Yes` : e`No` }) }),
182
- /* @__PURE__ */ T(x, { children: e("Read case properties: {{readSomeProperties}}", { readSomeProperties: $?.read_col_ids?.length > 0 ? e`Yes` : e`No` }) }),
183
- /* @__PURE__ */ T(x, { children: e("Write case properties: {{writeSomeProperties}}", { writeSomeProperties: $?.write_col_ids?.length > 0 ? e`Yes` : e`No` }) })
176
+ /* @__PURE__ */ C(b, { children: e("Add case: {{addCase}}", { addCase: $?.add_case ? e`Yes` : e`No` }) }),
177
+ /* @__PURE__ */ C(b, { children: e("Remove case: {{removeCase}}", { removeCase: $?.remove_case ? e`Yes` : e`No` }) }),
178
+ /* @__PURE__ */ C(b, { children: e("Add case set: {{addCaseSet}}", { addCaseSet: $?.add_case_set ? e`Yes` : e`No` }) }),
179
+ /* @__PURE__ */ C(b, { children: e("Remove case set: {{removeCaseSet}}", { removeCaseSet: $?.remove_case_set ? e`Yes` : e`No` }) }),
180
+ /* @__PURE__ */ C(b, { children: e("Read case set: {{readCaseSet}}", { readCaseSet: $?.read_case_set ? e`Yes` : e`No` }) }),
181
+ /* @__PURE__ */ C(b, { children: e("Write case set: {{writeCaseSet}}", { writeCaseSet: $?.write_case_set ? e`Yes` : e`No` }) }),
182
+ /* @__PURE__ */ C(b, { children: e("Read case properties: {{readSomeProperties}}", { readSomeProperties: $?.read_col_ids?.length > 0 ? e`Yes` : e`No` }) }),
183
+ /* @__PURE__ */ C(b, { children: e("Write case properties: {{writeSomeProperties}}", { writeSomeProperties: $?.write_col_ids?.length > 0 ? e`Yes` : e`No` }) })
184
184
  ]
185
185
  })
186
186
  ]