• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

teableio / teable / 8370273405

21 Mar 2024 05:44AM CUT coverage: 28.222% (-0.009%) from 28.231%
8370273405

push

github

web-flow
fix: drag row order not work (#482)

2122 of 3238 branches covered (65.53%)

0 of 33 new or added lines in 3 files covered. (0.0%)

16 existing lines in 1 file now uncovered.

25811 of 91456 relevant lines covered (28.22%)

5.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/sdk/src/components/grid-enhancements/hooks/use-grid-async-records.ts
1
import type { IRecord, IGetRecordsRo } from '@teable/core';
×
2
import { inRange, debounce } from 'lodash';
×
3
import { useCallback, useEffect, useRef, useState, useMemo } from 'react';
×
4
import type { IGridProps, IRectangle } from '../..';
×
5
import { useTableId } from '../../../hooks';
×
6
import { useRecords } from '../../../hooks/use-records';
×
7
import { useViewId } from '../../../hooks/use-view-id';
×
8
import { Record } from '../../../model';
×
9

×
10
// eslint-disable-next-line
×
11
export const LOAD_PAGE_SIZE = 300;
×
12
const defaultVisiblePages = { x: 0, y: 0, width: 0, height: 0 };
×
13

×
14
type IRes = {
×
15
  recordMap: IRecordIndexMap;
×
16
  onReset: () => void;
×
17
  onForceUpdate: () => void;
×
18
  onRowOrdered: (rowIndexCollection: number[], newRowIndex: number) => void;
×
19
  onVisibleRegionChanged: NonNullable<IGridProps['onVisibleRegionChanged']>;
×
20
};
×
21

×
22
export type IRecordIndexMap = { [i: number | string]: Record };
×
23

×
24
export const useGridAsyncRecords = (
×
25
  initRecords?: IRecord[],
×
26
  initQuery?: IGetRecordsRo,
×
27
  outerQuery?: Pick<IGetRecordsRo, 'filter' | 'orderBy' | 'groupBy'>
×
28
): IRes => {
×
29
  const [query, setQuery] = useState<IGetRecordsRo>({
×
30
    skip: 0,
×
31
    take: LOAD_PAGE_SIZE,
×
32
    ...initQuery,
×
33
  });
×
34
  const recordsQuery = useMemo(() => ({ ...query, ...outerQuery }), [query, outerQuery]);
×
35
  const tableId = useTableId();
×
36
  const viewId = useViewId();
×
37
  const queryRef = useRef(query);
×
38
  queryRef.current = query;
×
39
  const records = useRecords(recordsQuery, initRecords);
×
40
  const [loadedRecordMap, setLoadedRecordMap] = useState<IRecordIndexMap>(() =>
×
41
    records.reduce((acc, record, i) => {
×
42
      acc[i] = record;
×
43
      return acc;
×
44
    }, {} as IRecordIndexMap)
×
45
  );
×
46
  const [visiblePages, setVisiblePages] = useState<IRectangle>(defaultVisiblePages);
×
47
  const visiblePagesRef = useRef(visiblePages);
×
48
  visiblePagesRef.current = visiblePages;
×
49

×
50
  const onForceUpdate = useCallback(() => {
×
51
    const startIndex = queryRef.current.skip ?? 0;
×
52
    const take = queryRef.current.take ?? LOAD_PAGE_SIZE;
×
53
    setLoadedRecordMap((preLoadedRecords) => {
×
54
      const cacheLen = take * 2;
×
55
      const [cacheStartIndex, cacheEndIndex] = [
×
56
        Math.max(startIndex - cacheLen / 2, 0),
×
57
        startIndex + records.length + cacheLen / 2,
×
58
      ];
×
59
      const newRecordsState: IRecordIndexMap = {};
×
60
      for (let i = cacheStartIndex; i < cacheEndIndex; i++) {
×
61
        if (startIndex <= i && i < startIndex + records.length) {
×
62
          newRecordsState[i] = records[i - startIndex];
×
63
          continue;
×
64
        }
×
65
        newRecordsState[i] = preLoadedRecords[i];
×
66
      }
×
67
      return newRecordsState;
×
68
    });
×
69
  }, [records]);
×
70

×
71
  useEffect(() => onForceUpdate(), [onForceUpdate]);
×
72

×
73
  useEffect(() => {
×
74
    const { y, height } = visiblePages;
×
75
    setQuery((cv) => {
×
76
      if (cv.skip === undefined) {
×
77
        return cv;
×
78
      }
×
79

×
80
      const take = initQuery?.take ?? cv.take ?? LOAD_PAGE_SIZE;
×
81

×
82
      const pageOffsetSize = take / 3;
×
83
      const pageGap = take / 3;
×
84

×
85
      const visibleStartIndex = cv.skip <= y ? cv.skip - pageOffsetSize : cv.skip + pageOffsetSize;
×
86
      const visibleEndIndex = visibleStartIndex + take;
×
87
      const viewInRange =
×
88
        inRange(y, visibleStartIndex, visibleEndIndex) &&
×
89
        inRange(y + height, visibleStartIndex, visibleEndIndex);
×
90
      if (!viewInRange) {
×
91
        const skip = Math.floor(y / pageGap) * pageGap - pageGap;
×
92
        return {
×
93
          take: cv.take,
×
94
          ...initQuery,
×
95
          skip: Math.max(0, skip),
×
96
        };
×
97
      }
×
98
      return {
×
99
        take: cv.take,
×
100
        ...initQuery,
×
101
        skip: cv.skip,
×
102
      };
×
103
    });
×
104
  }, [visiblePages, initQuery]);
×
105

×
106
  const updateVisiblePages = useMemo(() => {
×
107
    return debounce(setVisiblePages, 30, { maxWait: 500 });
×
108
  }, []);
×
109

×
110
  const onVisibleRegionChanged: NonNullable<IGridProps['onVisibleRegionChanged']> = useCallback(
×
111
    (r) => {
×
112
      const { y, height } = visiblePagesRef.current;
×
113
      if (r.y === y && r.height === height) return;
×
114
      updateVisiblePages(r);
×
115
    },
×
116
    [updateVisiblePages]
×
117
  );
×
118

×
119
  const onReset = useCallback(() => {
×
120
    setLoadedRecordMap({});
×
121
    setVisiblePages(defaultVisiblePages);
×
122
  }, []);
×
123

×
124
  const onRowOrdered = useCallback(
×
125
    (rowIndexCollection: number[], newRowIndex: number) => {
×
126
      const operationRecordIds: string[] = [];
×
127

×
128
      for (const rowIndex of rowIndexCollection) {
×
129
        const record = loadedRecordMap[rowIndex];
×
130
        if (!record) {
×
131
          throw new Error('Can not find record by index: ' + rowIndex);
×
132
        }
×
133
        operationRecordIds.push(record.id);
×
134
      }
×
135

×
136
      if (!viewId) {
×
137
        throw new Error('Can not find view id');
×
138
      }
×
139

×
NEW
140
      if (newRowIndex === 0) {
×
141
        Record.updateRecordOrders(tableId as string, viewId, {
×
NEW
142
          anchorId: loadedRecordMap[0].id,
×
143
          position: 'before',
×
144
          recordIds: operationRecordIds,
×
145
        });
×
146
        return;
×
147
      }
×
NEW
148
      const record = loadedRecordMap[newRowIndex - 1];
×
149
      if (!record) {
×
150
        throw new Error("Can't find target record by index: " + newRowIndex);
×
151
      }
×
152
      Record.updateRecordOrders(tableId as string, viewId, {
×
153
        anchorId: record.id,
×
154
        position: 'after',
×
155
        recordIds: operationRecordIds,
×
156
      });
×
157
    },
×
158
    [viewId, loadedRecordMap, tableId]
×
159
  );
×
160

×
161
  return {
×
162
    recordMap: loadedRecordMap,
×
163
    onVisibleRegionChanged,
×
164
    onRowOrdered,
×
165
    onForceUpdate,
×
166
    onReset,
×
167
  };
×
168
};
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc