@burdenoff/microfe-vibecontrols 2026.526.6 → 2026.527.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/agent-manager/detail/SessionConfigPanel.js +6 -6
- package/dist/components/ai/AIContextsTab.js +5 -5
- package/dist/components/ai/AITasksTab.js +7 -7
- package/dist/components/ai/AITasksTab.js.map +1 -1
- package/dist/components/ai/AITemplatesTab.js +5 -5
- package/dist/components/docs/DocsTabPanel.js +61 -61
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +173 -173
- package/dist/components/notes/NotesTabPanel.js.map +1 -1
- package/dist/components/shared/PluginGate.js +4 -4
- package/dist/components/shared/index.js +2 -2
- package/dist/components/tunnels/TunnelCreateWizard.js +35 -35
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/hooks/usePluginAvailability.js +104 -104
- package/dist/hooks/usePluginAvailability.js.map +1 -1
- package/dist/pages/ActionsPage.js +202 -202
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js +682 -682
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +228 -228
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +61 -61
- package/dist/pages/ComponentDetailPage.js +66 -66
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +500 -446
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +425 -425
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +221 -221
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +11 -11
- package/dist/pages/VibeDeckPage.js +344 -344
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibesPage.js +305 -305
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelsTab.js +90 -90
- package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +4 -4
- package/dist/providers/QuotaExhaustedProvider.js +51 -0
- package/dist/providers/QuotaExhaustedProvider.js.map +1 -0
- package/dist/providers/VibeControlsProvider.js +96 -76
- package/dist/providers/VibeControlsProvider.js.map +1 -1
- package/dist/utils/quotaUtils.js +80 -2
- package/dist/utils/quotaUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTr as e } from "../../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { ConfirmDialog as t } from "../../shared/ConfirmDialog.js";
|
|
3
|
+
import { LoadingState as n } from "../../shared/LoadingState.js";
|
|
4
|
+
import { ErrorState as r } from "../../shared/ErrorState.js";
|
|
5
5
|
import "../../shared/index.js";
|
|
6
6
|
import { fetchSessions as i, terminateSession as a, updateSessionConfig as o } from "../../../services/aiApi.js";
|
|
7
7
|
import { useCallback as s, useEffect as c, useState as l } from "react";
|
|
@@ -99,8 +99,8 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
99
99
|
g,
|
|
100
100
|
R
|
|
101
101
|
]);
|
|
102
|
-
if (T) return /* @__PURE__ */ f(
|
|
103
|
-
if (k && !y) return /* @__PURE__ */ f(
|
|
102
|
+
if (T) return /* @__PURE__ */ f(n, { message: "Loading config..." });
|
|
103
|
+
if (k && !y) return /* @__PURE__ */ f(r, {
|
|
104
104
|
message: k,
|
|
105
105
|
onRetry: R
|
|
106
106
|
});
|
|
@@ -231,7 +231,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
231
231
|
})
|
|
232
232
|
]
|
|
233
233
|
}),
|
|
234
|
-
/* @__PURE__ */ f(
|
|
234
|
+
/* @__PURE__ */ f(t, {
|
|
235
235
|
isOpen: N,
|
|
236
236
|
onClose: () => P(!1),
|
|
237
237
|
onConfirm: V,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
|
|
3
|
+
import { LoadingState as n } from "../shared/LoadingState.js";
|
|
4
|
+
import { ErrorState as r } from "../shared/ErrorState.js";
|
|
5
5
|
import { EmptyState as i } from "../shared/EmptyState.js";
|
|
6
6
|
import { Card as a } from "../shared/Card.js";
|
|
7
7
|
import { SelectionCheckbox as o } from "../shared/SelectionCheckbox.js";
|
|
@@ -106,7 +106,7 @@ function C({ agent: C }) {
|
|
|
106
106
|
return t ? r.add(e) : r.delete(e), r;
|
|
107
107
|
});
|
|
108
108
|
};
|
|
109
|
-
return te ? /* @__PURE__ */ y(
|
|
109
|
+
return te ? /* @__PURE__ */ y(n, { message: w("vibecontrols.ai.contexts.loading", "Loading contexts...") }) : O ? /* @__PURE__ */ y(r, {
|
|
110
110
|
title: w("vibecontrols.ai.contexts.loadFailed", "Failed to load contexts"),
|
|
111
111
|
message: O,
|
|
112
112
|
onRetry: J
|
|
@@ -360,7 +360,7 @@ function C({ agent: C }) {
|
|
|
360
360
|
]
|
|
361
361
|
})
|
|
362
362
|
}),
|
|
363
|
-
/* @__PURE__ */ y(
|
|
363
|
+
/* @__PURE__ */ y(t, {
|
|
364
364
|
isOpen: H.length > 0,
|
|
365
365
|
title: H.length > 1 ? "Delete Contexts" : "Delete Context",
|
|
366
366
|
message: H.length > 1 ? `Are you sure you want to delete ${H.length} selected contexts? This action cannot be undone.` : "Are you sure you want to delete this context? This action cannot be undone.",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
|
|
3
|
+
import { useVibeControls as n } from "../../providers/VibeControlsProvider.js";
|
|
4
|
+
import { LoadingState as r } from "../shared/LoadingState.js";
|
|
5
|
+
import { ErrorState as ee } from "../shared/ErrorState.js";
|
|
6
6
|
import { EmptyState as i } from "../shared/EmptyState.js";
|
|
7
7
|
import { Card as te } from "../shared/Card.js";
|
|
8
8
|
import { SelectionCheckbox as a } from "../shared/SelectionCheckbox.js";
|
|
@@ -59,7 +59,7 @@ var m = "ai-task", h = "AI", g = "vibecontrols:ai-project-id", _ = [
|
|
|
59
59
|
}
|
|
60
60
|
}, ce = "id key title description type status priority assigneeId storyPoints dueDate labels tags metadata createdBy createdAt updatedAt";
|
|
61
61
|
function y() {
|
|
62
|
-
let y = e(), b = se(), { workspaceId: le } =
|
|
62
|
+
let y = e(), b = se(), { workspaceId: le } = n(), x = le || new URLSearchParams(window.location.search).get("workspace") || "", [S, C] = c(() => {
|
|
63
63
|
try {
|
|
64
64
|
return localStorage.getItem(d(g));
|
|
65
65
|
} catch {
|
|
@@ -250,7 +250,7 @@ function y() {
|
|
|
250
250
|
}), n;
|
|
251
251
|
});
|
|
252
252
|
}, [w]);
|
|
253
|
-
return x ? ue && w.length === 0 ? /* @__PURE__ */ f(
|
|
253
|
+
return x ? ue && w.length === 0 ? /* @__PURE__ */ f(r, { message: y("vibecontrols.ai.tasks.loading", "Loading AI tasks from PlanMagnet...") }) : D && w.length === 0 ? /* @__PURE__ */ f(ee, {
|
|
254
254
|
title: y("vibecontrols.ai.tasks.loadFailed", "Failed to load tasks"),
|
|
255
255
|
message: D,
|
|
256
256
|
action: /* @__PURE__ */ p("button", {
|
|
@@ -526,7 +526,7 @@ function y() {
|
|
|
526
526
|
]
|
|
527
527
|
})
|
|
528
528
|
}),
|
|
529
|
-
/* @__PURE__ */ f(
|
|
529
|
+
/* @__PURE__ */ f(t, {
|
|
530
530
|
isOpen: pe,
|
|
531
531
|
onClose: () => F(!1),
|
|
532
532
|
onConfirm: ye,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AITasksTab.js","names":[],"sources":["../../../src/components/ai/AITasksTab.tsx"],"sourcesContent":["/**\n * AI Tasks Tab — Kanban board backed by PlanMagnet's WorkItem model\n */\n\nimport { useState, useCallback, useEffect, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { Plus, X, GripVertical, RefreshCw, AlertCircle } from 'lucide-react';\nimport {\n Card,\n EmptyState,\n LoadingState,\n ErrorState,\n ConfirmDialog,\n SelectionCheckbox,\n} from '@/components/shared';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useTr } from '../../shared/hooks/useTr';\n\nconst AI_TASK_LABEL = 'ai-task';\nconst AI_PROJECT_KEY = 'AI';\nconst AI_PROJECT_STORAGE_KEY = 'vibecontrols:ai-project-id';\n\ntype TaskStatus = 'BACKLOG' | 'TODO' | 'IN_PROGRESS' | 'IN_REVIEW' | 'DONE';\ntype TaskPriority = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';\n\ninterface WorkItem {\n id: string;\n key: string;\n title: string;\n description?: string | null;\n type: string;\n status: TaskStatus;\n priority: TaskPriority;\n assigneeId?: string | null;\n storyPoints?: number | null;\n dueDate?: string | null;\n labels: string[];\n tags: string[];\n metadata?: Record<string, unknown> | null;\n createdBy: string;\n createdAt: string;\n updatedAt: string;\n}\n\nconst columns: { id: TaskStatus; label: string; color: string }[] = [\n { id: 'BACKLOG', label: 'Backlog', color: 'border-t-text-secondary' },\n { id: 'TODO', label: 'To Do', color: 'border-t-action-primary-bg' },\n { id: 'IN_PROGRESS', label: 'In Progress', color: 'border-t-status-warning-text' },\n { id: 'IN_REVIEW', label: 'In Review', color: 'border-t-action-primary-bg' },\n { id: 'DONE', label: 'Done', color: 'border-t-status-success-text' },\n];\n\nconst priorityLabels: Record<string, { label: string; color: string }> = {\n CRITICAL: { label: 'Critical', color: 'text-status-error-text' },\n HIGH: { label: 'High', color: 'text-status-warning-text' },\n MEDIUM: { label: 'Medium', color: 'text-action-primary-bg' },\n LOW: { label: 'Low', color: 'text-text-secondary' },\n};\n\nconst WORKITEM_FIELDS = `id key title description type status priority assigneeId storyPoints dueDate labels tags metadata createdBy createdAt updatedAt`;\n\nexport function AITasksTab() {\n const tr = useTr();\n const apolloClient = useApolloClient();\n const { workspaceId: ctxWorkspaceId } = useVibeControls();\n // Fall back to URL param if context doesn't have workspaceId\n const workspaceId =\n ctxWorkspaceId || new URLSearchParams(window.location.search).get('workspace') || '';\n\n const [projectId, setProjectId] = useState<string | null>(() => {\n try {\n return localStorage.getItem(getProfileScopedKey(AI_PROJECT_STORAGE_KEY));\n } catch {\n return null;\n }\n });\n const [items, setItems] = useState<WorkItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedTaskIds, setSelectedTaskIds] = useState<Set<string>>(new Set());\n const [bulkMoveStatus, setBulkMoveStatus] = useState<TaskStatus>('TODO');\n const [bulkDeleting, setBulkDeleting] = useState(false);\n const [bulkMoving, setBulkMoving] = useState(false);\n const [showBulkDeleteDialog, setShowBulkDeleteDialog] = useState(false);\n\n const gqlFetch = useCallback(\n async <T,>(query: string, variables?: Record<string, unknown>): Promise<T> => {\n const document = gql(query);\n const trimmed = query.trimStart();\n\n if (trimmed.startsWith('mutation')) {\n const result = await apolloClient.mutate<T>({ mutation: document, variables });\n if (result.error) throw new Error(result.error.message || 'Mutation failed');\n if (!result.data) throw new Error('Mutation returned no data');\n return result.data;\n }\n\n const result = await apolloClient.query<T>({\n query: document,\n variables,\n fetchPolicy: 'network-only',\n });\n if (result.error) throw new Error(result.error.message || 'Query failed');\n if (!result.data) throw new Error('Query returned no data');\n return result.data;\n },\n [apolloClient]\n );\n\n // ── Project auto-discovery ─────────────────────────────────────────\n useEffect(() => {\n if (projectId || !workspaceId) return;\n let cancelled = false;\n (async () => {\n try {\n const data = await gqlFetch<{\n planmagnetProjects: { items: { id: string; key: string }[] };\n }>(`query($wsId: ID!) { planmagnetProjects(workspaceId: $wsId) { items { id key } } }`, {\n wsId: workspaceId,\n });\n const existing = data.planmagnetProjects.items.find((p) => p.key === AI_PROJECT_KEY);\n if (existing && !cancelled) {\n setProjectId(existing.id);\n try {\n localStorage.setItem(getProfileScopedKey(AI_PROJECT_STORAGE_KEY), existing.id);\n } catch {\n // localStorage unavailable\n }\n return;\n }\n const createData = await gqlFetch<{ planmagnetCreateProject: { id: string } }>(\n `mutation($wsId: ID!, $input: PlanmagnetCreateProjectInput!) { planmagnetCreateProject(workspaceId: $wsId, input: $input) { id } }`,\n {\n wsId: workspaceId,\n input: {\n name: 'AI Tasks',\n key: AI_PROJECT_KEY,\n ownerId: 'system',\n methodology: 'KANBAN',\n tags: [AI_TASK_LABEL],\n },\n }\n );\n if (createData.planmagnetCreateProject.id && !cancelled) {\n setProjectId(createData.planmagnetCreateProject.id);\n try {\n localStorage.setItem(\n getProfileScopedKey(AI_PROJECT_STORAGE_KEY),\n createData.planmagnetCreateProject.id\n );\n } catch {\n // localStorage unavailable\n }\n }\n } catch (err) {\n console.error('Failed to find/create AI project:', err);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [workspaceId, projectId, apolloClient]);\n\n // ── Fetch tasks ────────────────────────────────────────────────────\n const fetchTasks = useCallback(async () => {\n if (!workspaceId) return;\n setLoading(true);\n setError(null);\n try {\n const data = await gqlFetch<{\n planmagnetWorkItems: { items: WorkItem[]; totalCount: number };\n }>(\n `query($wsId: ID!, $filter: PlanmagnetWorkItemFilter, $pagination: PlanmagnetPaginationInput) {\n planmagnetWorkItems(workspaceId: $wsId, filter: $filter, pagination: $pagination) {\n items { ${WORKITEM_FIELDS} }\n totalCount\n }\n }`,\n { wsId: workspaceId, filter: { type: 'TASK' }, pagination: { first: 200 } }\n );\n const all = data.planmagnetWorkItems.items ?? [];\n setItems(\n all.filter((i) => i.labels?.includes(AI_TASK_LABEL) || i.tags?.includes(AI_TASK_LABEL))\n );\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load tasks');\n } finally {\n setLoading(false);\n }\n }, [workspaceId, apolloClient]);\n\n useEffect(() => {\n fetchTasks();\n }, [fetchTasks]);\n\n const selectedTasks = useMemo(\n () => items.filter((item) => selectedTaskIds.has(item.id)),\n [items, selectedTaskIds]\n );\n const allVisibleSelected =\n items.length > 0 && items.every((item) => selectedTaskIds.has(item.id));\n const partiallySelected =\n items.some((item) => selectedTaskIds.has(item.id)) && !allVisibleSelected;\n\n // ── Create ─────────────────────────────────────────────────────────\n const [showCreate, setShowCreate] = useState(false);\n const [newTitle, setNewTitle] = useState('');\n const [newDescription, setNewDescription] = useState('');\n const [newStatus, setNewStatus] = useState<TaskStatus>('BACKLOG');\n const [newPriority, setNewPriority] = useState<TaskPriority>('MEDIUM');\n const [creating, setCreating] = useState(false);\n\n const handleCreate = async () => {\n if (!newTitle.trim() || !workspaceId || !projectId) return;\n setCreating(true);\n try {\n await gqlFetch(\n `mutation($wsId: ID!, $input: PlanmagnetCreateWorkItemInput!) { planmagnetCreateWorkItem(workspaceId: $wsId, input: $input) { id } }`,\n {\n wsId: workspaceId,\n input: {\n title: newTitle.trim(),\n description: newDescription.trim() || undefined,\n type: 'TASK',\n status: newStatus,\n priority: newPriority,\n labels: [AI_TASK_LABEL],\n projectId,\n },\n }\n );\n setNewTitle('');\n setNewDescription('');\n setNewStatus('BACKLOG');\n setNewPriority('MEDIUM');\n setShowCreate(false);\n fetchTasks();\n } catch (err) {\n console.error('Failed to create task:', err);\n } finally {\n setCreating(false);\n }\n };\n\n // ── Move (drag-drop status change) ─────────────────────────────────\n const [draggedId, setDraggedId] = useState<string | null>(null);\n\n const handleStatusChange = useCallback(\n async (taskId: string, targetStatus: TaskStatus) => {\n // Optimistic update\n setItems((prev) => prev.map((i) => (i.id === taskId ? { ...i, status: targetStatus } : i)));\n try {\n await gqlFetch(\n 'mutation($id: ID!, $input: PlanmagnetUpdateWorkItemInput!) { planmagnetUpdateWorkItem(id: $id, input: $input) { id } }',\n { id: taskId, input: { status: targetStatus } }\n );\n } catch (err) {\n console.error('Failed to move task:', err);\n fetchTasks(); // revert on failure\n }\n },\n [fetchTasks, gqlFetch]\n );\n\n const handleDrop = useCallback(\n (targetStatus: TaskStatus) => {\n if (!draggedId) return;\n const item = items.find((i) => i.id === draggedId);\n setDraggedId(null);\n if (!item || item.status === targetStatus) return;\n handleStatusChange(draggedId, targetStatus);\n },\n [draggedId, items, handleStatusChange]\n );\n\n // ── Delete ─────────────────────────────────────────────────────────\n const handleDelete = useCallback(\n async (id: string) => {\n setItems((prev) => prev.filter((i) => i.id !== id)); // optimistic\n try {\n await gqlFetch('mutation($id: ID!) { planmagnetDeleteWorkItem(id: $id) }', { id });\n } catch (err) {\n console.error('Failed to delete task:', err);\n fetchTasks(); // revert\n }\n },\n [fetchTasks, gqlFetch]\n );\n\n const handleBulkDelete = useCallback(async () => {\n if (selectedTasks.length === 0) return;\n setBulkDeleting(true);\n try {\n await Promise.allSettled(\n selectedTasks.map((task) =>\n gqlFetch('mutation($id: ID!) { planmagnetDeleteWorkItem(id: $id) }', { id: task.id })\n )\n );\n setSelectedTaskIds(new Set());\n setShowBulkDeleteDialog(false);\n await fetchTasks();\n } catch (err) {\n console.error('Failed to bulk delete tasks:', err);\n } finally {\n setBulkDeleting(false);\n }\n }, [fetchTasks, gqlFetch, selectedTasks]);\n\n const handleBulkMove = useCallback(async () => {\n if (selectedTasks.length === 0) return;\n setBulkMoving(true);\n try {\n setItems((prev) =>\n prev.map((item) =>\n selectedTaskIds.has(item.id) ? { ...item, status: bulkMoveStatus } : item\n )\n );\n await Promise.allSettled(\n selectedTasks.map((task) =>\n gqlFetch(\n 'mutation($id: ID!, $input: PlanmagnetUpdateWorkItemInput!) { planmagnetUpdateWorkItem(id: $id, input: $input) { id } }',\n { id: task.id, input: { status: bulkMoveStatus } }\n )\n )\n );\n setSelectedTaskIds(new Set());\n await fetchTasks();\n } catch (err) {\n console.error('Failed to bulk move tasks:', err);\n fetchTasks();\n } finally {\n setBulkMoving(false);\n }\n }, [bulkMoveStatus, fetchTasks, gqlFetch, selectedTaskIds, selectedTasks]);\n\n const toggleTaskSelection = useCallback((taskId: string, checked: boolean) => {\n setSelectedTaskIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(taskId);\n } else {\n next.delete(taskId);\n }\n return next;\n });\n }, []);\n\n const toggleAllVisibleTasks = useCallback(\n (checked: boolean) => {\n setSelectedTaskIds((prev) => {\n const next = new Set(prev);\n items.forEach((item) => {\n if (checked) {\n next.add(item.id);\n } else {\n next.delete(item.id);\n }\n });\n return next;\n });\n },\n [items]\n );\n\n const clearSelection = () => setSelectedTaskIds(new Set());\n\n // ── Render ─────────────────────────────────────────────────────────\n if (!workspaceId) {\n return (\n <EmptyState\n icon={<AlertCircle className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.tasks.noWorkspace', 'No workspace selected')}\n description={tr(\n 'vibecontrols.ai.tasks.noWorkspaceDesc',\n 'Select a workspace to manage AI tasks'\n )}\n />\n );\n }\n\n if (loading && items.length === 0) {\n return (\n <LoadingState\n message={tr('vibecontrols.ai.tasks.loading', 'Loading AI tasks from PlanMagnet...')}\n />\n );\n }\n\n if (error && items.length === 0) {\n return (\n <ErrorState\n title={tr('vibecontrols.ai.tasks.loadFailed', 'Failed to load tasks')}\n message={error}\n action={\n <button\n onClick={fetchTasks}\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 text-sm\"\n >\n <RefreshCw className=\"w-4 h-4\" />\n {tr('vibecontrols.ai.tasks.retry', 'Retry')}\n </button>\n }\n />\n );\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Toolbar */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-2\">\n <p className=\"text-sm text-text-secondary\">\n {items.length} task{items.length !== 1 ? 's' : ''}\n </p>\n <button\n onClick={fetchTasks}\n className=\"p-1 hover:bg-bg-sunken rounded-md text-text-secondary hover:text-text-primary transition-colors\"\n title=\"Refresh\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n </button>\n </div>\n <button\n onClick={() => setShowCreate(true)}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm text-action-primary-text transition-colors hover:bg-action-primary-bg-hover sm:w-auto\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibecontrols.ai.tasks.createTask', 'Create Task')}\n </button>\n </div>\n\n {items.length > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleTasks}\n ariaLabel=\"Select all visible AI tasks\"\n />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('vibecontrols.ai.tasks.selectAllVisible', 'Select all visible')}\n </span>\n </div>\n {selectedTaskIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('vibecontrols.ai.tasks.clearSelection', 'Clear selection')}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedTaskIds.size} {tr('vibecontrols.ai.tasks.selected', 'selected')}\n </span>\n <select\n value={bulkMoveStatus}\n onChange={(event) => setBulkMoveStatus(event.target.value as TaskStatus)}\n className=\"rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {columns.map((column) => (\n <option key={column.id} value={column.id}>\n Move to {column.label}\n </option>\n ))}\n </select>\n <button\n onClick={handleBulkMove}\n disabled={selectedTasks.length === 0 || bulkMoving}\n className=\"rounded-md border border-action-primary-bg/40 px-3 py-2 text-sm font-medium text-action-primary-bg hover:bg-action-primary-bg/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr('vibecontrols.ai.tasks.moveSelected', 'Move Selected')}\n {selectedTasks.length > 0 ? ` (${selectedTasks.length})` : ''}\n </button>\n <button\n onClick={() => setShowBulkDeleteDialog(true)}\n disabled={selectedTasks.length === 0 || bulkDeleting}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr('vibecontrols.ai.tasks.deleteSelected', 'Delete Selected')}\n {selectedTasks.length > 0 ? ` (${selectedTasks.length})` : ''}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Kanban Board */}\n {items.length === 0 ? (\n <EmptyState\n icon={<GripVertical className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.tasks.emptyTitle', 'No AI tasks')}\n description={tr(\n 'vibecontrols.ai.tasks.emptyDescription',\n 'Create tasks to track and organize your AI vibecoding work. Tasks are stored in PlanMagnet.'\n )}\n action={\n <button\n onClick={() => setShowCreate(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 <Plus className=\"w-4 h-4\" />\n {tr('vibecontrols.ai.tasks.createTask', 'Create Task')}\n </button>\n }\n />\n ) : (\n <div className=\"flex gap-3 overflow-x-auto pb-2\">\n {columns.map((col) => {\n const colItems = items.filter((i) => i.status === col.id);\n return (\n <div\n key={col.id}\n className={`flex-shrink-0 w-56 bg-bg-sunken rounded-lg border-t-2 ${col.color}`}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n e.preventDefault();\n handleDrop(col.id);\n }}\n >\n <div className=\"px-3 py-2 flex items-center justify-between\">\n <h4 className=\"text-xs font-semibold text-text-primary uppercase tracking-wide\">\n {col.label}\n </h4>\n <span className=\"text-xs text-text-secondary bg-bg-surface rounded-full px-1.5 py-0.5\">\n {colItems.length}\n </span>\n </div>\n <div className=\"px-2 pb-2 space-y-2 min-h-[100px]\">\n {colItems.map((item) => (\n <Card\n key={item.id}\n className=\"p-0 cursor-grab active:cursor-grabbing\"\n padding=\"none\"\n >\n <div draggable onDragStart={() => setDraggedId(item.id)} className=\"p-2\">\n <div className=\"flex items-start justify-between gap-1\">\n <div className=\"flex items-start gap-2 min-w-0 flex-1\">\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedTaskIds.has(item.id)}\n onChange={(checked) => toggleTaskSelection(item.id, checked)}\n ariaLabel={`Select task ${item.title}`}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n {item.key && (\n <span className=\"text-[10px] font-mono text-text-secondary\">\n {item.key}\n </span>\n )}\n <span className=\"block text-sm font-medium text-text-primary line-clamp-2\">\n {item.title}\n </span>\n </div>\n </div>\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(item.id);\n }}\n className=\"p-0.5 hover:bg-status-error-bg rounded flex-shrink-0\"\n >\n <X className=\"w-3 h-3 text-text-secondary hover:text-status-error-text\" />\n </button>\n </div>\n <div className=\"flex items-center gap-1.5 mt-1.5\">\n {item.priority && priorityLabels[item.priority] && (\n <span\n className={`text-[10px] font-medium ${priorityLabels[item.priority].color}`}\n >\n {priorityLabels[item.priority].label}\n </span>\n )}\n {item.storyPoints != null && (\n <span className=\"text-[10px] text-text-secondary bg-bg-surface rounded px-1\">\n {item.storyPoints}pt\n </span>\n )}\n </div>\n </div>\n </Card>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Create Task Dialog */}\n {showCreate && (\n <div\n className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\"\n onClick={() => setShowCreate(false)}\n >\n <div\n className=\"bg-bg-surface border border-border-default rounded-lg shadow-xl w-full max-w-sm p-6\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.ai.tasks.newAITask', 'New AI Task')}\n </h3>\n <button\n onClick={() => setShowCreate(false)}\n className=\"p-1 hover:bg-bg-sunken rounded-md\"\n >\n <X className=\"w-4 h-4 text-text-secondary\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.tasks.title', 'Title')}\n </label>\n <input\n type=\"text\"\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong\"\n placeholder={tr('vibecontrols.ai.tasks.titlePlaceholder', 'Task title')}\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) handleCreate();\n }}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.tasks.description', 'Description')}\n </label>\n <textarea\n value={newDescription}\n onChange={(e) => setNewDescription(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong resize-none\"\n placeholder={tr(\n 'vibecontrols.ai.tasks.descriptionPlaceholder',\n 'Optional description'\n )}\n rows={3}\n />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Status</label>\n <select\n value={newStatus}\n onChange={(e) => setNewStatus(e.target.value as TaskStatus)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {columns.map((c) => (\n <option key={c.id} value={c.id}>\n {c.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Priority\n </label>\n <select\n value={newPriority}\n onChange={(e) => setNewPriority(e.target.value as TaskPriority)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n <option value=\"CRITICAL\">Critical</option>\n <option value=\"HIGH\">High</option>\n <option value=\"MEDIUM\">Medium</option>\n <option value=\"LOW\">Low</option>\n </select>\n </div>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n onClick={() => setShowCreate(false)}\n className=\"px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!newTitle.trim() || creating || !projectId}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creating ? 'Creating...' : 'Create'}\n </button>\n </div>\n </div>\n </div>\n )}\n\n <ConfirmDialog\n isOpen={showBulkDeleteDialog}\n onClose={() => setShowBulkDeleteDialog(false)}\n onConfirm={handleBulkDelete}\n title=\"Delete AI Tasks\"\n message={`Delete ${selectedTasks.length} selected AI task${selectedTasks.length === 1 ? '' : 's'}? This cannot be undone.`}\n confirmLabel={bulkDeleting ? 'Deleting...' : 'Delete'}\n variant=\"danger\"\n isLoading={bulkDeleting}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,IAAM,IAAgB,WAChB,IAAiB,MACjB,IAAyB,8BAwBzB,IAA8D;CAClE;EAAE,IAAI;EAAW,OAAO;EAAW,OAAO;EAA2B;CACrE;EAAE,IAAI;EAAQ,OAAO;EAAS,OAAO;EAA8B;CACnE;EAAE,IAAI;EAAe,OAAO;EAAe,OAAO;EAAgC;CAClF;EAAE,IAAI;EAAa,OAAO;EAAa,OAAO;EAA8B;CAC5E;EAAE,IAAI;EAAQ,OAAO;EAAQ,OAAO;EAAgC;CACrE,EAEK,IAAmE;CACvE,UAAU;EAAE,OAAO;EAAY,OAAO;EAA0B;CAChE,MAAM;EAAE,OAAO;EAAQ,OAAO;EAA4B;CAC1D,QAAQ;EAAE,OAAO;EAAU,OAAO;EAA0B;CAC5D,KAAK;EAAE,OAAO;EAAO,OAAO;EAAuB;CACpD,EAEK,KAAkB;AAExB,SAAgB,IAAa;CAC3B,IAAM,IAAK,GAAO,EACZ,IAAe,IAAiB,EAChC,EAAE,aAAa,OAAmB,GAAiB,EAEnD,IACJ,MAAkB,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAAC,IAAI,YAAY,IAAI,IAE9E,CAAC,GAAW,KAAgB,QAA8B;AAC9D,MAAI;AACF,UAAO,aAAa,QAAQ,EAAoB,EAAuB,CAAC;UAClE;AACN,UAAO;;GAET,EACI,CAAC,GAAO,KAAY,EAAqB,EAAE,CAAC,EAC5C,CAAC,IAAS,KAAc,EAAS,GAAK,EACtC,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAiB,KAAsB,kBAAsB,IAAI,KAAK,CAAC,EACxE,CAAC,GAAgB,MAAqB,EAAqB,OAAO,EAClE,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,IAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,IAAsB,KAA2B,EAAS,GAAM,EAEjE,IAAW,EACf,OAAW,GAAe,MAAoD;EAC5E,IAAM,IAAW,GAAI,EAAM;AAG3B,MAFgB,EAAM,WAAW,CAErB,WAAW,WAAW,EAAE;GAClC,IAAM,IAAS,MAAM,EAAa,OAAU;IAAE,UAAU;IAAU;IAAW,CAAC;AAC9E,OAAI,EAAO,MAAO,OAAU,MAAM,EAAO,MAAM,WAAW,kBAAkB;AAC5E,OAAI,CAAC,EAAO,KAAM,OAAU,MAAM,4BAA4B;AAC9D,UAAO,EAAO;;EAGhB,IAAM,IAAS,MAAM,EAAa,MAAS;GACzC,OAAO;GACP;GACA,aAAa;GACd,CAAC;AACF,MAAI,EAAO,MAAO,OAAU,MAAM,EAAO,MAAM,WAAW,eAAe;AACzE,MAAI,CAAC,EAAO,KAAM,OAAU,MAAM,yBAAyB;AAC3D,SAAO,EAAO;IAEhB,CAAC,EAAa,CACf;AAGD,SAAgB;AACd,MAAI,KAAa,CAAC,EAAa;EAC/B,IAAI,IAAY;AA8ChB,UA7CC,YAAY;AACX,OAAI;IAMF,IAAM,KALO,MAAM,EAEhB,qFAAqF,EACtF,MAAM,GACP,CAAC,EACoB,mBAAmB,MAAM,MAAM,MAAM,EAAE,QAAQ,EAAe;AACpF,QAAI,KAAY,CAAC,GAAW;AAC1B,OAAa,EAAS,GAAG;AACzB,SAAI;AACF,mBAAa,QAAQ,EAAoB,EAAuB,EAAE,EAAS,GAAG;aACxE;AAGR;;IAEF,IAAM,IAAa,MAAM,EACvB,qIACA;KACE,MAAM;KACN,OAAO;MACL,MAAM;MACN,KAAK;MACL,SAAS;MACT,aAAa;MACb,MAAM,CAAC,EAAc;MACtB;KACF,CACF;AACD,QAAI,EAAW,wBAAwB,MAAM,CAAC,GAAW;AACvD,OAAa,EAAW,wBAAwB,GAAG;AACnD,SAAI;AACF,mBAAa,QACX,EAAoB,EAAuB,EAC3C,EAAW,wBAAwB,GACpC;aACK;;YAIH,GAAK;AACZ,YAAQ,MAAM,qCAAqC,EAAI;;MAEvD,QACS;AACX,OAAY;;IAEb;EAAC;EAAa;EAAW;EAAa,CAAC;CAG1C,IAAM,IAAa,EAAY,YAAY;AACpC,SAEL;GADA,EAAW,GAAK,EAChB,EAAS,KAAK;AACd,OAAI;AAaF,QAZa,MAAM,EAGjB;;sBAEc,GAAgB;;;YAI9B;KAAE,MAAM;KAAa,QAAQ,EAAE,MAAM,QAAQ;KAAE,YAAY,EAAE,OAAO,KAAK;KAAE,CAC5E,EACgB,oBAAoB,SAAS,EAAE,EAE1C,QAAQ,MAAM,EAAE,QAAQ,SAAS,EAAc,IAAI,EAAE,MAAM,SAAS,EAAc,CAAC,CACxF;YACM,GAAK;AACZ,MAAS,aAAe,QAAQ,EAAI,UAAU,uBAAuB;aAC7D;AACR,MAAW,GAAM;;;IAElB,CAAC,GAAa,EAAa,CAAC;AAE/B,SAAgB;AACd,KAAY;IACX,CAAC,EAAW,CAAC;CAEhB,IAAM,IAAgB,SACd,EAAM,QAAQ,MAAS,EAAgB,IAAI,EAAK,GAAG,CAAC,EAC1D,CAAC,GAAO,EAAgB,CACzB,EACK,IACJ,EAAM,SAAS,KAAK,EAAM,OAAO,MAAS,EAAgB,IAAI,EAAK,GAAG,CAAC,EACnE,KACJ,EAAM,MAAM,MAAS,EAAgB,IAAI,EAAK,GAAG,CAAC,IAAI,CAAC,GAGnD,CAAC,IAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAgB,KAAqB,EAAS,GAAG,EAClD,CAAC,GAAW,KAAgB,EAAqB,UAAU,EAC3D,CAAC,GAAa,KAAkB,EAAuB,SAAS,EAChE,CAAC,GAAU,KAAe,EAAS,GAAM,EAEzC,IAAe,YAAY;AAC3B,SAAC,EAAS,MAAM,IAAI,CAAC,KAAe,CAAC,IACzC;KAAY,GAAK;AACjB,OAAI;AAqBF,IApBA,MAAM,EACJ,uIACA;KACE,MAAM;KACN,OAAO;MACL,OAAO,EAAS,MAAM;MACtB,aAAa,EAAe,MAAM,IAAI,KAAA;MACtC,MAAM;MACN,QAAQ;MACR,UAAU;MACV,QAAQ,CAAC,EAAc;MACvB;MACD;KACF,CACF,EACD,EAAY,GAAG,EACf,EAAkB,GAAG,EACrB,EAAa,UAAU,EACvB,EAAe,SAAS,EACxB,EAAc,GAAM,EACpB,GAAY;YACL,GAAK;AACZ,YAAQ,MAAM,0BAA0B,EAAI;aACpC;AACR,MAAY,GAAM;;;IAKhB,CAAC,GAAW,MAAgB,EAAwB,KAAK,EAEzD,IAAqB,EACzB,OAAO,GAAgB,MAA6B;AAElD,KAAU,MAAS,EAAK,KAAK,MAAO,EAAE,OAAO,IAAS;GAAE,GAAG;GAAG,QAAQ;GAAc,GAAG,EAAG,CAAC;AAC3F,MAAI;AACF,SAAM,EACJ,0HACA;IAAE,IAAI;IAAQ,OAAO,EAAE,QAAQ,GAAc;IAAE,CAChD;WACM,GAAK;AAEZ,GADA,QAAQ,MAAM,wBAAwB,EAAI,EAC1C,GAAY;;IAGhB,CAAC,GAAY,EAAS,CACvB,EAEK,KAAa,GAChB,MAA6B;AAC5B,MAAI,CAAC,EAAW;EAChB,IAAM,IAAO,EAAM,MAAM,MAAM,EAAE,OAAO,EAAU;AAClD,KAAa,KAAK,EACd,GAAC,KAAQ,EAAK,WAAW,MAC7B,EAAmB,GAAW,EAAa;IAE7C;EAAC;EAAW;EAAO;EAAmB,CACvC,EAGK,KAAe,EACnB,OAAO,MAAe;AACpB,KAAU,MAAS,EAAK,QAAQ,MAAM,EAAE,OAAO,EAAG,CAAC;AACnD,MAAI;AACF,SAAM,EAAS,4DAA4D,EAAE,OAAI,CAAC;WAC3E,GAAK;AAEZ,GADA,QAAQ,MAAM,0BAA0B,EAAI,EAC5C,GAAY;;IAGhB,CAAC,GAAY,EAAS,CACvB,EAEK,KAAmB,EAAY,YAAY;AAC3C,QAAc,WAAW,GAC7B;KAAgB,GAAK;AACrB,OAAI;AAQF,IAPA,MAAM,QAAQ,WACZ,EAAc,KAAK,MACjB,EAAS,4DAA4D,EAAE,IAAI,EAAK,IAAI,CAAC,CACtF,CACF,EACD,kBAAmB,IAAI,KAAK,CAAC,EAC7B,EAAwB,GAAM,EAC9B,MAAM,GAAY;YACX,GAAK;AACZ,YAAQ,MAAM,gCAAgC,EAAI;aAC1C;AACR,MAAgB,GAAM;;;IAEvB;EAAC;EAAY;EAAU;EAAc,CAAC,EAEnC,KAAiB,EAAY,YAAY;AACzC,QAAc,WAAW,GAC7B;KAAc,GAAK;AACnB,OAAI;AAeF,IAdA,GAAU,MACR,EAAK,KAAK,MACR,EAAgB,IAAI,EAAK,GAAG,GAAG;KAAE,GAAG;KAAM,QAAQ;KAAgB,GAAG,EACtE,CACF,EACD,MAAM,QAAQ,WACZ,EAAc,KAAK,MACjB,EACE,0HACA;KAAE,IAAI,EAAK;KAAI,OAAO,EAAE,QAAQ,GAAgB;KAAE,CACnD,CACF,CACF,EACD,kBAAmB,IAAI,KAAK,CAAC,EAC7B,MAAM,GAAY;YACX,GAAK;AAEZ,IADA,QAAQ,MAAM,8BAA8B,EAAI,EAChD,GAAY;aACJ;AACR,MAAc,GAAM;;;IAErB;EAAC;EAAgB;EAAY;EAAU;EAAiB;EAAc,CAAC,EAEpE,KAAsB,GAAa,GAAgB,MAAqB;AAC5E,KAAoB,MAAS;GAC3B,IAAM,IAAO,IAAI,IAAI,EAAK;AAM1B,UALI,IACF,EAAK,IAAI,EAAO,GAEhB,EAAK,OAAO,EAAO,EAEd;IACP;IACD,EAAE,CAAC,EAEA,KAAwB,GAC3B,MAAqB;AACpB,KAAoB,MAAS;GAC3B,IAAM,IAAO,IAAI,IAAI,EAAK;AAQ1B,UAPA,EAAM,SAAS,MAAS;AACtB,IAAI,IACF,EAAK,IAAI,EAAK,GAAG,GAEjB,EAAK,OAAO,EAAK,GAAG;KAEtB,EACK;IACP;IAEJ,CAAC,EAAM,CACR;AA4CD,QAvCK,IAaD,MAAW,EAAM,WAAW,IAE5B,kBAAC,GAAD,EACE,SAAS,EAAG,iCAAiC,sCAAsC,EACnF,CAAA,GAIF,KAAS,EAAM,WAAW,IAE1B,kBAAC,GAAD;EACE,OAAO,EAAG,oCAAoC,uBAAuB;EACrE,SAAS;EACT,QACE,kBAAC,UAAD;GACE,SAAS;GACT,WAAU;aAFZ,CAIE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,EAAG,+BAA+B,QAAQ,CACpC;;EAEX,CAAA,GAKJ,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAM;OAAO;OAAM,EAAM,WAAW,IAAU,KAAN;OACvC;SACJ,kBAAC,UAAD;MACE,SAAS;MACT,WAAU;MACV,OAAM;gBAEN,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA;MAC9B,CAAA,CACL;QACN,kBAAC,UAAD;KACE,eAAe,EAAc,GAAK;KAClC,WAAU;eAFZ,CAIE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAG,oCAAoC,cAAc,CAC/C;OACL;;GAEL,EAAM,SAAS,KACd,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,SAAS;QACT,eAAe;QACf,UAAU;QACV,WAAU;QACV,CAAA,EACF,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,0CAA0C,qBAAqB;QAC9D,CAAA,CACH;UACL,EAAgB,OAAO,KACtB,kBAAC,UAAD;OACE,eApFa,kBAAmB,IAAI,KAAK,CAAC;OAqF1C,WAAU;iBAET,EAAG,wCAAwC,kBAAkB;OACvD,CAAA,CAEP;SAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACG,EAAgB;SAAK;SAAE,EAAG,kCAAkC,WAAW;SACnE;;OACP,kBAAC,UAAD;QACE,OAAO;QACP,WAAW,MAAU,GAAkB,EAAM,OAAO,MAAoB;QACxE,WAAU;kBAET,EAAQ,KAAK,MACZ,kBAAC,UAAD;SAAwB,OAAO,EAAO;mBAAtC,CAA0C,YAC/B,EAAO,MACT;WAFI,EAAO,GAEX,CACT;QACK,CAAA;OACT,kBAAC,UAAD;QACE,SAAS;QACT,UAAU,EAAc,WAAW,KAAK;QACxC,WAAU;kBAHZ,CAKG,EAAG,sCAAsC,gBAAgB,EACzD,EAAc,SAAS,IAAI,KAAK,EAAc,OAAO,KAAK,GACpD;;OACT,kBAAC,UAAD;QACE,eAAe,EAAwB,GAAK;QAC5C,UAAU,EAAc,WAAW,KAAK;QACxC,WAAU;kBAHZ,CAKG,EAAG,wCAAwC,kBAAkB,EAC7D,EAAc,SAAS,IAAI,KAAK,EAAc,OAAO,KAAK,GACpD;;OACL;QACF;;IACF,CAAA;GAIP,EAAM,WAAW,IAChB,kBAAC,GAAD;IACE,MAAM,kBAAC,IAAD,EAAc,WAAU,+BAAgC,CAAA;IAC9D,OAAO,EAAG,oCAAoC,cAAc;IAC5D,aAAa,EACX,0CACA,8FACD;IACD,QACE,kBAAC,UAAD;KACE,eAAe,EAAc,GAAK;KAClC,WAAU;eAFZ,CAIE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAG,oCAAoC,cAAc,CAC/C;;IAEX,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,MAAQ;KACpB,IAAM,IAAW,EAAM,QAAQ,MAAM,EAAE,WAAW,EAAI,GAAG;AACzD,YACE,kBAAC,OAAD;MAEE,WAAW,yDAAyD,EAAI;MACxE,aAAa,MAAM,EAAE,gBAAgB;MACrC,SAAS,MAAM;AAEb,OADA,EAAE,gBAAgB,EAClB,GAAW,EAAI,GAAG;;gBANtB,CASE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA,EACL,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAS;QACL,CAAA,CACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAS,KAAK,MACb,kBAAC,IAAD;QAEE,WAAU;QACV,SAAQ;kBAER,kBAAC,OAAD;SAAK,WAAA;SAAU,mBAAmB,GAAa,EAAK,GAAG;SAAE,WAAU;mBAAnE,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,UAAU,MAAU,EAAM,iBAAiB;sBAC9C,kBAAC,GAAD;aACE,SAAS,EAAgB,IAAI,EAAK,GAAG;aACrC,WAAW,MAAY,GAAoB,EAAK,IAAI,EAAQ;aAC5D,WAAW,eAAe,EAAK;aAC/B,CAAA;YACE,CAAA,EACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACG,EAAK,OACJ,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAK;aACD,CAAA,EAET,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAK;aACD,CAAA,CACH;cACF;cACN,kBAAC,UAAD;WACE,UAAU,MAAM;AAEd,YADA,EAAE,iBAAiB,EACnB,GAAa,EAAK,GAAG;;WAEvB,WAAU;qBAEV,kBAAC,IAAD,EAAG,WAAU,4DAA6D,CAAA;WACnE,CAAA,CACL;aACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACG,EAAK,YAAY,EAAe,EAAK,aACpC,kBAAC,QAAD;WACE,WAAW,2BAA2B,EAAe,EAAK,UAAU;qBAEnE,EAAe,EAAK,UAAU;WAC1B,CAAA,EAER,EAAK,eAAe,QACnB,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CACG,EAAK,aAAY,KACb;aAEL;YACF;;QACD,EAlDA,EAAK,GAkDL,CACP;OACE,CAAA,CACF;QAxEC,EAAI,GAwEL;MAER;IACE,CAAA;GAIP,MACC,kBAAC,OAAD;IACE,WAAU;IACV,eAAe,EAAc,GAAM;cAEnC,kBAAC,OAAD;KACE,WAAU;KACV,UAAU,MAAM,EAAE,iBAAiB;eAFrC;MAIE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,mCAAmC,cAAc;QAClD,CAAA,EACL,kBAAC,UAAD;QACE,eAAe,EAAc,GAAM;QACnC,WAAU;kBAEV,kBAAC,IAAD,EAAG,WAAU,+BAAgC,CAAA;QACtC,CAAA,CACL;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,+BAA+B,QAAQ;SACrC,CAAA,EACR,kBAAC,SAAD;SACE,MAAK;SACL,OAAO;SACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;SAC5C,WAAU;SACV,aAAa,EAAG,0CAA0C,aAAa;SACvE,WAAA;SACA,YAAY,MAAM;AAChB,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,YAAU,GAAc;;SAEtD,CAAA,CACE,EAAA,CAAA;QACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,qCAAqC,cAAc;SACjD,CAAA,EACR,kBAAC,YAAD;SACE,OAAO;SACP,WAAW,MAAM,EAAkB,EAAE,OAAO,MAAM;SAClD,WAAU;SACV,aAAa,EACX,gDACA,uBACD;SACD,MAAM;SACN,CAAA,CACE,EAAA,CAAA;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;UAAO,WAAU;oBAAmD;UAAc,CAAA,EAClF,kBAAC,UAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAa,EAAE,OAAO,MAAoB;UAC3D,WAAU;oBAET,EAAQ,KAAK,MACZ,kBAAC,UAAD;WAAmB,OAAO,EAAE;qBACzB,EAAE;WACI,EAFI,EAAE,GAEN,CACT;UACK,CAAA,CACL,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;UAAO,WAAU;oBAAmD;UAE5D,CAAA,EACR,kBAAC,UAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAsB;UAC/D,WAAU;oBAHZ;WAKE,kBAAC,UAAD;YAAQ,OAAM;sBAAW;YAAiB,CAAA;WAC1C,kBAAC,UAAD;YAAQ,OAAM;sBAAO;YAAa,CAAA;WAClC,kBAAC,UAAD;YAAQ,OAAM;sBAAS;YAAe,CAAA;WACtC,kBAAC,UAAD;YAAQ,OAAM;sBAAM;YAAY,CAAA;WACzB;YACL,EAAA,CAAA,CACF;;QACF;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,eAAe,EAAc,GAAM;QACnC,WAAU;kBACX;QAEQ,CAAA,EACT,kBAAC,UAAD;QACE,SAAS;QACT,UAAU,CAAC,EAAS,MAAM,IAAI,KAAY,CAAC;QAC3C,WAAU;kBAET,IAAW,gBAAgB;QACrB,CAAA,CACL;;MACF;;IACF,CAAA;GAGR,kBAAC,IAAD;IACE,QAAQ;IACR,eAAe,EAAwB,GAAM;IAC7C,WAAW;IACX,OAAM;IACN,SAAS,UAAU,EAAc,OAAO,mBAAmB,EAAc,WAAW,IAAI,KAAK,IAAI;IACjG,cAAc,IAAe,gBAAgB;IAC7C,SAAQ;IACR,WAAW;IACX,CAAA;GACE;MApVJ,kBAAC,GAAD;EACE,MAAM,kBAAC,IAAD,EAAa,WAAU,+BAAgC,CAAA;EAC7D,OAAO,EAAG,qCAAqC,wBAAwB;EACvE,aAAa,EACX,yCACA,wCACD;EACD,CAAA"}
|
|
1
|
+
{"version":3,"file":"AITasksTab.js","names":[],"sources":["../../../src/components/ai/AITasksTab.tsx"],"sourcesContent":["/**\n * AI Tasks Tab — Kanban board backed by PlanMagnet's WorkItem model\n */\n\nimport { useState, useCallback, useEffect, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { Plus, X, GripVertical, RefreshCw, AlertCircle } from 'lucide-react';\nimport {\n Card,\n EmptyState,\n LoadingState,\n ErrorState,\n ConfirmDialog,\n SelectionCheckbox,\n} from '@/components/shared';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useTr } from '../../shared/hooks/useTr';\n\nconst AI_TASK_LABEL = 'ai-task';\nconst AI_PROJECT_KEY = 'AI';\nconst AI_PROJECT_STORAGE_KEY = 'vibecontrols:ai-project-id';\n\ntype TaskStatus = 'BACKLOG' | 'TODO' | 'IN_PROGRESS' | 'IN_REVIEW' | 'DONE';\ntype TaskPriority = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';\n\ninterface WorkItem {\n id: string;\n key: string;\n title: string;\n description?: string | null;\n type: string;\n status: TaskStatus;\n priority: TaskPriority;\n assigneeId?: string | null;\n storyPoints?: number | null;\n dueDate?: string | null;\n labels: string[];\n tags: string[];\n metadata?: Record<string, unknown> | null;\n createdBy: string;\n createdAt: string;\n updatedAt: string;\n}\n\nconst columns: { id: TaskStatus; label: string; color: string }[] = [\n { id: 'BACKLOG', label: 'Backlog', color: 'border-t-text-secondary' },\n { id: 'TODO', label: 'To Do', color: 'border-t-action-primary-bg' },\n { id: 'IN_PROGRESS', label: 'In Progress', color: 'border-t-status-warning-text' },\n { id: 'IN_REVIEW', label: 'In Review', color: 'border-t-action-primary-bg' },\n { id: 'DONE', label: 'Done', color: 'border-t-status-success-text' },\n];\n\nconst priorityLabels: Record<string, { label: string; color: string }> = {\n CRITICAL: { label: 'Critical', color: 'text-status-error-text' },\n HIGH: { label: 'High', color: 'text-status-warning-text' },\n MEDIUM: { label: 'Medium', color: 'text-action-primary-bg' },\n LOW: { label: 'Low', color: 'text-text-secondary' },\n};\n\nconst WORKITEM_FIELDS = `id key title description type status priority assigneeId storyPoints dueDate labels tags metadata createdBy createdAt updatedAt`;\n\nexport function AITasksTab() {\n const tr = useTr();\n const apolloClient = useApolloClient();\n const { workspaceId: ctxWorkspaceId } = useVibeControls();\n // Fall back to URL param if context doesn't have workspaceId\n const workspaceId =\n ctxWorkspaceId || new URLSearchParams(window.location.search).get('workspace') || '';\n\n const [projectId, setProjectId] = useState<string | null>(() => {\n try {\n return localStorage.getItem(getProfileScopedKey(AI_PROJECT_STORAGE_KEY));\n } catch {\n return null;\n }\n });\n const [items, setItems] = useState<WorkItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedTaskIds, setSelectedTaskIds] = useState<Set<string>>(new Set());\n const [bulkMoveStatus, setBulkMoveStatus] = useState<TaskStatus>('TODO');\n const [bulkDeleting, setBulkDeleting] = useState(false);\n const [bulkMoving, setBulkMoving] = useState(false);\n const [showBulkDeleteDialog, setShowBulkDeleteDialog] = useState(false);\n\n const gqlFetch = useCallback(\n async <T,>(query: string, variables?: Record<string, unknown>): Promise<T> => {\n const document = gql(query);\n const trimmed = query.trimStart();\n\n if (trimmed.startsWith('mutation')) {\n const result = await apolloClient.mutate<T>({ mutation: document, variables });\n if (result.error) throw new Error(result.error.message || 'Mutation failed');\n if (!result.data) throw new Error('Mutation returned no data');\n return result.data;\n }\n\n const result = await apolloClient.query<T>({\n query: document,\n variables,\n fetchPolicy: 'network-only',\n });\n if (result.error) throw new Error(result.error.message || 'Query failed');\n if (!result.data) throw new Error('Query returned no data');\n return result.data;\n },\n [apolloClient]\n );\n\n // ── Project auto-discovery ─────────────────────────────────────────\n useEffect(() => {\n if (projectId || !workspaceId) return;\n let cancelled = false;\n (async () => {\n try {\n const data = await gqlFetch<{\n planmagnetProjects: { items: { id: string; key: string }[] };\n }>(`query($wsId: ID!) { planmagnetProjects(workspaceId: $wsId) { items { id key } } }`, {\n wsId: workspaceId,\n });\n const existing = data.planmagnetProjects.items.find((p) => p.key === AI_PROJECT_KEY);\n if (existing && !cancelled) {\n setProjectId(existing.id);\n try {\n localStorage.setItem(getProfileScopedKey(AI_PROJECT_STORAGE_KEY), existing.id);\n } catch {\n // localStorage unavailable\n }\n return;\n }\n const createData = await gqlFetch<{ planmagnetCreateProject: { id: string } }>(\n `mutation($wsId: ID!, $input: PlanmagnetCreateProjectInput!) { planmagnetCreateProject(workspaceId: $wsId, input: $input) { id } }`,\n {\n wsId: workspaceId,\n input: {\n name: 'AI Tasks',\n key: AI_PROJECT_KEY,\n ownerId: 'system',\n methodology: 'KANBAN',\n tags: [AI_TASK_LABEL],\n },\n }\n );\n if (createData.planmagnetCreateProject.id && !cancelled) {\n setProjectId(createData.planmagnetCreateProject.id);\n try {\n localStorage.setItem(\n getProfileScopedKey(AI_PROJECT_STORAGE_KEY),\n createData.planmagnetCreateProject.id\n );\n } catch {\n // localStorage unavailable\n }\n }\n } catch (err) {\n console.error('Failed to find/create AI project:', err);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [workspaceId, projectId, apolloClient]);\n\n // ── Fetch tasks ────────────────────────────────────────────────────\n const fetchTasks = useCallback(async () => {\n if (!workspaceId) return;\n setLoading(true);\n setError(null);\n try {\n const data = await gqlFetch<{\n planmagnetWorkItems: { items: WorkItem[]; totalCount: number };\n }>(\n `query($wsId: ID!, $filter: PlanmagnetWorkItemFilter, $pagination: PlanmagnetPaginationInput) {\n planmagnetWorkItems(workspaceId: $wsId, filter: $filter, pagination: $pagination) {\n items { ${WORKITEM_FIELDS} }\n totalCount\n }\n }`,\n { wsId: workspaceId, filter: { type: 'TASK' }, pagination: { first: 200 } }\n );\n const all = data.planmagnetWorkItems.items ?? [];\n setItems(\n all.filter((i) => i.labels?.includes(AI_TASK_LABEL) || i.tags?.includes(AI_TASK_LABEL))\n );\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load tasks');\n } finally {\n setLoading(false);\n }\n }, [workspaceId, apolloClient]);\n\n useEffect(() => {\n fetchTasks();\n }, [fetchTasks]);\n\n const selectedTasks = useMemo(\n () => items.filter((item) => selectedTaskIds.has(item.id)),\n [items, selectedTaskIds]\n );\n const allVisibleSelected =\n items.length > 0 && items.every((item) => selectedTaskIds.has(item.id));\n const partiallySelected =\n items.some((item) => selectedTaskIds.has(item.id)) && !allVisibleSelected;\n\n // ── Create ─────────────────────────────────────────────────────────\n const [showCreate, setShowCreate] = useState(false);\n const [newTitle, setNewTitle] = useState('');\n const [newDescription, setNewDescription] = useState('');\n const [newStatus, setNewStatus] = useState<TaskStatus>('BACKLOG');\n const [newPriority, setNewPriority] = useState<TaskPriority>('MEDIUM');\n const [creating, setCreating] = useState(false);\n\n const handleCreate = async () => {\n if (!newTitle.trim() || !workspaceId || !projectId) return;\n setCreating(true);\n try {\n await gqlFetch(\n `mutation($wsId: ID!, $input: PlanmagnetCreateWorkItemInput!) { planmagnetCreateWorkItem(workspaceId: $wsId, input: $input) { id } }`,\n {\n wsId: workspaceId,\n input: {\n title: newTitle.trim(),\n description: newDescription.trim() || undefined,\n type: 'TASK',\n status: newStatus,\n priority: newPriority,\n labels: [AI_TASK_LABEL],\n projectId,\n },\n }\n );\n setNewTitle('');\n setNewDescription('');\n setNewStatus('BACKLOG');\n setNewPriority('MEDIUM');\n setShowCreate(false);\n fetchTasks();\n } catch (err) {\n console.error('Failed to create task:', err);\n } finally {\n setCreating(false);\n }\n };\n\n // ── Move (drag-drop status change) ─────────────────────────────────\n const [draggedId, setDraggedId] = useState<string | null>(null);\n\n const handleStatusChange = useCallback(\n async (taskId: string, targetStatus: TaskStatus) => {\n // Optimistic update\n setItems((prev) => prev.map((i) => (i.id === taskId ? { ...i, status: targetStatus } : i)));\n try {\n await gqlFetch(\n 'mutation($id: ID!, $input: PlanmagnetUpdateWorkItemInput!) { planmagnetUpdateWorkItem(id: $id, input: $input) { id } }',\n { id: taskId, input: { status: targetStatus } }\n );\n } catch (err) {\n console.error('Failed to move task:', err);\n fetchTasks(); // revert on failure\n }\n },\n [fetchTasks, gqlFetch]\n );\n\n const handleDrop = useCallback(\n (targetStatus: TaskStatus) => {\n if (!draggedId) return;\n const item = items.find((i) => i.id === draggedId);\n setDraggedId(null);\n if (!item || item.status === targetStatus) return;\n handleStatusChange(draggedId, targetStatus);\n },\n [draggedId, items, handleStatusChange]\n );\n\n // ── Delete ─────────────────────────────────────────────────────────\n const handleDelete = useCallback(\n async (id: string) => {\n setItems((prev) => prev.filter((i) => i.id !== id)); // optimistic\n try {\n await gqlFetch('mutation($id: ID!) { planmagnetDeleteWorkItem(id: $id) }', { id });\n } catch (err) {\n console.error('Failed to delete task:', err);\n fetchTasks(); // revert\n }\n },\n [fetchTasks, gqlFetch]\n );\n\n const handleBulkDelete = useCallback(async () => {\n if (selectedTasks.length === 0) return;\n setBulkDeleting(true);\n try {\n await Promise.allSettled(\n selectedTasks.map((task) =>\n gqlFetch('mutation($id: ID!) { planmagnetDeleteWorkItem(id: $id) }', { id: task.id })\n )\n );\n setSelectedTaskIds(new Set());\n setShowBulkDeleteDialog(false);\n await fetchTasks();\n } catch (err) {\n console.error('Failed to bulk delete tasks:', err);\n } finally {\n setBulkDeleting(false);\n }\n }, [fetchTasks, gqlFetch, selectedTasks]);\n\n const handleBulkMove = useCallback(async () => {\n if (selectedTasks.length === 0) return;\n setBulkMoving(true);\n try {\n setItems((prev) =>\n prev.map((item) =>\n selectedTaskIds.has(item.id) ? { ...item, status: bulkMoveStatus } : item\n )\n );\n await Promise.allSettled(\n selectedTasks.map((task) =>\n gqlFetch(\n 'mutation($id: ID!, $input: PlanmagnetUpdateWorkItemInput!) { planmagnetUpdateWorkItem(id: $id, input: $input) { id } }',\n { id: task.id, input: { status: bulkMoveStatus } }\n )\n )\n );\n setSelectedTaskIds(new Set());\n await fetchTasks();\n } catch (err) {\n console.error('Failed to bulk move tasks:', err);\n fetchTasks();\n } finally {\n setBulkMoving(false);\n }\n }, [bulkMoveStatus, fetchTasks, gqlFetch, selectedTaskIds, selectedTasks]);\n\n const toggleTaskSelection = useCallback((taskId: string, checked: boolean) => {\n setSelectedTaskIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(taskId);\n } else {\n next.delete(taskId);\n }\n return next;\n });\n }, []);\n\n const toggleAllVisibleTasks = useCallback(\n (checked: boolean) => {\n setSelectedTaskIds((prev) => {\n const next = new Set(prev);\n items.forEach((item) => {\n if (checked) {\n next.add(item.id);\n } else {\n next.delete(item.id);\n }\n });\n return next;\n });\n },\n [items]\n );\n\n const clearSelection = () => setSelectedTaskIds(new Set());\n\n // ── Render ─────────────────────────────────────────────────────────\n if (!workspaceId) {\n return (\n <EmptyState\n icon={<AlertCircle className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.tasks.noWorkspace', 'No workspace selected')}\n description={tr(\n 'vibecontrols.ai.tasks.noWorkspaceDesc',\n 'Select a workspace to manage AI tasks'\n )}\n />\n );\n }\n\n if (loading && items.length === 0) {\n return (\n <LoadingState\n message={tr('vibecontrols.ai.tasks.loading', 'Loading AI tasks from PlanMagnet...')}\n />\n );\n }\n\n if (error && items.length === 0) {\n return (\n <ErrorState\n title={tr('vibecontrols.ai.tasks.loadFailed', 'Failed to load tasks')}\n message={error}\n action={\n <button\n onClick={fetchTasks}\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 text-sm\"\n >\n <RefreshCw className=\"w-4 h-4\" />\n {tr('vibecontrols.ai.tasks.retry', 'Retry')}\n </button>\n }\n />\n );\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Toolbar */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-2\">\n <p className=\"text-sm text-text-secondary\">\n {items.length} task{items.length !== 1 ? 's' : ''}\n </p>\n <button\n onClick={fetchTasks}\n className=\"p-1 hover:bg-bg-sunken rounded-md text-text-secondary hover:text-text-primary transition-colors\"\n title=\"Refresh\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n </button>\n </div>\n <button\n onClick={() => setShowCreate(true)}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm text-action-primary-text transition-colors hover:bg-action-primary-bg-hover sm:w-auto\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibecontrols.ai.tasks.createTask', 'Create Task')}\n </button>\n </div>\n\n {items.length > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleTasks}\n ariaLabel=\"Select all visible AI tasks\"\n />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('vibecontrols.ai.tasks.selectAllVisible', 'Select all visible')}\n </span>\n </div>\n {selectedTaskIds.size > 0 && (\n <button\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('vibecontrols.ai.tasks.clearSelection', 'Clear selection')}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedTaskIds.size} {tr('vibecontrols.ai.tasks.selected', 'selected')}\n </span>\n <select\n value={bulkMoveStatus}\n onChange={(event) => setBulkMoveStatus(event.target.value as TaskStatus)}\n className=\"rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {columns.map((column) => (\n <option key={column.id} value={column.id}>\n Move to {column.label}\n </option>\n ))}\n </select>\n <button\n onClick={handleBulkMove}\n disabled={selectedTasks.length === 0 || bulkMoving}\n className=\"rounded-md border border-action-primary-bg/40 px-3 py-2 text-sm font-medium text-action-primary-bg hover:bg-action-primary-bg/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr('vibecontrols.ai.tasks.moveSelected', 'Move Selected')}\n {selectedTasks.length > 0 ? ` (${selectedTasks.length})` : ''}\n </button>\n <button\n onClick={() => setShowBulkDeleteDialog(true)}\n disabled={selectedTasks.length === 0 || bulkDeleting}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr('vibecontrols.ai.tasks.deleteSelected', 'Delete Selected')}\n {selectedTasks.length > 0 ? ` (${selectedTasks.length})` : ''}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Kanban Board */}\n {items.length === 0 ? (\n <EmptyState\n icon={<GripVertical className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.tasks.emptyTitle', 'No AI tasks')}\n description={tr(\n 'vibecontrols.ai.tasks.emptyDescription',\n 'Create tasks to track and organize your AI vibecoding work. Tasks are stored in PlanMagnet.'\n )}\n action={\n <button\n onClick={() => setShowCreate(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 <Plus className=\"w-4 h-4\" />\n {tr('vibecontrols.ai.tasks.createTask', 'Create Task')}\n </button>\n }\n />\n ) : (\n <div className=\"flex gap-3 overflow-x-auto pb-2\">\n {columns.map((col) => {\n const colItems = items.filter((i) => i.status === col.id);\n return (\n <div\n key={col.id}\n className={`flex-shrink-0 w-56 bg-bg-sunken rounded-lg border-t-2 ${col.color}`}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n e.preventDefault();\n handleDrop(col.id);\n }}\n >\n <div className=\"px-3 py-2 flex items-center justify-between\">\n <h4 className=\"text-xs font-semibold text-text-primary uppercase tracking-wide\">\n {col.label}\n </h4>\n <span className=\"text-xs text-text-secondary bg-bg-surface rounded-full px-1.5 py-0.5\">\n {colItems.length}\n </span>\n </div>\n <div className=\"px-2 pb-2 space-y-2 min-h-[100px]\">\n {colItems.map((item) => (\n <Card\n key={item.id}\n className=\"p-0 cursor-grab active:cursor-grabbing\"\n padding=\"none\"\n >\n <div draggable onDragStart={() => setDraggedId(item.id)} className=\"p-2\">\n <div className=\"flex items-start justify-between gap-1\">\n <div className=\"flex items-start gap-2 min-w-0 flex-1\">\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedTaskIds.has(item.id)}\n onChange={(checked) => toggleTaskSelection(item.id, checked)}\n ariaLabel={`Select task ${item.title}`}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n {item.key && (\n <span className=\"text-[10px] font-mono text-text-secondary\">\n {item.key}\n </span>\n )}\n <span className=\"block text-sm font-medium text-text-primary line-clamp-2\">\n {item.title}\n </span>\n </div>\n </div>\n <button\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(item.id);\n }}\n className=\"p-0.5 hover:bg-status-error-bg rounded flex-shrink-0\"\n >\n <X className=\"w-3 h-3 text-text-secondary hover:text-status-error-text\" />\n </button>\n </div>\n <div className=\"flex items-center gap-1.5 mt-1.5\">\n {item.priority && priorityLabels[item.priority] && (\n <span\n className={`text-[10px] font-medium ${priorityLabels[item.priority].color}`}\n >\n {priorityLabels[item.priority].label}\n </span>\n )}\n {item.storyPoints != null && (\n <span className=\"text-[10px] text-text-secondary bg-bg-surface rounded px-1\">\n {item.storyPoints}pt\n </span>\n )}\n </div>\n </div>\n </Card>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Create Task Dialog */}\n {showCreate && (\n <div\n className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\"\n onClick={() => setShowCreate(false)}\n >\n <div\n className=\"bg-bg-surface border border-border-default rounded-lg shadow-xl w-full max-w-sm p-6\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.ai.tasks.newAITask', 'New AI Task')}\n </h3>\n <button\n onClick={() => setShowCreate(false)}\n className=\"p-1 hover:bg-bg-sunken rounded-md\"\n >\n <X className=\"w-4 h-4 text-text-secondary\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.tasks.title', 'Title')}\n </label>\n <input\n type=\"text\"\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong\"\n placeholder={tr('vibecontrols.ai.tasks.titlePlaceholder', 'Task title')}\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) handleCreate();\n }}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.tasks.description', 'Description')}\n </label>\n <textarea\n value={newDescription}\n onChange={(e) => setNewDescription(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong resize-none\"\n placeholder={tr(\n 'vibecontrols.ai.tasks.descriptionPlaceholder',\n 'Optional description'\n )}\n rows={3}\n />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Status</label>\n <select\n value={newStatus}\n onChange={(e) => setNewStatus(e.target.value as TaskStatus)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {columns.map((c) => (\n <option key={c.id} value={c.id}>\n {c.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Priority\n </label>\n <select\n value={newPriority}\n onChange={(e) => setNewPriority(e.target.value as TaskPriority)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n <option value=\"CRITICAL\">Critical</option>\n <option value=\"HIGH\">High</option>\n <option value=\"MEDIUM\">Medium</option>\n <option value=\"LOW\">Low</option>\n </select>\n </div>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n onClick={() => setShowCreate(false)}\n className=\"px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n Cancel\n </button>\n <button\n onClick={handleCreate}\n disabled={!newTitle.trim() || creating || !projectId}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creating ? 'Creating...' : 'Create'}\n </button>\n </div>\n </div>\n </div>\n )}\n\n <ConfirmDialog\n isOpen={showBulkDeleteDialog}\n onClose={() => setShowBulkDeleteDialog(false)}\n onConfirm={handleBulkDelete}\n title=\"Delete AI Tasks\"\n message={`Delete ${selectedTasks.length} selected AI task${selectedTasks.length === 1 ? '' : 's'}? This cannot be undone.`}\n confirmLabel={bulkDeleting ? 'Deleting...' : 'Delete'}\n variant=\"danger\"\n isLoading={bulkDeleting}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
|
|
3
|
+
import { LoadingState as n } from "../shared/LoadingState.js";
|
|
4
|
+
import { ErrorState as r } from "../shared/ErrorState.js";
|
|
5
5
|
import { EmptyState as i } from "../shared/EmptyState.js";
|
|
6
6
|
import { Card as a } from "../shared/Card.js";
|
|
7
7
|
import { SelectionCheckbox as o } from "../shared/SelectionCheckbox.js";
|
|
@@ -124,7 +124,7 @@ function g({ agentId: g }) {
|
|
|
124
124
|
return t ? r.add(e) : r.delete(e), r;
|
|
125
125
|
});
|
|
126
126
|
};
|
|
127
|
-
return de ? /* @__PURE__ */ p(
|
|
127
|
+
return de ? /* @__PURE__ */ p(n, { message: _("vibecontrols.ai.templates.loading", "Loading templates...") }) : b ? /* @__PURE__ */ p(r, {
|
|
128
128
|
title: _("vibecontrols.ai.templates.loadFailed", "Failed to load templates"),
|
|
129
129
|
message: b,
|
|
130
130
|
onRetry: Y
|
|
@@ -454,7 +454,7 @@ function g({ agentId: g }) {
|
|
|
454
454
|
]
|
|
455
455
|
})
|
|
456
456
|
}),
|
|
457
|
-
/* @__PURE__ */ p(
|
|
457
|
+
/* @__PURE__ */ p(t, {
|
|
458
458
|
isOpen: F.length > 0,
|
|
459
459
|
title: F.length > 1 ? "Delete Templates" : "Delete Template",
|
|
460
460
|
message: F.length > 1 ? `Are you sure you want to delete ${F.length} selected templates? This action cannot be undone.` : "Are you sure you want to delete this template? This action cannot be undone.",
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { QuotaExhaustedDialog as t } from "../shared/QuotaExhaustedDialog.js";
|
|
3
|
+
import { isQuotaExhaustedError as n, markQuotaHandledLocally as r } from "../../utils/quotaUtils.js";
|
|
4
|
+
import { useCompileDocsSiteMutation as ee, useCreateDocsPageMutation as te, useCreateDocsSiteMutation as ne, useDeleteDocsPageMutation as re, useDeleteDocsSiteMutation as ie, useDocsContentQuery as i, useGenerateDocsSignedUrlMutation as a, useGetDocsRevisionLazyQuery as o, useGetDocsSiteQuery as s, useRollbackDocsRevisionMutation as c, useUpdateDocsPageMutation as l, useUpdateDocsSiteMutation as u, useUpdateDocsSiteVisibilityMutation as d } from "../../generated/wspace-operations.js";
|
|
5
|
+
import { useVibeNavigate as f } from "../../providers/VibeControlsProvider.js";
|
|
6
|
+
import { LoadingState as p } from "../shared/LoadingState.js";
|
|
7
|
+
import { ErrorState as m } from "../shared/ErrorState.js";
|
|
8
8
|
import "../shared/index.js";
|
|
9
|
-
import { DocsEmptyState as
|
|
10
|
-
import { DocsPreviewPanel as
|
|
11
|
-
import { DocsEditPanel as
|
|
12
|
-
import { useEffect as
|
|
13
|
-
import { AlertCircle as
|
|
9
|
+
import { DocsEmptyState as h } from "./DocsEmptyState.js";
|
|
10
|
+
import { DocsPreviewPanel as g } from "./DocsPreviewPanel.js";
|
|
11
|
+
import { DocsEditPanel as _ } from "./DocsEditPanel.js";
|
|
12
|
+
import { useEffect as v, useRef as y, useState as b } from "react";
|
|
13
|
+
import { AlertCircle as ae, X as oe } from "lucide-react";
|
|
14
14
|
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
15
|
-
import { resolveGatewayUrls as
|
|
15
|
+
import { resolveGatewayUrls as se } from "@burdenoff/fe-libs/shared/config";
|
|
16
16
|
//#region src/components/docs/DocsTabPanel.tsx
|
|
17
|
-
function w({ vibeId: w, ownerType:
|
|
18
|
-
let T = e(), E =
|
|
17
|
+
function w({ vibeId: w, ownerType: ce, ownerId: le }) {
|
|
18
|
+
let T = e(), E = ce || "VIBE", D = le || w || "", [O, k] = b("preview"), [A, j] = b(null), [M, N] = b(!1), [P, F] = b(null), [I, L] = b(""), [R, z] = b(null), B = f(), [V, H] = b(!1), { data: U, loading: W, error: G, refetch: K } = s({
|
|
19
19
|
variables: {
|
|
20
20
|
ownerType: E,
|
|
21
21
|
ownerId: D
|
|
22
22
|
},
|
|
23
23
|
skip: !D,
|
|
24
24
|
fetchPolicy: "cache-and-network"
|
|
25
|
-
}), q = U?.vibecontrolsDocsSiteByOwner ?? null, J = q?.pages || [], { data:
|
|
25
|
+
}), q = U?.vibecontrolsDocsSiteByOwner ?? null, J = q?.pages || [], { data: ue, loading: de, refetch: fe } = i({
|
|
26
26
|
variables: {
|
|
27
27
|
siteId: q?.id || "",
|
|
28
28
|
path: I
|
|
29
29
|
},
|
|
30
30
|
skip: !q?.id || !q.currentRevisionId,
|
|
31
31
|
fetchPolicy: "network-only"
|
|
32
|
-
}),
|
|
33
|
-
|
|
32
|
+
}), pe = ue?.docsContent?.html ?? null, Y = y(void 0);
|
|
33
|
+
v(() => {
|
|
34
34
|
let e = q?.currentRevisionId ?? null;
|
|
35
35
|
if (Y.current === void 0) {
|
|
36
36
|
Y.current = e;
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
e && e !== Y.current && (Y.current = e,
|
|
39
|
+
e && e !== Y.current && (Y.current = e, fe());
|
|
40
40
|
}, [q?.currentRevisionId]);
|
|
41
|
-
let
|
|
41
|
+
let me = se(), he = q?.workspaceId ? `${me.workspaceBaseUrl}/workspaces/static/${q.workspaceId}/docs/${D}/` : null, [ge, { loading: _e }] = ne(), [ve] = u(), [ye] = d(), [be, { loading: xe }] = te(), [Se] = l(), [Ce] = re(), [we] = ee(), [Te] = a(), [Ee] = c(), [De] = ie(), [Oe] = o({ fetchPolicy: "network-only" }), ke = async (e = "DOCUSAURUS") => {
|
|
42
42
|
try {
|
|
43
|
-
await
|
|
43
|
+
await ge({
|
|
44
44
|
variables: { input: {
|
|
45
45
|
ownerType: E,
|
|
46
46
|
ownerId: D,
|
|
@@ -51,21 +51,21 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
51
51
|
awaitRefetchQueries: !0
|
|
52
52
|
}), k("edit");
|
|
53
53
|
} catch (e) {
|
|
54
|
-
if (
|
|
55
|
-
H(!0);
|
|
54
|
+
if (n(e)) {
|
|
55
|
+
r(), H(!0);
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
throw e;
|
|
59
59
|
}
|
|
60
|
-
},
|
|
61
|
-
await
|
|
60
|
+
}, Ae = async (e, t) => {
|
|
61
|
+
await Se({ variables: {
|
|
62
62
|
id: e,
|
|
63
63
|
input: t
|
|
64
64
|
} });
|
|
65
|
-
},
|
|
65
|
+
}, X = async (e, t) => {
|
|
66
66
|
if (!q) return;
|
|
67
67
|
let n = J.length, r = `page-${n + 1}`;
|
|
68
|
-
await
|
|
68
|
+
await be({ variables: { input: {
|
|
69
69
|
siteId: q.id,
|
|
70
70
|
parentId: e || null,
|
|
71
71
|
slug: r,
|
|
@@ -75,13 +75,13 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
75
75
|
sidebarPosition: n,
|
|
76
76
|
category: t || null
|
|
77
77
|
} } }), await K();
|
|
78
|
-
},
|
|
79
|
-
confirm("Delete this page?") && (await
|
|
78
|
+
}, je = async (e) => {
|
|
79
|
+
confirm("Delete this page?") && (await Ce({ variables: { id: e } }), await K());
|
|
80
80
|
}, Z = async () => {
|
|
81
81
|
if (q) {
|
|
82
82
|
N(!0), F(null);
|
|
83
83
|
try {
|
|
84
|
-
let { data: e } = await
|
|
84
|
+
let { data: e } = await we({ variables: {
|
|
85
85
|
siteId: q.id,
|
|
86
86
|
publish: !0
|
|
87
87
|
} });
|
|
@@ -91,15 +91,15 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}, Q = async (e) => {
|
|
94
|
-
let { data: t } = await
|
|
94
|
+
let { data: t } = await Oe({ variables: { id: e } }), n = t?.docsRevision;
|
|
95
95
|
return n && (j(n), [
|
|
96
96
|
"SUCCEEDED",
|
|
97
97
|
"PUBLISHED",
|
|
98
98
|
"FAILED"
|
|
99
99
|
].includes(n.status) && (N(!1), (n.status === "PUBLISHED" || n.status === "SUCCEEDED") && (L(""), await K()))), n;
|
|
100
|
-
},
|
|
100
|
+
}, Me = async (e) => {
|
|
101
101
|
if (!q) return;
|
|
102
|
-
e.visibility && e.visibility !== q.visibility && await
|
|
102
|
+
e.visibility && e.visibility !== q.visibility && await ye({ variables: {
|
|
103
103
|
id: q.id,
|
|
104
104
|
visibility: e.visibility
|
|
105
105
|
} });
|
|
@@ -108,23 +108,23 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
108
108
|
provider: e.provider,
|
|
109
109
|
providerConfig: e.providerConfig
|
|
110
110
|
};
|
|
111
|
-
Object.keys(t).length > 0 && await
|
|
111
|
+
Object.keys(t).length > 0 && await ve({ variables: {
|
|
112
112
|
id: q.id,
|
|
113
113
|
input: t
|
|
114
114
|
} }), await K();
|
|
115
|
-
},
|
|
115
|
+
}, Ne = async () => {
|
|
116
116
|
if (!q?.currentRevisionId) return null;
|
|
117
117
|
try {
|
|
118
|
-
let { data: e } = await
|
|
118
|
+
let { data: e } = await Te({ variables: { siteId: q.id } });
|
|
119
119
|
return e?.generateDocsSignedUrl?.url ?? null;
|
|
120
120
|
} catch {
|
|
121
121
|
return null;
|
|
122
122
|
}
|
|
123
|
-
},
|
|
123
|
+
}, Pe = async (e) => {
|
|
124
124
|
if (q && confirm("Roll back to this revision? The current published docs will be replaced.")) {
|
|
125
125
|
z(e);
|
|
126
126
|
try {
|
|
127
|
-
await
|
|
127
|
+
await Ee({ variables: {
|
|
128
128
|
siteId: q.id,
|
|
129
129
|
revisionId: e
|
|
130
130
|
} }), await K();
|
|
@@ -132,19 +132,19 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
132
132
|
z(null);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
},
|
|
136
|
-
q && confirm("Delete this docs site and all its pages and revisions? This cannot be undone.") && (await
|
|
135
|
+
}, Fe = async () => {
|
|
136
|
+
q && confirm("Delete this docs site and all its pages and revisions? This cannot be undone.") && (await De({ variables: { id: q.id } }), await K());
|
|
137
137
|
};
|
|
138
|
-
if (W && !q) return /* @__PURE__ */ S(
|
|
139
|
-
if (G && !q) return /* @__PURE__ */ S(
|
|
138
|
+
if (W && !q) return /* @__PURE__ */ S(p, { message: T("vibecontrols.docs.tab.loading", "Loading documentation...") });
|
|
139
|
+
if (G && !q) return /* @__PURE__ */ S(m, {
|
|
140
140
|
title: T("vibecontrols.docs.tab.loadFailed", "Failed to load docs"),
|
|
141
141
|
message: G.message,
|
|
142
142
|
onRetry: () => K()
|
|
143
143
|
});
|
|
144
|
-
if (!q) return /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S(
|
|
145
|
-
onCreate:
|
|
146
|
-
loading:
|
|
147
|
-
}), /* @__PURE__ */ S(
|
|
144
|
+
if (!q) return /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S(h, {
|
|
145
|
+
onCreate: ke,
|
|
146
|
+
loading: _e
|
|
147
|
+
}), /* @__PURE__ */ S(t, {
|
|
148
148
|
isOpen: V,
|
|
149
149
|
onClose: () => H(!1),
|
|
150
150
|
onConfirm: () => {
|
|
@@ -156,7 +156,7 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
156
156
|
let $ = P ? /* @__PURE__ */ C("div", {
|
|
157
157
|
className: "flex items-center gap-2 px-4 py-2 mb-2 bg-status-danger-bg text-status-danger-text text-sm rounded-md",
|
|
158
158
|
children: [
|
|
159
|
-
/* @__PURE__ */ S(
|
|
159
|
+
/* @__PURE__ */ S(ae, { className: "w-4 h-4 shrink-0" }),
|
|
160
160
|
/* @__PURE__ */ S("span", {
|
|
161
161
|
className: "flex-1",
|
|
162
162
|
children: P
|
|
@@ -164,40 +164,40 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
164
164
|
/* @__PURE__ */ S("button", {
|
|
165
165
|
onClick: () => F(null),
|
|
166
166
|
className: "p-0.5 hover:opacity-70",
|
|
167
|
-
children: /* @__PURE__ */ S(
|
|
167
|
+
children: /* @__PURE__ */ S(oe, { className: "w-3.5 h-3.5" })
|
|
168
168
|
})
|
|
169
169
|
]
|
|
170
170
|
}) : null;
|
|
171
|
-
return O === "edit" ? /* @__PURE__ */ C(x, { children: [$, /* @__PURE__ */ S(
|
|
171
|
+
return O === "edit" ? /* @__PURE__ */ C(x, { children: [$, /* @__PURE__ */ S(_, {
|
|
172
172
|
site: q,
|
|
173
173
|
pages: J,
|
|
174
174
|
onBack: () => k("preview"),
|
|
175
|
-
onSavePage:
|
|
176
|
-
onAddPage:
|
|
177
|
-
pageAdding:
|
|
178
|
-
onDeletePage:
|
|
175
|
+
onSavePage: Ae,
|
|
176
|
+
onAddPage: X,
|
|
177
|
+
pageAdding: xe,
|
|
178
|
+
onDeletePage: je,
|
|
179
179
|
onCompile: Z,
|
|
180
|
-
onSaveSettings:
|
|
181
|
-
onRollback:
|
|
182
|
-
onDeleteSite:
|
|
180
|
+
onSaveSettings: Me,
|
|
181
|
+
onRollback: Pe,
|
|
182
|
+
onDeleteSite: Fe,
|
|
183
183
|
rollingBack: R,
|
|
184
184
|
compileRevision: A,
|
|
185
185
|
onPollRevision: Q,
|
|
186
186
|
compiling: M
|
|
187
187
|
})] }) : /* @__PURE__ */ C(x, { children: [
|
|
188
188
|
$,
|
|
189
|
-
/* @__PURE__ */ S(
|
|
189
|
+
/* @__PURE__ */ S(g, {
|
|
190
190
|
site: q,
|
|
191
191
|
pages: J,
|
|
192
192
|
selectedPageSlug: I,
|
|
193
193
|
onSelectPage: L,
|
|
194
|
-
docsBaseUrl: q.currentRevisionId ?
|
|
195
|
-
docsHtml: q.currentRevisionId ?
|
|
196
|
-
docsContentLoading:
|
|
194
|
+
docsBaseUrl: q.currentRevisionId ? he ?? null : null,
|
|
195
|
+
docsHtml: q.currentRevisionId ? pe : null,
|
|
196
|
+
docsContentLoading: de,
|
|
197
197
|
onEdit: () => k("edit"),
|
|
198
198
|
onCompile: Z,
|
|
199
199
|
onSettings: () => k("edit"),
|
|
200
|
-
onGetShareUrl:
|
|
200
|
+
onGetShareUrl: Ne,
|
|
201
201
|
onOpenFullScreen: () => {
|
|
202
202
|
B(`/${{
|
|
203
203
|
VIBE: "vibes",
|
|
@@ -209,7 +209,7 @@ function w({ vibeId: w, ownerType: se, ownerId: ce }) {
|
|
|
209
209
|
onPollRevision: Q,
|
|
210
210
|
compiling: M
|
|
211
211
|
}),
|
|
212
|
-
/* @__PURE__ */ S(
|
|
212
|
+
/* @__PURE__ */ S(t, {
|
|
213
213
|
isOpen: V,
|
|
214
214
|
onClose: () => H(!1),
|
|
215
215
|
onConfirm: () => {
|