feat: reorder columns from table options (#1636)

* draggable prop addition

* draggable component addition

* state modification

* drag select state addition

* changed state name

* main merged

* lint fix

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
Aditya Pimpalkar
2023-09-19 23:31:21 +01:00
committed by GitHub
parent 321488ad3c
commit cb05b1fbc9
25 changed files with 979 additions and 33 deletions

View File

@ -1,5 +1,6 @@
import { useRef } from 'react';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@ -14,6 +15,7 @@ import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
import { useMapKeyboardToSoftFocus } from '../hooks/useMapKeyboardToSoftFocus';
import { useResetTableRowSelection } from '../hooks/useResetTableRowSelection';
import { useSetRowSelectedState } from '../hooks/useSetRowSelectedState';
import { isDraggingAndSelectingState } from '../states/isDraggingAndSelectingState';
import { TableHeader } from '../table-header/components/TableHeader';
import { TableHotkeyScope } from '../types/TableHotkeyScope';
@ -88,6 +90,9 @@ type OwnProps = {
export const EntityTable = ({ updateEntityMutation }: OwnProps) => {
const tableBodyRef = useRef<HTMLDivElement>(null);
const [isDraggingAndSelecting, setIsDraggingAndSelecting] = useRecoilState(
isDraggingAndSelectingState,
);
const setRowSelectedState = useSetRowSelectedState();
const resetTableRowSelection = useResetTableRowSelection();
@ -100,6 +105,7 @@ export const EntityTable = ({ updateEntityMutation }: OwnProps) => {
refs: [tableBodyRef],
callback: () => {
leaveTableFocus();
setIsDraggingAndSelecting(true);
},
});
@ -132,11 +138,13 @@ export const EntityTable = ({ updateEntityMutation }: OwnProps) => {
</StyledTable>
</div>
</ScrollWrapper>
<DragSelect
dragSelectable={tableBodyRef}
onDragSelectionStart={resetTableRowSelection}
onDragSelectionChange={setRowSelectedState}
/>
{isDraggingAndSelecting && (
<DragSelect
dragSelectable={tableBodyRef}
onDragSelectionStart={resetTableRowSelection}
onDragSelectionChange={setRowSelectedState}
/>
)}
</StyledTableContainer>
</StyledTableWithHeader>
</EntityUpdateMutationContext.Provider>

View File

@ -19,6 +19,19 @@ export const useTableColumns = () => {
TableRecoilScopeContext,
);
const handleColumnReorder = useCallback(
(columns: ColumnDefinition<ViewFieldMetadata>[]) => {
const updatedColumnOrder = columns
.map((column, index) => {
return { ...column, index };
})
.sort((columnA, columnB) => columnA.index - columnB.index);
setTableColumns(updatedColumnOrder);
},
[setTableColumns],
);
const handleColumnVisibilityChange = useCallback(
(column: ColumnDefinition<ViewFieldMetadata>) => {
const nextColumns = tableColumnsByKey[column.key]
@ -84,5 +97,6 @@ export const useTableColumns = () => {
handleColumnVisibilityChange,
handleColumnLeftMove,
handleColumnRightMove,
handleColumnReorder,
};
};

View File

@ -1,17 +1,27 @@
import { useRecoilState } from 'recoil';
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
import { useDropdownButton } from '@/ui/dropdown/hooks/useDropdownButton';
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
import { TableOptionsDropdownId } from '@/ui/table/constants/TableOptionsDropdownId';
import { isDraggingAndSelectingState } from '@/ui/table/states/isDraggingAndSelectingState';
export const TableOptionsDropdownButton = () => {
const [, setIsDraggingAndSelecting] = useRecoilState(
isDraggingAndSelectingState,
);
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton({
dropdownId: TableOptionsDropdownId,
});
const toggleDropdown = () => {
setIsDraggingAndSelecting(false);
toggleDropdownButton();
};
return (
<StyledHeaderDropdownButton
isUnfolded={isDropdownButtonOpen}
onClick={toggleDropdownButton}
onClick={toggleDropdown}
>
Options
</StyledHeaderDropdownButton>

View File

@ -1,5 +1,6 @@
import { useContext, useRef, useState } from 'react';
import { useCallback, useContext, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { OnDragEndResponder } from '@hello-pangea/dnd';
import { useRecoilCallback, useRecoilValue, useResetRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
@ -89,7 +90,8 @@ export const TableOptionsDropdownContent = () => {
TableRecoilScopeContext,
);
const { handleColumnVisibilityChange } = useTableColumns();
const { handleColumnVisibilityChange, handleColumnReorder } =
useTableColumns();
const { upsertView } = useUpsertView();
@ -115,6 +117,21 @@ export const TableOptionsDropdownContent = () => {
setCurrentMenu(option);
};
const handleReorderField: OnDragEndResponder = useCallback(
(result) => {
if (!result.destination) {
return;
}
const reorderFields = Array.from(visibleTableColumns);
const [removed] = reorderFields.splice(result.source.index, 1);
reorderFields.splice(result.destination.index, 0, removed);
handleColumnReorder(reorderFields);
},
[visibleTableColumns, handleColumnReorder],
);
const resetMenu = () => setCurrentMenu(undefined);
useScopedHotkeys(
@ -186,6 +203,8 @@ export const TableOptionsDropdownContent = () => {
title="Visible"
fields={visibleTableColumns}
onVisibilityChange={handleColumnVisibilityChange}
isDraggable={true}
onDragEnd={handleReorderField}
/>
{hiddenTableColumns.length > 0 && (
<>
@ -194,6 +213,7 @@ export const TableOptionsDropdownContent = () => {
title="Hidden"
fields={hiddenTableColumns}
onVisibilityChange={handleColumnVisibilityChange}
isDraggable={false}
/>
</>
)}

View File

@ -0,0 +1,6 @@
import { atom } from 'recoil';
export const isDraggingAndSelectingState = atom<boolean>({
key: 'isDraggingAndSelectingState',
default: true,
});

View File

@ -12,6 +12,7 @@ import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScop
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
import { TableOptionsDropdown } from '../../options/components/TableOptionsDropdown';
import { isDraggingAndSelectingState } from '../../states/isDraggingAndSelectingState';
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
import { canPersistTableColumnsScopedFamilySelector } from '../../states/selectors/canPersistTableColumnsScopedFamilySelector';
@ -40,6 +41,9 @@ export const TableHeader = () => {
const [savedTableColumns, setSavedTableColumns] = useRecoilState(
savedTableColumnsFamilyState(currentViewId),
);
const [, setIsDraggingAndSelecting] = useRecoilState(
isDraggingAndSelectingState,
);
const handleViewBarReset = () => setTableColumns(savedTableColumns);
@ -57,6 +61,7 @@ export const TableHeader = () => {
const handleCurrentViewSubmit = async () => {
if (canPersistTableColumns) {
setSavedTableColumns(tableColumns);
setIsDraggingAndSelecting(true);
}
await onCurrentViewSubmit?.();