Improve width of expanded sections in EntityDataTable. (#25290)

* Improove width of expanded sections by using with of scroll cotnainer instead of table width.

* Fixing issue with broken styling.

* Fixing filter spacing issue.
This commit is contained in:
Linus Pahl
2026-03-12 11:01:42 +01:00
committed by GitHub
parent e6e1e64c20
commit e9ec5d9829
5 changed files with 96 additions and 59 deletions

View File

@@ -21,3 +21,4 @@ export const columnOpacityVar = (colId: string) => `--col-${colId}-opacity`;
export const columnTransition = () => `--col-transition`;
export const actionsHeaderWidthVar = `--actions-header-width`;
export const displayScrollRightIndicatorVar = `--display-scroll-right-indicator`;
export const scrollContainerWidthVar = `--scroll-container-width`;

View File

@@ -37,6 +37,7 @@ import {
columnTransformVar,
columnWidthVar,
displayScrollRightIndicatorVar,
scrollContainerWidthVar,
} from 'components/common/EntityDataTable/CSSVariables';
import useHeaderMinWidths from 'components/common/EntityDataTable/hooks/useHeaderMinWidths';
import useColumnDefinitions from 'components/common/EntityDataTable/hooks/useColumnDefinitions';
@@ -60,20 +61,30 @@ const ScrollContainer = styled.div<{
$columnTransform: { [_attributeId: string]: string };
$actionsHeaderWidth: number;
$canScrollRight: boolean;
$scrollContainerWidth: number;
}>(
({ $columnWidths, $activeColId, $columnTransform, $actionsHeaderWidth, $canScrollRight }) => css`
({
$columnWidths,
$activeColId,
$columnTransform,
$actionsHeaderWidth,
$canScrollRight,
$scrollContainerWidth,
}) => css`
width: 100%;
overflow-x: auto;
${Object.entries($columnWidths).map(([id, width]) => cssVariable(columnWidthVar(id), `${width}px`))}
${Object.entries($columnTransform).map(([id, transform]) => cssVariable(columnTransformVar(id), transform))}
${$actionsHeaderWidth && cssVariable(actionsHeaderWidthVar, `${$actionsHeaderWidth}px`)}
${$canScrollRight && cssVariable(displayScrollRightIndicatorVar, 'block')}
${$activeColId &&
css`
${cssVariable(columnOpacityVar($activeColId), 0.4)}
${cssVariable(columnTransition(), 'transform 0.2s ease-in-out')}
`}
${$actionsHeaderWidth ? cssVariable(actionsHeaderWidthVar, `${$actionsHeaderWidth}px`) : ''}
${$canScrollRight ? cssVariable(displayScrollRightIndicatorVar, 'block') : ''}
${$scrollContainerWidth ? cssVariable(scrollContainerWidthVar, `${$scrollContainerWidth}px`) : ''}
${$activeColId
? css`
${cssVariable(columnOpacityVar($activeColId), 0.4)}
${cssVariable(columnTransition(), 'transform 0.2s ease-in-out')}
`
: ''}
`,
);
@@ -229,20 +240,18 @@ const EntityDataTable = <Entity extends EntityBase, Meta = unknown>({
displayBulkSelectCol,
);
const { columnWidths, handleActionsWidthChange, tableIsCompressed, actionsColMinWidth } = useElementWidths<
Entity,
Meta
>({
columnRenderersByAttribute,
columnSchemas: authorizedColumnSchemas,
columnWidthPreferences: internalColumnWidthPreferences,
displayBulkSelectCol,
entities,
hasRowActions,
headerMinWidths,
scrollContainerRef,
visibleColumns: columnOrder,
});
const { columnWidths, handleActionsWidthChange, tableIsCompressed, actionsColMinWidth, scrollContainerWidth } =
useElementWidths<Entity, Meta>({
columnRenderersByAttribute,
columnSchemas: authorizedColumnSchemas,
columnWidthPreferences: internalColumnWidthPreferences,
displayBulkSelectCol,
entities,
hasRowActions,
headerMinWidths,
scrollContainerRef,
visibleColumns: columnOrder,
});
const columnDefinitions = useColumnDefinitions<Entity, Meta>({
actionsColMinWidth,
@@ -324,7 +333,8 @@ const EntityDataTable = <Entity extends EntityBase, Meta = unknown>({
$activeColId={activeColId}
$columnTransform={columnTransform}
$columnWidths={columnWidths}
$canScrollRight={scrolledToRight && tableIsCompressed}>
$canScrollRight={scrolledToRight && tableIsCompressed}
$scrollContainerWidth={scrollContainerWidth}>
<InnerContainer>
<Table<Entity>
expandedSectionRenderers={expandedSectionRenderers}

View File

@@ -20,6 +20,8 @@ import styled, { css } from 'styled-components';
import IconButton from 'components/common/IconButton';
import { ButtonToolbar } from 'components/bootstrap';
import { CELL_PADDING } from 'components/common/EntityDataTable/Constants';
import { scrollContainerWidthVar } from 'components/common/EntityDataTable/CSSVariables';
import type { EntityBase, ExpandedSectionRenderers } from './types';
import ExpandedEntitiesSectionsContext from './contexts/ExpandedSectionsContext';
@@ -32,6 +34,20 @@ const Container = styled.tr(
`,
);
const ContentCell = styled.td`
&& {
padding: 0;
}
`;
const Content = styled.div`
position: sticky;
left: 0;
width: 100%;
max-width: var(${scrollContainerWidthVar}, 100%);
padding: ${CELL_PADDING}px;
`;
const Header = styled.div`
display: flex;
justify-content: space-between;
@@ -63,29 +79,31 @@ const ExpandedSections = <Entity extends EntityBase>({
return (
<Container>
<td colSpan={1000}>
{Object.entries(expandedSectionRenderers ?? {})
.filter(([sectionName]) => expandedEntitySections.includes(sectionName))
.map(([sectionName, section]) => {
const hideSection = () => toggleSection(entity.id, sectionName);
const actions = section.actions?.(entity);
<ContentCell colSpan={1000}>
<Content>
{Object.entries(expandedSectionRenderers ?? {})
.filter(([sectionName]) => expandedEntitySections.includes(sectionName))
.map(([sectionName, section]) => {
const hideSection = () => toggleSection(entity.id, sectionName);
const actions = section.actions?.(entity);
return (
<div key={`${sectionName}-${entity.id}`}>
{section.disableHeader !== true ? (
<Header>
<h3>{section.title}</h3>
<Actions>
{actions}
<HideSectionButton name="close" onClick={hideSection} title="Hide section" />
</Actions>
</Header>
) : null}
{section.content(entity)}
</div>
);
})}
</td>
return (
<div key={`${sectionName}-${entity.id}`}>
{section.disableHeader !== true ? (
<Header>
<h3>{section.title}</h3>
<Actions>
{actions}
<HideSectionButton name="close" onClick={hideSection} title="Hide section" />
</Actions>
</Header>
) : null}
{section.content(entity)}
</div>
);
})}
</Content>
</ContentCell>
</Container>
);
};

View File

@@ -69,6 +69,7 @@ const useElementWidths = <Entity extends EntityBase, Meta>({
columnWidths,
tableIsCompressed: actionsColMinWidth === columnWidths[ACTIONS_COL_ID],
actionsColMinWidth,
scrollContainerWidth,
};
};

View File

@@ -15,7 +15,7 @@
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import React from 'react';
import styled from 'styled-components';
import styled, { css } from 'styled-components';
import type { Filters, Filter } from 'components/common/EntityFilters/types';
import type { Attributes } from 'stores/PaginationTypes';
@@ -23,20 +23,27 @@ import ActiveFilter from 'components/common/EntityFilters/ActiveFilter';
import HoverForHelp from 'components/common/HoverForHelp';
import { ROW_MIN_HEIGHT } from 'components/common/EntityFilters/Constants';
const FilterGroup = styled.div`
display: inline-flex;
align-items: center;
min-height: ${ROW_MIN_HEIGHT}px;
gap: 3px;
flex-wrap: wrap;
`;
const FilterGroup = styled.div(
({ theme }) => css`
display: inline-flex;
align-items: center;
min-height: ${ROW_MIN_HEIGHT}px;
gap: ${theme.spacings.xxs};
flex-wrap: wrap;
const FilterGroupTitle = styled.div`
display: inline-flex;
align-items: center;
gap: 3px;
margin-right: 3px;
`;
&:not(:last-child) {
margin-right: ${theme.spacings.xs};
}
`,
);
const FilterGroupTitle = styled.div(
({ theme }) => css`
display: inline-flex;
align-items: center;
gap: ${theme.spacings.xxs};
`,
);
const SLICE_FILTER_CONFLICT_HELP =
'This filter is ignored because a slice is active for this attribute. Clear the slice to apply the filter.';