@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.
- package/dist/esm/__tests__/integration/replacementLink.integration.test.d.ts +0 -0
- package/dist/esm/__tests__/integration/serviceDesks.integration.test.d.ts +0 -0
- package/dist/esm/__tests__/integration/tools/AppDetailTools.d.ts +4 -0
- package/dist/esm/modules/appCatalog/context/AppCatalogContext.js +3 -3
- package/dist/esm/modules/appCatalog/ui/components/PersonBadge.js +3 -3
- package/dist/esm/modules/appCatalog/ui/components/SubResourcesSection.js +3 -3
- package/dist/esm/modules/appCatalog/ui/components/TierVariantsSection.js +3 -3
- package/dist/esm/modules/appCatalog/ui/components/ViewToggle.d.ts +6 -0
- package/dist/esm/modules/appCatalog/ui/components/ViewToggle.js +43 -0
- package/dist/esm/modules/appCatalog/ui/components/ViewToggle.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js +2 -1
- package/dist/esm/modules/appCatalog/ui/grid/AppCatalogGrid.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/layout/AppCatalogLayout.js +2 -1
- package/dist/esm/modules/appCatalog/ui/layout/AppCatalogLayout.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js +1 -1
- package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/pages/ServiceDesksPage.d.ts +6 -0
- package/dist/esm/modules/appCatalog/ui/pages/ServiceDesksPage.js +63 -0
- package/dist/esm/modules/appCatalog/ui/pages/ServiceDesksPage.js.map +1 -0
- package/dist/esm/routeTree.gen.d.ts +20 -3
- package/dist/esm/routeTree.gen.js +9 -2
- package/dist/esm/routeTree.gen.js.map +1 -1
- package/dist/esm/routes/_layout/service-desks.d.ts +6 -0
- package/dist/esm/routes/_layout/service-desks.js +25 -0
- package/dist/esm/routes/_layout/service-desks.js.map +1 -0
- package/package.json +4 -4
- package/src/__tests__/integration/mock-backend/magazines.ts +6 -0
- package/src/__tests__/integration/replacementLink.integration.test.ts +52 -0
- package/src/__tests__/integration/serviceDesks.integration.test.ts +85 -0
- package/src/__tests__/integration/tools/AppDetailTools.ts +12 -0
- package/src/modules/appCatalog/ui/components/ViewToggle.tsx +40 -0
- package/src/modules/appCatalog/ui/grid/AppCatalogGrid.tsx +8 -1
- package/src/modules/appCatalog/ui/layout/AppCatalogLayout.tsx +2 -1
- package/src/modules/appCatalog/ui/pages/AppCatalogPage.tsx +1 -1
- package/src/modules/appCatalog/ui/pages/ServiceDesksPage.tsx +91 -0
- package/src/routeTree.gen.ts +33 -2
- 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
|
+
}
|
package/src/routeTree.gen.ts
CHANGED
|
@@ -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:
|
|
83
|
+
fullPaths:
|
|
84
|
+
| '/'
|
|
85
|
+
| '/login'
|
|
86
|
+
| '/service-desks'
|
|
87
|
+
| '/auth/callback'
|
|
88
|
+
| '/app/$slug'
|
|
89
|
+
| '/catalog/apps/'
|
|
75
90
|
fileRoutesByTo: FileRoutesByTo
|
|
76
|
-
to:
|
|
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
|
+
}
|