fix: wires up abort controller logic for list columns (#9180)
### What? List column state could become out of sync if toggling columns happened in rapid succession as seen in CI. Or when using a spotty connection where responses could come back out of order. ### Why? State was not being preserved between toggles. Leading to incorrect columns being toggled on/off. ### How? Updates internal column state before making the request to the server so when a future toggle occurs it has up to date state of all columns. Also introduces an abort controller to prevent the out of order response issue.
This commit is contained in:
@@ -10,6 +10,7 @@ import type { Column } from '../Table/index.js'
|
||||
import { useConfig } from '../../providers/Config/index.js'
|
||||
import { usePreferences } from '../../providers/Preferences/index.js'
|
||||
import { useServerFunctions } from '../../providers/ServerFunctions/index.js'
|
||||
import { abortAndIgnore } from '../../utilities/abortAndIgnore.js'
|
||||
|
||||
export interface ITableColumns {
|
||||
columns: Column[]
|
||||
@@ -77,25 +78,36 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
const { getPreference, setPreference } = usePreferences()
|
||||
|
||||
const [tableColumns, setTableColumns] = React.useState(columnState)
|
||||
const tableStateControllerRef = React.useRef<AbortController>(null)
|
||||
|
||||
const moveColumn = useCallback(
|
||||
async (args: { fromIndex: number; toIndex: number }) => {
|
||||
abortAndIgnore(tableStateControllerRef.current)
|
||||
|
||||
const { fromIndex, toIndex } = args
|
||||
const withMovedColumn = [...tableColumns]
|
||||
const [columnToMove] = withMovedColumn.splice(fromIndex, 1)
|
||||
withMovedColumn.splice(toIndex, 0, columnToMove)
|
||||
|
||||
const { state: columnState, Table } = await getTableState({
|
||||
setTableColumns(withMovedColumn)
|
||||
|
||||
const controller = new AbortController()
|
||||
tableStateControllerRef.current = controller
|
||||
|
||||
const result = await getTableState({
|
||||
collectionSlug,
|
||||
columns: sanitizeColumns(withMovedColumn),
|
||||
docs,
|
||||
enableRowSelections,
|
||||
renderRowTypes,
|
||||
signal: controller.signal,
|
||||
tableAppearance,
|
||||
})
|
||||
|
||||
setTableColumns(columnState)
|
||||
setTable(Table)
|
||||
if (result) {
|
||||
setTableColumns(result.state)
|
||||
setTable(result.Table)
|
||||
}
|
||||
},
|
||||
[
|
||||
tableColumns,
|
||||
@@ -111,24 +123,55 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
|
||||
const toggleColumn = useCallback(
|
||||
async (column: string) => {
|
||||
const toggledColumns: Pick<Column, 'accessor' | 'active'>[] = tableColumns.map((col) => {
|
||||
return {
|
||||
accessor: col.accessor,
|
||||
active: col.accessor === column ? !col.active : col.active,
|
||||
}
|
||||
})
|
||||
abortAndIgnore(tableStateControllerRef.current)
|
||||
|
||||
const { state: columnState, Table } = await getTableState({
|
||||
const { newColumnState, toggledColumns } = tableColumns.reduce<{
|
||||
newColumnState: Column[]
|
||||
toggledColumns: Pick<Column, 'accessor' | 'active'>[]
|
||||
}>(
|
||||
(acc, col) => {
|
||||
if (col.accessor === column) {
|
||||
acc.newColumnState.push({
|
||||
...col,
|
||||
accessor: col.accessor,
|
||||
active: !col.active,
|
||||
})
|
||||
acc.toggledColumns.push({
|
||||
accessor: col.accessor,
|
||||
active: !col.active,
|
||||
})
|
||||
} else {
|
||||
acc.newColumnState.push(col)
|
||||
acc.toggledColumns.push({
|
||||
accessor: col.accessor,
|
||||
active: col.active,
|
||||
})
|
||||
}
|
||||
|
||||
return acc
|
||||
},
|
||||
{ newColumnState: [], toggledColumns: [] },
|
||||
)
|
||||
|
||||
setTableColumns(newColumnState)
|
||||
|
||||
const controller = new AbortController()
|
||||
tableStateControllerRef.current = controller
|
||||
|
||||
const result = await getTableState({
|
||||
collectionSlug,
|
||||
columns: toggledColumns,
|
||||
docs,
|
||||
enableRowSelections,
|
||||
renderRowTypes,
|
||||
signal: controller.signal,
|
||||
tableAppearance,
|
||||
})
|
||||
|
||||
setTableColumns(columnState)
|
||||
setTable(Table)
|
||||
if (result) {
|
||||
setTableColumns(result.state)
|
||||
setTable(result.Table)
|
||||
}
|
||||
},
|
||||
[
|
||||
tableColumns,
|
||||
@@ -233,6 +276,12 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
sortColumnProps,
|
||||
])
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
abortAndIgnore(tableStateControllerRef.current)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<TableColumnContext.Provider
|
||||
value={{
|
||||
|
||||
Reference in New Issue
Block a user