mirror of
https://github.com/Graylog2/graylog2-server.git
synced 2026-03-13 09:32:21 +08:00
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:
@@ -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`;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -69,6 +69,7 @@ const useElementWidths = <Entity extends EntityBase, Meta>({
|
||||
columnWidths,
|
||||
tableIsCompressed: actionsColMinWidth === columnWidths[ACTIONS_COL_ID],
|
||||
actionsColMinWidth,
|
||||
scrollContainerWidth,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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.';
|
||||
|
||||
Reference in New Issue
Block a user