@burdenoff/microfe-vibecontrols 2026.601.21 → 2026.601.23
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/components/actions/ActionCard.js +77 -66
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +186 -173
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AITemplatesTab.js +135 -125
- package/dist/components/ai/AITemplatesTab.js.map +1 -1
- package/dist/components/ai/InstructionFilesManager.js +151 -137
- package/dist/components/ai/InstructionFilesManager.js.map +1 -1
- package/dist/components/docs/DocsEditPanel.js +17 -16
- package/dist/components/docs/DocsEditPanel.js.map +1 -1
- package/dist/components/docs/DocsPreviewPanel.js +25 -24
- package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +110 -94
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +8 -8
- package/dist/components/scorecard/ScorecardPanel.js +271 -257
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/sharing/EntityShareButton.js +58 -0
- package/dist/components/sharing/EntityShareButton.js.map +1 -0
- package/dist/components/sharing/entityShareOps.js +603 -0
- package/dist/components/sharing/entityShareOps.js.map +1 -0
- package/dist/components/sharing/index.js +3 -0
- package/dist/components/sharing/shareRegistry.js +37 -12
- package/dist/components/sharing/shareRegistry.js.map +1 -1
- package/dist/components/sharing/useEntityShareController.js +88 -0
- package/dist/components/sharing/useEntityShareController.js.map +1 -0
- package/dist/constants/permissions.js +11 -0
- package/dist/constants/permissions.js.map +1 -1
- package/dist/pages/ActionsPage.js +162 -162
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +264 -250
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +124 -113
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +139 -126
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +78 -67
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +1 -1
- package/dist/pages/VibeDetailsPage.js +484 -484
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +91 -77
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateDetailPage.js","names":[],"sources":["../../src/pages/TemplateDetailPage.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport {\n ArrowLeft,\n FileCode,\n Copy,\n Layers,\n Tag,\n FolderTree,\n Clock,\n RefreshCw,\n Trash2,\n Variable,\n Github,\n CheckCircle2,\n XCircle,\n Loader2,\n} from 'lucide-react';\nimport {\n PageHeader,\n Card,\n EmptyState,\n ErrorState,\n ConfirmDialog,\n QuotaExhaustedDialog,\n} from '@/components/shared';\nimport { isQuotaExhaustedError } from '@/utils/quotaUtils';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { TemplateWizard } from '@/components/templates';\nimport type { TemplateVariable, GitHubConfig, GitHubConnection } from '@/components/templates';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useGetTemplateQuery,\n useInstantiateTemplateMutation,\n useDeleteTemplateMutation,\n useUpdateComponentMutation,\n useForkGitHubRepoMutation,\n useListActiveConnectionsQuery,\n} from '@/generated/wspace-operations';\n\nfunction substituteVars(text: string, vars: Record<string, unknown>): string {\n return text.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (_match, a, b) => {\n const key = a ?? b;\n return key in vars ? String(vars[key]) : _match;\n });\n}\n\nfunction parseGitHubRepo(url: string): { owner: string; repo: string } | null {\n try {\n const match = url.match(/^https?:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git)?(?:\\/.*)?$/);\n if (!match) return null;\n return { owner: match[1], repo: match[2] };\n } catch {\n return null;\n }\n}\n\nasync function scaffoldGitHubRepo(\n fullName: string,\n headers: Record<string, string>,\n data: {\n name: string;\n description: string;\n variableValues: Record<string, unknown>;\n },\n template: {\n name: string;\n description?: string | null;\n setupInstructions?: string | null;\n fileTree?: unknown;\n variables?: unknown;\n } | null\n) {\n if (!template) return;\n\n const vars = data.variableValues;\n const templateVars = Array.isArray(template.variables)\n ? (template.variables as Array<{ name: string; title?: string }>)\n : [];\n\n // Build README content\n const lines: string[] = [];\n lines.push(`# ${data.name}`);\n lines.push('');\n if (data.description) {\n lines.push(data.description);\n lines.push('');\n }\n lines.push(`> Scaffolded from VibeControls template: **${template.name}**`);\n lines.push('');\n\n // Variable values table\n if (templateVars.length > 0 && Object.keys(vars).length > 0) {\n lines.push('## Configuration');\n lines.push('');\n lines.push('| Variable | Value |');\n lines.push('|----------|-------|');\n for (const v of templateVars) {\n const val = vars[v.name];\n if (val !== undefined) {\n lines.push(`| ${v.title ?? v.name} | \\`${String(val)}\\` |`);\n }\n }\n lines.push('');\n }\n\n // Setup instructions (with variable substitution)\n if (template.setupInstructions) {\n lines.push('## Getting Started');\n lines.push('');\n lines.push(substituteVars(template.setupInstructions, vars));\n lines.push('');\n }\n\n // File tree\n if (template.fileTree) {\n lines.push('## Project Structure');\n lines.push('');\n lines.push('```');\n lines.push(\n typeof template.fileTree === 'string'\n ? template.fileTree\n : JSON.stringify(template.fileTree, null, 2)\n );\n lines.push('```');\n lines.push('');\n }\n\n const readmeContent = lines.join('\\n');\n\n // Get existing README.md SHA so we can update it\n const existing = await fetch(`https://api.github.com/repos/${fullName}/contents/README.md`, {\n headers,\n });\n let sha: string | undefined;\n if (existing.ok) {\n const existingData = (await existing.json()) as { sha?: string };\n sha = existingData.sha;\n }\n\n // Push scaffolded README.md\n await fetch(`https://api.github.com/repos/${fullName}/contents/README.md`, {\n method: 'PUT',\n headers,\n body: JSON.stringify({\n message: `chore: scaffold from VibeControls template \"${template.name}\"`,\n content: btoa(unescape(encodeURIComponent(readmeContent))),\n ...(sha ? { sha } : {}),\n }),\n });\n\n // Push GETTING_STARTED.md with setup instructions + resolved variable values\n if (template.setupInstructions || (templateVars.length > 0 && Object.keys(vars).length > 0)) {\n const gsLines: string[] = ['# Getting Started', ''];\n\n if (template.setupInstructions) {\n gsLines.push(substituteVars(template.setupInstructions, vars));\n gsLines.push('');\n }\n\n // Always append a resolved variables section so values are never lost\n if (templateVars.length > 0 && Object.keys(vars).length > 0) {\n gsLines.push('---');\n gsLines.push('');\n gsLines.push('## Template Variable Values');\n gsLines.push('');\n gsLines.push('These are the values you chose when creating this project:');\n gsLines.push('');\n for (const v of templateVars) {\n const val = vars[v.name];\n if (val !== undefined && val !== '') {\n gsLines.push(`**${v.title ?? v.name}**`);\n gsLines.push('');\n gsLines.push('```');\n gsLines.push(String(val));\n gsLines.push('```');\n gsLines.push('');\n }\n }\n }\n\n await fetch(`https://api.github.com/repos/${fullName}/contents/GETTING_STARTED.md`, {\n method: 'PUT',\n headers,\n body: JSON.stringify({\n message: 'docs: add getting started guide from template',\n content: btoa(unescape(encodeURIComponent(gsLines.join('\\n')))),\n }),\n });\n }\n}\n\nconst categoryStyles: Record<string, string> = {\n STARTER: 'bg-bg-sunken text-text-secondary',\n MICROSERVICE: 'bg-action-primary-bg/10 text-action-primary-bg',\n FRONTEND: 'bg-status-info-bg text-status-info-text',\n BACKEND: 'bg-action-primary-bg/10 text-action-primary-bg',\n FULLSTACK: 'bg-status-success-bg text-status-success-text',\n INFRASTRUCTURE: 'bg-status-warning-bg text-status-warning-text',\n LIBRARY: 'bg-status-warning-bg text-status-warning-text',\n CUSTOM: 'bg-bg-sunken text-text-secondary',\n};\n\nexport function TemplateDetailPage() {\n const { t } = useI18n();\n const { id } = useParams<{ id: string }>();\n const navigate = useVibeNavigate();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const [showWizard, setShowWizard] = useState(false);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [cloneError, setCloneError] = useState<string | null>(null);\n const [forkNotice, setForkNotice] = useState<string | null>(null);\n const [repoProgress, setRepoProgress] = useState<{\n stage: string;\n done: boolean;\n error: boolean;\n } | null>(null);\n\n const { data, loading, error, refetch } = useGetTemplateQuery({\n variables: { id: id || '' },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\n const [instantiateTemplate] = useInstantiateTemplateMutation({\n refetchQueries: ['ListComponents'],\n });\n const [deleteTemplate] = useDeleteTemplateMutation({ refetchQueries: ['ListTemplates'] });\n const [updateComponent] = useUpdateComponentMutation();\n const [forkGitHubRepo] = useForkGitHubRepoMutation();\n\n // Fetch active GitHub connections for the workspace\n const { data: connectionsData } = useListActiveConnectionsQuery({\n variables: { filter: { status: 'ACTIVE' as const }, pagination: { limit: 50, offset: 0 } },\n fetchPolicy: 'cache-first',\n });\n const githubConnections: GitHubConnection[] = (connectionsData?.getConnections?.items ?? [])\n .filter((c: { provider?: { key?: string } | null }) => c.provider?.key === 'github')\n .map(\n (c: {\n id: string;\n name: string;\n externalAccountEmail?: string | null;\n externalAccountName?: string | null;\n provider: { key: string; name: string };\n }) => ({\n id: c.id,\n name: c.name,\n externalAccountEmail: c.externalAccountEmail,\n externalAccountName: c.externalAccountName,\n provider: { key: c.provider.key, name: c.provider.name },\n })\n );\n\n const template = data?.vibecontrolsTemplate ?? null;\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (!hasPermission(VIBE_PERMISSIONS.VIBE_READ))\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n const handleBack = () => {\n navigate('/templates');\n };\n\n const handleClone = async (data: {\n name: string;\n description: string;\n variableValues: Record<string, unknown>;\n githubConfig: GitHubConfig | null;\n }) => {\n setShowWizard(false);\n setRepoProgress({ stage: 'Creating component…', done: false, error: false });\n\n const result = await instantiateTemplate({\n variables: {\n templateId: id,\n input: {\n name: data.name,\n description: data.description || undefined,\n ...(Object.keys(data.variableValues).length > 0 && {\n variableValues: data.variableValues,\n }),\n },\n },\n });\n if (result.error && isQuotaExhaustedError(result.error)) {\n setRepoProgress(null);\n setShowQuotaExhausted(true);\n return;\n }\n const newId = result.data?.instantiateVibecontrolsTemplate?.id;\n\n // GitHub repo creation + scaffolding\n if (newId && data.githubConfig?.enabled) {\n // Ensure repo URL starts empty before GitHub runs\n await updateComponent({ variables: { id: newId, input: { repositoryUrl: null } } });\n const gh = data.githubConfig;\n\n // Priority: explicit sourceRepositoryUrl > snapshot URL > sourceComponent.repositoryUrl\n const snapshotRepoUrl = (template?.componentSnapshot as Record<string, unknown> | null)\n ?.repositoryUrl as string | undefined;\n const sourceRepoUrl =\n template?.sourceRepositoryUrl ||\n snapshotRepoUrl ||\n template?.sourceComponent?.repositoryUrl ||\n undefined;\n\n try {\n if (gh.connectionId) {\n // ── OAuth path: backend resolves the token server-side ──────────────\n setRepoProgress({\n stage: sourceRepoUrl\n ? 'Forking repository via connected account…'\n : 'Creating GitHub repository via connected account…',\n done: false,\n error: false,\n });\n\n const forkResult = await forkGitHubRepo({\n variables: {\n input: {\n connectionId: gh.connectionId,\n sourceRepoUrl: sourceRepoUrl || undefined,\n repoName: gh.repoName,\n visibility: gh.visibility === 'private' ? 'PRIVATE' : 'PUBLIC',\n scope: gh.scope === 'org' ? 'ORG' : 'USER',\n orgName: gh.orgName || undefined,\n description:\n data.description || `Created from VibeControls template: ${template?.name}`,\n },\n },\n });\n\n const forkData = forkResult.data?.forkVibecontrolsGitHubRepo;\n if (forkData) {\n setRepoProgress({\n stage: forkData.isForked ? 'Repository forked!' : 'Repository created!',\n done: true,\n error: false,\n });\n await updateComponent({\n variables: { id: newId, input: { repositoryUrl: forkData.repoUrl } },\n });\n await new Promise((r) => setTimeout(r, 1200));\n } else {\n setRepoProgress({\n stage: 'GitHub repo creation failed — check your connected account',\n done: false,\n error: true,\n });\n setTimeout(() => setRepoProgress(null), 6000);\n }\n } else {\n // ── PAT path: existing client-side GitHub API flow ──────────────────\n const ghHeaders = {\n Authorization: `Bearer ${gh.token}`,\n 'Content-Type': 'application/json',\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n };\n const apiBase = 'https://api.github.com';\n\n const sourceRepo = sourceRepoUrl ? parseGitHubRepo(sourceRepoUrl) : null;\n let repoData: { html_url: string; full_name: string } | null = null;\n let isForked = false;\n\n if (sourceRepo) {\n setRepoProgress({\n stage: `Forking ${sourceRepo.owner}/${sourceRepo.repo}…`,\n done: false,\n error: false,\n });\n const forkRes = await fetch(\n `${apiBase}/repos/${encodeURIComponent(sourceRepo.owner)}/${encodeURIComponent(sourceRepo.repo)}/forks`,\n {\n method: 'POST',\n headers: ghHeaders,\n body: JSON.stringify({\n name: gh.repoName,\n ...(gh.scope === 'org' ? { organization: gh.orgName } : {}),\n default_branch_only: false,\n }),\n }\n );\n\n if (forkRes.ok) {\n repoData = (await forkRes.json()) as { html_url: string; full_name: string };\n isForked = true;\n } else {\n const forkErr = (await forkRes.json()) as { message?: string };\n setRepoProgress(null);\n setForkNotice(\n `Could not fork ${sourceRepoUrl} (${forkRes.status}: ${forkErr.message ?? forkRes.statusText}) — creating a new empty repository instead.`\n );\n setTimeout(() => setForkNotice(null), 10000);\n }\n }\n\n if (!repoData) {\n setRepoProgress({ stage: 'Creating GitHub repository…', done: false, error: false });\n const createEndpoint =\n gh.scope === 'org'\n ? `${apiBase}/orgs/${encodeURIComponent(gh.orgName)}/repos`\n : `${apiBase}/user/repos`;\n\n const repoRes = await fetch(createEndpoint, {\n method: 'POST',\n headers: ghHeaders,\n body: JSON.stringify({\n name: gh.repoName,\n private: gh.visibility === 'private',\n auto_init: true,\n description:\n data.description || `Created from VibeControls template: ${template?.name}`,\n }),\n });\n\n if (repoRes.ok) {\n repoData = (await repoRes.json()) as { html_url: string; full_name: string };\n } else {\n const errBody = (await repoRes.json()) as { message?: string };\n setRepoProgress({\n stage: `GitHub repo failed: ${errBody.message ?? repoRes.statusText}`,\n done: false,\n error: true,\n });\n setTimeout(() => setRepoProgress(null), 6000);\n }\n }\n\n if (repoData) {\n if (!isForked) {\n setRepoProgress({ stage: 'Scaffolding README…', done: false, error: false });\n await scaffoldGitHubRepo(repoData.full_name, ghHeaders, data, template);\n }\n\n setRepoProgress({\n stage: isForked ? 'Repository forked!' : 'Repository created!',\n done: true,\n error: false,\n });\n await updateComponent({\n variables: { id: newId, input: { repositoryUrl: repoData.html_url } },\n });\n await new Promise((r) => setTimeout(r, 1200));\n setRepoProgress(null);\n } else {\n await new Promise((r) => setTimeout(r, 3000));\n setRepoProgress(null);\n }\n }\n } catch {\n setRepoProgress({\n stage: 'GitHub repo creation failed — check your credentials',\n done: false,\n error: true,\n });\n setTimeout(() => setRepoProgress(null), 6000);\n }\n }\n\n setRepoProgress(null);\n if (newId) {\n navigate(`/components/${newId}`);\n } else {\n setSuccessMessage(tr('template.clonedSuccess', 'Component created — check Components list'));\n setTimeout(() => setSuccessMessage(null), 4000);\n }\n };\n\n const handleDeleteTemplate = async () => {\n if (!id) return;\n setIsDeleting(true);\n try {\n await deleteTemplate({ variables: { id } });\n setShowDeleteConfirm(false);\n navigate('/templates');\n } finally {\n setIsDeleting(false);\n }\n };\n\n // Guard states\n if (loading && !template) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (error && !template) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n <ErrorState\n title={tr('template.failedLoad', 'Failed to load template')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n if (!template) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n <EmptyState\n icon={<FileCode className=\"size-8 text-text-secondary\" />}\n title={tr('template.notFound', 'Template not found')}\n description={`No template with ID \"${id}\" exists`}\n action={\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-success-bg text-status-success-text px-4 py-3 rounded-md shadow-lg\">\n {successMessage}\n </div>\n )}\n {forkNotice && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-warning-bg text-status-warning-text px-4 py-3 rounded-md shadow-lg text-sm max-w-sm\">\n {forkNotice}\n </div>\n )}\n {/* Error Toast */}\n {cloneError && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-error-bg text-status-error-text px-4 py-3 rounded-md shadow-lg\">\n {cloneError}\n </div>\n )}\n {/* Repo creation progress overlay */}\n {repoProgress && (\n <div\n className=\"fixed inset-0 z-[9999] flex items-center justify-center p-4\"\n style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}\n >\n <div className=\"bg-bg-surface border border-border-default rounded-xl shadow-2xl p-8 flex flex-col items-center gap-4 max-w-xs w-full\">\n {repoProgress.done ? (\n <CheckCircle2 className=\"size-10 text-status-success-text\" />\n ) : repoProgress.error ? (\n <XCircle className=\"size-10 text-status-error-text\" />\n ) : (\n <Loader2 className=\"size-10 text-action-primary-bg animate-spin\" />\n )}\n <p className=\"text-sm font-medium text-text-primary text-center\">\n {repoProgress.stage}\n </p>\n </div>\n </div>\n )}\n\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n\n {/* Header */}\n <PageHeader\n title={template.name}\n description={template.description || tr('template.noDescription', 'No description')}\n actions={\n <div className=\"flex items-center gap-2 flex-wrap\">\n <button\n type=\"button\"\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken/80 transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowWizard(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Copy className=\"size-4\" />\n {tr('template.useTemplate', 'Use Template')}\n </button>\n <button\n type=\"button\"\n data-testid=\"template-delete-button\"\n onClick={() => setShowDeleteConfirm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-status-error-bg text-status-error-text rounded-md hover:opacity-90 transition-opacity\"\n aria-label={tr('template.deleteTemplate', 'Delete Template')}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {tr('common.delete', 'Delete')}\n </button>\n </div>\n }\n />\n\n {/* Context hint for new users */}\n <p className=\"text-sm text-text-muted\">\n Click <span className=\"font-medium text-text-secondary\">Use Template</span> to open a short\n wizard — give your new component a name, fill in any variables, and optionally create a\n GitHub repository. The whole thing takes under a minute.\n </p>\n\n {/* Badges */}\n <div className=\"flex items-center gap-3 flex-wrap\">\n {template.category && (\n <span\n className={`inline-flex items-center gap-1.5 px-2.5 py-1 text-sm font-medium rounded ${categoryStyles[template.category] || 'bg-bg-sunken text-text-secondary'}`}\n >\n <Layers className=\"size-3.5\" />\n {template.category}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <Copy className=\"size-3.5\" />\n {template.cloneCount} {tr('template.clones', 'clones')}\n </span>\n {template.sourceRepositoryUrl && (\n <a\n href={template.sourceRepositoryUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n className=\"inline-flex items-center gap-1.5 text-sm text-action-primary-bg hover:underline\"\n >\n <Github className=\"size-3.5\" />\n {template.sourceRepositoryUrl.replace('https://github.com/', '')}\n </a>\n )}\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <Clock className=\"size-3.5\" />\n {new Date(template.createdAt).toLocaleDateString()}\n </span>\n </div>\n\n {/* Tags */}\n {template.tags?.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.tags.map((tag: string) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2.5 py-1 text-sm bg-bg-sunken text-text-secondary rounded-md\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n </div>\n )}\n\n {/* Universal tags */}\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Tag className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">{tr('template.tags', 'Tags')}</h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_TEMPLATE\" entityId={template.id} />\n </div>\n </Card>\n\n {/* Source Component */}\n {template.sourceComponent && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.sourceComponent', 'Source Component')}\n </h3>\n </div>\n <div className=\"p-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`/components/${template.sourceComponent.id}`)}\n className=\"flex items-center gap-3 text-left hover:bg-bg-sunken p-2 -m-2 rounded-md transition-colors\"\n >\n <div className=\"size-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center flex-shrink-0\">\n <FileCode className=\"size-5 text-action-primary-bg\" />\n </div>\n <div>\n <p className=\"font-medium text-text-primary\">{template.sourceComponent.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {template.sourceComponent.type} · {template.sourceComponent.lifecycle}\n </p>\n </div>\n </button>\n </div>\n </Card>\n )}\n\n {/* Cloned Components */}\n {template.clonedComponents && template.clonedComponents.length > 0 && (\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Copy className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.createdComponents', 'Created Components')}\n </h3>\n <span className=\"ml-auto text-xs text-text-muted\">\n {template.clonedComponents.length} component\n {template.clonedComponents.length !== 1 ? 's' : ''}\n </span>\n </div>\n <div className=\"divide-y divide-border-default\">\n {template.clonedComponents.map(\n (comp: {\n id: string;\n name: string;\n description?: string | null;\n type: string;\n lifecycle: string;\n repositoryUrl?: string | null;\n createdAt: string;\n }) => (\n <button\n type=\"button\"\n key={comp.id}\n onClick={() => navigate(`/components/${comp.id}`)}\n className=\"flex items-center gap-3 w-full text-left px-4 py-3 hover:bg-bg-sunken transition-colors\"\n >\n <div className=\"size-8 rounded-md bg-action-primary-bg/10 flex items-center justify-center flex-shrink-0\">\n <FileCode className=\"size-4 text-action-primary-bg\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{comp.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {comp.type} · {comp.lifecycle}\n {comp.repositoryUrl && (\n <>\n {' '}\n ·{' '}\n <span className=\"font-mono\">\n {comp.repositoryUrl.replace('https://github.com/', '')}\n </span>\n </>\n )}\n </p>\n </div>\n <span className=\"text-xs text-text-muted flex-shrink-0\">\n {new Date(comp.createdAt).toLocaleDateString()}\n </span>\n </button>\n )\n )}\n </div>\n </Card>\n )}\n\n {/* Variables preview */}\n {Array.isArray(template.variables) &&\n (template.variables as TemplateVariable[]).length > 0 && (\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Variable className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.variables', 'Template Variables')}\n </h3>\n <span className=\"ml-auto text-xs text-text-muted\">\n {(template.variables as TemplateVariable[]).length} variable\n {(template.variables as TemplateVariable[]).length !== 1 ? 's' : ''}\n </span>\n </div>\n <div className=\"divide-y divide-border-default\">\n {(template.variables as TemplateVariable[]).map((v) => (\n <div key={v.name} className=\"px-4 py-3 flex items-start gap-4\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary font-mono\">\n {v.name}\n </span>\n {v.required && (\n <span className=\"text-xs bg-status-error-bg text-status-error-text px-1.5 py-0.5 rounded\">\n required\n </span>\n )}\n <span className=\"text-xs bg-bg-sunken text-text-muted px-1.5 py-0.5 rounded\">\n {v.type}\n </span>\n </div>\n {v.title && v.title !== v.name && (\n <p className=\"text-xs text-text-secondary mt-0.5\">{v.title}</p>\n )}\n {v.default && (\n <p className=\"text-xs text-text-muted mt-0.5\">\n Default: <span className=\"font-mono\">{v.default}</span>\n </p>\n )}\n </div>\n {v.options.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {v.options.map((opt) => (\n <span\n key={opt}\n className=\"text-xs bg-bg-sunken text-text-secondary px-1.5 py-0.5 rounded\"\n >\n {opt}\n </span>\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n </Card>\n )}\n\n {/* Setup Instructions */}\n {template.setupInstructions && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.setupInstructions', 'Setup Instructions')}\n </h3>\n </div>\n <div className=\"p-4\">\n <div className=\"prose prose-sm max-w-none text-text-primary\">\n <pre className=\"bg-bg-sunken rounded-md p-4 text-xs sm:text-sm overflow-x-auto whitespace-pre-wrap font-mono text-text-primary\">\n {template.setupInstructions}\n </pre>\n </div>\n </div>\n </Card>\n )}\n\n {/* File Tree */}\n {template.fileTree && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <FolderTree className=\"size-5\" />\n {tr('template.fileTree', 'File Tree')}\n </h3>\n </div>\n <div className=\"p-4\">\n <pre className=\"bg-bg-sunken rounded-md p-4 text-xs sm:text-sm overflow-x-auto font-mono text-text-primary\">\n {typeof template.fileTree === 'string'\n ? template.fileTree\n : JSON.stringify(template.fileTree, null, 2)}\n </pre>\n </div>\n </Card>\n )}\n\n {showWizard && (\n <TemplateWizard\n templateName={template.name}\n variables={\n Array.isArray(template.variables) ? (template.variables as TemplateVariable[]) : []\n }\n sourceRepoUrl={\n template.sourceRepositoryUrl ||\n ((template.componentSnapshot as Record<string, unknown> | null)\n ?.repositoryUrl as string) ||\n template.sourceComponent?.repositoryUrl ||\n null\n }\n githubConnections={githubConnections}\n onClose={() => setShowWizard(false)}\n onSubmit={handleClone}\n />\n )}\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Component Quota Reached\"\n message=\"You've reached the maximum number of components on your current plan. Upgrade your plan or purchase an add-on to create more components.\"\n />\n\n <ConfirmDialog\n isOpen={showDeleteConfirm}\n onClose={() => setShowDeleteConfirm(false)}\n onConfirm={handleDeleteTemplate}\n title={tr('template.deleteTemplate', 'Delete Template')}\n message={tr(\n 'template.deleteConfirmMessage',\n `Are you sure you want to delete template \"${template.name}\"? Existing instantiated components are unaffected, but the template will no longer be available for cloning. This cannot be undone.`\n )}\n confirmLabel={tr('common.delete', 'Delete')}\n variant=\"danger\"\n isLoading={isDeleting}\n />\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TemplateDetailPage.js","names":[],"sources":["../../src/pages/TemplateDetailPage.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport {\n ArrowLeft,\n FileCode,\n Copy,\n Layers,\n Tag,\n FolderTree,\n Clock,\n RefreshCw,\n Trash2,\n Variable,\n Github,\n CheckCircle2,\n XCircle,\n Loader2,\n} from 'lucide-react';\nimport {\n PageHeader,\n Card,\n EmptyState,\n ErrorState,\n ConfirmDialog,\n QuotaExhaustedDialog,\n} from '@/components/shared';\nimport { isQuotaExhaustedError } from '@/utils/quotaUtils';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { TemplateWizard } from '@/components/templates';\nimport type { TemplateVariable, GitHubConfig, GitHubConnection } from '@/components/templates';\nimport { EntityShareButton } from '@/components/sharing';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useGetTemplateQuery,\n useInstantiateTemplateMutation,\n useDeleteTemplateMutation,\n useUpdateComponentMutation,\n useForkGitHubRepoMutation,\n useListActiveConnectionsQuery,\n} from '@/generated/wspace-operations';\n\nfunction substituteVars(text: string, vars: Record<string, unknown>): string {\n return text.replace(/\\{\\{(\\w+)\\}\\}|\\{(\\w+)\\}/g, (_match, a, b) => {\n const key = a ?? b;\n return key in vars ? String(vars[key]) : _match;\n });\n}\n\nfunction parseGitHubRepo(url: string): { owner: string; repo: string } | null {\n try {\n const match = url.match(/^https?:\\/\\/github\\.com\\/([^/]+)\\/([^/]+?)(?:\\.git)?(?:\\/.*)?$/);\n if (!match) return null;\n return { owner: match[1], repo: match[2] };\n } catch {\n return null;\n }\n}\n\nasync function scaffoldGitHubRepo(\n fullName: string,\n headers: Record<string, string>,\n data: {\n name: string;\n description: string;\n variableValues: Record<string, unknown>;\n },\n template: {\n name: string;\n description?: string | null;\n setupInstructions?: string | null;\n fileTree?: unknown;\n variables?: unknown;\n } | null\n) {\n if (!template) return;\n\n const vars = data.variableValues;\n const templateVars = Array.isArray(template.variables)\n ? (template.variables as Array<{ name: string; title?: string }>)\n : [];\n\n // Build README content\n const lines: string[] = [];\n lines.push(`# ${data.name}`);\n lines.push('');\n if (data.description) {\n lines.push(data.description);\n lines.push('');\n }\n lines.push(`> Scaffolded from VibeControls template: **${template.name}**`);\n lines.push('');\n\n // Variable values table\n if (templateVars.length > 0 && Object.keys(vars).length > 0) {\n lines.push('## Configuration');\n lines.push('');\n lines.push('| Variable | Value |');\n lines.push('|----------|-------|');\n for (const v of templateVars) {\n const val = vars[v.name];\n if (val !== undefined) {\n lines.push(`| ${v.title ?? v.name} | \\`${String(val)}\\` |`);\n }\n }\n lines.push('');\n }\n\n // Setup instructions (with variable substitution)\n if (template.setupInstructions) {\n lines.push('## Getting Started');\n lines.push('');\n lines.push(substituteVars(template.setupInstructions, vars));\n lines.push('');\n }\n\n // File tree\n if (template.fileTree) {\n lines.push('## Project Structure');\n lines.push('');\n lines.push('```');\n lines.push(\n typeof template.fileTree === 'string'\n ? template.fileTree\n : JSON.stringify(template.fileTree, null, 2)\n );\n lines.push('```');\n lines.push('');\n }\n\n const readmeContent = lines.join('\\n');\n\n // Get existing README.md SHA so we can update it\n const existing = await fetch(`https://api.github.com/repos/${fullName}/contents/README.md`, {\n headers,\n });\n let sha: string | undefined;\n if (existing.ok) {\n const existingData = (await existing.json()) as { sha?: string };\n sha = existingData.sha;\n }\n\n // Push scaffolded README.md\n await fetch(`https://api.github.com/repos/${fullName}/contents/README.md`, {\n method: 'PUT',\n headers,\n body: JSON.stringify({\n message: `chore: scaffold from VibeControls template \"${template.name}\"`,\n content: btoa(unescape(encodeURIComponent(readmeContent))),\n ...(sha ? { sha } : {}),\n }),\n });\n\n // Push GETTING_STARTED.md with setup instructions + resolved variable values\n if (template.setupInstructions || (templateVars.length > 0 && Object.keys(vars).length > 0)) {\n const gsLines: string[] = ['# Getting Started', ''];\n\n if (template.setupInstructions) {\n gsLines.push(substituteVars(template.setupInstructions, vars));\n gsLines.push('');\n }\n\n // Always append a resolved variables section so values are never lost\n if (templateVars.length > 0 && Object.keys(vars).length > 0) {\n gsLines.push('---');\n gsLines.push('');\n gsLines.push('## Template Variable Values');\n gsLines.push('');\n gsLines.push('These are the values you chose when creating this project:');\n gsLines.push('');\n for (const v of templateVars) {\n const val = vars[v.name];\n if (val !== undefined && val !== '') {\n gsLines.push(`**${v.title ?? v.name}**`);\n gsLines.push('');\n gsLines.push('```');\n gsLines.push(String(val));\n gsLines.push('```');\n gsLines.push('');\n }\n }\n }\n\n await fetch(`https://api.github.com/repos/${fullName}/contents/GETTING_STARTED.md`, {\n method: 'PUT',\n headers,\n body: JSON.stringify({\n message: 'docs: add getting started guide from template',\n content: btoa(unescape(encodeURIComponent(gsLines.join('\\n')))),\n }),\n });\n }\n}\n\nconst categoryStyles: Record<string, string> = {\n STARTER: 'bg-bg-sunken text-text-secondary',\n MICROSERVICE: 'bg-action-primary-bg/10 text-action-primary-bg',\n FRONTEND: 'bg-status-info-bg text-status-info-text',\n BACKEND: 'bg-action-primary-bg/10 text-action-primary-bg',\n FULLSTACK: 'bg-status-success-bg text-status-success-text',\n INFRASTRUCTURE: 'bg-status-warning-bg text-status-warning-text',\n LIBRARY: 'bg-status-warning-bg text-status-warning-text',\n CUSTOM: 'bg-bg-sunken text-text-secondary',\n};\n\nexport function TemplateDetailPage() {\n const { t } = useI18n();\n const { id } = useParams<{ id: string }>();\n const navigate = useVibeNavigate();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const [showWizard, setShowWizard] = useState(false);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [cloneError, setCloneError] = useState<string | null>(null);\n const [forkNotice, setForkNotice] = useState<string | null>(null);\n const [repoProgress, setRepoProgress] = useState<{\n stage: string;\n done: boolean;\n error: boolean;\n } | null>(null);\n\n const { data, loading, error, refetch } = useGetTemplateQuery({\n variables: { id: id || '' },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\n const [instantiateTemplate] = useInstantiateTemplateMutation({\n refetchQueries: ['ListComponents'],\n });\n const [deleteTemplate] = useDeleteTemplateMutation({ refetchQueries: ['ListTemplates'] });\n const [updateComponent] = useUpdateComponentMutation();\n const [forkGitHubRepo] = useForkGitHubRepoMutation();\n\n // Fetch active GitHub connections for the workspace\n const { data: connectionsData } = useListActiveConnectionsQuery({\n variables: { filter: { status: 'ACTIVE' as const }, pagination: { limit: 50, offset: 0 } },\n fetchPolicy: 'cache-first',\n });\n const githubConnections: GitHubConnection[] = (connectionsData?.getConnections?.items ?? [])\n .filter((c: { provider?: { key?: string } | null }) => c.provider?.key === 'github')\n .map(\n (c: {\n id: string;\n name: string;\n externalAccountEmail?: string | null;\n externalAccountName?: string | null;\n provider: { key: string; name: string };\n }) => ({\n id: c.id,\n name: c.name,\n externalAccountEmail: c.externalAccountEmail,\n externalAccountName: c.externalAccountName,\n provider: { key: c.provider.key, name: c.provider.name },\n })\n );\n\n const template = data?.vibecontrolsTemplate ?? null;\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (!hasPermission(VIBE_PERMISSIONS.VIBE_READ))\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n const handleBack = () => {\n navigate('/templates');\n };\n\n const handleClone = async (data: {\n name: string;\n description: string;\n variableValues: Record<string, unknown>;\n githubConfig: GitHubConfig | null;\n }) => {\n setShowWizard(false);\n setRepoProgress({ stage: 'Creating component…', done: false, error: false });\n\n const result = await instantiateTemplate({\n variables: {\n templateId: id,\n input: {\n name: data.name,\n description: data.description || undefined,\n ...(Object.keys(data.variableValues).length > 0 && {\n variableValues: data.variableValues,\n }),\n },\n },\n });\n if (result.error && isQuotaExhaustedError(result.error)) {\n setRepoProgress(null);\n setShowQuotaExhausted(true);\n return;\n }\n const newId = result.data?.instantiateVibecontrolsTemplate?.id;\n\n // GitHub repo creation + scaffolding\n if (newId && data.githubConfig?.enabled) {\n // Ensure repo URL starts empty before GitHub runs\n await updateComponent({ variables: { id: newId, input: { repositoryUrl: null } } });\n const gh = data.githubConfig;\n\n // Priority: explicit sourceRepositoryUrl > snapshot URL > sourceComponent.repositoryUrl\n const snapshotRepoUrl = (template?.componentSnapshot as Record<string, unknown> | null)\n ?.repositoryUrl as string | undefined;\n const sourceRepoUrl =\n template?.sourceRepositoryUrl ||\n snapshotRepoUrl ||\n template?.sourceComponent?.repositoryUrl ||\n undefined;\n\n try {\n if (gh.connectionId) {\n // ── OAuth path: backend resolves the token server-side ──────────────\n setRepoProgress({\n stage: sourceRepoUrl\n ? 'Forking repository via connected account…'\n : 'Creating GitHub repository via connected account…',\n done: false,\n error: false,\n });\n\n const forkResult = await forkGitHubRepo({\n variables: {\n input: {\n connectionId: gh.connectionId,\n sourceRepoUrl: sourceRepoUrl || undefined,\n repoName: gh.repoName,\n visibility: gh.visibility === 'private' ? 'PRIVATE' : 'PUBLIC',\n scope: gh.scope === 'org' ? 'ORG' : 'USER',\n orgName: gh.orgName || undefined,\n description:\n data.description || `Created from VibeControls template: ${template?.name}`,\n },\n },\n });\n\n const forkData = forkResult.data?.forkVibecontrolsGitHubRepo;\n if (forkData) {\n setRepoProgress({\n stage: forkData.isForked ? 'Repository forked!' : 'Repository created!',\n done: true,\n error: false,\n });\n await updateComponent({\n variables: { id: newId, input: { repositoryUrl: forkData.repoUrl } },\n });\n await new Promise((r) => setTimeout(r, 1200));\n } else {\n setRepoProgress({\n stage: 'GitHub repo creation failed — check your connected account',\n done: false,\n error: true,\n });\n setTimeout(() => setRepoProgress(null), 6000);\n }\n } else {\n // ── PAT path: existing client-side GitHub API flow ──────────────────\n const ghHeaders = {\n Authorization: `Bearer ${gh.token}`,\n 'Content-Type': 'application/json',\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n };\n const apiBase = 'https://api.github.com';\n\n const sourceRepo = sourceRepoUrl ? parseGitHubRepo(sourceRepoUrl) : null;\n let repoData: { html_url: string; full_name: string } | null = null;\n let isForked = false;\n\n if (sourceRepo) {\n setRepoProgress({\n stage: `Forking ${sourceRepo.owner}/${sourceRepo.repo}…`,\n done: false,\n error: false,\n });\n const forkRes = await fetch(\n `${apiBase}/repos/${encodeURIComponent(sourceRepo.owner)}/${encodeURIComponent(sourceRepo.repo)}/forks`,\n {\n method: 'POST',\n headers: ghHeaders,\n body: JSON.stringify({\n name: gh.repoName,\n ...(gh.scope === 'org' ? { organization: gh.orgName } : {}),\n default_branch_only: false,\n }),\n }\n );\n\n if (forkRes.ok) {\n repoData = (await forkRes.json()) as { html_url: string; full_name: string };\n isForked = true;\n } else {\n const forkErr = (await forkRes.json()) as { message?: string };\n setRepoProgress(null);\n setForkNotice(\n `Could not fork ${sourceRepoUrl} (${forkRes.status}: ${forkErr.message ?? forkRes.statusText}) — creating a new empty repository instead.`\n );\n setTimeout(() => setForkNotice(null), 10000);\n }\n }\n\n if (!repoData) {\n setRepoProgress({ stage: 'Creating GitHub repository…', done: false, error: false });\n const createEndpoint =\n gh.scope === 'org'\n ? `${apiBase}/orgs/${encodeURIComponent(gh.orgName)}/repos`\n : `${apiBase}/user/repos`;\n\n const repoRes = await fetch(createEndpoint, {\n method: 'POST',\n headers: ghHeaders,\n body: JSON.stringify({\n name: gh.repoName,\n private: gh.visibility === 'private',\n auto_init: true,\n description:\n data.description || `Created from VibeControls template: ${template?.name}`,\n }),\n });\n\n if (repoRes.ok) {\n repoData = (await repoRes.json()) as { html_url: string; full_name: string };\n } else {\n const errBody = (await repoRes.json()) as { message?: string };\n setRepoProgress({\n stage: `GitHub repo failed: ${errBody.message ?? repoRes.statusText}`,\n done: false,\n error: true,\n });\n setTimeout(() => setRepoProgress(null), 6000);\n }\n }\n\n if (repoData) {\n if (!isForked) {\n setRepoProgress({ stage: 'Scaffolding README…', done: false, error: false });\n await scaffoldGitHubRepo(repoData.full_name, ghHeaders, data, template);\n }\n\n setRepoProgress({\n stage: isForked ? 'Repository forked!' : 'Repository created!',\n done: true,\n error: false,\n });\n await updateComponent({\n variables: { id: newId, input: { repositoryUrl: repoData.html_url } },\n });\n await new Promise((r) => setTimeout(r, 1200));\n setRepoProgress(null);\n } else {\n await new Promise((r) => setTimeout(r, 3000));\n setRepoProgress(null);\n }\n }\n } catch {\n setRepoProgress({\n stage: 'GitHub repo creation failed — check your credentials',\n done: false,\n error: true,\n });\n setTimeout(() => setRepoProgress(null), 6000);\n }\n }\n\n setRepoProgress(null);\n if (newId) {\n navigate(`/components/${newId}`);\n } else {\n setSuccessMessage(tr('template.clonedSuccess', 'Component created — check Components list'));\n setTimeout(() => setSuccessMessage(null), 4000);\n }\n };\n\n const handleDeleteTemplate = async () => {\n if (!id) return;\n setIsDeleting(true);\n try {\n await deleteTemplate({ variables: { id } });\n setShowDeleteConfirm(false);\n navigate('/templates');\n } finally {\n setIsDeleting(false);\n }\n };\n\n // Guard states\n if (loading && !template) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (error && !template) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n <ErrorState\n title={tr('template.failedLoad', 'Failed to load template')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n if (!template) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n <EmptyState\n icon={<FileCode className=\"size-8 text-text-secondary\" />}\n title={tr('template.notFound', 'Template not found')}\n description={`No template with ID \"${id}\" exists`}\n action={\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-success-bg text-status-success-text px-4 py-3 rounded-md shadow-lg\">\n {successMessage}\n </div>\n )}\n {forkNotice && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-warning-bg text-status-warning-text px-4 py-3 rounded-md shadow-lg text-sm max-w-sm\">\n {forkNotice}\n </div>\n )}\n {/* Error Toast */}\n {cloneError && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-error-bg text-status-error-text px-4 py-3 rounded-md shadow-lg\">\n {cloneError}\n </div>\n )}\n {/* Repo creation progress overlay */}\n {repoProgress && (\n <div\n className=\"fixed inset-0 z-[9999] flex items-center justify-center p-4\"\n style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}\n >\n <div className=\"bg-bg-surface border border-border-default rounded-xl shadow-2xl p-8 flex flex-col items-center gap-4 max-w-xs w-full\">\n {repoProgress.done ? (\n <CheckCircle2 className=\"size-10 text-status-success-text\" />\n ) : repoProgress.error ? (\n <XCircle className=\"size-10 text-status-error-text\" />\n ) : (\n <Loader2 className=\"size-10 text-action-primary-bg animate-spin\" />\n )}\n <p className=\"text-sm font-medium text-text-primary text-center\">\n {repoProgress.stage}\n </p>\n </div>\n </div>\n )}\n\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('template.backToTemplates', 'Back to Templates')}\n </button>\n\n {/* Header */}\n <PageHeader\n title={template.name}\n description={template.description || tr('template.noDescription', 'No description')}\n actions={\n <div className=\"flex items-center gap-2 flex-wrap\">\n <EntityShareButton\n entity=\"template\"\n resource={{ id: template.id, name: template.name }}\n label={tr('template.share', 'Share')}\n variant=\"button\"\n />\n <button\n type=\"button\"\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken/80 transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowWizard(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Copy className=\"size-4\" />\n {tr('template.useTemplate', 'Use Template')}\n </button>\n <button\n type=\"button\"\n data-testid=\"template-delete-button\"\n onClick={() => setShowDeleteConfirm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-status-error-bg text-status-error-text rounded-md hover:opacity-90 transition-opacity\"\n aria-label={tr('template.deleteTemplate', 'Delete Template')}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {tr('common.delete', 'Delete')}\n </button>\n </div>\n }\n />\n\n {/* Context hint for new users */}\n <p className=\"text-sm text-text-muted\">\n Click <span className=\"font-medium text-text-secondary\">Use Template</span> to open a short\n wizard — give your new component a name, fill in any variables, and optionally create a\n GitHub repository. The whole thing takes under a minute.\n </p>\n\n {/* Badges */}\n <div className=\"flex items-center gap-3 flex-wrap\">\n {template.category && (\n <span\n className={`inline-flex items-center gap-1.5 px-2.5 py-1 text-sm font-medium rounded ${categoryStyles[template.category] || 'bg-bg-sunken text-text-secondary'}`}\n >\n <Layers className=\"size-3.5\" />\n {template.category}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <Copy className=\"size-3.5\" />\n {template.cloneCount} {tr('template.clones', 'clones')}\n </span>\n {template.sourceRepositoryUrl && (\n <a\n href={template.sourceRepositoryUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n className=\"inline-flex items-center gap-1.5 text-sm text-action-primary-bg hover:underline\"\n >\n <Github className=\"size-3.5\" />\n {template.sourceRepositoryUrl.replace('https://github.com/', '')}\n </a>\n )}\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <Clock className=\"size-3.5\" />\n {new Date(template.createdAt).toLocaleDateString()}\n </span>\n </div>\n\n {/* Tags */}\n {template.tags?.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.tags.map((tag: string) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2.5 py-1 text-sm bg-bg-sunken text-text-secondary rounded-md\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n </div>\n )}\n\n {/* Universal tags */}\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Tag className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">{tr('template.tags', 'Tags')}</h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_TEMPLATE\" entityId={template.id} />\n </div>\n </Card>\n\n {/* Source Component */}\n {template.sourceComponent && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.sourceComponent', 'Source Component')}\n </h3>\n </div>\n <div className=\"p-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`/components/${template.sourceComponent.id}`)}\n className=\"flex items-center gap-3 text-left hover:bg-bg-sunken p-2 -m-2 rounded-md transition-colors\"\n >\n <div className=\"size-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center flex-shrink-0\">\n <FileCode className=\"size-5 text-action-primary-bg\" />\n </div>\n <div>\n <p className=\"font-medium text-text-primary\">{template.sourceComponent.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {template.sourceComponent.type} · {template.sourceComponent.lifecycle}\n </p>\n </div>\n </button>\n </div>\n </Card>\n )}\n\n {/* Cloned Components */}\n {template.clonedComponents && template.clonedComponents.length > 0 && (\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Copy className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.createdComponents', 'Created Components')}\n </h3>\n <span className=\"ml-auto text-xs text-text-muted\">\n {template.clonedComponents.length} component\n {template.clonedComponents.length !== 1 ? 's' : ''}\n </span>\n </div>\n <div className=\"divide-y divide-border-default\">\n {template.clonedComponents.map(\n (comp: {\n id: string;\n name: string;\n description?: string | null;\n type: string;\n lifecycle: string;\n repositoryUrl?: string | null;\n createdAt: string;\n }) => (\n <button\n type=\"button\"\n key={comp.id}\n onClick={() => navigate(`/components/${comp.id}`)}\n className=\"flex items-center gap-3 w-full text-left px-4 py-3 hover:bg-bg-sunken transition-colors\"\n >\n <div className=\"size-8 rounded-md bg-action-primary-bg/10 flex items-center justify-center flex-shrink-0\">\n <FileCode className=\"size-4 text-action-primary-bg\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{comp.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {comp.type} · {comp.lifecycle}\n {comp.repositoryUrl && (\n <>\n {' '}\n ·{' '}\n <span className=\"font-mono\">\n {comp.repositoryUrl.replace('https://github.com/', '')}\n </span>\n </>\n )}\n </p>\n </div>\n <span className=\"text-xs text-text-muted flex-shrink-0\">\n {new Date(comp.createdAt).toLocaleDateString()}\n </span>\n </button>\n )\n )}\n </div>\n </Card>\n )}\n\n {/* Variables preview */}\n {Array.isArray(template.variables) &&\n (template.variables as TemplateVariable[]).length > 0 && (\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Variable className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.variables', 'Template Variables')}\n </h3>\n <span className=\"ml-auto text-xs text-text-muted\">\n {(template.variables as TemplateVariable[]).length} variable\n {(template.variables as TemplateVariable[]).length !== 1 ? 's' : ''}\n </span>\n </div>\n <div className=\"divide-y divide-border-default\">\n {(template.variables as TemplateVariable[]).map((v) => (\n <div key={v.name} className=\"px-4 py-3 flex items-start gap-4\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary font-mono\">\n {v.name}\n </span>\n {v.required && (\n <span className=\"text-xs bg-status-error-bg text-status-error-text px-1.5 py-0.5 rounded\">\n required\n </span>\n )}\n <span className=\"text-xs bg-bg-sunken text-text-muted px-1.5 py-0.5 rounded\">\n {v.type}\n </span>\n </div>\n {v.title && v.title !== v.name && (\n <p className=\"text-xs text-text-secondary mt-0.5\">{v.title}</p>\n )}\n {v.default && (\n <p className=\"text-xs text-text-muted mt-0.5\">\n Default: <span className=\"font-mono\">{v.default}</span>\n </p>\n )}\n </div>\n {v.options.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {v.options.map((opt) => (\n <span\n key={opt}\n className=\"text-xs bg-bg-sunken text-text-secondary px-1.5 py-0.5 rounded\"\n >\n {opt}\n </span>\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n </Card>\n )}\n\n {/* Setup Instructions */}\n {template.setupInstructions && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('template.setupInstructions', 'Setup Instructions')}\n </h3>\n </div>\n <div className=\"p-4\">\n <div className=\"prose prose-sm max-w-none text-text-primary\">\n <pre className=\"bg-bg-sunken rounded-md p-4 text-xs sm:text-sm overflow-x-auto whitespace-pre-wrap font-mono text-text-primary\">\n {template.setupInstructions}\n </pre>\n </div>\n </div>\n </Card>\n )}\n\n {/* File Tree */}\n {template.fileTree && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <FolderTree className=\"size-5\" />\n {tr('template.fileTree', 'File Tree')}\n </h3>\n </div>\n <div className=\"p-4\">\n <pre className=\"bg-bg-sunken rounded-md p-4 text-xs sm:text-sm overflow-x-auto font-mono text-text-primary\">\n {typeof template.fileTree === 'string'\n ? template.fileTree\n : JSON.stringify(template.fileTree, null, 2)}\n </pre>\n </div>\n </Card>\n )}\n\n {showWizard && (\n <TemplateWizard\n templateName={template.name}\n variables={\n Array.isArray(template.variables) ? (template.variables as TemplateVariable[]) : []\n }\n sourceRepoUrl={\n template.sourceRepositoryUrl ||\n ((template.componentSnapshot as Record<string, unknown> | null)\n ?.repositoryUrl as string) ||\n template.sourceComponent?.repositoryUrl ||\n null\n }\n githubConnections={githubConnections}\n onClose={() => setShowWizard(false)}\n onSubmit={handleClone}\n />\n )}\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Component Quota Reached\"\n message=\"You've reached the maximum number of components on your current plan. Upgrade your plan or purchase an add-on to create more components.\"\n />\n\n <ConfirmDialog\n isOpen={showDeleteConfirm}\n onClose={() => setShowDeleteConfirm(false)}\n onConfirm={handleDeleteTemplate}\n title={tr('template.deleteTemplate', 'Delete Template')}\n message={tr(\n 'template.deleteConfirmMessage',\n `Are you sure you want to delete template \"${template.name}\"? Existing instantiated components are unaffected, but the template will no longer be available for cloning. This cannot be undone.`\n )}\n confirmLabel={tr('common.delete', 'Delete')}\n variant=\"danger\"\n isLoading={isDeleting}\n />\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
|
@@ -17,8 +17,8 @@ import { SelectionCheckbox as Ce } from "../components/shared/SelectionCheckbox.
|
|
|
17
17
|
import { useActiveAgentProfile as we } from "../hooks/useActiveAgentProfile.js";
|
|
18
18
|
import "../components/shared/index.js";
|
|
19
19
|
import { isNative as Te, nativeNotify as Ee } from "../utils/nativeBridge.js";
|
|
20
|
-
import { enableRemoteTaskExecution as De, isRemoteTaskDeniedError as Oe } from "../services/agentRemoteTaskGates.js";
|
|
21
20
|
import { VIBE_PERMISSIONS as c } from "../constants/permissions.js";
|
|
21
|
+
import { enableRemoteTaskExecution as De, isRemoteTaskDeniedError as Oe } from "../services/agentRemoteTaskGates.js";
|
|
22
22
|
import { VibeDeckGrid as ke } from "../components/vibedeck/VibeDeckGrid.js";
|
|
23
23
|
import { VibeDeckSwitcher as Ae } from "../components/vibedeck/VibeDeckSwitcher.js";
|
|
24
24
|
import { VibeDeckForm as je } from "../components/vibedeck/VibeDeckForm.js";
|