All the MD files via Database
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
import { useState, useCallback, useEffect, useRef } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { PACKAGE_CATALOG, type PackageDef } from "@/lib/packages";
|
||||
@@ -9,7 +9,8 @@ type Step = "welcome" | "configure" | "billing" | "confirm";
|
||||
|
||||
const STEPS: Step[] = ["welcome", "configure", "billing", "confirm"];
|
||||
|
||||
const DEFAULT_SOUL = `# AI Assistant
|
||||
// Inline fallbacks — only used if the API call to /api/workspace-defaults fails
|
||||
const FALLBACK_SOUL = `# AI Assistant
|
||||
|
||||
You are a helpful AI assistant for {company}. You are professional, concise, and friendly.
|
||||
|
||||
@@ -20,6 +21,25 @@ You are a helpful AI assistant for {company}. You are professional, concise, and
|
||||
- Respect privacy and confidentiality
|
||||
`;
|
||||
|
||||
const FALLBACK_AGENTS = `# Agents
|
||||
|
||||
On session start, read the following workspace files in order:
|
||||
1. SOUL.md — your personality and behavioural guidelines
|
||||
2. TOOLS.md — available tools and how to use them
|
||||
3. USER.md — information about the current user (if present)
|
||||
|
||||
Follow the instructions in SOUL.md for every interaction.
|
||||
`;
|
||||
|
||||
const FALLBACK_TOOLS = `# Tools
|
||||
|
||||
The following tools are available to you as an AI assistant.
|
||||
|
||||
## LLM
|
||||
You have access to a large language model for text generation, summarisation,
|
||||
translation, and general question answering.
|
||||
`;
|
||||
|
||||
const CATEGORIES = [
|
||||
{ key: "channel" as const, labelKey: "categories.channels" },
|
||||
{ key: "skill" as const, labelKey: "categories.skills" },
|
||||
@@ -38,10 +58,13 @@ export function OnboardingWizard({ orgName, onComplete }: WizardProps) {
|
||||
const [step, setStep] = useState<Step>("welcome");
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [advancedOpen, setAdvancedOpen] = useState(false);
|
||||
const [defaultsLoaded, setDefaultsLoaded] = useState(false);
|
||||
|
||||
const [config, setConfig] = useState({
|
||||
agentName: "Assistant",
|
||||
soulMd: DEFAULT_SOUL.replace("{company}", orgName),
|
||||
soulMd: FALLBACK_SOUL.replace("{company}", orgName),
|
||||
agentsMd: FALLBACK_AGENTS,
|
||||
packages: [] as string[],
|
||||
billingAddress: {
|
||||
company: orgName,
|
||||
@@ -53,6 +76,9 @@ export function OnboardingWizard({ orgName, onComplete }: WizardProps) {
|
||||
billingNotes: "",
|
||||
});
|
||||
|
||||
// TOOLS.md preview — readonly, auto-generated
|
||||
const [toolsMdPreview, setToolsMdPreview] = useState(FALLBACK_TOOLS);
|
||||
|
||||
// Per-package collected secrets: { "telegram": { "bot-token": "123:ABC" }, ... }
|
||||
const [packageSecrets, setPackageSecrets] = useState<
|
||||
Record<string, Record<string, string>>
|
||||
@@ -62,6 +88,42 @@ export function OnboardingWizard({ orgName, onComplete }: WizardProps) {
|
||||
Record<string, boolean>
|
||||
>({});
|
||||
|
||||
// Fetch DB-stored defaults on mount
|
||||
useEffect(() => {
|
||||
fetch(`/api/workspace-defaults?orgName=${encodeURIComponent(orgName)}`)
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
soulMd: data.soulMd ?? prev.soulMd,
|
||||
agentsMd: data.agentsMd ?? prev.agentsMd,
|
||||
}));
|
||||
setToolsMdPreview(data.toolsMd ?? FALLBACK_TOOLS);
|
||||
setDefaultsLoaded(true);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
/* use inline fallbacks */
|
||||
});
|
||||
}, [orgName]);
|
||||
|
||||
// Re-fetch TOOLS.md preview when packages change
|
||||
const packagesKey = config.packages.sort().join(",");
|
||||
const prevPackagesKey = useRef(packagesKey);
|
||||
useEffect(() => {
|
||||
if (prevPackagesKey.current === packagesKey && defaultsLoaded) return;
|
||||
prevPackagesKey.current = packagesKey;
|
||||
fetch(
|
||||
`/api/workspace-defaults?orgName=${encodeURIComponent(orgName)}&packages=${encodeURIComponent(packagesKey)}`
|
||||
)
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => {
|
||||
if (data?.toolsMd) setToolsMdPreview(data.toolsMd);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, [packagesKey, orgName, defaultsLoaded]);
|
||||
|
||||
const stepIndex = STEPS.indexOf(step);
|
||||
|
||||
const goNext = () => {
|
||||
@@ -274,6 +336,74 @@ export function OnboardingWizard({ orgName, onComplete }: WizardProps) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Advanced: AGENTS.md + TOOLS.md preview */}
|
||||
<div className="border border-border rounded-lg overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setAdvancedOpen((o) => !o)}
|
||||
className="w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-surface-3/30 transition-colors"
|
||||
>
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-text-muted">
|
||||
{t("advancedConfig")}
|
||||
</span>
|
||||
<svg
|
||||
className={`h-4 w-4 text-text-muted transition-transform ${
|
||||
advancedOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
{advancedOpen && (
|
||||
<div className="border-t border-border px-3 py-4 space-y-4 bg-surface-1/30">
|
||||
{/* AGENTS.md */}
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-wider text-text-muted mb-1.5">
|
||||
{t("agentsMd")}
|
||||
</label>
|
||||
<textarea
|
||||
value={config.agentsMd}
|
||||
onChange={(e) =>
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
agentsMd: e.target.value,
|
||||
}))
|
||||
}
|
||||
rows={6}
|
||||
className="w-full px-3 py-2 bg-surface-2 border border-border rounded-lg text-sm text-text-primary font-mono text-xs focus:outline-none focus:ring-1 focus:ring-accent focus:border-accent transition-colors resize-y"
|
||||
/>
|
||||
<p className="text-xs text-text-muted mt-1">
|
||||
{t("agentsMdHint")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* TOOLS.md — readonly preview */}
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-wider text-text-muted mb-1.5">
|
||||
{t("toolsMd")}
|
||||
</label>
|
||||
<textarea
|
||||
value={toolsMdPreview}
|
||||
readOnly
|
||||
rows={6}
|
||||
className="w-full px-3 py-2 bg-surface-3/50 border border-border rounded-lg text-sm text-text-secondary font-mono text-xs cursor-not-allowed resize-y"
|
||||
/>
|
||||
<p className="text-xs text-text-muted mt-1">
|
||||
{t("toolsMdHint")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Packages — grouped by category */}
|
||||
<div>
|
||||
<label className="block text-xs font-semibold uppercase tracking-wider text-text-muted mb-2">
|
||||
|
||||
Reference in New Issue
Block a user