larkup 0.1.29 → 0.1.31
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +5 -5
- package/.next/diagnostics/route-bundle-stats.json +35 -35
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +3 -3
- package/.next/required-server-files.js +4 -4
- package/.next/required-server-files.json +4 -4
- package/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +16 -16
- package/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/analytics/page/build-manifest.json +2 -2
- package/.next/server/app/analytics/page.js.nft.json +1 -1
- package/.next/server/app/analytics/page_client-reference-manifest.js +1 -1
- package/.next/server/app/analytics.html +1 -1
- package/.next/server/app/analytics.rsc +17 -17
- package/.next/server/app/analytics.segments/_full.segment.rsc +17 -17
- package/.next/server/app/analytics.segments/_head.segment.rsc +4 -4
- package/.next/server/app/analytics.segments/_index.segment.rsc +11 -11
- package/.next/server/app/analytics.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/analytics.segments/analytics/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/analytics.segments/analytics.segment.rsc +3 -3
- package/.next/server/app/api/analytics/route.js.nft.json +1 -1
- package/.next/server/app/api/chat/route.js.nft.json +1 -1
- package/.next/server/app/api/chat/status/route.js.nft.json +1 -1
- package/.next/server/app/api/chat/suggestions/route.js.nft.json +1 -1
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/config/test/route.js.nft.json +1 -1
- package/.next/server/app/api/config/test-embedding/route.js.nft.json +1 -1
- package/.next/server/app/api/config/test-llm/route.js.nft.json +1 -1
- package/.next/server/app/api/config/test-provider/route.js +4 -4
- package/.next/server/app/api/config/test-provider/route.js.nft.json +1 -1
- package/.next/server/app/api/config/verify/route.js +3 -3
- package/.next/server/app/api/config/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/server/app/api/connections/webhook/route.js.nft.json +1 -1
- package/.next/server/app/api/demo/route.js.nft.json +1 -1
- package/.next/server/app/api/deploy/cloud-project/route.js.nft.json +1 -1
- package/.next/server/app/api/deploy/ssh/route.js.nft.json +1 -1
- package/.next/server/app/api/deployment/blob-setup/route.js.nft.json +1 -1
- package/.next/server/app/api/deployment/config/route.js.nft.json +1 -1
- package/.next/server/app/api/describe-image/route.js.nft.json +1 -1
- package/.next/server/app/api/doc-editor/edit/route.js.nft.json +1 -1
- package/.next/server/app/api/doc-editor/export/route.js.nft.json +1 -1
- package/.next/server/app/api/doc-editor/extract-text/route.js.nft.json +1 -1
- package/.next/server/app/api/doc-editor/parse/route.js.nft.json +1 -1
- package/.next/server/app/api/doc-editor/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/document/sign/route.js.nft.json +1 -1
- package/.next/server/app/api/documents/route.js.nft.json +1 -1
- package/.next/server/app/api/firecrawl/local/route.js.nft.json +1 -1
- package/.next/server/app/api/index/route.js.nft.json +1 -1
- package/.next/server/app/api/integrations/notion/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/integrations/notion/route.js.nft.json +1 -1
- package/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/jobs/route.js.nft.json +1 -1
- package/.next/server/app/api/marketplace/[toolId]/route.js.nft.json +1 -1
- package/.next/server/app/api/marketplace/route.js.nft.json +1 -1
- package/.next/server/app/api/media/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/media/process/route.js.nft.json +1 -1
- package/.next/server/app/api/media/route.js.nft.json +1 -1
- package/.next/server/app/api/media/stream/route.js.nft.json +1 -1
- package/.next/server/app/api/models/route.js.nft.json +1 -1
- package/.next/server/app/api/parse-file/route.js.nft.json +1 -1
- package/.next/server/app/api/proxy/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/sandbox/route.js.nft.json +1 -1
- package/.next/server/app/api/search/bing/route.js.nft.json +1 -1
- package/.next/server/app/api/search/brave/route.js.nft.json +1 -1
- package/.next/server/app/api/search/exa/route.js.nft.json +1 -1
- package/.next/server/app/api/search/google/route.js.nft.json +1 -1
- package/.next/server/app/api/search/route.js.nft.json +1 -1
- package/.next/server/app/api/search/tavily/route.js.nft.json +1 -1
- package/.next/server/app/api/search/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/server/agent/route.js.nft.json +1 -1
- package/.next/server/app/api/server/download/route.js.nft.json +1 -1
- package/.next/server/app/api/server/generate/route.js.nft.json +1 -1
- package/.next/server/app/api/server/local/route.js.nft.json +1 -1
- package/.next/server/app/api/servers/route.js.nft.json +1 -1
- package/.next/server/app/api/tabular/query/route.js.nft.json +1 -1
- package/.next/server/app/api/tabular/route.js.nft.json +1 -1
- package/.next/server/app/api/upload-file/route.js.nft.json +1 -1
- package/.next/server/app/api/uploads/[...slug]/route.js.nft.json +1 -1
- package/.next/server/app/api/vector-stores/install/route.js.nft.json +1 -1
- package/.next/server/app/api/vector-stores/status/route.js.nft.json +1 -1
- package/.next/server/app/chat/page/build-manifest.json +2 -2
- package/.next/server/app/chat/page.js.nft.json +1 -1
- package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/chat.html +1 -1
- package/.next/server/app/chat.rsc +17 -17
- package/.next/server/app/chat.segments/_full.segment.rsc +17 -17
- package/.next/server/app/chat.segments/_head.segment.rsc +4 -4
- package/.next/server/app/chat.segments/_index.segment.rsc +11 -11
- package/.next/server/app/chat.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/chat.segments/chat/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/chat.segments/chat.segment.rsc +3 -3
- package/.next/server/app/data/page/build-manifest.json +2 -2
- package/.next/server/app/data/page.js.nft.json +1 -1
- package/.next/server/app/data/page_client-reference-manifest.js +1 -1
- package/.next/server/app/data.html +1 -1
- package/.next/server/app/data.rsc +17 -17
- package/.next/server/app/data.segments/_full.segment.rsc +17 -17
- package/.next/server/app/data.segments/_head.segment.rsc +4 -4
- package/.next/server/app/data.segments/_index.segment.rsc +11 -11
- package/.next/server/app/data.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/data.segments/data/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/data.segments/data.segment.rsc +3 -3
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +16 -16
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +16 -16
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +11 -11
- package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/page/build-manifest.json +2 -2
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/page/build-manifest.json +2 -2
- package/.next/server/app/settings/page/server-reference-manifest.json +3 -3
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +18 -18
- package/.next/server/app/settings.segments/_full.segment.rsc +18 -18
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +11 -11
- package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_0kbcuk-.js +17 -3
- package/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_1f4h7rr.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__01al2n0._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__067hiof._.js +18 -6
- package/.next/server/chunks/[root-of-the-server]__0a_0ywc._.js +18 -6
- package/.next/server/chunks/[root-of-the-server]__0u17zp8._.js +18 -6
- package/.next/server/chunks/{[root-of-the-server]__1xuhh_i._.js → [root-of-the-server]__16jk_se._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__1ahdfq9._.js +18 -6
- package/.next/server/chunks/[root-of-the-server]__1o3rcbz._.js +2 -1
- package/.next/server/chunks/{[root-of-the-server]__10gcb7d._.js → [root-of-the-server]__1qh2h5v._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__1s9is1o._.js +2 -1
- package/.next/server/chunks/[root-of-the-server]__1vsvck0._.js +18 -6
- package/.next/server/chunks/[root-of-the-server]__1wy6wes._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1zptg4z._.js +2 -1
- package/.next/server/chunks/packages_core_src_generator_generate-server_ts_11-w3m3._.js +2 -2
- package/.next/server/chunks/packages_core_src_generator_server-runtime_ts_1_68l7t._.js +4 -4
- package/.next/server/chunks/packages_marketplace_src_125_g2p._.js +1 -1
- package/.next/server/chunks/ssr/{[root-of-the-server]__0wdatpx._.js → [root-of-the-server]__0m21fli._.js} +1 -1
- package/.next/server/chunks/ssr/{[root-of-the-server]__1r9ap67._.js → [root-of-the-server]__0t8ud_u._.js} +1 -1
- package/.next/server/chunks/ssr/{[root-of-the-server]__046ldu_._.js → [root-of-the-server]__0xyo3ni._.js} +1 -1
- package/.next/server/chunks/ssr/{_0k81--x._.js → _0ckxy33._.js} +2 -2
- package/.next/server/chunks/ssr/_169pdlf._.js +6 -6
- package/.next/server/chunks/ssr/_1hetwwu._.js +4 -3
- package/.next/server/chunks/ssr/_1iff9ia._.js +1 -1
- package/.next/server/chunks/ssr/_1yqlx1m._.js +1 -1
- package/.next/server/chunks/ssr/apps_web_components_analytics_analytics-dashboard_tsx_1056-z3._.js +1 -1
- package/.next/server/chunks/ssr/packages_core_src_generator_generate-server_ts_15zzrn2._.js +2 -2
- package/.next/server/functions-config-manifest.json +3 -1
- package/.next/server/middleware-build-manifest.js +5 -5
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +4 -4
- package/.next/static/chunks/{1sh7d5tt49x8b.js → 0ff5osu771ajz.js} +6 -6
- package/.next/static/chunks/{1z4nte07k3dt6.js → 1-afr-snks55m.js} +1 -1
- package/.next/static/chunks/{1dykihoo_1ae5.js → 1fz_0-qb5r5wd.js} +1 -1
- package/.next/static/chunks/{3g_wl1fri6jb-.js → 21_6-9hjj2i68.js} +1 -1
- package/.next/static/chunks/{13kyiy7q3of41.js → 2jqjx4-rh414_.js} +1 -1
- package/.next/static/chunks/2jrpgzxyrmuqp.js +121 -0
- package/.next/static/chunks/390ds7l_plpmd.js +1 -0
- package/.next/static/chunks/{3een1tiktxr6a.js → 3zw6tgf7mxo39.js} +1 -1
- package/.next/static/chunks/{turbopack-2qt7vn_ocj4ao.js → turbopack-2gu-fmc6o5wkn.js} +1 -1
- package/CHANGELOG.md +33 -0
- package/app/api/chat/route.ts +14 -1
- package/app/api/chat/tools.ts +7 -3
- package/app/api/config/test-provider/route.ts +16 -18
- package/app/api/config/verify/route.ts +5 -7
- package/app/api/firecrawl/local/route.ts +7 -4
- package/app/api/jobs/route.ts +1 -2
- package/app/api/marketplace/[toolId]/route.ts +1 -0
- package/archive/redesign-v2/app/configure/page.tsx +53 -0
- package/archive/redesign-v2/app/demo/page.tsx +15 -0
- package/archive/redesign-v2/app/server/page.tsx +22 -0
- package/archive/redesign-v2/app/simple/chat/page.tsx +17 -0
- package/archive/redesign-v2/app/simple/docs/page.tsx +21 -0
- package/archive/redesign-v2/app/simple/settings/page.tsx +1104 -0
- package/archive/redesign-v2/app-routes/configure/page.tsx +53 -0
- package/archive/redesign-v2/app-routes/demo/page.tsx +15 -0
- package/archive/redesign-v2/app-routes/server/page.tsx +22 -0
- package/archive/redesign-v2/app-routes/simple/chat/page.tsx +17 -0
- package/archive/redesign-v2/app-routes/simple/docs/page.tsx +21 -0
- package/archive/redesign-v2/app-routes/simple/layout.tsx +9 -0
- package/archive/redesign-v2/app-routes/simple/settings/page.tsx +1104 -0
- package/archive/redesign-v2/components/app-sidebar.tsx +188 -0
- package/archive/redesign-v2/components/app-topnav.tsx +195 -0
- package/archive/redesign-v2/components/global-settings.tsx +288 -0
- package/archive/redesign-v2/components/simple/simple-sidebar.tsx +171 -0
- package/archive/redesign-v2/components/simple/simple-topnav.tsx +175 -0
- package/components/analytics/analytics-dashboard.tsx +1 -1
- package/components/data/firecrawl-notice.tsx +41 -98
- package/components/data/media-panel.tsx +0 -3
- package/components/data/scrape-panel.tsx +17 -1
- package/components/onboarding/welcome-screen.tsx +45 -15
- package/components/settings/general-section.tsx +15 -10
- package/components/settings/server-section.tsx +3 -3
- package/lib/error-formatter.ts +19 -4
- package/next-env.d.ts +1 -1
- package/package.json +7 -7
- package/.next/static/chunks/01qmngac69n9j.js +0 -1
- package/.next/static/chunks/102b8vinedggz.js +0 -120
- /package/.next/static/{W6QdudzTPo_OVPpNt29f7 → kaW1RhJBmrNB5F_JAJ6QO}/_buildManifest.js +0 -0
- /package/.next/static/{W6QdudzTPo_OVPpNt29f7 → kaW1RhJBmrNB5F_JAJ6QO}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{W6QdudzTPo_OVPpNt29f7 → kaW1RhJBmrNB5F_JAJ6QO}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { usePathname } from "next/navigation";
|
|
5
|
+
import {
|
|
6
|
+
FileStack,
|
|
7
|
+
FlaskConical,
|
|
8
|
+
Lock,
|
|
9
|
+
type LucideIcon,
|
|
10
|
+
MessageCircle,
|
|
11
|
+
Server,
|
|
12
|
+
SlidersHorizontal,
|
|
13
|
+
} from "lucide-react";
|
|
14
|
+
import { cn } from "@/lib/utils";
|
|
15
|
+
import { STAGES, CURRENT_PHASE } from "@larkup/core/stages";
|
|
16
|
+
import type { StageId } from "@larkup/core/types";
|
|
17
|
+
import {
|
|
18
|
+
Tooltip,
|
|
19
|
+
TooltipContent,
|
|
20
|
+
TooltipProvider,
|
|
21
|
+
TooltipTrigger,
|
|
22
|
+
} from "@/components/ui/tooltip";
|
|
23
|
+
import {
|
|
24
|
+
useThemeCustomizer,
|
|
25
|
+
type PanelBgVariant,
|
|
26
|
+
} from "./theme-customizer-provider";
|
|
27
|
+
import { ThemeSwitcher } from "./theme-switcher";
|
|
28
|
+
|
|
29
|
+
const NAV_BG_COLORS: Record<PanelBgVariant, string | undefined> = {
|
|
30
|
+
"panel-default": undefined,
|
|
31
|
+
"panel-white": "#FFFFFF",
|
|
32
|
+
"panel-fafafa": "#F4F4F4",
|
|
33
|
+
"panel-warm": "#F7F1EA",
|
|
34
|
+
"panel-soft": "#FBFAF8",
|
|
35
|
+
"panel-silver": "#F8F8F8",
|
|
36
|
+
"panel-stone": "#F5F5F2",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// [#CDA1FE]
|
|
40
|
+
const STAGE_ICONS: Record<StageId, LucideIcon> = {
|
|
41
|
+
configure: SlidersHorizontal,
|
|
42
|
+
data: FileStack,
|
|
43
|
+
server: Server,
|
|
44
|
+
demo: FlaskConical,
|
|
45
|
+
chat: MessageCircle,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export function AppSidebar() {
|
|
49
|
+
const pathname = usePathname();
|
|
50
|
+
const { pageStyle, navBg } = useThemeCustomizer();
|
|
51
|
+
|
|
52
|
+
const navColor = navBg ? NAV_BG_COLORS[navBg] : undefined;
|
|
53
|
+
const navStyle = navColor ? { backgroundColor: navColor } : undefined;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<TooltipProvider delay={150}>
|
|
57
|
+
<aside
|
|
58
|
+
className={cn(
|
|
59
|
+
"sticky top-0 hidden h-screen w-[84px] shrink-0 flex-col items-center gap-1 self-start py-3 md:flex",
|
|
60
|
+
!navColor ? "bg-background" : "",
|
|
61
|
+
pageStyle === "fused" ? "border-r border-border" : "",
|
|
62
|
+
)}
|
|
63
|
+
style={navStyle}
|
|
64
|
+
>
|
|
65
|
+
{/* Brand */}
|
|
66
|
+
<Tooltip>
|
|
67
|
+
<TooltipTrigger
|
|
68
|
+
render={
|
|
69
|
+
<Link
|
|
70
|
+
href="/configure"
|
|
71
|
+
aria-label="larkup home"
|
|
72
|
+
className="mb-2 flex size-11 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm transition-transform hover:scale-105"
|
|
73
|
+
/>
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
{/* <Boxes className="size-5" /> */}
|
|
77
|
+
<img src={"/logo9.png"} className="size-6.5" alt="logo" />
|
|
78
|
+
</TooltipTrigger>
|
|
79
|
+
<TooltipContent side="right" sideOffset={10}>
|
|
80
|
+
Larkup
|
|
81
|
+
</TooltipContent>
|
|
82
|
+
</Tooltip>
|
|
83
|
+
|
|
84
|
+
{/* Pipeline rail */}
|
|
85
|
+
<nav className="flex flex-1 flex-col items-center gap-4.5 ">
|
|
86
|
+
{STAGES.map((stage) => {
|
|
87
|
+
const Icon = STAGE_ICONS[stage.id];
|
|
88
|
+
const active =
|
|
89
|
+
pathname === stage.href ||
|
|
90
|
+
(stage.href === "/configure" && pathname === "/");
|
|
91
|
+
const locked = stage.phase > CURRENT_PHASE;
|
|
92
|
+
|
|
93
|
+
const body = (
|
|
94
|
+
<>
|
|
95
|
+
{/* active accent bar (Teams-style) */}
|
|
96
|
+
<span
|
|
97
|
+
className={cn(
|
|
98
|
+
"absolute left-0 top-1/2 h-6 w-1 -translate-y-1/2 rounded-r-full bg-primary transition-opacity",
|
|
99
|
+
active ? "opacity-100" : "opacity-0",
|
|
100
|
+
)}
|
|
101
|
+
/>
|
|
102
|
+
<span
|
|
103
|
+
className={cn(
|
|
104
|
+
"relative flex size-9 items-center justify-center rounded-xl transition-colors",
|
|
105
|
+
active
|
|
106
|
+
? "bg-white border text-primary"
|
|
107
|
+
: locked
|
|
108
|
+
? "text-muted-foreground/50"
|
|
109
|
+
: "text-foreground/70 group-hover:bg-white/90 group-hover:text-foreground",
|
|
110
|
+
)}
|
|
111
|
+
>
|
|
112
|
+
<Icon
|
|
113
|
+
className="size-[19px]"
|
|
114
|
+
strokeWidth={active ? 2.25 : 2}
|
|
115
|
+
/>
|
|
116
|
+
{locked && (
|
|
117
|
+
<span className="absolute -right-0.5 -top-0.5 flex size-3.5 items-center justify-center rounded-full bg-background">
|
|
118
|
+
<Lock className="size-2.5 text-muted-foreground" />
|
|
119
|
+
</span>
|
|
120
|
+
)}
|
|
121
|
+
</span>
|
|
122
|
+
<span
|
|
123
|
+
className={cn(
|
|
124
|
+
"text-[10px] leading-none tracking-tight",
|
|
125
|
+
active
|
|
126
|
+
? "font-semibold text-primary"
|
|
127
|
+
: locked
|
|
128
|
+
? "text-muted-foreground/50"
|
|
129
|
+
: "text-muted-foreground",
|
|
130
|
+
)}
|
|
131
|
+
>
|
|
132
|
+
{stage.label}
|
|
133
|
+
</span>
|
|
134
|
+
</>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Tooltip key={stage.id}>
|
|
139
|
+
<TooltipTrigger
|
|
140
|
+
render={
|
|
141
|
+
locked ? (
|
|
142
|
+
<div
|
|
143
|
+
aria-disabled
|
|
144
|
+
className="group relative flex w-16 cursor-not-allowed flex-col items-center gap-0.5 rounded-2xl py-1"
|
|
145
|
+
/>
|
|
146
|
+
) : (
|
|
147
|
+
<Link
|
|
148
|
+
href={stage.href}
|
|
149
|
+
aria-current={active ? "page" : undefined}
|
|
150
|
+
className="group relative flex w-16 flex-col items-center gap-0.5 rounded-2xl py-1 outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
151
|
+
/>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
>
|
|
155
|
+
{body}
|
|
156
|
+
</TooltipTrigger>
|
|
157
|
+
<TooltipContent
|
|
158
|
+
side="right"
|
|
159
|
+
sideOffset={10}
|
|
160
|
+
className="max-w-56"
|
|
161
|
+
>
|
|
162
|
+
<div className="flex flex-col gap-0.5">
|
|
163
|
+
<span className="font-medium">
|
|
164
|
+
{stage.label}
|
|
165
|
+
{locked && (
|
|
166
|
+
<span className="ml-1.5 font-mono text-[10px] opacity-70">
|
|
167
|
+
Phase {stage.phase}
|
|
168
|
+
</span>
|
|
169
|
+
)}
|
|
170
|
+
</span>
|
|
171
|
+
<span className="text-[11px] leading-snug opacity-80">
|
|
172
|
+
{locked
|
|
173
|
+
? `Unlocks in Phase ${stage.phase}.`
|
|
174
|
+
: stage.description}
|
|
175
|
+
</span>
|
|
176
|
+
</div>
|
|
177
|
+
</TooltipContent>
|
|
178
|
+
</Tooltip>
|
|
179
|
+
);
|
|
180
|
+
})}
|
|
181
|
+
</nav>
|
|
182
|
+
|
|
183
|
+
{/* Footer — dual-mode indicator */}
|
|
184
|
+
<ThemeSwitcher floating={false} />
|
|
185
|
+
</aside>
|
|
186
|
+
</TooltipProvider>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { usePathname } from "next/navigation";
|
|
5
|
+
import {
|
|
6
|
+
FileStack,
|
|
7
|
+
FlaskConical,
|
|
8
|
+
Layers,
|
|
9
|
+
Lock,
|
|
10
|
+
type LucideIcon,
|
|
11
|
+
MessageCircle,
|
|
12
|
+
Server,
|
|
13
|
+
SlidersHorizontal,
|
|
14
|
+
} from "lucide-react";
|
|
15
|
+
import { cn } from "@/lib/utils";
|
|
16
|
+
import { STAGES, CURRENT_PHASE } from "@larkup/core/stages";
|
|
17
|
+
import type { StageId } from "@larkup/core/types";
|
|
18
|
+
import {
|
|
19
|
+
Tooltip,
|
|
20
|
+
TooltipContent,
|
|
21
|
+
TooltipProvider,
|
|
22
|
+
TooltipTrigger,
|
|
23
|
+
} from "@/components/ui/tooltip";
|
|
24
|
+
import { ServerSwitcher } from "@/components/workspace/server-switcher";
|
|
25
|
+
import { useWorkspace } from "@/components/workspace/workspace-provider";
|
|
26
|
+
import { ThemeSwitcher } from "./theme-switcher";
|
|
27
|
+
import { useThemeCustomizer, type PanelBgVariant } from "./theme-customizer-provider";
|
|
28
|
+
|
|
29
|
+
const NAV_BG_COLORS: Record<PanelBgVariant, string | undefined> = {
|
|
30
|
+
"panel-default": undefined,
|
|
31
|
+
"panel-white": "#FFFFFF",
|
|
32
|
+
"panel-fafafa": "#F4F4F4",
|
|
33
|
+
"panel-warm": "#F7F1EA",
|
|
34
|
+
"panel-soft": "#FBFAF8",
|
|
35
|
+
"panel-silver": "#F8F8F8",
|
|
36
|
+
"panel-stone": "#F5F5F2",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const STAGE_ICONS: Record<StageId, LucideIcon> = {
|
|
40
|
+
configure: SlidersHorizontal,
|
|
41
|
+
data: FileStack,
|
|
42
|
+
index: Layers,
|
|
43
|
+
server: Server,
|
|
44
|
+
demo: FlaskConical,
|
|
45
|
+
chat: MessageCircle,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export function AppTopNav() {
|
|
49
|
+
const pathname = usePathname();
|
|
50
|
+
const { username } = useWorkspace();
|
|
51
|
+
const { navBg } = useThemeCustomizer();
|
|
52
|
+
|
|
53
|
+
const navColor = navBg ? NAV_BG_COLORS[navBg] : undefined;
|
|
54
|
+
const navStyle = navColor ? { backgroundColor: navColor } : undefined;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<TooltipProvider delay={150}>
|
|
58
|
+
<header
|
|
59
|
+
className={cn(
|
|
60
|
+
"sticky top-0 z-50 flex h-16 shrink-0 items-center gap-4 border-b border-border px-4 md:px-6",
|
|
61
|
+
!navColor ? "bg-white" : "",
|
|
62
|
+
)}
|
|
63
|
+
style={navStyle}
|
|
64
|
+
>
|
|
65
|
+
{/* Brand */}
|
|
66
|
+
<Link
|
|
67
|
+
href="/configure"
|
|
68
|
+
aria-label="larkup home"
|
|
69
|
+
className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm transition-transform hover:scale-105"
|
|
70
|
+
>
|
|
71
|
+
<img src={"/logo9.png"} className="size-5" alt="logo" />
|
|
72
|
+
</Link>
|
|
73
|
+
<span className="font-semibold tracking-tight hidden sm:inline-block">
|
|
74
|
+
Larkup
|
|
75
|
+
</span>
|
|
76
|
+
|
|
77
|
+
{/* Pipeline rail */}
|
|
78
|
+
<nav className="flex flex-1 h-full items-end pb-0 gap-2 md:gap-4 ml-4">
|
|
79
|
+
{STAGES.map((stage, index) => {
|
|
80
|
+
const Icon = STAGE_ICONS[stage.id];
|
|
81
|
+
const active =
|
|
82
|
+
pathname === stage.href ||
|
|
83
|
+
(stage.href === "/configure" && pathname === "/");
|
|
84
|
+
const locked = stage.phase > CURRENT_PHASE;
|
|
85
|
+
|
|
86
|
+
const body = (
|
|
87
|
+
<div className="flex items-center ">
|
|
88
|
+
<span
|
|
89
|
+
className={cn(
|
|
90
|
+
"flex size-9 items-center justify-center rounded-lg transition-colors",
|
|
91
|
+
active
|
|
92
|
+
? "text-primary"
|
|
93
|
+
: locked
|
|
94
|
+
? "text-muted-foreground/50"
|
|
95
|
+
: "text-muted-foreground group-hover:text-foreground",
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
<Icon
|
|
99
|
+
className="size-[18px]"
|
|
100
|
+
strokeWidth={active ? 2.25 : 2}
|
|
101
|
+
/>
|
|
102
|
+
{locked && (
|
|
103
|
+
<span className="absolute -right-0.5 -top-0.5 flex size-3 items-center justify-center rounded-full bg-background">
|
|
104
|
+
<Lock className="size-2 text-muted-foreground" />
|
|
105
|
+
</span>
|
|
106
|
+
)}
|
|
107
|
+
</span>
|
|
108
|
+
<span
|
|
109
|
+
className={cn(
|
|
110
|
+
"hidden md:block text-[13px] tracking-tight",
|
|
111
|
+
active
|
|
112
|
+
? "font-semibold text-primary"
|
|
113
|
+
: locked
|
|
114
|
+
? "text-muted-foreground/50"
|
|
115
|
+
: "text-muted-foreground group-hover:text-foreground",
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
{index + 1}. {stage.label}
|
|
119
|
+
</span>
|
|
120
|
+
{/* active accent bar (bottom) */}
|
|
121
|
+
<span
|
|
122
|
+
className={cn(
|
|
123
|
+
"absolute bottom-0 left-0 h-0.5 w-full bg-primary transition-opacity",
|
|
124
|
+
active
|
|
125
|
+
? "opacity-100"
|
|
126
|
+
: "opacity-0 group-hover:opacity-100",
|
|
127
|
+
)}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<Tooltip key={stage.id}>
|
|
134
|
+
<TooltipTrigger
|
|
135
|
+
render={
|
|
136
|
+
locked ? (
|
|
137
|
+
<div
|
|
138
|
+
aria-disabled
|
|
139
|
+
className="group relative flex cursor-not-allowed items-center gap-2 h-10 px-3 rounded-md transition-colors"
|
|
140
|
+
/>
|
|
141
|
+
) : (
|
|
142
|
+
<Link
|
|
143
|
+
href={stage.href}
|
|
144
|
+
aria-current={active ? "page" : undefined}
|
|
145
|
+
className={cn(
|
|
146
|
+
"group relative flex items-center gap-2 h-10 px-3 rounded-md transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
147
|
+
active ? "bg-muted/0" : "hover:bg-muted/30",
|
|
148
|
+
)}
|
|
149
|
+
/>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
>
|
|
153
|
+
{body}
|
|
154
|
+
</TooltipTrigger>
|
|
155
|
+
<TooltipContent
|
|
156
|
+
side="bottom"
|
|
157
|
+
sideOffset={10}
|
|
158
|
+
className="max-w-56"
|
|
159
|
+
>
|
|
160
|
+
<div className="flex flex-col gap-0.5">
|
|
161
|
+
<span className="font-medium">
|
|
162
|
+
{index + 1}. {stage.label}
|
|
163
|
+
{locked && (
|
|
164
|
+
<span className="ml-1.5 font-mono text-[10px] opacity-70">
|
|
165
|
+
Phase {stage.phase}
|
|
166
|
+
</span>
|
|
167
|
+
)}
|
|
168
|
+
</span>
|
|
169
|
+
<span className="text-[11px] leading-snug opacity-80">
|
|
170
|
+
{locked
|
|
171
|
+
? `Unlocks in Phase ${stage.phase}.`
|
|
172
|
+
: stage.description}
|
|
173
|
+
</span>
|
|
174
|
+
</div>
|
|
175
|
+
</TooltipContent>
|
|
176
|
+
</Tooltip>
|
|
177
|
+
);
|
|
178
|
+
})}
|
|
179
|
+
</nav>
|
|
180
|
+
|
|
181
|
+
{/* Right side: Workspace & Theme Customizer */}
|
|
182
|
+
<div className="flex items-center gap-3">
|
|
183
|
+
<ServerSwitcher />
|
|
184
|
+
{username && (
|
|
185
|
+
<span className="hidden text-sm text-muted-foreground md:block">
|
|
186
|
+
Hi,{" "}
|
|
187
|
+
<span className="font-medium text-foreground">{username}</span>
|
|
188
|
+
</span>
|
|
189
|
+
)}
|
|
190
|
+
<ThemeSwitcher floating={false} />{" "}
|
|
191
|
+
</div>
|
|
192
|
+
</header>
|
|
193
|
+
</TooltipProvider>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import useSWR from "swr";
|
|
5
|
+
import { Loader2, Save, ChevronLeft } from "lucide-react";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { Input } from "@/components/ui/input";
|
|
8
|
+
import { Label } from "@/components/ui/label";
|
|
9
|
+
import { toast } from "sonner";
|
|
10
|
+
import { RagConfig } from "@larkup/core/types";
|
|
11
|
+
import {
|
|
12
|
+
Select,
|
|
13
|
+
SelectContent,
|
|
14
|
+
SelectItem,
|
|
15
|
+
SelectTrigger,
|
|
16
|
+
} from "@/components/ui/select";
|
|
17
|
+
import { useSearchParams, useRouter, usePathname } from "next/navigation";
|
|
18
|
+
import { useWorkspace } from "@/components/workspace/workspace-provider";
|
|
19
|
+
|
|
20
|
+
const fetcher = (url: string) =>
|
|
21
|
+
fetch(url).then((r) => r.json() as Promise<{ config: RagConfig }>);
|
|
22
|
+
|
|
23
|
+
export function GlobalSettings({ onBack }: { onBack: () => void }) {
|
|
24
|
+
const { data, isLoading, mutate } = useSWR("/api/config", fetcher);
|
|
25
|
+
const [form, setForm] = useState<Partial<RagConfig>>({});
|
|
26
|
+
const [saving, setSaving] = useState(false);
|
|
27
|
+
|
|
28
|
+
const searchParams = useSearchParams();
|
|
29
|
+
const highlightSerper = searchParams.get("settings") === "serper";
|
|
30
|
+
const router = useRouter();
|
|
31
|
+
const pathname = usePathname();
|
|
32
|
+
const { setMode } = useWorkspace();
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (data?.config) {
|
|
36
|
+
setForm(data.config);
|
|
37
|
+
}
|
|
38
|
+
}, [data]);
|
|
39
|
+
|
|
40
|
+
const handleSave = async () => {
|
|
41
|
+
setSaving(true);
|
|
42
|
+
try {
|
|
43
|
+
const res = await fetch("/api/config", {
|
|
44
|
+
method: "PUT",
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
body: JSON.stringify({ ...data?.config, ...form }),
|
|
47
|
+
});
|
|
48
|
+
const json = await res.json();
|
|
49
|
+
if (!res.ok)
|
|
50
|
+
throw new Error(json.error ?? "Failed to save configuration");
|
|
51
|
+
|
|
52
|
+
await mutate(json, { revalidate: false });
|
|
53
|
+
toast.success("Global Settings saved");
|
|
54
|
+
|
|
55
|
+
if (highlightSerper) {
|
|
56
|
+
// Remove the query param if it was set
|
|
57
|
+
const params = new URLSearchParams(searchParams);
|
|
58
|
+
params.delete("settings");
|
|
59
|
+
router.replace(`${pathname}?${params.toString()}`);
|
|
60
|
+
}
|
|
61
|
+
} catch (err) {
|
|
62
|
+
toast.error(err instanceof Error ? err.message : "Failed to save");
|
|
63
|
+
} finally {
|
|
64
|
+
setSaving(false);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (isLoading) {
|
|
69
|
+
return (
|
|
70
|
+
<div className="flex items-center justify-center h-40">
|
|
71
|
+
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className="flex flex-col min-h-0 h-full">
|
|
78
|
+
<div className="border-b px-4 py-3 font-semibold flex items-center gap-2 shrink-0 bg-muted/30">
|
|
79
|
+
<Button
|
|
80
|
+
variant="ghost"
|
|
81
|
+
size="icon"
|
|
82
|
+
className="h-6 w-6 shrink-0"
|
|
83
|
+
onClick={onBack}
|
|
84
|
+
>
|
|
85
|
+
<ChevronLeft className="h-4 w-4" />
|
|
86
|
+
</Button>
|
|
87
|
+
<span className="flex-1 truncate">Global Settings</span>
|
|
88
|
+
<Button
|
|
89
|
+
size="sm"
|
|
90
|
+
onClick={handleSave}
|
|
91
|
+
disabled={saving}
|
|
92
|
+
className="h-7 px-3 text-xs"
|
|
93
|
+
>
|
|
94
|
+
{saving ? (
|
|
95
|
+
<Loader2 className="h-3 w-3 mr-1 animate-spin" />
|
|
96
|
+
) : (
|
|
97
|
+
<Save className="h-3 w-3 mr-1" />
|
|
98
|
+
)}
|
|
99
|
+
Save
|
|
100
|
+
</Button>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div className="flex-1 min-h-0 p-4 space-y-6 overflow-y-auto ">
|
|
104
|
+
<div className="space-y-4">
|
|
105
|
+
<div className=" bg-card text-card-foreground p-3 space-y-3">
|
|
106
|
+
<h4 className="font-semibold leading-none tracking-tight text-sm">
|
|
107
|
+
Embedding
|
|
108
|
+
</h4>
|
|
109
|
+
<div className="space-y-1.5">
|
|
110
|
+
<Label className="text-xs">Provider</Label>
|
|
111
|
+
<Select
|
|
112
|
+
value={form.embeddingProvider || ""}
|
|
113
|
+
onValueChange={(v) =>
|
|
114
|
+
setForm({ ...form, embeddingProvider: v === null ? undefined : v })
|
|
115
|
+
}
|
|
116
|
+
>
|
|
117
|
+
<SelectTrigger className="h-8! text-sm w-full">
|
|
118
|
+
<span>{form.embeddingProvider || "Select provider"}</span>
|
|
119
|
+
</SelectTrigger>
|
|
120
|
+
<SelectContent>
|
|
121
|
+
<SelectItem value="openai">OpenAI</SelectItem>
|
|
122
|
+
<SelectItem value="google">Google</SelectItem>
|
|
123
|
+
<SelectItem value="cohere">Cohere</SelectItem>
|
|
124
|
+
<SelectItem value="mistral">Mistral</SelectItem>
|
|
125
|
+
<SelectItem value="deepseek">DeepSeek</SelectItem>
|
|
126
|
+
<SelectItem value="vercel_ai_gateway">
|
|
127
|
+
Vercel AI Gateway
|
|
128
|
+
</SelectItem>
|
|
129
|
+
</SelectContent>
|
|
130
|
+
</Select>
|
|
131
|
+
</div>
|
|
132
|
+
<div className="space-y-1.5">
|
|
133
|
+
<Label className="text-xs">API Key</Label>
|
|
134
|
+
<Input
|
|
135
|
+
type="password"
|
|
136
|
+
className="h-8 text-sm"
|
|
137
|
+
value={form.embeddingApiKey || ""}
|
|
138
|
+
onChange={(e) =>
|
|
139
|
+
setForm({ ...form, embeddingApiKey: e.target.value })
|
|
140
|
+
}
|
|
141
|
+
placeholder="sk-..."
|
|
142
|
+
/>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div className=" text-card-foreground p-3 space-y-3">
|
|
147
|
+
<h4 className="font-semibold leading-none tracking-tight text-sm">
|
|
148
|
+
Chat (LLM)
|
|
149
|
+
</h4>
|
|
150
|
+
<div className="space-y-1.5">
|
|
151
|
+
<Label className="text-xs">Provider</Label>
|
|
152
|
+
<Select
|
|
153
|
+
value={form.chatProvider || form.embeddingProvider || ""}
|
|
154
|
+
onValueChange={(v) =>
|
|
155
|
+
setForm({ ...form, chatProvider: v === null ? undefined : v })
|
|
156
|
+
}
|
|
157
|
+
>
|
|
158
|
+
<SelectTrigger className="h-8! w-full text-sm">
|
|
159
|
+
<span>
|
|
160
|
+
{form.chatProvider ||
|
|
161
|
+
form.embeddingProvider ||
|
|
162
|
+
"Select provider"}
|
|
163
|
+
</span>
|
|
164
|
+
</SelectTrigger>
|
|
165
|
+
<SelectContent>
|
|
166
|
+
<SelectItem value="openai">OpenAI</SelectItem>
|
|
167
|
+
<SelectItem value="google">Google</SelectItem>
|
|
168
|
+
<SelectItem value="cohere">Cohere</SelectItem>
|
|
169
|
+
<SelectItem value="mistral">Mistral</SelectItem>
|
|
170
|
+
<SelectItem value="deepseek">DeepSeek</SelectItem>
|
|
171
|
+
<SelectItem value="vercel_ai_gateway">
|
|
172
|
+
Vercel AI Gateway
|
|
173
|
+
</SelectItem>
|
|
174
|
+
</SelectContent>
|
|
175
|
+
</Select>
|
|
176
|
+
</div>
|
|
177
|
+
<div className="space-y-1.5">
|
|
178
|
+
<Label className="text-xs">API Key</Label>
|
|
179
|
+
<Input
|
|
180
|
+
type="password"
|
|
181
|
+
className="h-8 text-sm"
|
|
182
|
+
value={form.chatApiKey || ""}
|
|
183
|
+
onChange={(e) =>
|
|
184
|
+
setForm({ ...form, chatApiKey: e.target.value })
|
|
185
|
+
}
|
|
186
|
+
placeholder="Leave blank to use Embedding Key"
|
|
187
|
+
/>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<div className=" bg-card text-card-foreground p-3 space-y-3">
|
|
192
|
+
<h4 className="font-semibold leading-none tracking-tight text-sm">
|
|
193
|
+
Web Search
|
|
194
|
+
</h4>
|
|
195
|
+
<div className="space-y-1.5">
|
|
196
|
+
<Label className="text-xs">Serper.dev API Key</Label>
|
|
197
|
+
<Input
|
|
198
|
+
type="password"
|
|
199
|
+
className={`h-8 text-sm ${highlightSerper && !form.serperApiKey ? "border-red-500 focus-visible:ring-red-500" : ""}`}
|
|
200
|
+
value={form.serperApiKey || ""}
|
|
201
|
+
onChange={(e) =>
|
|
202
|
+
setForm({ ...form, serperApiKey: e.target.value })
|
|
203
|
+
}
|
|
204
|
+
placeholder="Serper API Key"
|
|
205
|
+
/>
|
|
206
|
+
{highlightSerper && !form.serperApiKey && (
|
|
207
|
+
<p className="text-[10px] text-red-500">
|
|
208
|
+
API Key is required for web search.
|
|
209
|
+
</p>
|
|
210
|
+
)}
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<div className=" bg-card text-card-foreground p-3 space-y-3">
|
|
215
|
+
<h4 className="font-semibold leading-none tracking-tight text-sm">
|
|
216
|
+
Scraper
|
|
217
|
+
</h4>
|
|
218
|
+
<div className="space-y-1.5">
|
|
219
|
+
<Label className="text-xs">Proxy Server</Label>
|
|
220
|
+
<Input
|
|
221
|
+
className="h-8 text-sm"
|
|
222
|
+
value={form.scraperProxyServer || ""}
|
|
223
|
+
onChange={(e) =>
|
|
224
|
+
setForm({ ...form, scraperProxyServer: e.target.value })
|
|
225
|
+
}
|
|
226
|
+
placeholder="http://proxy.example.com:8080"
|
|
227
|
+
/>
|
|
228
|
+
</div>
|
|
229
|
+
<div className="space-y-1.5">
|
|
230
|
+
<Label className="text-xs">Proxy Username</Label>
|
|
231
|
+
<Input
|
|
232
|
+
className="h-8 text-sm"
|
|
233
|
+
value={form.scraperProxyUsername || ""}
|
|
234
|
+
onChange={(e) =>
|
|
235
|
+
setForm({ ...form, scraperProxyUsername: e.target.value })
|
|
236
|
+
}
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
239
|
+
<div className="space-y-1.5">
|
|
240
|
+
<Label className="text-xs">Proxy Password</Label>
|
|
241
|
+
<Input
|
|
242
|
+
type="password"
|
|
243
|
+
className="h-8 text-sm"
|
|
244
|
+
value={form.scraperProxyPassword || ""}
|
|
245
|
+
onChange={(e) =>
|
|
246
|
+
setForm({ ...form, scraperProxyPassword: e.target.value })
|
|
247
|
+
}
|
|
248
|
+
/>
|
|
249
|
+
</div>
|
|
250
|
+
<div className="space-y-1.5 pt-2">
|
|
251
|
+
<Label className="text-xs">Firecrawl API Key (Cloud)</Label>
|
|
252
|
+
<Input
|
|
253
|
+
type="password"
|
|
254
|
+
className="h-8 text-sm"
|
|
255
|
+
value={form.firecrawlApiKey || ""}
|
|
256
|
+
onChange={(e) =>
|
|
257
|
+
setForm({ ...form, firecrawlApiKey: e.target.value })
|
|
258
|
+
}
|
|
259
|
+
placeholder="fc-..."
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<div className="bg-card text-card-foreground p-3 space-y-3 rounded-lg border">
|
|
265
|
+
<h4 className="font-semibold leading-none tracking-tight text-sm">
|
|
266
|
+
Workspace Mode
|
|
267
|
+
</h4>
|
|
268
|
+
<p className="text-xs text-muted-foreground">
|
|
269
|
+
Switch to simple mode for a streamlined experience without
|
|
270
|
+
pipeline configuration.
|
|
271
|
+
</p>
|
|
272
|
+
<Button
|
|
273
|
+
variant="outline"
|
|
274
|
+
size="sm"
|
|
275
|
+
className="w-full text-xs"
|
|
276
|
+
onClick={async () => {
|
|
277
|
+
await setMode("simple");
|
|
278
|
+
router.push("/simple/chat");
|
|
279
|
+
}}
|
|
280
|
+
>
|
|
281
|
+
Switch to Simple Mode
|
|
282
|
+
</Button>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
}
|