@igstack/app-catalog-frontend-core 0.2.0 → 0.3.1-alpha-20260305175850

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 (190) hide show
  1. package/dist/esm/api/infra/trpc.d.ts +0 -1491
  2. package/dist/esm/modules/appCatalog/ui/filters/FilterBar.js +23 -11
  3. package/dist/esm/modules/appCatalog/ui/filters/FilterBar.js.map +1 -1
  4. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.d.ts +5 -1
  5. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js +146 -56
  6. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js.map +1 -1
  7. package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js +20 -1
  8. package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js.map +1 -1
  9. package/dist/esm/modules/auth/AuthContext.js +1 -1
  10. package/dist/esm/modules/auth/AuthModalContext.js +1 -1
  11. package/dist/esm/modules/auth/authClient.d.ts +2 -2
  12. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/classic/schemas.js +4 -37
  13. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/classic/schemas.js.map +1 -1
  14. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/api.js +2 -10
  15. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/api.js.map +1 -1
  16. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/checks.js +1 -1
  17. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/json-schema-processors.js +0 -44
  18. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/json-schema-processors.js.map +1 -1
  19. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/parse.js +0 -4
  20. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/parse.js.map +1 -1
  21. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/regexes.js +0 -2
  22. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/regexes.js.map +1 -1
  23. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/schemas.js +4 -49
  24. package/dist/esm/node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/schemas.js.map +1 -1
  25. package/dist/esm/routeTree.gen.d.ts +3 -164
  26. package/dist/esm/routeTree.gen.js +8 -80
  27. package/dist/esm/routeTree.gen.js.map +1 -1
  28. package/dist/esm/ui/button.d.ts +1 -1
  29. package/dist/esm/ui/card.js +1 -48
  30. package/dist/esm/ui/card.js.map +1 -1
  31. package/dist/esm/ui/command.js +1 -15
  32. package/dist/esm/ui/command.js.map +1 -1
  33. package/dist/esm/ui/components/header/Header.js +2 -11
  34. package/dist/esm/ui/components/header/Header.js.map +1 -1
  35. package/dist/esm/ui/input-group.js +125 -0
  36. package/dist/esm/ui/input-group.js.map +1 -0
  37. package/package.json +3 -3
  38. package/src/modules/appCatalog/ui/components/AppDetailModal.tsx +2 -21
  39. package/src/routeTree.gen.ts +2 -220
  40. package/src/ui/components/header/Header.tsx +2 -12
  41. package/dist/esm/components/IconPickerDialog.d.ts +0 -8
  42. package/dist/esm/components/IconPickerDialog.js +0 -98
  43. package/dist/esm/components/IconPickerDialog.js.map +0 -1
  44. package/dist/esm/components/IconPickerField.d.ts +0 -9
  45. package/dist/esm/components/IconPickerField.js +0 -76
  46. package/dist/esm/components/IconPickerField.js.map +0 -1
  47. package/dist/esm/modules/admin-base/components/AdminChat.d.ts +0 -1
  48. package/dist/esm/modules/admin-base/components/AdminChat.js +0 -82
  49. package/dist/esm/modules/admin-base/components/AdminChat.js.map +0 -1
  50. package/dist/esm/modules/admin-base/components/AdminLayout.d.ts +0 -5
  51. package/dist/esm/modules/admin-base/components/AdminLayout.js +0 -83
  52. package/dist/esm/modules/admin-base/components/AdminLayout.js.map +0 -1
  53. package/dist/esm/modules/admin-base/components/AdminWelcome.d.ts +0 -1
  54. package/dist/esm/modules/admin-base/components/AdminWelcome.js +0 -37
  55. package/dist/esm/modules/admin-base/components/AdminWelcome.js.map +0 -1
  56. package/dist/esm/modules/admin-base/context/AdminConfigContext.d.ts +0 -8
  57. package/dist/esm/modules/admin-base/context/AdminConfigContext.js +0 -27
  58. package/dist/esm/modules/admin-base/context/AdminConfigContext.js.map +0 -1
  59. package/dist/esm/modules/admin-base/index.d.ts +0 -5
  60. package/dist/esm/modules/admin-base/types/adminTypes.d.ts +0 -10
  61. package/dist/esm/modules/appCatalog/AppCatalogAdminPage.d.ts +0 -1
  62. package/dist/esm/modules/appCatalog/AppCatalogAdminPage.js +0 -196
  63. package/dist/esm/modules/appCatalog/AppCatalogAdminPage.js.map +0 -1
  64. package/dist/esm/modules/appCatalog/ScreenshotItem.js +0 -57
  65. package/dist/esm/modules/appCatalog/ScreenshotItem.js.map +0 -1
  66. package/dist/esm/modules/appCatalog/ScreenshotManager.js +0 -155
  67. package/dist/esm/modules/appCatalog/ScreenshotManager.js.map +0 -1
  68. package/dist/esm/modules/approvalMethod/AccessRequestFormFields.d.ts +0 -7
  69. package/dist/esm/modules/approvalMethod/AccessRequestFormFields.js +0 -323
  70. package/dist/esm/modules/approvalMethod/AccessRequestFormFields.js.map +0 -1
  71. package/dist/esm/modules/approvalMethod/ApprovalMethodForm.d.ts +0 -14
  72. package/dist/esm/modules/approvalMethod/ApprovalMethodForm.js +0 -227
  73. package/dist/esm/modules/approvalMethod/ApprovalMethodForm.js.map +0 -1
  74. package/dist/esm/modules/approvalMethod/ApprovalMethodSelector.d.ts +0 -7
  75. package/dist/esm/modules/approvalMethod/ApprovalMethodSelector.js +0 -124
  76. package/dist/esm/modules/approvalMethod/ApprovalMethodSelector.js.map +0 -1
  77. package/dist/esm/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.d.ts +0 -381
  78. package/dist/esm/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.js +0 -26
  79. package/dist/esm/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.js.map +0 -1
  80. package/dist/esm/modules/auth/authUtils.js +0 -25
  81. package/dist/esm/modules/auth/authUtils.js.map +0 -1
  82. package/dist/esm/modules/icons/IconManagementPage.d.ts +0 -1
  83. package/dist/esm/modules/icons/IconManagementPage.js +0 -177
  84. package/dist/esm/modules/icons/IconManagementPage.js.map +0 -1
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. 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
  92. 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
  93. 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
  94. 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
  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/zod/dist/zod.js +0 -94
  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/zod/dist/zod.js.map +0 -1
  97. 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
  98. 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
  99. package/dist/esm/routes/admin/app-for-catalog/$id.d.ts +0 -5
  100. package/dist/esm/routes/admin/app-for-catalog/_id.js +0 -67
  101. package/dist/esm/routes/admin/app-for-catalog/_id.js.map +0 -1
  102. package/dist/esm/routes/admin/app-for-catalog/_id2.js +0 -321
  103. package/dist/esm/routes/admin/app-for-catalog/_id2.js.map +0 -1
  104. package/dist/esm/routes/admin/app-for-catalog/index.d.ts +0 -1
  105. package/dist/esm/routes/admin/app-for-catalog/index.js +0 -9
  106. package/dist/esm/routes/admin/app-for-catalog/index.js.map +0 -1
  107. package/dist/esm/routes/admin/app-for-catalog/index2.js +0 -12
  108. package/dist/esm/routes/admin/app-for-catalog/index2.js.map +0 -1
  109. package/dist/esm/routes/admin/app-for-catalog.d.ts +0 -1
  110. package/dist/esm/routes/admin/app-for-catalog.js +0 -14
  111. package/dist/esm/routes/admin/app-for-catalog.js.map +0 -1
  112. package/dist/esm/routes/admin/app-for-catalog2.js +0 -9
  113. package/dist/esm/routes/admin/app-for-catalog2.js.map +0 -1
  114. package/dist/esm/routes/admin/approval-methods/index.d.ts +0 -32
  115. package/dist/esm/routes/admin/approval-methods/index.js +0 -24
  116. package/dist/esm/routes/admin/approval-methods/index.js.map +0 -1
  117. package/dist/esm/routes/admin/approval-methods/index2.js +0 -100
  118. package/dist/esm/routes/admin/approval-methods/index2.js.map +0 -1
  119. package/dist/esm/routes/admin/approval-methods.d.ts +0 -1
  120. package/dist/esm/routes/admin/approval-methods.js +0 -14
  121. package/dist/esm/routes/admin/approval-methods.js.map +0 -1
  122. package/dist/esm/routes/admin/approval-methods2.js +0 -7
  123. package/dist/esm/routes/admin/approval-methods2.js.map +0 -1
  124. package/dist/esm/routes/admin/chat.d.ts +0 -1
  125. package/dist/esm/routes/admin/chat.js +0 -14
  126. package/dist/esm/routes/admin/chat.js.map +0 -1
  127. package/dist/esm/routes/admin/chat2.js +0 -9
  128. package/dist/esm/routes/admin/chat2.js.map +0 -1
  129. package/dist/esm/routes/admin/icons.d.ts +0 -1
  130. package/dist/esm/routes/admin/icons.js +0 -14
  131. package/dist/esm/routes/admin/icons.js.map +0 -1
  132. package/dist/esm/routes/admin/icons2.js +0 -12
  133. package/dist/esm/routes/admin/icons2.js.map +0 -1
  134. package/dist/esm/routes/admin/index.d.ts +0 -1
  135. package/dist/esm/routes/admin/index.js +0 -9
  136. package/dist/esm/routes/admin/index.js.map +0 -1
  137. package/dist/esm/routes/admin/index2.js +0 -9
  138. package/dist/esm/routes/admin/index2.js.map +0 -1
  139. package/dist/esm/routes/admin.d.ts +0 -1
  140. package/dist/esm/routes/admin.js +0 -37
  141. package/dist/esm/routes/admin.js.map +0 -1
  142. package/dist/esm/routes/admin2.js +0 -18
  143. package/dist/esm/routes/admin2.js.map +0 -1
  144. package/dist/esm/ui/alert-dialog.js +0 -141
  145. package/dist/esm/ui/alert-dialog.js.map +0 -1
  146. package/dist/esm/ui/breadcrumb.js +0 -84
  147. package/dist/esm/ui/breadcrumb.js.map +0 -1
  148. package/dist/esm/ui/components/Breadcrumbs.js +0 -36
  149. package/dist/esm/ui/components/Breadcrumbs.js.map +0 -1
  150. package/dist/esm/ui/crud-list/CrudList.js +0 -189
  151. package/dist/esm/ui/crud-list/CrudList.js.map +0 -1
  152. package/dist/esm/ui/editable-list/EditableListField.js +0 -130
  153. package/dist/esm/ui/editable-list/EditableListField.js.map +0 -1
  154. package/dist/esm/ui/form.js +0 -134
  155. package/dist/esm/ui/form.js.map +0 -1
  156. package/dist/esm/ui/linkExternal.js +0 -26
  157. package/dist/esm/ui/linkExternal.js.map +0 -1
  158. package/dist/esm/ui/markdown-editor/MarkdownEditor.js +0 -116
  159. package/dist/esm/ui/markdown-editor/MarkdownEditor.js.map +0 -1
  160. package/dist/esm/ui/markdown-editor/MarkdownToolbar.js +0 -99
  161. package/dist/esm/ui/markdown-editor/MarkdownToolbar.js.map +0 -1
  162. package/dist/esm/ui/scroll-area.js +0 -62
  163. package/dist/esm/ui/scroll-area.js.map +0 -1
  164. package/dist/esm/ui/select.js +0 -138
  165. package/dist/esm/ui/select.js.map +0 -1
  166. package/dist/esm/ui/textarea.js +0 -19
  167. package/dist/esm/ui/textarea.js.map +0 -1
  168. package/src/components/IconPickerDialog.tsx +0 -136
  169. package/src/components/IconPickerField.tsx +0 -88
  170. package/src/modules/admin-base/components/AdminChat.tsx +0 -122
  171. package/src/modules/admin-base/components/AdminLayout.tsx +0 -111
  172. package/src/modules/admin-base/components/AdminWelcome.tsx +0 -52
  173. package/src/modules/admin-base/context/AdminConfigContext.tsx +0 -36
  174. package/src/modules/admin-base/index.ts +0 -16
  175. package/src/modules/admin-base/types/adminTypes.ts +0 -11
  176. package/src/modules/appCatalog/AppCatalogAdminPage.tsx +0 -274
  177. package/src/modules/approvalMethod/AccessRequestFormFields.tsx +0 -393
  178. package/src/modules/approvalMethod/ApprovalMethodForm.tsx +0 -323
  179. package/src/modules/approvalMethod/ApprovalMethodSelector.tsx +0 -150
  180. package/src/modules/approvalMethod/api/ApiQueryMagazineApprovalMethod.ts +0 -34
  181. package/src/modules/icons/IconManagementPage.tsx +0 -245
  182. package/src/routes/admin/app-for-catalog/$id.tsx +0 -571
  183. package/src/routes/admin/app-for-catalog/index.tsx +0 -19
  184. package/src/routes/admin/app-for-catalog.tsx +0 -12
  185. package/src/routes/admin/approval-methods/index.tsx +0 -161
  186. package/src/routes/admin/approval-methods.tsx +0 -10
  187. package/src/routes/admin/chat.tsx +0 -13
  188. package/src/routes/admin/icons.tsx +0 -22
  189. package/src/routes/admin/index.tsx +0 -9
  190. 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
- }