create-ej-app 12.0.0 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/cli.js +5 -4
  2. package/cli.ts +9 -4
  3. package/package.json +1 -1
  4. package/template/base/package.json +9 -15
  5. package/template/base/terraform/artifact-registry.tf +5 -0
  6. package/template/base/terraform/backend-service.tf +13 -0
  7. package/template/base/terraform/cleanup.sh +9 -0
  8. package/template/base/terraform/cloudbuild.tf +70 -0
  9. package/template/base/terraform/cloudrun.tf +68 -0
  10. package/template/base/terraform/database.tf +60 -0
  11. package/template/base/terraform/forwarding-rule.tf +43 -0
  12. package/template/base/terraform/ip-address.tf +11 -0
  13. package/template/base/terraform/network-endpoint-group.tf +11 -0
  14. package/template/base/terraform/network.tf +21 -0
  15. package/template/base/terraform/pre.sh +3 -0
  16. package/template/base/terraform/providers.tf +18 -0
  17. package/template/base/terraform/secret.txt +11 -0
  18. package/template/base/terraform/setup.sh +25 -0
  19. package/template/base/terraform/ssl-certs.tf +32 -0
  20. package/template/base/terraform/target-https-proxy copy.tf +14 -0
  21. package/template/base/terraform/target-https-proxy.tf +14 -0
  22. package/template/base/terraform/terraform.tfvars +4 -0
  23. package/template/base/terraform/url-map.tf +23 -0
  24. package/template/base/terraform/variables.tf +21 -0
  25. package/template/old/.env.example +0 -17
  26. package/template/old/.eslintrc.cjs +0 -26
  27. package/template/old/components.json +0 -17
  28. package/template/old/drizzle.config.ts +0 -11
  29. package/template/old/next.config.mjs +0 -4
  30. package/template/old/package.json +0 -87
  31. package/template/old/postcss.config.mjs +0 -8
  32. package/template/old/prettier.config.mjs +0 -11
  33. package/template/old/public/next.svg +0 -1
  34. package/template/old/public/vercel.svg +0 -1
  35. package/template/old/src/app/(app)/dashboard/layout.tsx +0 -14
  36. package/template/old/src/app/(app)/dashboard/page.tsx +0 -12
  37. package/template/old/src/app/(app)/layout.tsx +0 -125
  38. package/template/old/src/app/(app)/roles/[id]/actions.ts +0 -59
  39. package/template/old/src/app/(app)/roles/[id]/page.tsx +0 -46
  40. package/template/old/src/app/(app)/roles/[id]/render.tsx +0 -264
  41. package/template/old/src/app/(app)/roles/[id]/validation.ts +0 -22
  42. package/template/old/src/app/(app)/roles/actions.ts +0 -33
  43. package/template/old/src/app/(app)/roles/page.tsx +0 -52
  44. package/template/old/src/app/(app)/roles/render.tsx +0 -80
  45. package/template/old/src/app/(app)/settings/actions.ts +0 -17
  46. package/template/old/src/app/(app)/settings/layout.tsx +0 -14
  47. package/template/old/src/app/(app)/settings/loading.tsx +0 -28
  48. package/template/old/src/app/(app)/settings/page.tsx +0 -19
  49. package/template/old/src/app/(app)/settings/render.tsx +0 -107
  50. package/template/old/src/app/(app)/settings/validation.ts +0 -5
  51. package/template/old/src/app/(app)/tasks/[id]/actions.ts +0 -92
  52. package/template/old/src/app/(app)/tasks/[id]/page.tsx +0 -59
  53. package/template/old/src/app/(app)/tasks/[id]/render.tsx +0 -482
  54. package/template/old/src/app/(app)/tasks/[id]/validation.ts +0 -18
  55. package/template/old/src/app/(app)/tasks/actions.ts +0 -39
  56. package/template/old/src/app/(app)/tasks/page.tsx +0 -59
  57. package/template/old/src/app/(app)/tasks/render.tsx +0 -129
  58. package/template/old/src/app/(app)/tasks/statusEnum.ts +0 -3
  59. package/template/old/src/app/(app)/users/[id]/actions.ts +0 -68
  60. package/template/old/src/app/(app)/users/[id]/page.tsx +0 -39
  61. package/template/old/src/app/(app)/users/[id]/render.tsx +0 -325
  62. package/template/old/src/app/(app)/users/[id]/validation.ts +0 -18
  63. package/template/old/src/app/(app)/users/actions.ts +0 -34
  64. package/template/old/src/app/(app)/users/page.tsx +0 -62
  65. package/template/old/src/app/(app)/users/render.tsx +0 -124
  66. package/template/old/src/app/(auth)/layout.tsx +0 -27
  67. package/template/old/src/app/(auth)/login/page.tsx +0 -49
  68. package/template/old/src/app/(auth)/login/render.tsx +0 -146
  69. package/template/old/src/app/(marketing)/layout.tsx +0 -42
  70. package/template/old/src/app/(marketing)/page.tsx +0 -97
  71. package/template/old/src/app/api/auth/[...nextauth]/route.ts +0 -7
  72. package/template/old/src/app/favicon.ico +0 -0
  73. package/template/old/src/app/globals.css +0 -76
  74. package/template/old/src/app/layout.tsx +0 -31
  75. package/template/old/src/components/app-nav-command.tsx +0 -178
  76. package/template/old/src/components/dark-mode-toggle.tsx +0 -43
  77. package/template/old/src/components/data-table/data-table-column-header.tsx +0 -91
  78. package/template/old/src/components/data-table/data-table-faceted-filter.tsx +0 -149
  79. package/template/old/src/components/data-table/data-table-loading.tsx +0 -77
  80. package/template/old/src/components/data-table/data-table-pagination.tsx +0 -94
  81. package/template/old/src/components/data-table/data-table-toolbar.tsx +0 -78
  82. package/template/old/src/components/data-table/data-table-types.ts +0 -17
  83. package/template/old/src/components/data-table/data-table-view-options.tsx +0 -59
  84. package/template/old/src/components/data-table/data-table.tsx +0 -301
  85. package/template/old/src/components/data-table/simple-data-table.tsx +0 -109
  86. package/template/old/src/components/empty-placeholder.tsx +0 -78
  87. package/template/old/src/components/heading.tsx +0 -17
  88. package/template/old/src/components/icons.tsx +0 -101
  89. package/template/old/src/components/main-nav.tsx +0 -64
  90. package/template/old/src/components/mobile-nav.tsx +0 -50
  91. package/template/old/src/components/shell.tsx +0 -13
  92. package/template/old/src/components/side-nav.tsx +0 -51
  93. package/template/old/src/components/site-footer.tsx +0 -31
  94. package/template/old/src/components/system-info.tsx +0 -36
  95. package/template/old/src/components/ui/alert-dialog.tsx +0 -141
  96. package/template/old/src/components/ui/avatar.tsx +0 -50
  97. package/template/old/src/components/ui/badge.tsx +0 -36
  98. package/template/old/src/components/ui/button.tsx +0 -56
  99. package/template/old/src/components/ui/card.tsx +0 -79
  100. package/template/old/src/components/ui/checkbox.tsx +0 -30
  101. package/template/old/src/components/ui/command.tsx +0 -155
  102. package/template/old/src/components/ui/dialog.tsx +0 -122
  103. package/template/old/src/components/ui/dropdown-menu.tsx +0 -200
  104. package/template/old/src/components/ui/form.tsx +0 -176
  105. package/template/old/src/components/ui/input.tsx +0 -25
  106. package/template/old/src/components/ui/label.tsx +0 -26
  107. package/template/old/src/components/ui/popover.tsx +0 -31
  108. package/template/old/src/components/ui/select.tsx +0 -160
  109. package/template/old/src/components/ui/separator.tsx +0 -31
  110. package/template/old/src/components/ui/skeleton.tsx +0 -15
  111. package/template/old/src/components/ui/sonner.tsx +0 -31
  112. package/template/old/src/components/ui/table.tsx +0 -117
  113. package/template/old/src/components/user-account-nav.tsx +0 -60
  114. package/template/old/src/components/user-avatar.tsx +0 -27
  115. package/template/old/src/data-access/resource.ts +0 -85
  116. package/template/old/src/data-access/role-permission.ts +0 -45
  117. package/template/old/src/data-access/role.ts +0 -105
  118. package/template/old/src/data-access/task.ts +0 -141
  119. package/template/old/src/data-access/user.ts +0 -141
  120. package/template/old/src/db/index.ts +0 -14
  121. package/template/old/src/db/schema.ts +0 -287
  122. package/template/old/src/env.mjs +0 -58
  123. package/template/old/src/hooks/use-debounce.tsx +0 -17
  124. package/template/old/src/hooks/use-lock-body.tsx +0 -13
  125. package/template/old/src/lib/auth.ts +0 -89
  126. package/template/old/src/lib/cn.ts +0 -4
  127. package/template/old/src/lib/currentUser.ts +0 -8
  128. package/template/old/src/lib/delay.ts +0 -2
  129. package/template/old/src/lib/formatDate.ts +0 -11
  130. package/template/old/src/lib/generateLabel.ts +0 -5
  131. package/template/old/src/lib/s3Client.ts +0 -156
  132. package/template/old/src/lib/safe-action.ts +0 -19
  133. package/template/old/src/lib/siteConfig.ts +0 -4
  134. package/template/old/src/lib/sortOrderEnum.ts +0 -2
  135. package/template/old/src/use-case/role-permission.ts +0 -19
  136. package/template/old/src/use-case/role.ts +0 -110
  137. package/template/old/src/use-case/task.ts +0 -166
  138. package/template/old/src/use-case/user.ts +0 -121
  139. package/template/old/tailwind.config.ts +0 -81
  140. package/template/old/tsconfig.json +0 -47
@@ -1,78 +0,0 @@
1
- 'use client'
2
-
3
- import type { Table } from '@tanstack/react-table'
4
-
5
- import { DataTableFacetedFilter } from '@/components/data-table/data-table-faceted-filter'
6
- import { DataTableViewOptions } from '@/components/data-table/data-table-view-options'
7
- import { Icons } from '@/components/icons'
8
- import { Button } from '@/components/ui/button'
9
- import { Input } from '@/components/ui/input'
10
- import {
11
- DataTableFilterableColumn,
12
- DataTableSearchableColumn
13
- } from './data-table-types'
14
-
15
- interface DataTableToolbarProps<TData> {
16
- table: Table<TData>
17
- filterableColumns?: DataTableFilterableColumn<TData>[]
18
- searchableColumns?: DataTableSearchableColumn<TData>[]
19
- }
20
-
21
- export function DataTableToolbar<TData>({
22
- table,
23
- filterableColumns = [],
24
- searchableColumns = []
25
- }: DataTableToolbarProps<TData>) {
26
- const isFiltered = table.getState().columnFilters.length > 0
27
-
28
- return (
29
- <div className="flex items-center justify-between p-1">
30
- <div className="flex flex-1 items-center space-x-2">
31
- {searchableColumns.length > 0 &&
32
- searchableColumns.map(
33
- column =>
34
- table.getColumn(column.id ? String(column.id) : '') && (
35
- <Input
36
- key={String(column.id)}
37
- placeholder={`Filter ${column.title}...`}
38
- value={
39
- (table
40
- .getColumn(String(column.id))
41
- ?.getFilterValue() as string) ?? ''
42
- }
43
- onChange={event =>
44
- table
45
- .getColumn(String(column.id))
46
- ?.setFilterValue(event.target.value)
47
- }
48
- className="h-8 w-[150px] lg:w-[250px]"
49
- />
50
- )
51
- )}
52
- {filterableColumns.length > 0 &&
53
- filterableColumns.map(
54
- column =>
55
- table.getColumn(column.id ? String(column.id) : '') && (
56
- <DataTableFacetedFilter
57
- key={String(column.id)}
58
- column={table.getColumn(column.id ? String(column.id) : '')}
59
- title={column.title}
60
- options={column.options}
61
- />
62
- )
63
- )}
64
- {isFiltered && (
65
- <Button
66
- variant="ghost"
67
- onClick={() => table.resetColumnFilters()}
68
- className="h-8 px-2 lg:px-3"
69
- >
70
- Reset
71
- <Icons.close className="ml-2 h-4 w-4" />
72
- </Button>
73
- )}
74
- </div>
75
- <DataTableViewOptions table={table} />
76
- </div>
77
- )
78
- }
@@ -1,17 +0,0 @@
1
- import { ComponentType } from 'react'
2
-
3
- export type Option = {
4
- label: string
5
- value: string
6
- icon?: ComponentType<{ className?: string }>
7
- }
8
-
9
- export interface DataTableSearchableColumn<TData> {
10
- id: keyof TData
11
- title: string
12
- }
13
-
14
- export interface DataTableFilterableColumn<TData>
15
- extends DataTableSearchableColumn<TData> {
16
- options: Option[]
17
- }
@@ -1,59 +0,0 @@
1
- 'use client'
2
-
3
- import { DropdownMenuTrigger } from '@radix-ui/react-dropdown-menu'
4
- import { type Table } from '@tanstack/react-table'
5
-
6
- import { Icons } from '@/components/icons'
7
- import { Button } from '@/components/ui/button'
8
- import {
9
- DropdownMenu,
10
- DropdownMenuCheckboxItem,
11
- DropdownMenuContent,
12
- DropdownMenuLabel,
13
- DropdownMenuSeparator
14
- } from '@/components/ui/dropdown-menu'
15
-
16
- interface DataTableViewOptionsProps<TData> {
17
- table: Table<TData>
18
- }
19
-
20
- export function DataTableViewOptions<TData>({
21
- table
22
- }: DataTableViewOptionsProps<TData>) {
23
- return (
24
- <DropdownMenu>
25
- <DropdownMenuTrigger asChild>
26
- <Button
27
- variant="outline"
28
- size="sm"
29
- className="ml-auto hidden h-8 lg:flex"
30
- >
31
- <Icons.mixer className="mr-2 h-4 w-4" />
32
- View
33
- </Button>
34
- </DropdownMenuTrigger>
35
- <DropdownMenuContent align="end" className="w-[150px]">
36
- <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
37
- <DropdownMenuSeparator />
38
- {table
39
- .getAllColumns()
40
- .filter(
41
- column =>
42
- typeof column.accessorFn !== 'undefined' && column.getCanHide()
43
- )
44
- .map(column => {
45
- return (
46
- <DropdownMenuCheckboxItem
47
- key={column.id}
48
- className="capitalize"
49
- checked={column.getIsVisible()}
50
- onCheckedChange={value => column.toggleVisibility(!!value)}
51
- >
52
- {column.id}
53
- </DropdownMenuCheckboxItem>
54
- )
55
- })}
56
- </DropdownMenuContent>
57
- </DropdownMenu>
58
- )
59
- }
@@ -1,301 +0,0 @@
1
- 'use client'
2
-
3
- import {
4
- flexRender,
5
- getCoreRowModel,
6
- getFacetedRowModel,
7
- getFacetedUniqueValues,
8
- getFilteredRowModel,
9
- getPaginationRowModel,
10
- getSortedRowModel,
11
- useReactTable,
12
- type ColumnDef,
13
- type ColumnFiltersState,
14
- type PaginationState,
15
- type SortingState,
16
- type VisibilityState
17
- } from '@tanstack/react-table'
18
- import { usePathname, useRouter, useSearchParams } from 'next/navigation'
19
-
20
- import { DataTablePagination } from '@/components/data-table/data-table-pagination'
21
- import { DataTableToolbar } from '@/components/data-table/data-table-toolbar'
22
- import {
23
- Table,
24
- TableBody,
25
- TableCell,
26
- TableHead,
27
- TableHeader,
28
- TableRow
29
- } from '@/components/ui/table'
30
- import { useDebounce } from '@/hooks/use-debounce'
31
- import { useCallback, useEffect, useMemo, useState } from 'react'
32
- import {
33
- DataTableFilterableColumn,
34
- DataTableSearchableColumn
35
- } from './data-table-types'
36
-
37
- interface DataTableProps<TData, TValue> {
38
- columns: ColumnDef<TData, TValue>[]
39
- data: TData[]
40
- total: number
41
- filterableColumns?: DataTableFilterableColumn<TData>[]
42
- searchableColumns?: DataTableSearchableColumn<TData>[]
43
- }
44
-
45
- export function DataTable<TData, TValue>({
46
- columns,
47
- data,
48
- total,
49
- filterableColumns = [],
50
- searchableColumns = []
51
- }: DataTableProps<TData, TValue>) {
52
- const router = useRouter()
53
- const pathname = usePathname()
54
- const searchParams = useSearchParams()
55
-
56
- // Search params
57
- const page = searchParams?.get('page') ?? '1'
58
- const limit = searchParams?.get('limit') ?? '10'
59
- const sort = searchParams?.get('sort')
60
- const [column, order] = sort?.split('.') ?? []
61
-
62
- // Create query string
63
- const createQueryString = useCallback(
64
- (params: Record<string, string | number | null>) => {
65
- const newSearchParams = new URLSearchParams(searchParams?.toString())
66
-
67
- for (const [key, value] of Object.entries(params)) {
68
- if (value === null) {
69
- newSearchParams.delete(key)
70
- } else {
71
- newSearchParams.set(key, String(value))
72
- }
73
- }
74
-
75
- return newSearchParams.toString()
76
- },
77
- [searchParams]
78
- )
79
-
80
- // Table states
81
- const [rowSelection, setRowSelection] = useState({})
82
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
83
- const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
84
-
85
- // Handle server-side pagination
86
- const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({
87
- pageIndex: Number(page) - 1,
88
- pageSize: Number(limit)
89
- })
90
-
91
- const pagination = useMemo(
92
- () => ({
93
- pageIndex,
94
- pageSize
95
- }),
96
- [pageIndex, pageSize]
97
- )
98
-
99
- useEffect(() => {
100
- setPagination({
101
- pageIndex: Number(page) - 1,
102
- pageSize: Number(limit)
103
- })
104
- }, [page, limit])
105
-
106
- useEffect(() => {
107
- router.push(
108
- `${pathname}?${createQueryString({
109
- page: pageIndex + 1,
110
- limit: pageSize
111
- })}`
112
- )
113
- // eslint-disable-next-line react-hooks/exhaustive-deps
114
- }, [pageIndex, pageSize])
115
-
116
- // Handle server-side sorting
117
- const [sorting, setSorting] = useState<SortingState>([
118
- {
119
- id: column ?? '',
120
- desc: order === 'desc'
121
- }
122
- ])
123
-
124
- useEffect(() => {
125
- router.push(
126
- `${pathname}?${createQueryString({
127
- page,
128
- sort: sorting[0]?.id
129
- ? `${sorting[0]?.id}.${sorting[0]?.desc ? 'desc' : 'asc'}`
130
- : null
131
- })}`
132
- )
133
- // eslint-disable-next-line react-hooks/exhaustive-deps
134
- }, [sorting])
135
-
136
- // Handle server-side filtering
137
- const debouncedSearchableColumnFilters = JSON.parse(
138
- useDebounce(
139
- JSON.stringify(
140
- columnFilters.filter(filter => {
141
- return searchableColumns.find(column => column.id === filter.id)
142
- })
143
- ),
144
- 500
145
- )
146
- ) as ColumnFiltersState
147
-
148
- const filterableColumnFilters = columnFilters.filter(filter => {
149
- return filterableColumns.find(column => column.id === filter.id)
150
- })
151
-
152
- useEffect(() => {
153
- for (const column of debouncedSearchableColumnFilters) {
154
- if (typeof column.value === 'string') {
155
- router.push(
156
- `${pathname}?${createQueryString({
157
- page: 1,
158
- [column.id]: typeof column.value === 'string' ? column.value : null
159
- })}`
160
- )
161
- }
162
- }
163
-
164
- for (const key of searchParams.keys()) {
165
- if (
166
- searchableColumns.find(column => column.id === key) &&
167
- !debouncedSearchableColumnFilters.find(column => column.id === key)
168
- ) {
169
- router.push(
170
- `${pathname}?${createQueryString({
171
- page: 1,
172
- [key]: null
173
- })}`
174
- )
175
- }
176
- }
177
- // eslint-disable-next-line react-hooks/exhaustive-deps
178
- }, [JSON.stringify(debouncedSearchableColumnFilters)])
179
-
180
- useEffect(() => {
181
- for (const column of filterableColumnFilters) {
182
- if (typeof column.value === 'object' && Array.isArray(column.value)) {
183
- router.push(
184
- `${pathname}?${createQueryString({
185
- page: 1,
186
- [column.id]: column.value.join('.')
187
- })}`
188
- )
189
- }
190
- }
191
-
192
- for (const key of searchParams.keys()) {
193
- if (
194
- filterableColumns.find(column => column.id === key) &&
195
- !filterableColumnFilters.find(column => column.id === key)
196
- ) {
197
- router.push(
198
- `${pathname}?${createQueryString({
199
- page: 1,
200
- [key]: null
201
- })}`
202
- )
203
- }
204
- }
205
- // eslint-disable-next-line react-hooks/exhaustive-deps
206
- }, [JSON.stringify(filterableColumnFilters)])
207
-
208
- const pageCount = useMemo(
209
- () => Math.ceil(total / pageSize),
210
- [total, pageSize]
211
- )
212
-
213
- const table = useReactTable({
214
- data,
215
- columns,
216
- pageCount,
217
- state: {
218
- pagination,
219
- sorting,
220
- columnVisibility,
221
- rowSelection,
222
- columnFilters
223
- },
224
- enableRowSelection: true,
225
- onRowSelectionChange: setRowSelection,
226
- onPaginationChange: setPagination,
227
- onSortingChange: setSorting,
228
- onColumnFiltersChange: setColumnFilters,
229
- onColumnVisibilityChange: setColumnVisibility,
230
- getCoreRowModel: getCoreRowModel(),
231
- getFilteredRowModel: getFilteredRowModel(),
232
- getPaginationRowModel: getPaginationRowModel(),
233
- getSortedRowModel: getSortedRowModel(),
234
- getFacetedRowModel: getFacetedRowModel(),
235
- getFacetedUniqueValues: getFacetedUniqueValues(),
236
- manualPagination: true,
237
- manualSorting: true,
238
- manualFiltering: true
239
- })
240
-
241
- return (
242
- <div className="w-full space-y-4 overflow-auto">
243
- <DataTableToolbar
244
- table={table}
245
- filterableColumns={filterableColumns}
246
- searchableColumns={searchableColumns}
247
- />
248
- <div className="rounded-md border">
249
- <Table>
250
- <TableHeader>
251
- {table.getHeaderGroups().map(headerGroup => (
252
- <TableRow key={headerGroup.id}>
253
- {headerGroup.headers.map(header => {
254
- return (
255
- <TableHead key={header.id}>
256
- {header.isPlaceholder
257
- ? null
258
- : flexRender(
259
- header.column.columnDef.header,
260
- header.getContext()
261
- )}
262
- </TableHead>
263
- )
264
- })}
265
- </TableRow>
266
- ))}
267
- </TableHeader>
268
- <TableBody>
269
- {table.getRowModel().rows?.length ? (
270
- table.getRowModel().rows.map(row => (
271
- <TableRow
272
- key={row.id}
273
- data-state={row.getIsSelected() && 'selected'}
274
- >
275
- {row.getVisibleCells().map(cell => (
276
- <TableCell key={cell.id}>
277
- {flexRender(
278
- cell.column.columnDef.cell,
279
- cell.getContext()
280
- )}
281
- </TableCell>
282
- ))}
283
- </TableRow>
284
- ))
285
- ) : (
286
- <TableRow>
287
- <TableCell
288
- colSpan={columns.length}
289
- className="h-24 text-center"
290
- >
291
- No results.
292
- </TableCell>
293
- </TableRow>
294
- )}
295
- </TableBody>
296
- </Table>
297
- </div>
298
- <DataTablePagination table={table} />
299
- </div>
300
- )
301
- }
@@ -1,109 +0,0 @@
1
- 'use client'
2
-
3
- import {
4
- ColumnDef,
5
- flexRender,
6
- getCoreRowModel,
7
- getPaginationRowModel,
8
- useReactTable
9
- } from '@tanstack/react-table'
10
-
11
- import { Button } from '@/components/ui/button'
12
- import {
13
- Table,
14
- TableBody,
15
- TableCell,
16
- TableHead,
17
- TableHeader,
18
- TableRow
19
- } from '@/components/ui/table'
20
-
21
- interface DataTableProps<TData, TValue> {
22
- columns: ColumnDef<TData, TValue>[]
23
- data: TData[]
24
- }
25
-
26
- export function SimpleDataTable<TData, TValue>({
27
- columns,
28
- data
29
- }: DataTableProps<TData, TValue>) {
30
- const table = useReactTable({
31
- data,
32
- columns,
33
- getCoreRowModel: getCoreRowModel(),
34
- getPaginationRowModel: getPaginationRowModel()
35
- })
36
-
37
- return (
38
- <div>
39
- <div className="rounded-md border">
40
- <Table>
41
- <TableHeader>
42
- {table.getHeaderGroups().map(headerGroup => (
43
- <TableRow key={headerGroup.id}>
44
- {headerGroup.headers.map(header => {
45
- return (
46
- <TableHead key={header.id}>
47
- {header.isPlaceholder
48
- ? null
49
- : flexRender(
50
- header.column.columnDef.header,
51
- header.getContext()
52
- )}
53
- </TableHead>
54
- )
55
- })}
56
- </TableRow>
57
- ))}
58
- </TableHeader>
59
- <TableBody>
60
- {table.getRowModel().rows?.length ? (
61
- table.getRowModel().rows.map(row => (
62
- <TableRow
63
- key={row.id}
64
- data-state={row.getIsSelected() && 'selected'}
65
- >
66
- {row.getVisibleCells().map(cell => (
67
- <TableCell key={cell.id}>
68
- {flexRender(
69
- cell.column.columnDef.cell,
70
- cell.getContext()
71
- )}
72
- </TableCell>
73
- ))}
74
- </TableRow>
75
- ))
76
- ) : (
77
- <TableRow>
78
- <TableCell
79
- colSpan={columns.length}
80
- className="h-24 text-center"
81
- >
82
- No results.
83
- </TableCell>
84
- </TableRow>
85
- )}
86
- </TableBody>
87
- </Table>
88
- </div>
89
- <div className="flex items-center justify-end space-x-2 py-4">
90
- <Button
91
- variant="outline"
92
- size="sm"
93
- onClick={() => table.previousPage()}
94
- disabled={!table.getCanPreviousPage()}
95
- >
96
- Previous
97
- </Button>
98
- <Button
99
- variant="outline"
100
- size="sm"
101
- onClick={() => table.nextPage()}
102
- disabled={!table.getCanNextPage()}
103
- >
104
- Next
105
- </Button>
106
- </div>
107
- </div>
108
- )
109
- }
@@ -1,78 +0,0 @@
1
- import * as React from 'react'
2
-
3
- import { Icons } from '@/components/icons'
4
- import { cn } from '@/lib/cn'
5
-
6
- interface EmptyPlaceholderProps extends React.HTMLAttributes<HTMLDivElement> {}
7
-
8
- export function EmptyPlaceholder({
9
- className,
10
- children,
11
- ...props
12
- }: EmptyPlaceholderProps) {
13
- return (
14
- <div
15
- className={cn(
16
- 'flex min-h-[400px] flex-col items-center justify-center rounded-md border border-dashed p-8 text-center animate-in fade-in-50',
17
- className
18
- )}
19
- {...props}
20
- >
21
- <div className="mx-auto flex max-w-[420px] flex-col items-center justify-center text-center">
22
- {children}
23
- </div>
24
- </div>
25
- )
26
- }
27
-
28
- interface EmptyPlaceholderIconProps
29
- extends Partial<React.SVGProps<SVGSVGElement>> {
30
- name: keyof typeof Icons
31
- }
32
-
33
- EmptyPlaceholder.Icon = function EmptyPlaceHolderIcon({
34
- name,
35
- className
36
- }: EmptyPlaceholderIconProps) {
37
- const Icon = Icons[name]
38
-
39
- if (!Icon) {
40
- return null
41
- }
42
-
43
- return (
44
- <div className="flex h-20 w-20 items-center justify-center rounded-full bg-muted">
45
- <Icon className={cn('h-10 w-10', className)} />
46
- </div>
47
- )
48
- }
49
-
50
- interface EmptyPlacholderTitleProps
51
- extends React.HTMLAttributes<HTMLHeadingElement> {}
52
-
53
- EmptyPlaceholder.Title = function EmptyPlaceholderTitle({
54
- className,
55
- ...props
56
- }: EmptyPlacholderTitleProps) {
57
- return (
58
- <h2 className={cn('mt-6 text-xl font-semibold', className)} {...props} />
59
- )
60
- }
61
-
62
- interface EmptyPlacholderDescriptionProps
63
- extends React.HTMLAttributes<HTMLParagraphElement> {}
64
-
65
- EmptyPlaceholder.Description = function EmptyPlaceholderDescription({
66
- className,
67
- ...props
68
- }: EmptyPlacholderDescriptionProps) {
69
- return (
70
- <p
71
- className={cn(
72
- 'mb-8 mt-2 text-center text-sm font-normal leading-6 text-muted-foreground',
73
- className
74
- )}
75
- {...props}
76
- />
77
- )
78
- }
@@ -1,17 +0,0 @@
1
- import { FC, ReactNode } from 'react'
2
-
3
- export const Heading: FC<{
4
- heading: string
5
- text?: string
6
- children?: ReactNode
7
- }> = ({ heading, text, children }) => {
8
- return (
9
- <div className="flex items-center justify-between px-2">
10
- <div className="grid gap-1">
11
- <h1 className="font-heading text-3xl md:text-4xl">{heading}</h1>
12
- {text && <p className="text-lg text-muted-foreground">{text}</p>}
13
- </div>
14
- {children}
15
- </div>
16
- )
17
- }