Skip to content

Commit 325e4e0

Browse files
authored
Clearer list page loading states (#9547)
1 parent 3cc7215 commit 325e4e0

2 files changed

Lines changed: 36 additions & 21 deletions

File tree

  • packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage
  • tests/admin-ui-tests

packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { toastQueue } from '@keystar/ui/toast'
2525
import { TooltipTrigger, Tooltip } from '@keystar/ui/tooltip'
2626
import { Heading, Text } from '@keystar/ui/typography'
2727

28+
import type { TypedDocumentNode } from '../../../../admin-ui/apollo'
2829
import { gql, useMutation, useQuery } from '../../../../admin-ui/apollo'
2930
import { PageContainer } from '../../../../admin-ui/components/PageContainer'
3031
import { useList } from '../../../../admin-ui/context'
@@ -39,6 +40,7 @@ import { useFilters } from './useFilters'
3940
import { useSearchFilter } from '../../../../fields/types/relationship/views/useFilter'
4041
import { useSelectedFields } from './useSelectedFields'
4142
import { useSort } from './useSort'
43+
import { ProgressCircle } from '@keystar/ui/progress'
4244

4345
type ListPageProps = { listKey: string }
4446
type SelectedKeys = 'all' | Set<number | string>
@@ -103,8 +105,11 @@ function ListPage({ listKey }: ListPageProps) {
103105
const search = useSearchFilter(searchParam, list, list.initialSearchFields)
104106

105107
const selectedFields = useSelectedFields(list)
106-
const { data, error, refetch } = useQuery(
107-
useMemo(() => {
108+
const { data, error, refetch, loading } = useQuery(
109+
useMemo((): TypedDocumentNode<{
110+
items: Record<string, unknown>[] | null
111+
count: number | null
112+
}> => {
108113
const selectedGqlFields = [...selectedFields]
109114
.map(fieldPath => list.fields[fieldPath].controller.graphqlSelection)
110115
.join('\n')
@@ -156,6 +161,11 @@ function ListPage({ listKey }: ListPageProps) {
156161
}
157162
}
158163

164+
const [dataWithPevious, setDataWithPrevious] = useState<typeof data>(data)
165+
if (!loading && data !== dataWithPevious) {
166+
setDataWithPrevious(data)
167+
}
168+
159169
const allowCreate = !(list.hideCreate ?? true)
160170
const allowDelete = !(list.hideDelete ?? true)
161171
const isConstrained = Boolean(filters.filters.length || query.search)
@@ -194,6 +204,7 @@ function ListPage({ listKey }: ListPageProps) {
194204
<Tooltip>Reset to defaults</Tooltip>
195205
</TooltipTrigger>
196206
)}
207+
{!!dataWithPevious && loading && <ProgressCircle size="small" isIndeterminate />}
197208
</HStack>
198209

199210
{filters.filters.length ? <FilterList filters={filters.filters} list={list} /> : null}
@@ -203,13 +214,13 @@ function ListPage({ listKey }: ListPageProps) {
203214
<ListTable
204215
listKey={listKey}
205216
allowDelete={allowDelete}
206-
count={data?.count ?? 0}
217+
data={dataWithPevious}
207218
currentPage={currentPage}
208219
isConstrained={isConstrained}
209220
pageSize={pageSize}
210221
refetch={refetch}
211-
items={data?.items ?? []}
212222
selectedFields={selectedFields}
223+
loading={loading}
213224
/>
214225
</VStack>
215226
</PageContainer>
@@ -236,24 +247,24 @@ function ListPageHeader({ listKey, showCreate }: { listKey: string; showCreate?:
236247

237248
function ListTable({
238249
allowDelete,
239-
count,
250+
data,
240251
currentPage,
241252
isConstrained,
242253
listKey,
243-
items,
244254
pageSize,
245255
refetch,
246256
selectedFields,
257+
loading,
247258
}: {
248259
allowDelete: boolean
249-
count: number
250260
currentPage: number
251261
isConstrained: boolean
252262
listKey: string
253263
pageSize: number
254264
refetch: () => void
255265
selectedFields: ReturnType<typeof useSelectedFields>
256-
items: Record<string, unknown>[]
266+
data: { items: Record<string, unknown>[] | null; count: number | null } | undefined
267+
loading: boolean
257268
}) {
258269
const list = useList(listKey)
259270
const router = useRouter()
@@ -271,7 +282,7 @@ function ListTable({
271282
return {
272283
id: path,
273284
label: field.label,
274-
allowsSorting: !isConstrained && !items.length ? false : field.isOrderable,
285+
allowsSorting: !isConstrained && !data?.items?.length ? false : field.isOrderable,
275286
}
276287
})
277288

@@ -288,7 +299,9 @@ function ListTable({
288299
onSelectionChange={setSelectedKeys}
289300
selectedKeys={selectedKeys}
290301
renderEmptyState={() =>
291-
isConstrained ? (
302+
loading ? (
303+
<ProgressCircle isIndeterminate />
304+
) : isConstrained ? (
292305
<EmptyState
293306
icon={searchXIcon}
294307
title="No results"
@@ -303,6 +316,9 @@ function ListTable({
303316
)
304317
}
305318
flex
319+
UNSAFE_style={{
320+
opacity: loading && !!data ? 0.5 : undefined,
321+
}}
306322
>
307323
<TableHeader columns={columns}>
308324
{({ label, id, ...options }) => (
@@ -311,7 +327,7 @@ function ListTable({
311327
</Column>
312328
)}
313329
</TableHeader>
314-
<TableBody items={items}>
330+
<TableBody items={data?.items ?? []}>
315331
{row => {
316332
return (
317333
<Row href={`/${list.path}/${row?.id}`}>
@@ -352,7 +368,7 @@ function ListTable({
352368
switch (key) {
353369
case 'delete':
354370
if (selectedKeys === 'all') {
355-
const ids = items.filter(x => x.id != null).map(x => `${x.id}`)
371+
const ids = data?.items?.filter(x => x.id != null).map(x => `${x.id}`)
356372
setIdsForDeletion(new Set(ids))
357373
} else {
358374
setIdsForDeletion(selectedKeys)
@@ -370,13 +386,13 @@ function ListTable({
370386
</ActionBar>
371387
</ActionBarContainer>
372388

373-
{count > 0 && (
389+
{!!data?.count && (
374390
<Pagination
375391
currentPage={currentPage}
376392
pageSize={pageSize}
377393
plural={list.plural}
378394
singular={list.singular}
379-
total={count}
395+
total={data.count}
380396
/>
381397
)}
382398

tests/admin-ui-tests/filters.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,18 @@ adminUITests('./tests/test-projects/basic', browserType => {
88

99
beforeAll(async () => {
1010
browser = await browserType.launch()
11-
context = await browser.newContext()
12-
page = await browser.newPage()
13-
await loadIndex(page)
1411
})
1512

1613
describe('relationship filters', () => {
1714
beforeEach(async () => {
18-
await context.clearCookies()
19-
await page.evaluate(() => {
20-
window.localStorage.clear()
21-
})
15+
context = await browser.newContext()
16+
page = await context.newPage()
17+
await loadIndex(page)
2218
await deleteAllData('./tests/test-projects/basic')
2319
})
20+
afterEach(async () => {
21+
await context.close()
22+
})
2423
test('Lists are filterable by relationships', async () => {
2524
const gql = String.raw
2625
const TASK_MUTATION_CREATE = gql`

0 commit comments

Comments
 (0)