Skip to content

Commit deca10d

Browse files
authored
Revert "feat: templates list pagination (#352)" (#391)
This reverts commit 58ab886.
1 parent 41d3a2d commit deca10d

14 files changed

Lines changed: 258 additions & 381 deletions

File tree

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,11 @@
11
import { Suspense } from 'react'
22
import LoadingLayout from '@/features/dashboard/loading-layout'
3-
import {
4-
TEMPLATES_DEFAULT_SORT,
5-
TEMPLATES_PAGE_SIZE,
6-
} from '@/features/dashboard/templates/list/constants'
73
import TemplatesTable from '@/features/dashboard/templates/list/table'
8-
import { HydrateClient, prefetch, trpc } from '@/trpc/server'
9-
10-
export default async function TemplatesListPage({
11-
params,
12-
}: PageProps<'/dashboard/[teamSlug]/templates/list'>) {
13-
const { teamSlug } = await params
14-
15-
prefetch(
16-
trpc.templates.getTemplates.infiniteQueryOptions({
17-
teamSlug,
18-
limit: TEMPLATES_PAGE_SIZE,
19-
sort: TEMPLATES_DEFAULT_SORT,
20-
})
21-
)
224

5+
export default function TemplatesListPage() {
236
return (
24-
<HydrateClient>
25-
<Suspense fallback={<LoadingLayout />}>
26-
<TemplatesTable />
27-
</Suspense>
28-
</HydrateClient>
7+
<Suspense fallback={<LoadingLayout />}>
8+
<TemplatesTable />
9+
</Suspense>
2910
)
3011
}

src/core/modules/templates/models.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import type {
2-
components as DashboardComponents,
3-
paths as DashboardPaths,
4-
} from '@/contracts/dashboard-api'
51
import type { components as InfraComponents } from '@/contracts/infra-api'
62

73
export type Template = Pick<
@@ -27,14 +23,3 @@ export type DefaultTemplate = Template & {
2723
isDefault: true
2824
defaultDescription?: string
2925
}
30-
31-
export type TemplatesSort = DashboardComponents['parameters']['templates_sort']
32-
33-
export type ListTeamTemplatesOptions = NonNullable<
34-
DashboardPaths['/templates']['get']['parameters']['query']
35-
>
36-
37-
export interface ListTeamTemplatesResult {
38-
data: Array<Template | DefaultTemplate>
39-
nextCursor: string | null
40-
}

src/core/modules/templates/repository.server.ts

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ import {
77
MOCK_DEFAULT_TEMPLATES_DATA,
88
MOCK_TEMPLATES_DATA,
99
} from '@/configs/mock-data'
10-
import type {
11-
DefaultTemplate,
12-
ListTeamTemplatesOptions,
13-
ListTeamTemplatesResult,
14-
Template,
15-
} from '@/core/modules/templates/models'
10+
import type { DefaultTemplate, Template } from '@/core/modules/templates/models'
1611
import {
1712
type AuthUserEmailResolver,
1813
getAuthUserEmailsById,
@@ -35,9 +30,6 @@ type TemplatesRepositoryDeps = {
3530

3631
export interface TeamTemplatesRepository {
3732
getTeamTemplates(): Promise<RepoResult<{ templates: Template[] }>>
38-
listTeamTemplates(
39-
options: ListTeamTemplatesOptions
40-
): Promise<RepoResult<ListTeamTemplatesResult>>
4133
deleteTemplate(templateId: string): Promise<RepoResult<{ success: true }>>
4234
updateTemplateVisibility(
4335
templateId: string,
@@ -95,62 +87,6 @@ export function createTemplatesRepository(
9587
),
9688
})
9789
},
98-
async listTeamTemplates(options) {
99-
if (USE_MOCK_DATA) {
100-
return ok({ data: MOCK_TEMPLATES_DATA, nextCursor: null })
101-
}
102-
103-
const res = await deps.apiClient.GET('/templates', {
104-
params: {
105-
query: options,
106-
},
107-
headers: {
108-
...deps.authHeaders(scope.accessToken, scope.teamId),
109-
},
110-
})
111-
112-
if (!res.response.ok || res.error) {
113-
return err(
114-
repoErrorFromHttp(
115-
res.response.status,
116-
res.error?.message ?? 'Failed to fetch templates',
117-
res.error
118-
)
119-
)
120-
}
121-
122-
if (!res.data?.data?.length) {
123-
return ok({ data: [], nextCursor: res.data?.nextCursor ?? null })
124-
}
125-
126-
const data = res.data.data.map((t): Template | DefaultTemplate => ({
127-
templateID: t.templateID,
128-
buildID: t.buildID,
129-
cpuCount: t.cpuCount,
130-
memoryMB: t.memoryMB,
131-
diskSizeMB: t.diskSizeMB ?? 0,
132-
public: t.public,
133-
aliases: t.aliases,
134-
names: t.names,
135-
createdAt: t.createdAt,
136-
updatedAt: t.updatedAt,
137-
// Email resolution is deferred while the Supabase auth migration is
138-
// in progress; the endpoint returns only the creator id for now.
139-
createdBy: t.createdBy
140-
? { id: t.createdBy.id, email: t.createdBy.email ?? '' }
141-
: null,
142-
lastSpawnedAt: t.lastSpawnedAt ?? null,
143-
spawnCount: t.spawnCount,
144-
buildCount: t.buildCount,
145-
envdVersion: t.envdVersion ?? '',
146-
...(t.isDefault && {
147-
isDefault: true as const,
148-
defaultDescription: t.defaultDescription ?? undefined,
149-
}),
150-
}))
151-
152-
return ok({ data, nextCursor: res.data.nextCursor ?? null })
153-
},
15490
async deleteTemplate(templateId) {
15591
const res = await deps.infraClient.DELETE('/templates/{templateID}', {
15692
params: {

src/core/server/api/routers/templates.ts

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,44 +36,11 @@ const teamTemplatesRepositoryProcedure = protectedTeamProcedure.use(
3636
export const templatesRouter = createTRPCRouter({
3737
// QUERIES
3838

39-
getTemplates: teamTemplatesRepositoryProcedure
40-
.input(
41-
z.object({
42-
cursor: z.string().optional(),
43-
limit: z.number().int().min(1).max(100).default(50),
44-
cpuCount: z.number().int().positive().optional(),
45-
memoryMB: z.number().int().positive().optional(),
46-
public: z.boolean().optional(),
47-
search: z.string().optional(),
48-
sort: z
49-
.enum([
50-
'name_asc',
51-
'name_desc',
52-
'cpu_count_asc',
53-
'cpu_count_desc',
54-
'memory_mb_asc',
55-
'memory_mb_desc',
56-
'created_at_asc',
57-
'created_at_desc',
58-
'updated_at_asc',
59-
'updated_at_desc',
60-
])
61-
.default('updated_at_desc'),
62-
})
63-
)
64-
.query(async ({ ctx, input }) => {
65-
const result = await ctx.templatesRepository.listTeamTemplates({
66-
cursor: input.cursor,
67-
limit: input.limit,
68-
cpuCount: input.cpuCount,
69-
memoryMB: input.memoryMB,
70-
public: input.public,
71-
search: input.search,
72-
sort: input.sort,
73-
})
74-
if (!result.ok) throwTRPCErrorFromRepoError(result.error)
75-
return result.data
76-
}),
39+
getTemplates: teamTemplatesRepositoryProcedure.query(async ({ ctx }) => {
40+
const result = await ctx.templatesRepository.getTeamTemplates()
41+
if (!result.ok) throwTRPCErrorFromRepoError(result.error)
42+
return result.data
43+
}),
7744

7845
getDefaultTemplatesCached: templatesRepositoryProcedure.query(
7946
async ({ ctx }) => {

src/features/dashboard/templates/builds/table-cells.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import CopyButtonInline from '@/ui/copy-button-inline'
1818
import { Badge } from '@/ui/primitives/badge'
1919
import { Button } from '@/ui/primitives/button'
2020
import { CheckIcon, CloseIcon } from '@/ui/primitives/icons'
21+
import { Loader } from '@/ui/primitives/loader'
2122

2223
export function BuildId({ id }: { id: string }) {
2324
return (
@@ -60,6 +61,42 @@ export function Template({
6061
)
6162
}
6263

64+
export function LoadMoreButton({
65+
isLoading,
66+
onLoadMore,
67+
}: {
68+
isLoading: boolean
69+
onLoadMore: () => void
70+
}) {
71+
if (isLoading) {
72+
return (
73+
<span className="inline-flex items-center gap-1">
74+
Loading
75+
<Loader variant="dots" />
76+
</span>
77+
)
78+
}
79+
return (
80+
<button
81+
onClick={onLoadMore}
82+
className="underline text-fg-secondary hover:text-accent-main-highlight transition-colors"
83+
>
84+
Load more
85+
</button>
86+
)
87+
}
88+
89+
export function BackToTopButton({ onBackToTop }: { onBackToTop: () => void }) {
90+
return (
91+
<button
92+
onClick={onBackToTop}
93+
className="underline text-fg-secondary hover:text-accent-main-highlight transition-colors"
94+
>
95+
Back to top
96+
</button>
97+
)
98+
}
99+
63100
export function Duration({
64101
createdAt,
65102
finishedAt,

src/features/dashboard/templates/builds/table.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import type {
1616
import { useRouteParams } from '@/lib/hooks/use-route-params'
1717
import { cn } from '@/lib/utils/ui'
1818
import { useTRPC } from '@/trpc/client'
19-
import { BackToTopButton, LoadMoreButton } from '@/ui/pagination-buttons'
2019
import { ArrowDownIcon } from '@/ui/primitives/icons'
2120
import { Loader } from '@/ui/primitives/loader'
2221
import {
@@ -29,8 +28,10 @@ import {
2928
} from '@/ui/primitives/table'
3029
import BuildsEmpty from './empty'
3130
import {
31+
BackToTopButton,
3232
BuildId,
3333
Duration,
34+
LoadMoreButton,
3435
Reason,
3536
StartedAt,
3637
Status,

src/features/dashboard/templates/list/constants.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/features/dashboard/templates/list/header.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Table } from '@tanstack/react-table'
22
import { Suspense } from 'react'
33
import type { Template } from '@/core/modules/templates/models'
4-
import { useTemplateTableStore } from './stores/table-store'
54
import TemplatesTableFilters from './table-filters'
65
import { SearchInput } from './table-search'
76

@@ -12,16 +11,13 @@ interface TemplatesHeaderProps {
1211
export default function TemplatesHeader({ table }: TemplatesHeaderProps) {
1312
'use no memo'
1413

15-
const { globalFilter, cpuCount, memoryMB, isPublic } = useTemplateTableStore()
16-
const isFiltered =
17-
Boolean(globalFilter) ||
18-
cpuCount !== undefined ||
19-
memoryMB !== undefined ||
20-
isPublic !== undefined
14+
const { columnFilters, globalFilter } = table.getState()
15+
const showFilteredRowCount = columnFilters.length > 0 || Boolean(globalFilter)
2116

22-
// With server-side pagination we only know how many rows are currently
23-
// loaded, not the grand total.
24-
const loadedCount = table.options.data.length
17+
const totalCount = table.options.data.length
18+
const filteredCount = showFilteredRowCount
19+
? table.getFilteredRowModel().rows.length
20+
: totalCount
2521

2622
return (
2723
<div className="flex min-w-0 flex-wrap items-start gap-1 sm:items-center">
@@ -37,12 +33,17 @@ export default function TemplatesHeader({ table }: TemplatesHeaderProps) {
3733
<div className="hidden w-2 shrink-0 sm:block" aria-hidden="true" />
3834

3935
<span className="prose-label-highlight h-9 flex w-full min-w-0 items-center gap-1 uppercase sm:w-auto">
40-
<span className="text-fg">
41-
{loadedCount} {loadedCount === 1 ? 'template' : 'templates'}
42-
</span>
43-
{isFiltered ? (
44-
<span className="text-fg-tertiary"> · filtered</span>
45-
) : null}
36+
{showFilteredRowCount ? (
37+
<>
38+
<span className="text-fg">
39+
{filteredCount} {filteredCount === 1 ? 'result' : 'results'}
40+
</span>
41+
<span className="text-fg-tertiary"> · </span>
42+
<span className="text-fg-tertiary">{totalCount} total</span>
43+
</>
44+
) : (
45+
<span className="text-fg-tertiary">{totalCount} total</span>
46+
)}
4647
</span>
4748
</div>
4849
)

src/features/dashboard/templates/list/stores/table-store.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { OnChangeFn, SortingState } from '@tanstack/react-table'
22
import { create } from 'zustand'
33
import { createJSONStorage, persist } from 'zustand/middleware'
44
import { createHashStorage } from '@/lib/utils/store'
5-
import { TEMPLATES_DEFAULT_SORTING } from '../constants'
65
import { trackTemplateTableInteraction } from '../table-config'
76

87
interface TemplateTableState {
@@ -34,7 +33,7 @@ type Store = TemplateTableState & TemplateTableActions
3433

3534
const initialState: TemplateTableState = {
3635
// Table state
37-
sorting: TEMPLATES_DEFAULT_SORTING,
36+
sorting: [{ id: 'updatedAt', desc: true }],
3837
globalFilter: '',
3938
// Filter state
4039
cpuCount: undefined,

0 commit comments

Comments
 (0)