@burdenoff/microfe-admin 2026.625.1 → 2026.626.1
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/admin/components/AccessDenied.js +2 -2
- package/dist/admin/components/AccessDenied.js.map +1 -1
- package/dist/admin/components/ActivityFeed.js +4 -4
- package/dist/admin/components/ActivityFeed.js.map +1 -1
- package/dist/admin/components/Charts.js.map +1 -1
- package/dist/admin/components/ConfirmDialog.js +1 -1
- package/dist/admin/components/ConfirmDialog.js.map +1 -1
- package/dist/admin/components/FormSheet.js +1 -1
- package/dist/admin/components/FormSheet.js.map +1 -1
- package/dist/admin/components/TenantSsoPanel.js +1 -1
- package/dist/admin/components/TenantSsoPanel.js.map +1 -1
- package/dist/admin/components/Toast.js +11 -11
- package/dist/admin/components/Toast.js.map +1 -1
- package/dist/admin/components/forms/SubscriptionForm.js +2 -2
- package/dist/admin/components/forms/SubscriptionForm.js.map +1 -1
- package/dist/admin/components/forms/TenantForm.js +1 -1
- package/dist/admin/components/forms/UserForm.js +1 -1
- package/dist/admin/components/ui.js +3 -3
- package/dist/admin/components/ui.js.map +1 -1
- package/dist/admin/constants/index.js +33 -24
- package/dist/admin/constants/index.js.map +1 -1
- package/dist/admin/pages/AuditLogsPage.js +92 -77
- package/dist/admin/pages/AuditLogsPage.js.map +1 -1
- package/dist/admin/pages/BillingPage.js +95 -51
- package/dist/admin/pages/BillingPage.js.map +1 -1
- package/dist/admin/pages/CommunicationsPage.js +97 -92
- package/dist/admin/pages/CommunicationsPage.js.map +1 -1
- package/dist/admin/pages/ContentPagesPage.js +274 -259
- package/dist/admin/pages/ContentPagesPage.js.map +1 -1
- package/dist/admin/pages/DashboardPage.js +113 -84
- package/dist/admin/pages/DashboardPage.js.map +1 -1
- package/dist/admin/pages/FeatureFlagsPage.js +93 -75
- package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
- package/dist/admin/pages/OrganizationsListPage.js +105 -87
- package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
- package/dist/admin/pages/ProductsPage.js +138 -130
- package/dist/admin/pages/ProductsPage.js.map +1 -1
- package/dist/admin/pages/ReferralsPage.js +70 -52
- package/dist/admin/pages/ReferralsPage.js.map +1 -1
- package/dist/admin/pages/RolesPermissionsPage.js +136 -118
- package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
- package/dist/admin/pages/SREPage.js +34 -32
- package/dist/admin/pages/SREPage.js.map +1 -1
- package/dist/admin/pages/SandboxSettingsPage.js +360 -322
- package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage.js +63 -60
- package/dist/admin/pages/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SyncFailuresPage.js +120 -118
- package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
- package/dist/admin/pages/TenantDetailPage.js +261 -218
- package/dist/admin/pages/TenantDetailPage.js.map +1 -1
- package/dist/admin/pages/TenantFormRoutePage.js +65 -61
- package/dist/admin/pages/TenantFormRoutePage.js.map +1 -1
- package/dist/admin/pages/TenantsListPage.js +86 -71
- package/dist/admin/pages/TenantsListPage.js.map +1 -1
- package/dist/admin/pages/UsersListPage.js +128 -113
- package/dist/admin/pages/UsersListPage.js.map +1 -1
- package/dist/admin/pages/WaitlistPage.js +78 -63
- package/dist/admin/pages/WaitlistPage.js.map +1 -1
- package/dist/admin/pages/WorkflowsPage.js +107 -102
- package/dist/admin/pages/WorkflowsPage.js.map +1 -1
- package/dist/admin/pages/WorkspacesListPage.js +61 -49
- package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
- package/dist/node_modules/@hookform/resolvers/dist/resolvers.js +2 -2
- package/dist/node_modules/@hookform/resolvers/dist/resolvers.js.map +1 -1
- package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js +35 -26
- package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js.map +1 -1
- package/dist/node_modules/react-hook-form/dist/index.esm.js +609 -516
- package/dist/node_modules/react-hook-form/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,8 +8,9 @@ import { PermissionGuard as d } from "../components/PermissionGuard.js";
|
|
|
8
8
|
import "../components/index.js";
|
|
9
9
|
import { useGetPlatformProductStatsQuery as f, useListPlatformProductsQuery as p } from "../../generated/global-operations.js";
|
|
10
10
|
import { useCallback as m, useMemo as h, useState as g } from "react";
|
|
11
|
-
import { Database as _, ExternalLink as
|
|
12
|
-
import { jsx as
|
|
11
|
+
import { Database as _, ExternalLink as ee, Package as v, Search as y, Server as b } from "lucide-react";
|
|
12
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
13
|
+
import { PagePurpose as C } from "@burdenoff/fe-libs/ui";
|
|
13
14
|
import { gql as w } from "@apollo/client";
|
|
14
15
|
import { useApolloClient as T } from "@apollo/client/react";
|
|
15
16
|
//#region src/admin/pages/ProductsPage.tsx
|
|
@@ -213,7 +214,7 @@ function M() {
|
|
|
213
214
|
},
|
|
214
215
|
fetchPolicy: "cache-and-network",
|
|
215
216
|
skip: W
|
|
216
|
-
}), X = h(() => K?.platformProducts?.items ?? [], [K]), Z = K?.platformProducts?.total ?? 0, Q = Math.ceil(Z / E), $ = G?.platformProductStats,
|
|
217
|
+
}), X = h(() => K?.platformProducts?.items ?? [], [K]), Z = K?.platformProducts?.total ?? 0, Q = Math.ceil(Z / E), $ = G?.platformProductStats, te = m(async () => {
|
|
217
218
|
z(!0), V(null), U(null);
|
|
218
219
|
try {
|
|
219
220
|
let e = (await N.query({
|
|
@@ -247,145 +248,152 @@ function M() {
|
|
|
247
248
|
z(!1);
|
|
248
249
|
}
|
|
249
250
|
}, [N, Y]);
|
|
250
|
-
return /* @__PURE__ */
|
|
251
|
+
return /* @__PURE__ */ x(d, {
|
|
251
252
|
allowed: w,
|
|
252
253
|
isLoading: M,
|
|
253
254
|
pageTitle: "Products",
|
|
254
255
|
denyMessage: "You don't have permission to view products.",
|
|
255
|
-
children: /* @__PURE__ */
|
|
256
|
+
children: /* @__PURE__ */ S(a, {
|
|
256
257
|
title: "Products",
|
|
257
258
|
gradientWord: "Products",
|
|
258
259
|
description: `Platform products and services${Z ? ` · ${Z} total` : ""}`,
|
|
259
|
-
actions: /* @__PURE__ */
|
|
260
|
-
onClick:
|
|
260
|
+
actions: /* @__PURE__ */ S(n, {
|
|
261
|
+
onClick: te,
|
|
261
262
|
disabled: R,
|
|
262
|
-
children: [/* @__PURE__ */
|
|
263
|
+
children: [/* @__PURE__ */ x(_, { className: "mr-2 h-4 w-4" }), R ? "Seeding..." : "Seed Active Products"]
|
|
263
264
|
}),
|
|
264
|
-
children: [
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
className: "
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
265
|
+
children: [
|
|
266
|
+
/* @__PURE__ */ x(C, {
|
|
267
|
+
className: "mb-6",
|
|
268
|
+
children: "Every product and service the platform offers lives here. Use this page to see which are live, in draft, or running a waitlist, and to seed the active product catalog — it's the source of truth other admin areas (billing, waitlist, referrals) point back to."
|
|
269
|
+
}),
|
|
270
|
+
$ && /* @__PURE__ */ S(c, {
|
|
271
|
+
className: "mb-6",
|
|
272
|
+
children: [
|
|
273
|
+
/* @__PURE__ */ x(s, {
|
|
274
|
+
title: "Total Products",
|
|
275
|
+
hero: !0,
|
|
276
|
+
value: $.total,
|
|
277
|
+
icon: /* @__PURE__ */ x(v, { className: "h-5 w-5" })
|
|
278
|
+
}),
|
|
279
|
+
/* @__PURE__ */ x(s, {
|
|
280
|
+
title: "Active",
|
|
281
|
+
value: $.active,
|
|
282
|
+
icon: /* @__PURE__ */ x(b, { className: "h-5 w-5" })
|
|
283
|
+
}),
|
|
284
|
+
/* @__PURE__ */ x(s, {
|
|
285
|
+
title: "Waitlist",
|
|
286
|
+
value: $.waitlist,
|
|
287
|
+
icon: /* @__PURE__ */ x(v, { className: "h-5 w-5" })
|
|
288
|
+
}),
|
|
289
|
+
/* @__PURE__ */ x(s, {
|
|
290
|
+
title: "Draft",
|
|
291
|
+
value: $.draft,
|
|
292
|
+
icon: /* @__PURE__ */ x(v, { className: "h-5 w-5" })
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
}),
|
|
296
|
+
/* @__PURE__ */ S("div", {
|
|
297
|
+
className: "space-y-4",
|
|
298
|
+
children: [
|
|
299
|
+
/* @__PURE__ */ S("div", {
|
|
300
|
+
className: "relative max-w-sm",
|
|
301
|
+
children: [/* @__PURE__ */ x(y, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ x(i, {
|
|
302
|
+
placeholder: "Search products...",
|
|
303
|
+
value: I,
|
|
304
|
+
onChange: (e) => {
|
|
305
|
+
F(1), L(e.target.value);
|
|
306
|
+
},
|
|
307
|
+
className: "pl-9"
|
|
308
|
+
})]
|
|
309
|
+
}),
|
|
310
|
+
J && /* @__PURE__ */ S("div", {
|
|
311
|
+
className: "rounded-md border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
312
|
+
children: ["Failed to load products: ", J.message]
|
|
313
|
+
}),
|
|
314
|
+
B && /* @__PURE__ */ x("div", {
|
|
315
|
+
className: "rounded-md border border-border-subtle bg-bg-sunken p-4 text-sm text-text-primary",
|
|
316
|
+
children: B
|
|
317
|
+
}),
|
|
318
|
+
H && /* @__PURE__ */ x("div", {
|
|
319
|
+
className: "rounded-md border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
320
|
+
children: H
|
|
321
|
+
}),
|
|
322
|
+
/* @__PURE__ */ x(l, {
|
|
323
|
+
columns: [
|
|
324
|
+
{
|
|
325
|
+
key: "name",
|
|
326
|
+
header: "Product",
|
|
327
|
+
render: (e) => /* @__PURE__ */ x("div", {
|
|
328
|
+
className: "flex items-center gap-3",
|
|
329
|
+
children: /* @__PURE__ */ S("div", {
|
|
330
|
+
className: "min-w-0",
|
|
331
|
+
children: [/* @__PURE__ */ S("div", {
|
|
332
|
+
className: "flex items-center gap-2",
|
|
333
|
+
children: [/* @__PURE__ */ x("span", {
|
|
334
|
+
className: "font-medium text-text-primary",
|
|
335
|
+
children: e.name
|
|
336
|
+
}), e.appUrl && /* @__PURE__ */ x("a", {
|
|
337
|
+
href: e.appUrl,
|
|
338
|
+
target: "_blank",
|
|
339
|
+
rel: "noopener noreferrer",
|
|
340
|
+
onClick: (e) => e.stopPropagation(),
|
|
341
|
+
children: /* @__PURE__ */ x(ee, { className: "h-3 w-3 text-text-secondary hover:text-text-primary" })
|
|
342
|
+
})]
|
|
343
|
+
}), /* @__PURE__ */ x("div", {
|
|
344
|
+
className: "truncate text-xs text-text-secondary",
|
|
345
|
+
children: e.slug
|
|
335
346
|
})]
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
347
|
+
})
|
|
348
|
+
})
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
key: "status",
|
|
352
|
+
header: "Status",
|
|
353
|
+
width: "110px",
|
|
354
|
+
render: (e) => /* @__PURE__ */ x(t, {
|
|
355
|
+
variant: D[e.status] ?? "outline",
|
|
356
|
+
className: "text-xs capitalize",
|
|
357
|
+
children: e.status.toLowerCase().replace("_", " ")
|
|
358
|
+
})
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
key: "activeUsers",
|
|
362
|
+
header: "Users",
|
|
363
|
+
width: "80px",
|
|
364
|
+
align: "right",
|
|
365
|
+
render: (e) => /* @__PURE__ */ x("span", {
|
|
366
|
+
className: "text-sm",
|
|
367
|
+
children: e.activeUsers
|
|
340
368
|
})
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
header: "Updated",
|
|
366
|
-
width: "110px",
|
|
367
|
-
render: (e) => o(e.updatedAt)
|
|
368
|
-
}
|
|
369
|
-
],
|
|
370
|
-
data: X,
|
|
371
|
-
keyExtractor: (e) => e.id,
|
|
372
|
-
loading: q,
|
|
373
|
-
emptyState: /* @__PURE__ */ S(r, {
|
|
374
|
-
illustration: "empty-search",
|
|
375
|
-
icon: /* @__PURE__ */ S(y, { className: "h-8 w-8" }),
|
|
376
|
-
title: "No products found",
|
|
377
|
-
description: "No platform products match your search"
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
key: "updatedAt",
|
|
372
|
+
header: "Updated",
|
|
373
|
+
width: "110px",
|
|
374
|
+
render: (e) => o(e.updatedAt)
|
|
375
|
+
}
|
|
376
|
+
],
|
|
377
|
+
data: X,
|
|
378
|
+
keyExtractor: (e) => e.id,
|
|
379
|
+
loading: q,
|
|
380
|
+
emptyState: /* @__PURE__ */ x(r, {
|
|
381
|
+
illustration: "empty-search",
|
|
382
|
+
icon: /* @__PURE__ */ x(v, { className: "h-8 w-8" }),
|
|
383
|
+
title: "No products found",
|
|
384
|
+
description: "No platform products match your search"
|
|
385
|
+
})
|
|
386
|
+
}),
|
|
387
|
+
Z > E && /* @__PURE__ */ x(u, {
|
|
388
|
+
page: P,
|
|
389
|
+
totalPages: Q,
|
|
390
|
+
totalItems: Z,
|
|
391
|
+
pageSize: E,
|
|
392
|
+
onPageChange: F
|
|
378
393
|
})
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
totalPages: Q,
|
|
383
|
-
totalItems: Z,
|
|
384
|
-
pageSize: E,
|
|
385
|
-
onPageChange: F
|
|
386
|
-
})
|
|
387
|
-
]
|
|
388
|
-
})]
|
|
394
|
+
]
|
|
395
|
+
})
|
|
396
|
+
]
|
|
389
397
|
})
|
|
390
398
|
});
|
|
391
399
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsPage.js","names":[],"sources":["../../../src/admin/pages/ProductsPage.tsx"],"sourcesContent":["import { useState, useMemo, useCallback } from 'react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { Package, Search, ExternalLink, Server, Database } from 'lucide-react';\nimport { useAdminPermissions } from '../hooks/useAdminPermissions';\nimport {\n PageLayout,\n Input,\n DataTable,\n Pagination,\n EmptyState,\n MetricCard,\n MetricsGrid,\n Badge,\n Button,\n PermissionGuard,\n} from '../components';\nimport { formatDate } from '../utils/formatters';\nimport {\n useListPlatformProductsQuery,\n useGetPlatformProductStatsQuery,\n} from '../../generated/global-operations';\n\nconst PAGE_SIZE = 20;\n\ntype ProductStatus = 'ACTIVE' | 'COMING_SOON' | 'WAITLIST' | 'DRAFT';\n\nconst STATUS_VARIANT: Record<ProductStatus, 'default' | 'secondary' | 'outline' | 'destructive'> = {\n ACTIVE: 'default',\n COMING_SOON: 'secondary',\n WAITLIST: 'outline',\n DRAFT: 'destructive',\n};\n\nconst PLATFORM_PRODUCT_FIELDS = gql`\n fragment AdminSeedPlatformProductFields on PlatformProduct {\n id\n name\n slug\n }\n`;\n\nconst UPSERT_PRODUCTS_QUERY = gql`\n ${PLATFORM_PRODUCT_FIELDS}\n query AdminSeedListProducts($limit: Int, $offset: Int) {\n platformProducts(limit: $limit, offset: $offset) {\n items {\n ...AdminSeedPlatformProductFields\n }\n }\n }\n`;\n\nconst CREATE_PRODUCT_MUTATION = gql`\n mutation AdminSeedCreateProduct($input: CreatePlatformProductInput!) {\n createPlatformProduct(input: $input) {\n id\n slug\n }\n }\n`;\n\nconst UPDATE_PRODUCT_MUTATION = gql`\n mutation AdminSeedUpdateProduct($id: ID!, $input: UpdatePlatformProductInput!) {\n updatePlatformProduct(id: $id, input: $input) {\n id\n slug\n }\n }\n`;\n\ntype SeedProductInput = {\n name: string;\n slug: string;\n description: string;\n status: ProductStatus;\n website: string | null;\n appUrl: string;\n docsUrl: string | null;\n githubUrl: string;\n statusPageUrl: string;\n contactEmail: string;\n supportEmail: string;\n contactPhone: string;\n contactAddress: string;\n seoTitle: string;\n seoDescription: string;\n seoKeywords: string;\n socialLinks: Record<string, string>;\n metadata: Record<string, string>;\n};\n\nconst PRODUCT_SEEDS: SeedProductInput[] = [\n {\n name: 'Workspaces',\n slug: 'workspaces',\n description: 'Enterprise collaboration and workspace management platform.',\n status: 'ACTIVE',\n website: 'https://workspaces.burdenoff.com',\n appUrl: 'https://app.local.burdenoff.com/',\n docsUrl: 'https://docs.burdenoff.com/workspaces',\n githubUrl: 'https://github.com/algoshred/workspaces',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@burdenoff.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'Workspaces - Enterprise Collaboration Platform',\n seoDescription: 'The enterprise-grade foundation for collaborative digital workspaces.',\n seoKeywords: 'enterprise,collaboration,workspace,saas,multi-tenant',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline: 'The Enterprise-Grade Foundation for Collaborative Digital Workspaces',\n businessDomain: 'Enterprise Collaboration & Workspace Management',\n category: 'Core Infrastructure',\n company: 'algoshred',\n pricingRange: '$15-$125/user/month',\n },\n },\n {\n name: 'VibeControls',\n slug: 'vibecontrols',\n description: 'Developer control panel for environments, terminals, tunnels, and remote work.',\n status: 'ACTIVE',\n website: 'https://vibecontrols.com',\n appUrl: 'https://vibecontrols.local.burdenoff.com/',\n docsUrl: 'https://docs.vibecontrols.com',\n githubUrl: 'https://github.com/algoshred/vibecontrols',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@vibecontrols.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'VibeControls - Developer Environment Management',\n seoDescription: \"The Developer's Command Center for Multi-Environment Development\",\n seoKeywords: 'developer tools,environment management,terminal,remote development,devops',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline: \"The Developer's Command Center for Multi-Environment Development\",\n businessDomain: 'Developer Control Panel',\n category: 'Core Infrastructure',\n company: 'algoshred',\n pricingRange: '$25-$150/user/month',\n },\n },\n {\n name: 'FluidGrids',\n slug: 'fluidgrids',\n description:\n 'Visual workflow automation platform for building and operating complex workflows.',\n status: 'ACTIVE',\n website: 'https://fluidgrids.com',\n appUrl: 'https://fluidgrids.local.burdenoff.com/',\n docsUrl: 'https://docs.fluidgrids.com',\n githubUrl: 'https://github.com/algoshred/fluidgrids',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@fluidgrids.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'FluidGrids - Visual Workflow Automation',\n seoDescription:\n 'The Visual Automation Platform That Scales From Simple Tasks to Enterprise Workflows',\n seoKeywords: 'workflow,automation,drag-and-drop,visual,enterprise,integration,process',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline:\n 'The Visual Automation Platform That Scales From Simple Tasks to Enterprise Workflows',\n businessDomain: 'Visual Workflow Automation Platform',\n category: 'Workflow & Automation',\n company: 'algoshred',\n pricingRange: '$29-$299/user/month',\n },\n },\n {\n name: 'BigConsole',\n slug: 'bigconsole',\n description: 'AI-first dashboard and data visualization platform.',\n status: 'ACTIVE',\n website: 'https://bigconsole.com',\n appUrl: 'https://bigconsole.local.burdenoff.com/',\n docsUrl: 'https://docs.bigconsole.com',\n githubUrl: 'https://github.com/algoshred/bigconsole',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@bigconsole.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'BigConsole - AI Data Visualization Platform',\n seoDescription: 'Where Data Becomes Intelligence',\n seoKeywords: 'data visualization,business intelligence,AI,dashboard,analytics,reporting',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline: 'Where Data Becomes Intelligence',\n businessDomain: 'Data Visualization and Business Intelligence',\n category: 'AI & Intelligence',\n company: 'algoshred',\n pricingRange: '$29-$149/user/month',\n },\n },\n {\n name: 'Botlit',\n slug: 'botlit',\n description: 'Enterprise AI agent and bot automation platform.',\n status: 'ACTIVE',\n website: 'https://botlit.ai',\n appUrl: 'https://botlit.local.burdenoff.com/',\n docsUrl: 'https://docs.botlit.ai',\n githubUrl: 'https://github.com/algoshred/botlit',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@botlit.ai',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'Botlit - Enterprise AI Agent Platform',\n seoDescription:\n 'The Enterprise AI Platform That Makes Intelligent Automation Accessible to Everyone',\n seoKeywords: 'AI,bots,automation,agentic AI,intelligent automation,chatbot,enterprise AI',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline:\n 'The Enterprise AI Platform That Makes Intelligent Automation Accessible to Everyone',\n businessDomain: 'AI Platform',\n category: 'AI & Intelligence',\n company: 'algoshred',\n pricingRange: '$99-$1,999/month',\n },\n },\n];\n\ntype ProductItem = {\n id: string;\n name: string;\n slug: string;\n description: string | null | undefined;\n status: string;\n appUrl: string | null | undefined;\n activeUsers: number;\n apiCalls: number;\n contactEmail: string | null | undefined;\n createdAt: string;\n updatedAt: string;\n};\n\n/**\n * Products page — connected to real backend\n */\nexport function ProductsPage() {\n const { canViewProducts, isLoading: permissionsLoading } = useAdminPermissions();\n const apolloClient = useApolloClient();\n\n const [page, setPage] = useState(1);\n const [search, setSearch] = useState('');\n const [isSeeding, setIsSeeding] = useState(false);\n const [seedMessage, setSeedMessage] = useState<string | null>(null);\n const [seedError, setSeedError] = useState<string | null>(null);\n\n const skipQueries = permissionsLoading || !canViewProducts;\n\n const { data: statsData } = useGetPlatformProductStatsQuery({\n skip: skipQueries,\n });\n const { data, loading, error, refetch } = useListPlatformProductsQuery({\n variables: {\n filter: search ? { search } : undefined,\n limit: PAGE_SIZE,\n offset: (page - 1) * PAGE_SIZE,\n },\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n\n const products: ProductItem[] = useMemo(\n () => (data?.platformProducts?.items ?? []) as ProductItem[],\n [data]\n );\n\n const total = data?.platformProducts?.total ?? 0;\n const totalPages = Math.ceil(total / PAGE_SIZE);\n const stats = statsData?.platformProductStats;\n\n const handleSeedProducts = useCallback(async () => {\n setIsSeeding(true);\n setSeedMessage(null);\n setSeedError(null);\n\n try {\n const existingResult = await apolloClient.query<{\n platformProducts: { items: Array<{ id: string; slug: string }> };\n }>({\n query: UPSERT_PRODUCTS_QUERY,\n variables: { limit: 200, offset: 0 },\n fetchPolicy: 'network-only',\n });\n const existingProducts = existingResult.data?.platformProducts?.items ?? [];\n const existingBySlug = new Map(existingProducts.map((product) => [product.slug, product]));\n\n let created = 0;\n let updated = 0;\n for (const seed of PRODUCT_SEEDS) {\n const existing = existingBySlug.get(seed.slug);\n if (existing) {\n const input = Object.fromEntries(Object.entries(seed).filter(([key]) => key !== 'slug'));\n await apolloClient.mutate({\n mutation: UPDATE_PRODUCT_MUTATION,\n variables: { id: existing.id, input },\n });\n updated += 1;\n } else {\n await apolloClient.mutate({\n mutation: CREATE_PRODUCT_MUTATION,\n variables: { input: seed },\n });\n created += 1;\n }\n }\n\n setSeedMessage(`Seeded products: ${created} created, ${updated} updated.`);\n await refetch();\n } catch (err) {\n setSeedError(err instanceof Error ? err.message : 'Failed to seed products');\n } finally {\n setIsSeeding(false);\n }\n }, [apolloClient, refetch]);\n\n const columns = [\n {\n key: 'name',\n header: 'Product',\n render: (p: ProductItem) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-text-primary\">{p.name}</span>\n {p.appUrl && (\n <a\n href={p.appUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"h-3 w-3 text-text-secondary hover:text-text-primary\" />\n </a>\n )}\n </div>\n <div className=\"truncate text-xs text-text-secondary\">{p.slug}</div>\n </div>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n width: '110px',\n render: (p: ProductItem) => (\n <Badge\n variant={STATUS_VARIANT[p.status as ProductStatus] ?? 'outline'}\n className=\"text-xs capitalize\"\n >\n {p.status.toLowerCase().replace('_', ' ')}\n </Badge>\n ),\n },\n {\n key: 'activeUsers',\n header: 'Users',\n width: '80px',\n align: 'right' as const,\n render: (p: ProductItem) => <span className=\"text-sm\">{p.activeUsers}</span>,\n },\n {\n key: 'updatedAt',\n header: 'Updated',\n width: '110px',\n render: (p: ProductItem) => formatDate(p.updatedAt),\n },\n ];\n\n return (\n <PermissionGuard\n allowed={canViewProducts}\n isLoading={permissionsLoading}\n pageTitle=\"Products\"\n denyMessage=\"You don't have permission to view products.\"\n >\n <PageLayout\n title=\"Products\"\n gradientWord=\"Products\"\n description={`Platform products and services${total ? ` · ${total} total` : ''}`}\n actions={\n <Button onClick={handleSeedProducts} disabled={isSeeding}>\n <Database className=\"mr-2 h-4 w-4\" />\n {isSeeding ? 'Seeding...' : 'Seed Active Products'}\n </Button>\n }\n >\n {/* Stats */}\n {stats && (\n <MetricsGrid className=\"mb-6\">\n <MetricCard\n title=\"Total Products\"\n hero\n value={stats.total}\n icon={<Package className=\"h-5 w-5\" />}\n />\n <MetricCard title=\"Active\" value={stats.active} icon={<Server className=\"h-5 w-5\" />} />\n <MetricCard\n title=\"Waitlist\"\n value={stats.waitlist}\n icon={<Package className=\"h-5 w-5\" />}\n />\n <MetricCard title=\"Draft\" value={stats.draft} icon={<Package className=\"h-5 w-5\" />} />\n </MetricsGrid>\n )}\n\n <div className=\"space-y-4\">\n <div className=\"relative max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search products...\"\n value={search}\n onChange={(e) => {\n setPage(1);\n setSearch(e.target.value);\n }}\n className=\"pl-9\"\n />\n </div>\n\n {error && (\n <div className=\"rounded-md border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n Failed to load products: {error.message}\n </div>\n )}\n {seedMessage && (\n <div className=\"rounded-md border border-border-subtle bg-bg-sunken p-4 text-sm text-text-primary\">\n {seedMessage}\n </div>\n )}\n {seedError && (\n <div className=\"rounded-md border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n {seedError}\n </div>\n )}\n\n <DataTable\n columns={columns}\n data={products}\n keyExtractor={(p) => p.id}\n loading={loading}\n emptyState={\n <EmptyState\n illustration=\"empty-search\"\n icon={<Package className=\"h-8 w-8\" />}\n title=\"No products found\"\n description=\"No platform products match your search\"\n />\n }\n />\n\n {total > PAGE_SIZE && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalItems={total}\n pageSize={PAGE_SIZE}\n onPageChange={setPage}\n />\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductsPage.js","names":[],"sources":["../../../src/admin/pages/ProductsPage.tsx"],"sourcesContent":["import { useState, useMemo, useCallback } from 'react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { Package, Search, ExternalLink, Server, Database } from 'lucide-react';\nimport { useAdminPermissions } from '../hooks/useAdminPermissions';\nimport {\n PageLayout,\n Input,\n DataTable,\n Pagination,\n EmptyState,\n MetricCard,\n MetricsGrid,\n Badge,\n Button,\n PermissionGuard,\n} from '../components';\nimport { formatDate } from '../utils/formatters';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n useListPlatformProductsQuery,\n useGetPlatformProductStatsQuery,\n} from '../../generated/global-operations';\n\nconst PAGE_SIZE = 20;\n\ntype ProductStatus = 'ACTIVE' | 'COMING_SOON' | 'WAITLIST' | 'DRAFT';\n\nconst STATUS_VARIANT: Record<ProductStatus, 'default' | 'secondary' | 'outline' | 'destructive'> = {\n ACTIVE: 'default',\n COMING_SOON: 'secondary',\n WAITLIST: 'outline',\n DRAFT: 'destructive',\n};\n\nconst PLATFORM_PRODUCT_FIELDS = gql`\n fragment AdminSeedPlatformProductFields on PlatformProduct {\n id\n name\n slug\n }\n`;\n\nconst UPSERT_PRODUCTS_QUERY = gql`\n ${PLATFORM_PRODUCT_FIELDS}\n query AdminSeedListProducts($limit: Int, $offset: Int) {\n platformProducts(limit: $limit, offset: $offset) {\n items {\n ...AdminSeedPlatformProductFields\n }\n }\n }\n`;\n\nconst CREATE_PRODUCT_MUTATION = gql`\n mutation AdminSeedCreateProduct($input: CreatePlatformProductInput!) {\n createPlatformProduct(input: $input) {\n id\n slug\n }\n }\n`;\n\nconst UPDATE_PRODUCT_MUTATION = gql`\n mutation AdminSeedUpdateProduct($id: ID!, $input: UpdatePlatformProductInput!) {\n updatePlatformProduct(id: $id, input: $input) {\n id\n slug\n }\n }\n`;\n\ntype SeedProductInput = {\n name: string;\n slug: string;\n description: string;\n status: ProductStatus;\n website: string | null;\n appUrl: string;\n docsUrl: string | null;\n githubUrl: string;\n statusPageUrl: string;\n contactEmail: string;\n supportEmail: string;\n contactPhone: string;\n contactAddress: string;\n seoTitle: string;\n seoDescription: string;\n seoKeywords: string;\n socialLinks: Record<string, string>;\n metadata: Record<string, string>;\n};\n\nconst PRODUCT_SEEDS: SeedProductInput[] = [\n {\n name: 'Workspaces',\n slug: 'workspaces',\n description: 'Enterprise collaboration and workspace management platform.',\n status: 'ACTIVE',\n website: 'https://workspaces.burdenoff.com',\n appUrl: 'https://app.local.burdenoff.com/',\n docsUrl: 'https://docs.burdenoff.com/workspaces',\n githubUrl: 'https://github.com/algoshred/workspaces',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@burdenoff.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'Workspaces - Enterprise Collaboration Platform',\n seoDescription: 'The enterprise-grade foundation for collaborative digital workspaces.',\n seoKeywords: 'enterprise,collaboration,workspace,saas,multi-tenant',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline: 'The Enterprise-Grade Foundation for Collaborative Digital Workspaces',\n businessDomain: 'Enterprise Collaboration & Workspace Management',\n category: 'Core Infrastructure',\n company: 'algoshred',\n pricingRange: '$15-$125/user/month',\n },\n },\n {\n name: 'VibeControls',\n slug: 'vibecontrols',\n description: 'Developer control panel for environments, terminals, tunnels, and remote work.',\n status: 'ACTIVE',\n website: 'https://vibecontrols.com',\n appUrl: 'https://vibecontrols.local.burdenoff.com/',\n docsUrl: 'https://docs.vibecontrols.com',\n githubUrl: 'https://github.com/algoshred/vibecontrols',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@vibecontrols.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'VibeControls - Developer Environment Management',\n seoDescription: \"The Developer's Command Center for Multi-Environment Development\",\n seoKeywords: 'developer tools,environment management,terminal,remote development,devops',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline: \"The Developer's Command Center for Multi-Environment Development\",\n businessDomain: 'Developer Control Panel',\n category: 'Core Infrastructure',\n company: 'algoshred',\n pricingRange: '$25-$150/user/month',\n },\n },\n {\n name: 'FluidGrids',\n slug: 'fluidgrids',\n description:\n 'Visual workflow automation platform for building and operating complex workflows.',\n status: 'ACTIVE',\n website: 'https://fluidgrids.com',\n appUrl: 'https://fluidgrids.local.burdenoff.com/',\n docsUrl: 'https://docs.fluidgrids.com',\n githubUrl: 'https://github.com/algoshred/fluidgrids',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@fluidgrids.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'FluidGrids - Visual Workflow Automation',\n seoDescription:\n 'The Visual Automation Platform That Scales From Simple Tasks to Enterprise Workflows',\n seoKeywords: 'workflow,automation,drag-and-drop,visual,enterprise,integration,process',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline:\n 'The Visual Automation Platform That Scales From Simple Tasks to Enterprise Workflows',\n businessDomain: 'Visual Workflow Automation Platform',\n category: 'Workflow & Automation',\n company: 'algoshred',\n pricingRange: '$29-$299/user/month',\n },\n },\n {\n name: 'BigConsole',\n slug: 'bigconsole',\n description: 'AI-first dashboard and data visualization platform.',\n status: 'ACTIVE',\n website: 'https://bigconsole.com',\n appUrl: 'https://bigconsole.local.burdenoff.com/',\n docsUrl: 'https://docs.bigconsole.com',\n githubUrl: 'https://github.com/algoshred/bigconsole',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@bigconsole.com',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'BigConsole - AI Data Visualization Platform',\n seoDescription: 'Where Data Becomes Intelligence',\n seoKeywords: 'data visualization,business intelligence,AI,dashboard,analytics,reporting',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline: 'Where Data Becomes Intelligence',\n businessDomain: 'Data Visualization and Business Intelligence',\n category: 'AI & Intelligence',\n company: 'algoshred',\n pricingRange: '$29-$149/user/month',\n },\n },\n {\n name: 'Botlit',\n slug: 'botlit',\n description: 'Enterprise AI agent and bot automation platform.',\n status: 'ACTIVE',\n website: 'https://botlit.ai',\n appUrl: 'https://botlit.local.burdenoff.com/',\n docsUrl: 'https://docs.botlit.ai',\n githubUrl: 'https://github.com/algoshred/botlit',\n statusPageUrl: 'https://status.burdenoff.com',\n contactEmail: 'contact@botlit.ai',\n supportEmail: 'support@burdenoff.com',\n contactPhone: '+91-7358445777',\n contactAddress: 'Plot No.43, Veeramani Nagar, 2nd Cross Street, Nanmangalam, Chennai - 600117',\n seoTitle: 'Botlit - Enterprise AI Agent Platform',\n seoDescription:\n 'The Enterprise AI Platform That Makes Intelligent Automation Accessible to Everyone',\n seoKeywords: 'AI,bots,automation,agentic AI,intelligent automation,chatbot,enterprise AI',\n socialLinks: {\n twitter: 'https://twitter.com/burdenoff',\n github: 'https://github.com/algoshred',\n discord: 'https://discord.gg/burdenoff',\n linkedin: 'https://linkedin.com/company/burdenoff',\n },\n metadata: {\n tagline:\n 'The Enterprise AI Platform That Makes Intelligent Automation Accessible to Everyone',\n businessDomain: 'AI Platform',\n category: 'AI & Intelligence',\n company: 'algoshred',\n pricingRange: '$99-$1,999/month',\n },\n },\n];\n\ntype ProductItem = {\n id: string;\n name: string;\n slug: string;\n description: string | null | undefined;\n status: string;\n appUrl: string | null | undefined;\n activeUsers: number;\n apiCalls: number;\n contactEmail: string | null | undefined;\n createdAt: string;\n updatedAt: string;\n};\n\n/**\n * Products page — connected to real backend\n */\nexport function ProductsPage() {\n const { canViewProducts, isLoading: permissionsLoading } = useAdminPermissions();\n const apolloClient = useApolloClient();\n\n const [page, setPage] = useState(1);\n const [search, setSearch] = useState('');\n const [isSeeding, setIsSeeding] = useState(false);\n const [seedMessage, setSeedMessage] = useState<string | null>(null);\n const [seedError, setSeedError] = useState<string | null>(null);\n\n const skipQueries = permissionsLoading || !canViewProducts;\n\n const { data: statsData } = useGetPlatformProductStatsQuery({\n skip: skipQueries,\n });\n const { data, loading, error, refetch } = useListPlatformProductsQuery({\n variables: {\n filter: search ? { search } : undefined,\n limit: PAGE_SIZE,\n offset: (page - 1) * PAGE_SIZE,\n },\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n\n const products: ProductItem[] = useMemo(\n () => (data?.platformProducts?.items ?? []) as ProductItem[],\n [data]\n );\n\n const total = data?.platformProducts?.total ?? 0;\n const totalPages = Math.ceil(total / PAGE_SIZE);\n const stats = statsData?.platformProductStats;\n\n const handleSeedProducts = useCallback(async () => {\n setIsSeeding(true);\n setSeedMessage(null);\n setSeedError(null);\n\n try {\n const existingResult = await apolloClient.query<{\n platformProducts: { items: Array<{ id: string; slug: string }> };\n }>({\n query: UPSERT_PRODUCTS_QUERY,\n variables: { limit: 200, offset: 0 },\n fetchPolicy: 'network-only',\n });\n const existingProducts = existingResult.data?.platformProducts?.items ?? [];\n const existingBySlug = new Map(existingProducts.map((product) => [product.slug, product]));\n\n let created = 0;\n let updated = 0;\n for (const seed of PRODUCT_SEEDS) {\n const existing = existingBySlug.get(seed.slug);\n if (existing) {\n const input = Object.fromEntries(Object.entries(seed).filter(([key]) => key !== 'slug'));\n await apolloClient.mutate({\n mutation: UPDATE_PRODUCT_MUTATION,\n variables: { id: existing.id, input },\n });\n updated += 1;\n } else {\n await apolloClient.mutate({\n mutation: CREATE_PRODUCT_MUTATION,\n variables: { input: seed },\n });\n created += 1;\n }\n }\n\n setSeedMessage(`Seeded products: ${created} created, ${updated} updated.`);\n await refetch();\n } catch (err) {\n setSeedError(err instanceof Error ? err.message : 'Failed to seed products');\n } finally {\n setIsSeeding(false);\n }\n }, [apolloClient, refetch]);\n\n const columns = [\n {\n key: 'name',\n header: 'Product',\n render: (p: ProductItem) => (\n <div className=\"flex items-center gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-text-primary\">{p.name}</span>\n {p.appUrl && (\n <a\n href={p.appUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"h-3 w-3 text-text-secondary hover:text-text-primary\" />\n </a>\n )}\n </div>\n <div className=\"truncate text-xs text-text-secondary\">{p.slug}</div>\n </div>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n width: '110px',\n render: (p: ProductItem) => (\n <Badge\n variant={STATUS_VARIANT[p.status as ProductStatus] ?? 'outline'}\n className=\"text-xs capitalize\"\n >\n {p.status.toLowerCase().replace('_', ' ')}\n </Badge>\n ),\n },\n {\n key: 'activeUsers',\n header: 'Users',\n width: '80px',\n align: 'right' as const,\n render: (p: ProductItem) => <span className=\"text-sm\">{p.activeUsers}</span>,\n },\n {\n key: 'updatedAt',\n header: 'Updated',\n width: '110px',\n render: (p: ProductItem) => formatDate(p.updatedAt),\n },\n ];\n\n return (\n <PermissionGuard\n allowed={canViewProducts}\n isLoading={permissionsLoading}\n pageTitle=\"Products\"\n denyMessage=\"You don't have permission to view products.\"\n >\n <PageLayout\n title=\"Products\"\n gradientWord=\"Products\"\n description={`Platform products and services${total ? ` · ${total} total` : ''}`}\n actions={\n <Button onClick={handleSeedProducts} disabled={isSeeding}>\n <Database className=\"mr-2 h-4 w-4\" />\n {isSeeding ? 'Seeding...' : 'Seed Active Products'}\n </Button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Every product and service the platform offers lives here. Use this page to see which are\n live, in draft, or running a waitlist, and to seed the active product catalog — it's\n the source of truth other admin areas (billing, waitlist, referrals) point back to.\n </PagePurpose>\n\n {/* Stats */}\n {stats && (\n <MetricsGrid className=\"mb-6\">\n <MetricCard\n title=\"Total Products\"\n hero\n value={stats.total}\n icon={<Package className=\"h-5 w-5\" />}\n />\n <MetricCard title=\"Active\" value={stats.active} icon={<Server className=\"h-5 w-5\" />} />\n <MetricCard\n title=\"Waitlist\"\n value={stats.waitlist}\n icon={<Package className=\"h-5 w-5\" />}\n />\n <MetricCard title=\"Draft\" value={stats.draft} icon={<Package className=\"h-5 w-5\" />} />\n </MetricsGrid>\n )}\n\n <div className=\"space-y-4\">\n <div className=\"relative max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search products...\"\n value={search}\n onChange={(e) => {\n setPage(1);\n setSearch(e.target.value);\n }}\n className=\"pl-9\"\n />\n </div>\n\n {error && (\n <div className=\"rounded-md border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n Failed to load products: {error.message}\n </div>\n )}\n {seedMessage && (\n <div className=\"rounded-md border border-border-subtle bg-bg-sunken p-4 text-sm text-text-primary\">\n {seedMessage}\n </div>\n )}\n {seedError && (\n <div className=\"rounded-md border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n {seedError}\n </div>\n )}\n\n <DataTable\n columns={columns}\n data={products}\n keyExtractor={(p) => p.id}\n loading={loading}\n emptyState={\n <EmptyState\n illustration=\"empty-search\"\n icon={<Package className=\"h-8 w-8\" />}\n title=\"No products found\"\n description=\"No platform products match your search\"\n />\n }\n />\n\n {total > PAGE_SIZE && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalItems={total}\n pageSize={PAGE_SIZE}\n onPageChange={setPage}\n />\n )}\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|