@igstack/app-catalog-frontend-core 0.2.0 → 0.3.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 (192) hide show
  1. package/dist/esm/api/infra/trpc.d.ts +0 -1491
  2. package/dist/esm/modules/appCatalog/context/AppCatalogContext.js +1 -0
  3. package/dist/esm/modules/appCatalog/context/AppCatalogContext.js.map +1 -1
  4. package/dist/esm/modules/appCatalog/ui/filters/FilterBar.js +23 -11
  5. package/dist/esm/modules/appCatalog/ui/filters/FilterBar.js.map +1 -1
  6. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.d.ts +5 -1
  7. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js +146 -56
  8. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js.map +1 -1
  9. package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js +20 -1
  10. package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js.map +1 -1
  11. package/dist/esm/modules/auth/AuthContext.js +1 -1
  12. package/dist/esm/modules/auth/AuthModalContext.js +1 -1
  13. package/dist/esm/modules/auth/authClient.d.ts +2 -2
  14. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/classic/schemas.js +4 -37
  15. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/classic/schemas.js.map +1 -1
  16. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/api.js +2 -10
  17. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/api.js.map +1 -1
  18. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/checks.js +1 -1
  19. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/json-schema-processors.js +0 -44
  20. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/json-schema-processors.js.map +1 -1
  21. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/parse.js +0 -4
  22. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/parse.js.map +1 -1
  23. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/regexes.js +0 -2
  24. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/regexes.js.map +1 -1
  25. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/schemas.js +4 -49
  26. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/schemas.js.map +1 -1
  27. package/dist/esm/routeTree.gen.d.ts +3 -164
  28. package/dist/esm/routeTree.gen.js +8 -80
  29. package/dist/esm/routeTree.gen.js.map +1 -1
  30. package/dist/esm/ui/button.d.ts +1 -1
  31. package/dist/esm/ui/card.js +1 -48
  32. package/dist/esm/ui/card.js.map +1 -1
  33. package/dist/esm/ui/command.js +1 -15
  34. package/dist/esm/ui/command.js.map +1 -1
  35. package/dist/esm/ui/components/header/Header.js +2 -11
  36. package/dist/esm/ui/components/header/Header.js.map +1 -1
  37. package/dist/esm/ui/input-group.js +125 -0
  38. package/dist/esm/ui/input-group.js.map +1 -0
  39. package/package.json +3 -3
  40. package/src/modules/appCatalog/ui/components/AppDetailModal.tsx +2 -21
  41. package/src/routeTree.gen.ts +2 -220
  42. package/src/ui/components/header/Header.tsx +2 -12
  43. package/dist/esm/components/IconPickerDialog.d.ts +0 -8
  44. package/dist/esm/components/IconPickerDialog.js +0 -98
  45. package/dist/esm/components/IconPickerDialog.js.map +0 -1
  46. package/dist/esm/components/IconPickerField.d.ts +0 -9
  47. package/dist/esm/components/IconPickerField.js +0 -76
  48. package/dist/esm/components/IconPickerField.js.map +0 -1
  49. package/dist/esm/modules/admin-base/components/AdminChat.d.ts +0 -1
  50. package/dist/esm/modules/admin-base/components/AdminChat.js +0 -82
  51. package/dist/esm/modules/admin-base/components/AdminChat.js.map +0 -1
  52. package/dist/esm/modules/admin-base/components/AdminLayout.d.ts +0 -5
  53. package/dist/esm/modules/admin-base/components/AdminLayout.js +0 -83
  54. package/dist/esm/modules/admin-base/components/AdminLayout.js.map +0 -1
  55. package/dist/esm/modules/admin-base/components/AdminWelcome.d.ts +0 -1
  56. package/dist/esm/modules/admin-base/components/AdminWelcome.js +0 -37
  57. package/dist/esm/modules/admin-base/components/AdminWelcome.js.map +0 -1
  58. package/dist/esm/modules/admin-base/context/AdminConfigContext.d.ts +0 -8
  59. package/dist/esm/modules/admin-base/context/AdminConfigContext.js +0 -27
  60. package/dist/esm/modules/admin-base/context/AdminConfigContext.js.map +0 -1
  61. package/dist/esm/modules/admin-base/index.d.ts +0 -5
  62. package/dist/esm/modules/admin-base/types/adminTypes.d.ts +0 -10
  63. package/dist/esm/modules/appCatalog/AppCatalogAdminPage.d.ts +0 -1
  64. package/dist/esm/modules/appCatalog/AppCatalogAdminPage.js +0 -196
  65. package/dist/esm/modules/appCatalog/AppCatalogAdminPage.js.map +0 -1
  66. package/dist/esm/modules/appCatalog/ScreenshotItem.js +0 -57
  67. package/dist/esm/modules/appCatalog/ScreenshotItem.js.map +0 -1
  68. package/dist/esm/modules/appCatalog/ScreenshotManager.js +0 -155
  69. package/dist/esm/modules/appCatalog/ScreenshotManager.js.map +0 -1
  70. package/dist/esm/modules/approvalMethod/AccessRequestFormFields.d.ts +0 -7
  71. package/dist/esm/modules/approvalMethod/AccessRequestFormFields.js +0 -323
  72. package/dist/esm/modules/approvalMethod/AccessRequestFormFields.js.map +0 -1
  73. package/dist/esm/modules/approvalMethod/ApprovalMethodForm.d.ts +0 -14
  74. package/dist/esm/modules/approvalMethod/ApprovalMethodForm.js +0 -227
  75. package/dist/esm/modules/approvalMethod/ApprovalMethodForm.js.map +0 -1
  76. package/dist/esm/modules/approvalMethod/ApprovalMethodSelector.d.ts +0 -7
  77. package/dist/esm/modules/approvalMethod/ApprovalMethodSelector.js +0 -124
  78. package/dist/esm/modules/approvalMethod/ApprovalMethodSelector.js.map +0 -1
  79. package/dist/esm/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.d.ts +0 -381
  80. package/dist/esm/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.js +0 -26
  81. package/dist/esm/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.js.map +0 -1
  82. package/dist/esm/modules/auth/authUtils.js +0 -25
  83. package/dist/esm/modules/auth/authUtils.js.map +0 -1
  84. package/dist/esm/modules/icons/IconManagementPage.d.ts +0 -1
  85. package/dist/esm/modules/icons/IconManagementPage.js +0 -177
  86. package/dist/esm/modules/icons/IconManagementPage.js.map +0 -1
  87. package/dist/esm/node_modules/.pnpm/@dnd-kit_accessibility@3.1.1_react@19.1.2/node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js +0 -60
  88. package/dist/esm/node_modules/.pnpm/@dnd-kit_accessibility@3.1.1_react@19.1.2/node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js.map +0 -1
  89. package/dist/esm/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.1.2_react@19.1.2__react@19.1.2/node_modules/@dnd-kit/core/dist/core.esm.js +0 -3055
  90. package/dist/esm/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.1.2_react@19.1.2__react@19.1.2/node_modules/@dnd-kit/core/dist/core.esm.js.map +0 -1
  91. package/dist/esm/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.1.2_react@19.1.2__react@19.1.2__react@19.1.2/node_modules/@dnd-kit/sortable/dist/sortable.esm.js +0 -593
  92. package/dist/esm/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.1.2_react@19.1.2__react@19.1.2__react@19.1.2/node_modules/@dnd-kit/sortable/dist/sortable.esm.js.map +0 -1
  93. package/dist/esm/node_modules/.pnpm/@dnd-kit_utilities@3.2.2_react@19.1.2/node_modules/@dnd-kit/utilities/dist/utilities.esm.js +0 -302
  94. package/dist/esm/node_modules/.pnpm/@dnd-kit_utilities@3.2.2_react@19.1.2/node_modules/@dnd-kit/utilities/dist/utilities.esm.js.map +0 -1
  95. package/dist/esm/node_modules/.pnpm/@hookform_resolvers@5.2.2_react-hook-form@7.71.1_react@19.1.2_/node_modules/@hookform/resolvers/dist/resolvers.js +0 -34
  96. package/dist/esm/node_modules/.pnpm/@hookform_resolvers@5.2.2_react-hook-form@7.71.1_react@19.1.2_/node_modules/@hookform/resolvers/dist/resolvers.js.map +0 -1
  97. package/dist/esm/node_modules/.pnpm/@hookform_resolvers@5.2.2_react-hook-form@7.71.1_react@19.1.2_/node_modules/@hookform/resolvers/zod/dist/zod.js +0 -94
  98. package/dist/esm/node_modules/.pnpm/@hookform_resolvers@5.2.2_react-hook-form@7.71.1_react@19.1.2_/node_modules/@hookform/resolvers/zod/dist/zod.js.map +0 -1
  99. package/dist/esm/node_modules/.pnpm/react-hook-form@7.71.1_react@19.1.2/node_modules/react-hook-form/dist/index.esm.js +0 -1894
  100. package/dist/esm/node_modules/.pnpm/react-hook-form@7.71.1_react@19.1.2/node_modules/react-hook-form/dist/index.esm.js.map +0 -1
  101. package/dist/esm/routes/admin/app-for-catalog/$id.d.ts +0 -5
  102. package/dist/esm/routes/admin/app-for-catalog/_id.js +0 -67
  103. package/dist/esm/routes/admin/app-for-catalog/_id.js.map +0 -1
  104. package/dist/esm/routes/admin/app-for-catalog/_id2.js +0 -321
  105. package/dist/esm/routes/admin/app-for-catalog/_id2.js.map +0 -1
  106. package/dist/esm/routes/admin/app-for-catalog/index.d.ts +0 -1
  107. package/dist/esm/routes/admin/app-for-catalog/index.js +0 -9
  108. package/dist/esm/routes/admin/app-for-catalog/index.js.map +0 -1
  109. package/dist/esm/routes/admin/app-for-catalog/index2.js +0 -12
  110. package/dist/esm/routes/admin/app-for-catalog/index2.js.map +0 -1
  111. package/dist/esm/routes/admin/app-for-catalog.d.ts +0 -1
  112. package/dist/esm/routes/admin/app-for-catalog.js +0 -14
  113. package/dist/esm/routes/admin/app-for-catalog.js.map +0 -1
  114. package/dist/esm/routes/admin/app-for-catalog2.js +0 -9
  115. package/dist/esm/routes/admin/app-for-catalog2.js.map +0 -1
  116. package/dist/esm/routes/admin/approval-methods/index.d.ts +0 -32
  117. package/dist/esm/routes/admin/approval-methods/index.js +0 -24
  118. package/dist/esm/routes/admin/approval-methods/index.js.map +0 -1
  119. package/dist/esm/routes/admin/approval-methods/index2.js +0 -100
  120. package/dist/esm/routes/admin/approval-methods/index2.js.map +0 -1
  121. package/dist/esm/routes/admin/approval-methods.d.ts +0 -1
  122. package/dist/esm/routes/admin/approval-methods.js +0 -14
  123. package/dist/esm/routes/admin/approval-methods.js.map +0 -1
  124. package/dist/esm/routes/admin/approval-methods2.js +0 -7
  125. package/dist/esm/routes/admin/approval-methods2.js.map +0 -1
  126. package/dist/esm/routes/admin/chat.d.ts +0 -1
  127. package/dist/esm/routes/admin/chat.js +0 -14
  128. package/dist/esm/routes/admin/chat.js.map +0 -1
  129. package/dist/esm/routes/admin/chat2.js +0 -9
  130. package/dist/esm/routes/admin/chat2.js.map +0 -1
  131. package/dist/esm/routes/admin/icons.d.ts +0 -1
  132. package/dist/esm/routes/admin/icons.js +0 -14
  133. package/dist/esm/routes/admin/icons.js.map +0 -1
  134. package/dist/esm/routes/admin/icons2.js +0 -12
  135. package/dist/esm/routes/admin/icons2.js.map +0 -1
  136. package/dist/esm/routes/admin/index.d.ts +0 -1
  137. package/dist/esm/routes/admin/index.js +0 -9
  138. package/dist/esm/routes/admin/index.js.map +0 -1
  139. package/dist/esm/routes/admin/index2.js +0 -9
  140. package/dist/esm/routes/admin/index2.js.map +0 -1
  141. package/dist/esm/routes/admin.d.ts +0 -1
  142. package/dist/esm/routes/admin.js +0 -37
  143. package/dist/esm/routes/admin.js.map +0 -1
  144. package/dist/esm/routes/admin2.js +0 -18
  145. package/dist/esm/routes/admin2.js.map +0 -1
  146. package/dist/esm/ui/alert-dialog.js +0 -141
  147. package/dist/esm/ui/alert-dialog.js.map +0 -1
  148. package/dist/esm/ui/breadcrumb.js +0 -84
  149. package/dist/esm/ui/breadcrumb.js.map +0 -1
  150. package/dist/esm/ui/components/Breadcrumbs.js +0 -36
  151. package/dist/esm/ui/components/Breadcrumbs.js.map +0 -1
  152. package/dist/esm/ui/crud-list/CrudList.js +0 -189
  153. package/dist/esm/ui/crud-list/CrudList.js.map +0 -1
  154. package/dist/esm/ui/editable-list/EditableListField.js +0 -130
  155. package/dist/esm/ui/editable-list/EditableListField.js.map +0 -1
  156. package/dist/esm/ui/form.js +0 -134
  157. package/dist/esm/ui/form.js.map +0 -1
  158. package/dist/esm/ui/linkExternal.js +0 -26
  159. package/dist/esm/ui/linkExternal.js.map +0 -1
  160. package/dist/esm/ui/markdown-editor/MarkdownEditor.js +0 -116
  161. package/dist/esm/ui/markdown-editor/MarkdownEditor.js.map +0 -1
  162. package/dist/esm/ui/markdown-editor/MarkdownToolbar.js +0 -99
  163. package/dist/esm/ui/markdown-editor/MarkdownToolbar.js.map +0 -1
  164. package/dist/esm/ui/scroll-area.js +0 -62
  165. package/dist/esm/ui/scroll-area.js.map +0 -1
  166. package/dist/esm/ui/select.js +0 -138
  167. package/dist/esm/ui/select.js.map +0 -1
  168. package/dist/esm/ui/textarea.js +0 -19
  169. package/dist/esm/ui/textarea.js.map +0 -1
  170. package/src/components/IconPickerDialog.tsx +0 -136
  171. package/src/components/IconPickerField.tsx +0 -88
  172. package/src/modules/admin-base/components/AdminChat.tsx +0 -122
  173. package/src/modules/admin-base/components/AdminLayout.tsx +0 -111
  174. package/src/modules/admin-base/components/AdminWelcome.tsx +0 -52
  175. package/src/modules/admin-base/context/AdminConfigContext.tsx +0 -36
  176. package/src/modules/admin-base/index.ts +0 -16
  177. package/src/modules/admin-base/types/adminTypes.ts +0 -11
  178. package/src/modules/appCatalog/AppCatalogAdminPage.tsx +0 -274
  179. package/src/modules/approvalMethod/AccessRequestFormFields.tsx +0 -393
  180. package/src/modules/approvalMethod/ApprovalMethodForm.tsx +0 -323
  181. package/src/modules/approvalMethod/ApprovalMethodSelector.tsx +0 -150
  182. package/src/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.ts +0 -34
  183. package/src/modules/icons/IconManagementPage.tsx +0 -245
  184. package/src/routes/admin/app-for-catalog/$id.tsx +0 -571
  185. package/src/routes/admin/app-for-catalog/index.tsx +0 -19
  186. package/src/routes/admin/app-for-catalog.tsx +0 -12
  187. package/src/routes/admin/approval-methods/index.tsx +0 -161
  188. package/src/routes/admin/approval-methods.tsx +0 -10
  189. package/src/routes/admin/chat.tsx +0 -13
  190. package/src/routes/admin/icons.tsx +0 -22
  191. package/src/routes/admin/index.tsx +0 -9
  192. package/src/routes/admin.tsx +0 -60
@@ -1,274 +0,0 @@
1
- import type { AppForCatalog } from '@igstack/app-catalog-backend-core'
2
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
3
- import { Link } from '@tanstack/react-router'
4
- import {
5
- createColumnHelper,
6
- flexRender,
7
- getCoreRowModel,
8
- getFilteredRowModel,
9
- getSortedRowModel,
10
- useReactTable,
11
- } from '@tanstack/react-table'
12
- import { Edit, Plus, Trash2 } from 'lucide-react'
13
- import { useState } from 'react'
14
- import { useTRPC } from '~/api/infra/trpc'
15
- import { Button } from '~/ui/button'
16
- import {
17
- Card,
18
- CardContent,
19
- CardDescription,
20
- CardHeader,
21
- CardTitle,
22
- } from '~/ui/card'
23
- import { Input } from '~/ui/input'
24
- import {
25
- Table,
26
- TableBody,
27
- TableCell,
28
- TableHead,
29
- TableHeader,
30
- TableRow,
31
- } from '~/ui/table'
32
-
33
- // Extended type with DB fields
34
- type AppForCatalogRow = AppForCatalog & {
35
- slug: string
36
- links?: Array<{ displayName?: string; url: string }>
37
- screenshotIds?: Array<string>
38
- createdAt: string
39
- updatedAt: string
40
- }
41
-
42
- const columnHelper = createColumnHelper<AppForCatalogRow>()
43
-
44
- const columns = [
45
- columnHelper.accessor('slug', {
46
- header: 'Slug',
47
- cell: (info) => <code className="text-xs truncate">{info.getValue()}</code>,
48
- size: 100,
49
- }),
50
- columnHelper.accessor('displayName', {
51
- header: 'Name',
52
- cell: (info) => (
53
- <Link
54
- to="/admin/app-for-catalog/$id"
55
- params={{ id: info.row.original.slug }}
56
- >
57
- <span className="font-medium cursor-pointer hover:underline truncate">
58
- {info.getValue()}
59
- </span>
60
- </Link>
61
- ),
62
- size: 120,
63
- }),
64
- columnHelper.accessor('description', {
65
- header: 'Description',
66
- cell: (info) => {
67
- const desc = info.getValue()
68
- return (
69
- <span className="text-sm text-muted-foreground truncate" title={desc}>
70
- {desc}
71
- </span>
72
- )
73
- },
74
- size: 140,
75
- }),
76
- columnHelper.accessor('iconName', {
77
- header: 'Icon',
78
- cell: (info) => {
79
- const iconName = info.getValue()
80
- return iconName ? (
81
- <div className="w-8 h-8 flex items-center justify-center shrink-0">
82
- <img
83
- src={`/api/assets/by-name/${iconName}`}
84
- alt={iconName}
85
- className="max-w-full max-h-full object-contain"
86
- />
87
- </div>
88
- ) : (
89
- <span className="text-sm text-muted-foreground">-</span>
90
- )
91
- },
92
- size: 50,
93
- }),
94
- columnHelper.accessor('links', {
95
- header: 'Links',
96
- cell: (info) => (
97
- <span className="text-sm truncate">{info.getValue()?.length || 0}</span>
98
- ),
99
- size: 50,
100
- }),
101
- columnHelper.accessor('screenshotIds', {
102
- header: 'Screenshots',
103
- cell: (info) => (
104
- <span className="text-sm truncate">{info.getValue()?.length || 0}</span>
105
- ),
106
- size: 70,
107
- }),
108
- columnHelper.accessor('createdAt', {
109
- header: 'Created',
110
- cell: (info) => new Date(info.getValue()).toLocaleDateString(),
111
- size: 100,
112
- }),
113
- columnHelper.display({
114
- id: 'actions',
115
- header: 'Actions',
116
- cell: (props) => <AppActions app={props.row.original} />,
117
- size: 70,
118
- }),
119
- ]
120
-
121
- function AppActions({ app }: { app: AppForCatalogRow }) {
122
- const trpc = useTRPC()
123
- const queryClient = useQueryClient()
124
-
125
- const deleteMutation = useMutation({
126
- ...trpc.appCatalogAdmin.delete.mutationOptions(),
127
- onSuccess: () => {
128
- queryClient.invalidateQueries({
129
- queryKey: trpc.appCatalogAdmin.list.queryKey(),
130
- })
131
- },
132
- })
133
-
134
- return (
135
- <div className="flex gap-2">
136
- <Button variant="ghost" size="sm" asChild>
137
- <Link to="/admin/app-for-catalog/$id" params={{ id: app.slug }}>
138
- <Edit className="w-4 h-4" />
139
- </Link>
140
- </Button>
141
- <Button
142
- variant="ghost"
143
- size="sm"
144
- onClick={() => {
145
- if (
146
- confirm(`Are you sure you want to delete "${app.displayName}"?`)
147
- ) {
148
- deleteMutation.mutate({ id: app.id })
149
- }
150
- }}
151
- disabled={deleteMutation.isPending}
152
- >
153
- <Trash2 className="w-4 h-4" />
154
- </Button>
155
- </div>
156
- )
157
- }
158
-
159
- export function AppCatalogAdminPage() {
160
- const trpc = useTRPC()
161
- const [globalFilter, setGlobalFilter] = useState('')
162
-
163
- const { data: apps = [], isLoading } = useQuery({
164
- ...trpc.appCatalogAdmin.list.queryOptions(),
165
- })
166
-
167
- const table = useReactTable({
168
- data: apps as Array<AppForCatalogRow>,
169
- columns,
170
- getCoreRowModel: getCoreRowModel(),
171
- getFilteredRowModel: getFilteredRowModel(),
172
- getSortedRowModel: getSortedRowModel(),
173
- state: {
174
- globalFilter,
175
- },
176
- onGlobalFilterChange: setGlobalFilter,
177
- })
178
-
179
- return (
180
- <div className="space-y-6">
181
- <Card>
182
- <CardHeader>
183
- <div className="flex justify-between items-center">
184
- <div>
185
- <CardTitle>App Catalog Management</CardTitle>
186
- <CardDescription>
187
- Manage apps in the catalog with full CRUD operations
188
- </CardDescription>
189
- </div>
190
- <Button asChild>
191
- <Link to="/admin/app-for-catalog/$id" params={{ id: 'new' }}>
192
- <Plus className="w-4 h-4 mr-2" />
193
- Add App
194
- </Link>
195
- </Button>
196
- </div>
197
- </CardHeader>
198
- <CardContent className="space-y-4">
199
- <Input
200
- placeholder="Search apps by name, slug, or description..."
201
- value={globalFilter || ''}
202
- onChange={(e) => setGlobalFilter(e.target.value)}
203
- className="max-w-sm"
204
- />
205
- {isLoading ? (
206
- <div className="text-center py-8">Loading...</div>
207
- ) : (
208
- <div className="rounded-md border">
209
- <Table>
210
- <TableHeader>
211
- {table.getHeaderGroups().map((headerGroup) => (
212
- <TableRow key={headerGroup.id}>
213
- {headerGroup.headers.map((header) => (
214
- <TableHead
215
- key={header.id}
216
- style={{
217
- width: `${header.getSize()}px`,
218
- minWidth: `${header.getSize()}px`,
219
- maxWidth: `${header.getSize()}px`,
220
- }}
221
- className="overflow-hidden"
222
- >
223
- {header.isPlaceholder
224
- ? null
225
- : flexRender(
226
- header.column.columnDef.header,
227
- header.getContext(),
228
- )}
229
- </TableHead>
230
- ))}
231
- </TableRow>
232
- ))}
233
- </TableHeader>
234
- <TableBody>
235
- {table.getRowModel().rows.length ? (
236
- table.getRowModel().rows.map((row) => (
237
- <TableRow key={row.id}>
238
- {row.getVisibleCells().map((cell) => (
239
- <TableCell
240
- key={cell.id}
241
- style={{
242
- width: `${cell.column.getSize()}px`,
243
- minWidth: `${cell.column.getSize()}px`,
244
- maxWidth: `${cell.column.getSize()}px`,
245
- }}
246
- className="overflow-hidden"
247
- >
248
- {flexRender(
249
- cell.column.columnDef.cell,
250
- cell.getContext(),
251
- )}
252
- </TableCell>
253
- ))}
254
- </TableRow>
255
- ))
256
- ) : (
257
- <TableRow>
258
- <TableCell
259
- colSpan={columns.length}
260
- className="h-24 text-center"
261
- >
262
- No apps found.
263
- </TableCell>
264
- </TableRow>
265
- )}
266
- </TableBody>
267
- </Table>
268
- </div>
269
- )}
270
- </CardContent>
271
- </Card>
272
- </div>
273
- )
274
- }
@@ -1,393 +0,0 @@
1
- import { useQuery } from '@tanstack/react-query'
2
- import type { Control, FieldValues } from 'react-hook-form'
3
- import { useForm } from 'react-hook-form'
4
- import {
5
- FormControl,
6
- FormDescription,
7
- FormField,
8
- FormItem,
9
- FormLabel,
10
- } from '~/ui/form'
11
- import { MarkdownEditor } from '~/ui/markdown-editor'
12
- import { EditableListField } from '~/ui/editable-list'
13
- import { LinkExternal } from '~/ui/linkExternal'
14
- import { Input } from '~/ui/input'
15
- import { Button } from '~/ui/button'
16
- import { ApiQueryMagazineApprovalMethod } from './api/ApiQueryMagazineApprovalMethod'
17
-
18
- interface AccessRequestFormFieldsProps {
19
- control: Control<FieldValues>
20
- approvalMethodId: string | undefined
21
- }
22
-
23
- export function AccessRequestFormFields({
24
- control,
25
- approvalMethodId,
26
- }: AccessRequestFormFieldsProps) {
27
- const { data: method } = useQuery({
28
- ...ApiQueryMagazineApprovalMethod.getById(approvalMethodId!),
29
- enabled: !!approvalMethodId,
30
- })
31
-
32
- if (!approvalMethodId) {
33
- return (
34
- <div className="text-sm text-muted-foreground py-4">
35
- Select an approval method to configure details
36
- </div>
37
- )
38
- }
39
-
40
- if (!method) {
41
- return <div className="text-sm text-muted-foreground py-4">Loading...</div>
42
- }
43
-
44
- const methodConfig = method.config as
45
- | Record<string, unknown>
46
- | undefined
47
- | null
48
-
49
- return (
50
- <div className="space-y-6">
51
- {/* Service type: Show clickable URL if configured */}
52
- {method.type === 'service' && methodConfig?.url ? (
53
- <div className="p-4 border rounded-lg bg-muted/30">
54
- <div className="text-sm font-medium mb-2">Service URL</div>
55
- <LinkExternal href={methodConfig.url as string}>
56
- {methodConfig.url as string}
57
- </LinkExternal>
58
- </div>
59
- ) : null}
60
-
61
- {/* Common Fields */}
62
- <FormField
63
- control={control}
64
- name="accessRequest.comments"
65
- render={({ field }) => (
66
- <FormItem>
67
- <FormLabel>Comments</FormLabel>
68
- <FormControl>
69
- <MarkdownEditor
70
- value={field.value ?? ''}
71
- onChange={field.onChange}
72
- placeholder="General comments about access..."
73
- />
74
- </FormControl>
75
- </FormItem>
76
- )}
77
- />
78
-
79
- <FormField
80
- control={control}
81
- name="accessRequest.requestPrompt"
82
- render={({ field }) => (
83
- <FormItem>
84
- <FormLabel>Request Prompt</FormLabel>
85
- <FormControl>
86
- <MarkdownEditor
87
- value={field.value ?? ''}
88
- onChange={field.onChange}
89
- placeholder="Instructions on how to request access..."
90
- />
91
- </FormControl>
92
- <FormDescription>
93
- Explain how users should request access to this app
94
- </FormDescription>
95
- </FormItem>
96
- )}
97
- />
98
-
99
- {/* Roles List */}
100
- <FormField
101
- control={control}
102
- name="accessRequest.roles"
103
- render={({ field }) => (
104
- <FormItem>
105
- <FormLabel>Available Roles</FormLabel>
106
- <EditableListField
107
- value={field.value ?? []}
108
- onChange={field.onChange}
109
- columns={[
110
- { accessorKey: 'name', header: 'Role Name' },
111
- { accessorKey: 'description', header: 'Description' },
112
- ]}
113
- createEmpty={() => ({ name: '', description: '' })}
114
- getItemKey={(_, i) => String(i)}
115
- addButtonLabel="Add Role"
116
- emptyMessage="No roles defined"
117
- renderForm={({ item, onSave, onCancel }) => {
118
- if (!item) return null
119
- return (
120
- <RoleForm item={item} onSave={onSave} onCancel={onCancel} />
121
- )
122
- }}
123
- />
124
- </FormItem>
125
- )}
126
- />
127
-
128
- {/* Approvers List */}
129
- <FormField
130
- control={control}
131
- name="accessRequest.approvers"
132
- render={({ field }) => (
133
- <FormItem>
134
- <FormLabel>Approvers</FormLabel>
135
- <EditableListField
136
- value={field.value ?? []}
137
- onChange={field.onChange}
138
- columns={[
139
- { accessorKey: 'displayName', header: 'Name' },
140
- { accessorKey: 'contact', header: 'Contact' },
141
- ]}
142
- createEmpty={() => ({ displayName: '', contact: '' })}
143
- getItemKey={(_, i) => String(i)}
144
- addButtonLabel="Add Approver"
145
- emptyMessage="No approvers defined"
146
- renderForm={({ item, onSave, onCancel }) => {
147
- if (!item) return null
148
- return (
149
- <ApproverForm
150
- item={item}
151
- onSave={onSave}
152
- onCancel={onCancel}
153
- />
154
- )
155
- }}
156
- />
157
- <FormDescription>
158
- People who can approve access requests
159
- </FormDescription>
160
- </FormItem>
161
- )}
162
- />
163
-
164
- {/* URLs List */}
165
- <FormField
166
- control={control}
167
- name="accessRequest.urls"
168
- render={({ field }) => (
169
- <FormItem>
170
- <FormLabel>Related URLs</FormLabel>
171
- <EditableListField
172
- value={field.value ?? []}
173
- onChange={field.onChange}
174
- columns={[
175
- { accessorKey: 'label', header: 'Label' },
176
- { accessorKey: 'url', header: 'URL' },
177
- ]}
178
- createEmpty={() => ({ label: '', url: '' })}
179
- getItemKey={(_, i) => String(i)}
180
- addButtonLabel="Add URL"
181
- emptyMessage="No URLs defined"
182
- renderForm={({ item, onSave, onCancel }) => {
183
- if (!item) return null
184
- return (
185
- <UrlForm item={item} onSave={onSave} onCancel={onCancel} />
186
- )
187
- }}
188
- />
189
- </FormItem>
190
- )}
191
- />
192
-
193
- <FormField
194
- control={control}
195
- name="accessRequest.postApprovalInstructions"
196
- render={({ field }) => (
197
- <FormItem>
198
- <FormLabel>Post-Approval Instructions</FormLabel>
199
- <FormControl>
200
- <MarkdownEditor
201
- value={field.value ?? ''}
202
- onChange={field.onChange}
203
- placeholder="Steps to follow after approval is granted..."
204
- />
205
- </FormControl>
206
- </FormItem>
207
- )}
208
- />
209
-
210
- {/* Person/Team specific: Who to reach out */}
211
- {method.type === 'personTeam' && (
212
- <FormField
213
- control={control}
214
- name="accessRequest.whoToReachOut"
215
- render={({ field }) => (
216
- <FormItem>
217
- <FormLabel>Who to Reach Out</FormLabel>
218
- <FormControl>
219
- <MarkdownEditor
220
- value={field.value ?? ''}
221
- onChange={field.onChange}
222
- placeholder="Describe who to contact and how..."
223
- />
224
- </FormControl>
225
- <FormDescription>
226
- Specific instructions for contacting the person or team
227
- </FormDescription>
228
- </FormItem>
229
- )}
230
- />
231
- )}
232
- </div>
233
- )
234
- }
235
-
236
- // Sub-forms for list editing
237
-
238
- function RoleForm({
239
- item,
240
- onSave,
241
- onCancel,
242
- }: {
243
- item: { name: string; description: string }
244
- onSave: (item: { name: string; description: string }) => void
245
- onCancel: () => void
246
- }) {
247
- const form = useForm<{ name: string; description: string }>({
248
- defaultValues: item,
249
- })
250
-
251
- return (
252
- <form onSubmit={form.handleSubmit(onSave)} className="space-y-4">
253
- <FormField
254
- control={form.control as any}
255
- name="name"
256
- render={({ field }) => (
257
- <FormItem>
258
- <FormLabel>Role Name</FormLabel>
259
- <FormControl>
260
- <Input {...field} placeholder="e.g., Admin, Read-Only" />
261
- </FormControl>
262
- </FormItem>
263
- )}
264
- />
265
- <FormField
266
- control={form.control as any}
267
- name="description"
268
- render={({ field }) => (
269
- <FormItem>
270
- <FormLabel>Description</FormLabel>
271
- <FormControl>
272
- <Input {...field} placeholder="Brief description of the role" />
273
- </FormControl>
274
- </FormItem>
275
- )}
276
- />
277
- <div className="flex gap-2">
278
- <Button type="submit" size="sm">
279
- Save
280
- </Button>
281
- <Button type="button" variant="outline" size="sm" onClick={onCancel}>
282
- Cancel
283
- </Button>
284
- </div>
285
- </form>
286
- )
287
- }
288
-
289
- function ApproverForm({
290
- item,
291
- onSave,
292
- onCancel,
293
- }: {
294
- item: { displayName: string; contact: string }
295
- onSave: (item: { displayName: string; contact: string }) => void
296
- onCancel: () => void
297
- }) {
298
- const form = useForm<{ displayName: string; contact: string }>({
299
- defaultValues: item,
300
- })
301
-
302
- return (
303
- <form onSubmit={form.handleSubmit(onSave)} className="space-y-4">
304
- <FormField
305
- control={form.control as any}
306
- name="displayName"
307
- render={({ field }) => (
308
- <FormItem>
309
- <FormLabel>Name</FormLabel>
310
- <FormControl>
311
- <Input {...field} placeholder="e.g., John Doe" />
312
- </FormControl>
313
- </FormItem>
314
- )}
315
- />
316
- <FormField
317
- control={form.control as any}
318
- name="contact"
319
- render={({ field }) => (
320
- <FormItem>
321
- <FormLabel>Contact</FormLabel>
322
- <FormControl>
323
- <Input {...field} placeholder="e.g., email, Slack handle" />
324
- </FormControl>
325
- </FormItem>
326
- )}
327
- />
328
- <div className="flex gap-2">
329
- <Button type="submit" size="sm">
330
- Save
331
- </Button>
332
- <Button type="button" variant="outline" size="sm" onClick={onCancel}>
333
- Cancel
334
- </Button>
335
- </div>
336
- </form>
337
- )
338
- }
339
-
340
- function UrlForm({
341
- item,
342
- onSave,
343
- onCancel,
344
- }: {
345
- item: { label: string; url: string }
346
- onSave: (item: { label: string; url: string }) => void
347
- onCancel: () => void
348
- }) {
349
- const form = useForm<{ label: string; url: string }>({
350
- defaultValues: item,
351
- })
352
-
353
- return (
354
- <form onSubmit={form.handleSubmit(onSave)} className="space-y-4">
355
- <FormField
356
- control={form.control as any}
357
- name="label"
358
- render={({ field }) => (
359
- <FormItem>
360
- <FormLabel>Label</FormLabel>
361
- <FormControl>
362
- <Input {...field} placeholder="e.g., Documentation" />
363
- </FormControl>
364
- </FormItem>
365
- )}
366
- />
367
- <FormField
368
- control={form.control as any}
369
- name="url"
370
- render={({ field }) => (
371
- <FormItem>
372
- <FormLabel>URL</FormLabel>
373
- <FormControl>
374
- <Input
375
- {...field}
376
- type="url"
377
- placeholder="e.g., https://example.com"
378
- />
379
- </FormControl>
380
- </FormItem>
381
- )}
382
- />
383
- <div className="flex gap-2">
384
- <Button type="submit" size="sm">
385
- Save
386
- </Button>
387
- <Button type="button" variant="outline" size="sm" onClick={onCancel}>
388
- Cancel
389
- </Button>
390
- </div>
391
- </form>
392
- )
393
- }