@igstack/app-catalog-frontend-core 6.3.1-alpha-20261003051755 → 6.5.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__/modules/appCatalog/ui/detail/AppDetails.subResourceTab.test.d.ts +0 -0
- package/dist/esm/__tests__/modules/appCatalog/ui/detail/FeedbackSection.emptyState.test.d.ts +0 -0
- package/dist/esm/__tests__/modules/appCatalog/ui/detail/FeedbackSection.reviewStatus.test.d.ts +0 -0
- package/dist/esm/__tests__/modules/appCatalog/utils/accessTabLabel.test.d.ts +1 -0
- package/dist/esm/api/infra/trpc.d.ts +42 -21
- package/dist/esm/modules/appCatalog/hooks/useUpdateApp.d.ts +1 -0
- package/dist/esm/modules/appCatalog/ui/catalog/AppCatalogGrid.js +19 -0
- package/dist/esm/modules/appCatalog/ui/catalog/AppCatalogGrid.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.js +17 -2
- package/dist/esm/modules/appCatalog/ui/catalog/AppDetailPanel.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/catalog/RequestAppDialog.d.ts +14 -0
- package/dist/esm/modules/appCatalog/ui/catalog/RequestAppDialog.js +115 -0
- package/dist/esm/modules/appCatalog/ui/catalog/RequestAppDialog.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/components/AccessPrerequisiteChain.js +1 -0
- package/dist/esm/modules/appCatalog/ui/components/AccessPrerequisiteChain.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/components/AccessRequestSection.js +11 -4
- package/dist/esm/modules/appCatalog/ui/components/AccessRequestSection.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/components/QuickJumpBar.js +0 -4
- package/dist/esm/modules/appCatalog/ui/components/QuickJumpBar.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/components/SubResourceDetailPanel.js +4 -1
- package/dist/esm/modules/appCatalog/ui/components/SubResourceDetailPanel.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/AppDetails.js +377 -385
- package/dist/esm/modules/appCatalog/ui/detail/AppDetails.js.map +1 -1
- package/dist/esm/modules/appCatalog/ui/detail/AppDoor.d.ts +20 -0
- package/dist/esm/modules/appCatalog/ui/detail/AppDoor.js +59 -0
- package/dist/esm/modules/appCatalog/ui/detail/AppDoor.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/detail/DetailTabs.d.ts +64 -0
- package/dist/esm/modules/appCatalog/ui/detail/DetailTabs.js +90 -0
- package/dist/esm/modules/appCatalog/ui/detail/DetailTabs.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/detail/FeedbackSection.d.ts +13 -0
- package/dist/esm/modules/appCatalog/ui/detail/FeedbackSection.js +433 -0
- package/dist/esm/modules/appCatalog/ui/detail/FeedbackSection.js.map +1 -0
- package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js +18 -1
- package/dist/esm/modules/appCatalog/ui/pages/AppCatalogPage.js.map +1 -1
- package/dist/esm/modules/appCatalog/utils/accessTabLabel.d.ts +30 -0
- package/dist/esm/modules/appCatalog/utils/accessTabLabel.js +34 -0
- package/dist/esm/modules/appCatalog/utils/accessTabLabel.js.map +1 -0
- package/dist/index.css +269 -5
- package/package.json +4 -4
- package/src/__tests__/modules/appCatalog/ui/catalog/AppDetailPanel.appSwitch.test.tsx +17 -3
- package/src/__tests__/modules/appCatalog/ui/catalog/RequestAppDialog.test.tsx +113 -0
- package/src/__tests__/modules/appCatalog/ui/components/AccessRequestSection.test.tsx +6 -4
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.background.test.tsx +25 -10
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.doorAndTabs.test.tsx +193 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.escape.test.tsx +2 -2
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.sectionOrder.test.tsx +32 -9
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.subResourceTab.test.tsx +125 -0
- package/src/__tests__/modules/appCatalog/ui/detail/AppDetails.tags.test.tsx +2 -2
- package/src/__tests__/modules/appCatalog/ui/detail/FeedbackSection.emptyState.test.tsx +181 -0
- package/src/__tests__/modules/appCatalog/ui/detail/FeedbackSection.reviewStatus.test.tsx +131 -0
- package/src/__tests__/modules/appCatalog/utils/accessTabLabel.test.ts +206 -0
- package/src/__tests__/ui/components/header/Header.loginHidden.test.tsx +1 -1
- package/src/index.css +269 -5
- package/src/modules/appCatalog/ui/catalog/AppCatalogGrid.tsx +24 -0
- package/src/modules/appCatalog/ui/catalog/AppDetailPanel.tsx +46 -2
- package/src/modules/appCatalog/ui/catalog/RequestAppDialog.tsx +169 -0
- package/src/modules/appCatalog/ui/components/AccessPrerequisiteChain.tsx +3 -0
- package/src/modules/appCatalog/ui/components/AccessRequestSection.tsx +9 -4
- package/src/modules/appCatalog/ui/components/SubResourceDetailPanel.tsx +4 -1
- package/src/modules/appCatalog/ui/detail/AppDetails.tsx +574 -554
- package/src/modules/appCatalog/ui/detail/AppDoor.tsx +97 -0
- package/src/modules/appCatalog/ui/detail/DetailTabs.tsx +195 -0
- package/src/modules/appCatalog/ui/detail/FeedbackSection.tsx +605 -0
- package/src/modules/appCatalog/ui/pages/AppCatalogPage.tsx +20 -1
- package/src/modules/appCatalog/utils/accessTabLabel.ts +95 -0
- package/dist/esm/modules/appCatalog/ui/detail/CommentsSection.d.ts +0 -3
- package/dist/esm/modules/appCatalog/ui/detail/CommentsSection.js +0 -228
- package/dist/esm/modules/appCatalog/ui/detail/CommentsSection.js.map +0 -1
- package/src/__tests__/modules/appCatalog/ui/detail/CommentsSection.emptyState.test.tsx +0 -64
- package/src/__tests__/modules/appCatalog/ui/detail/CommentsSection.reviewStatus.test.tsx +0 -93
- package/src/modules/appCatalog/ui/detail/CommentsSection.tsx +0 -296
- /package/dist/esm/__tests__/modules/appCatalog/ui/{detail/CommentsSection.emptyState.test.d.ts → catalog/RequestAppDialog.test.d.ts} +0 -0
- /package/dist/esm/__tests__/modules/appCatalog/ui/detail/{CommentsSection.reviewStatus.test.d.ts → AppDetails.doorAndTabs.test.d.ts} +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { jsxs,
|
|
2
|
-
import {
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useSearch } from "@tanstack/react-router";
|
|
3
|
+
import { ExternalLink, Trash2, Plus, CalendarPlus, Clock } from "lucide-react";
|
|
3
4
|
import React__default from "react";
|
|
4
5
|
import { useHotkeys } from "react-hotkeys-hook";
|
|
5
|
-
import { cn } from "../../../../lib/utils.js";
|
|
6
6
|
import { Badge } from "../../../../ui/badge.js";
|
|
7
7
|
import { Button } from "../../../../ui/button.js";
|
|
8
8
|
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "../../../../ui/accordion.js";
|
|
9
9
|
import { AccessRequestSection } from "../components/AccessRequestSection.js";
|
|
10
10
|
import { AccessPrerequisiteChain } from "../components/AccessPrerequisiteChain.js";
|
|
11
|
-
import {
|
|
11
|
+
import { hasQuickJumps, QuickJumpBar } from "../components/QuickJumpBar.js";
|
|
12
12
|
import { useAppCatalogFilters } from "../context/AppCatalogFiltersContext.js";
|
|
13
13
|
import { PersonBadge } from "../components/PersonBadge.js";
|
|
14
14
|
import { useUser } from "../../../auth/AuthContext.js";
|
|
@@ -25,34 +25,29 @@ import { formatRelativeTime } from "../../utils/formatRelativeTime.js";
|
|
|
25
25
|
import { TierVariantsSection } from "../components/TierVariantsSection.js";
|
|
26
26
|
import { SubResourcesSection } from "../components/SubResourcesSection.js";
|
|
27
27
|
import { getChildResources } from "../../utils/resolveHelpers.js";
|
|
28
|
-
import {
|
|
28
|
+
import { FeedbackSection } from "./FeedbackSection.js";
|
|
29
29
|
import { displayUrl } from "../../utils/displayUrl.js";
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return /* @__PURE__ */
|
|
47
|
-
"
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
className
|
|
52
|
-
),
|
|
53
|
-
children: /* @__PURE__ */ jsx(AppWindow, { className: "size-6" })
|
|
54
|
-
}
|
|
55
|
-
);
|
|
30
|
+
import { accessTabLabel } from "../../utils/accessTabLabel.js";
|
|
31
|
+
import { AppDoor } from "./AppDoor.js";
|
|
32
|
+
import { DetailTabs } from "./DetailTabs.js";
|
|
33
|
+
const TAB = {
|
|
34
|
+
overview: "overview",
|
|
35
|
+
access: "access",
|
|
36
|
+
resources: "resources",
|
|
37
|
+
documentation: "documentation",
|
|
38
|
+
notes: "notes"
|
|
39
|
+
};
|
|
40
|
+
function Section({
|
|
41
|
+
title,
|
|
42
|
+
hint,
|
|
43
|
+
first,
|
|
44
|
+
children
|
|
45
|
+
}) {
|
|
46
|
+
return /* @__PURE__ */ jsxs("div", { className: first ? "" : "mt-7", children: [
|
|
47
|
+
/* @__PURE__ */ jsx("h3", { className: "section-label mb-1.5", children: title }),
|
|
48
|
+
hint && /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-muted-foreground", children: hint }),
|
|
49
|
+
children
|
|
50
|
+
] });
|
|
56
51
|
}
|
|
57
52
|
function AppScreenshot({ app }) {
|
|
58
53
|
var _a;
|
|
@@ -80,39 +75,24 @@ function AppScreenshot({ app }) {
|
|
|
80
75
|
(imageError || isLoadingImage) && /* @__PURE__ */ jsx("div", { className: "w-full h-64 bg-muted/30 flex items-center justify-center text-muted-foreground text-sm", children: isLoadingImage ? "Loading screenshot..." : "No screenshot available" })
|
|
81
76
|
] }) });
|
|
82
77
|
}
|
|
83
|
-
function TiersAndSubResourcesPanel({ app }) {
|
|
84
|
-
const { resources } = useAppCatalogContext();
|
|
85
|
-
const { state: filterState } = useAppCatalogFilters();
|
|
86
|
-
const appSubResources = React__default.useMemo(
|
|
87
|
-
() => getChildResources(resources, app.slug),
|
|
88
|
-
[resources, app.slug]
|
|
89
|
-
);
|
|
90
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
91
|
-
app.tiers && app.tiers.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsx(TierVariantsSection, { tiers: app.tiers }) }),
|
|
92
|
-
appSubResources.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsx(
|
|
93
|
-
SubResourcesSection,
|
|
94
|
-
{
|
|
95
|
-
subResources: appSubResources,
|
|
96
|
-
parentSlug: app.slug,
|
|
97
|
-
initialSearch: filterState.searchValue
|
|
98
|
-
}
|
|
99
|
-
) })
|
|
100
|
-
] });
|
|
101
|
-
}
|
|
102
78
|
function AppDetails({
|
|
103
79
|
app,
|
|
104
80
|
onAppClick,
|
|
105
81
|
onClosePanel
|
|
106
82
|
}) {
|
|
107
|
-
var _a, _b, _c
|
|
83
|
+
var _a, _b, _c;
|
|
108
84
|
const [isGalleryOpen, setIsGalleryOpen] = React__default.useState(false);
|
|
109
85
|
const [galleryInitialIndex, setGalleryInitialIndex] = React__default.useState(0);
|
|
86
|
+
const [composeRequests, setComposeRequests] = React__default.useState(0);
|
|
110
87
|
const { approvalMethods, resources: allResources } = useAppCatalogContext();
|
|
111
88
|
const { recordClick } = useAppClickHistory();
|
|
112
89
|
const updateApp = useUpdateApp();
|
|
113
90
|
const [draftSource, setDraftSource] = React__default.useState(null);
|
|
114
91
|
const user = useUser();
|
|
115
92
|
const isAdmin = (user == null ? void 0 : user.isAdmin) ?? false;
|
|
93
|
+
const { state: filterState } = useAppCatalogFilters();
|
|
94
|
+
const search = useSearch({ strict: false });
|
|
95
|
+
const subSlug = search.sub;
|
|
116
96
|
const displayTags = (app.tags ?? []).filter((tag) => !tag.includes(":"));
|
|
117
97
|
const sourceUrls = ((_a = app.sources) == null ? void 0 : _a.map((s) => typeof s === "string" ? s : s.url)) ?? [];
|
|
118
98
|
const displaySources = draftSource !== null ? [...sourceUrls, draftSource] : sourceUrls;
|
|
@@ -125,6 +105,10 @@ function AppDetails({
|
|
|
125
105
|
}
|
|
126
106
|
return byUrl;
|
|
127
107
|
}, [app.sources]);
|
|
108
|
+
const children = React__default.useMemo(
|
|
109
|
+
() => getChildResources(allResources, app.slug),
|
|
110
|
+
[allResources, app.slug]
|
|
111
|
+
);
|
|
128
112
|
useHotkeys(
|
|
129
113
|
"enter",
|
|
130
114
|
() => {
|
|
@@ -156,122 +140,15 @@ function AppDetails({
|
|
|
156
140
|
var _a2;
|
|
157
141
|
return a.slug === ((_a2 = app.deprecated) == null ? void 0 : _a2.replacementSlug);
|
|
158
142
|
}) : null;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
{
|
|
169
|
-
variant: app.deprecated.type === "discouraged" ? "secondary" : "destructive",
|
|
170
|
-
children: app.deprecated.type === "discouraged" ? "Discouraged" : "Deprecated"
|
|
171
|
-
}
|
|
172
|
-
)
|
|
173
|
-
] }),
|
|
174
|
-
isAdmin && /* @__PURE__ */ jsxs("div", { className: "mt-1 px-3", children: [
|
|
175
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mr-2", children: "Slug:" }),
|
|
176
|
-
/* @__PURE__ */ jsx(
|
|
177
|
-
InlineEditableField,
|
|
178
|
-
{
|
|
179
|
-
value: app.slug,
|
|
180
|
-
onSave: (slug) => updateApp.mutate({ id: app.id, data: { slug } }),
|
|
181
|
-
className: "text-sm"
|
|
182
|
-
}
|
|
183
|
-
)
|
|
184
|
-
] }),
|
|
185
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-stretch gap-3 px-3", children: [
|
|
186
|
-
isAdmin ? /* @__PURE__ */ jsx(
|
|
187
|
-
InlineEditableField,
|
|
188
|
-
{
|
|
189
|
-
value: app.appUrl ?? "",
|
|
190
|
-
onSave: (appUrl) => updateApp.mutate({ id: app.id, data: { appUrl } }),
|
|
191
|
-
placeholder: "App URL",
|
|
192
|
-
renderView: (url) => url ? /* @__PURE__ */ jsxs(
|
|
193
|
-
"a",
|
|
194
|
-
{
|
|
195
|
-
href: url,
|
|
196
|
-
target: "_blank",
|
|
197
|
-
rel: "noopener noreferrer",
|
|
198
|
-
onClick: () => recordClick(app.slug),
|
|
199
|
-
className: "inline-flex items-center gap-1 rounded-md py-1 text-sm text-blue-600 hover:bg-accent/30 hover:underline dark:text-blue-400 transition-all",
|
|
200
|
-
children: [
|
|
201
|
-
displayUrl(url),
|
|
202
|
-
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3.5 shrink-0 opacity-40 group-hover:opacity-100 transition-opacity" })
|
|
203
|
-
]
|
|
204
|
-
}
|
|
205
|
-
) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" })
|
|
206
|
-
}
|
|
207
|
-
) : app.appUrl ? /* @__PURE__ */ jsxs(
|
|
208
|
-
"a",
|
|
209
|
-
{
|
|
210
|
-
href: app.appUrl,
|
|
211
|
-
target: "_blank",
|
|
212
|
-
rel: "noopener noreferrer",
|
|
213
|
-
onClick: () => recordClick(app.slug),
|
|
214
|
-
className: cn(
|
|
215
|
-
// The row's one inset and icon gap, and its height stated
|
|
216
|
-
// rather than left to the taller neighbour.
|
|
217
|
-
"inline-flex min-h-[34px] items-center gap-1.5 rounded-md px-3 text-sm font-medium shadow-sm",
|
|
218
|
-
// Only ever ONE solid brand fill in this row: it goes to
|
|
219
|
-
// Quick Jump's submit when there is one, because that is
|
|
220
|
-
// the control that acts on something the user typed.
|
|
221
|
-
hasQuickJumps(app) ? QUIET_FILL : LEAVE_FILL,
|
|
222
|
-
LEAP
|
|
223
|
-
),
|
|
224
|
-
title: displayUrl(app.appUrl),
|
|
225
|
-
"aria-label": `Open ${app.displayName} in a new tab (${displayUrl(app.appUrl)})`,
|
|
226
|
-
children: [
|
|
227
|
-
/* @__PURE__ */ jsxs("span", { className: "max-w-[280px] truncate whitespace-nowrap", children: [
|
|
228
|
-
"Go to ",
|
|
229
|
-
displayUrl(app.appUrl)
|
|
230
|
-
] }),
|
|
231
|
-
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3.5 shrink-0" })
|
|
232
|
-
]
|
|
233
|
-
}
|
|
234
|
-
) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" }),
|
|
235
|
-
/* @__PURE__ */ jsx(QuickJumpBar, { app })
|
|
236
|
-
] })
|
|
237
|
-
] })
|
|
238
|
-
] }) }),
|
|
239
|
-
app.deprecated && (() => {
|
|
240
|
-
const deprecationType = app.deprecated.type || "deprecated";
|
|
241
|
-
const isDiscouraged = deprecationType === "discouraged";
|
|
242
|
-
return /* @__PURE__ */ jsxs(
|
|
243
|
-
"div",
|
|
244
|
-
{
|
|
245
|
-
className: isDiscouraged ? "mt-6 p-4 border border-yellow-500/50 rounded-lg bg-yellow-50 dark:bg-yellow-950/20" : "mt-6 p-4 border border-destructive/50 rounded-lg bg-destructive/10",
|
|
246
|
-
children: [
|
|
247
|
-
/* @__PURE__ */ jsx(
|
|
248
|
-
"h3",
|
|
249
|
-
{
|
|
250
|
-
className: isDiscouraged ? "text-sm font-semibold text-yellow-700 dark:text-yellow-500 mb-2" : "text-sm font-semibold text-destructive mb-2",
|
|
251
|
-
children: isDiscouraged ? "Usage discouraged" : "This application is deprecated"
|
|
252
|
-
}
|
|
253
|
-
),
|
|
254
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-3", children: app.deprecated.comment }),
|
|
255
|
-
replacementApp && /* @__PURE__ */ jsxs(
|
|
256
|
-
"button",
|
|
257
|
-
{
|
|
258
|
-
type: "button",
|
|
259
|
-
onClick: () => onAppClick == null ? void 0 : onAppClick(replacementApp),
|
|
260
|
-
className: "text-sm font-medium text-primary hover:underline inline-flex items-center gap-1",
|
|
261
|
-
children: [
|
|
262
|
-
"View replacement: ",
|
|
263
|
-
replacementApp.displayName,
|
|
264
|
-
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3" })
|
|
265
|
-
]
|
|
266
|
-
}
|
|
267
|
-
)
|
|
268
|
-
]
|
|
269
|
-
}
|
|
270
|
-
);
|
|
271
|
-
})(),
|
|
272
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
273
|
-
/* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-medium", children: "Description" }),
|
|
274
|
-
isAdmin ? /* @__PURE__ */ jsx(
|
|
143
|
+
const access = accessTabLabel(app, approvalMethods);
|
|
144
|
+
const hasResourcesTab = children.length > 0 || (((_c = app.tiers) == null ? void 0 : _c.length) ?? 0) > 0;
|
|
145
|
+
const resourcesLabel = children.length ? app.childrenLabel ?? "Resources" : "Environments";
|
|
146
|
+
const tabs = [
|
|
147
|
+
{
|
|
148
|
+
id: TAB.overview,
|
|
149
|
+
label: "Overview",
|
|
150
|
+
render: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
151
|
+
/* @__PURE__ */ jsx(Section, { title: "Description", first: true, children: isAdmin ? /* @__PURE__ */ jsx(
|
|
275
152
|
InlineEditableField,
|
|
276
153
|
{
|
|
277
154
|
value: app.description ?? "",
|
|
@@ -280,17 +157,8 @@ function AppDetails({
|
|
|
280
157
|
placeholder: "Description",
|
|
281
158
|
className: "min-h-[4rem] resize-y text-sm text-muted-foreground"
|
|
282
159
|
}
|
|
283
|
-
) : app.description ? /* @__PURE__ */ jsx(MarkdownText, { className: "prose prose-sm max-w-none text-sm text-muted-foreground [&_p]:m-0", children: app.description }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "—" })
|
|
284
|
-
|
|
285
|
-
/* @__PURE__ */ jsx(AccessPrerequisiteChain, { resource: app, onOpenParent: onAppClick }),
|
|
286
|
-
/* @__PURE__ */ jsx(AccessRequestSection, { app, approvalMethods }),
|
|
287
|
-
app.screenshotIds && app.screenshotIds.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
288
|
-
/* @__PURE__ */ jsxs("h3", { className: "mb-2 text-sm font-medium", children: [
|
|
289
|
-
"Screenshots (",
|
|
290
|
-
app.screenshotIds.length,
|
|
291
|
-
")"
|
|
292
|
-
] }),
|
|
293
|
-
/* @__PURE__ */ jsxs(
|
|
160
|
+
) : app.description ? /* @__PURE__ */ jsx(MarkdownText, { className: "prose prose-sm max-w-none text-sm text-muted-foreground [&_p]:m-0", children: app.description }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "—" }) }),
|
|
161
|
+
app.screenshotIds && app.screenshotIds.length > 0 && /* @__PURE__ */ jsx(Section, { title: `Screenshots (${app.screenshotIds.length})`, children: /* @__PURE__ */ jsxs(
|
|
294
162
|
"button",
|
|
295
163
|
{
|
|
296
164
|
type: "button",
|
|
@@ -306,102 +174,167 @@ function AppDetails({
|
|
|
306
174
|
] })
|
|
307
175
|
]
|
|
308
176
|
}
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
/* @__PURE__ */ jsx("
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
app.background && /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
343
|
-
/* @__PURE__ */ jsx("h3", { className: "text-muted-foreground mb-2 text-xs font-medium", children: "Background" }),
|
|
344
|
-
/* @__PURE__ */ jsx(MarkdownText, { className: "prose prose-sm text-muted-foreground max-w-none text-sm [&_p]:mt-0 [&_p]:mb-2 [&_p:last-child]:mb-0", children: app.background })
|
|
345
|
-
] }),
|
|
346
|
-
(app.aiPrompt || app.aiMemory) && /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "mt-6", children: /* @__PURE__ */ jsxs(
|
|
347
|
-
AccordionItem,
|
|
348
|
-
{
|
|
349
|
-
value: "technical-info",
|
|
350
|
-
className: "border rounded-lg px-4",
|
|
351
|
-
children: [
|
|
352
|
-
/* @__PURE__ */ jsx(AccordionTrigger, { className: "text-sm hover:no-underline py-3", children: "Technical information" }),
|
|
353
|
-
/* @__PURE__ */ jsxs(AccordionContent, { className: "pb-3 space-y-3", children: [
|
|
354
|
-
app.aiPrompt && /* @__PURE__ */ jsxs("div", { children: [
|
|
355
|
-
/* @__PURE__ */ jsx("h4", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "AI Prompt" }),
|
|
356
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs whitespace-pre-wrap", children: app.aiPrompt })
|
|
357
|
-
] }),
|
|
358
|
-
app.aiMemory && /* @__PURE__ */ jsxs("div", { children: [
|
|
359
|
-
/* @__PURE__ */ jsx("h4", { className: "mb-1 text-xs font-medium text-muted-foreground", children: "AI Memory" }),
|
|
360
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs whitespace-pre-wrap", children: app.aiMemory })
|
|
361
|
-
] })
|
|
362
|
-
] })
|
|
363
|
-
]
|
|
177
|
+
) }),
|
|
178
|
+
app.ownerPersonSlug && /* @__PURE__ */ jsx(Section, { title: "Owner", hint: "Who is responsible for this resource", children: /* @__PURE__ */ jsx(PersonBadge, { slug: app.ownerPersonSlug }) }),
|
|
179
|
+
displayTags.length > 0 && /* @__PURE__ */ jsx(Section, { title: "Tags", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: displayTags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: tag }, tag)) }) }),
|
|
180
|
+
app.teams && app.teams.length > 0 && /* @__PURE__ */ jsx(Section, { title: "Teams", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: app.teams.map((team) => /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-xs", children: team }, team)) }) })
|
|
181
|
+
] })
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: TAB.access,
|
|
185
|
+
label: `Access — ${access.route}`,
|
|
186
|
+
chip: access.chip,
|
|
187
|
+
render: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
188
|
+
/* @__PURE__ */ jsx(AccessPrerequisiteChain, { resource: app, onOpenParent: onAppClick }),
|
|
189
|
+
/* @__PURE__ */ jsx(AccessRequestSection, { app, approvalMethods })
|
|
190
|
+
] })
|
|
191
|
+
},
|
|
192
|
+
...hasResourcesTab ? [
|
|
193
|
+
{
|
|
194
|
+
id: TAB.resources,
|
|
195
|
+
label: resourcesLabel,
|
|
196
|
+
chip: children.length ? String(children.length) : void 0,
|
|
197
|
+
render: () => {
|
|
198
|
+
var _a2;
|
|
199
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
200
|
+
app.tiers && app.tiers.length > 0 && /* @__PURE__ */ jsx(TierVariantsSection, { tiers: app.tiers }),
|
|
201
|
+
children.length > 0 && /* @__PURE__ */ jsx("div", { className: ((_a2 = app.tiers) == null ? void 0 : _a2.length) ? "mt-7" : "", children: /* @__PURE__ */ jsx(
|
|
202
|
+
SubResourcesSection,
|
|
203
|
+
{
|
|
204
|
+
subResources: children,
|
|
205
|
+
parentSlug: app.slug,
|
|
206
|
+
initialSearch: filterState.searchValue
|
|
207
|
+
}
|
|
208
|
+
) })
|
|
209
|
+
] });
|
|
364
210
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
"
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
211
|
+
}
|
|
212
|
+
] : [],
|
|
213
|
+
{
|
|
214
|
+
id: TAB.documentation,
|
|
215
|
+
label: "Documentation",
|
|
216
|
+
render: () => {
|
|
217
|
+
var _a2, _b2;
|
|
218
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
219
|
+
app.links && app.links.length > 0 && /* @__PURE__ */ jsx(Section, { title: "Documentation", first: true, children: /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: app.links.map((link) => /* @__PURE__ */ jsxs(
|
|
220
|
+
"a",
|
|
221
|
+
{
|
|
222
|
+
href: link.url,
|
|
223
|
+
target: "_blank",
|
|
224
|
+
rel: "noopener noreferrer",
|
|
225
|
+
className: "flex items-center gap-1 text-xs text-muted-foreground hover:text-primary truncate",
|
|
226
|
+
children: [
|
|
227
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3 shrink-0" }),
|
|
228
|
+
link.title || displayUrl(link.url)
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
link.url
|
|
232
|
+
)) }) }),
|
|
233
|
+
app.background && /* @__PURE__ */ jsx(Section, { title: "Background", children: /* @__PURE__ */ jsx(MarkdownText, { className: "prose prose-sm text-muted-foreground max-w-none text-sm [&_p]:mt-0 [&_p]:mb-2 [&_p:last-child]:mb-0", children: app.background }) }),
|
|
234
|
+
/* @__PURE__ */ jsx(Section, { title: "Sources", first: !app.background, children: isAdmin ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
235
|
+
/* @__PURE__ */ jsx("ul", { className: "space-y-2", children: displaySources.map((url, index) => {
|
|
236
|
+
const isDraft = draftSource !== null && index === sourceUrls.length;
|
|
237
|
+
return /* @__PURE__ */ jsxs(
|
|
238
|
+
"li",
|
|
239
|
+
{
|
|
240
|
+
className: "group flex items-center gap-2 text-xs",
|
|
241
|
+
children: [
|
|
242
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground shrink-0 tabular-nums", children: [
|
|
243
|
+
index + 1,
|
|
244
|
+
"."
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ jsx(
|
|
247
|
+
InlineEditableField,
|
|
248
|
+
{
|
|
249
|
+
value: url,
|
|
250
|
+
initialEditMode: isDraft,
|
|
251
|
+
onCancel: isDraft ? () => setDraftSource(null) : void 0,
|
|
252
|
+
onSave: (newUrl) => {
|
|
253
|
+
if (isDraft) {
|
|
254
|
+
setDraftSource(null);
|
|
255
|
+
if (newUrl) {
|
|
256
|
+
updateApp.mutate({
|
|
257
|
+
id: app.id,
|
|
258
|
+
data: { sources: [...sourceUrls, newUrl] }
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
const next = [...sourceUrls];
|
|
263
|
+
next[index] = newUrl;
|
|
264
|
+
updateApp.mutate({
|
|
265
|
+
id: app.id,
|
|
266
|
+
data: { sources: next.filter(Boolean) }
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
placeholder: "https://...",
|
|
271
|
+
viewClassName: "flex-1 min-w-0",
|
|
272
|
+
renderView: (val) => val ? /* @__PURE__ */ jsxs(
|
|
273
|
+
"a",
|
|
274
|
+
{
|
|
275
|
+
href: val,
|
|
276
|
+
target: "_blank",
|
|
277
|
+
rel: "noopener noreferrer",
|
|
278
|
+
className: "hover:text-primary inline-flex items-center gap-1 truncate",
|
|
279
|
+
children: [
|
|
280
|
+
displayUrl(val),
|
|
281
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3 shrink-0" })
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" })
|
|
285
|
+
}
|
|
286
|
+
),
|
|
287
|
+
!isDraft && pulseByUrl.has(url) && /* @__PURE__ */ jsx(
|
|
288
|
+
SourcePulse,
|
|
289
|
+
{
|
|
290
|
+
pulse: pulseByUrl.get(url),
|
|
291
|
+
className: "ml-auto"
|
|
292
|
+
}
|
|
293
|
+
),
|
|
294
|
+
!isDraft && /* @__PURE__ */ jsx(
|
|
295
|
+
Button,
|
|
296
|
+
{
|
|
297
|
+
type: "button",
|
|
298
|
+
variant: "ghost",
|
|
299
|
+
size: "icon-sm",
|
|
300
|
+
"aria-label": "Remove source",
|
|
301
|
+
className: "shrink-0 text-muted-foreground hover:text-destructive",
|
|
302
|
+
onClick: () => {
|
|
303
|
+
const next = sourceUrls.filter(
|
|
304
|
+
(_, i) => i !== index
|
|
305
|
+
);
|
|
306
|
+
updateApp.mutate({
|
|
307
|
+
id: app.id,
|
|
308
|
+
data: { sources: next }
|
|
309
|
+
});
|
|
310
|
+
},
|
|
311
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5" })
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
isDraft ? "draft" : `${index}-${url}`
|
|
317
|
+
);
|
|
318
|
+
}) }),
|
|
319
|
+
/* @__PURE__ */ jsxs(
|
|
320
|
+
Button,
|
|
321
|
+
{
|
|
322
|
+
type: "button",
|
|
323
|
+
variant: "ghost",
|
|
324
|
+
size: "sm",
|
|
325
|
+
className: "mt-2 gap-1 text-muted-foreground",
|
|
326
|
+
onClick: () => setDraftSource(""),
|
|
327
|
+
children: [
|
|
328
|
+
/* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
|
|
329
|
+
"Add source"
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
] }) : /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: sourceUrls.map((url, index) => (
|
|
334
|
+
// `group` so hovering anywhere on the row fades that source's
|
|
335
|
+
// track in — the mark sits in a right-hand column, and row
|
|
336
|
+
// hover is what ties the two ends of a wide row together.
|
|
337
|
+
/* @__PURE__ */ jsxs(
|
|
405
338
|
"li",
|
|
406
339
|
{
|
|
407
340
|
className: "group flex items-center gap-2 text-xs",
|
|
@@ -410,134 +343,193 @@ function AppDetails({
|
|
|
410
343
|
index + 1,
|
|
411
344
|
"."
|
|
412
345
|
] }),
|
|
413
|
-
/* @__PURE__ */
|
|
414
|
-
|
|
346
|
+
url ? /* @__PURE__ */ jsxs(
|
|
347
|
+
"a",
|
|
415
348
|
{
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
id: app.id,
|
|
425
|
-
data: { sources: [...sourceUrls, newUrl] }
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
} else {
|
|
429
|
-
const next = [...sourceUrls];
|
|
430
|
-
next[index] = newUrl;
|
|
431
|
-
updateApp.mutate({
|
|
432
|
-
id: app.id,
|
|
433
|
-
data: { sources: next.filter(Boolean) }
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
placeholder: "https://...",
|
|
438
|
-
viewClassName: "flex-1 min-w-0",
|
|
439
|
-
renderView: (val) => val ? /* @__PURE__ */ jsxs(
|
|
440
|
-
"a",
|
|
441
|
-
{
|
|
442
|
-
href: val,
|
|
443
|
-
target: "_blank",
|
|
444
|
-
rel: "noopener noreferrer",
|
|
445
|
-
className: "hover:text-primary inline-flex items-center gap-1 truncate",
|
|
446
|
-
children: [
|
|
447
|
-
displayUrl(val),
|
|
448
|
-
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3 shrink-0" })
|
|
449
|
-
]
|
|
450
|
-
}
|
|
451
|
-
) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" })
|
|
349
|
+
href: url,
|
|
350
|
+
target: "_blank",
|
|
351
|
+
rel: "noopener noreferrer",
|
|
352
|
+
className: "hover:text-primary inline-flex min-w-0 items-center gap-1 truncate",
|
|
353
|
+
children: [
|
|
354
|
+
displayUrl(url),
|
|
355
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3 shrink-0" })
|
|
356
|
+
]
|
|
452
357
|
}
|
|
453
|
-
),
|
|
454
|
-
|
|
358
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" }),
|
|
359
|
+
pulseByUrl.has(url) && /* @__PURE__ */ jsx(
|
|
455
360
|
SourcePulse,
|
|
456
361
|
{
|
|
457
362
|
pulse: pulseByUrl.get(url),
|
|
458
363
|
className: "ml-auto"
|
|
459
364
|
}
|
|
460
|
-
),
|
|
461
|
-
!isDraft && /* @__PURE__ */ jsx(
|
|
462
|
-
Button,
|
|
463
|
-
{
|
|
464
|
-
type: "button",
|
|
465
|
-
variant: "ghost",
|
|
466
|
-
size: "icon-sm",
|
|
467
|
-
"aria-label": "Remove source",
|
|
468
|
-
className: "shrink-0 text-muted-foreground hover:text-destructive",
|
|
469
|
-
onClick: () => {
|
|
470
|
-
const next = sourceUrls.filter(
|
|
471
|
-
(_, i) => i !== index
|
|
472
|
-
);
|
|
473
|
-
updateApp.mutate({
|
|
474
|
-
id: app.id,
|
|
475
|
-
data: { sources: next }
|
|
476
|
-
});
|
|
477
|
-
},
|
|
478
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5" })
|
|
479
|
-
}
|
|
480
365
|
)
|
|
481
366
|
]
|
|
482
367
|
},
|
|
483
|
-
|
|
484
|
-
)
|
|
485
|
-
}) }),
|
|
486
|
-
/* @__PURE__ */ jsxs(
|
|
487
|
-
|
|
368
|
+
index
|
|
369
|
+
)
|
|
370
|
+
)) }) }),
|
|
371
|
+
(app.createdAt || ((_a2 = app.freshness) == null ? void 0 : _a2.lastCheckedAt)) && /* @__PURE__ */ jsx(Section, { title: "Dates", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-5 gap-y-1", children: [
|
|
372
|
+
app.createdAt && /* @__PURE__ */ jsxs(
|
|
373
|
+
"span",
|
|
374
|
+
{
|
|
375
|
+
className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
376
|
+
title: app.createdAt,
|
|
377
|
+
children: [
|
|
378
|
+
/* @__PURE__ */ jsx(CalendarPlus, { className: "size-3" }),
|
|
379
|
+
"Added ",
|
|
380
|
+
formatRelativeTime(app.createdAt)
|
|
381
|
+
]
|
|
382
|
+
}
|
|
383
|
+
),
|
|
384
|
+
((_b2 = app.freshness) == null ? void 0 : _b2.lastCheckedAt) && /* @__PURE__ */ jsxs(
|
|
385
|
+
"span",
|
|
386
|
+
{
|
|
387
|
+
className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
388
|
+
title: app.freshness.lastContentChangeAt ? `Content last changed ${app.freshness.lastContentChangeAt} · last checked ${app.freshness.lastCheckedAt}` : `Last checked ${app.freshness.lastCheckedAt}`,
|
|
389
|
+
children: [
|
|
390
|
+
/* @__PURE__ */ jsx(Clock, { className: "size-3" }),
|
|
391
|
+
"Updated",
|
|
392
|
+
" ",
|
|
393
|
+
formatRelativeTime(
|
|
394
|
+
app.freshness.lastContentChangeAt ?? app.freshness.lastCheckedAt
|
|
395
|
+
),
|
|
396
|
+
app.freshness.isStale && /* @__PURE__ */ jsxs("span", { className: "italic opacity-75", children: [
|
|
397
|
+
" ",
|
|
398
|
+
"· may be out of date"
|
|
399
|
+
] })
|
|
400
|
+
]
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
] }) }),
|
|
404
|
+
(app.aiPrompt || app.aiMemory) && /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "mt-7", children: /* @__PURE__ */ jsxs(
|
|
405
|
+
AccordionItem,
|
|
488
406
|
{
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
size: "sm",
|
|
492
|
-
className: "mt-2 gap-1 text-muted-foreground",
|
|
493
|
-
onClick: () => setDraftSource(""),
|
|
407
|
+
value: "technical-info",
|
|
408
|
+
className: "border rounded-lg px-4",
|
|
494
409
|
children: [
|
|
495
|
-
/* @__PURE__ */ jsx(
|
|
496
|
-
"
|
|
410
|
+
/* @__PURE__ */ jsx(AccordionTrigger, { className: "text-sm hover:no-underline py-3", children: "Technical information" }),
|
|
411
|
+
/* @__PURE__ */ jsxs(AccordionContent, { className: "pb-3 space-y-3", children: [
|
|
412
|
+
app.aiPrompt && /* @__PURE__ */ jsxs("div", { children: [
|
|
413
|
+
/* @__PURE__ */ jsx("h4", { className: "section-label mb-1", children: "AI Prompt" }),
|
|
414
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs whitespace-pre-wrap", children: app.aiPrompt })
|
|
415
|
+
] }),
|
|
416
|
+
app.aiMemory && /* @__PURE__ */ jsxs("div", { children: [
|
|
417
|
+
/* @__PURE__ */ jsx("h4", { className: "section-label mb-1", children: "AI Memory" }),
|
|
418
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs whitespace-pre-wrap", children: app.aiMemory })
|
|
419
|
+
] })
|
|
420
|
+
] })
|
|
497
421
|
]
|
|
498
422
|
}
|
|
499
|
-
)
|
|
500
|
-
] })
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
423
|
+
) })
|
|
424
|
+
] });
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
id: TAB.notes,
|
|
429
|
+
label: "Notes & requests",
|
|
430
|
+
render: () => /* @__PURE__ */ jsx(FeedbackSection, { appSlug: app.slug, openComposer: composeRequests })
|
|
431
|
+
}
|
|
432
|
+
];
|
|
433
|
+
const band = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
434
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-7 gap-y-2", children: [
|
|
435
|
+
/* @__PURE__ */ jsx(AppDoor, { app, onOpen: () => recordClick(app.slug) }),
|
|
436
|
+
app.deprecated && /* @__PURE__ */ jsx(
|
|
437
|
+
Badge,
|
|
438
|
+
{
|
|
439
|
+
variant: app.deprecated.type === "discouraged" ? "secondary" : "destructive",
|
|
440
|
+
children: app.deprecated.type === "discouraged" ? "Discouraged" : "Deprecated"
|
|
441
|
+
}
|
|
442
|
+
),
|
|
443
|
+
/* @__PURE__ */ jsx(
|
|
444
|
+
Button,
|
|
445
|
+
{
|
|
446
|
+
type: "button",
|
|
447
|
+
size: "sm",
|
|
448
|
+
variant: "outline",
|
|
449
|
+
className: "ml-auto mr-10",
|
|
450
|
+
onClick: () => setComposeRequests((n) => n + 1),
|
|
451
|
+
children: "✎ Suggest a change"
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
] }),
|
|
455
|
+
app.nicknames && app.nicknames.length > 0 && /* @__PURE__ */ jsxs("p", { className: "mt-2.5 text-xs text-muted-foreground", children: [
|
|
456
|
+
"Also known as ",
|
|
457
|
+
app.nicknames.join(", ")
|
|
458
|
+
] }),
|
|
459
|
+
isAdmin && /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-x-6 gap-y-1", children: [
|
|
460
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
|
|
461
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Slug:" }),
|
|
462
|
+
/* @__PURE__ */ jsx(
|
|
463
|
+
InlineEditableField,
|
|
464
|
+
{
|
|
465
|
+
value: app.slug,
|
|
466
|
+
onSave: (slug) => updateApp.mutate({ id: app.id, data: { slug } }),
|
|
467
|
+
className: "text-sm"
|
|
468
|
+
}
|
|
469
|
+
)
|
|
538
470
|
] }),
|
|
539
|
-
/* @__PURE__ */
|
|
471
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
|
|
472
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "URL:" }),
|
|
473
|
+
/* @__PURE__ */ jsx(
|
|
474
|
+
InlineEditableField,
|
|
475
|
+
{
|
|
476
|
+
value: app.appUrl ?? "",
|
|
477
|
+
onSave: (appUrl) => updateApp.mutate({ id: app.id, data: { appUrl } }),
|
|
478
|
+
placeholder: "App URL",
|
|
479
|
+
className: "text-sm"
|
|
480
|
+
}
|
|
481
|
+
)
|
|
482
|
+
] })
|
|
540
483
|
] }),
|
|
484
|
+
hasQuickJumps(app) && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
|
485
|
+
/* @__PURE__ */ jsx("p", { className: "mb-1.5 text-xs text-muted-foreground", children: "Or go straight to a record:" }),
|
|
486
|
+
/* @__PURE__ */ jsx(QuickJumpBar, { app })
|
|
487
|
+
] }),
|
|
488
|
+
app.deprecated && (() => {
|
|
489
|
+
const isDiscouraged = app.deprecated.type === "discouraged";
|
|
490
|
+
return /* @__PURE__ */ jsxs(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
className: isDiscouraged ? "mt-4 rounded-lg border border-yellow-500/50 bg-yellow-50 p-4 dark:bg-yellow-950/20" : "mt-4 rounded-lg border border-destructive/50 bg-destructive/10 p-4",
|
|
494
|
+
children: [
|
|
495
|
+
/* @__PURE__ */ jsx(
|
|
496
|
+
"h3",
|
|
497
|
+
{
|
|
498
|
+
className: isDiscouraged ? "section-label mb-1.5 text-yellow-700 dark:text-yellow-500" : "section-label mb-1.5 text-destructive",
|
|
499
|
+
children: isDiscouraged ? "Usage discouraged" : "This application is deprecated"
|
|
500
|
+
}
|
|
501
|
+
),
|
|
502
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: app.deprecated.comment }),
|
|
503
|
+
replacementApp && /* @__PURE__ */ jsxs(
|
|
504
|
+
"button",
|
|
505
|
+
{
|
|
506
|
+
type: "button",
|
|
507
|
+
onClick: () => onAppClick == null ? void 0 : onAppClick(replacementApp),
|
|
508
|
+
className: "mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline",
|
|
509
|
+
children: [
|
|
510
|
+
"View replacement: ",
|
|
511
|
+
replacementApp.displayName,
|
|
512
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3" })
|
|
513
|
+
]
|
|
514
|
+
}
|
|
515
|
+
)
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
})()
|
|
520
|
+
] });
|
|
521
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
522
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-full flex-col", children: /* @__PURE__ */ jsx(
|
|
523
|
+
DetailTabs,
|
|
524
|
+
{
|
|
525
|
+
tabs,
|
|
526
|
+
band,
|
|
527
|
+
bandClassName: "-mx-6 -mt-5 px-6 pt-5 sm:-mx-8 sm:-mt-7 sm:px-8 sm:pt-7",
|
|
528
|
+
forcedTab: subSlug && hasResourcesTab ? TAB.resources : void 0,
|
|
529
|
+
requestTab: composeRequests > 0 ? TAB.notes : void 0,
|
|
530
|
+
requestNonce: composeRequests
|
|
531
|
+
}
|
|
532
|
+
) }),
|
|
541
533
|
/* @__PURE__ */ jsx(
|
|
542
534
|
ScreenshotGallery,
|
|
543
535
|
{
|