diff --git a/front/src/modules/ui/table/components/ColumnHead.tsx b/front/src/modules/ui/table/components/ColumnHead.tsx
index 4a3b3d58559e..5f55b49f5719 100644
--- a/front/src/modules/ui/table/components/ColumnHead.tsx
+++ b/front/src/modules/ui/table/components/ColumnHead.tsx
@@ -13,6 +13,7 @@ const StyledTitle = styled.div`
font-weight: ${({ theme }) => theme.font.weight.medium};
height: ${({ theme }) => theme.spacing(8)};
padding-left: ${({ theme }) => theme.spacing(2)};
+ padding-right: ${({ theme }) => theme.spacing(2)};
`;
const StyledIcon = styled.div`
@@ -20,11 +21,17 @@ const StyledIcon = styled.div`
margin-right: ${({ theme }) => theme.spacing(1)};
`;
+const StyledText = styled.span`
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+`;
+
export function ColumnHead({ viewName, viewIcon }: OwnProps) {
return (
{viewIcon}
- {viewName}
+ {viewName}
);
}
diff --git a/front/src/modules/ui/table/components/EntityTableHeader.tsx b/front/src/modules/ui/table/components/EntityTableHeader.tsx
index 292962fea1b4..a9025b47817b 100644
--- a/front/src/modules/ui/table/components/EntityTableHeader.tsx
+++ b/front/src/modules/ui/table/components/EntityTableHeader.tsx
@@ -1,13 +1,91 @@
+import { DragEvent, useCallback, useRef, useState } from 'react';
+import styled from '@emotion/styled';
+
import { TableColumn } from '@/people/table/components/peopleColumns';
import { ColumnHead } from './ColumnHead';
import { SelectAllCheckbox } from './SelectAllCheckbox';
+const COLUMN_MIN_WIDTH = 75;
+
+const StyledColumnHeaderCell = styled.th<{ isResizing?: boolean }>`
+ min-width: ${COLUMN_MIN_WIDTH}px;
+ position: relative;
+
+ ${(props) =>
+ props.isResizing
+ ? `&:after {
+ background-color: ${props.theme.color.blue};
+ bottom: 0;
+ content: '';
+ display: block;
+ position: absolute;
+ right: -1.5px;
+ top: 0;
+ width: 2px;
+ }`
+ : ''}
+`;
+
+const StyledResizeHandler = styled.div`
+ bottom: 0;
+ cursor: col-resize;
+ padding: 0 ${({ theme }) => theme.spacing(2)};
+ position: absolute;
+ right: -9px;
+ top: 0;
+ width: 1px;
+ z-index: 1;
+`;
+
export function EntityTableHeader({
columns,
}: {
columns: Array;
}) {
+ const [columnWidths, setColumnWidths] = useState(
+ columns.reduce>(
+ (result, column) => ({ ...result, [column.id]: column.size }),
+ {},
+ ),
+ );
+ const [offset, setOffset] = useState(0);
+ const resizedColumnId = useRef('');
+ const initialHandlerPosition = useRef(-1);
+
+ const handleResizeHandlerDragStart = useCallback(
+ (event: DragEvent, columnId: string) => {
+ resizedColumnId.current = columnId;
+ initialHandlerPosition.current = event.clientX;
+ },
+ [],
+ );
+
+ const handleResizeHandlerDrag = useCallback(
+ (event: DragEvent) => {
+ // @see https://stackoverflow.com/q/36308460
+ // `event.screenX === 0` allows to detect the last "drag" event
+ // which is emitted on mouse release.
+ // On this last "drag" event, `event.clientX` is reset to an incorrect value
+ // which does not reflect the handler's position, so we ignore it.
+ if (event.screenX === 0) return;
+
+ setOffset(event.clientX - initialHandlerPosition.current);
+ },
+ [],
+ );
+
+ const handleResizeHandlerDragEnd = useCallback(() => {
+ setColumnWidths((previousColumnWidths) => ({
+ ...previousColumnWidths,
+ [resizedColumnId.current]: Math.max(
+ previousColumnWidths[resizedColumnId.current] + offset,
+ COLUMN_MIN_WIDTH,
+ ),
+ }));
+ resizedColumnId.current = '';
+ }, [offset]);
+
return (
@@ -21,16 +99,28 @@ export function EntityTableHeader({
{columns.map((column) => (
-
- |
+
+ handleResizeHandlerDragStart(event, column.id)
+ }
+ onDrag={handleResizeHandlerDrag}
+ onDragEnd={handleResizeHandlerDragEnd}
+ />
+
))}
|