Refactor fast follow on column move feature (#1665)

* Refactor fast follow on column move feature

* Fix lint
This commit is contained in:
Charles Bochet 2023-09-19 16:42:11 -07:00 committed by GitHub
parent cb05b1fbc9
commit 8c21dc8bba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 66 additions and 75 deletions

View File

@ -5,11 +5,8 @@ export {
IconAlertTriangle,
IconArchive,
IconArrowBack,
IconArrowNarrowDown,
IconArrowNarrowLeft,
IconArrowNarrowRight,
IconArrowNarrowUp,
IconArrowDown,
IconArrowLeft,
IconArrowRight,
IconArrowUp,
IconArrowUpRight,

View File

@ -4,7 +4,7 @@ import styled from '@emotion/styled';
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
import { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
import { ColumnHeaderDropdownId } from '../constants/ColumnHeaderDropdownId';
import { ColumnHeadDropdownId } from '../constants/ColumnHeadDropdownId';
import { ColumnDefinition } from '../types/ColumnDefinition';
import { EntityTableHeaderOptions } from './EntityTableHeaderOptions';
@ -49,7 +49,7 @@ export const ColumnHead = ({
const theme = useTheme();
const { openDropdownButton } = useDropdownButton({
dropdownId: ColumnHeaderDropdownId,
dropdownId: ColumnHeadDropdownId,
});
return (

View File

@ -166,21 +166,22 @@ export const EntityTableHeader = () => {
</th>
{visibleTableColumns.map((column, index) => (
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
<StyledColumnHeaderCell
key={column.key}
isResizing={resizedFieldKey === column.key}
columnWidth={Math.max(
tableColumnsByKey[column.key].size +
(resizedFieldKey === column.key ? resizeFieldOffset : 0),
COLUMN_MIN_WIDTH,
)}
>
<StyledColumnHeaderCell
key={column.key}
isResizing={resizedFieldKey === column.key}
columnWidth={Math.max(
tableColumnsByKey[column.key].size +
(resizedFieldKey === column.key ? resizeFieldOffset : 0),
COLUMN_MIN_WIDTH,
)}
>
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
<ColumnHead
column={column}
isFirstColumn={index === 0}
isLastColumn={index === visibleTableColumns.length - 1}
/>
<StyledResizeHandler
className="cursor-col-resize"
role="separator"
@ -188,8 +189,8 @@ export const EntityTableHeader = () => {
setResizedFieldKey(column.key);
}}
/>
</StyledColumnHeaderCell>
</RecoilScope>
</RecoilScope>
</StyledColumnHeaderCell>
))}
<th>
{hiddenTableColumns.length > 0 && (

View File

@ -1,4 +1,3 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
@ -6,14 +5,10 @@ import { StyledDropdownMenu } from '@/ui/dropdown/components/StyledDropdownMenu'
import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer';
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
import { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
import {
IconArrowNarrowLeft,
IconArrowNarrowRight,
IconEyeOff,
} from '@/ui/icon';
import { IconArrowLeft, IconArrowRight, IconEyeOff } from '@/ui/icon';
import { MenuItem } from '@/ui/menu-item/components/MenuItem';
import { ColumnHeaderDropdownId } from '../constants/ColumnHeaderDropdownId';
import { ColumnHeadDropdownId } from '../constants/ColumnHeadDropdownId';
import { useTableColumns } from '../hooks/useTableColumns';
import { ColumnDefinition } from '../types/ColumnDefinition';
@ -33,8 +28,6 @@ export const EntityTableHeaderOptions = ({
isFirstColumn,
isLastColumn,
}: EntityTableHeaderOptionsProps) => {
const theme = useTheme();
const {
handleColumnVisibilityChange,
handleColumnLeftMove,
@ -42,19 +35,23 @@ export const EntityTableHeaderOptions = ({
} = useTableColumns();
const { closeDropdownButton } = useDropdownButton({
dropdownId: ColumnHeaderDropdownId,
dropdownId: ColumnHeadDropdownId,
});
const handleColumnMoveLeft = () => {
closeDropdownButton();
if (isFirstColumn) return;
else handleColumnLeftMove(column);
if (isFirstColumn) {
return;
}
handleColumnLeftMove(column);
};
const handleColumnMoveRight = () => {
closeDropdownButton();
if (isLastColumn) return;
else handleColumnRightMove(column);
if (isLastColumn) {
return;
}
handleColumnRightMove(column);
};
const handleColumnVisibility = () => {
@ -64,26 +61,22 @@ export const EntityTableHeaderOptions = ({
return (
<StyledDropdownContainer>
<DropdownButton
dropdownId={ColumnHeaderDropdownId}
dropdownId={ColumnHeadDropdownId}
dropdownComponents={
<StyledDropdownMenu>
<StyledDropdownMenuItemsContainer>
<MenuItem
LeftIcon={() => (
<IconArrowNarrowLeft size={theme.icon.size.md} />
)}
LeftIcon={IconArrowLeft}
onClick={handleColumnMoveLeft}
text="Move left"
/>
<MenuItem
LeftIcon={() => (
<IconArrowNarrowRight size={theme.icon.size.md} />
)}
LeftIcon={IconArrowRight}
onClick={handleColumnMoveRight}
text="Move right"
/>
<MenuItem
LeftIcon={() => <IconEyeOff size={theme.icon.size.md} />}
LeftIcon={IconEyeOff}
onClick={handleColumnVisibility}
text="Hide"
/>

View File

@ -0,0 +1 @@
export const ColumnHeadDropdownId = 'table-head-options';

View File

@ -1 +0,0 @@
export const ColumnHeaderDropdownId = 'table-header-options';

View File

@ -51,29 +51,29 @@ export const useTableColumns = () => {
const handleColumnMove = useCallback(
(direction: string, column: ColumnDefinition<ViewFieldMetadata>) => {
const tableColumnIndex = tableColumns.findIndex(
const currentColumnArrayIndex = tableColumns.findIndex(
(tableColumn) => tableColumn.key === column.key,
);
if (tableColumnIndex >= 0) {
const currentColumn = tableColumns[tableColumnIndex];
const targetColumn =
direction === 'left'
? tableColumns[tableColumnIndex - 1]
: tableColumns[tableColumnIndex + 1];
const updatedColumns = tableColumns
.map((tableColumn) => {
switch (tableColumn.key) {
case targetColumn.key:
return { ...tableColumn, index: currentColumn.index };
case currentColumn.key:
return { ...tableColumn, index: targetColumn.index };
default:
return tableColumn;
}
})
.sort((columnA, columnB) => columnA.index - columnB.index);
const targetColumnArrayIndex =
direction === 'left'
? currentColumnArrayIndex - 1
: currentColumnArrayIndex + 1;
setTableColumns(updatedColumns);
if (currentColumnArrayIndex >= 0) {
const currentColumn = tableColumns[currentColumnArrayIndex];
const targetColumn = tableColumns[targetColumnArrayIndex];
const newTableColumns = [...tableColumns];
newTableColumns[currentColumnArrayIndex] = {
...targetColumn,
index: currentColumn.index,
};
newTableColumns[targetColumnArrayIndex] = {
...currentColumn,
index: targetColumn.index,
};
setTableColumns(newTableColumns);
}
},
[tableColumns, setTableColumns],

View File

@ -164,6 +164,7 @@ export const useTableViewFields = ({
(column) =>
savedTableColumnsByKey[column.key] &&
(savedTableColumnsByKey[column.key].size !== column.size ||
savedTableColumnsByKey[column.key].index !== column.index ||
savedTableColumnsByKey[column.key].isVisible !== column.isVisible),
);
await updateViewFields(viewFieldsToUpdate);
@ -178,5 +179,5 @@ export const useTableViewFields = ({
updateViewFields,
]);
return { createViewFields, persistColumns, updateViewFields };
return { createViewFields, persistColumns };
};

View File

@ -41,12 +41,11 @@ export const useTableViews = ({
type: ViewType.Table,
RecoilScopeContext: TableRecoilScopeContext,
});
const { createViewFields, persistColumns, updateViewFields } =
useTableViewFields({
objectId,
columnDefinitions,
skipFetch: isFetchingViews,
});
const { createViewFields, persistColumns } = useTableViewFields({
objectId,
columnDefinitions,
skipFetch: isFetchingViews,
});
const { createViewFilters, persistFilters } = useViewFilters({
RecoilScopeContext: TableRecoilScopeContext,
@ -62,7 +61,6 @@ export const useTableViews = ({
await persistColumns();
await persistFilters();
await persistSorts();
await updateViewFields(tableColumns);
};
return { createView, deleteView, submitCurrentView, updateView };

View File

@ -46,17 +46,16 @@ export const FilterByName: Story = {
delay: 200,
});
await sleep(50);
await sleep(200);
expect(await canvas.findByText('Airbnb')).toBeInTheDocument();
expect(await canvas.findByText('Aircall')).toBeInTheDocument();
await sleep(50);
await expect(canvas.queryAllByText('Qonto')).toStrictEqual([]);
expect(await canvas.queryAllByText('Qonto')).toStrictEqual([]);
const accountOwnerFilter = canvas.getAllByText('Name').find((item) => {
const nameFilter = canvas.getAllByText('Name').find((item) => {
return item.parentElement?.textContent?.includes('Name: Air');
});
expect(accountOwnerFilter).toBeInTheDocument();
expect(nameFilter).toBeInTheDocument();
},
};

View File

@ -280,7 +280,7 @@ export const SelectRelationWithKeys: Story = {
await userEvent.type(relationInput, '{enter}');
await sleep(50);
await sleep(200);
const allAirbns = await canvas.findAllByText('Aircall');
expect(allAirbns.length).toBe(1);

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "viewFields" ALTER COLUMN "index" SET DATA TYPE DOUBLE PRECISION;