ltcai 8.0.0 → 8.2.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.
- package/README.md +33 -72
- package/docs/CHANGELOG.md +52 -874
- package/docs/DEVELOPMENT.md +26 -3
- package/docs/LEGACY_COMPATIBILITY.md +3 -1
- package/docs/TRUST_MODEL.md +26 -26
- package/docs/WHY_LATTICE.md +28 -25
- package/docs/kg-schema.md +6 -4
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/embeddings.py +9 -1
- package/lattice_brain/graph/schema.py +6 -0
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/computer_use.py +2 -0
- package/latticeai/api/memory.py +13 -0
- package/latticeai/app_factory.py +43 -162
- package/latticeai/brain/__init__.py +1 -1
- package/latticeai/core/config.py +10 -0
- package/latticeai/core/local_embeddings.py +8 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/mcp_registry.py +140 -1
- package/latticeai/core/tool_registry.py +10 -0
- package/latticeai/core/workspace_graph_trace.py +132 -0
- package/latticeai/core/workspace_memory.py +75 -0
- package/latticeai/core/workspace_os.py +135 -1283
- package/latticeai/core/workspace_os_utils.py +132 -0
- package/latticeai/core/workspace_permissions.py +99 -0
- package/latticeai/core/workspace_plugins.py +97 -0
- package/latticeai/core/workspace_runs.py +612 -0
- package/latticeai/core/workspace_skills.py +114 -0
- package/latticeai/core/workspace_snapshots.py +195 -0
- package/latticeai/core/workspace_timeline.py +107 -0
- package/latticeai/runtime/audit_runtime.py +64 -0
- package/latticeai/runtime/config_runtime.py +4 -0
- package/latticeai/runtime/sso_runtime.py +52 -0
- package/latticeai/services/architecture_readiness.py +6 -5
- package/latticeai/services/memory_service.py +215 -7
- package/latticeai/services/model_capability_registry.py +68 -0
- package/latticeai/services/model_engines.py +603 -0
- package/latticeai/services/model_loading.py +482 -0
- package/latticeai/services/model_recommendation.py +5 -0
- package/latticeai/services/model_runtime.py +146 -837
- package/latticeai/services/product_readiness.py +19 -18
- package/package.json +2 -2
- package/scripts/build_frontend_assets.mjs +11 -2
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +11 -102
- package/static/app/assets/Act-D9jIknFd.js +1 -0
- package/static/app/assets/Brain-CFOtWbPN.js +321 -0
- package/static/app/assets/{Capture-B9Tlhzqr.js → Capture-Q4WYzwr5.js} +1 -2
- package/static/app/assets/Library-C5Q2yWee.js +1 -0
- package/static/app/assets/System-BLbjdr1_.js +1 -0
- package/static/app/assets/core-CwxXejkd.js +1 -2
- package/static/app/assets/index-BqammyNu.js +16 -0
- package/static/app/assets/index-ty1iGgZu.css +2 -0
- package/static/app/assets/primitives-Br8uSfZ4.js +1 -0
- package/static/app/assets/{textarea-BZk6ybp5.js → textarea-BnhNs1_X.js} +1 -2
- package/static/app/index.html +3 -10
- package/static/app/theme-boot.js +8 -0
- package/static/sw.js +1 -1
- package/tools/__init__.py +2 -1
- package/tools/computer.py +21 -0
- package/docs/CARRYOVER_AUDIT_v3.6.0.md +0 -61
- package/docs/HANDOVER_v3.6.0.md +0 -46
- package/docs/RUNTIME_HOOK_COVERAGE_v3.5.0.md +0 -56
- package/docs/RUNTIME_HOOK_COVERAGE_v3.6.0.md +0 -49
- package/docs/V2_ARCHITECTURE.md +0 -561
- package/docs/V3_2_AUDIT.md +0 -82
- package/docs/V3_BACKEND_ARCHITECTURE.md +0 -138
- package/docs/V3_FRONTEND.md +0 -140
- package/docs/V4_1_FRONTEND_ARCHITECTURE_REVIEW.md +0 -65
- package/docs/V4_1_FRONTEND_MIGRATION_REPORT.md +0 -70
- package/docs/V4_1_VALIDATION_REPORT.md +0 -47
- package/docs/V4_2_BRAIN_CORE_ARCHITECTURE.md +0 -97
- package/docs/V4_2_STORAGE_MIGRATION_REPORT.md +0 -91
- package/docs/V4_2_VALIDATION_REPORT.md +0 -89
- package/docs/V4_3_2_DEADCODE_AUDIT_REPORT.md +0 -174
- package/docs/V4_3_2_DOCUMENTATION_CLEANUP_REPORT.md +0 -81
- package/docs/V4_3_2_GITHUB_VERCEL_CHECK_REPORT.md +0 -75
- package/docs/V4_3_2_GRAPH_UX_REPORT.md +0 -48
- package/docs/V4_3_2_INDEPENDENT_AUDIT_PACKAGE.md +0 -209
- package/docs/V4_3_2_PRODUCT_POLISH_REPORT.md +0 -57
- package/docs/V4_3_2_SELF_AUDIT_REPORT.md +0 -63
- package/docs/V4_3_2_VALIDATION_REPORT.md +0 -97
- package/docs/V4_3_3_VALIDATION_REPORT.md +0 -46
- package/docs/V4_3_PORTABILITY_ARCHITECTURE.md +0 -69
- package/docs/V4_3_PRIVACY_AUDIT.md +0 -60
- package/docs/V4_3_PRODUCT_HARDENING_REPORT.md +0 -53
- package/docs/V4_3_VALIDATION_REPORT.md +0 -58
- package/docs/V4_4_0_EXTRACTION_REPORT.md +0 -239
- package/docs/V4_5_0_GEMMA_RUNTIME_COMPATIBILITY_REPORT.md +0 -49
- package/docs/V4_5_0_GRAPH_UX_REPORT.md +0 -34
- package/docs/V4_5_0_MODEL_RUNTIME_UX_REPORT.md +0 -40
- package/docs/V4_5_0_ONBOARDING_REPORT.md +0 -31
- package/docs/V4_5_0_PRODUCT_EXPERIENCE_RECOVERY_REPORT.md +0 -49
- package/docs/V4_5_0_VALIDATION_REPORT.md +0 -60
- package/docs/V4_5_1_GRAPH_EXPERIENCE_REPORT.md +0 -33
- package/docs/V4_5_1_MODEL_EXPERIENCE_REPORT.md +0 -37
- package/docs/V4_5_1_NAVIGATION_REPORT.md +0 -37
- package/docs/V4_5_1_ONBOARDING_REPORT.md +0 -29
- package/docs/V4_5_1_PRODUCT_REIMAGINING_REPORT.md +0 -61
- package/docs/V4_5_1_RC_ARTIFACTS.md +0 -44
- package/docs/V4_5_1_UX_REPORT.md +0 -45
- package/docs/V4_5_1_VALIDATION_REPORT.md +0 -55
- package/docs/V4_5_1_VISUAL_DESIGN_REPORT.md +0 -30
- package/docs/V4_6_0_LIVING_BRAIN_EXPERIENCE_REPORT.md +0 -72
- package/docs/V4_6_1_RELEASE_REFRESH_REPORT.md +0 -42
- package/docs/V4_7_0_ADMIN_SEPARATION_REPORT.md +0 -42
- package/docs/V4_7_1_ADMIN_OPERATIONS_REPORT.md +0 -49
- package/docs/V4_7_2_INTUITIVE_BRAIN_UX_REPORT.md +0 -62
- package/docs/V4_BRAIN_ARCHITECTURE.md +0 -322
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +0 -555
- package/docs/V4_IMPLEMENTATION_PLAN.md +0 -470
- package/frontend/index.html +0 -24
- package/frontend/openapi.json +0 -15425
- package/frontend/src/App.tsx +0 -243
- package/frontend/src/api/client.ts +0 -580
- package/frontend/src/api/openapi.ts +0 -17892
- package/frontend/src/components/AdminAccessGate.tsx +0 -70
- package/frontend/src/components/FeedbackState.tsx +0 -45
- package/frontend/src/components/LanguageSwitcher.tsx +0 -23
- package/frontend/src/components/LivingBrain.tsx +0 -220
- package/frontend/src/components/ProductFlow.tsx +0 -171
- package/frontend/src/components/WorkspaceProfileSwitcher.tsx +0 -176
- package/frontend/src/components/onboarding/AnalysisScreen.tsx +0 -135
- package/frontend/src/components/onboarding/DownloadConsentPanel.tsx +0 -29
- package/frontend/src/components/onboarding/InstallScreen.tsx +0 -263
- package/frontend/src/components/onboarding/LanguageChooser.tsx +0 -23
- package/frontend/src/components/onboarding/LoginScreen.tsx +0 -131
- package/frontend/src/components/onboarding/ProductFlowScreens.tsx +0 -13
- package/frontend/src/components/onboarding/RecommendationScreen.tsx +0 -116
- package/frontend/src/components/onboarding/recommendationModel.ts +0 -189
- package/frontend/src/components/primitives.tsx +0 -392
- package/frontend/src/components/ui/badge.tsx +0 -27
- package/frontend/src/components/ui/button.tsx +0 -37
- package/frontend/src/components/ui/card.tsx +0 -22
- package/frontend/src/components/ui/input.tsx +0 -16
- package/frontend/src/components/ui/textarea.tsx +0 -16
- package/frontend/src/features/admin/AdminConsole.tsx +0 -334
- package/frontend/src/features/brain/BrainCarePanel.tsx +0 -254
- package/frontend/src/features/brain/BrainComposer.tsx +0 -85
- package/frontend/src/features/brain/BrainConversation.tsx +0 -688
- package/frontend/src/features/brain/BrainGraphLayer.tsx +0 -365
- package/frontend/src/features/brain/BrainHome.tsx +0 -624
- package/frontend/src/features/brain/BrainMemoryLayer.tsx +0 -45
- package/frontend/src/features/brain/BrainOverviewPanel.tsx +0 -149
- package/frontend/src/features/brain/BrainRelationshipLayer.tsx +0 -43
- package/frontend/src/features/brain/DepthEmergence.tsx +0 -53
- package/frontend/src/features/brain/brainData.ts +0 -246
- package/frontend/src/features/brain/graphLayout.ts +0 -37
- package/frontend/src/features/brain/types.ts +0 -150
- package/frontend/src/features/review/ReviewCard.tsx +0 -100
- package/frontend/src/features/review/ReviewInbox.tsx +0 -127
- package/frontend/src/features/review/reviewHelpers.ts +0 -69
- package/frontend/src/i18n.ts +0 -1303
- package/frontend/src/lib/utils.ts +0 -33
- package/frontend/src/main.tsx +0 -23
- package/frontend/src/pages/Act.tsx +0 -458
- package/frontend/src/pages/Ask.tsx +0 -14
- package/frontend/src/pages/Brain.tsx +0 -914
- package/frontend/src/pages/Capture.tsx +0 -258
- package/frontend/src/pages/Library.tsx +0 -486
- package/frontend/src/pages/System.tsx +0 -621
- package/frontend/src/routes.ts +0 -92
- package/frontend/src/store/appStore.ts +0 -94
- package/frontend/src/styles.css +0 -6579
- package/static/app/assets/Act-DOvf59ru.js +0 -2
- package/static/app/assets/Act-DOvf59ru.js.map +0 -1
- package/static/app/assets/Brain-C7_0mEiI.js +0 -322
- package/static/app/assets/Brain-C7_0mEiI.js.map +0 -1
- package/static/app/assets/Capture-B9Tlhzqr.js.map +0 -1
- package/static/app/assets/Library-BJPEEm5O.js +0 -2
- package/static/app/assets/Library-BJPEEm5O.js.map +0 -1
- package/static/app/assets/System-D6t9jo9V.js +0 -2
- package/static/app/assets/System-D6t9jo9V.js.map +0 -1
- package/static/app/assets/core-CwxXejkd.js.map +0 -1
- package/static/app/assets/index-C7g26IF6.css +0 -2
- package/static/app/assets/index-DbcEYJQ2.js +0 -17
- package/static/app/assets/index-DbcEYJQ2.js.map +0 -1
- package/static/app/assets/primitives-CD38lt4n.js +0 -2
- package/static/app/assets/primitives-CD38lt4n.js.map +0 -1
- package/static/app/assets/textarea-BZk6ybp5.js.map +0 -1
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
|
-
import { AlertCircle, CheckCircle2, FolderPlus, Globe2, HardDrive, Loader2, RotateCcw, Upload } from "lucide-react";
|
|
4
|
-
import { latticeApi } from "@/api/client";
|
|
5
|
-
import { ActionButton, DataPanel, EntityList, OperationResult, StructuredView, Tabs } from "@/components/primitives";
|
|
6
|
-
import { Button } from "@/components/ui/button";
|
|
7
|
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
8
|
-
import { Input } from "@/components/ui/input";
|
|
9
|
-
import { t, type Language } from "@/i18n";
|
|
10
|
-
import { asArray } from "@/lib/utils";
|
|
11
|
-
import { useAppStore } from "@/store/appStore";
|
|
12
|
-
|
|
13
|
-
type CaptureTab = "files" | "local" | "browser" | "pipeline";
|
|
14
|
-
|
|
15
|
-
export function CapturePage({ initialTab }: { initialTab?: string }) {
|
|
16
|
-
const language = useAppStore((state) => state.language);
|
|
17
|
-
const [tab, setTab] = React.useState<CaptureTab>((initialTab as CaptureTab) || "files");
|
|
18
|
-
const tabs: Array<{ id: CaptureTab; label: string }> = [
|
|
19
|
-
{ id: "files", label: t(language, "capture.tab.files") },
|
|
20
|
-
{ id: "local", label: t(language, "capture.tab.local") },
|
|
21
|
-
{ id: "browser", label: t(language, "capture.tab.browser") },
|
|
22
|
-
{ id: "pipeline", label: t(language, "capture.tab.pipeline") },
|
|
23
|
-
];
|
|
24
|
-
React.useEffect(() => {
|
|
25
|
-
if (initialTab === "pipeline" || initialTab === "local" || initialTab === "files") setTab(initialTab);
|
|
26
|
-
}, [initialTab]);
|
|
27
|
-
return (
|
|
28
|
-
<div className="space-y-5">
|
|
29
|
-
<header className="page-hero">
|
|
30
|
-
<div className="page-kicker"><Upload className="h-4 w-4" /> {t(language, "capture.kicker")}</div>
|
|
31
|
-
<h1 className="page-title">{t(language, "capture.title")}</h1>
|
|
32
|
-
<p className="page-copy">{t(language, "capture.body")}</p>
|
|
33
|
-
</header>
|
|
34
|
-
<Tabs tabs={tabs} value={tab} onChange={(id) => setTab(id as CaptureTab)} />
|
|
35
|
-
{tab === "files" ? <FilesPanel /> : null}
|
|
36
|
-
{tab === "local" ? <LocalPanel /> : null}
|
|
37
|
-
{tab === "browser" ? <BrowserPanel /> : null}
|
|
38
|
-
{tab === "pipeline" ? <PipelinePanel /> : null}
|
|
39
|
-
</div>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function FilesPanel() {
|
|
44
|
-
const language = useAppStore((state) => state.language);
|
|
45
|
-
const qc = useQueryClient();
|
|
46
|
-
const docs = useQuery({ queryKey: ["documents"], queryFn: () => latticeApi.documents(200) });
|
|
47
|
-
const [queue, setQueue] = React.useState<UploadQueueItem[]>([]);
|
|
48
|
-
const upload = useMutation({
|
|
49
|
-
mutationFn: (files: File[]) => uploadFiles(files, setQueue),
|
|
50
|
-
onSuccess: () => {
|
|
51
|
-
void qc.invalidateQueries({ queryKey: ["documents"] });
|
|
52
|
-
void qc.invalidateQueries({ queryKey: ["graphStats"] });
|
|
53
|
-
void qc.invalidateQueries({ queryKey: ["memoryManager"] });
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
const beginUpload = React.useCallback((files: FileList | File[]) => {
|
|
57
|
-
const nextFiles = Array.from(files);
|
|
58
|
-
if (!nextFiles.length) return;
|
|
59
|
-
upload.mutate(nextFiles);
|
|
60
|
-
}, [upload]);
|
|
61
|
-
return (
|
|
62
|
-
<div className="grid gap-4 xl:grid-cols-[0.75fr_1.25fr]">
|
|
63
|
-
<Card>
|
|
64
|
-
<CardHeader>
|
|
65
|
-
<CardTitle className="flex items-center gap-2"><Upload className="h-4 w-4" /> {t(language, "capture.files.title")}</CardTitle>
|
|
66
|
-
<CardDescription>{t(language, "capture.files.description")}</CardDescription>
|
|
67
|
-
</CardHeader>
|
|
68
|
-
<CardContent>
|
|
69
|
-
<label
|
|
70
|
-
className="flex min-h-56 cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border border-dashed border-border bg-muted/30 p-6 text-center transition hover:bg-muted/50"
|
|
71
|
-
onDragOver={(event) => event.preventDefault()}
|
|
72
|
-
onDrop={(event) => {
|
|
73
|
-
event.preventDefault();
|
|
74
|
-
beginUpload(event.dataTransfer.files);
|
|
75
|
-
}}
|
|
76
|
-
>
|
|
77
|
-
<Upload className="h-7 w-7 text-primary" />
|
|
78
|
-
<span className="text-lg font-semibold">{t(language, "capture.files.drop")}</span>
|
|
79
|
-
<span className="max-w-sm text-sm leading-6 text-muted-foreground">{t(language, "capture.files.dropDetail")}</span>
|
|
80
|
-
<input type="file" multiple className="sr-only" onChange={(e) => e.target.files && beginUpload(e.target.files)} />
|
|
81
|
-
</label>
|
|
82
|
-
<DocumentUploadQueue queue={queue} onRetry={(file) => beginUpload([file])} />
|
|
83
|
-
</CardContent>
|
|
84
|
-
</Card>
|
|
85
|
-
<DataPanel title={t(language, "capture.files.uploaded")} result={docs.data}>
|
|
86
|
-
{(data) => (
|
|
87
|
-
<div className="space-y-3">
|
|
88
|
-
<EntityList items={(data as Record<string, unknown>).documents || data} titleKey="filename" metaKey="ingest_state" limit={12} />
|
|
89
|
-
<div className="rounded-md border border-border bg-background/55 p-3 text-sm text-muted-foreground">
|
|
90
|
-
{t(language, "capture.files.completed")}
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
)}
|
|
94
|
-
</DataPanel>
|
|
95
|
-
</div>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
type UploadQueueItem = {
|
|
100
|
-
id: string;
|
|
101
|
-
file: File;
|
|
102
|
-
name: string;
|
|
103
|
-
size: number;
|
|
104
|
-
status: "queued" | "uploading" | "done" | "failed";
|
|
105
|
-
result?: Awaited<ReturnType<typeof latticeApi.uploadDocument>>;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
async function uploadFiles(files: File[], setQueue: React.Dispatch<React.SetStateAction<UploadQueueItem[]>>) {
|
|
109
|
-
const rows = files.map((file) => ({
|
|
110
|
-
id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}`,
|
|
111
|
-
file,
|
|
112
|
-
name: file.name,
|
|
113
|
-
size: file.size,
|
|
114
|
-
status: "queued" as const,
|
|
115
|
-
}));
|
|
116
|
-
setQueue((items) => [...rows, ...items].slice(0, 12));
|
|
117
|
-
const results = [];
|
|
118
|
-
for (const row of rows) {
|
|
119
|
-
setQueue((items) => items.map((item) => item.id === row.id ? { ...item, status: "uploading" } : item));
|
|
120
|
-
const result = await latticeApi.uploadDocument(row.file);
|
|
121
|
-
results.push(result);
|
|
122
|
-
setQueue((items) => items.map((item) => item.id === row.id ? { ...item, status: result.ok ? "done" : "failed", result } : item));
|
|
123
|
-
}
|
|
124
|
-
return results;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function DocumentUploadQueue({ queue, onRetry }: { queue: UploadQueueItem[]; onRetry: (file: File) => void }) {
|
|
128
|
-
const language = useAppStore((state) => state.language);
|
|
129
|
-
if (!queue.length) return null;
|
|
130
|
-
return (
|
|
131
|
-
<div className="mt-4 space-y-2">
|
|
132
|
-
{queue.map((item) => {
|
|
133
|
-
const detail = uploadResultDetail(item, language);
|
|
134
|
-
return (
|
|
135
|
-
<div key={item.id} className="rounded-md border border-border bg-background/55 p-3 text-sm">
|
|
136
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
137
|
-
<div>
|
|
138
|
-
<div className="flex items-center gap-2 font-medium">
|
|
139
|
-
{item.status === "done" ? <CheckCircle2 className="h-4 w-4 text-emerald-400" /> : item.status === "failed" ? <AlertCircle className="h-4 w-4 text-amber-400" /> : <Loader2 className="h-4 w-4 animate-spin text-primary" />}
|
|
140
|
-
{item.name}
|
|
141
|
-
</div>
|
|
142
|
-
<div className="mt-1 text-xs text-muted-foreground">
|
|
143
|
-
{Math.max(1, Math.round(item.size / 1024))} KB · {detail}
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
{item.status === "failed" ? (
|
|
147
|
-
<Button size="sm" variant="outline" onClick={() => onRetry(item.file)}>
|
|
148
|
-
<RotateCcw className="h-3.5 w-3.5" /> {t(language, "capture.retry")}
|
|
149
|
-
</Button>
|
|
150
|
-
) : null}
|
|
151
|
-
</div>
|
|
152
|
-
{item.result ? <OperationResult result={item.result} successLabel={t(language, "capture.files.success")} /> : null}
|
|
153
|
-
</div>
|
|
154
|
-
);
|
|
155
|
-
})}
|
|
156
|
-
</div>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function uploadResultDetail(item: UploadQueueItem, language: Language) {
|
|
161
|
-
if (item.status === "queued") return t(language, "capture.files.queued");
|
|
162
|
-
if (item.status === "uploading") return t(language, "capture.files.uploading");
|
|
163
|
-
if (!item.result?.ok) return item.result?.error || t(language, "capture.files.failed");
|
|
164
|
-
const data = item.result.data || {};
|
|
165
|
-
const node = String(data.node_id || data.graph_node || data.provenance_id || "");
|
|
166
|
-
return node ? t(language, "capture.files.capturedWithNode", { node }) : t(language, "capture.files.captured");
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function LocalPanel() {
|
|
170
|
-
const language = useAppStore((state) => state.language);
|
|
171
|
-
const qc = useQueryClient();
|
|
172
|
-
const [path, setPath] = React.useState("");
|
|
173
|
-
const local = useQuery({ queryKey: ["localSources"], queryFn: latticeApi.localSources });
|
|
174
|
-
const agent = useQuery({ queryKey: ["localAgent"], queryFn: latticeApi.localAgent });
|
|
175
|
-
const connect = useMutation({
|
|
176
|
-
mutationFn: () => latticeApi.connectFolder(path),
|
|
177
|
-
onSuccess: () => qc.invalidateQueries({ queryKey: ["localSources"] }),
|
|
178
|
-
});
|
|
179
|
-
return (
|
|
180
|
-
<div className="grid gap-4 xl:grid-cols-[0.9fr_1.1fr]">
|
|
181
|
-
<Card>
|
|
182
|
-
<CardHeader>
|
|
183
|
-
<CardTitle className="flex items-center gap-2"><FolderPlus className="h-4 w-4" /> {t(language, "capture.local.title")}</CardTitle>
|
|
184
|
-
<CardDescription>{t(language, "capture.local.description")}</CardDescription>
|
|
185
|
-
</CardHeader>
|
|
186
|
-
<CardContent className="space-y-3">
|
|
187
|
-
<Input value={path} onChange={(e) => setPath(e.target.value)} placeholder={t(language, "capture.local.placeholder")} />
|
|
188
|
-
<Button disabled={!path.trim() || connect.isPending} onClick={() => connect.mutate()}>{t(language, "capture.local.connect")}</Button>
|
|
189
|
-
{connect.data ? <OperationResult result={connect.data} successLabel={t(language, "capture.local.success")} /> : null}
|
|
190
|
-
</CardContent>
|
|
191
|
-
</Card>
|
|
192
|
-
<DataPanel title={t(language, "capture.local.sources")} result={local.data}>
|
|
193
|
-
{(data) => (
|
|
194
|
-
<div className="space-y-3">
|
|
195
|
-
<EntityList items={(data as Record<string, unknown>).sources} titleKey="path" metaKey="status" />
|
|
196
|
-
{asArray<Record<string, unknown>>((data as Record<string, unknown>).sources).map((source) => (
|
|
197
|
-
<ActionButton
|
|
198
|
-
key={String(source.id || source.source_id || source.path)}
|
|
199
|
-
label={`Stop ${String(source.path || source.id || "source")}`}
|
|
200
|
-
action={() => latticeApi.localWatchStop(String(source.id || source.source_id))}
|
|
201
|
-
invalidate={["localSources"]}
|
|
202
|
-
/>
|
|
203
|
-
))}
|
|
204
|
-
</div>
|
|
205
|
-
)}
|
|
206
|
-
</DataPanel>
|
|
207
|
-
<DataPanel title={t(language, "capture.local.access")} result={agent.data} className="xl:col-span-2">
|
|
208
|
-
{(data) => <StructuredView value={data} />}
|
|
209
|
-
</DataPanel>
|
|
210
|
-
</div>
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function BrowserPanel() {
|
|
215
|
-
const language = useAppStore((state) => state.language);
|
|
216
|
-
const [url, setUrl] = React.useState("");
|
|
217
|
-
const read = useMutation({ mutationFn: () => latticeApi.browserReadUrl(url) });
|
|
218
|
-
return (
|
|
219
|
-
<Card>
|
|
220
|
-
<CardHeader>
|
|
221
|
-
<CardTitle className="flex items-center gap-2"><Globe2 className="h-4 w-4" /> {t(language, "capture.browser.title")}</CardTitle>
|
|
222
|
-
<CardDescription>{t(language, "capture.browser.description")}</CardDescription>
|
|
223
|
-
</CardHeader>
|
|
224
|
-
<CardContent className="space-y-3">
|
|
225
|
-
<div className="flex flex-col gap-2 sm:flex-row">
|
|
226
|
-
<Input value={url} onChange={(e) => setUrl(e.target.value)} placeholder={t(language, "capture.browser.placeholder")} />
|
|
227
|
-
<Button disabled={!url.trim() || read.isPending} onClick={() => read.mutate()}>{t(language, "capture.browser.capture")}</Button>
|
|
228
|
-
</div>
|
|
229
|
-
{read.data ? <OperationResult result={read.data} successLabel={t(language, "capture.browser.success")} /> : null}
|
|
230
|
-
</CardContent>
|
|
231
|
-
</Card>
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function PipelinePanel() {
|
|
236
|
-
const language = useAppStore((state) => state.language);
|
|
237
|
-
const index = useQuery({ queryKey: ["index"], queryFn: latticeApi.indexStatus });
|
|
238
|
-
const stats = useQuery({ queryKey: ["graphStats"], queryFn: latticeApi.graphStats });
|
|
239
|
-
return (
|
|
240
|
-
<div className="grid gap-4 xl:grid-cols-2">
|
|
241
|
-
<DataPanel title={t(language, "capture.pipeline.status")} result={index.data}>
|
|
242
|
-
{(data) => <StructuredView value={data} />}
|
|
243
|
-
</DataPanel>
|
|
244
|
-
<DataPanel title={t(language, "capture.pipeline.growth")} result={stats.data}>
|
|
245
|
-
{(data) => <StructuredView value={data} />}
|
|
246
|
-
</DataPanel>
|
|
247
|
-
<Card className="xl:col-span-2">
|
|
248
|
-
<CardHeader>
|
|
249
|
-
<CardTitle className="flex items-center gap-2"><HardDrive className="h-4 w-4" /> {t(language, "capture.pipeline.refresh")}</CardTitle>
|
|
250
|
-
<CardDescription>{t(language, "capture.pipeline.description")}</CardDescription>
|
|
251
|
-
</CardHeader>
|
|
252
|
-
<CardContent>
|
|
253
|
-
<ActionButton label={t(language, "capture.pipeline.rebuild")} action={() => latticeApi.rebuildIndex()} invalidate={["index"]} />
|
|
254
|
-
</CardContent>
|
|
255
|
-
</Card>
|
|
256
|
-
</div>
|
|
257
|
-
);
|
|
258
|
-
}
|