@burdenoff/microfe-store 2026.624.1 → 2026.624.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AdminStoresPage.js","names":[],"sources":["../../src/pages/AdminStoresPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { ArrowLeft, Plus, Pencil, Trash2, RefreshCw, Store as StoreIcon } from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { useNavigate } from 'react-router-dom';\nimport { useStore } from '../providers/StoreProvider';\n\ntype StoreRecord = {\n id: string;\n slug: string;\n name: string;\n type: 'PUBLIC' | 'PRIVATE' | 'ENTERPRISE';\n tenantId?: string | null;\n isPublic: boolean;\n requiresApproval: boolean;\n allowUnverifiedPublishers: boolean;\n currency: string;\n logoUrl?: string | null;\n description?: string | null;\n createdAt: string;\n};\n\nconst STORES_QUERY = /* GraphQL */ `\n query AdminStores {\n stores {\n id\n slug\n name\n type\n tenantId\n isPublic\n requiresApproval\n allowUnverifiedPublishers\n currency\n logoUrl\n description\n createdAt\n }\n }\n`;\n\nconst CREATE_STORE_MUTATION = /* GraphQL */ `\n mutation CreateStore($input: CreateStoreInput!) {\n createStore(input: $input) {\n id\n slug\n name\n type\n }\n }\n`;\n\nconst UPDATE_STORE_MUTATION = /* GraphQL */ `\n mutation UpdateStore($id: ID!, $input: UpdateStoreInput!) {\n updateStore(id: $id, input: $input) {\n id\n name\n isPublic\n requiresApproval\n }\n }\n`;\n\nconst DELETE_STORE_MUTATION = /* GraphQL */ `\n mutation DeleteStore($id: ID!) {\n deleteStore(id: $id)\n }\n`;\n\ntype FormState = {\n slug: string;\n name: string;\n type: StoreRecord['type'];\n tenantId: string;\n isPublic: boolean;\n requiresApproval: boolean;\n allowUnverifiedPublishers: boolean;\n currency: string;\n description: string;\n};\n\nconst emptyForm: FormState = {\n slug: '',\n name: '',\n type: 'PRIVATE',\n tenantId: '',\n isPublic: false,\n requiresApproval: false,\n allowUnverifiedPublishers: true,\n currency: 'USD',\n description: '',\n};\n\nexport const AdminStoresPage: FC = () => {\n const navigate = useNavigate();\n const { authToken, basePath } = useStore();\n const [stores, setStores] = useState<StoreRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [showForm, setShowForm] = useState(false);\n const [form, setForm] = useState<FormState>(emptyForm);\n const [editingId, setEditingId] = useState<string | null>(null);\n\n const load = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await graphqlFetch<{ stores: StoreRecord[] }>({\n gateway: 'global',\n query: STORES_QUERY,\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to load stores');\n }\n setStores(result.data?.stores ?? []);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load stores');\n } finally {\n setLoading(false);\n }\n }, [authToken]);\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const openCreate = () => {\n setEditingId(null);\n setForm(emptyForm);\n setShowForm(true);\n };\n\n const openEdit = (s: StoreRecord) => {\n setEditingId(s.id);\n setForm({\n slug: s.slug,\n name: s.name,\n type: s.type,\n tenantId: s.tenantId ?? '',\n isPublic: s.isPublic,\n requiresApproval: s.requiresApproval,\n allowUnverifiedPublishers: s.allowUnverifiedPublishers,\n currency: s.currency,\n description: s.description ?? '',\n });\n setShowForm(true);\n };\n\n const submit = async () => {\n if (!form.slug.trim() || !form.name.trim()) {\n setError('Slug and name are required');\n return;\n }\n setError(null);\n try {\n if (editingId) {\n await graphqlFetch({\n gateway: 'global',\n query: UPDATE_STORE_MUTATION,\n variables: {\n id: editingId,\n input: {\n name: form.name,\n isPublic: form.isPublic,\n requiresApproval: form.requiresApproval,\n allowUnverifiedPublishers: form.allowUnverifiedPublishers,\n currency: form.currency,\n description: form.description || null,\n },\n },\n authToken: authToken || undefined,\n });\n } else {\n await graphqlFetch({\n gateway: 'global',\n query: CREATE_STORE_MUTATION,\n variables: {\n input: {\n slug: form.slug,\n name: form.name,\n type: form.type,\n tenantId: form.tenantId || null,\n isPublic: form.isPublic,\n requiresApproval: form.requiresApproval,\n allowUnverifiedPublishers: form.allowUnverifiedPublishers,\n currency: form.currency,\n description: form.description || null,\n },\n },\n authToken: authToken || undefined,\n });\n }\n setShowForm(false);\n setEditingId(null);\n setForm(emptyForm);\n await load();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Save failed');\n }\n };\n\n const remove = async (id: string) => {\n if (!confirm('Delete this store? This is a soft delete.')) return;\n try {\n await graphqlFetch({\n gateway: 'global',\n query: DELETE_STORE_MUTATION,\n variables: { id },\n authToken: authToken || undefined,\n });\n await load();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Delete failed');\n }\n };\n\n return (\n <div className=\"min-h-screen bg-surface-default\">\n <header className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-7xl px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/dashboard`)}\n className=\"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n <div className=\"flex items-center gap-2\">\n <StoreIcon className=\"size-5 text-text-primary\" />\n <h1 className=\"text-xl font-semibold text-text-primary\">Store registry</h1>\n <span className=\"rounded-full bg-surface-accent-muted px-2 py-0.5 text-xs font-medium text-text-accent\">\n {stores.length}\n </span>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => void load()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover\"\n disabled={loading}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n <button\n type=\"button\"\n onClick={openCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-surface-accent px-3 py-1.5 text-sm font-medium text-text-on-accent hover:bg-surface-accent-hover\"\n >\n <Plus className=\"size-4\" />\n Create store\n </button>\n </div>\n </div>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-7xl p-6\">\n {error && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n )}\n\n {showForm && (\n <div className=\"mb-6 rounded-lg border border-border-default bg-surface-raised p-4\">\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {editingId ? 'Edit store' : 'Create store'}\n </h2>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Slug</span>\n <input\n type=\"text\"\n aria-label=\"Slug\"\n value={form.slug}\n onChange={(e) => setForm({ ...form, slug: e.target.value })}\n disabled={!!editingId}\n required\n aria-required=\"true\"\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary disabled:opacity-60\"\n />\n </label>\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Name</span>\n <input\n type=\"text\"\n aria-label=\"Name\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n required\n aria-required=\"true\"\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary\"\n />\n </label>\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Type</span>\n <select\n aria-label=\"Store type\"\n value={form.type}\n onChange={(e) => setForm({ ...form, type: e.target.value as FormState['type'] })}\n disabled={!!editingId}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary disabled:opacity-60\"\n >\n <option value=\"PUBLIC\">Public</option>\n <option value=\"PRIVATE\">Private (opt-in)</option>\n <option value=\"ENTERPRISE\">Enterprise (tenant-scoped)</option>\n </select>\n </label>\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Currency</span>\n <input\n type=\"text\"\n aria-label=\"Currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary\"\n />\n </label>\n {form.type !== 'PUBLIC' && (\n <label className=\"block md:col-span-2\">\n <span className=\"text-xs text-text-secondary\">Tenant ID (optional)</span>\n <input\n type=\"text\"\n aria-label=\"Tenant ID\"\n value={form.tenantId}\n onChange={(e) => setForm({ ...form, tenantId: e.target.value })}\n disabled={!!editingId}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary disabled:opacity-60\"\n />\n </label>\n )}\n <label className=\"block md:col-span-2\">\n <span className=\"text-xs text-text-secondary\">Description</span>\n <textarea\n aria-label=\"Description\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={2}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Publicly visible\"\n checked={form.isPublic}\n onChange={(e) => setForm({ ...form, isPublic: e.target.checked })}\n />\n <span className=\"text-sm text-text-primary\">Publicly visible</span>\n </label>\n <label className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Requires admin approval\"\n checked={form.requiresApproval}\n onChange={(e) => setForm({ ...form, requiresApproval: e.target.checked })}\n />\n <span className=\"text-sm text-text-primary\">Requires admin approval</span>\n </label>\n <label className=\"flex items-center gap-2 md:col-span-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Allow unverified publishers to submit\"\n checked={form.allowUnverifiedPublishers}\n onChange={(e) =>\n setForm({ ...form, allowUnverifiedPublishers: e.target.checked })\n }\n />\n <span className=\"text-sm text-text-primary\">\n Allow unverified publishers to submit\n </span>\n </label>\n </div>\n <div className=\"mt-4 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setShowForm(false);\n setEditingId(null);\n setForm(emptyForm);\n }}\n className=\"rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void submit()}\n className=\"rounded-md bg-surface-accent px-3 py-1.5 text-sm font-medium text-text-on-accent hover:bg-surface-accent-hover\"\n >\n {editingId ? 'Save changes' : 'Create'}\n </button>\n </div>\n </div>\n )}\n\n {loading && stores.length === 0 ? (\n <output className=\"block py-16 text-center text-text-secondary\">Loading stores…</output>\n ) : stores.length === 0 ? (\n <div className=\"py-16 text-center text-text-secondary\">No stores yet.</div>\n ) : (\n <div className=\"overflow-hidden rounded-lg border border-border-default\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-surface-muted text-left text-xs uppercase tracking-wide text-text-secondary\">\n <tr>\n <th className=\"px-4 py-2\">Slug</th>\n <th className=\"px-4 py-2\">Name</th>\n <th className=\"px-4 py-2\">Type</th>\n <th className=\"px-4 py-2\">Public</th>\n <th className=\"px-4 py-2\">Approval</th>\n <th className=\"px-4 py-2\">Currency</th>\n <th className=\"px-4 py-2 text-right\">Actions</th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-default bg-surface-raised\">\n {stores.map((s) => (\n <tr key={s.id} className=\"text-text-primary\">\n <td className=\"px-4 py-2 font-mono text-xs\">{s.slug}</td>\n <td className=\"px-4 py-2\">{s.name}</td>\n <td className=\"px-4 py-2\">\n <span className=\"rounded-full bg-surface-accent-muted px-2 py-0.5 text-xs font-medium text-text-accent\">\n {s.type}\n </span>\n </td>\n <td className=\"px-4 py-2 text-xs\">{s.isPublic ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-2 text-xs\">\n {s.requiresApproval ? 'Required' : 'Auto-publish'}\n </td>\n <td className=\"px-4 py-2 text-xs\">{s.currency}</td>\n <td className=\"px-4 py-2 text-right\">\n <button\n type=\"button\"\n onClick={() => openEdit(s)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-default px-2 py-1 text-xs text-text-primary hover:bg-surface-hover\"\n >\n <Pencil className=\"size-3\" />\n Edit\n </button>\n {s.id !== 'store_public_default' && (\n <button\n type=\"button\"\n onClick={() => void remove(s.id)}\n className=\"ml-2 inline-flex items-center gap-1 rounded-md border border-border-danger px-2 py-1 text-xs text-text-danger hover:bg-surface-danger-muted\"\n >\n <Trash2 className=\"size-3\" />\n Delete\n </button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </main>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdminStoresPage.js","names":[],"sources":["../../src/pages/AdminStoresPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { ArrowLeft, Plus, Pencil, Trash2, RefreshCw, Store as StoreIcon } from 'lucide-react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { useNavigate } from 'react-router-dom';\nimport { useStore } from '../providers/StoreProvider';\nimport {\n AlertDialog,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogCancel,\n AlertDialogAction,\n} from '@burdenoff/fe-libs/ui';\n\ntype StoreRecord = {\n id: string;\n slug: string;\n name: string;\n type: 'PUBLIC' | 'PRIVATE' | 'ENTERPRISE';\n tenantId?: string | null;\n isPublic: boolean;\n requiresApproval: boolean;\n allowUnverifiedPublishers: boolean;\n currency: string;\n logoUrl?: string | null;\n description?: string | null;\n createdAt: string;\n};\n\nconst STORES_QUERY = /* GraphQL */ `\n query AdminStores {\n stores {\n id\n slug\n name\n type\n tenantId\n isPublic\n requiresApproval\n allowUnverifiedPublishers\n currency\n logoUrl\n description\n createdAt\n }\n }\n`;\n\nconst CREATE_STORE_MUTATION = /* GraphQL */ `\n mutation CreateStore($input: CreateStoreInput!) {\n createStore(input: $input) {\n id\n slug\n name\n type\n }\n }\n`;\n\nconst UPDATE_STORE_MUTATION = /* GraphQL */ `\n mutation UpdateStore($id: ID!, $input: UpdateStoreInput!) {\n updateStore(id: $id, input: $input) {\n id\n name\n isPublic\n requiresApproval\n }\n }\n`;\n\nconst DELETE_STORE_MUTATION = /* GraphQL */ `\n mutation DeleteStore($id: ID!) {\n deleteStore(id: $id)\n }\n`;\n\ntype FormState = {\n slug: string;\n name: string;\n type: StoreRecord['type'];\n tenantId: string;\n isPublic: boolean;\n requiresApproval: boolean;\n allowUnverifiedPublishers: boolean;\n currency: string;\n description: string;\n};\n\nconst emptyForm: FormState = {\n slug: '',\n name: '',\n type: 'PRIVATE',\n tenantId: '',\n isPublic: false,\n requiresApproval: false,\n allowUnverifiedPublishers: true,\n currency: 'USD',\n description: '',\n};\n\nexport const AdminStoresPage: FC = () => {\n const navigate = useNavigate();\n const { authToken, basePath } = useStore();\n const [stores, setStores] = useState<StoreRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [showForm, setShowForm] = useState(false);\n const [form, setForm] = useState<FormState>(emptyForm);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);\n\n const load = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await graphqlFetch<{ stores: StoreRecord[] }>({\n gateway: 'global',\n query: STORES_QUERY,\n authToken: authToken || undefined,\n });\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to load stores');\n }\n setStores(result.data?.stores ?? []);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load stores');\n } finally {\n setLoading(false);\n }\n }, [authToken]);\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const openCreate = () => {\n setEditingId(null);\n setForm(emptyForm);\n setShowForm(true);\n };\n\n const openEdit = (s: StoreRecord) => {\n setEditingId(s.id);\n setForm({\n slug: s.slug,\n name: s.name,\n type: s.type,\n tenantId: s.tenantId ?? '',\n isPublic: s.isPublic,\n requiresApproval: s.requiresApproval,\n allowUnverifiedPublishers: s.allowUnverifiedPublishers,\n currency: s.currency,\n description: s.description ?? '',\n });\n setShowForm(true);\n };\n\n const submit = async () => {\n if (!form.slug.trim() || !form.name.trim()) {\n setError('Slug and name are required');\n return;\n }\n setError(null);\n try {\n if (editingId) {\n await graphqlFetch({\n gateway: 'global',\n query: UPDATE_STORE_MUTATION,\n variables: {\n id: editingId,\n input: {\n name: form.name,\n isPublic: form.isPublic,\n requiresApproval: form.requiresApproval,\n allowUnverifiedPublishers: form.allowUnverifiedPublishers,\n currency: form.currency,\n description: form.description || null,\n },\n },\n authToken: authToken || undefined,\n });\n } else {\n await graphqlFetch({\n gateway: 'global',\n query: CREATE_STORE_MUTATION,\n variables: {\n input: {\n slug: form.slug,\n name: form.name,\n type: form.type,\n tenantId: form.tenantId || null,\n isPublic: form.isPublic,\n requiresApproval: form.requiresApproval,\n allowUnverifiedPublishers: form.allowUnverifiedPublishers,\n currency: form.currency,\n description: form.description || null,\n },\n },\n authToken: authToken || undefined,\n });\n }\n setShowForm(false);\n setEditingId(null);\n setForm(emptyForm);\n await load();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Save failed');\n }\n };\n\n const remove = async (id: string) => {\n try {\n await graphqlFetch({\n gateway: 'global',\n query: DELETE_STORE_MUTATION,\n variables: { id },\n authToken: authToken || undefined,\n });\n await load();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Delete failed');\n }\n };\n\n return (\n <div className=\"min-h-screen bg-surface-default\">\n <header className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-7xl px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/dashboard`)}\n className=\"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n <div className=\"flex items-center gap-2\">\n <StoreIcon className=\"size-5 text-text-primary\" />\n <h1 className=\"text-xl font-semibold text-text-primary\">Store registry</h1>\n <span className=\"rounded-full bg-surface-accent-muted px-2 py-0.5 text-xs font-medium text-text-accent\">\n {stores.length}\n </span>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => void load()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover\"\n disabled={loading}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n <button\n type=\"button\"\n onClick={openCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-surface-accent px-3 py-1.5 text-sm font-medium text-text-on-accent hover:bg-surface-accent-hover\"\n >\n <Plus className=\"size-4\" />\n Create store\n </button>\n </div>\n </div>\n </div>\n </header>\n\n <main className=\"mx-auto max-w-7xl p-6\">\n {error && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n )}\n\n {showForm && (\n <div className=\"mb-6 rounded-lg border border-border-default bg-surface-raised p-4\">\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {editingId ? 'Edit store' : 'Create store'}\n </h2>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Slug</span>\n <input\n type=\"text\"\n aria-label=\"Slug\"\n value={form.slug}\n onChange={(e) => setForm({ ...form, slug: e.target.value })}\n disabled={!!editingId}\n required\n aria-required=\"true\"\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary disabled:opacity-60\"\n />\n </label>\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Name</span>\n <input\n type=\"text\"\n aria-label=\"Name\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n required\n aria-required=\"true\"\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary\"\n />\n </label>\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Type</span>\n <select\n aria-label=\"Store type\"\n value={form.type}\n onChange={(e) => setForm({ ...form, type: e.target.value as FormState['type'] })}\n disabled={!!editingId}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary disabled:opacity-60\"\n >\n <option value=\"PUBLIC\">Public</option>\n <option value=\"PRIVATE\">Private (opt-in)</option>\n <option value=\"ENTERPRISE\">Enterprise (tenant-scoped)</option>\n </select>\n </label>\n <label className=\"block\">\n <span className=\"text-xs text-text-secondary\">Currency</span>\n <input\n type=\"text\"\n aria-label=\"Currency\"\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value })}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary\"\n />\n </label>\n {form.type !== 'PUBLIC' && (\n <label className=\"block md:col-span-2\">\n <span className=\"text-xs text-text-secondary\">Tenant ID (optional)</span>\n <input\n type=\"text\"\n aria-label=\"Tenant ID\"\n value={form.tenantId}\n onChange={(e) => setForm({ ...form, tenantId: e.target.value })}\n disabled={!!editingId}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary disabled:opacity-60\"\n />\n </label>\n )}\n <label className=\"block md:col-span-2\">\n <span className=\"text-xs text-text-secondary\">Description</span>\n <textarea\n aria-label=\"Description\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={2}\n className=\"mt-1 w-full rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary\"\n />\n </label>\n <label className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Publicly visible\"\n checked={form.isPublic}\n onChange={(e) => setForm({ ...form, isPublic: e.target.checked })}\n />\n <span className=\"text-sm text-text-primary\">Publicly visible</span>\n </label>\n <label className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Requires admin approval\"\n checked={form.requiresApproval}\n onChange={(e) => setForm({ ...form, requiresApproval: e.target.checked })}\n />\n <span className=\"text-sm text-text-primary\">Requires admin approval</span>\n </label>\n <label className=\"flex items-center gap-2 md:col-span-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Allow unverified publishers to submit\"\n checked={form.allowUnverifiedPublishers}\n onChange={(e) =>\n setForm({ ...form, allowUnverifiedPublishers: e.target.checked })\n }\n />\n <span className=\"text-sm text-text-primary\">\n Allow unverified publishers to submit\n </span>\n </label>\n </div>\n <div className=\"mt-4 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setShowForm(false);\n setEditingId(null);\n setForm(emptyForm);\n }}\n className=\"rounded-md border border-border-default bg-surface-default px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void submit()}\n className=\"rounded-md bg-surface-accent px-3 py-1.5 text-sm font-medium text-text-on-accent hover:bg-surface-accent-hover\"\n >\n {editingId ? 'Save changes' : 'Create'}\n </button>\n </div>\n </div>\n )}\n\n {loading && stores.length === 0 ? (\n <output className=\"block py-16 text-center text-text-secondary\">Loading stores…</output>\n ) : stores.length === 0 ? (\n <div className=\"py-16 text-center text-text-secondary\">No stores yet.</div>\n ) : (\n <div className=\"overflow-hidden rounded-lg border border-border-default\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-surface-muted text-left text-xs uppercase tracking-wide text-text-secondary\">\n <tr>\n <th className=\"px-4 py-2\">Slug</th>\n <th className=\"px-4 py-2\">Name</th>\n <th className=\"px-4 py-2\">Type</th>\n <th className=\"px-4 py-2\">Public</th>\n <th className=\"px-4 py-2\">Approval</th>\n <th className=\"px-4 py-2\">Currency</th>\n <th className=\"px-4 py-2 text-right\">Actions</th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-default bg-surface-raised\">\n {stores.map((s) => (\n <tr key={s.id} className=\"text-text-primary\">\n <td className=\"px-4 py-2 font-mono text-xs\">{s.slug}</td>\n <td className=\"px-4 py-2\">{s.name}</td>\n <td className=\"px-4 py-2\">\n <span className=\"rounded-full bg-surface-accent-muted px-2 py-0.5 text-xs font-medium text-text-accent\">\n {s.type}\n </span>\n </td>\n <td className=\"px-4 py-2 text-xs\">{s.isPublic ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-2 text-xs\">\n {s.requiresApproval ? 'Required' : 'Auto-publish'}\n </td>\n <td className=\"px-4 py-2 text-xs\">{s.currency}</td>\n <td className=\"px-4 py-2 text-right\">\n <button\n type=\"button\"\n onClick={() => openEdit(s)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-default px-2 py-1 text-xs text-text-primary hover:bg-surface-hover\"\n >\n <Pencil className=\"size-3\" />\n Edit\n </button>\n {s.id !== 'store_public_default' && (\n <button\n type=\"button\"\n onClick={() => setPendingDeleteId(s.id)}\n className=\"ml-2 inline-flex items-center gap-1 rounded-md border border-border-danger px-2 py-1 text-xs text-text-danger hover:bg-surface-danger-muted\"\n >\n <Trash2 className=\"size-3\" />\n Delete\n </button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </main>\n\n <AlertDialog\n open={pendingDeleteId !== null}\n onOpenChange={(open) => !open && setPendingDeleteId(null)}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete this store?</AlertDialogTitle>\n <AlertDialogDescription>This is a soft delete.</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel onClick={() => setPendingDeleteId(null)}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n className=\"bg-surface-danger text-text-on-danger hover:bg-surface-danger-hover\"\n onClick={() => {\n if (pendingDeleteId) void remove(pendingDeleteId);\n setPendingDeleteId(null);\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -5,10 +5,11 @@ import { StoreInstallationStatus as r } from "../generated/global-types.js";
5
5
  import { useMemo as i, useState as a } from "react";
6
6
  import { useI18n as o } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
7
  import { AlertCircle as s, Loader2 as c, Package as l, Plus as u, RefreshCw as d, Trash2 as f } from "lucide-react";
8
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
9
- import { useNavigate as h } from "react-router-dom";
8
+ import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
9
+ import { useNavigate as g } from "react-router-dom";
10
+ import { AlertDialog as _, AlertDialogAction as v, AlertDialogCancel as y, AlertDialogContent as b, AlertDialogDescription as x, AlertDialogFooter as S, AlertDialogHeader as C, AlertDialogTitle as w } from "@burdenoff/fe-libs/ui";
10
11
  //#region src/pages/InstalledAppsPage.tsx
11
- var g = [
12
+ var T = [
12
13
  {
13
14
  label: "All",
14
15
  value: "all"
@@ -37,185 +38,185 @@ var g = [
37
38
  label: "Uninstalled",
38
39
  value: r.Uninstalled
39
40
  }
40
- ], _ = (e) => e === r.Active ? "bg-status-success-bg-subtle text-status-success-text" : e === r.Pending || e === r.Installing || e === r.Inactive ? "bg-status-warning-bg-subtle text-status-warning-text" : e === r.Failed ? "bg-status-error-bg-subtle text-status-error-text" : "bg-bg-sunken text-text-muted", v = () => {
41
- let v = h(), { basePath: y, workspaceId: b } = e(), { t: x } = o(), [S, C] = a("all"), [w, T] = a(null), [E, D] = a(null), { installations: O, totalCount: k, hasMore: A, loading: j, error: M, uninstall: N, uninstallingIds: P, refetch: F, loadMore: I } = n({ filter: i(() => S === "all" ? void 0 : { status: S }, [S]) });
41
+ ], E = (e) => e === r.Active ? "bg-status-success-bg-subtle text-status-success-text" : e === r.Pending || e === r.Installing || e === r.Inactive ? "bg-status-warning-bg-subtle text-status-warning-text" : e === r.Failed ? "bg-status-error-bg-subtle text-status-error-text" : "bg-bg-sunken text-text-muted", D = () => {
42
+ let D = g(), { basePath: O, workspaceId: k } = e(), { t: A } = o(), [j, M] = a("all"), [N, P] = a(null), [F, I] = a(null), { installations: L, totalCount: R, hasMore: z, loading: B, error: V, uninstall: H, uninstallingIds: U, refetch: W, loadMore: G } = n({ filter: i(() => j === "all" ? void 0 : { status: j }, [j]) });
42
43
  t({
43
- variables: { workspaceId: b ?? "" },
44
- skip: !b,
44
+ variables: { workspaceId: k ?? "" },
45
+ skip: !k,
45
46
  onData: () => {
46
- F();
47
+ W();
47
48
  },
48
49
  onError: (e) => {
49
50
  console.warn("InstallationStatusUpdated subscription error:", e.message);
50
51
  }
51
52
  });
52
- let L = i(() => [...O].sort((e, t) => t.installedAt.localeCompare(e.installedAt)), [O]), R = () => {
53
- v(`${y}/marketplace`);
54
- }, z = async (e) => {
55
- T(null), await N(e, "User requested uninstall from store UI") || T("Could not uninstall. Try again."), D(null);
53
+ let K = i(() => [...L].sort((e, t) => t.installedAt.localeCompare(e.installedAt)), [L]), q = () => {
54
+ D(`${O}/marketplace`);
55
+ }, J = async (e) => {
56
+ P(null), await H(e, "User requested uninstall from store UI") || P("Could not uninstall. Try again."), I(null);
56
57
  };
57
- return /* @__PURE__ */ m("div", {
58
+ return /* @__PURE__ */ h("div", {
58
59
  className: "flex h-full flex-col",
59
60
  children: [
60
- /* @__PURE__ */ p("header", {
61
+ /* @__PURE__ */ m("header", {
61
62
  className: "border-b border-border-default bg-bg-surface px-6 py-4",
62
- children: /* @__PURE__ */ m("div", {
63
+ children: /* @__PURE__ */ h("div", {
63
64
  className: "flex items-center justify-between",
64
- children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
65
+ children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
65
66
  className: "text-2xl font-bold text-text-primary",
66
- children: x("pages.installed.title", { defaultValue: "Installed Apps" })
67
- }), /* @__PURE__ */ p("p", {
67
+ children: A("pages.installed.title", { defaultValue: "Installed Apps" })
68
+ }), /* @__PURE__ */ m("p", {
68
69
  className: "text-sm text-text-muted",
69
70
  children: "Manage your installed applications"
70
- })] }), /* @__PURE__ */ m("button", {
71
+ })] }), /* @__PURE__ */ h("button", {
71
72
  type: "button",
72
- onClick: R,
73
+ onClick: q,
73
74
  className: "flex cursor-pointer items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 font-semibold text-action-primary-text transition-colors hover:opacity-90",
74
- children: [/* @__PURE__ */ p(u, { className: "size-5" }), /* @__PURE__ */ p("span", { children: x("pages.installed.installNew", { defaultValue: "Install New App" }) })]
75
+ children: [/* @__PURE__ */ m(u, { className: "size-5" }), /* @__PURE__ */ m("span", { children: A("pages.installed.installNew", { defaultValue: "Install New App" }) })]
75
76
  })]
76
77
  })
77
78
  }),
78
- /* @__PURE__ */ p("main", {
79
+ /* @__PURE__ */ m("main", {
79
80
  className: "flex-1 overflow-y-auto p-6",
80
- children: /* @__PURE__ */ m("div", {
81
+ children: /* @__PURE__ */ h("div", {
81
82
  className: "mx-auto max-w-6xl",
82
83
  children: [
83
- /* @__PURE__ */ m("div", {
84
+ /* @__PURE__ */ h("div", {
84
85
  className: "mb-4 flex flex-wrap items-center gap-2",
85
- children: [g.map((e) => /* @__PURE__ */ p("button", {
86
+ children: [T.map((e) => /* @__PURE__ */ m("button", {
86
87
  type: "button",
87
- onClick: () => C(e.value),
88
- className: `cursor-pointer rounded-full px-3 py-1.5 text-sm font-medium transition-colors ${S === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-primary hover:bg-bg-surface"}`,
88
+ onClick: () => M(e.value),
89
+ className: `cursor-pointer rounded-full px-3 py-1.5 text-sm font-medium transition-colors ${j === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-primary hover:bg-bg-surface"}`,
89
90
  children: e.label
90
- }, e.label)), /* @__PURE__ */ m("button", {
91
+ }, e.label)), /* @__PURE__ */ h("button", {
91
92
  type: "button",
92
- onClick: () => F(),
93
+ onClick: () => W(),
93
94
  className: "ml-auto cursor-pointer inline-flex items-center gap-2 rounded-lg border border-border-default bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
94
- children: [/* @__PURE__ */ p(d, { className: "size-4" }), "Refresh"]
95
+ children: [/* @__PURE__ */ m(d, { className: "size-4" }), "Refresh"]
95
96
  })]
96
97
  }),
97
- w && /* @__PURE__ */ p("div", {
98
+ N && /* @__PURE__ */ m("div", {
98
99
  role: "alert",
99
100
  className: "mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text",
100
- children: w
101
+ children: N
101
102
  }),
102
- j ? /* @__PURE__ */ p("output", {
103
+ B ? /* @__PURE__ */ m("output", {
103
104
  "aria-label": "Loading installed apps",
104
105
  className: "flex items-center justify-center py-16",
105
- children: /* @__PURE__ */ p(c, {
106
+ children: /* @__PURE__ */ m(c, {
106
107
  className: "size-8 animate-spin text-text-muted",
107
108
  "aria-hidden": "true"
108
109
  })
109
- }) : M ? /* @__PURE__ */ m("div", {
110
+ }) : V ? /* @__PURE__ */ h("div", {
110
111
  role: "alert",
111
112
  className: "flex flex-col items-center justify-center rounded-xl border border-status-error-border bg-status-error-bg-subtle py-16 text-center",
112
113
  children: [
113
- /* @__PURE__ */ p(s, { className: "mb-3 size-10 text-status-error-text" }),
114
- /* @__PURE__ */ p("h3", {
114
+ /* @__PURE__ */ m(s, { className: "mb-3 size-10 text-status-error-text" }),
115
+ /* @__PURE__ */ m("h3", {
115
116
  className: "text-lg font-semibold text-status-error-text",
116
117
  children: "Failed to load installations"
117
118
  }),
118
- /* @__PURE__ */ p("p", {
119
+ /* @__PURE__ */ m("p", {
119
120
  className: "mt-2 text-sm text-text-muted",
120
- children: M.message
121
+ children: V.message
121
122
  }),
122
- /* @__PURE__ */ p("button", {
123
+ /* @__PURE__ */ m("button", {
123
124
  type: "button",
124
- onClick: () => F(),
125
+ onClick: () => W(),
125
126
  className: "mt-4 cursor-pointer rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
126
127
  children: "Try Again"
127
128
  })
128
129
  ]
129
- }) : L.length === 0 ? /* @__PURE__ */ p("div", {
130
+ }) : K.length === 0 ? /* @__PURE__ */ m("div", {
130
131
  className: "flex items-center justify-center py-16",
131
- children: /* @__PURE__ */ m("div", {
132
+ children: /* @__PURE__ */ h("div", {
132
133
  className: "text-center",
133
134
  children: [
134
- /* @__PURE__ */ p(l, { className: "mx-auto mb-4 size-16 text-text-muted" }),
135
- /* @__PURE__ */ p("h3", {
135
+ /* @__PURE__ */ m(l, { className: "mx-auto mb-4 size-16 text-text-muted" }),
136
+ /* @__PURE__ */ m("h3", {
136
137
  className: "mb-2 text-lg font-semibold text-text-primary",
137
138
  children: "No apps installed"
138
139
  }),
139
- /* @__PURE__ */ p("p", {
140
+ /* @__PURE__ */ m("p", {
140
141
  className: "mb-4 text-sm text-text-muted",
141
142
  children: "Browse the marketplace to install your first app"
142
143
  }),
143
- /* @__PURE__ */ p("button", {
144
+ /* @__PURE__ */ m("button", {
144
145
  type: "button",
145
- onClick: R,
146
+ onClick: q,
146
147
  className: "rounded-lg bg-action-primary-bg px-4 py-2 font-semibold text-action-primary-text transition-colors hover:opacity-90",
147
148
  children: "Browse Marketplace"
148
149
  })
149
150
  ]
150
151
  })
151
- }) : /* @__PURE__ */ m("div", {
152
+ }) : /* @__PURE__ */ h("div", {
152
153
  className: "flex flex-col gap-y-4",
153
154
  children: [
154
- /* @__PURE__ */ m("p", {
155
+ /* @__PURE__ */ h("p", {
155
156
  "aria-live": "polite",
156
157
  className: "text-sm text-text-muted",
157
158
  children: [
158
- k,
159
+ R,
159
160
  " installation",
160
- k === 1 ? "" : "s",
161
+ R === 1 ? "" : "s",
161
162
  " found"
162
163
  ]
163
164
  }),
164
- /* @__PURE__ */ p("ul", {
165
+ /* @__PURE__ */ m("ul", {
165
166
  className: "flex flex-col gap-y-4",
166
- children: L.map((e) => {
167
- let t = P.has(`${e.workspaceId}:${e.productId}`);
168
- return /* @__PURE__ */ p("li", {
167
+ children: K.map((e) => {
168
+ let t = U.has(`${e.workspaceId}:${e.productId}`);
169
+ return /* @__PURE__ */ m("li", {
169
170
  className: "rounded-xl border border-border-default bg-bg-surface p-4",
170
- children: /* @__PURE__ */ m("div", {
171
+ children: /* @__PURE__ */ h("div", {
171
172
  className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
172
- children: [/* @__PURE__ */ m("div", {
173
+ children: [/* @__PURE__ */ h("div", {
173
174
  className: "flex items-start gap-3",
174
- children: [/* @__PURE__ */ p("div", {
175
+ children: [/* @__PURE__ */ m("div", {
175
176
  className: "flex size-12 items-center justify-center rounded-lg bg-bg-sunken text-lg font-semibold text-text-muted",
176
- children: /* @__PURE__ */ p(l, { className: "size-6" })
177
- }), /* @__PURE__ */ m("div", { children: [
178
- /* @__PURE__ */ p("h3", {
177
+ children: /* @__PURE__ */ m(l, { className: "size-6" })
178
+ }), /* @__PURE__ */ h("div", { children: [
179
+ /* @__PURE__ */ m("h3", {
179
180
  className: "font-semibold text-text-primary",
180
181
  children: e.workspaceName ?? e.workspaceId
181
182
  }),
182
- /* @__PURE__ */ m("p", {
183
+ /* @__PURE__ */ h("p", {
183
184
  className: "text-sm text-text-muted",
184
185
  children: ["Product: ", e.productId]
185
186
  }),
186
- /* @__PURE__ */ m("div", {
187
+ /* @__PURE__ */ h("div", {
187
188
  className: "mt-2 flex flex-wrap items-center gap-2 text-xs text-text-muted",
188
189
  children: [
189
- /* @__PURE__ */ p("span", {
190
- className: `rounded-full px-2 py-1 font-medium ${_(e.status)}`,
190
+ /* @__PURE__ */ m("span", {
191
+ className: `rounded-full px-2 py-1 font-medium ${E(e.status)}`,
191
192
  children: e.status
192
193
  }),
193
- e.version && /* @__PURE__ */ m("span", { children: ["v", e.version] }),
194
- e.workspaceType && /* @__PURE__ */ p("span", { children: e.workspaceType })
194
+ e.version && /* @__PURE__ */ h("span", { children: ["v", e.version] }),
195
+ e.workspaceType && /* @__PURE__ */ m("span", { children: e.workspaceType })
195
196
  ]
196
197
  })
197
198
  ] })]
198
- }), /* @__PURE__ */ m("div", {
199
+ }), /* @__PURE__ */ h("div", {
199
200
  className: "flex items-center gap-2",
200
201
  children: [
201
- /* @__PURE__ */ p("button", {
202
+ /* @__PURE__ */ m("button", {
202
203
  type: "button",
203
- onClick: () => v(`${y}/installed/${e.id}`),
204
+ onClick: () => D(`${O}/installed/${e.id}`),
204
205
  className: "cursor-pointer rounded-lg border border-border-default px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
205
206
  children: "Details"
206
207
  }),
207
- /* @__PURE__ */ p("button", {
208
+ /* @__PURE__ */ m("button", {
208
209
  type: "button",
209
- onClick: () => v(`${y}/marketplace/product/${e.productId}`),
210
+ onClick: () => D(`${O}/marketplace/product/${e.productId}`),
210
211
  className: "cursor-pointer rounded-lg border border-border-default px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
211
212
  children: "View Product"
212
213
  }),
213
- e.status !== r.Uninstalled && /* @__PURE__ */ m("button", {
214
+ e.status !== r.Uninstalled && /* @__PURE__ */ h("button", {
214
215
  type: "button",
215
- onClick: () => D(e),
216
+ onClick: () => I(e),
216
217
  disabled: t,
217
218
  className: "cursor-pointer inline-flex items-center gap-1.5 rounded-lg border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:opacity-60",
218
- children: [t ? /* @__PURE__ */ p(c, { className: "size-4 animate-spin" }) : /* @__PURE__ */ p(f, { className: "size-4" }), "Uninstall"]
219
+ children: [t ? /* @__PURE__ */ m(c, { className: "size-4 animate-spin" }) : /* @__PURE__ */ m(f, { className: "size-4" }), "Uninstall"]
219
220
  })
220
221
  ]
221
222
  })]
@@ -223,14 +224,14 @@ var g = [
223
224
  }, e.id);
224
225
  })
225
226
  }),
226
- A && /* @__PURE__ */ p("div", {
227
+ z && /* @__PURE__ */ m("div", {
227
228
  className: "flex justify-center pt-6",
228
- children: /* @__PURE__ */ p("button", {
229
+ children: /* @__PURE__ */ m("button", {
229
230
  type: "button",
230
- onClick: I,
231
- disabled: j,
231
+ onClick: G,
232
+ disabled: B,
232
233
  className: "rounded-lg border border-border-default px-6 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-subtle disabled:opacity-50",
233
- children: j ? "Loading…" : "Load more"
234
+ children: B ? "Loading…" : "Load more"
234
235
  })
235
236
  })
236
237
  ]
@@ -238,64 +239,40 @@ var g = [
238
239
  ]
239
240
  })
240
241
  }),
241
- E && /* @__PURE__ */ m("div", {
242
- className: "fixed inset-0 z-50 flex items-center justify-center p-4",
243
- children: [/* @__PURE__ */ p("button", {
244
- type: "button",
245
- "aria-label": "Cancel uninstall",
246
- className: "absolute inset-0 bg-bg-overlay/50",
247
- onClick: () => D(null)
248
- }), /* @__PURE__ */ m("dialog", {
249
- open: !0,
250
- "aria-modal": "true",
251
- "aria-labelledby": "installed-apps-uninstall-title",
252
- className: "relative z-10 w-full max-w-md rounded-2xl border border-border-default bg-bg-surface p-6 shadow-2xl",
253
- children: [
254
- /* @__PURE__ */ p("h2", {
255
- id: "installed-apps-uninstall-title",
256
- className: "text-lg font-semibold text-text-primary",
257
- children: "Uninstall app"
242
+ /* @__PURE__ */ m(_, {
243
+ open: F !== null,
244
+ onOpenChange: (e) => !e && I(null),
245
+ children: /* @__PURE__ */ h(b, {
246
+ className: "max-w-md",
247
+ children: [/* @__PURE__ */ h(C, { children: [/* @__PURE__ */ m(w, { children: "Uninstall app" }), /* @__PURE__ */ m(x, { children: F && /* @__PURE__ */ h(p, { children: [
248
+ "Remove product",
249
+ " ",
250
+ /* @__PURE__ */ m("span", {
251
+ className: "font-medium text-text-primary",
252
+ children: F.productId
258
253
  }),
259
- /* @__PURE__ */ m("p", {
260
- className: "mt-2 text-sm text-text-muted",
261
- children: [
262
- "Remove product",
263
- " ",
264
- /* @__PURE__ */ p("span", {
265
- className: "font-medium text-text-primary",
266
- children: E.productId
267
- }),
268
- " ",
269
- "from workspace",
270
- " ",
271
- /* @__PURE__ */ p("span", {
272
- className: "font-medium text-text-primary",
273
- children: E.workspaceName ?? E.workspaceId
274
- }),
275
- "?"
276
- ]
254
+ " ",
255
+ "from workspace",
256
+ " ",
257
+ /* @__PURE__ */ m("span", {
258
+ className: "font-medium text-text-primary",
259
+ children: F.workspaceName ?? F.workspaceId
277
260
  }),
278
- /* @__PURE__ */ m("div", {
279
- className: "mt-6 flex flex-wrap justify-end gap-3",
280
- children: [/* @__PURE__ */ p("button", {
281
- type: "button",
282
- onClick: () => D(null),
283
- className: "cursor-pointer rounded-lg border border-border-default px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
284
- children: "Cancel"
285
- }), /* @__PURE__ */ p("button", {
286
- type: "button",
287
- onClick: () => z(E),
288
- className: "cursor-pointer rounded-lg bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-emphasis",
289
- children: "Uninstall"
290
- })]
291
- })
292
- ]
293
- })]
261
+ "?"
262
+ ] }) })] }), /* @__PURE__ */ h(S, { children: [/* @__PURE__ */ m(y, {
263
+ onClick: () => I(null),
264
+ children: "Cancel"
265
+ }), /* @__PURE__ */ m(v, {
266
+ className: "bg-status-error-bg text-status-error-text hover:bg-status-error-bg-emphasis",
267
+ onClick: () => F && J(F),
268
+ children: "Uninstall"
269
+ })] })]
270
+ })
294
271
  })
295
272
  ]
296
273
  });
297
274
  };
298
275
  //#endregion
299
- export { v as InstalledAppsPage };
276
+ export { D as InstalledAppsPage };
300
277
 
301
278
  //# sourceMappingURL=InstalledAppsPage.js.map