From d455612e758ea3192d982da6ff2d04277ea807fd Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Mon, 2 Nov 2026 17:54:49 +0530 Subject: [PATCH 1/3] OpenConceptLab/ocl_issues#2986 | Keep the Mapper project header on one row at narrow widths --- src/components/map-projects/Controls.jsx | 94 ++++++++++++++----- src/components/map-projects/MapProject.jsx | 22 +---- .../__tests__/controlsLayout.test.js | 23 +++++ src/components/map-projects/controlsLayout.js | 40 ++++++++ 4 files changed, 139 insertions(+), 40 deletions(-) diff --git a/src/components/map-projects/Controls.jsx b/src/components/map-projects/Controls.jsx index 89562124..11e70f69 100644 --- a/src/components/map-projects/Controls.jsx +++ b/src/components/map-projects/Controls.jsx @@ -10,6 +10,8 @@ import Menu from '@mui/material/Menu'; import Divider from '@mui/material/Divider'; import ListItemIcon from '@mui/material/ListItemIcon'; import CircularProgress from '@mui/material/CircularProgress' +import DoubleArrowIcon from '@mui/icons-material/DoubleArrow'; +import AutoMatchIcon from '@mui/icons-material/MotionPhotosAutoOutlined'; import DownloadIcon from '@mui/icons-material/Download'; import TimelineIcon from '@mui/icons-material/Timeline'; import SettingsIcon from '@mui/icons-material/Settings'; @@ -20,7 +22,7 @@ import JSONIcon from '@mui/icons-material/DataObject'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import { copyToClipboard } from '../../common/utils' import RepoIcon from '../repos/RepoIcon' -import { splitSecondaryActionsByVisibility } from './controlsLayout' +import { getToolbarLayout, HEADER_RESERVED_WIDTH } from './controlsLayout' const IkonButton = ({title, icon, onClick, color, disabled, id}) => { return ( @@ -42,7 +44,7 @@ const IkonButton = ({title, icon, onClick, color, disabled, id}) => { ) } -const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, onImport, importResponse, onDownloadImportReport, onProjectLogsClick, isProjectsLogOpen, configure, setConfigure, isCoreUser, loadingMatches, onCopyClick}) => { +const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, onImport, importResponse, onDownloadImportReport, onProjectLogsClick, isProjectsLogOpen, configure, setConfigure, isCoreUser, loadingMatches, onCopyClick, autoMatch}) => { const { t } = useTranslation(); const toolbarRef = React.useRef(null) const overflowButtonRef = React.useRef(null) @@ -56,12 +58,12 @@ const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, const hasPersistentOverflowActions = Boolean(project?.id) React.useEffect(() => { - const node = toolbarRef.current + const node = toolbarRef.current?.parentElement if (!node) return undefined const updateToolbarWidth = () => { const nextWidth = node.getBoundingClientRect?.().width - setToolbarWidth(nextWidth || Number.POSITIVE_INFINITY) + setToolbarWidth(nextWidth ? nextWidth - HEADER_RESERVED_WIDTH : Number.POSITIVE_INFINITY) } updateToolbarWidth() @@ -110,14 +112,24 @@ const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, } } - const { overflowActionKeys, visibleActionKeys } = splitSecondaryActionsByVisibility({ - toolbarWidth, - hasOverflowItems: hasPersistentOverflowActions - }) + const hasActions = Boolean(file?.name) + const { autoMatch: autoMatchMode, saveInMenu, overflowActionKeys, visibleActionKeys } = hasActions ? + getToolbarLayout({ + toolbarWidth, + hasOverflowItems: hasPersistentOverflowActions, + hasAutoMatch: Boolean(autoMatch) + }) : + {autoMatch: 'full', saveInMenu: false, overflowActionKeys: [], visibleActionKeys: []} const visibleSecondaryActions = visibleActionKeys.map(key => actionsByKey[key]) const overflowSecondaryActions = overflowActionKeys.map(key => actionsByKey[key]) - const hasOverflowActions = hasPersistentOverflowActions || overflowSecondaryActions.length > 0 + const autoMatchInMenu = Boolean(autoMatch) && autoMatchMode === 'menu' + const hasOverflowActions = hasActions && (hasPersistentOverflowActions || overflowSecondaryActions.length > 0 || saveInMenu || autoMatchInMenu) + const overflowMenuActions = [ + ...(autoMatchInMenu ? [{key: 'autoMatch', icon: , title: autoMatch.label, disabled: autoMatch.disabled || autoMatch.loading, onClick: autoMatch.onClick}] : []), + ...overflowSecondaryActions, + ...(saveInMenu ? [actionsByKey.save] : []) + ] const closeDownloadMenu = () => setDownloadAnchorEl(null) const closeOverflowMenu = () => setOverflowAnchorEl(null) @@ -134,8 +146,43 @@ const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, } return ( - -
+ +
+ { + autoMatch && !autoMatchInMenu && (autoMatchMode === 'compact' ? + + + + {autoMatch.loading ? : } + + + : + + ) + } + { + autoMatch && !autoMatchInMenu && hasActions && + + } { visibleSecondaryActions.map(action => ( 0 && } - + { + hasActions && !saveInMenu && + + } { hasOverflowActions && <> - + {!saveInMenu && } { (lastSavedText || isSaving) && -
+
{ isSaving ? t('map_project.saving') : t('map_project.last_saved', {time: lastSavedText}) @@ -266,7 +316,7 @@ const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, transformOrigin={{ vertical: 'top', horizontal: 'right' }} > { - overflowSecondaryActions.map(action => ( + overflowMenuActions.map(action => ( {action.icon} {action.title} @@ -274,7 +324,7 @@ const Controls = ({project, onDownload, onSave, onDelete, owner, file, isSaving, )) } { - overflowSecondaryActions.length > 0 && project?.id && + overflowMenuActions.length > 0 && project?.id && } { diff --git a/src/components/map-projects/MapProject.jsx b/src/components/map-projects/MapProject.jsx index 3f92f9c4..2855e7c9 100644 --- a/src/components/map-projects/MapProject.jsx +++ b/src/components/map-projects/MapProject.jsx @@ -30,10 +30,8 @@ import Snackbar from '@mui/material/Snackbar'; import { DataGrid, GRID_CHECKBOX_SELECTION_COL_DEF } from '@mui/x-data-grid'; -import DoubleArrowIcon from '@mui/icons-material/DoubleArrow'; import DoneIcon from '@mui/icons-material/Done'; import CloseIcon from '@mui/icons-material/Close'; -import AutoMatchIcon from '@mui/icons-material/MotionPhotosAutoOutlined'; import ClearIcon from '@mui/icons-material/Clear'; import AssistantIcon from '@mui/icons-material/Assistant'; import PendingIcon from '@mui/icons-material/HourglassBottom'; @@ -6345,30 +6343,17 @@ const MapProject = () => {
{ !isConfigFormInline && - + { name && - + {name} } - { scispacyCandidatesStartedAt &&