Skip to content

Commit 1fe826f

Browse files
committed
chore: show loading indicator
1 parent 620b9cf commit 1fe826f

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

src/application/database-yjs/context.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,18 @@ export const useRowData = (rowId: string) => {
301301
return useRow(rowId)?.get(YjsEditorKey.database_row) as YDatabaseRow;
302302
};
303303

304+
/**
305+
* Returns true once the row's collab content has been loaded into the local
306+
* doc (i.e. the `database_row` YMap is present in the row's data_section).
307+
* Useful for showing a loading indicator on rows that have no local
308+
* IndexedDB cache yet while their first sync arrives.
309+
*/
310+
export const useIsRowLoaded = (rowId: string) => {
311+
const dataSection = useRow(rowId);
312+
313+
return Boolean(dataSection?.has(YjsEditorKey.database_row));
314+
};
315+
304316
/**
305317
* Returns the currently active view tab ID.
306318
* This is the view that is currently being displayed (Grid, Board, or Calendar).

src/components/database/components/cell/primary/PrimaryCell.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { useMemo, useRef } from 'react';
22

3-
import { RowMetaKey, useDatabaseContext, useRowMetaSelector } from '@/application/database-yjs';
3+
import CircularProgress from '@mui/material/CircularProgress';
4+
5+
import { RowMetaKey, useDatabaseContext, useIsRowLoaded, useRowMetaSelector } from '@/application/database-yjs';
46
import { Cell as CellType, CellProps } from '@/application/database-yjs/cell.type';
57
import { useUpdateRowMetaDispatch } from '@/application/database-yjs/dispatch';
68
import { ReactComponent as DocumentSvg } from '@/assets/icons/doc.svg';
@@ -16,6 +18,7 @@ export function PrimaryCell(props: CellProps<CellType>) {
1618
const ref = useRef<HTMLDivElement>(null);
1719
const meta = useRowMetaSelector(rowId);
1820
const navigateToRow = useDatabaseContext().navigateToRow;
21+
const isRowLoaded = useIsRowLoaded(rowId);
1922

2023
const hasDocument = meta?.isEmptyDocument === false;
2124
const icon = meta?.icon;
@@ -69,7 +72,15 @@ export function PrimaryCell(props: CellProps<CellType>) {
6972
</CustomIconPopover>
7073

7174
<div className={'flex flex-1 items-center overflow-x-hidden'}>
72-
<DatabaseCell {...props} />
75+
{isRowLoaded ? (
76+
<DatabaseCell {...props} />
77+
) : (
78+
<CircularProgress
79+
size={14}
80+
className={'text-icon-secondary'}
81+
data-testid={`primary-cell-loading-${rowId}`}
82+
/>
83+
)}
7384
</div>
7485
</div>
7586
);

src/components/database/components/grid/grid-cell/GridRowCell.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
22

3-
import { FieldType, useCellSelector, useFieldWrap, useReadOnly } from '@/application/database-yjs';
3+
import { FieldType, useCellSelector, useFieldWrap, useIsRowLoaded, useReadOnly } from '@/application/database-yjs';
44
import { CellProps, Cell as CellType } from '@/application/database-yjs/cell.type';
55
import { useFieldSelector } from '@/application/database-yjs/selector';
66
import { FieldId, YjsDatabaseKey } from '@/application/types';
@@ -26,6 +26,7 @@ export function GridRowCell({ rowId, fieldId }: GridCellProps) {
2626
const isPrimary = field?.get(YjsDatabaseKey.is_primary);
2727
const disableRelationRollupEdit = isFieldEditingDisabled(fieldType as FieldType);
2828
const isReadOnlyCell = readOnly || disableRelationRollupEdit;
29+
const isRowLoaded = useIsRowLoaded(rowId);
2930
const cell = useCellSelector({
3031
rowId,
3132
fieldId,
@@ -118,6 +119,19 @@ export function GridRowCell({ rowId, fieldId }: GridCellProps) {
118119

119120
if (!field) return null;
120121

122+
// While the row's collab content is still loading from IndexedDB/network,
123+
// render blank non-primary cells. The primary cell renders a loading
124+
// indicator (handled inside PrimaryCell).
125+
if (!isRowLoaded && !isPrimary) {
126+
return (
127+
<div
128+
ref={ref}
129+
data-testid={`grid-cell-${rowId}-${fieldId}`}
130+
className={cn('grid-cell flex h-full w-full items-start overflow-hidden px-2 text-sm', paddingVertical)}
131+
/>
132+
);
133+
}
134+
121135
return (
122136
<div
123137
ref={ref}

0 commit comments

Comments
 (0)