stagent 0.6.3 → 0.7.0

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.
Files changed (123) hide show
  1. package/README.md +21 -2
  2. package/dist/cli.js +226 -1
  3. package/docs/.coverage-gaps.json +66 -16
  4. package/docs/.last-generated +1 -1
  5. package/docs/features/dashboard-kanban.md +13 -7
  6. package/docs/features/settings.md +15 -3
  7. package/docs/features/tables.md +122 -0
  8. package/docs/index.md +3 -2
  9. package/docs/journeys/developer.md +26 -16
  10. package/docs/journeys/personal-use.md +23 -9
  11. package/docs/journeys/power-user.md +40 -14
  12. package/docs/journeys/work-use.md +43 -15
  13. package/docs/manifest.json +27 -17
  14. package/package.json +3 -1
  15. package/src/app/api/chat/entities/search/route.ts +12 -3
  16. package/src/app/api/projects/[id]/route.ts +37 -0
  17. package/src/app/api/projects/__tests__/delete-project.test.ts +12 -0
  18. package/src/app/api/snapshots/[id]/restore/route.ts +62 -0
  19. package/src/app/api/snapshots/[id]/route.ts +44 -0
  20. package/src/app/api/snapshots/route.ts +54 -0
  21. package/src/app/api/snapshots/settings/route.ts +67 -0
  22. package/src/app/api/tables/[id]/charts/[chartId]/route.ts +89 -0
  23. package/src/app/api/tables/[id]/charts/route.ts +72 -0
  24. package/src/app/api/tables/[id]/columns/route.ts +70 -0
  25. package/src/app/api/tables/[id]/export/route.ts +94 -0
  26. package/src/app/api/tables/[id]/history/route.ts +15 -0
  27. package/src/app/api/tables/[id]/import/route.ts +111 -0
  28. package/src/app/api/tables/[id]/route.ts +86 -0
  29. package/src/app/api/tables/[id]/rows/[rowId]/history/route.ts +32 -0
  30. package/src/app/api/tables/[id]/rows/[rowId]/route.ts +51 -0
  31. package/src/app/api/tables/[id]/rows/route.ts +101 -0
  32. package/src/app/api/tables/[id]/triggers/[triggerId]/route.ts +65 -0
  33. package/src/app/api/tables/[id]/triggers/route.ts +122 -0
  34. package/src/app/api/tables/route.ts +65 -0
  35. package/src/app/api/tables/templates/route.ts +92 -0
  36. package/src/app/settings/page.tsx +2 -0
  37. package/src/app/tables/[id]/page.tsx +67 -0
  38. package/src/app/tables/page.tsx +21 -0
  39. package/src/app/tables/templates/page.tsx +19 -0
  40. package/src/components/chat/chat-table-result.tsx +139 -0
  41. package/src/components/documents/document-browser.tsx +1 -1
  42. package/src/components/projects/project-form-sheet.tsx +3 -27
  43. package/src/components/schedules/schedule-form.tsx +5 -27
  44. package/src/components/settings/data-management-section.tsx +17 -12
  45. package/src/components/settings/database-snapshots-section.tsx +469 -0
  46. package/src/components/shared/app-sidebar.tsx +2 -0
  47. package/src/components/shared/document-picker-sheet.tsx +214 -11
  48. package/src/components/tables/table-browser.tsx +234 -0
  49. package/src/components/tables/table-cell-editor.tsx +226 -0
  50. package/src/components/tables/table-chart-builder.tsx +288 -0
  51. package/src/components/tables/table-chart-view.tsx +146 -0
  52. package/src/components/tables/table-column-header.tsx +103 -0
  53. package/src/components/tables/table-column-sheet.tsx +331 -0
  54. package/src/components/tables/table-create-sheet.tsx +240 -0
  55. package/src/components/tables/table-detail-sheet.tsx +144 -0
  56. package/src/components/tables/table-detail-tabs.tsx +278 -0
  57. package/src/components/tables/table-grid.tsx +61 -0
  58. package/src/components/tables/table-history-tab.tsx +148 -0
  59. package/src/components/tables/table-import-wizard.tsx +542 -0
  60. package/src/components/tables/table-list-table.tsx +95 -0
  61. package/src/components/tables/table-relation-combobox.tsx +217 -0
  62. package/src/components/tables/table-spreadsheet.tsx +499 -0
  63. package/src/components/tables/table-template-gallery.tsx +162 -0
  64. package/src/components/tables/table-template-preview.tsx +219 -0
  65. package/src/components/tables/table-toolbar.tsx +79 -0
  66. package/src/components/tables/table-triggers-tab.tsx +446 -0
  67. package/src/components/tables/types.ts +6 -0
  68. package/src/components/tables/use-spreadsheet-keys.ts +171 -0
  69. package/src/components/tables/utils.ts +29 -0
  70. package/src/components/tasks/task-create-panel.tsx +5 -31
  71. package/src/components/tasks/task-edit-dialog.tsx +5 -27
  72. package/src/components/workflows/workflow-form-view.tsx +5 -29
  73. package/src/components/workflows/workflow-status-view.tsx +1 -1
  74. package/src/instrumentation.ts +3 -0
  75. package/src/lib/agents/__tests__/claude-agent.test.ts +5 -1
  76. package/src/lib/agents/claude-agent.ts +3 -1
  77. package/src/lib/agents/runtime/anthropic-direct.ts +29 -0
  78. package/src/lib/agents/runtime/openai-direct.ts +29 -0
  79. package/src/lib/chat/stagent-tools.ts +2 -0
  80. package/src/lib/chat/tool-catalog.ts +34 -0
  81. package/src/lib/chat/tools/table-tools.ts +955 -0
  82. package/src/lib/constants/table-status.ts +68 -0
  83. package/src/lib/data/__tests__/clear.test.ts +1 -1
  84. package/src/lib/data/clear.ts +45 -0
  85. package/src/lib/data/seed-data/__tests__/profiles.test.ts +28 -23
  86. package/src/lib/data/seed-data/conversations.ts +350 -42
  87. package/src/lib/data/seed-data/documents.ts +564 -591
  88. package/src/lib/data/seed-data/learned-context.ts +101 -22
  89. package/src/lib/data/seed-data/notifications.ts +344 -70
  90. package/src/lib/data/seed-data/profile-test-results.ts +92 -11
  91. package/src/lib/data/seed-data/profiles.ts +144 -46
  92. package/src/lib/data/seed-data/projects.ts +50 -18
  93. package/src/lib/data/seed-data/repo-imports.ts +28 -13
  94. package/src/lib/data/seed-data/schedules.ts +208 -41
  95. package/src/lib/data/seed-data/table-templates.ts +234 -0
  96. package/src/lib/data/seed-data/tasks.ts +614 -116
  97. package/src/lib/data/seed-data/usage-ledger.ts +182 -103
  98. package/src/lib/data/seed-data/user-tables.ts +203 -0
  99. package/src/lib/data/seed-data/views.ts +52 -7
  100. package/src/lib/data/seed-data/workflows.ts +231 -84
  101. package/src/lib/data/seed.ts +55 -14
  102. package/src/lib/data/tables.ts +417 -0
  103. package/src/lib/db/bootstrap.ts +227 -0
  104. package/src/lib/db/index.ts +9 -0
  105. package/src/lib/db/migrations/0019_add_tables_feature.sql +160 -0
  106. package/src/lib/db/migrations/0020_add_table_triggers.sql +19 -0
  107. package/src/lib/db/migrations/0021_add_row_history.sql +15 -0
  108. package/src/lib/db/schema.ts +368 -0
  109. package/src/lib/snapshots/auto-backup.ts +132 -0
  110. package/src/lib/snapshots/retention.ts +64 -0
  111. package/src/lib/snapshots/snapshot-manager.ts +429 -0
  112. package/src/lib/tables/computed.ts +61 -0
  113. package/src/lib/tables/context-builder.ts +139 -0
  114. package/src/lib/tables/formula-engine.ts +415 -0
  115. package/src/lib/tables/history.ts +115 -0
  116. package/src/lib/tables/import.ts +343 -0
  117. package/src/lib/tables/query-builder.ts +152 -0
  118. package/src/lib/tables/trigger-evaluator.ts +146 -0
  119. package/src/lib/tables/types.ts +141 -0
  120. package/src/lib/tables/validation.ts +119 -0
  121. package/src/lib/utils/stagent-paths.ts +20 -0
  122. package/tsconfig.json +3 -1
  123. /package/docs/features/{playbook.md → user-guide.md} +0 -0
@@ -0,0 +1,469 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect, useCallback } from "react";
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from "@/components/ui/card";
11
+ import { Button } from "@/components/ui/button";
12
+ import { Input } from "@/components/ui/input";
13
+ import { Label } from "@/components/ui/label";
14
+ import { Switch } from "@/components/ui/switch";
15
+ import { Badge } from "@/components/ui/badge";
16
+ import { Separator } from "@/components/ui/separator";
17
+ import { ConfirmDialog } from "@/components/shared/confirm-dialog";
18
+ import { toast } from "sonner";
19
+ import {
20
+ Loader2,
21
+ Camera,
22
+ RotateCcw,
23
+ Trash2,
24
+ HardDrive,
25
+ Clock,
26
+ AlertTriangle,
27
+ } from "lucide-react";
28
+
29
+ interface Snapshot {
30
+ id: string;
31
+ label: string;
32
+ type: "manual" | "auto";
33
+ status: "in_progress" | "completed" | "failed";
34
+ filePath: string;
35
+ sizeBytes: number;
36
+ dbSizeBytes: number;
37
+ filesSizeBytes: number;
38
+ fileCount: number;
39
+ error: string | null;
40
+ createdAt: string;
41
+ filesMissing: boolean;
42
+ }
43
+
44
+ function formatBytes(bytes: number): string {
45
+ if (bytes === 0) return "0 B";
46
+ const k = 1024;
47
+ const sizes = ["B", "KB", "MB", "GB"];
48
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
49
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
50
+ }
51
+
52
+ function formatRelativeTime(dateStr: string): string {
53
+ const date = new Date(dateStr);
54
+ const now = new Date();
55
+ const diffMs = now.getTime() - date.getTime();
56
+ const diffMins = Math.floor(diffMs / 60000);
57
+ const diffHours = Math.floor(diffMins / 60);
58
+ const diffDays = Math.floor(diffHours / 24);
59
+
60
+ if (diffMins < 1) return "just now";
61
+ if (diffMins < 60) return `${diffMins}m ago`;
62
+ if (diffHours < 24) return `${diffHours}h ago`;
63
+ if (diffDays < 7) return `${diffDays}d ago`;
64
+ return date.toLocaleDateString();
65
+ }
66
+
67
+ export function DatabaseSnapshotsSection() {
68
+ const [snapshotList, setSnapshotList] = useState<Snapshot[]>([]);
69
+ const [totalBytes, setTotalBytes] = useState(0);
70
+ const [loading, setLoading] = useState(true);
71
+ const [creating, setCreating] = useState(false);
72
+ const [restoring, setRestoring] = useState(false);
73
+ const [snapshotLabel, setSnapshotLabel] = useState("");
74
+ const [deleteId, setDeleteId] = useState<string | null>(null);
75
+ const [restoreId, setRestoreId] = useState<string | null>(null);
76
+ const [restoreComplete, setRestoreComplete] = useState(false);
77
+
78
+ // Auto-backup settings
79
+ const [autoEnabled, setAutoEnabled] = useState(false);
80
+ const [autoInterval, setAutoInterval] = useState("1d");
81
+ const [maxCount, setMaxCount] = useState("10");
82
+ const [maxAgeWeeks, setMaxAgeWeeks] = useState("4");
83
+ const [savingSettings, setSavingSettings] = useState(false);
84
+
85
+ const fetchSnapshots = useCallback(async () => {
86
+ try {
87
+ const res = await fetch("/api/snapshots");
88
+ const data = await res.json();
89
+ setSnapshotList(data.snapshots || []);
90
+ setTotalBytes(data.totalBytes || 0);
91
+ } catch {
92
+ // Silent fail on fetch
93
+ } finally {
94
+ setLoading(false);
95
+ }
96
+ }, []);
97
+
98
+ const fetchSettings = useCallback(async () => {
99
+ try {
100
+ const res = await fetch("/api/snapshots/settings");
101
+ if (res.ok) {
102
+ const settings = await res.json();
103
+ setAutoEnabled(settings.enabled === "true");
104
+ setAutoInterval(settings.interval || "1d");
105
+ setMaxCount(settings.maxCount || "10");
106
+ setMaxAgeWeeks(settings.maxAgeWeeks || "4");
107
+ }
108
+ } catch {
109
+ // Use defaults
110
+ }
111
+ }, []);
112
+
113
+ useEffect(() => {
114
+ fetchSnapshots();
115
+ fetchSettings();
116
+ }, [fetchSnapshots, fetchSettings]);
117
+
118
+ async function handleCreate() {
119
+ setCreating(true);
120
+ try {
121
+ const res = await fetch("/api/snapshots", {
122
+ method: "POST",
123
+ headers: { "Content-Type": "application/json" },
124
+ body: JSON.stringify({
125
+ label: snapshotLabel.trim() || undefined,
126
+ }),
127
+ });
128
+ const data = await res.json();
129
+ if (res.ok) {
130
+ toast.success(
131
+ `Snapshot created — ${formatBytes(data.sizeBytes)} (${data.fileCount} files)`
132
+ );
133
+ setSnapshotLabel("");
134
+ fetchSnapshots();
135
+ } else {
136
+ toast.error(data.error || "Failed to create snapshot");
137
+ }
138
+ } catch {
139
+ toast.error("Failed to create snapshot — network error");
140
+ } finally {
141
+ setCreating(false);
142
+ }
143
+ }
144
+
145
+ async function handleDelete() {
146
+ if (!deleteId) return;
147
+ try {
148
+ const res = await fetch(`/api/snapshots/${deleteId}`, {
149
+ method: "DELETE",
150
+ });
151
+ if (res.ok) {
152
+ toast.success("Snapshot deleted");
153
+ fetchSnapshots();
154
+ } else {
155
+ const data = await res.json();
156
+ toast.error(data.error || "Failed to delete snapshot");
157
+ }
158
+ } catch {
159
+ toast.error("Failed to delete — network error");
160
+ } finally {
161
+ setDeleteId(null);
162
+ }
163
+ }
164
+
165
+ async function handleRestore() {
166
+ if (!restoreId) return;
167
+ setRestoring(true);
168
+ try {
169
+ const res = await fetch(`/api/snapshots/${restoreId}/restore`, {
170
+ method: "POST",
171
+ });
172
+ const data = await res.json();
173
+ if (res.ok) {
174
+ setRestoreComplete(true);
175
+ toast.success("Restore complete — please restart the server");
176
+ } else {
177
+ toast.error(data.error || "Restore failed");
178
+ }
179
+ } catch {
180
+ toast.error("Restore failed — network error");
181
+ } finally {
182
+ setRestoring(false);
183
+ setRestoreId(null);
184
+ }
185
+ }
186
+
187
+ async function handleSaveSettings() {
188
+ setSavingSettings(true);
189
+ try {
190
+ const res = await fetch("/api/snapshots/settings", {
191
+ method: "PUT",
192
+ headers: { "Content-Type": "application/json" },
193
+ body: JSON.stringify({
194
+ enabled: autoEnabled ? "true" : "false",
195
+ interval: autoInterval,
196
+ maxCount,
197
+ maxAgeWeeks,
198
+ }),
199
+ });
200
+ if (res.ok) {
201
+ toast.success("Snapshot settings saved");
202
+ } else {
203
+ const data = await res.json();
204
+ toast.error(data.error || "Failed to save settings");
205
+ }
206
+ } catch {
207
+ toast.error("Failed to save settings — network error");
208
+ } finally {
209
+ setSavingSettings(false);
210
+ }
211
+ }
212
+
213
+ return (
214
+ <>
215
+ <Card className="surface-card">
216
+ <CardHeader>
217
+ <div className="flex items-center justify-between">
218
+ <div>
219
+ <CardTitle className="flex items-center gap-2">
220
+ <HardDrive className="h-5 w-5" />
221
+ Database Snapshots
222
+ </CardTitle>
223
+ <CardDescription>
224
+ Create, schedule, and restore full-state backups of your database
225
+ and files
226
+ </CardDescription>
227
+ </div>
228
+ {totalBytes > 0 && (
229
+ <Badge variant="secondary">{formatBytes(totalBytes)} used</Badge>
230
+ )}
231
+ </div>
232
+ </CardHeader>
233
+ <CardContent className="space-y-6">
234
+ {/* Restart banner */}
235
+ {restoreComplete && (
236
+ <div className="flex items-center gap-3 rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-800 dark:bg-amber-950">
237
+ <AlertTriangle className="h-5 w-5 text-amber-600 shrink-0" />
238
+ <div className="text-sm">
239
+ <p className="font-medium text-amber-800 dark:text-amber-200">
240
+ Restart required
241
+ </p>
242
+ <p className="text-amber-700 dark:text-amber-300">
243
+ The database has been restored. Please restart the server to
244
+ load the restored data.
245
+ </p>
246
+ </div>
247
+ </div>
248
+ )}
249
+
250
+ {/* Create snapshot */}
251
+ <div className="space-y-3">
252
+ <Label className="text-sm font-medium">Manual Snapshot</Label>
253
+ <div className="flex items-center gap-2">
254
+ <Input
255
+ placeholder="Optional label (e.g., Before migration)"
256
+ value={snapshotLabel}
257
+ onChange={(e) => setSnapshotLabel(e.target.value)}
258
+ className="max-w-sm"
259
+ disabled={creating}
260
+ />
261
+ <Button
262
+ onClick={handleCreate}
263
+ disabled={creating || restoreComplete}
264
+ >
265
+ {creating ? (
266
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
267
+ ) : (
268
+ <Camera className="mr-2 h-4 w-4" />
269
+ )}
270
+ {creating ? "Creating..." : "Create Snapshot"}
271
+ </Button>
272
+ </div>
273
+ </div>
274
+
275
+ <Separator />
276
+
277
+ {/* Auto-backup settings */}
278
+ <div className="space-y-4">
279
+ <Label className="text-sm font-medium">Auto-Backup</Label>
280
+ <div className="flex items-center justify-between">
281
+ <div className="space-y-0.5">
282
+ <p className="text-sm">Enable automatic backups</p>
283
+ <p className="text-xs text-muted-foreground">
284
+ Snapshots are created at the configured interval
285
+ </p>
286
+ </div>
287
+ <Switch
288
+ checked={autoEnabled}
289
+ onCheckedChange={setAutoEnabled}
290
+ />
291
+ </div>
292
+
293
+ {autoEnabled && (
294
+ <div className="grid grid-cols-3 gap-4">
295
+ <div className="space-y-2">
296
+ <Label className="text-xs text-muted-foreground">
297
+ Interval
298
+ </Label>
299
+ <Input
300
+ value={autoInterval}
301
+ onChange={(e) => setAutoInterval(e.target.value)}
302
+ placeholder="1d"
303
+ className="font-mono"
304
+ />
305
+ <p className="text-xs text-muted-foreground">
306
+ e.g., 6h, 1d, 1w
307
+ </p>
308
+ </div>
309
+ <div className="space-y-2">
310
+ <Label className="text-xs text-muted-foreground">
311
+ Keep last N snapshots
312
+ </Label>
313
+ <Input
314
+ type="number"
315
+ value={maxCount}
316
+ onChange={(e) => setMaxCount(e.target.value)}
317
+ min={1}
318
+ max={100}
319
+ />
320
+ </div>
321
+ <div className="space-y-2">
322
+ <Label className="text-xs text-muted-foreground">
323
+ Keep last N weeks
324
+ </Label>
325
+ <Input
326
+ type="number"
327
+ value={maxAgeWeeks}
328
+ onChange={(e) => setMaxAgeWeeks(e.target.value)}
329
+ min={1}
330
+ max={52}
331
+ />
332
+ </div>
333
+ </div>
334
+ )}
335
+
336
+ <Button
337
+ variant="outline"
338
+ size="sm"
339
+ onClick={handleSaveSettings}
340
+ disabled={savingSettings}
341
+ >
342
+ {savingSettings ? (
343
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
344
+ ) : (
345
+ <Clock className="mr-2 h-4 w-4" />
346
+ )}
347
+ {savingSettings ? "Saving..." : "Save Settings"}
348
+ </Button>
349
+ </div>
350
+
351
+ <Separator />
352
+
353
+ {/* Snapshot list */}
354
+ <div className="space-y-3">
355
+ <Label className="text-sm font-medium">
356
+ Snapshots ({snapshotList.length})
357
+ </Label>
358
+
359
+ {loading ? (
360
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
361
+ <Loader2 className="h-4 w-4 animate-spin" />
362
+ Loading snapshots...
363
+ </div>
364
+ ) : snapshotList.length === 0 ? (
365
+ <p className="text-sm text-muted-foreground">
366
+ No snapshots yet. Create one to get started.
367
+ </p>
368
+ ) : (
369
+ <div className="space-y-2">
370
+ {snapshotList.map((snap) => (
371
+ <div
372
+ key={snap.id}
373
+ className="flex items-center justify-between rounded-lg border p-3"
374
+ >
375
+ <div className="space-y-1 min-w-0 flex-1">
376
+ <div className="flex items-center gap-2">
377
+ <p className="text-sm font-medium truncate">
378
+ {snap.label}
379
+ </p>
380
+ <Badge
381
+ variant={
382
+ snap.type === "auto" ? "secondary" : "default"
383
+ }
384
+ className="shrink-0 text-xs"
385
+ >
386
+ {snap.type}
387
+ </Badge>
388
+ {snap.status === "failed" && (
389
+ <Badge variant="destructive" className="shrink-0 text-xs">
390
+ failed
391
+ </Badge>
392
+ )}
393
+ {snap.status === "in_progress" && (
394
+ <Badge variant="outline" className="shrink-0 text-xs">
395
+ in progress
396
+ </Badge>
397
+ )}
398
+ {snap.filesMissing && (
399
+ <Badge
400
+ variant="destructive"
401
+ className="shrink-0 text-xs"
402
+ >
403
+ files missing
404
+ </Badge>
405
+ )}
406
+ </div>
407
+ <p className="text-xs text-muted-foreground">
408
+ {formatRelativeTime(snap.createdAt)} ·{" "}
409
+ {formatBytes(snap.sizeBytes)} ·{" "}
410
+ {snap.fileCount} files
411
+ </p>
412
+ </div>
413
+
414
+ <div className="flex items-center gap-1 shrink-0">
415
+ <Button
416
+ variant="ghost"
417
+ size="sm"
418
+ onClick={() => setRestoreId(snap.id)}
419
+ disabled={
420
+ snap.status !== "completed" ||
421
+ snap.filesMissing ||
422
+ restoring ||
423
+ restoreComplete
424
+ }
425
+ title="Restore from this snapshot"
426
+ >
427
+ <RotateCcw className="h-4 w-4" />
428
+ </Button>
429
+ <Button
430
+ variant="ghost"
431
+ size="sm"
432
+ onClick={() => setDeleteId(snap.id)}
433
+ title="Delete this snapshot"
434
+ >
435
+ <Trash2 className="h-4 w-4" />
436
+ </Button>
437
+ </div>
438
+ </div>
439
+ ))}
440
+ </div>
441
+ )}
442
+ </div>
443
+ </CardContent>
444
+ </Card>
445
+
446
+ {/* Delete confirmation */}
447
+ <ConfirmDialog
448
+ open={deleteId !== null}
449
+ onOpenChange={(open) => !open && setDeleteId(null)}
450
+ title="Delete snapshot?"
451
+ description="This will permanently delete the snapshot and its files from disk. This action cannot be undone."
452
+ confirmLabel="Delete Snapshot"
453
+ onConfirm={handleDelete}
454
+ destructive
455
+ />
456
+
457
+ {/* Restore confirmation */}
458
+ <ConfirmDialog
459
+ open={restoreId !== null}
460
+ onOpenChange={(open) => !open && setRestoreId(null)}
461
+ title="Restore from snapshot?"
462
+ description="This will replace your current database and all files with the snapshot's contents. A safety snapshot of your current state will be created first. The server must be restarted after restore."
463
+ confirmLabel="Restore"
464
+ onConfirm={handleRestore}
465
+ destructive
466
+ />
467
+ </>
468
+ );
469
+ }
@@ -18,6 +18,7 @@ import {
18
18
  Globe,
19
19
  Settings,
20
20
  MessageCircle,
21
+ Table2,
21
22
  } from "lucide-react";
22
23
  import {
23
24
  Sidebar,
@@ -56,6 +57,7 @@ const workItems: NavItem[] = [
56
57
  { title: "Projects", href: "/projects", icon: FolderKanban },
57
58
  { title: "Workflows", href: "/workflows", icon: Workflow },
58
59
  { title: "Documents", href: "/documents", icon: FileText },
60
+ { title: "Tables", href: "/tables", icon: Table2, alsoMatches: ["/tables/"] },
59
61
  ];
60
62
 
61
63
  const manageItems: NavItem[] = [