ui/server: start no-company flow in onboarding and remove auto-seed
This commit is contained in:
@@ -210,28 +210,6 @@ async function ensureLocalTrustedBoardPrincipal(db: any): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureInitialCompanySeed(db: any): Promise<{ id: string; name: string; issuePrefix: string } | null> {
|
|
||||||
const existingCompany = await db
|
|
||||||
.select({ id: companies.id })
|
|
||||||
.from(companies)
|
|
||||||
.limit(1)
|
|
||||||
.then((rows: Array<{ id: string }>) => rows[0] ?? null);
|
|
||||||
if (existingCompany) return null;
|
|
||||||
|
|
||||||
return db
|
|
||||||
.insert(companies)
|
|
||||||
.values({
|
|
||||||
name: "Paperclip",
|
|
||||||
description: "Default company created on first startup",
|
|
||||||
})
|
|
||||||
.returning({
|
|
||||||
id: companies.id,
|
|
||||||
name: companies.name,
|
|
||||||
issuePrefix: companies.issuePrefix,
|
|
||||||
})
|
|
||||||
.then((rows: Array<{ id: string; name: string; issuePrefix: string }>) => rows[0] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
let db;
|
let db;
|
||||||
let embeddedPostgres: EmbeddedPostgresInstance | null = null;
|
let embeddedPostgres: EmbeddedPostgresInstance | null = null;
|
||||||
let embeddedPostgresStartedByThisProcess = false;
|
let embeddedPostgresStartedByThisProcess = false;
|
||||||
@@ -383,11 +361,6 @@ if (config.databaseUrl) {
|
|||||||
startupDbInfo = { mode: "embedded-postgres", dataDir, port };
|
startupDbInfo = { mode: "embedded-postgres", dataDir, port };
|
||||||
}
|
}
|
||||||
|
|
||||||
const seededCompany = await ensureInitialCompanySeed(db as any);
|
|
||||||
if (seededCompany) {
|
|
||||||
logger.info(`Seeded initial company: ${seededCompany.name} (${seededCompany.issuePrefix})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.deploymentMode === "local_trusted" && !isLoopbackHost(config.host)) {
|
if (config.deploymentMode === "local_trusted" && !isLoopbackHost(config.host)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`local_trusted mode requires loopback host binding (received: ${config.host}). ` +
|
`local_trusted mode requires loopback host binding (received: ${config.host}). ` +
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import { useEffect, useRef } from "react";
|
||||||
import { Navigate, Outlet, Route, Routes, useLocation } from "@/lib/router";
|
import { Navigate, Outlet, Route, Routes, useLocation } from "@/lib/router";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
import { Layout } from "./components/Layout";
|
import { Layout } from "./components/Layout";
|
||||||
|
import { OnboardingWizard } from "./components/OnboardingWizard";
|
||||||
import { authApi } from "./api/auth";
|
import { authApi } from "./api/auth";
|
||||||
import { healthApi } from "./api/health";
|
import { healthApi } from "./api/health";
|
||||||
import { Dashboard } from "./pages/Dashboard";
|
import { Dashboard } from "./pages/Dashboard";
|
||||||
@@ -26,6 +29,7 @@ import { BoardClaimPage } from "./pages/BoardClaim";
|
|||||||
import { InviteLandingPage } from "./pages/InviteLanding";
|
import { InviteLandingPage } from "./pages/InviteLanding";
|
||||||
import { queryKeys } from "./lib/queryKeys";
|
import { queryKeys } from "./lib/queryKeys";
|
||||||
import { useCompany } from "./context/CompanyContext";
|
import { useCompany } from "./context/CompanyContext";
|
||||||
|
import { useDialog } from "./context/DialogContext";
|
||||||
|
|
||||||
function BootstrapPendingPage() {
|
function BootstrapPendingPage() {
|
||||||
return (
|
return (
|
||||||
@@ -137,11 +141,7 @@ function CompanyRootRedirect() {
|
|||||||
|
|
||||||
const targetCompany = selectedCompany ?? companies[0] ?? null;
|
const targetCompany = selectedCompany ?? companies[0] ?? null;
|
||||||
if (!targetCompany) {
|
if (!targetCompany) {
|
||||||
return (
|
return <NoCompaniesStartPage />;
|
||||||
<div className="mx-auto max-w-xl py-10 text-sm text-muted-foreground">
|
|
||||||
No accessible companies found.
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Navigate to={`/${targetCompany.issuePrefix}/dashboard`} replace />;
|
return <Navigate to={`/${targetCompany.issuePrefix}/dashboard`} replace />;
|
||||||
@@ -157,11 +157,7 @@ function UnprefixedBoardRedirect() {
|
|||||||
|
|
||||||
const targetCompany = selectedCompany ?? companies[0] ?? null;
|
const targetCompany = selectedCompany ?? companies[0] ?? null;
|
||||||
if (!targetCompany) {
|
if (!targetCompany) {
|
||||||
return (
|
return <NoCompaniesStartPage />;
|
||||||
<div className="mx-auto max-w-xl py-10 text-sm text-muted-foreground">
|
|
||||||
No accessible companies found.
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -172,6 +168,32 @@ function UnprefixedBoardRedirect() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NoCompaniesStartPage() {
|
||||||
|
const { openOnboarding } = useDialog();
|
||||||
|
const opened = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (opened.current) return;
|
||||||
|
opened.current = true;
|
||||||
|
openOnboarding();
|
||||||
|
}, [openOnboarding]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-xl py-10">
|
||||||
|
<div className="rounded-lg border border-border bg-card p-6">
|
||||||
|
<h1 className="text-xl font-semibold">Create your first company</h1>
|
||||||
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
|
Get started by creating a company.
|
||||||
|
</p>
|
||||||
|
<div className="mt-4">
|
||||||
|
<Button onClick={openOnboarding}>New Company</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<OnboardingWizard />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
@@ -181,6 +203,7 @@ export function App() {
|
|||||||
|
|
||||||
<Route element={<CloudAccessGate />}>
|
<Route element={<CloudAccessGate />}>
|
||||||
<Route index element={<CompanyRootRedirect />} />
|
<Route index element={<CompanyRootRedirect />} />
|
||||||
|
<Route path="companies" element={<UnprefixedBoardRedirect />} />
|
||||||
<Route path="issues" element={<UnprefixedBoardRedirect />} />
|
<Route path="issues" element={<UnprefixedBoardRedirect />} />
|
||||||
<Route path="issues/:issueId" element={<UnprefixedBoardRedirect />} />
|
<Route path="issues/:issueId" element={<UnprefixedBoardRedirect />} />
|
||||||
<Route path="agents" element={<UnprefixedBoardRedirect />} />
|
<Route path="agents" element={<UnprefixedBoardRedirect />} />
|
||||||
|
|||||||
Reference in New Issue
Block a user