@burdenoff/microfe-vibecontrols 2026.601.2 → 2026.601.4
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/agent-manager/dialogs/NewSessionDialog.js +16 -15
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
- package/dist/components/agents/AgentMaintenanceTab.js +373 -0
- package/dist/components/agents/AgentMaintenanceTab.js.map +1 -0
- package/dist/components/docs/DocsTabPanel.js +7 -4
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/shared/ConfirmDialog.js +34 -27
- package/dist/components/shared/ConfirmDialog.js.map +1 -1
- package/dist/generated/wspace-operations.js +1778 -1565
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/index.js +10 -10
- package/dist/pages/AgentDetailsPage.js +1038 -932
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/VibesPage.js +3 -3
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/ai/AgentManagerPage.js +138 -127
- package/dist/pages/ai/AgentManagerPage.js.map +1 -1
- package/dist/providers/VibeControlsProvider.js +43 -35
- package/dist/providers/VibeControlsProvider.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentMaintenanceTab.js","names":[],"sources":["../../../src/components/agents/AgentMaintenanceTab.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport { ArrowUpCircle, Loader2, RefreshCw, Terminal, Trash2, AlertTriangle } from 'lucide-react';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\n\nimport {\n useAgentUpdateStatusQuery,\n useAgentUpdateCheckLazyQuery,\n useAgentSelfUpdateMutation,\n useSetAgentAutoUpdateMutation,\n useAgentCommandsQuery,\n useRunAgentCommandMutation,\n useNukeVibecontrolsAgentMutation,\n} from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { ConfirmDialog } from '../shared/ConfirmDialog';\n\ntype Json = Record<string, unknown> | null | undefined;\n\nfunction asRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null;\n}\nfunction jstr(obj: Json, key: string): string | null {\n const v = obj?.[key];\n return typeof v === 'string' ? v : null;\n}\nfunction jbool(obj: Json, key: string): boolean | null {\n const v = obj?.[key];\n return typeof v === 'boolean' ? v : null;\n}\n\ninterface CommandInfo {\n name: string;\n description: string;\n destructive?: boolean;\n options?: Array<{ flags: string; description: string }>;\n}\n\ninterface AgentMaintenanceTabProps {\n agentId: string;\n agentVersion?: string | null;\n onAfterDestructiveNuke?: () => void | Promise<void>;\n}\n\nconst SECTION = 'rounded-lg border border-border-default bg-bg-surface p-4 sm:p-5';\nconst BTN_PRIMARY =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50';\nconst BTN_NEUTRAL =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-bg-sunken text-text-primary hover:bg-bg-elevated transition-colors disabled:opacity-50';\nconst BTN_DANGER =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-status-error-bg text-text-inverse hover:opacity-80 transition-colors disabled:opacity-50';\n\nexport function AgentMaintenanceTab({\n agentId,\n agentVersion,\n onAfterDestructiveNuke,\n}: AgentMaintenanceTabProps) {\n const tr = useTr();\n\n // ── Output + toast plumbing (component-local) ───────────────────────────\n const [output, setOutput] = useState<{ title: string; body: string; error?: boolean } | null>(\n null\n );\n const showOutput = useCallback((title: string, body: string, error = false) => {\n setOutput({ title, body, error });\n }, []);\n\n // ── Update / autoupdate ─────────────────────────────────────────────────\n const { data: statusData, refetch: refetchStatus } = useAgentUpdateStatusQuery({\n variables: { agentId },\n fetchPolicy: 'cache-and-network',\n });\n const [checkUpdate, { data: checkData, loading: checking }] = useAgentUpdateCheckLazyQuery({\n fetchPolicy: 'network-only',\n });\n const [selfUpdate, { loading: updating }] = useAgentSelfUpdateMutation();\n const [setAutoUpdate, { loading: togglingAuto }] = useSetAgentAutoUpdateMutation();\n\n const status = asRecord(statusData?.agentUpdateStatus?.data);\n const lastCheck = asRecord(status?.lastCheck);\n const checkResult = asRecord(checkData?.agentUpdateCheck?.data);\n const autoUpdateEnabled = jbool(status, 'enabled') ?? true;\n const latestVersion = jstr(checkResult, 'latest') ?? jstr(lastCheck, 'latest') ?? null;\n const hasUpdate = jbool(checkResult, 'hasUpdate') ?? jbool(lastCheck, 'hasUpdate') ?? false;\n\n const [versionInput, setVersionInput] = useState('');\n\n const handleCheck = useCallback(async () => {\n setOutput(null);\n try {\n const res = await checkUpdate({ variables: { agentId } });\n const d = asRecord(res.data?.agentUpdateCheck?.data);\n if (res.data?.agentUpdateCheck?.error) {\n showOutput(\n tr('agentDetails.maintenance.update', 'Update'),\n res.data.agentUpdateCheck.error,\n true\n );\n } else if (jbool(d, 'hasUpdate')) {\n showOutput(\n tr('agentDetails.maintenance.update', 'Update'),\n `Update available: ${jstr(d, 'current')} → ${jstr(d, 'latest')}`\n );\n } else {\n showOutput(\n tr('agentDetails.maintenance.update', 'Update'),\n `Up to date (${jstr(d, 'current') ?? agentVersion ?? '?'}).`\n );\n }\n } catch (err) {\n showOutput('Update', err instanceof Error ? err.message : String(err), true);\n }\n }, [agentId, checkUpdate, showOutput, tr, agentVersion]);\n\n const runSelfUpdate = useCallback(\n async (version?: string) => {\n setOutput(null);\n try {\n const res = await selfUpdate({ variables: { agentId, version: version || null } });\n const proxy = res.data?.agentSelfUpdate;\n const d = asRecord(proxy?.data);\n if (proxy?.error || jbool(d, 'ok') === false) {\n showOutput(\n 'Update',\n (jstr(d, 'error') ?? proxy?.error ?? 'Update failed') as string,\n true\n );\n } else {\n showOutput(\n 'Update',\n `Updated → ${jstr(d, 'current') ?? version ?? 'latest'} (restart: ${jstr(d, 'restart') ?? 'n/a'}).`\n );\n }\n await refetchStatus();\n } catch (err) {\n showOutput('Update', err instanceof Error ? err.message : String(err), true);\n }\n },\n [agentId, selfUpdate, showOutput, refetchStatus]\n );\n\n const toggleAutoUpdate = useCallback(\n async (enabled: boolean) => {\n try {\n await setAutoUpdate({ variables: { agentId, enabled } });\n await refetchStatus();\n } catch (err) {\n showOutput('Autoupdate', err instanceof Error ? err.message : String(err), true);\n }\n },\n [agentId, setAutoUpdate, refetchStatus, showOutput]\n );\n\n // ── Command runner ──────────────────────────────────────────────────────\n const {\n data: cmdData,\n loading: cmdsLoading,\n refetch: refetchCmds,\n } = useAgentCommandsQuery({\n variables: { agentId },\n fetchPolicy: 'cache-and-network',\n });\n const [runCommand, { loading: running }] = useRunAgentCommandMutation();\n\n const commands = useMemo<CommandInfo[]>(() => {\n const raw = asRecord(cmdData?.agentCommands?.data)?.commands;\n return Array.isArray(raw) ? (raw as CommandInfo[]) : [];\n }, [cmdData]);\n\n const [selectedCommand, setSelectedCommand] = useState('');\n const [argsInput, setArgsInput] = useState('');\n const [pendingCommand, setPendingCommand] = useState<string[] | null>(null);\n\n const selectedMeta = commands.find((c) => c.name === selectedCommand);\n\n const buildArgv = useCallback((): string[] => {\n const extra = argsInput.trim().length > 0 ? argsInput.trim().split(/\\s+/) : [];\n return [selectedCommand, ...extra];\n }, [selectedCommand, argsInput]);\n\n const executeCommand = useCallback(\n async (argv: string[]) => {\n setOutput(null);\n try {\n const res = await runCommand({ variables: { agentId, argv } });\n const proxy = res.data?.runAgentCommand;\n const d = asRecord(proxy?.data);\n const stdout = jstr(d, 'stdout') ?? '';\n const stderr = jstr(d, 'stderr') ?? '';\n const exit = d?.exitCode;\n const body =\n (stdout ? stdout : '') +\n (stderr ? `\\n[stderr]\\n${stderr}` : '') +\n `\\n[exit ${exit ?? '?'}]`;\n showOutput(\n `vibe ${argv.join(' ')}`,\n body.trim() || proxy?.error || '(no output)',\n !jbool(d, 'ok')\n );\n } catch (err) {\n showOutput('Command', err instanceof Error ? err.message : String(err), true);\n }\n },\n [agentId, runCommand, showOutput]\n );\n\n const handleRunClick = useCallback(() => {\n if (!selectedCommand) return;\n const argv = buildArgv();\n if (selectedMeta?.destructive) {\n setPendingCommand(argv);\n } else {\n void executeCommand(argv);\n }\n }, [selectedCommand, buildArgv, selectedMeta, executeCommand]);\n\n // ── Nuke ────────────────────────────────────────────────────────────────\n const [nuke, { loading: nuking }] = useNukeVibecontrolsAgentMutation();\n const [nukeDryRun, setNukeDryRun] = useState(true);\n const [pendingNuke, setPendingNuke] = useState<{ all: boolean; removeConfig: boolean } | null>(\n null\n );\n\n const runNuke = useCallback(\n async (opts: { all: boolean; removeConfig: boolean }) => {\n setOutput(null);\n try {\n const res = await nuke({\n variables: {\n agentId,\n all: opts.all,\n removeConfig: opts.removeConfig,\n dryRun: nukeDryRun,\n },\n });\n const proxy = res.data?.nukeVibecontrolsAgent;\n const d = asRecord(proxy?.data);\n const stdout = jstr(d, 'stdout') ?? '';\n const stderr = jstr(d, 'stderr') ?? '';\n const ok = jbool(d, 'ok') === true && !proxy?.error;\n showOutput(\n `vibe nuke${opts.all ? ' --all' : ''}${nukeDryRun ? ' --dry-run' : ''}`,\n (stdout + (stderr ? `\\n[stderr]\\n${stderr}` : '')).trim() ||\n proxy?.error ||\n '(no output)',\n !ok && !!proxy?.error\n );\n if (ok && !nukeDryRun) {\n await onAfterDestructiveNuke?.();\n }\n } catch (err) {\n showOutput('Nuke', err instanceof Error ? err.message : String(err), true);\n }\n },\n [agentId, nuke, nukeDryRun, onAfterDestructiveNuke, showOutput]\n );\n\n return (\n <div className=\"space-y-5\">\n {/* ── Agent update ────────────────────────────────────────────── */}\n <section className={SECTION}>\n <div className=\"flex items-center gap-2 mb-3\">\n <ArrowUpCircle className=\"size-5 text-text-secondary\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.maintenance.updateTitle', 'Agent version & updates')}\n </h3>\n </div>\n <div className=\"grid grid-cols-2 gap-3 text-sm mb-4\">\n <div>\n <div className=\"text-text-muted\">\n {tr('agentDetails.maintenance.current', 'Current')}\n </div>\n <div className=\"font-mono text-text-primary\">{agentVersion ?? '—'}</div>\n </div>\n <div>\n <div className=\"text-text-muted\">{tr('agentDetails.maintenance.latest', 'Latest')}</div>\n <div className=\"font-mono text-text-primary\">\n {latestVersion ?? '—'}\n {hasUpdate ? (\n <span className=\"ml-2 text-xs text-status-warning-text\">\n {tr('agentDetails.maintenance.updateAvailable', 'update available')}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 mb-4\">\n <button type=\"button\" onClick={handleCheck} disabled={checking} className={BTN_NEUTRAL}>\n {checking ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <RefreshCw className=\"size-4\" />\n )}\n {tr('agentDetails.maintenance.check', 'Check for updates')}\n </button>\n <button\n type=\"button\"\n onClick={() => runSelfUpdate()}\n disabled={updating}\n className={BTN_PRIMARY}\n >\n {updating ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <ArrowUpCircle className=\"size-4\" />\n )}\n {tr('agentDetails.maintenance.updateLatest', 'Update to latest')}\n </button>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 mb-4\">\n <input\n type=\"text\"\n value={versionInput}\n onChange={(e) => setVersionInput(e.target.value)}\n placeholder={tr('agentDetails.maintenance.versionPlaceholder', 'e.g. 2026.601.21')}\n className=\"px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 font-mono w-44\"\n />\n <button\n type=\"button\"\n onClick={() => runSelfUpdate(versionInput.trim())}\n disabled={updating || versionInput.trim().length === 0}\n className={BTN_NEUTRAL}\n >\n {tr('agentDetails.maintenance.updateVersion', 'Update to version')}\n </button>\n </div>\n\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <Checkbox\n checked={autoUpdateEnabled}\n disabled={togglingAuto}\n onCheckedChange={(c) => toggleAutoUpdate(c === true)}\n />\n <span className=\"text-sm text-text-primary\">\n {tr(\n 'agentDetails.maintenance.autoUpdate',\n 'Automatically install updates when idle (daily background check)'\n )}\n </span>\n </label>\n </section>\n\n {/* ── Command runner ──────────────────────────────────────────── */}\n <section className={SECTION}>\n <div className=\"flex items-center justify-between gap-2 mb-3\">\n <div className=\"flex items-center gap-2\">\n <Terminal className=\"size-5 text-text-secondary\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.maintenance.commandsTitle', 'Run a command')}\n </h3>\n </div>\n <button\n type=\"button\"\n onClick={() => refetchCmds()}\n disabled={cmdsLoading}\n className=\"text-text-muted hover:text-text-primary\"\n aria-label={tr('agentDetails.maintenance.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${cmdsLoading ? 'animate-spin' : ''}`} />\n </button>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.maintenance.commandsHint',\n 'Every agent command can be run here. Destructive commands ask for confirmation.'\n )}\n </p>\n <div className=\"flex flex-wrap items-end gap-2 mb-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-text-muted\">\n {tr('agentDetails.maintenance.command', 'Command')}\n </span>\n <select\n value={selectedCommand}\n onChange={(e) => setSelectedCommand(e.target.value)}\n className=\"px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 min-w-44\"\n >\n <option value=\"\">\n {cmdsLoading\n ? tr('agentDetails.maintenance.loading', 'Loading…')\n : tr('agentDetails.maintenance.selectCommand', 'Select a command…')}\n </option>\n {commands.map((c) => (\n <option key={c.name} value={c.name}>\n {c.name}\n {c.destructive ? ' ⚠' : ''}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex flex-col gap-1 flex-1 min-w-44\">\n <span className=\"text-xs text-text-muted\">\n {tr('agentDetails.maintenance.args', 'Arguments (optional)')}\n </span>\n <input\n type=\"text\"\n value={argsInput}\n onChange={(e) => setArgsInput(e.target.value)}\n placeholder=\"--json --tail 50\"\n className=\"px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 font-mono w-full\"\n />\n </div>\n <button\n type=\"button\"\n onClick={handleRunClick}\n disabled={running || !selectedCommand}\n className={BTN_PRIMARY}\n >\n {running ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Terminal className=\"size-4\" />\n )}\n {tr('agentDetails.maintenance.run', 'Run')}\n </button>\n </div>\n {selectedMeta?.description ? (\n <p className=\"text-xs text-text-muted\">{selectedMeta.description}</p>\n ) : null}\n </section>\n\n {/* ── Danger zone (nuke) ──────────────────────────────────────── */}\n <section className={`${SECTION} border-status-error-bg/40`}>\n <div className=\"flex items-center gap-2 mb-3\">\n <AlertTriangle className=\"size-5 text-status-error-text\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.maintenance.dangerTitle', 'Danger zone')}\n </h3>\n </div>\n <label className=\"flex items-center gap-3 cursor-pointer mb-3\">\n <Checkbox checked={nukeDryRun} onCheckedChange={(c) => setNukeDryRun(c === true)} />\n <span className=\"text-sm text-text-primary\">\n {tr('agentDetails.maintenance.dryRun', 'Dry run (preview only — nothing is deleted)')}\n </span>\n </label>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => setPendingNuke({ all: false, removeConfig: false })}\n disabled={nuking}\n className={BTN_NEUTRAL}\n >\n {nuking ? <Loader2 className=\"size-4 animate-spin\" /> : <Trash2 className=\"size-4\" />}\n {tr('agentDetails.maintenance.nukeState', 'Nuke state')}\n </button>\n <button\n type=\"button\"\n onClick={() => setPendingNuke({ all: true, removeConfig: true })}\n disabled={nuking}\n className={BTN_DANGER}\n >\n <Trash2 className=\"size-4\" />\n {tr('agentDetails.maintenance.nukeAll', 'Nuke everything (--all)')}\n </button>\n </div>\n <p className=\"text-xs text-text-muted mt-2\">\n {tr(\n 'agentDetails.maintenance.nukeHint',\n '“Nuke state” wipes this agent’s data + tracked binaries. “Nuke everything” also removes all VibeControls plugins, secrets, and config across every profile on the host.'\n )}\n </p>\n </section>\n\n {/* ── Output pane ─────────────────────────────────────────────── */}\n {output ? (\n <section className={SECTION}>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-sm font-semibold text-text-primary\">{output.title}</h4>\n <button\n type=\"button\"\n onClick={() => setOutput(null)}\n className=\"text-xs text-text-muted hover:text-text-primary\"\n >\n {tr('agentDetails.maintenance.dismiss', 'Dismiss')}\n </button>\n </div>\n <pre\n className={`text-xs whitespace-pre-wrap break-words max-h-96 overflow-auto rounded-md p-3 ${\n output.error\n ? 'bg-status-error-bg-subtle text-status-error-text'\n : 'bg-bg-sunken text-text-primary'\n }`}\n >\n {output.body}\n </pre>\n </section>\n ) : null}\n\n {/* ── Confirms ────────────────────────────────────────────────── */}\n <ConfirmDialog\n isOpen={pendingCommand !== null}\n onClose={() => setPendingCommand(null)}\n onConfirm={() => {\n const argv = pendingCommand;\n setPendingCommand(null);\n if (argv) void executeCommand(argv);\n }}\n title={tr('agentDetails.maintenance.confirmCommandTitle', 'Run destructive command?')}\n message={tr(\n 'agentDetails.maintenance.confirmCommandMsg',\n 'This command can change or destroy agent state: {{cmd}}',\n { cmd: (pendingCommand ?? []).join(' ') }\n )}\n confirmLabel={tr('agentDetails.maintenance.run', 'Run')}\n variant=\"danger\"\n isLoading={running}\n />\n <ConfirmDialog\n isOpen={pendingNuke !== null}\n onClose={() => setPendingNuke(null)}\n onConfirm={() => {\n const opts = pendingNuke;\n setPendingNuke(null);\n if (opts) void runNuke(opts);\n }}\n title={\n nukeDryRun\n ? tr('agentDetails.maintenance.confirmNukeDryTitle', 'Preview nuke?')\n : tr('agentDetails.maintenance.confirmNukeTitle', 'Nuke agent?')\n }\n message={\n pendingNuke?.all\n ? tr(\n 'agentDetails.maintenance.confirmNukeAllMsg',\n 'This wipes ALL state, plugins, secrets and config on the host.'\n )\n : tr(\n 'agentDetails.maintenance.confirmNukeStateMsg',\n 'This wipes this agent’s state and tracked binaries.'\n )\n }\n confirmLabel={\n nukeDryRun\n ? tr('agentDetails.maintenance.preview', 'Preview')\n : tr('agentDetails.maintenance.nuke', 'Nuke')\n }\n variant=\"danger\"\n isLoading={nuking}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAkBA,SAAS,EAAS,GAA4C;AAC5D,QAAO,KAAK,OAAO,KAAM,YAAY,CAAC,MAAM,QAAQ,EAAE,GAAI,IAAgC;;AAE5F,SAAS,EAAK,GAAW,GAA4B;CACnD,IAAM,IAAI,IAAM;AAChB,QAAO,OAAO,KAAM,WAAW,IAAI;;AAErC,SAAS,EAAM,GAAW,GAA6B;CACrD,IAAM,IAAI,IAAM;AAChB,QAAO,OAAO,KAAM,YAAY,IAAI;;AAgBtC,IAAM,IAAU,oEACV,IACJ,gMACI,IACJ,qKACI,KACJ;AAEF,SAAgB,EAAoB,EAClC,YACA,iBACA,6BAC2B;CAC3B,IAAM,IAAK,IAAO,EAGZ,CAAC,GAAQ,KAAa,EAC1B,KACD,EACK,IAAa,GAAa,GAAe,GAAc,IAAQ,OAAU;AAC7E,IAAU;GAAE;GAAO;GAAM;GAAO,CAAC;IAChC,EAAE,CAAC,EAGA,EAAE,MAAM,IAAY,SAAS,MAAkB,EAA0B;EAC7E,WAAW,EAAE,YAAS;EACtB,aAAa;EACd,CAAC,EACI,CAAC,IAAa,EAAE,MAAM,IAAW,SAAS,OAAc,EAA6B,EACzF,aAAa,gBACd,CAAC,EACI,CAAC,GAAY,EAAE,SAAS,OAAc,GAA4B,EAClE,CAAC,GAAe,EAAE,SAAS,QAAkB,GAA+B,EAE5E,IAAS,EAAS,IAAY,mBAAmB,KAAK,EACtD,IAAY,EAAS,GAAQ,UAAU,EACvC,IAAc,EAAS,IAAW,kBAAkB,KAAK,EACzD,KAAoB,EAAM,GAAQ,UAAU,IAAI,IAChD,KAAgB,EAAK,GAAa,SAAS,IAAI,EAAK,GAAW,SAAS,IAAI,MAC5E,KAAY,EAAM,GAAa,YAAY,IAAI,EAAM,GAAW,YAAY,IAAI,IAEhF,CAAC,GAAc,MAAmB,EAAS,GAAG,EAE9C,KAAc,EAAY,YAAY;AAC1C,IAAU,KAAK;AACf,MAAI;GACF,IAAM,IAAM,MAAM,GAAY,EAAE,WAAW,EAAE,YAAS,EAAE,CAAC,EACnD,IAAI,EAAS,EAAI,MAAM,kBAAkB,KAAK;AACpD,GAAI,EAAI,MAAM,kBAAkB,QAC9B,EACE,EAAG,mCAAmC,SAAS,EAC/C,EAAI,KAAK,iBAAiB,OAC1B,GACD,GACQ,EAAM,GAAG,YAAY,GAC9B,EACE,EAAG,mCAAmC,SAAS,EAC/C,qBAAqB,EAAK,GAAG,UAAU,CAAC,KAAK,EAAK,GAAG,SAAS,GAC/D,GAED,EACE,EAAG,mCAAmC,SAAS,EAC/C,eAAe,EAAK,GAAG,UAAU,IAAI,KAAgB,IAAI,IAC1D;WAEI,GAAK;AACZ,KAAW,UAAU,aAAe,QAAQ,EAAI,UAAU,OAAO,EAAI,EAAE,GAAK;;IAE7E;EAAC;EAAS;EAAa;EAAY;EAAI;EAAa,CAAC,EAElD,IAAgB,EACpB,OAAO,MAAqB;AAC1B,IAAU,KAAK;AACf,MAAI;GAEF,IAAM,KADM,MAAM,EAAW,EAAE,WAAW;IAAE;IAAS,SAAS,KAAW;IAAM,EAAE,CAAC,EAChE,MAAM,iBAClB,IAAI,EAAS,GAAO,KAAK;AAa/B,GAZI,GAAO,SAAS,EAAM,GAAG,KAAK,KAAK,KACrC,EACE,UACC,EAAK,GAAG,QAAQ,IAAI,GAAO,SAAS,iBACrC,GACD,GAED,EACE,UACA,aAAa,EAAK,GAAG,UAAU,IAAI,KAAW,SAAS,aAAa,EAAK,GAAG,UAAU,IAAI,MAAM,IACjG,EAEH,MAAM,GAAe;WACd,GAAK;AACZ,KAAW,UAAU,aAAe,QAAQ,EAAI,UAAU,OAAO,EAAI,EAAE,GAAK;;IAGhF;EAAC;EAAS;EAAY;EAAY;EAAc,CACjD,EAEK,KAAmB,EACvB,OAAO,MAAqB;AAC1B,MAAI;AAEF,GADA,MAAM,EAAc,EAAE,WAAW;IAAE;IAAS;IAAS,EAAE,CAAC,EACxD,MAAM,GAAe;WACd,GAAK;AACZ,KAAW,cAAc,aAAe,QAAQ,EAAI,UAAU,OAAO,EAAI,EAAE,GAAK;;IAGpF;EAAC;EAAS;EAAe;EAAe;EAAW,CACpD,EAGK,EACJ,MAAM,GACN,SAAS,GACT,SAAS,OACP,EAAsB;EACxB,WAAW,EAAE,YAAS;EACtB,aAAa;EACd,CAAC,EACI,CAAC,IAAY,EAAE,SAAS,OAAa,GAA4B,EAEjE,IAAW,SAA6B;EAC5C,IAAM,IAAM,EAAS,GAAS,eAAe,KAAK,EAAE;AACpD,SAAO,MAAM,QAAQ,EAAI,GAAI,IAAwB,EAAE;IACtD,CAAC,EAAQ,CAAC,EAEP,CAAC,GAAiB,MAAsB,EAAS,GAAG,EACpD,CAAC,GAAW,MAAgB,EAAS,GAAG,EACxC,CAAC,GAAgB,KAAqB,EAA0B,KAAK,EAErE,IAAe,EAAS,MAAM,MAAM,EAAE,SAAS,EAAgB,EAE/D,KAAY,QAET,CAAC,GAAiB,GADX,EAAU,MAAM,CAAC,SAAS,IAAI,EAAU,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,CAC5C,EACjC,CAAC,GAAiB,EAAU,CAAC,EAE1B,IAAiB,EACrB,OAAO,MAAmB;AACxB,IAAU,KAAK;AACf,MAAI;GAEF,IAAM,KADM,MAAM,GAAW,EAAE,WAAW;IAAE;IAAS;IAAM,EAAE,CAAC,EAC5C,MAAM,iBAClB,IAAI,EAAS,GAAO,KAAK,EACzB,IAAS,EAAK,GAAG,SAAS,IAAI,IAC9B,IAAS,EAAK,GAAG,SAAS,IAAI,IAC9B,IAAO,GAAG,UACV,KACH,KAAkB,OAClB,IAAS,eAAe,MAAW,MACpC,WAAW,KAAQ,IAAI;AACzB,KACE,QAAQ,EAAK,KAAK,IAAI,IACtB,EAAK,MAAM,IAAI,GAAO,SAAS,eAC/B,CAAC,EAAM,GAAG,KAAK,CAChB;WACM,GAAK;AACZ,KAAW,WAAW,aAAe,QAAQ,EAAI,UAAU,OAAO,EAAI,EAAE,GAAK;;IAGjF;EAAC;EAAS;EAAY;EAAW,CAClC,EAEK,KAAiB,QAAkB;AACvC,MAAI,CAAC,EAAiB;EACtB,IAAM,IAAO,IAAW;AACxB,EAAI,GAAc,cAChB,EAAkB,EAAK,GAElB,EAAe,EAAK;IAE1B;EAAC;EAAiB;EAAW;EAAc;EAAe,CAAC,EAGxD,CAAC,IAAM,EAAE,SAAS,OAAY,GAAkC,EAChE,CAAC,GAAY,MAAiB,EAAS,GAAK,EAC5C,CAAC,GAAa,KAAkB,EACpC,KACD,EAEK,KAAU,EACd,OAAO,MAAkD;AACvD,IAAU,KAAK;AACf,MAAI;GASF,IAAM,KARM,MAAM,GAAK,EACrB,WAAW;IACT;IACA,KAAK,EAAK;IACV,cAAc,EAAK;IACnB,QAAQ;IACT,EACF,CAAC,EACgB,MAAM,uBAClB,IAAI,EAAS,GAAO,KAAK,EACzB,IAAS,EAAK,GAAG,SAAS,IAAI,IAC9B,IAAS,EAAK,GAAG,SAAS,IAAI,IAC9B,IAAK,EAAM,GAAG,KAAK,KAAK,MAAQ,CAAC,GAAO;AAQ9C,GAPA,EACE,YAAY,EAAK,MAAM,WAAW,KAAK,IAAa,eAAe,OAClE,KAAU,IAAS,eAAe,MAAW,KAAK,MAAM,IACvD,GAAO,SACP,eACF,CAAC,KAAM,CAAC,CAAC,GAAO,MACjB,EACG,KAAM,CAAC,KACT,MAAM,KAA0B;WAE3B,GAAK;AACZ,KAAW,QAAQ,aAAe,QAAQ,EAAI,UAAU,OAAO,EAAI,EAAE,GAAK;;IAG9E;EAAC;EAAS;EAAM;EAAY;EAAwB;EAAW,CAChE;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,WAAD;IAAS,WAAW;cAApB;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAe,WAAU,8BAA+B,CAAA,EACxD,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,wCAAwC,0BAA0B;OACnE,CAAA,CACD;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAG,oCAAoC,UAAU;OAC9C,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBAA+B,KAAgB;OAAU,CAAA,CACpE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAmB,EAAG,mCAAmC,SAAS;OAAO,CAAA,EACxF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,MAAiB,KACjB,KACC,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,4CAA4C,mBAAmB;QAC9D,CAAA,GACL,KACA;SACF,EAAA,CAAA,CACF;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OAAQ,MAAK;OAAS,SAAS;OAAa,UAAU;OAAU,WAAW;iBAA3E,CACG,IACC,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,GAE3C,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA,EAEjC,EAAG,kCAAkC,oBAAoB,CACnD;UACT,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,GAAe;OAC9B,UAAU;OACV,WAAW;iBAJb,CAMG,IACC,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,GAE3C,kBAAC,GAAD,EAAe,WAAU,UAAW,CAAA,EAErC,EAAG,yCAAyC,mBAAmB,CACzD;SACL;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OACE,MAAK;OACL,OAAO;OACP,WAAW,MAAM,GAAgB,EAAE,OAAO,MAAM;OAChD,aAAa,EAAG,+CAA+C,mBAAmB;OAClF,WAAU;OACV,CAAA,EACF,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAc,EAAa,MAAM,CAAC;OACjD,UAAU,KAAY,EAAa,MAAM,CAAC,WAAW;OACrD,WAAW;iBAEV,EAAG,0CAA0C,oBAAoB;OAC3D,CAAA,CACL;;KAEN,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,GAAD;OACE,SAAS;OACT,UAAU;OACV,kBAAkB,MAAM,GAAiB,MAAM,GAAK;OACpD,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBACb,EACC,uCACA,mEACD;OACI,CAAA,CACD;;KACA;;GAGV,kBAAC,WAAD;IAAS,WAAW;cAApB;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,8BAA+B,CAAA,EACnD,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,0CAA0C,gBAAgB;QAC3D,CAAA,CACD;UACN,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,IAAa;OAC5B,UAAU;OACV,WAAU;OACV,cAAY,EAAG,oCAAoC,UAAU;iBAE7D,kBAAC,GAAD,EAAW,WAAW,UAAU,IAAc,iBAAiB,MAAQ,CAAA;OAChE,CAAA,CACL;;KACN,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,yCACA,kFACD;MACC,CAAA;KACJ,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAG,oCAAoC,UAAU;SAC7C,CAAA,EACP,kBAAC,UAAD;SACE,OAAO;SACP,WAAW,MAAM,GAAmB,EAAE,OAAO,MAAM;SACnD,WAAU;mBAHZ,CAKE,kBAAC,UAAD;UAAQ,OAAM;oBACX,IACG,EAAG,oCAAoC,WAAW,GAClD,EAAG,0CAA0C,oBAAoB;UAC9D,CAAA,EACR,EAAS,KAAK,MACb,kBAAC,UAAD;UAAqB,OAAO,EAAE;oBAA9B,CACG,EAAE,MACF,EAAE,cAAc,OAAO,GACjB;YAHI,EAAE,KAGN,CACT,CACK;WACL;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAG,iCAAiC,uBAAuB;SACvD,CAAA,EACP,kBAAC,SAAD;SACE,MAAK;SACL,OAAO;SACP,WAAW,MAAM,GAAa,EAAE,OAAO,MAAM;SAC7C,aAAY;SACZ,WAAU;SACV,CAAA,CACE;;OACN,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,UAAU,KAAW,CAAC;QACtB,WAAW;kBAJb,CAMG,IACC,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,GAE3C,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA,EAEhC,EAAG,gCAAgC,MAAM,CACnC;;OACL;;KACL,GAAc,cACb,kBAAC,KAAD;MAAG,WAAU;gBAA2B,EAAa;MAAgB,CAAA,GACnE;KACI;;GAGV,kBAAC,WAAD;IAAS,WAAW,GAAG,EAAQ;cAA/B;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,IAAD,EAAe,WAAU,iCAAkC,CAAA,EAC3D,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,wCAAwC,cAAc;OACvD,CAAA,CACD;;KACN,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,GAAD;OAAU,SAAS;OAAY,kBAAkB,MAAM,GAAc,MAAM,GAAK;OAAI,CAAA,EACpF,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAG,mCAAmC,8CAA8C;OAChF,CAAA,CACD;;KACR,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAe;QAAE,KAAK;QAAO,cAAc;QAAO,CAAC;OAClE,UAAU;OACV,WAAW;iBAJb,CAMG,IAAS,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,GAAG,kBAAC,IAAD,EAAQ,WAAU,UAAW,CAAA,EACpF,EAAG,sCAAsC,aAAa,CAChD;UACT,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAe;QAAE,KAAK;QAAM,cAAc;QAAM,CAAC;OAChE,UAAU;OACV,WAAW;iBAJb,CAME,kBAAC,IAAD,EAAQ,WAAU,UAAW,CAAA,EAC5B,EAAG,oCAAoC,0BAA0B,CAC3D;SACL;;KACN,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,qCACA,0KACD;MACC,CAAA;KACI;;GAGT,IACC,kBAAC,WAAD;IAAS,WAAW;cAApB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA2C,EAAO;MAAW,CAAA,EAC3E,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAU,KAAK;MAC9B,WAAU;gBAET,EAAG,oCAAoC,UAAU;MAC3C,CAAA,CACL;QACN,kBAAC,OAAD;KACE,WAAW,iFACT,EAAO,QACH,qDACA;eAGL,EAAO;KACJ,CAAA,CACE;QACR;GAGJ,kBAAC,GAAD;IACE,QAAQ,MAAmB;IAC3B,eAAe,EAAkB,KAAK;IACtC,iBAAiB;KACf,IAAM,IAAO;AAEb,KADA,EAAkB,KAAK,EACnB,KAAW,EAAe,EAAK;;IAErC,OAAO,EAAG,gDAAgD,2BAA2B;IACrF,SAAS,EACP,8CACA,2DACA,EAAE,MAAM,KAAkB,EAAE,EAAE,KAAK,IAAI,EAAE,CAC1C;IACD,cAAc,EAAG,gCAAgC,MAAM;IACvD,SAAQ;IACR,WAAW;IACX,CAAA;GACF,kBAAC,GAAD;IACE,QAAQ,MAAgB;IACxB,eAAe,EAAe,KAAK;IACnC,iBAAiB;KACf,IAAM,IAAO;AAEb,KADA,EAAe,KAAK,EAChB,KAAW,GAAQ,EAAK;;IAE9B,OACE,IACI,EAAG,gDAAgD,gBAAgB,GACnE,EAAG,6CAA6C,cAAc;IAEpE,SACE,GAAa,MACT,EACE,8CACA,iEACD,GACD,EACE,gDACA,sDACD;IAEP,cACE,IACI,EAAG,oCAAoC,UAAU,GACjD,EAAG,iCAAiC,OAAO;IAEjD,SAAQ;IACR,WAAW;IACX,CAAA;GACE"}
|
|
@@ -58,10 +58,13 @@ function w({ vibeId: w, ownerType: le, ownerId: ue }) {
|
|
|
58
58
|
throw e;
|
|
59
59
|
}
|
|
60
60
|
}, Ne = async (e, t) => {
|
|
61
|
-
await Ee({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
await Ee({
|
|
62
|
+
variables: {
|
|
63
|
+
id: e,
|
|
64
|
+
input: t
|
|
65
|
+
},
|
|
66
|
+
context: { autoRefreshAfterMutation: !1 }
|
|
67
|
+
});
|
|
65
68
|
}, Pe = async (e, t) => {
|
|
66
69
|
if (!K) return;
|
|
67
70
|
let n = q.length, r = `page-${n + 1}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocsTabPanel.js","names":[],"sources":["../../../src/components/docs/DocsTabPanel.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { AlertCircle, X } from 'lucide-react';\nimport { LoadingState, ErrorState, QuotaExhaustedDialog } from '@/components/shared';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { resolveGatewayUrls } from '@burdenoff/fe-libs/shared/config';\nimport { DocsEmptyState } from './DocsEmptyState';\nimport { DocsPreviewPanel } from './DocsPreviewPanel';\nimport { DocsEditPanel } from './DocsEditPanel';\nimport type { DocsSite, DocsRevision } from './types';\nimport {\n isQuotaExhaustedError,\n markQuotaHandledLocally,\n getQuotaDialogContent,\n} from '@/utils/quotaUtils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport {\n useGetDocsSiteQuery,\n useCreateDocsSiteMutation,\n useUpdateDocsSiteMutation,\n useUpdateDocsSiteVisibilityMutation,\n useCreateDocsPageMutation,\n useUpdateDocsPageMutation,\n useDeleteDocsPageMutation,\n useCompileDocsSiteMutation,\n useDocsContentQuery,\n useGetDocsRevisionLazyQuery,\n useGenerateDocsSignedUrlMutation,\n useRollbackDocsRevisionMutation,\n useDeleteDocsSiteMutation,\n} from '@/generated/wspace-operations';\n\ninterface DocsTabPanelProps {\n vibeId?: string;\n ownerType?: string;\n ownerId?: string;\n}\n\nexport function DocsTabPanel({ vibeId, ownerType, ownerId }: DocsTabPanelProps) {\n const tr = useTr();\n const effectiveOwnerType = ownerType || 'VIBE';\n const effectiveOwnerId = ownerId || vibeId || '';\n const [mode, setMode] = useState<'preview' | 'edit'>('preview');\n const [compileRevision, setCompileRevision] = useState<DocsRevision | null>(null);\n const [compiling, setCompiling] = useState(false);\n const [compileError, setCompileError] = useState<string | null>(null);\n const [selectedPageSlug, setSelectedPageSlug] = useState('');\n const [rollingBack, setRollingBack] = useState<string | null>(null);\n const navigate = useVibeNavigate();\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [showCompileQuotaExhausted, setShowCompileQuotaExhausted] = useState(false);\n\n // Queries\n const { data, loading, error, refetch } = useGetDocsSiteQuery({\n variables: { ownerType: effectiveOwnerType as any, ownerId: effectiveOwnerId },\n skip: !effectiveOwnerId,\n fetchPolicy: 'cache-and-network',\n });\n\n const site = (data?.vibecontrolsDocsSiteByOwner ?? null) as DocsSite | null;\n const pages = site?.pages || [];\n\n const {\n data: docsContentData,\n loading: docsContentLoading,\n refetch: refetchDocsContent,\n } = useDocsContentQuery({\n variables: { siteId: site?.id || '', path: selectedPageSlug },\n skip: !site?.id || !site.currentRevisionId,\n fetchPolicy: 'network-only',\n });\n const docsHtml = docsContentData?.docsContent?.html ?? null;\n\n // Re-fetch docs content whenever currentRevisionId changes (compile finished or first publish).\n // This runs post-render so skip:false is guaranteed — imperative calls during async handlers\n // are no-ops when skip is still true in the closure.\n const prevRevisionIdRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n const currentId = site?.currentRevisionId ?? null;\n if (prevRevisionIdRef.current === undefined) {\n prevRevisionIdRef.current = currentId;\n return;\n }\n if (currentId && currentId !== prevRevisionIdRef.current) {\n prevRevisionIdRef.current = currentId;\n refetchDocsContent();\n }\n }, [site?.currentRevisionId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Compute gateway docs URL for iframe src (workspaceId prefix for isolation)\n const gatewayUrls = resolveGatewayUrls();\n const docsBaseUrl = site?.workspaceId\n ? `${gatewayUrls.workspaceBaseUrl}/workspaces/static/${site.workspaceId}/docs/${effectiveOwnerId}/`\n : null;\n\n // Mutations\n const [createSiteMutation, { loading: creating }] = useCreateDocsSiteMutation();\n const [updateSiteMutation] = useUpdateDocsSiteMutation();\n const [updateVisibilityMutation] = useUpdateDocsSiteVisibilityMutation();\n const [createPageMutation, { loading: pageAdding }] = useCreateDocsPageMutation();\n const [updatePageMutation] = useUpdateDocsPageMutation();\n const [deletePageMutation] = useDeleteDocsPageMutation();\n const [compileMutation] = useCompileDocsSiteMutation();\n const [generateSignedUrl] = useGenerateDocsSignedUrlMutation();\n const [rollbackRevision] = useRollbackDocsRevisionMutation();\n const [deleteSiteMutation] = useDeleteDocsSiteMutation();\n const [fetchRevision] = useGetDocsRevisionLazyQuery({\n fetchPolicy: 'network-only',\n });\n\n // Handlers\n const handleCreateSite = async (\n provider: 'DOCUSAURUS' | 'MKDOCS' | 'VITEPRESS' = 'DOCUSAURUS'\n ) => {\n try {\n await createSiteMutation({\n variables: {\n input: {\n ownerType: effectiveOwnerType as any,\n ownerId: effectiveOwnerId,\n name: 'Documentation',\n provider: provider as any,\n },\n },\n refetchQueries: ['GetDocsSite'],\n awaitRefetchQueries: true,\n });\n setMode('edit');\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setShowQuotaExhausted(true);\n return;\n }\n throw err;\n }\n };\n\n const handleSavePage = async (\n id: string,\n data: { title?: string; content?: string; slug?: string }\n ) => {\n await updatePageMutation({ variables: { id, input: data } });\n };\n\n const handleAddPage = async (parentId?: string, category?: string) => {\n if (!site) return;\n const pageCount = pages.length;\n const slug = `page-${pageCount + 1}`;\n await createPageMutation({\n variables: {\n input: {\n siteId: site.id,\n parentId: parentId || null,\n slug,\n title: `New Page ${pageCount + 1}`,\n content: '# New Page\\n\\nStart writing here...',\n status: 'DRAFT',\n sidebarPosition: pageCount,\n category: category || null,\n },\n },\n });\n await refetch();\n };\n\n const handleDeletePage = async (pageId: string) => {\n if (!confirm('Delete this page?')) return;\n await deletePageMutation({ variables: { id: pageId } });\n await refetch();\n };\n\n const handleCompile = async () => {\n if (!site) return;\n setCompiling(true);\n setCompileError(null);\n try {\n const result = await compileMutation({\n variables: { siteId: site.id, publish: true },\n });\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setCompiling(false);\n setShowCompileQuotaExhausted(true);\n return;\n }\n if (result.data?.compileDocsSite) {\n setCompileRevision(result.data.compileDocsSite as DocsRevision);\n } else {\n setCompiling(false);\n setCompileError(\n 'Build could not be started — the server returned an empty response. Please try again.'\n );\n }\n } catch (err) {\n setCompiling(false);\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setShowCompileQuotaExhausted(true);\n return;\n }\n setCompileError(\n err instanceof Error ? err.message : 'Failed to start the build. Please try again.'\n );\n }\n };\n\n const handlePollRevision = async (revisionId: string): Promise<DocsRevision | null> => {\n const { data: revData } = await fetchRevision({ variables: { id: revisionId } });\n const rev = revData?.docsRevision as DocsRevision | null;\n if (rev) {\n setCompileRevision(rev);\n const done = ['SUCCEEDED', 'PUBLISHED', 'FAILED'].includes(rev.status);\n if (done) {\n setCompiling(false);\n if (rev.status === 'PUBLISHED' || rev.status === 'SUCCEEDED') {\n setSelectedPageSlug('');\n await refetch();\n }\n }\n }\n return rev;\n };\n\n const handleSaveSettings = async (data: {\n name?: string;\n visibility?: 'PRIVATE' | 'PUBLIC';\n provider?: 'DOCUSAURUS' | 'MKDOCS' | 'VITEPRESS';\n providerConfig?: Record<string, unknown>;\n }) => {\n if (!site) return;\n if (data.visibility && data.visibility !== site.visibility) {\n await updateVisibilityMutation({ variables: { id: site.id, visibility: data.visibility } });\n }\n const rest = {\n name: data.name,\n provider: data.provider,\n providerConfig: data.providerConfig,\n };\n if (Object.keys(rest).length > 0) {\n await updateSiteMutation({ variables: { id: site.id, input: rest } });\n }\n await refetch();\n };\n\n const handleGetShareUrl = async (): Promise<string | null> => {\n if (!site?.currentRevisionId) return null;\n try {\n const { data: urlData } = await generateSignedUrl({ variables: { siteId: site.id } });\n return urlData?.generateDocsSignedUrl?.url ?? null;\n } catch {\n return null;\n }\n };\n\n const handleRollback = async (revisionId: string) => {\n if (!site) return;\n if (!confirm('Roll back to this revision? The current published docs will be replaced.'))\n return;\n setRollingBack(revisionId);\n try {\n await rollbackRevision({ variables: { siteId: site.id, revisionId } });\n await refetch();\n } finally {\n setRollingBack(null);\n }\n };\n\n const handleDeleteSite = async () => {\n if (!site) return;\n if (!confirm('Delete this docs site and all its pages and revisions? This cannot be undone.'))\n return;\n await deleteSiteMutation({ variables: { id: site.id } });\n await refetch();\n };\n\n // Loading / Error states\n if (loading && !site) {\n return (\n <LoadingState message={tr('vibecontrols.docs.tab.loading', 'Loading documentation...')} />\n );\n }\n\n if (error && !site) {\n return (\n <ErrorState\n title={tr('vibecontrols.docs.tab.loadFailed', 'Failed to load docs')}\n message={error.message}\n onRetry={() => refetch()}\n />\n );\n }\n\n // No site yet\n if (!site) {\n return (\n <>\n <DocsEmptyState onCreate={handleCreateSite} loading={creating} />\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Docs Site Quota Reached\"\n message=\"You have reached the documentation site limit for your current plan. Upgrade to create more docs sites.\"\n />\n </>\n );\n }\n\n const compileErrorBanner = compileError ? (\n <div className=\"flex items-center gap-2 px-4 py-2 mb-2 bg-status-error-bg text-status-error-text text-sm rounded-md\">\n <AlertCircle className=\"size-4 shrink-0\" />\n <span className=\"flex-1\">{compileError}</span>\n <button\n type=\"button\"\n onClick={() => setCompileError(null)}\n className=\"p-0.5 hover:opacity-70\"\n >\n <X className=\"size-3.5\" />\n </button>\n </div>\n ) : null;\n\n const compileQuotaDialog = (\n <QuotaExhaustedDialog\n isOpen={showCompileQuotaExhausted}\n onClose={() => setShowCompileQuotaExhausted(false)}\n onConfirm={() => {\n setShowCompileQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title={getQuotaDialogContent('docs-compilation').title}\n message={getQuotaDialogContent('docs-compilation').message}\n />\n );\n\n // Edit mode\n if (mode === 'edit') {\n return (\n <>\n {compileErrorBanner}\n {compileQuotaDialog}\n <DocsEditPanel\n site={site}\n pages={pages}\n onBack={() => setMode('preview')}\n onSavePage={handleSavePage}\n onAddPage={handleAddPage}\n pageAdding={pageAdding}\n onDeletePage={handleDeletePage}\n onCompile={handleCompile}\n onSaveSettings={handleSaveSettings}\n onRollback={handleRollback}\n onDeleteSite={handleDeleteSite}\n rollingBack={rollingBack}\n compileRevision={compileRevision}\n onPollRevision={handlePollRevision}\n compiling={compiling}\n />\n </>\n );\n }\n\n // Preview mode\n return (\n <>\n {compileErrorBanner}\n {compileQuotaDialog}\n <DocsPreviewPanel\n site={site}\n pages={pages}\n selectedPageSlug={selectedPageSlug}\n onSelectPage={setSelectedPageSlug}\n docsBaseUrl={site.currentRevisionId ? (docsBaseUrl ?? null) : null}\n docsHtml={site.currentRevisionId ? docsHtml : null}\n docsContentLoading={docsContentLoading}\n onEdit={() => setMode('edit')}\n onCompile={handleCompile}\n onSettings={() => setMode('edit')}\n onGetShareUrl={handleGetShareUrl}\n onOpenFullScreen={() => {\n const pathMap: Record<string, string> = {\n VIBE: 'vibes',\n CATALOG: 'catalogs',\n COMPONENT: 'components',\n };\n const segment = pathMap[effectiveOwnerType] || 'vibes';\n navigate(`/${segment}/${effectiveOwnerId}/docs`);\n }}\n compileRevision={compileRevision}\n onPollRevision={handlePollRevision}\n compiling={compiling}\n />\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Docs Site Quota Reached\"\n message=\"You have reached the documentation site limit for your current plan. Upgrade to create more docs sites.\"\n />\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DocsTabPanel.js","names":[],"sources":["../../../src/components/docs/DocsTabPanel.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport { AlertCircle, X } from 'lucide-react';\nimport { LoadingState, ErrorState, QuotaExhaustedDialog } from '@/components/shared';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { resolveGatewayUrls } from '@burdenoff/fe-libs/shared/config';\nimport { DocsEmptyState } from './DocsEmptyState';\nimport { DocsPreviewPanel } from './DocsPreviewPanel';\nimport { DocsEditPanel } from './DocsEditPanel';\nimport type { DocsSite, DocsRevision } from './types';\nimport {\n isQuotaExhaustedError,\n markQuotaHandledLocally,\n getQuotaDialogContent,\n} from '@/utils/quotaUtils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport {\n useGetDocsSiteQuery,\n useCreateDocsSiteMutation,\n useUpdateDocsSiteMutation,\n useUpdateDocsSiteVisibilityMutation,\n useCreateDocsPageMutation,\n useUpdateDocsPageMutation,\n useDeleteDocsPageMutation,\n useCompileDocsSiteMutation,\n useDocsContentQuery,\n useGetDocsRevisionLazyQuery,\n useGenerateDocsSignedUrlMutation,\n useRollbackDocsRevisionMutation,\n useDeleteDocsSiteMutation,\n} from '@/generated/wspace-operations';\n\ninterface DocsTabPanelProps {\n vibeId?: string;\n ownerType?: string;\n ownerId?: string;\n}\n\nexport function DocsTabPanel({ vibeId, ownerType, ownerId }: DocsTabPanelProps) {\n const tr = useTr();\n const effectiveOwnerType = ownerType || 'VIBE';\n const effectiveOwnerId = ownerId || vibeId || '';\n const [mode, setMode] = useState<'preview' | 'edit'>('preview');\n const [compileRevision, setCompileRevision] = useState<DocsRevision | null>(null);\n const [compiling, setCompiling] = useState(false);\n const [compileError, setCompileError] = useState<string | null>(null);\n const [selectedPageSlug, setSelectedPageSlug] = useState('');\n const [rollingBack, setRollingBack] = useState<string | null>(null);\n const navigate = useVibeNavigate();\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [showCompileQuotaExhausted, setShowCompileQuotaExhausted] = useState(false);\n\n // Queries\n const { data, loading, error, refetch } = useGetDocsSiteQuery({\n variables: { ownerType: effectiveOwnerType as any, ownerId: effectiveOwnerId },\n skip: !effectiveOwnerId,\n fetchPolicy: 'cache-and-network',\n });\n\n const site = (data?.vibecontrolsDocsSiteByOwner ?? null) as DocsSite | null;\n const pages = site?.pages || [];\n\n const {\n data: docsContentData,\n loading: docsContentLoading,\n refetch: refetchDocsContent,\n } = useDocsContentQuery({\n variables: { siteId: site?.id || '', path: selectedPageSlug },\n skip: !site?.id || !site.currentRevisionId,\n fetchPolicy: 'network-only',\n });\n const docsHtml = docsContentData?.docsContent?.html ?? null;\n\n // Re-fetch docs content whenever currentRevisionId changes (compile finished or first publish).\n // This runs post-render so skip:false is guaranteed — imperative calls during async handlers\n // are no-ops when skip is still true in the closure.\n const prevRevisionIdRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n const currentId = site?.currentRevisionId ?? null;\n if (prevRevisionIdRef.current === undefined) {\n prevRevisionIdRef.current = currentId;\n return;\n }\n if (currentId && currentId !== prevRevisionIdRef.current) {\n prevRevisionIdRef.current = currentId;\n refetchDocsContent();\n }\n }, [site?.currentRevisionId]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Compute gateway docs URL for iframe src (workspaceId prefix for isolation)\n const gatewayUrls = resolveGatewayUrls();\n const docsBaseUrl = site?.workspaceId\n ? `${gatewayUrls.workspaceBaseUrl}/workspaces/static/${site.workspaceId}/docs/${effectiveOwnerId}/`\n : null;\n\n // Mutations\n const [createSiteMutation, { loading: creating }] = useCreateDocsSiteMutation();\n const [updateSiteMutation] = useUpdateDocsSiteMutation();\n const [updateVisibilityMutation] = useUpdateDocsSiteVisibilityMutation();\n const [createPageMutation, { loading: pageAdding }] = useCreateDocsPageMutation();\n const [updatePageMutation] = useUpdateDocsPageMutation();\n const [deletePageMutation] = useDeleteDocsPageMutation();\n const [compileMutation] = useCompileDocsSiteMutation();\n const [generateSignedUrl] = useGenerateDocsSignedUrlMutation();\n const [rollbackRevision] = useRollbackDocsRevisionMutation();\n const [deleteSiteMutation] = useDeleteDocsSiteMutation();\n const [fetchRevision] = useGetDocsRevisionLazyQuery({\n fetchPolicy: 'network-only',\n });\n\n // Handlers\n const handleCreateSite = async (\n provider: 'DOCUSAURUS' | 'MKDOCS' | 'VITEPRESS' = 'DOCUSAURUS'\n ) => {\n try {\n await createSiteMutation({\n variables: {\n input: {\n ownerType: effectiveOwnerType as any,\n ownerId: effectiveOwnerId,\n name: 'Documentation',\n provider: provider as any,\n },\n },\n refetchQueries: ['GetDocsSite'],\n awaitRefetchQueries: true,\n });\n setMode('edit');\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setShowQuotaExhausted(true);\n return;\n }\n throw err;\n }\n };\n\n const handleSavePage = async (\n id: string,\n data: { title?: string; content?: string; slug?: string }\n ) => {\n await updatePageMutation({\n variables: { id, input: data },\n context: { autoRefreshAfterMutation: false },\n });\n };\n\n const handleAddPage = async (parentId?: string, category?: string) => {\n if (!site) return;\n const pageCount = pages.length;\n const slug = `page-${pageCount + 1}`;\n await createPageMutation({\n variables: {\n input: {\n siteId: site.id,\n parentId: parentId || null,\n slug,\n title: `New Page ${pageCount + 1}`,\n content: '# New Page\\n\\nStart writing here...',\n status: 'DRAFT',\n sidebarPosition: pageCount,\n category: category || null,\n },\n },\n });\n await refetch();\n };\n\n const handleDeletePage = async (pageId: string) => {\n if (!confirm('Delete this page?')) return;\n await deletePageMutation({ variables: { id: pageId } });\n await refetch();\n };\n\n const handleCompile = async () => {\n if (!site) return;\n setCompiling(true);\n setCompileError(null);\n try {\n const result = await compileMutation({\n variables: { siteId: site.id, publish: true },\n });\n if (result.error && isQuotaExhaustedError(result.error)) {\n markQuotaHandledLocally();\n setCompiling(false);\n setShowCompileQuotaExhausted(true);\n return;\n }\n if (result.data?.compileDocsSite) {\n setCompileRevision(result.data.compileDocsSite as DocsRevision);\n } else {\n setCompiling(false);\n setCompileError(\n 'Build could not be started — the server returned an empty response. Please try again.'\n );\n }\n } catch (err) {\n setCompiling(false);\n if (isQuotaExhaustedError(err)) {\n markQuotaHandledLocally();\n setShowCompileQuotaExhausted(true);\n return;\n }\n setCompileError(\n err instanceof Error ? err.message : 'Failed to start the build. Please try again.'\n );\n }\n };\n\n const handlePollRevision = async (revisionId: string): Promise<DocsRevision | null> => {\n const { data: revData } = await fetchRevision({ variables: { id: revisionId } });\n const rev = revData?.docsRevision as DocsRevision | null;\n if (rev) {\n setCompileRevision(rev);\n const done = ['SUCCEEDED', 'PUBLISHED', 'FAILED'].includes(rev.status);\n if (done) {\n setCompiling(false);\n if (rev.status === 'PUBLISHED' || rev.status === 'SUCCEEDED') {\n setSelectedPageSlug('');\n await refetch();\n }\n }\n }\n return rev;\n };\n\n const handleSaveSettings = async (data: {\n name?: string;\n visibility?: 'PRIVATE' | 'PUBLIC';\n provider?: 'DOCUSAURUS' | 'MKDOCS' | 'VITEPRESS';\n providerConfig?: Record<string, unknown>;\n }) => {\n if (!site) return;\n if (data.visibility && data.visibility !== site.visibility) {\n await updateVisibilityMutation({ variables: { id: site.id, visibility: data.visibility } });\n }\n const rest = {\n name: data.name,\n provider: data.provider,\n providerConfig: data.providerConfig,\n };\n if (Object.keys(rest).length > 0) {\n await updateSiteMutation({ variables: { id: site.id, input: rest } });\n }\n await refetch();\n };\n\n const handleGetShareUrl = async (): Promise<string | null> => {\n if (!site?.currentRevisionId) return null;\n try {\n const { data: urlData } = await generateSignedUrl({ variables: { siteId: site.id } });\n return urlData?.generateDocsSignedUrl?.url ?? null;\n } catch {\n return null;\n }\n };\n\n const handleRollback = async (revisionId: string) => {\n if (!site) return;\n if (!confirm('Roll back to this revision? The current published docs will be replaced.'))\n return;\n setRollingBack(revisionId);\n try {\n await rollbackRevision({ variables: { siteId: site.id, revisionId } });\n await refetch();\n } finally {\n setRollingBack(null);\n }\n };\n\n const handleDeleteSite = async () => {\n if (!site) return;\n if (!confirm('Delete this docs site and all its pages and revisions? This cannot be undone.'))\n return;\n await deleteSiteMutation({ variables: { id: site.id } });\n await refetch();\n };\n\n // Loading / Error states\n if (loading && !site) {\n return (\n <LoadingState message={tr('vibecontrols.docs.tab.loading', 'Loading documentation...')} />\n );\n }\n\n if (error && !site) {\n return (\n <ErrorState\n title={tr('vibecontrols.docs.tab.loadFailed', 'Failed to load docs')}\n message={error.message}\n onRetry={() => refetch()}\n />\n );\n }\n\n // No site yet\n if (!site) {\n return (\n <>\n <DocsEmptyState onCreate={handleCreateSite} loading={creating} />\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Docs Site Quota Reached\"\n message=\"You have reached the documentation site limit for your current plan. Upgrade to create more docs sites.\"\n />\n </>\n );\n }\n\n const compileErrorBanner = compileError ? (\n <div className=\"flex items-center gap-2 px-4 py-2 mb-2 bg-status-error-bg text-status-error-text text-sm rounded-md\">\n <AlertCircle className=\"size-4 shrink-0\" />\n <span className=\"flex-1\">{compileError}</span>\n <button\n type=\"button\"\n onClick={() => setCompileError(null)}\n className=\"p-0.5 hover:opacity-70\"\n >\n <X className=\"size-3.5\" />\n </button>\n </div>\n ) : null;\n\n const compileQuotaDialog = (\n <QuotaExhaustedDialog\n isOpen={showCompileQuotaExhausted}\n onClose={() => setShowCompileQuotaExhausted(false)}\n onConfirm={() => {\n setShowCompileQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title={getQuotaDialogContent('docs-compilation').title}\n message={getQuotaDialogContent('docs-compilation').message}\n />\n );\n\n // Edit mode\n if (mode === 'edit') {\n return (\n <>\n {compileErrorBanner}\n {compileQuotaDialog}\n <DocsEditPanel\n site={site}\n pages={pages}\n onBack={() => setMode('preview')}\n onSavePage={handleSavePage}\n onAddPage={handleAddPage}\n pageAdding={pageAdding}\n onDeletePage={handleDeletePage}\n onCompile={handleCompile}\n onSaveSettings={handleSaveSettings}\n onRollback={handleRollback}\n onDeleteSite={handleDeleteSite}\n rollingBack={rollingBack}\n compileRevision={compileRevision}\n onPollRevision={handlePollRevision}\n compiling={compiling}\n />\n </>\n );\n }\n\n // Preview mode\n return (\n <>\n {compileErrorBanner}\n {compileQuotaDialog}\n <DocsPreviewPanel\n site={site}\n pages={pages}\n selectedPageSlug={selectedPageSlug}\n onSelectPage={setSelectedPageSlug}\n docsBaseUrl={site.currentRevisionId ? (docsBaseUrl ?? null) : null}\n docsHtml={site.currentRevisionId ? docsHtml : null}\n docsContentLoading={docsContentLoading}\n onEdit={() => setMode('edit')}\n onCompile={handleCompile}\n onSettings={() => setMode('edit')}\n onGetShareUrl={handleGetShareUrl}\n onOpenFullScreen={() => {\n const pathMap: Record<string, string> = {\n VIBE: 'vibes',\n CATALOG: 'catalogs',\n COMPONENT: 'components',\n };\n const segment = pathMap[effectiveOwnerType] || 'vibes';\n navigate(`/${segment}/${effectiveOwnerId}/docs`);\n }}\n compileRevision={compileRevision}\n onPollRevision={handlePollRevision}\n compiling={compiling}\n />\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Docs Site Quota Reached\"\n message=\"You have reached the documentation site limit for your current plan. Upgrade to create more docs sites.\"\n />\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -17,8 +17,8 @@ var u = {
|
|
|
17
17
|
confirmBtn: "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover"
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
function d({ isOpen: d, onClose: f, onConfirm: p, title: m, message: h, confirmLabel: g, cancelLabel: _, variant: v = "default", isLoading: y = !1 }) {
|
|
21
|
-
let
|
|
20
|
+
function d({ isOpen: d, onClose: f, onConfirm: p, title: m, message: h, confirmLabel: g, cancelLabel: _, variant: v = "default", isLoading: y = !1, children: b }) {
|
|
21
|
+
let x = e(), S = g ?? x("vibecontrols.shared.confirmDialog.confirm", "Confirm"), C = _ ?? x("vibecontrols.shared.confirmDialog.cancel", "Cancel"), w = u[v];
|
|
22
22
|
return /* @__PURE__ */ n(i, {
|
|
23
23
|
open: d,
|
|
24
24
|
onOpenChange: (e) => {
|
|
@@ -26,32 +26,39 @@ function d({ isOpen: d, onClose: f, onConfirm: p, title: m, message: h, confirmL
|
|
|
26
26
|
},
|
|
27
27
|
children: /* @__PURE__ */ r(a, {
|
|
28
28
|
className: "sm:max-w-md",
|
|
29
|
-
children: [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
children: [
|
|
30
|
+
/* @__PURE__ */ n(c, { children: /* @__PURE__ */ r("div", {
|
|
31
|
+
className: "flex items-start gap-3",
|
|
32
|
+
children: [/* @__PURE__ */ n("div", {
|
|
33
|
+
className: `flex-shrink-0 size-10 rounded-full flex items-center justify-center ${w.iconWrap}`,
|
|
34
|
+
"aria-hidden": "true",
|
|
35
|
+
children: /* @__PURE__ */ n(t, { className: "size-5" })
|
|
36
|
+
}), /* @__PURE__ */ r("div", {
|
|
37
|
+
className: "flex-1 min-w-0",
|
|
38
|
+
children: [/* @__PURE__ */ n(l, { children: m }), /* @__PURE__ */ n(o, {
|
|
39
|
+
className: "mt-1",
|
|
40
|
+
children: h
|
|
41
|
+
})]
|
|
40
42
|
})]
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
}) }),
|
|
44
|
+
b ? /* @__PURE__ */ n("div", {
|
|
45
|
+
className: "px-1 pt-1",
|
|
46
|
+
children: b
|
|
47
|
+
}) : null,
|
|
48
|
+
/* @__PURE__ */ r(s, { children: [/* @__PURE__ */ n("button", {
|
|
49
|
+
type: "button",
|
|
50
|
+
onClick: f,
|
|
51
|
+
disabled: y,
|
|
52
|
+
className: "min-h-11 px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40",
|
|
53
|
+
children: C
|
|
54
|
+
}), /* @__PURE__ */ n("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: p,
|
|
57
|
+
disabled: y,
|
|
58
|
+
className: `min-h-11 px-4 py-2 text-sm font-medium rounded-md transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 ${w.confirmBtn}`,
|
|
59
|
+
children: y ? x("vibecontrols.shared.confirmDialog.processing", "Processing...") : S
|
|
60
|
+
})] })
|
|
61
|
+
]
|
|
55
62
|
})
|
|
56
63
|
});
|
|
57
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/shared/ConfirmDialog.tsx"],"sourcesContent":["import { AlertTriangle } from 'lucide-react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface ConfirmDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void;\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: 'danger' | 'warning' | 'default';\n isLoading?: boolean;\n}\n\nconst VARIANT_STYLES: Record<\n NonNullable<ConfirmDialogProps['variant']>,\n { iconWrap: string; confirmBtn: string }\n> = {\n danger: {\n iconWrap: 'bg-status-error-bg-subtle text-status-error-text',\n confirmBtn: 'bg-status-error-bg text-text-inverse hover:bg-status-error-text-hover',\n },\n warning: {\n iconWrap: 'bg-status-warning-bg-subtle text-status-warning-text',\n confirmBtn: 'bg-status-warning-bg text-text-primary hover:bg-status-warning-text-hover',\n },\n default: {\n iconWrap: 'bg-action-primary-bg text-action-primary-text',\n confirmBtn: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover',\n },\n};\n\nexport function ConfirmDialog({\n isOpen,\n onClose,\n onConfirm,\n title,\n message,\n confirmLabel,\n cancelLabel,\n variant = 'default',\n isLoading = false,\n}: ConfirmDialogProps) {\n const tr = useTr();\n const resolvedConfirmLabel =\n confirmLabel ?? tr('vibecontrols.shared.confirmDialog.confirm', 'Confirm');\n const resolvedCancelLabel =\n cancelLabel ?? tr('vibecontrols.shared.confirmDialog.cancel', 'Cancel');\n const styles = VARIANT_STYLES[variant];\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <ResponsiveDialogHeader>\n <div className=\"flex items-start gap-3\">\n <div\n className={`flex-shrink-0 size-10 rounded-full flex items-center justify-center ${styles.iconWrap}`}\n aria-hidden=\"true\"\n >\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription className=\"mt-1\">{message}</ResponsiveDialogDescription>\n </div>\n </div>\n </ResponsiveDialogHeader>\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isLoading}\n className=\"min-h-11 px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40\"\n >\n {resolvedCancelLabel}\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n disabled={isLoading}\n className={`min-h-11 px-4 py-2 text-sm font-medium rounded-md transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 ${styles.confirmBtn}`}\n >\n {isLoading\n ? tr('vibecontrols.shared.confirmDialog.processing', 'Processing...')\n : resolvedConfirmLabel}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/shared/ConfirmDialog.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { AlertTriangle } from 'lucide-react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface ConfirmDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void;\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: 'danger' | 'warning' | 'default';\n isLoading?: boolean;\n /** Optional extra content rendered between the message and the footer\n * (e.g. an opt-in checkbox). */\n children?: ReactNode;\n}\n\nconst VARIANT_STYLES: Record<\n NonNullable<ConfirmDialogProps['variant']>,\n { iconWrap: string; confirmBtn: string }\n> = {\n danger: {\n iconWrap: 'bg-status-error-bg-subtle text-status-error-text',\n confirmBtn: 'bg-status-error-bg text-text-inverse hover:bg-status-error-text-hover',\n },\n warning: {\n iconWrap: 'bg-status-warning-bg-subtle text-status-warning-text',\n confirmBtn: 'bg-status-warning-bg text-text-primary hover:bg-status-warning-text-hover',\n },\n default: {\n iconWrap: 'bg-action-primary-bg text-action-primary-text',\n confirmBtn: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover',\n },\n};\n\nexport function ConfirmDialog({\n isOpen,\n onClose,\n onConfirm,\n title,\n message,\n confirmLabel,\n cancelLabel,\n variant = 'default',\n isLoading = false,\n children,\n}: ConfirmDialogProps) {\n const tr = useTr();\n const resolvedConfirmLabel =\n confirmLabel ?? tr('vibecontrols.shared.confirmDialog.confirm', 'Confirm');\n const resolvedCancelLabel =\n cancelLabel ?? tr('vibecontrols.shared.confirmDialog.cancel', 'Cancel');\n const styles = VARIANT_STYLES[variant];\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <ResponsiveDialogHeader>\n <div className=\"flex items-start gap-3\">\n <div\n className={`flex-shrink-0 size-10 rounded-full flex items-center justify-center ${styles.iconWrap}`}\n aria-hidden=\"true\"\n >\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription className=\"mt-1\">{message}</ResponsiveDialogDescription>\n </div>\n </div>\n </ResponsiveDialogHeader>\n {children ? <div className=\"px-1 pt-1\">{children}</div> : null}\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isLoading}\n className=\"min-h-11 px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40\"\n >\n {resolvedCancelLabel}\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n disabled={isLoading}\n className={`min-h-11 px-4 py-2 text-sm font-medium rounded-md transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 ${styles.confirmBtn}`}\n >\n {isLoading\n ? tr('vibecontrols.shared.confirmDialog.processing', 'Processing...')\n : resolvedConfirmLabel}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;;AA2BA,IAAM,IAGF;CACF,QAAQ;EACN,UAAU;EACV,YAAY;EACb;CACD,SAAS;EACP,UAAU;EACV,YAAY;EACb;CACD,SAAS;EACP,UAAU;EACV,YAAY;EACb;CACF;AAED,SAAgB,EAAc,EAC5B,WACA,YACA,cACA,UACA,YACA,iBACA,gBACA,aAAU,WACV,eAAY,IACZ,eACqB;CACrB,IAAM,IAAK,GAAO,EACZ,IACJ,KAAgB,EAAG,6CAA6C,UAAU,EACtE,IACJ,KAAe,EAAG,4CAA4C,SAAS,EACnE,IAAS,EAAe;AAE9B,QACE,kBAAC,GAAD;EACE,MAAM;EACN,eAAe,MAAS;AACtB,GAAK,KAAM,GAAS;;YAGtB,kBAAC,GAAD;GAAyB,WAAU;aAAnC;IACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MACE,WAAW,uEAAuE,EAAO;MACzF,eAAY;gBAEZ,kBAAC,GAAD,EAAe,WAAU,UAAW,CAAA;MAChC,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAwB,GAA8B,CAAA,EACtD,kBAAC,GAAD;OAA6B,WAAU;iBAAQ;OAAsC,CAAA,CACjF;QACF;QACiB,CAAA;IACxB,IAAW,kBAAC,OAAD;KAAK,WAAU;KAAa;KAAe,CAAA,GAAG;IAC1D,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,UAAU;KACV,WAAU;eAET;KACM,CAAA,EACT,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,UAAU;KACV,WAAW,2JAA2J,EAAO;eAE5K,IACG,EAAG,gDAAgD,gBAAgB,GACnE;KACG,CAAA,CACc,EAAA,CAAA;IACD;;EACT,CAAA"}
|