@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.
- package/dist/_chunks/AddCasesToEventDialog.js +98 -98
- package/dist/_chunks/AddCasesToEventDialog.js.map +1 -1
- package/dist/_chunks/CaseContentForm.js +10 -10
- package/dist/_chunks/CaseDbDownloadUtil.js +1 -1
- package/dist/_chunks/CaseDbDownloadUtil.js.map +1 -1
- package/dist/_chunks/CaseInfoDialog.js +222 -222
- package/dist/_chunks/CaseInfoDialog.js.map +1 -1
- package/dist/_chunks/CaseSetInfoDialog.js +222 -222
- package/dist/_chunks/CaseSetInfoDialog.js.map +1 -1
- package/dist/_chunks/CasesAlreadyInCaseSetWarning.js.map +1 -1
- package/dist/_chunks/Dashboard.js +296 -295
- package/dist/_chunks/Dashboard.js.map +1 -1
- package/dist/_chunks/FindSimilarCasesDialog.js +81 -81
- package/dist/_chunks/FindSimilarCasesDialog.js.map +1 -1
- package/dist/_chunks/HomePageTrends.js.map +1 -1
- package/dist/_chunks/LegendaItem.js.map +1 -1
- package/dist/_chunks/LineListWidget.js +46 -45
- package/dist/_chunks/LineListWidget.js.map +1 -1
- package/dist/_chunks/PanelSeparator.js +3 -3
- package/dist/_chunks/PanelSeparator.js.map +1 -1
- package/dist/_chunks/Upload.js +422 -418
- package/dist/_chunks/Upload.js.map +1 -1
- package/dist/_chunks/UploadUtil.js +44 -40
- package/dist/_chunks/UploadUtil.js.map +1 -1
- package/dist/_chunks/chunk-BV7QT456.js +1 -1
- package/dist/_chunks/chunk-BV7QT456.js.map +1 -1
- package/dist/_chunks/cloneDeep.js +1 -1
- package/dist/_chunks/cloneDeep.js.map +1 -1
- package/dist/_chunks/dashboardStore.js.map +1 -1
- package/dist/_chunks/esm.js +3 -3
- package/dist/_chunks/esm.js.map +1 -1
- package/dist/_chunks/index.module.js +1 -1
- package/dist/_chunks/index.module.js.map +1 -1
- package/dist/_chunks/react.js +1 -1
- package/dist/_chunks/react.js.map +1 -1
- package/dist/_chunks/shallow.js +2 -2
- package/dist/_chunks/shallow.js.map +1 -1
- package/dist/_chunks/vanilla.js +1 -1
- package/dist/_chunks/vanilla.js.map +1 -1
- package/dist/_chunks/yup.js +24 -24
- package/dist/_chunks/yup.js.map +1 -1
- package/dist/classes/services/EventBusService/EventBusService.d.ts +9 -2
- package/dist/classes/services/EventBusService/index.js.map +1 -1
- package/dist/components/form/fields/ArrangementEditor/index.js +30 -30
- package/dist/components/ui/CreateEventDialog/index.js +40 -40
- package/dist/components/ui/CreateEventDialog/index.js.map +1 -1
- package/dist/components/ui/MapWidget/index.js.map +1 -1
- package/dist/components/ui/RemoveCasesFromEventDialog/index.js.map +1 -1
- package/dist/components/ui/SequenceDownloadDialog/index.js +57 -44
- package/dist/components/ui/SequenceDownloadDialog/index.js.map +1 -1
- package/dist/components/ui/TreeWidget/index.js +8 -2
- package/dist/components/ui/TreeWidget/index.js.map +1 -1
- package/dist/locale/en.json +0 -11
- package/dist/locale/nl.json +0 -11
- package/dist/models/config.d.ts +2 -0
- package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js +59 -59
- package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js.map +1 -1
- package/dist/utils/UploadUtil/UploadUtil.d.ts +1 -0
- package/package.json +68 -75
- package/dist/_chunks/index.esm.js +0 -1465
- package/dist/_chunks/index.esm.js.map +0 -1
- package/dist/components/ui/FileSelector/FileSelector.d.ts +0 -7
- package/dist/components/ui/FileSelector/index.d.ts +0 -1
- package/dist/components/ui/FileSelector/index.js +0 -206
- package/dist/components/ui/FileSelector/index.js.map +0 -1
- package/dist/utils/FileUtil/FileUtil.d.ts +0 -5
- package/dist/utils/FileUtil/index.d.ts +0 -1
- package/dist/utils/FileUtil/index.js +0 -15
- 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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"}
|
package/dist/locale/en.json
CHANGED
|
@@ -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",
|
package/dist/locale/nl.json
CHANGED
|
@@ -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",
|
package/dist/models/config.d.ts
CHANGED
|
@@ -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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
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 } =
|
|
33
|
-
baseQueryKey:
|
|
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
|
|
36
|
-
}), L =
|
|
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 =
|
|
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 =
|
|
67
|
-
caseTypeId:
|
|
68
|
-
dataCollectionId:
|
|
69
|
-
fromDataCollectionId:
|
|
70
|
-
}), []), Y =
|
|
71
|
-
resolver:
|
|
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 =
|
|
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 =
|
|
96
|
+
]), te = x(() => [
|
|
97
97
|
{
|
|
98
|
-
definition:
|
|
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:
|
|
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:
|
|
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__ */
|
|
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__ */
|
|
132
|
+
children: /* @__PURE__ */ C(v, {
|
|
133
133
|
sx: {
|
|
134
134
|
height: "100%",
|
|
135
135
|
position: "relative"
|
|
136
136
|
},
|
|
137
|
-
children: /* @__PURE__ */ T
|
|
137
|
+
children: /* @__PURE__ */ C(T, {
|
|
138
138
|
inlineSpinner: !0,
|
|
139
139
|
loadables: K,
|
|
140
|
-
children: /* @__PURE__ */
|
|
140
|
+
children: /* @__PURE__ */ w(y, {
|
|
141
141
|
maxWidth: "md",
|
|
142
142
|
children: [
|
|
143
|
-
/* @__PURE__ */
|
|
143
|
+
/* @__PURE__ */ w(v, {
|
|
144
144
|
sx: { marginY: 2 },
|
|
145
145
|
children: [
|
|
146
|
-
/* @__PURE__ */
|
|
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__ */
|
|
152
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
162
|
+
typeof $ == "object" && !!$ && /* @__PURE__ */ w(v, {
|
|
163
163
|
sx: { marginY: 2 },
|
|
164
164
|
children: [
|
|
165
|
-
/* @__PURE__ */
|
|
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__ */
|
|
169
|
+
!Q.fromDataCollectionId && $.has_share_case_rights && /* @__PURE__ */ C(v, {
|
|
170
170
|
sx: { marginY: 2 },
|
|
171
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
177
|
-
/* @__PURE__ */
|
|
178
|
-
/* @__PURE__ */
|
|
179
|
-
/* @__PURE__ */
|
|
180
|
-
/* @__PURE__ */
|
|
181
|
-
/* @__PURE__ */
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */
|
|
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
|
]
|