@igstack/app-catalog-frontend-core 0.6.4 → 0.7.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 (37) hide show
  1. package/dist/esm/__tests__/integration/replacementLink.integration.test.d.ts +0 -0
  2. package/dist/esm/__tests__/integration/serviceDesks.integration.test.d.ts +0 -0
  3. package/dist/esm/__tests__/integration/tools/AppDetailTools.d.ts +4 -0
  4. package/dist/esm/modules/appCatalog/context/AppCatalogContext.js +3 -3
  5. package/dist/esm/modules/appCatalog/ui/components/PersonBadge.js +3 -3
  6. package/dist/esm/modules/appCatalog/ui/components/SubResourcesSection.js +3 -3
  7. package/dist/esm/modules/appCatalog/ui/components/TierVariantsSection.js +3 -3
  8. package/dist/esm/modules/appCatalog/ui/components/ViewToggle.d.ts +6 -0
  9. package/dist/esm/modules/appCatalog/ui/components/ViewToggle.js +43 -0
  10. package/dist/esm/modules/appCatalog/ui/components/ViewToggle.js.map +1 -0
  11. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js +2 -1
  12. package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js.map +1 -1
  13. package/dist/esm/modules/appCatalog/ui/layout/AppCatalogLayout.js +2 -1
  14. package/dist/esm/modules/appCatalog/ui/layout/AppCatalogLayout.js.map +1 -1
  15. package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js +1 -1
  16. package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js.map +1 -1
  17. package/dist/esm/modules/appCatalog/ui/pages/ServiceDesksPage.d.ts +6 -0
  18. package/dist/esm/modules/appCatalog/ui/pages/ServiceDesksPage.js +63 -0
  19. package/dist/esm/modules/appCatalog/ui/pages/ServiceDesksPage.js.map +1 -0
  20. package/dist/esm/routeTree.gen.d.ts +20 -3
  21. package/dist/esm/routeTree.gen.js +9 -2
  22. package/dist/esm/routeTree.gen.js.map +1 -1
  23. package/dist/esm/routes/_layout/service-desks.d.ts +6 -0
  24. package/dist/esm/routes/_layout/service-desks.js +25 -0
  25. package/dist/esm/routes/_layout/service-desks.js.map +1 -0
  26. package/package.json +4 -4
  27. package/src/__tests__/integration/mock-backend/magazines.ts +6 -0
  28. package/src/__tests__/integration/replacementLink.integration.test.ts +52 -0
  29. package/src/__tests__/integration/serviceDesks.integration.test.ts +85 -0
  30. package/src/__tests__/integration/tools/AppDetailTools.ts +12 -0
  31. package/src/modules/appCatalog/ui/components/ViewToggle.tsx +40 -0
  32. package/src/modules/appCatalog/ui/grid/AppCatalogGrid.tsx +8 -1
  33. package/src/modules/appCatalog/ui/layout/AppCatalogLayout.tsx +2 -1
  34. package/src/modules/appCatalog/ui/pages/AppCatalogPage.tsx +1 -1
  35. package/src/modules/appCatalog/ui/pages/ServiceDesksPage.tsx +91 -0
  36. package/src/routeTree.gen.ts +33 -2
  37. package/src/routes/_layout/service-desks.tsx +28 -0
@@ -0,0 +1,91 @@
1
+ import { ExternalLink } from 'lucide-react'
2
+ import { useMemo, useState } from 'react'
3
+ import { InputGroup, InputGroupInput } from '~/ui/input-group'
4
+ import {
5
+ Table,
6
+ TableBody,
7
+ TableCell,
8
+ TableHead,
9
+ TableHeader,
10
+ TableRow,
11
+ } from '~/ui/table'
12
+ import { useAppCatalogContext } from '../../context/AppCatalogContext'
13
+
14
+ /**
15
+ * Service Desks view (#9): a searchable table of all service-desk approval
16
+ * methods (type === 'service'), each with a link that opens its portal in a new
17
+ * tab. Data rides in on the existing app-catalog query (context.approvalMethods).
18
+ */
19
+ export function ServiceDesksPage() {
20
+ const { approvalMethods } = useAppCatalogContext()
21
+ const [search, setSearch] = useState('')
22
+
23
+ const desks = useMemo(() => {
24
+ const services = approvalMethods.filter((m) => m.type === 'service')
25
+ const q = search.trim().toLowerCase()
26
+ const filtered = q
27
+ ? services.filter((m) => m.displayName.toLowerCase().includes(q))
28
+ : services
29
+ return [...filtered].sort((a, b) =>
30
+ a.displayName.localeCompare(b.displayName),
31
+ )
32
+ }, [approvalMethods, search])
33
+
34
+ return (
35
+ <div className="flex flex-col flex-1 min-h-0 gap-4">
36
+ <InputGroup className="max-w-sm">
37
+ <InputGroupInput
38
+ value={search}
39
+ onChange={(e) => setSearch(e.target.value)}
40
+ placeholder="Search service desks by name…"
41
+ aria-label="Search service desks"
42
+ />
43
+ </InputGroup>
44
+
45
+ <div className="flex-1 min-h-0 overflow-y-auto">
46
+ {desks.length === 0 ? (
47
+ <p className="text-sm text-muted-foreground">
48
+ No service desks found{search && ` for "${search}"`}.
49
+ </p>
50
+ ) : (
51
+ <Table>
52
+ <TableHeader>
53
+ <TableRow>
54
+ <TableHead>Service Desk</TableHead>
55
+ <TableHead>Link</TableHead>
56
+ </TableRow>
57
+ </TableHeader>
58
+ <TableBody>
59
+ {desks.map((desk) => {
60
+ const url = desk.config.url
61
+ return (
62
+ <TableRow key={desk.slug}>
63
+ <TableCell className="font-medium">
64
+ {desk.displayName}
65
+ </TableCell>
66
+ <TableCell>
67
+ {url ? (
68
+ <a
69
+ href={url}
70
+ target="_blank"
71
+ rel="noopener noreferrer"
72
+ className="inline-flex items-center gap-1 text-primary hover:underline"
73
+ title={url}
74
+ >
75
+ Open
76
+ <ExternalLink className="size-3" />
77
+ </a>
78
+ ) : (
79
+ <span className="text-muted-foreground">—</span>
80
+ )}
81
+ </TableCell>
82
+ </TableRow>
83
+ )
84
+ })}
85
+ </TableBody>
86
+ </Table>
87
+ )}
88
+ </div>
89
+ </div>
90
+ )
91
+ }
@@ -12,6 +12,7 @@ import { Route as rootRouteImport } from './routes/__root'
12
12
  import { Route as LayoutRouteImport } from './routes/_layout'
13
13
  import { Route as LayoutIndexRouteImport } from './routes/_layout/index'
14
14
  import { Route as AuthCallbackRouteImport } from './routes/auth.callback'
15
+ import { Route as LayoutServiceDesksRouteImport } from './routes/_layout/service-desks'
15
16
  import { Route as LayoutLoginRouteImport } from './routes/_layout/login'
16
17
  import { Route as LayoutAppSlugRouteImport } from './routes/_layout/app.$slug'
17
18
  import { Route as LayoutCatalogAppsIndexRouteImport } from './routes/_layout/catalog.apps.index'
@@ -30,6 +31,11 @@ const AuthCallbackRoute = AuthCallbackRouteImport.update({
30
31
  path: '/auth/callback',
31
32
  getParentRoute: () => rootRouteImport,
32
33
  } as any)
34
+ const LayoutServiceDesksRoute = LayoutServiceDesksRouteImport.update({
35
+ id: '/service-desks',
36
+ path: '/service-desks',
37
+ getParentRoute: () => LayoutRoute,
38
+ } as any)
33
39
  const LayoutLoginRoute = LayoutLoginRouteImport.update({
34
40
  id: '/login',
35
41
  path: '/login',
@@ -49,12 +55,14 @@ const LayoutCatalogAppsIndexRoute = LayoutCatalogAppsIndexRouteImport.update({
49
55
  export interface FileRoutesByFullPath {
50
56
  '/': typeof LayoutIndexRoute
51
57
  '/login': typeof LayoutLoginRoute
58
+ '/service-desks': typeof LayoutServiceDesksRoute
52
59
  '/auth/callback': typeof AuthCallbackRoute
53
60
  '/app/$slug': typeof LayoutAppSlugRoute
54
61
  '/catalog/apps/': typeof LayoutCatalogAppsIndexRoute
55
62
  }
56
63
  export interface FileRoutesByTo {
57
64
  '/login': typeof LayoutLoginRoute
65
+ '/service-desks': typeof LayoutServiceDesksRoute
58
66
  '/auth/callback': typeof AuthCallbackRoute
59
67
  '/': typeof LayoutIndexRoute
60
68
  '/app/$slug': typeof LayoutAppSlugRoute
@@ -64,6 +72,7 @@ export interface FileRoutesById {
64
72
  __root__: typeof rootRouteImport
65
73
  '/_layout': typeof LayoutRouteWithChildren
66
74
  '/_layout/login': typeof LayoutLoginRoute
75
+ '/_layout/service-desks': typeof LayoutServiceDesksRoute
67
76
  '/auth/callback': typeof AuthCallbackRoute
68
77
  '/_layout/': typeof LayoutIndexRoute
69
78
  '/_layout/app/$slug': typeof LayoutAppSlugRoute
@@ -71,13 +80,26 @@ export interface FileRoutesById {
71
80
  }
72
81
  export interface FileRouteTypes {
73
82
  fileRoutesByFullPath: FileRoutesByFullPath
74
- fullPaths: '/' | '/login' | '/auth/callback' | '/app/$slug' | '/catalog/apps/'
83
+ fullPaths:
84
+ | '/'
85
+ | '/login'
86
+ | '/service-desks'
87
+ | '/auth/callback'
88
+ | '/app/$slug'
89
+ | '/catalog/apps/'
75
90
  fileRoutesByTo: FileRoutesByTo
76
- to: '/login' | '/auth/callback' | '/' | '/app/$slug' | '/catalog/apps'
91
+ to:
92
+ | '/login'
93
+ | '/service-desks'
94
+ | '/auth/callback'
95
+ | '/'
96
+ | '/app/$slug'
97
+ | '/catalog/apps'
77
98
  id:
78
99
  | '__root__'
79
100
  | '/_layout'
80
101
  | '/_layout/login'
102
+ | '/_layout/service-desks'
81
103
  | '/auth/callback'
82
104
  | '/_layout/'
83
105
  | '/_layout/app/$slug'
@@ -112,6 +134,13 @@ declare module '@tanstack/react-router' {
112
134
  preLoaderRoute: typeof AuthCallbackRouteImport
113
135
  parentRoute: typeof rootRouteImport
114
136
  }
137
+ '/_layout/service-desks': {
138
+ id: '/_layout/service-desks'
139
+ path: '/service-desks'
140
+ fullPath: '/service-desks'
141
+ preLoaderRoute: typeof LayoutServiceDesksRouteImport
142
+ parentRoute: typeof LayoutRoute
143
+ }
115
144
  '/_layout/login': {
116
145
  id: '/_layout/login'
117
146
  path: '/login'
@@ -138,6 +167,7 @@ declare module '@tanstack/react-router' {
138
167
 
139
168
  interface LayoutRouteChildren {
140
169
  LayoutLoginRoute: typeof LayoutLoginRoute
170
+ LayoutServiceDesksRoute: typeof LayoutServiceDesksRoute
141
171
  LayoutIndexRoute: typeof LayoutIndexRoute
142
172
  LayoutAppSlugRoute: typeof LayoutAppSlugRoute
143
173
  LayoutCatalogAppsIndexRoute: typeof LayoutCatalogAppsIndexRoute
@@ -145,6 +175,7 @@ interface LayoutRouteChildren {
145
175
 
146
176
  const LayoutRouteChildren: LayoutRouteChildren = {
147
177
  LayoutLoginRoute: LayoutLoginRoute,
178
+ LayoutServiceDesksRoute: LayoutServiceDesksRoute,
148
179
  LayoutIndexRoute: LayoutIndexRoute,
149
180
  LayoutAppSlugRoute: LayoutAppSlugRoute,
150
181
  LayoutCatalogAppsIndexRoute: LayoutCatalogAppsIndexRoute,
@@ -0,0 +1,28 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { z } from 'zod'
3
+ import { appCatalogRouteLoader } from '~/modules/appCatalog/routeLoader'
4
+ import { AppCatalogLayout } from '~/modules/appCatalog/ui/layout/AppCatalogLayout'
5
+ import { ServiceDesksPage } from '~/modules/appCatalog/ui/pages/ServiceDesksPage'
6
+
7
+ const searchSchema = z.object({
8
+ q: z.string().optional(),
9
+ })
10
+
11
+ export const Route = createFileRoute('/_layout/service-desks')({
12
+ component: RouteComponent,
13
+ validateSearch: searchSchema,
14
+ async loader() {
15
+ const appCatalogLoader = await appCatalogRouteLoader()
16
+ return { appCatalogLoader }
17
+ },
18
+ })
19
+
20
+ function RouteComponent() {
21
+ const { queryClient, trpcClient } = Route.useRouteContext()
22
+
23
+ return (
24
+ <AppCatalogLayout queryClient={queryClient} trpcClient={trpcClient}>
25
+ <ServiceDesksPage />
26
+ </AppCatalogLayout>
27
+ )
28
+ }