From 4f07138560883f8d652d4e3f76fb28253fa3bbee Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 08:54:45 +0000 Subject: [PATCH 01/10] chore: remove outerbase session provider --- src/app/(outerbase)/layout.tsx | 5 +- src/app/(outerbase)/local/page.tsx | 175 +-------------------------- src/app/(outerbase)/nav-layout.tsx | 23 +--- src/app/(outerbase)/page.tsx | 184 +++++++++++++++++++++++++---- 4 files changed, 167 insertions(+), 220 deletions(-) diff --git a/src/app/(outerbase)/layout.tsx b/src/app/(outerbase)/layout.tsx index 853ce284..3df6370e 100644 --- a/src/app/(outerbase)/layout.tsx +++ b/src/app/(outerbase)/layout.tsx @@ -1,4 +1,3 @@ -import { OuterbaseSessionProvider } from "@/app/(outerbase)/session-provider"; import ClientOnly from "@/components/client-only"; import ThemeLayout from "../(theme)/theme_layout"; import { WorkspaceProvider } from "./workspace-provider"; @@ -11,9 +10,7 @@ export default function OuterbaseLayout({ return ( - - {children} - + {children} ); diff --git a/src/app/(outerbase)/local/page.tsx b/src/app/(outerbase)/local/page.tsx index 44ca3efa..76b58b5b 100644 --- a/src/app/(outerbase)/local/page.tsx +++ b/src/app/(outerbase)/local/page.tsx @@ -1,179 +1,10 @@ "use client"; - -import { MySQLIcon, SQLiteIcon } from "@/components/icons/outerbase-icon"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { CaretDown } from "@phosphor-icons/react"; -import Link from "next/link"; import { useRouter } from "next/navigation"; -import { useCallback, useMemo } from "react"; -import NavigationLayout from "../nav-layout"; -import { ResourceItemList, ResourceItemProps } from "../resource-item-helper"; -import { deleteLocalBaseDialog } from "./dialog-base-delete"; -import { createLocalBoardDialog } from "./dialog-board-create"; -import { deleteLocalBoardDialog } from "./dialog-board-delete"; -import { useLocalConnectionList, useLocalDashboardList } from "./hooks"; export default function LocalConnectionPage() { + // Redirect to root const router = useRouter(); + router.push("/"); - const { - data: localBases, - isLoading, - mutate: refreshBase, - } = useLocalConnectionList(); - - const baseResources = useMemo(() => { - return (localBases ?? []).map((conn) => { - return { - href: - conn.content.driver === "sqlite-filehandler" - ? `/playground/client?s=${conn.id}` - : `/client/s/${conn.content.driver ?? "turso"}?p=${conn.id}`, - name: conn.content.name, - lastUsed: conn.updated_at, - id: conn.id, - type: conn.content.driver, - status: "", - color: conn.content.label || "default", - } as ResourceItemProps; - }); - }, [localBases]); - - // Getting the board from indexdb - const { data: dashboardList, mutate: refreshDashboard } = - useLocalDashboardList(); - const dashboardResources = useMemo(() => { - return ( - (dashboardList ?? []).map((board) => { - return { - href: `/local/board/${board.id}`, - name: board.content.name, - lastUsed: board.content.updated_at, - id: board.id, - type: "board", - } as ResourceItemProps; - }) ?? [] - ); - }, [dashboardList]); - - const onBoardCreate = useCallback(() => { - createLocalBoardDialog.show({}).then(() => { - refreshDashboard(); - }); - }, [refreshDashboard]); - - const onBaseRemove = useCallback( - (deletedResource: ResourceItemProps) => { - deleteLocalBaseDialog - .show({ baseId: deletedResource.id, baseName: deletedResource.name }) - .then(refreshBase) - .catch(); - }, - [refreshBase] - ); - - const onBoardRemove = useCallback((deletedResource: ResourceItemProps) => { - deleteLocalBoardDialog - .show({ boardId: deletedResource.id, boardName: deletedResource.name }) - .then() - .catch(); - }, []); - - return ( - -
-
- - - - - - - Open Empty SQLite Database - - -
- - Northwind - - The Northwind Database is a sample business database for - learning SQL queries and database design. - - - - - Chinook - - The Chinook Database is a sample digital media store - database for learning and practicing SQL queries. - - -
-
-
- - -
- - { - router.push(`/local/edit-base/${resource.id}`); - }} - onBoardCreate={onBoardCreate} - /> -
-
- ); + return
; } diff --git a/src/app/(outerbase)/nav-layout.tsx b/src/app/(outerbase)/nav-layout.tsx index 4aefe8e7..10107c9b 100644 --- a/src/app/(outerbase)/nav-layout.tsx +++ b/src/app/(outerbase)/nav-layout.tsx @@ -5,18 +5,15 @@ import { SidebarMenuLoadingItem, } from "@/components/sidebar-menu"; import { cn } from "@/lib/utils"; -import { Database, List, Plus } from "@phosphor-icons/react"; +import { Database, List } from "@phosphor-icons/react"; import { useParams, usePathname, useRouter } from "next/navigation"; import { PropsWithChildren, useState } from "react"; -import NavigationProfile from "./nav-profile"; -import NavigationSigninBanner from "./nav-signin-banner"; -import { useSession } from "./session-provider"; import { useWorkspaces } from "./workspace-provider"; export default function NavigationLayout({ children }: PropsWithChildren) { const router = useRouter(); const [mobileToggle, setMobileToggle] = useState(false); - const { session } = useSession(); + const { workspaces, loading: workspaceLoading } = useWorkspaces(); const pathname = usePathname(); const { workspaceId } = useParams<{ workspaceId?: string }>(); @@ -25,7 +22,6 @@ export default function NavigationLayout({ children }: PropsWithChildren) {
- { @@ -93,22 +89,7 @@ export default function NavigationLayout({ children }: PropsWithChildren) { )} - - { - if (session?.user) { - router.push("/new-workspace"); - } else { - localStorage.setItem("continue-redirect", "/new-workspace"); - router.push("/signin"); - } - }} - />
- -
diff --git a/src/app/(outerbase)/page.tsx b/src/app/(outerbase)/page.tsx index fcb67f60..e019985a 100644 --- a/src/app/(outerbase)/page.tsx +++ b/src/app/(outerbase)/page.tsx @@ -1,40 +1,178 @@ "use client"; +import { MySQLIcon, SQLiteIcon } from "@/components/icons/outerbase-icon"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { CaretDown } from "@phosphor-icons/react"; +import Link from "next/link"; import { useRouter } from "next/navigation"; -import { useEffect } from "react"; +import { useCallback, useMemo } from "react"; +import { deleteLocalBaseDialog } from "./local/dialog-base-delete"; +import { createLocalBoardDialog } from "./local/dialog-board-create"; +import { deleteLocalBoardDialog } from "./local/dialog-board-delete"; +import { useLocalConnectionList, useLocalDashboardList } from "./local/hooks"; import NavigationLayout from "./nav-layout"; -import { ResourceItemList } from "./resource-item-helper"; -import { useSession } from "./session-provider"; -import { useWorkspaces } from "./workspace-provider"; +import { ResourceItemList, ResourceItemProps } from "./resource-item-helper"; -export default function OuterbaseMainPage() { +export default function LocalConnectionPage() { const router = useRouter(); - const { isLoading: sessionLoading, session } = useSession(); - const { workspaces, loading: workspaceLoading } = useWorkspaces(); - useEffect(() => { - if (sessionLoading) return; + const { + data: localBases, + isLoading, + mutate: refreshBase, + } = useLocalConnectionList(); - // Invalid session, go to local connection - if (!session) { - router.push("/local"); - } + const baseResources = useMemo(() => { + return (localBases ?? []).map((conn) => { + return { + href: + conn.content.driver === "sqlite-filehandler" + ? `/playground/client?s=${conn.id}` + : `/client/s/${conn.content.driver ?? "turso"}?p=${conn.id}`, + name: conn.content.name, + lastUsed: conn.updated_at, + id: conn.id, + type: conn.content.driver, + status: "", + color: conn.content.label || "default", + } as ResourceItemProps; + }); + }, [localBases]); - if (workspaceLoading) return; - if (!workspaces) return; + // Getting the board from indexdb + const { data: dashboardList, mutate: refreshDashboard } = + useLocalDashboardList(); + const dashboardResources = useMemo(() => { + return ( + (dashboardList ?? []).map((board) => { + return { + href: `/local/board/${board.id}`, + name: board.content.name, + lastUsed: board.content.updated_at, + id: board.id, + type: "board", + } as ResourceItemProps; + }) ?? [] + ); + }, [dashboardList]); - // Redirect to the first workspace - if (workspaces.length > 0) { - router.push(`/w/${workspaces[0].short_name}`); - } else { - router.push("/local"); - } - }, [session, sessionLoading, workspaceLoading, workspaces, router]); + const onBoardCreate = useCallback(() => { + createLocalBoardDialog.show({}).then(() => { + refreshDashboard(); + }); + }, [refreshDashboard]); + + const onBaseRemove = useCallback( + (deletedResource: ResourceItemProps) => { + deleteLocalBaseDialog + .show({ baseId: deletedResource.id, baseName: deletedResource.name }) + .then(refreshBase) + .catch(); + }, + [refreshBase] + ); + + const onBoardRemove = useCallback((deletedResource: ResourceItemProps) => { + deleteLocalBoardDialog + .show({ boardId: deletedResource.id, boardName: deletedResource.name }) + .then() + .catch(); + }, []); return (
- +
+ + + + + + + Open Empty SQLite Database + + +
+ + Northwind + + The Northwind Database is a sample business database for + learning SQL queries and database design. + + + + + Chinook + + The Chinook Database is a sample digital media store + database for learning and practicing SQL queries. + + +
+
+
+ + +
+ + { + router.push(`/local/edit-base/${resource.id}`); + }} + onBoardCreate={onBoardCreate} + />
); From f2fcb9898344f8f8c64b7b2d889a5acfd39313a9 Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 08:55:49 +0000 Subject: [PATCH 02/10] chore: remove outerbase workspace --- .../w/[workspaceId]/[baseId]/page.tsx | 121 ----------- .../w/[workspaceId]/billing/page.tsx | 16 -- .../w/[workspaceId]/board/[boardId]/page.tsx | 116 ---------- .../w/[workspaceId]/dialog-base-delete.tsx | 78 ------- .../w/[workspaceId]/dialog-board-create.tsx | 67 ------ .../w/[workspaceId]/dialog-board-delete.tsx | 77 ------- .../[workspaceId]/edit-base/[baseId]/page.tsx | 204 ------------------ .../w/[workspaceId]/edit-base/page.tsx | 5 - .../(outerbase)/w/[workspaceId]/layout.tsx | 15 -- .../[workspaceId]/new-base/[driver]/page.tsx | 152 ------------- .../w/[workspaceId]/new-base/page.tsx | 5 - src/app/(outerbase)/w/[workspaceId]/page.tsx | 148 ------------- .../[workspaceId]/redirect-valid-workspace.ts | 24 --- .../w/[workspaceId]/settings/delete.tsx | 121 ----------- .../w/[workspaceId]/settings/detail.tsx | 69 ------ .../w/[workspaceId]/settings/gateway.tsx | 20 -- .../w/[workspaceId]/settings/members.tsx | 17 -- .../w/[workspaceId]/settings/page.tsx | 37 ---- 18 files changed, 1292 deletions(-) delete mode 100644 src/app/(outerbase)/w/[workspaceId]/[baseId]/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/billing/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/board/[boardId]/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/dialog-base-delete.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/dialog-board-create.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/dialog-board-delete.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/edit-base/[baseId]/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/edit-base/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/layout.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/new-base/[driver]/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/new-base/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/page.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/redirect-valid-workspace.ts delete mode 100644 src/app/(outerbase)/w/[workspaceId]/settings/delete.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/settings/detail.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/settings/gateway.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/settings/members.tsx delete mode 100644 src/app/(outerbase)/w/[workspaceId]/settings/page.tsx diff --git a/src/app/(outerbase)/w/[workspaceId]/[baseId]/page.tsx b/src/app/(outerbase)/w/[workspaceId]/[baseId]/page.tsx deleted file mode 100644 index 25f46284..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/[baseId]/page.tsx +++ /dev/null @@ -1,121 +0,0 @@ -"use client"; - -import { Studio } from "@/components/gui/studio"; -import PageLoading from "@/components/page-loading"; -import { StudioExtensionManager } from "@/core/extension-manager"; -import { - createMySQLExtensions, - createPostgreSQLExtensions, - createSQLiteExtensions, -} from "@/core/standard-extension"; -import MySQLLikeDriver from "@/drivers/mysql/mysql-driver"; -import PostgresLikeDriver from "@/drivers/postgres/postgres-driver"; -import { SqliteLikeBaseDriver } from "@/drivers/sqlite-base-driver"; -import DataCatalogExtension from "@/extensions/data-catalog"; -import OuterbaseExtension from "@/extensions/outerbase"; -import { - getOuterbaseBase, - sendOuterbaseBaseAnalytics, -} from "@/outerbase-cloud/api"; -import { OuterbaseAPIBaseCredential } from "@/outerbase-cloud/api-type"; -import { getOuterbaseBaseCredential } from "@/outerbase-cloud/api-workspace"; -import DataCatalogOuterbaseDriver from "@/outerbase-cloud/data-catalog-driver"; -import { OuterbaseQueryable } from "@/outerbase-cloud/database/query"; -import OuterbaseQueryDriver from "@/outerbase-cloud/query-driver"; -import { useParams } from "next/navigation"; -import { useEffect, useMemo, useState } from "react"; - -export const runtime = "edge"; - -export default function OuterbaseSourcePage() { - const { workspaceId, baseId } = useParams<{ - workspaceId: string; - baseId: string; - }>(); - const [name, setName] = useState(""); - const [credential, setCredential] = useState(); - - useEffect(() => { - if (!workspaceId) return; - if (!baseId) return; - - getOuterbaseBase(workspaceId, baseId).then((base) => { - if (!base) return; - - setName(base.name); - getOuterbaseBaseCredential(workspaceId, base.sources[0]?.id ?? "").then( - setCredential - ); - }); - }, [workspaceId, baseId]); - - const savedDocDriver = useMemo(() => { - if (!workspaceId || !credential?.id || !baseId) return null; - return new OuterbaseQueryDriver(workspaceId, baseId, credential.id); - }, [workspaceId, baseId, credential?.id]); - - // We need to send analytics to update the last used time - useEffect(() => { - sendOuterbaseBaseAnalytics(workspaceId, baseId).then().catch(); - }, [workspaceId, baseId]); - - const [outerbaseDriver, extensions] = useMemo(() => { - if (!workspaceId || !credential) return [null, null]; - - const dialect = credential.type; - const outerbaseConfig = { - workspaceId, - sourceId: credential.id, - baseId, - token: localStorage.getItem("ob-token") ?? "", - }; - - const outerbaseSpecifiedDrivers = [ - new OuterbaseExtension(outerbaseConfig), - new DataCatalogExtension(new DataCatalogOuterbaseDriver(outerbaseConfig)), - ]; - - if (dialect === "postgres") { - return [ - new PostgresLikeDriver(new OuterbaseQueryable(outerbaseConfig)), - new StudioExtensionManager([ - ...createPostgreSQLExtensions(), - ...outerbaseSpecifiedDrivers, - ]), - ]; - } else if (dialect === "mysql") { - return [ - new MySQLLikeDriver( - new OuterbaseQueryable(outerbaseConfig), - credential.database - ), - new StudioExtensionManager([ - ...createMySQLExtensions(), - ...outerbaseSpecifiedDrivers, - ]), - ]; - } - - return [ - new SqliteLikeBaseDriver(new OuterbaseQueryable(outerbaseConfig)), - new StudioExtensionManager([ - ...createSQLiteExtensions(), - ...outerbaseSpecifiedDrivers, - ]), - ]; - }, [workspaceId, credential, baseId]); - - if (!outerbaseDriver || !savedDocDriver) { - return Loading Base ...; - } - - return ( - - ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/billing/page.tsx b/src/app/(outerbase)/w/[workspaceId]/billing/page.tsx deleted file mode 100644 index d173a416..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/billing/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -"use client"; -import NavigationHeader from "@/app/(outerbase)/nav-header"; -import NavigationLayout from "@/app/(outerbase)/nav-layout"; - -export const runtime = "edge"; - -export default function WorkspaceBillingPage() { - return ( - - -
-

Billing

-
-
- ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/board/[boardId]/page.tsx b/src/app/(outerbase)/w/[workspaceId]/board/[boardId]/page.tsx deleted file mode 100644 index 33375164..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/board/[boardId]/page.tsx +++ /dev/null @@ -1,116 +0,0 @@ -"use client"; - -import NavigationDashboardLayout from "@/app/(outerbase)/nav-board-layout"; -import { useWorkspaces } from "@/app/(outerbase)/workspace-provider"; -import Board, { DashboardProps } from "@/components/board"; -import { Loader } from "@/components/orbit/loader"; -import { WEBSITE_NAME } from "@/const"; -import OuterbaseBoardStorageDriver from "@/drivers/board-storage/outerbase"; - -import { getOuterbaseDashboard } from "@/outerbase-cloud/api"; -import { OuterbaseAPIDashboardDetail } from "@/outerbase-cloud/api-type"; -import OuterbaseBoardSourceDriver from "@/outerbase-cloud/database-source"; -import { useOuterbaseDashboardList } from "@/outerbase-cloud/hook"; -import { useParams } from "next/navigation"; -import { useMemo, useState } from "react"; -import useSWR, { KeyedMutator } from "swr"; - -export const runtime = "edge"; - -function BoardPageEditor({ - initialValue, -}: { - initialValue: OuterbaseAPIDashboardDetail; - mutate: KeyedMutator; -}) { - const { boardId } = useParams<{ - workspaceId: string; - boardId: string; - }>(); - const { currentWorkspace } = useWorkspaces(); - const [interval, setIntervals] = useState(0); - - const boardSources = useMemo(() => { - if (!currentWorkspace) return; - return new OuterbaseBoardSourceDriver(currentWorkspace); - }, [currentWorkspace]); - - const storageDriver = useMemo(() => { - if (!currentWorkspace) return; - return new OuterbaseBoardStorageDriver( - currentWorkspace.short_name, - boardId - ); - }, [boardId, currentWorkspace]); - - const [value, setValue] = useState(initialValue); - const [filter, setFilter] = useState({}); - - if (!boardSources) { - return
Loading Workspace....
; - } - - return ( - - ); -} - -export default function BoardPage() { - const { workspaceId, boardId } = useParams<{ - boardId: string; - workspaceId: string; - }>(); - const { data, mutate } = useSWR(`board-${boardId}`, () => { - return getOuterbaseDashboard(workspaceId, boardId); - }); - - const { currentWorkspace, loading: workspaceLoading } = useWorkspaces(); - const { data: dashboardList, isLoading: dashboardLoading } = - useOuterbaseDashboardList(); - - const dashboards = useMemo(() => { - if (!currentWorkspace) return []; - if (!dashboardList) return []; - - const tmp = (dashboardList ?? []).filter( - (board) => - board.workspace_id === currentWorkspace.id && board.base_id === null - ); - - tmp.sort((a, b) => a.name.localeCompare(b.name)); - return tmp.map((board) => { - return { - id: board.id, - name: board.name, - href: `/w/${currentWorkspace.short_name}/board/${board.id}`, - }; - }); - }, [dashboardList, currentWorkspace]); - - return ( - - {data?.name ?? WEBSITE_NAME} -
- {data ? ( - - ) : ( - - )} -
-
- ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/dialog-base-delete.tsx b/src/app/(outerbase)/w/[workspaceId]/dialog-base-delete.tsx deleted file mode 100644 index 86a30c61..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/dialog-base-delete.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import CopyableText from "@/components/copyable-text"; -import { createDialog } from "@/components/create-dialog"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/ui/button"; -import { - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { deleteOuterbaseBase } from "@/outerbase-cloud/api"; -import { LucideLoader } from "lucide-react"; -import { useCallback, useState } from "react"; - -export const deleteBaseDialog = createDialog<{ - workspaceId: string; - baseId: string; - baseName: string; -}>(({ close, baseName, workspaceId, baseId }) => { - const [loading, setLoading] = useState(false); - const [name, setName] = useState(""); - - const deleteClicked = useCallback(() => { - if (name !== baseName) return; - - setLoading(true); - - deleteOuterbaseBase(workspaceId, baseId) - .then(() => { - close(undefined); - }) - .finally(() => { - setLoading(false); - }); - }, [name, workspaceId, baseId, close, baseName]); - - return ( - <> - - Confirm deletion of {baseName} - - All saved queries, dashboards, definitions and any other contributions - made to your Base will be deleted. This action is permanent and{" "} - cannot - be undone. - - - -
-
- -
- - setName(e.currentTarget.value)} - /> -
- - - - - - - ); -}); diff --git a/src/app/(outerbase)/w/[workspaceId]/dialog-board-create.tsx b/src/app/(outerbase)/w/[workspaceId]/dialog-board-create.tsx deleted file mode 100644 index eb194bc9..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/dialog-board-create.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { createDialog } from "@/components/create-dialog"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { createOuterbaseDashboard } from "@/outerbase-cloud/api"; -import { OuterbaseAPIDashboardDetail } from "@/outerbase-cloud/api-type"; -import { LucideLoader } from "lucide-react"; -import { useCallback, useState } from "react"; - -export const createBoardDialog = createDialog< - { workspaceId: string }, - OuterbaseAPIDashboardDetail | undefined ->(({ close, workspaceId }) => { - const [loading, setLoading] = useState(false); - const [name, setName] = useState(""); - - const createBoardClicked = useCallback(() => { - if (name.length === 0) return; - - setLoading(true); - - createOuterbaseDashboard(workspaceId, undefined, name) - .then((createdBoard) => { - close(createdBoard); - }) - .finally(() => { - setLoading(false); - }); - }, [close, name, workspaceId]); - - return ( - <> - - New Board - - - -
- setName(e.currentTarget.value)} - /> -
- - - - - - - ); -}); diff --git a/src/app/(outerbase)/w/[workspaceId]/dialog-board-delete.tsx b/src/app/(outerbase)/w/[workspaceId]/dialog-board-delete.tsx deleted file mode 100644 index 8caea7e8..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/dialog-board-delete.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import CopyableText from "@/components/copyable-text"; -import { createDialog } from "@/components/create-dialog"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/ui/button"; -import { - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { deleteOuterbaseDashboard } from "@/outerbase-cloud/api"; -import { LucideLoader } from "lucide-react"; -import { useCallback, useState } from "react"; - -export const deleteBoardDialog = createDialog<{ - workspaceId: string; - boardId: string; - boardName: string; -}>(({ close, boardName, workspaceId, boardId }) => { - const [loading, setLoading] = useState(false); - const [name, setName] = useState(""); - - const deleteClicked = useCallback(() => { - if (name !== boardName) return; - - setLoading(true); - - deleteOuterbaseDashboard(workspaceId, boardId) - .then(() => { - close(undefined); - }) - .finally(() => { - setLoading(false); - }); - }, [name, workspaceId, boardId, close, boardName]); - - return ( - <> - - Confirm deletion of board {boardName} - - All saved charts and any other contributions made to your Dashboard - will be deleted. This action is permanent and cannot{" "} - be undone. - - - -
-
- -
- - setName(e.currentTarget.value)} - /> -
- - - - - - - ); -}); diff --git a/src/app/(outerbase)/w/[workspaceId]/edit-base/[baseId]/page.tsx b/src/app/(outerbase)/w/[workspaceId]/edit-base/[baseId]/page.tsx deleted file mode 100644 index 6649f463..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/edit-base/[baseId]/page.tsx +++ /dev/null @@ -1,204 +0,0 @@ -"use client"; -import { ConnectionTemplateList } from "@/app/(outerbase)/base-template"; -import { - CommonConnectionConfig, - ConnectionConfigEditor, - validateTemplate, -} from "@/components/connection-config-editor"; -import { ConnectionTemplateDictionary } from "@/components/connection-config-editor/template"; -import { Button } from "@/components/orbit/button"; -import { Loader } from "@/components/orbit/loader"; -import { - OuterbaseAPIBase, - OuterbaseAPISourceInput, -} from "@/outerbase-cloud/api-type"; -import { updateOuterbaseSource } from "@/outerbase-cloud/api-workspace"; -import { - useOuterbaseBase, - useOuterbaseBaseCredential, -} from "@/outerbase-cloud/hook"; -import { ArrowLeft, ArrowRight, FloppyDisk } from "@phosphor-icons/react"; -import { useParams, useRouter } from "next/navigation"; -import { useCallback, useEffect, useMemo, useState } from "react"; - -export const runtime = "edge"; - -function WorkspaceEditBaseBody({ - base, - credential, - template, -}: { - base: OuterbaseAPIBase; - credential: OuterbaseAPISourceInput; - template: ConnectionTemplateList; -}) { - const router = useRouter(); - const { workspaceId } = useParams<{ workspaceId: string }>(); - - const [value, setValue] = useState(() => { - if (!template.remoteFrom) throw new Error("Invalid driver"); - - return template.remoteFrom({ - source: credential, - name: base.name, - }); - }); - - const [loading, setLoading] = useState(false); - const [error, setError] = useState(""); - const [validateErrors, setValidateErrors] = useState>( - {} - ); - - useEffect(() => {}); - - const onSave = useCallback( - (overrideRedirect?: string) => { - if (!template.remoteFrom || !template.remoteTo) return; - - const errors = validateTemplate(value, template); - setValidateErrors(errors); - if (Object.keys(errors).length > 0) return; - - setLoading(true); - setError(""); - - const { source } = template.remoteTo(value); - - const runSave = async () => { - await updateOuterbaseSource( - workspaceId, - base.sources[0]?.id ?? "", - source - ); - - router.replace( - overrideRedirect ?? `/w/${workspaceId}/${base.short_name}` - ); - }; - - runSave() - .then() - .catch((e) => { - if (e instanceof Error) { - setError(e.message); - } else { - setError(e.toString()); - } - }) - .finally(() => setLoading(false)); - }, - [workspaceId, template, value, router, base] - ); - - if (!template.remoteFrom || !template.remoteTo) { - return
Invalid driver
; - } - - return ( - <> -
-
- - -
-
- -
-
Editing {base.name} base
-
- - {error && ( -
- {error} -
- )} - - -
- -
-
- - - -
-
- - ); -} - -export default function WorkspaceEditBasePage() { - const { workspaceId, baseId } = useParams<{ - baseId: string; - workspaceId: string; - }>(); - - const { isLoading: isBaseLoading, data: base } = useOuterbaseBase( - workspaceId, - baseId - ); - - const { isLoading: isCredentialLoading, data: credential } = - useOuterbaseBaseCredential(workspaceId, base?.sources[0]?.id ?? ""); - - const template = useMemo(() => { - if (!credential) return null; - return ConnectionTemplateDictionary[credential.type]; - }, [credential]); - - if (isBaseLoading || isCredentialLoading) { - return ( -
- -
- ); - } - - if (!template) { - return
Unknown driver
; - } - - if (!credential || !base) { - return
Fill to get credential
; - } - - return ( - - ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/edit-base/page.tsx b/src/app/(outerbase)/w/[workspaceId]/edit-base/page.tsx deleted file mode 100644 index 3efffb0b..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/edit-base/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -export const runtime = "edge"; - -export default function NewBasePage() { - return
Unknown page
; -} diff --git a/src/app/(outerbase)/w/[workspaceId]/layout.tsx b/src/app/(outerbase)/w/[workspaceId]/layout.tsx deleted file mode 100644 index 0c544d48..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/layout.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DialogProvider } from "@/components/create-dialog"; -import AuthProvider from "../../auth-provider"; - -export default function OuterbaseLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - {children} - - - ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/new-base/[driver]/page.tsx b/src/app/(outerbase)/w/[workspaceId]/new-base/[driver]/page.tsx deleted file mode 100644 index 129b2a9b..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/new-base/[driver]/page.tsx +++ /dev/null @@ -1,152 +0,0 @@ -"use client"; -import { - CommonConnectionConfig, - ConnectionConfigEditor, - validateTemplate, -} from "@/components/connection-config-editor"; -import { ConnectionTemplateDictionary } from "@/components/connection-config-editor/template"; -import { Button } from "@/components/orbit/button"; -import { getDatabaseFriendlyName } from "@/components/resource-card/utils"; -import { - createOuterbaseBase, - createOuterbaseConnection, - createOuterbaseSource, - testOuterbaseSource, -} from "@/outerbase-cloud/api-workspace"; -import { ArrowLeft, ArrowRight, FloppyDisk } from "@phosphor-icons/react"; -import { useParams, useRouter } from "next/navigation"; -import { useCallback, useMemo, useState } from "react"; - -export const runtime = "edge"; - -export default function WorkspaceNewBasePage() { - const { driver, workspaceId } = useParams<{ - driver: string; - workspaceId: string; - }>(); - const router = useRouter(); - const [value, setValue] = useState({ name: "" }); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(""); - const [validateErrors, setValidateErrors] = useState>( - {} - ); - - const template = useMemo(() => { - return ConnectionTemplateDictionary[driver]; - }, [driver]); - - const onSave = useCallback( - (overrideRedirect?: string) => { - if (!template.remoteFrom || !template.remoteTo) return; - - const errors = validateTemplate(value, template); - setValidateErrors(errors); - if (Object.keys(errors).length > 0) return; - - setLoading(true); - setError(""); - - const { name: baseName, source } = template.remoteTo(value); - - const runSave = async () => { - await testOuterbaseSource(workspaceId, source); - const baseResponse = await createOuterbaseBase(workspaceId, baseName); - const connResponse = await createOuterbaseConnection( - workspaceId, - baseResponse.id, - baseName - ); - - await createOuterbaseSource(workspaceId, { - ...source, - base_id: baseResponse.id, - connection_id: connResponse.id, - }); - - router.replace( - overrideRedirect ?? `/w/${workspaceId}/${baseResponse.short_name}` - ); - }; - - runSave() - .then() - .catch((e) => { - if (e instanceof Error) { - setError(e.message); - } else { - setError(e.toString()); - } - }) - .finally(() => setLoading(false)); - }, - [workspaceId, template, value, router] - ); - - if (!template.remoteFrom || !template.remoteTo) { - return
Invalid driver
; - } - - return ( - <> -
-
- - -
-
- -
-
Connect to {getDatabaseFriendlyName(driver)} database
-
- - {error && ( -
- {error} -
- )} - - -
- -
-
- - - -
-
- - ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/new-base/page.tsx b/src/app/(outerbase)/w/[workspaceId]/new-base/page.tsx deleted file mode 100644 index 3efffb0b..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/new-base/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -export const runtime = "edge"; - -export default function NewBasePage() { - return
Unknown page
; -} diff --git a/src/app/(outerbase)/w/[workspaceId]/page.tsx b/src/app/(outerbase)/w/[workspaceId]/page.tsx deleted file mode 100644 index a18c863f..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/page.tsx +++ /dev/null @@ -1,148 +0,0 @@ -"use client"; - -import { ConnectionTemplateDictionary } from "@/components/connection-config-editor/template"; -import { useOuterbaseDashboardList } from "@/outerbase-cloud/hook"; -import { useRouter } from "next/navigation"; -import { useCallback, useMemo } from "react"; -import { toast } from "sonner"; -import NavigationHeader from "../../nav-header"; -import NavigationLayout from "../../nav-layout"; -import { - getResourceItemPropsFromBase, - getResourceItemPropsFromBoard, - ResourceItemList, - ResourceItemProps, -} from "../../resource-item-helper"; -import { useWorkspaces } from "../../workspace-provider"; -import { deleteBaseDialog } from "./dialog-base-delete"; -import { createBoardDialog } from "./dialog-board-create"; -import { deleteBoardDialog } from "./dialog-board-delete"; - -export const runtime = "edge"; - -export default function WorkspaceListPage() { - const router = useRouter(); - const { - currentWorkspace, - loading: workspaceLoading, - refreshWorkspace, - } = useWorkspaces(); - const { data: dashboardList, mutate: refreshDashboardList } = - useOuterbaseDashboardList(); - - const bases = useMemo(() => { - if (!currentWorkspace) return []; - - const bases = - (currentWorkspace.bases ?? []).map((base) => { - return getResourceItemPropsFromBase(currentWorkspace, base); - }) ?? []; - - return bases; - }, [currentWorkspace]); - - const dashboards = useMemo(() => { - if (!currentWorkspace) return []; - - return ( - (dashboardList ?? []) - .filter( - (board) => - board.workspace_id === currentWorkspace.id && board.base_id === null - ) - .map((board) => { - return getResourceItemPropsFromBoard(currentWorkspace, board); - }) ?? [] - ); - }, [currentWorkspace, dashboardList]); - - const onDeleteBoardClicked = useCallback( - (deletedResource: ResourceItemProps) => { - if (!currentWorkspace) return; - - deleteBoardDialog - .show({ - workspaceId: currentWorkspace.id, - boardId: deletedResource.id, - boardName: deletedResource.name, - }) - .then(() => { - refreshDashboardList(); - }) - .catch(); - }, - [currentWorkspace, refreshDashboardList] - ); - - const onDeleteBaseClicked = useCallback( - (deletedResource: ResourceItemProps) => { - if (!currentWorkspace) return; - - deleteBaseDialog - .show({ - workspaceId: currentWorkspace.id, - baseId: deletedResource.id, - baseName: deletedResource.name, - }) - .then(() => { - refreshWorkspace(); - }) - .catch(); - }, - [currentWorkspace, refreshWorkspace] - ); - - const onCreateBoardClicked = useCallback(() => { - if (!currentWorkspace) return; - - createBoardDialog - .show({ - workspaceId: currentWorkspace.id, - }) - .then((createdBoard) => { - if (!createdBoard) return; - - refreshDashboardList(); - router.push( - `/w/${currentWorkspace.short_name}/board/${createdBoard.id}` - ); - }); - }, [currentWorkspace, router, refreshDashboardList]); - - const onBaseEditClicked = useCallback( - (editResource: ResourceItemProps) => { - if (!currentWorkspace) return; - if (ConnectionTemplateDictionary[editResource.type ?? ""] === undefined) { - toast("Editing this type of resource is not supported at the moment."); - return; - } - - router.push( - `/w/${currentWorkspace.short_name}/edit-base/${editResource.id}` - ); - }, - [currentWorkspace, router] - ); - - return ( - <> - {currentWorkspace?.name ?? "Untitled"} - - - -
- -
-
- - ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/redirect-valid-workspace.ts b/src/app/(outerbase)/w/[workspaceId]/redirect-valid-workspace.ts deleted file mode 100644 index b20afd13..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/redirect-valid-workspace.ts +++ /dev/null @@ -1,24 +0,0 @@ -"use client"; -import { useParams, useRouter } from "next/navigation"; -import { useEffect } from "react"; -import { useWorkspaces } from "../../workspace-provider"; - -export default function useRedirectValidWorkspace() { - const { workspaceId } = useParams(); - const { currentWorkspace, workspaces, loading } = useWorkspaces(); - const router = useRouter(); - - useEffect(() => { - // If the current workspace is not found, redirect to the first workspace - if (loading) return; - if (!workspaceId) return; - if (workspaceId === "local-workspace") return; - if (typeof window === "undefined") return; - - if (!currentWorkspace) { - if (workspaces?.length) { - router.replace(`/w/${workspaces[0].short_name}`); - } - } - }, [loading, workspaces, currentWorkspace, workspaceId, router]); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/settings/delete.tsx b/src/app/(outerbase)/w/[workspaceId]/settings/delete.tsx deleted file mode 100644 index b5075281..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/settings/delete.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { useWorkspaces } from "@/app/(outerbase)/workspace-provider"; -import CopyableText from "@/components/copyable-text"; -import { createDialog } from "@/components/create-dialog"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { OuterbaseAPIWorkspace } from "@/outerbase-cloud/api-type"; -import { deleteOuterbaseWorkspace } from "@/outerbase-cloud/api-workspace"; -import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; - -function DeleteWorkspaceDialog({ - workspace, - close, -}: { - workspace: OuterbaseAPIWorkspace; - close: (value: boolean) => void; -}) { - const [loading, setLoading] = useState(false); - const [name, setName] = useState(""); - - const onDeletedClicked = useCallback(() => { - setLoading(true); - deleteOuterbaseWorkspace(workspace.id) - .then(() => { - close(true); - }) - .finally(() => { - setLoading(false); - }); - }, [close, workspace]); - - return ( - <> - - Confirm deletion of {workspace.name} - - - - Deleting this workspace will delete all Bases and revoke all connections - made to your databases. All members will lose access. This action is - permanent and cannot be undone. - - -
-
- -
- - -
- - - - - - - ); -} - -const deleteWorkspaceDialog = createDialog< - { - workspace: OuterbaseAPIWorkspace; - }, - boolean ->( - ({ workspace, close }) => { - return ; - }, - { defaultValue: false, slot: "workspace" } -); - -export default function WorkspaceDeleteSection({ - workspace, -}: { - workspace: OuterbaseAPIWorkspace; -}) { - const router = useRouter(); - const { refreshWorkspace } = useWorkspaces(); - - const onDeleteClicked = useCallback(async () => { - const success = await deleteWorkspaceDialog.show({ workspace }); - if (success) { - refreshWorkspace().then(() => router.push("/")); - } - }, [workspace, router, refreshWorkspace]); - - return ( -
-

Delete workspace

-

- This will delete all Bases within this workspace. All members will lose - access. -

- -
- -
-
- ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/settings/detail.tsx b/src/app/(outerbase)/w/[workspaceId]/settings/detail.tsx deleted file mode 100644 index 5e33f9b4..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/settings/detail.tsx +++ /dev/null @@ -1,69 +0,0 @@ -"use client"; -import { useWorkspaces } from "@/app/(outerbase)/workspace-provider"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { OuterbaseAPIWorkspace } from "@/outerbase-cloud/api-type"; -import { updateOuterbaseWorkspace } from "@/outerbase-cloud/api-workspace"; -import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; - -export default function WorkspaceDetailSection({ - workspace, -}: { - workspace: OuterbaseAPIWorkspace; -}) { - const router = useRouter(); - const { refreshWorkspace } = useWorkspaces(); - const [loading, setLoading] = useState(false); - const [shortName, setShortName] = useState(workspace.short_name); - const [name, setName] = useState(workspace.name); - - const onUpdateClicked = useCallback(() => { - setLoading(true); - updateOuterbaseWorkspace(workspace.id, { short_name: shortName, name }) - .then(() => { - refreshWorkspace().then(() => { - if (workspace.short_name !== shortName) { - router.push(`/w/${shortName}/settings`); - } - setLoading(false); - }); - }) - .catch(() => setLoading(false)); - }, [shortName, name, workspace, router, refreshWorkspace]); - - return ( -
-

Details

- -
- - -
- -
-
-
- ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/settings/gateway.tsx b/src/app/(outerbase)/w/[workspaceId]/settings/gateway.tsx deleted file mode 100644 index b5b55b5f..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/settings/gateway.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Button } from "@/components/orbit/button"; - -export default function WorkspaceGatewaySection() { - return ( -
-

Gateway

- -

- Securely access private network databases without modifying your - firewall or VPN -

- -
- -
-
- ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/settings/members.tsx b/src/app/(outerbase)/w/[workspaceId]/settings/members.tsx deleted file mode 100644 index 780c1f82..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/settings/members.tsx +++ /dev/null @@ -1,17 +0,0 @@ -"use client"; -import { Button } from "@/components/orbit/button"; -import { Plus } from "@phosphor-icons/react"; - -export default function WorkspaceMemberSection() { - return ( -
-
-

Members

- -
-
- ); -} diff --git a/src/app/(outerbase)/w/[workspaceId]/settings/page.tsx b/src/app/(outerbase)/w/[workspaceId]/settings/page.tsx deleted file mode 100644 index 1bc42c46..00000000 --- a/src/app/(outerbase)/w/[workspaceId]/settings/page.tsx +++ /dev/null @@ -1,37 +0,0 @@ -"use client"; -import NavigationHeader from "@/app/(outerbase)/nav-header"; -import NavigationLayout from "@/app/(outerbase)/nav-layout"; -import { useWorkspaces } from "@/app/(outerbase)/workspace-provider"; -import { Loader } from "@/components/orbit/loader"; -import WorkspaceDeleteSection from "./delete"; -import WorkspaceDetailSection from "./detail"; - -export const runtime = "edge"; - -export default function WorkspaceBillingPage() { - const { currentWorkspace } = useWorkspaces(); - - return ( - - - -
-

Workspace settings

- - {currentWorkspace ? ( - <> - - {/* - */} - - - ) : ( -
- - Loading workspace... -
- )} -
-
- ); -} From 5893e1341d36c4b62f5b9073238b158f3c3ffb1f Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 08:57:19 +0000 Subject: [PATCH 03/10] chore: remove outerbase signin and signout --- src/app/(dark-only)/password_reset/page.tsx | 147 ---------------- src/app/(dark-only)/signin/page.tsx | 124 ------------- .../(dark-only)/signin/starbase-portal.tsx | 48 ----- src/app/(dark-only)/signin/styles.css | 53 ------ src/app/(dark-only)/signup-workspace/page.tsx | 164 ------------------ src/app/(dark-only)/signup/page.tsx | 19 -- src/app/(dark-only)/signup/signup-form.tsx | 147 ---------------- src/app/(dark-only)/signup/signup-otp.tsx | 101 ----------- src/app/(dark-only)/verify/page.tsx | 103 ----------- 9 files changed, 906 deletions(-) delete mode 100644 src/app/(dark-only)/password_reset/page.tsx delete mode 100644 src/app/(dark-only)/signin/page.tsx delete mode 100644 src/app/(dark-only)/signin/starbase-portal.tsx delete mode 100644 src/app/(dark-only)/signin/styles.css delete mode 100644 src/app/(dark-only)/signup-workspace/page.tsx delete mode 100644 src/app/(dark-only)/signup/page.tsx delete mode 100644 src/app/(dark-only)/signup/signup-form.tsx delete mode 100644 src/app/(dark-only)/signup/signup-otp.tsx delete mode 100644 src/app/(dark-only)/verify/page.tsx diff --git a/src/app/(dark-only)/password_reset/page.tsx b/src/app/(dark-only)/password_reset/page.tsx deleted file mode 100644 index f794c80f..00000000 --- a/src/app/(dark-only)/password_reset/page.tsx +++ /dev/null @@ -1,147 +0,0 @@ -"use client"; -import OuterbaseLogo from "@/components/icons/outerbase"; -import { Button } from "@/components/orbit/button"; -import { Input } from "@/components/orbit/input"; -import { Label } from "@/components/orbit/label"; -import { isValidEmail } from "@/lib/validation"; -import { - requestResetPassword, - resetPassword, -} from "@/outerbase-cloud/api-account"; -import { SendHorizonal } from "lucide-react"; -import Link from "next/link"; -import { useRouter, useSearchParams } from "next/navigation"; -import { useCallback, useMemo, useState } from "react"; -import { toast } from "sonner"; - -export default function PasswordResetPage() { - const param = useSearchParams(); - const router = useRouter(); - const reset_token = param.get("reset_token"); - const [loading, setLoading] = useState(false); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [isSent, setIsSent] = useState(false); - - const onResetPassword = useCallback(() => { - if (!reset_token) return; - setLoading(true); - resetPassword({ - password, - reset_token, - }) - .then(() => { - toast.success("Your password has been reseted"); - router.replace("/signin"); - }) - .catch((error) => { - setLoading(false); - toast.error(`Error: ${error.message}`); - }); - }, [password, reset_token, router]); - - const onRequestResetPassword = useCallback(() => { - setLoading(true); - requestResetPassword({ email }) - .then(() => setIsSent(true)) - .catch((error) => { - setLoading(false); - toast.error(`Error: ${error.message}`); - }) - .finally(() => { - setLoading(false); - }); - }, [email]); - - const { title, description } = useMemo(() => { - let title, description; - - if (isSent) { - title = "Check your email"; - description = "We've sent a reset link to"; - } else if (reset_token) { - title = "Choose a new password"; - description = "Enter a new password for your account."; - } else { - title = "Reset your password"; - description = `Enter the email address you log in to Outerbase with, and we’ll email you a link to reset your password.`; - } - - return { title, description }; - }, [isSent, reset_token]); - - return ( -
-
-
-
-
-
-
- - - -
-
-
{title}
-
- {isSent && } - -

- {description} - {isSent && ( - -
- {email} -
- )} -

-
- {(!isSent || reset_token) && ( - <> - -
-
-
-
-
-
-
- ); -} diff --git a/src/app/(dark-only)/signin/page.tsx b/src/app/(dark-only)/signin/page.tsx deleted file mode 100644 index 5661f39a..00000000 --- a/src/app/(dark-only)/signin/page.tsx +++ /dev/null @@ -1,124 +0,0 @@ -"use client"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { - getOuterbaseSession, - loginOuterbaseByPassword, -} from "@/outerbase-cloud/api"; -import { OuterbaseAPIError } from "@/outerbase-cloud/api-type"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; -import { LoginBaseSpaceship } from "./starbase-portal"; - -export default function SigninPage() { - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [error, setError] = useState(""); - const router = useRouter(); - const [loading, setLoading] = useState(false); - - const onLoginClicked = useCallback(() => { - setLoading(true); - - loginOuterbaseByPassword(email, password) - .then(async (session) => { - localStorage.setItem("ob-token", session.token); - localStorage.setItem("session", JSON.stringify(session)); - - const { user } = await getOuterbaseSession(); - - if (user.has_otp) { - router.push("/verify"); - return; - } - - const redirect = localStorage.getItem("continue-redirect"); - router.push(redirect ?? "/"); - }) - .catch((e) => { - setLoading(false); - if (e instanceof OuterbaseAPIError) { - setError(e.description); - } - }); - }, [email, password, router]); - - return ( - <> -
-
- - - - -

Welcome back

-

Sign in to your existing account

-
- -
{ - onLoginClicked(); - e.preventDefault(); - }} - className="flex flex-col gap-4" - > - setEmail(e.currentTarget.value)} - /> - - setPassword(e.currentTarget.value)} - /> - - {error &&
{error}
} - - - - - - Forget password - -
- {`Don't have an account?`}{" "} - - Sign Up - -
-
- - - - ); -} diff --git a/src/app/(dark-only)/signin/starbase-portal.tsx b/src/app/(dark-only)/signin/starbase-portal.tsx deleted file mode 100644 index 9ad41526..00000000 --- a/src/app/(dark-only)/signin/starbase-portal.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import "./styles.css"; - -export function LoginBaseSpaceship() { - return ( -
-
- -
-
- stars - - planet -
-
-
- ); -} diff --git a/src/app/(dark-only)/signin/styles.css b/src/app/(dark-only)/signin/styles.css deleted file mode 100644 index 0c507818..00000000 --- a/src/app/(dark-only)/signin/styles.css +++ /dev/null @@ -1,53 +0,0 @@ -@keyframes moveStars { - 0% { - bottom: 32%; - transform: rotate(0deg); - } - 25% { - bottom: 33%; - transform: rotate(-1deg); - } - 50% { - bottom: 34%; - transform: rotate(0deg); - } - 75% { - bottom: 33%; - transform: rotate(1deg); - } - 100% { - bottom: 32%; - transform: rotate(0deg); - } -} - -@keyframes movePlanet { - 0% { - bottom: 16%; - transform: rotate(0deg); - } - 25% { - bottom: 17.5%; - transform: rotate(1deg); - } - 50% { - bottom: 20%; - transform: rotate(0deg); - } - 75% { - bottom: 17.5%; - transform: rotate(-1deg); - } - 100% { - bottom: 16%; - transform: rotate(0deg); - } -} - -.stars-animation { - animation: moveStars 30s ease-in-out infinite; -} - -.planet-animation { - animation: movePlanet 30s ease-in-out infinite; -} diff --git a/src/app/(dark-only)/signup-workspace/page.tsx b/src/app/(dark-only)/signup-workspace/page.tsx deleted file mode 100644 index fb12b9bf..00000000 --- a/src/app/(dark-only)/signup-workspace/page.tsx +++ /dev/null @@ -1,164 +0,0 @@ -"use client"; -import { useWorkspaces } from "@/app/(outerbase)/workspace-provider"; -import { OuterbaseIcon } from "@/components/icons/outerbase"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { Label } from "@/components/orbit/label"; -import { Select } from "@/components/orbit/select"; -import { strippedWorkspaceName } from "@/lib/utils"; -import { updateOuterbaseUserProfile } from "@/outerbase-cloud/api-account"; -import { createOuterbaseWorkspace } from "@/outerbase-cloud/api-workspace"; -import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; -import { LoginBaseSpaceship } from "../signin/starbase-portal"; -import { SpaceshipContentContainer } from "../spaceship-container"; - -function generateRandomString(length: number) { - const characters = "0123456789abcdefghijklmnopqrstuvwxyz"; - let result = ""; - for (let i = 0; i < length; i++) { - const randomIndex = Math.floor(Math.random() * characters.length); - result += characters[randomIndex]; - } - return result; -} - -export default function SignupPage() { - const router = useRouter(); - const [role, setRole] = useState(""); - const [companySize, setCompanySize] = useState(""); - const [firstName, setFirstName] = useState(""); - const [lastName, setLastName] = useState(""); - const [workspaceName, setWorkspaceName] = useState(""); - const [loading, setLoading] = useState(false); - const { refreshPartial } = useWorkspaces(); - - const createWorkspaceWithProfile = useCallback(async () => { - const random = generateRandomString(4); - const workspaceShortName = `${strippedWorkspaceName(workspaceName)}-${random}`; - - await updateOuterbaseUserProfile({ - first_name: firstName, - last_name: lastName, - }).then(() => {}); - - const createdWorkspace = await createOuterbaseWorkspace({ - name: workspaceName, - short_name: workspaceShortName, - }); - - refreshPartial(createdWorkspace); - router.push(`/w/${createdWorkspace.short_name}`); - }, [workspaceName, firstName, lastName, router, refreshPartial]); - - return ( - <> - -
- - -

Create Workspace

-

Workspaces are a home for your databases.

-
- -
{ - e.preventDefault(); - - setLoading(true); - createWorkspaceWithProfile() - .then() - .catch() - .finally(() => { - setLoading(false); - }); - }} - className="flex flex-col gap-4" - > - setFirstName(e.currentTarget.value)} - required - /> - - setLastName(e.currentTarget.value)} - required - /> - - setWorkspaceName(e.currentTarget.value)} - /> - - - - - -
- - - ); -} diff --git a/src/app/(dark-only)/signup/page.tsx b/src/app/(dark-only)/signup/page.tsx deleted file mode 100644 index c1a9b88d..00000000 --- a/src/app/(dark-only)/signup/page.tsx +++ /dev/null @@ -1,19 +0,0 @@ -"use client"; -import { useSearchParams } from "next/navigation"; -import { LoginBaseSpaceship } from "../signin/starbase-portal"; -import { SignupForm } from "./signup-form"; -import { SignupOtp } from "./signup-otp"; - -//https://app.outerbase.com/api/v1/auth/register -export default function SignupPage() { - const searchParams = useSearchParams(); - - const verify = searchParams.get("verify") === "true"; - - return ( - <> - {verify ? : } - - - ); -} diff --git a/src/app/(dark-only)/signup/signup-form.tsx b/src/app/(dark-only)/signup/signup-form.tsx deleted file mode 100644 index 9b6ef272..00000000 --- a/src/app/(dark-only)/signup/signup-form.tsx +++ /dev/null @@ -1,147 +0,0 @@ -"use client"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { - registerOuterbaseByPassword, - verifyOuterbaseRequestEmail, -} from "@/outerbase-cloud/api"; -import { - OuterbaseAPIError, - OuterbaseAPISession, -} from "@/outerbase-cloud/api-type"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useCallback, useEffect, useState } from "react"; - -export function SignupForm() { - const router = useRouter(); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [error, setError] = useState(""); - const [loading, setLoading] = useState(false); - const [session, setSession] = useState(); - - const onRegisterClicked = useCallback(() => { - setLoading(true); - - registerOuterbaseByPassword(email, password) - .then((session) => { - localStorage.setItem("ob-token", session.token); - localStorage.setItem("session", JSON.stringify({ ...session, email })); - //Alway error 403 - verifyOuterbaseRequestEmail().then(() => { - setLoading(false); - localStorage.setItem("continue-redirect", "/signup?verify=true"); - setSession(session); - }); - }) - .catch((e) => { - setLoading(false); - if (e instanceof OuterbaseAPIError) { - setError(e.description); - } - }); - }, [email, password]); - - useEffect(() => { - if (!session) return; - - const redirect = localStorage.getItem("continue-redirect"); - if (redirect) { - router.push(redirect); - return; - } - - router.push("/"); - }, [session, router]); - - return ( -
-
-
- - - - -

Create your Account

-

Sign up to get started with Outerbase

-
- -
{ - e.preventDefault(); - }} - className="flex flex-col gap-4" - > - setEmail(e.currentTarget.value)} - /> - - setPassword(e.currentTarget.value)} - /> - - {error &&
{error}
} - - - -
- Already have an account?{" "} - - Sign In - -
-
-
- By signing up, you agree to our -
- - Terms of Service - {" "} - and{" "} - - Privacy Policy - -
-
- ); -} diff --git a/src/app/(dark-only)/signup/signup-otp.tsx b/src/app/(dark-only)/signup/signup-otp.tsx deleted file mode 100644 index 3eee92d1..00000000 --- a/src/app/(dark-only)/signup/signup-otp.tsx +++ /dev/null @@ -1,101 +0,0 @@ -"use client"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { verifyOuterbaseSubmitEmail } from "@/outerbase-cloud/api"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useCallback, useEffect, useState } from "react"; - -export function SignupOtp() { - const [code, setCode] = useState(""); - const [error, setError] = useState(""); - const router = useRouter(); - const [loading, setLoading] = useState(false); - const [email, setEmail] = useState(""); - - const onVerifyOTP = useCallback(() => { - if (code.length < 6) return; - setLoading(true); - verifyOuterbaseSubmitEmail(code) - .then(() => { - localStorage.removeItem("continue-redirect"); - router.push("/"); - }) - .catch((err) => setError(err.message)) - .finally(() => { - setLoading(false); - }); - }, [code, router]); - - useEffect(() => { - const session = localStorage.getItem("session"); - if (!session) return; - const user = JSON.parse(session); - setEmail(user.email); - }, []); - - return ( -
-
- - - - -

Check your email

-

- We've sent a link to {email ?? ""} -

-
- -
{ - onVerifyOTP(); - e.preventDefault(); - }} - className="flex flex-col gap-4" - > - setCode(e.currentTarget.value)} - /> - - {error &&
{error}
} - - - - -
- Still having trouble?{" "} - - Contact support - -
-
- ); -} diff --git a/src/app/(dark-only)/verify/page.tsx b/src/app/(dark-only)/verify/page.tsx deleted file mode 100644 index 97aa1270..00000000 --- a/src/app/(dark-only)/verify/page.tsx +++ /dev/null @@ -1,103 +0,0 @@ -"use client"; -import LabelInput from "@/components/label-input"; -import { Button } from "@/components/orbit/button"; -import { verifyOuterbaseOTP } from "@/outerbase-cloud/api-account"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; -import { LoginBaseSpaceship } from "../signin/starbase-portal"; - -export default function VerifyPage() { - const [code, setCode] = useState(""); - const [error, setError] = useState(""); - const router = useRouter(); - const [loading, setLoading] = useState(false); - - const onVerifyOTP = useCallback(() => { - if (code.length < 6) return; - setLoading(true); - verifyOuterbaseOTP(code) - .then(() => { - if (localStorage.getItem("continue-redirect")) { - router.push(localStorage.getItem("continue-redirect") ?? "/"); - localStorage.removeItem("continue-redirect"); - } else { - router.push("/"); - } - }) - .catch((err) => setError(err.message)) - .finally(() => { - setLoading(false); - }); - }, [code, router]); - - return ( - <> -
-
- - - - -

Verify that it's you

-

- Enter the verification code for Outerbase from your two-factor - authentication app. -

-
- -
{ - onVerifyOTP(); - e.preventDefault(); - }} - className="flex flex-col gap-4" - > - setCode(e.currentTarget.value)} - /> - - {error &&
{error}
} - - - - -
- Still having trouble?{" "} - - Contact support - -
-
- - - - ); -} From c1f6a3c6fd5a93c9023880d5b1481833a9875f00 Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 08:57:53 +0000 Subject: [PATCH 04/10] chore: remove outerbase account page --- .../(outerbase)/account/account-footer.tsx | 136 -------- src/app/(outerbase)/account/editor-theme.tsx | 106 ------ src/app/(outerbase)/account/page.tsx | 30 -- .../(outerbase)/account/two-factor-auth.tsx | 326 ------------------ src/app/(outerbase)/account/user-avatar.tsx | 25 -- .../(outerbase)/account/user-form-input.tsx | 140 -------- 6 files changed, 763 deletions(-) delete mode 100644 src/app/(outerbase)/account/account-footer.tsx delete mode 100644 src/app/(outerbase)/account/editor-theme.tsx delete mode 100644 src/app/(outerbase)/account/page.tsx delete mode 100644 src/app/(outerbase)/account/two-factor-auth.tsx delete mode 100644 src/app/(outerbase)/account/user-avatar.tsx delete mode 100644 src/app/(outerbase)/account/user-form-input.tsx diff --git a/src/app/(outerbase)/account/account-footer.tsx b/src/app/(outerbase)/account/account-footer.tsx deleted file mode 100644 index 3fb1c359..00000000 --- a/src/app/(outerbase)/account/account-footer.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { useSession } from "@/app/(outerbase)/session-provider"; -import { Button } from "@/components/orbit/button"; -import { Input } from "@/components/orbit/input"; -import { Label } from "@/components/orbit/label"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { isValidEmail } from "@/lib/validation"; -import { deleteOuterbaseUser } from "@/outerbase-cloud/api-account"; -import { Check, Copy } from "lucide-react"; -import { useRouter } from "next/router"; -import { useCallback, useMemo, useState } from "react"; -import { toast } from "sonner"; - -export default function AccountFooter() { - const { session } = useSession(); - const router = useRouter(); - const [open, setOpen] = useState(false); - const [copied, setCopied] = useState(false); - const [email, setEmail] = useState(""); - const [loading, setLoading] = useState(false); - - const copyToClipboard = async () => { - if (!session) return; - try { - await navigator.clipboard.writeText(session?.user.email); - setCopied(true); - } catch (error) { - console.error("Failed to copy:", error); - } - }; - - const onClose = () => { - setCopied(false); - setOpen(false); - setEmail(""); - setLoading(false); - }; - - const onDeleteOuerbaseUser = useCallback(() => { - setLoading(true); - deleteOuterbaseUser() - .then(() => { - onClose(); - router.push("/signout"); - }) - .catch((err) => { - setLoading(false); - toast.error(err.message); - }); - }, [router]); - - const fullName = useMemo(() => { - if (!session) return; - return session?.user.first_name + " " + session?.user.last_name; - }, [session]); - - const disabled = useMemo(() => { - return !isValidEmail(email) || email !== session?.user.email; - }, [email, session]); - - return ( - <> - { - if (!open) { - onClose(); - } - }} - > - - - - Confirm deletion of {fullName}' account - - - - - Deleting this account will delete all Bases and Workspaces and - revoke all connections made to your databases. All members will lose - access. This action is permanent and{" "} - cannot be - undone. - - - -
-
-
-
-
-

- Delete Account -

-
- This will delete your account and all the workspaces you own. -
-
- - ); -} diff --git a/src/app/(outerbase)/account/editor-theme.tsx b/src/app/(outerbase)/account/editor-theme.tsx deleted file mode 100644 index 2d4f93e6..00000000 --- a/src/app/(outerbase)/account/editor-theme.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import SqlEditor from "@/components/gui/sql-editor"; -import { Button } from "@/components/orbit/button"; -import { Label } from "@/components/ui/label"; -import { cn } from "@/lib/utils"; -import { useTheme } from "next-themes"; -import { useState } from "react"; - -function EditorTheme() { - const [selectedTheme, setSelectedTheme] = useState(""); - - const statement = `CREATE TABLE video_game ( - game_id SERIAL PRIMARY KEY, - title VARCHAR(222) NOT NULL, - genre VARCHAR(222), - plaform VARCHAR(100), - release_dat DATE, - developer VARCHAR(255) - );`; - - const EditorThemes = [ - { - title: "Moondust", - value: "moondust", - }, - { - title: "Invasion", - value: "invasion", - }, - { - title: "Freedom", - value: "freedom", - }, - ]; - return ( -
-

Editor theme

- {EditorThemes.map((theme, index) => { - const isSelected = theme.value === selectedTheme; - return ( -
setSelectedTheme(theme.value)} - className="mb-2 w-full cursor-pointer" - > - -
-
- -
-
-
- ); - })} -
- ); -} - -export default function UserEditorTheme() { - const { theme, setTheme } = useTheme(); - - // Not implement yet - return ( -
-

- Theming -

-

Theme

-
-
- -
- ); -} diff --git a/src/app/(outerbase)/account/page.tsx b/src/app/(outerbase)/account/page.tsx deleted file mode 100644 index ac60d7d0..00000000 --- a/src/app/(outerbase)/account/page.tsx +++ /dev/null @@ -1,30 +0,0 @@ -"use client"; -import { useSession } from "@/app/(outerbase)/session-provider"; -import NavigationLayout from "../nav-layout"; -import AccountFooter from "./account-footer"; -import TwoFactorAuth from "./two-factor-auth"; -import UserAvatar from "./user-avatar"; -import UserFormInput from "./user-form-input"; - -export default function AccountPage() { - const { session } = useSession(); - - if (!session?.user) return
You are not login!
; - - return ( - -
-
-

Account Setting

-

- Details -

- - - - -
-
-
- ); -} diff --git a/src/app/(outerbase)/account/two-factor-auth.tsx b/src/app/(outerbase)/account/two-factor-auth.tsx deleted file mode 100644 index 34f756f0..00000000 --- a/src/app/(outerbase)/account/two-factor-auth.tsx +++ /dev/null @@ -1,326 +0,0 @@ -import { Button } from "@/components/orbit/button"; -import { Input } from "@/components/orbit/input"; -import { CountryCodePicker } from "@/components/picker/country-code-picker"; -import { Label } from "@/components/ui/label"; -import { - deleteOuterbaseTwoFactorAuth, - requestOuterbase2FAPhone, - requestOuterbaseTwoFactorAuth, - submitVerifyPhone2FA, - verifyOuterbase2FAOTP, -} from "@/outerbase-cloud/api-account"; -import { CheckCircle2 } from "lucide-react"; -import Image from "next/image"; -import { useCallback, useState } from "react"; -import { toast } from "sonner"; -import { useSession } from "../session-provider"; - -interface HasOTPProps { - loading?: boolean; - onDelete: () => void; -} -function HasOTP({ onDelete, loading }: HasOTPProps) { - return ( -
-
Authentication App
-

- Verification codes will be generated by the authentication app you - configured. -

-
- ); -} - -interface VerifyCodeInputProps { - loading: boolean; - code: string; - disabled?: boolean; - onCancel?: () => void; - onSave: () => void; - onChange: (v: string) => void; -} -function VerifyCodeInput({ - code, - onChange, - onSave, - disabled, - loading, - onCancel, -}: VerifyCodeInputProps) { - return ( - <> -
- - -
-
-
- - ); -} - -type TwoFactorAuthType = "otp" | "phone"; -interface QRCode { - base32: string; - id: string; - image: string; -} - -interface ISMS { - id: string; - number_masked: string; - user_id: string; -} -export default function TwoFactorAuth() { - const { session, refreshSession } = useSession(); - const [twoFactorType, setTwoFactorType] = - useState("phone"); - const [add, setAdd] = useState(false); - const [loading, setLoading] = useState(false); - const [prefix, setPrefix] = useState("+1"); - const [phone, setPhone] = useState(""); - const [verifyCode, setVerifyCode] = useState(""); - const [sms, setSMS] = useState(); - const [qrcode, setQrcode] = useState(); - const [deleting, setDeleting] = useState(false); - const [sending, setSending] = useState(false); - - const onClear = () => { - setDeleting(false); - setQrcode(undefined); - setDeleting(false); - setVerifyCode(""); - setAdd(false); - setTwoFactorType("phone"); - }; - - const onRefreshSession = useCallback( - (msg: string) => { - refreshSession().then(() => { - onClear(); - toast.success(msg); - }); - }, - [refreshSession] - ); - - const onSendRequestPhone2FA = useCallback(() => { - setSending(true); - requestOuterbaseTwoFactorAuth("phone", { - number: prefix + phone, - }) - .then((r) => { - requestOuterbase2FAPhone((r as ISMS).id).then(() => { - setSMS(r as ISMS); - setSending(false); - }); - }) - .catch(() => setSending(false)); - }, [prefix, phone]); - - const onRequestOuterbaseTwoFactorAuth = useCallback( - (type: TwoFactorAuthType) => { - setTwoFactorType(type); - if (type === "otp" && !qrcode) { - requestOuterbaseTwoFactorAuth(type, {}) - .then((r) => { - if (type === "otp") { - setQrcode(r as QRCode); - } - }) - .catch() - .finally(); - } - }, - [qrcode] - ); - - const onVerifyOuterbaseOTP = useCallback(() => { - if (!qrcode?.id) return; - setLoading(true); - verifyOuterbase2FAOTP({ - otp_id: qrcode.id, - token: verifyCode, - }) - .then(() => { - onRefreshSession("2FA enabled"); - }) - .catch((error) => { - setLoading(false); - toast.error(error.message); - }); - }, [qrcode, verifyCode, onRefreshSession]); - - const onSubmitPhone2FA = useCallback(() => { - if (!sms) return; - setLoading(true); - submitVerifyPhone2FA(sms?.id, { code: verifyCode }) - .then(() => { - onRefreshSession("2FA enabled"); - }) - .catch((error) => { - setLoading(false); - toast.error(error.message); - }); - }, [sms, verifyCode, onRefreshSession]); - - function handleSave() { - if (twoFactorType === "otp") { - onVerifyOuterbaseOTP(); - } else { - onSubmitPhone2FA(); - } - } - - const onDeleteTwoFactor = useCallback(() => { - setDeleting(true); - deleteOuterbaseTwoFactorAuth() - .then(() => { - onRefreshSession("2FA disabled"); - }) - .catch((error) => { - setDeleting(false); - toast.error(error.message); - }); - }, [onRefreshSession]); - - const disabled = twoFactorType === "otp" && verifyCode.length < 6; - - if (session?.user.has_otp) { - return ; - } - - let footer = ( -
-
- {twoFactorType === "otp" ? ( - <> - -
- Use an authentication app like Google Authenticator, 1Password - or Authy. -
{" "} -
- {qrcode && ( - qr-code - )} -
- - ) : ( - <> - -
- { - setPrefix(c.code); - }} - className="w-[250px]" - /> -
- - )} -
- {twoFactorType === "phone" && ( -
- - -
-
-
- )} - - -
- ); - } - return ( -
-

- Two-factor authentication -

- - Requiring more than just a password to sign in to your account, giving - your Outerbase account an additional layer of security. - - {footer} -
- ); -} diff --git a/src/app/(outerbase)/account/user-avatar.tsx b/src/app/(outerbase)/account/user-avatar.tsx deleted file mode 100644 index 34727a32..00000000 --- a/src/app/(outerbase)/account/user-avatar.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Button } from "@/components/orbit/button"; -import { OuterbaseAPIUser } from "@/outerbase-cloud/api-type"; -import Image from "next/image"; - -export default function UserAvatar({ user }: { user: OuterbaseAPIUser }) { - // not implement upload user avatar - - return ( -
-
- {user.avatar ? ( - User Avatar - ) : ( - {user.initials} - )} -
-
- ); -} diff --git a/src/app/(outerbase)/account/user-form-input.tsx b/src/app/(outerbase)/account/user-form-input.tsx deleted file mode 100644 index 7bfb1a90..00000000 --- a/src/app/(outerbase)/account/user-form-input.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { useSession } from "@/app/(outerbase)/session-provider"; -import { Button } from "@/components/orbit/button"; -import { Input } from "@/components/orbit/input"; -import { Label } from "@/components/orbit/label"; -import { - updateOuterbaseUserPassword, - updateOuterbaseUserProfile, -} from "@/outerbase-cloud/api-account"; -import { OuterbaseAPIUser } from "@/outerbase-cloud/api-type"; -import { produce } from "immer"; -import { useCallback, useState } from "react"; -import { toast } from "sonner"; - -interface Props { - user: OuterbaseAPIUser; -} - -export default function UserFormInput({ user }: Props) { - const { refreshSession } = useSession(); - const [loading, setLoading] = useState< - "user_profile" | "login_method" | undefined - >(); - const [userData, setUserData] = useState(user); - const [currentPassword, setCurrentPassword] = useState(""); - const [newPassword, setNewPassword] = useState(""); - const updateUserProfile = useCallback(() => { - setLoading("user_profile"); - updateOuterbaseUserProfile({ - first_name: userData.first_name, - last_name: userData.last_name, - }) - .then(() => { - toast.success("Profile updated"); - refreshSession(); - }) - .catch((error) => { - toast.error(error?.message); - }) - .finally(() => { - setLoading(undefined); - }); - }, [userData, refreshSession]); - - const updateUserPassword = useCallback(() => { - setLoading("login_method"); - updateOuterbaseUserPassword({ - new_password: newPassword, - old_password: currentPassword, - }) - .then(() => { - toast.success("Password updated"); - refreshSession(); - }) - .catch((error) => toast.error(error?.message)) - .finally(() => { - setLoading(undefined); - }); - }, [newPassword, currentPassword, refreshSession]); - - return ( -
- - -
- ); -} From 3162ecdc2a57ba2be03c1669d410647e8abfc603 Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 08:58:45 +0000 Subject: [PATCH 05/10] remove the outerbase signout and auth --- src/app/(outerbase)/auth-provider.tsx | 26 ----------- src/app/(outerbase)/nav-signin-banner.tsx | 53 ----------------------- src/app/(outerbase)/signout/page.tsx | 25 ----------- 3 files changed, 104 deletions(-) delete mode 100644 src/app/(outerbase)/auth-provider.tsx delete mode 100644 src/app/(outerbase)/nav-signin-banner.tsx delete mode 100644 src/app/(outerbase)/signout/page.tsx diff --git a/src/app/(outerbase)/auth-provider.tsx b/src/app/(outerbase)/auth-provider.tsx deleted file mode 100644 index 5f0a72c1..00000000 --- a/src/app/(outerbase)/auth-provider.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; -import { usePathname, useRouter } from "next/navigation"; -import { PropsWithChildren, useEffect } from "react"; -import { useSession } from "./session-provider"; - -export default function AuthProvider({ children }: PropsWithChildren) { - const router = useRouter(); - const pathname = usePathname(); - const { isLoading, session } = useSession(); - - useEffect(() => { - if (isLoading) return; - const redirect = localStorage.getItem("continue-redirect"); - if (!session?.session || !session?.user) { - localStorage.setItem("continue-redirect", pathname); - router.replace("/signin"); - // IF user enabled 2FA keep redirect to verify page - } else if (session.user.has_otp && redirect === "/verify") { - router.replace(redirect); - } else { - localStorage.removeItem("continue-redirect"); - } - }, [isLoading, session, pathname, router]); - - return <>{children}; -} diff --git a/src/app/(outerbase)/nav-signin-banner.tsx b/src/app/(outerbase)/nav-signin-banner.tsx deleted file mode 100644 index 02dd7195..00000000 --- a/src/app/(outerbase)/nav-signin-banner.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import Banner from "@/components/orbit/banner"; -import RippleFilter from "@/components/orbit/banner/ripple-filter"; -import { Button } from "@/components/orbit/button"; -import { useRouter } from "next/navigation"; -import { useSession } from "./session-provider"; - -export default function NavigationSigninBanner() { - const { isLoading, session } = useSession(); - const router = useRouter(); - - if (isLoading) { - return null; - } - - if (session) { - return null; - } - - return ( -
- } - className="ripple w-full" - onClick={() => { - router.push("/signin"); - }} - > -
- -
-

Unlock Full Potential

-

- Outerbase Cloud gives you AI-driver insights, managed database, and - team collaboation. -

- - -
- -
- img -
-
-
- ); -} diff --git a/src/app/(outerbase)/signout/page.tsx b/src/app/(outerbase)/signout/page.tsx deleted file mode 100644 index 1c15335a..00000000 --- a/src/app/(outerbase)/signout/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -"use client"; - -import { Loader } from "@/components/orbit/loader"; -import { useRouter } from "next/navigation"; -import { useEffect } from "react"; -import { useSession } from "../session-provider"; - -export default function SignoutPage() { - const { logout } = useSession(); - const router = useRouter(); - - useEffect(() => { - if (typeof window === "undefined") return; - - logout(); - router.push("/"); - }, [router, logout]); - - return ( -
- -

Signing out....

-
- ); -} From b56023e1d07b39e8071cf71af76d13ac48f0cdd6 Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 09:00:09 +0000 Subject: [PATCH 06/10] chore: remove nav rely on outerbase cloud workspace --- src/app/(outerbase)/nav-layout.tsx | 47 ++---------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/src/app/(outerbase)/nav-layout.tsx b/src/app/(outerbase)/nav-layout.tsx index 10107c9b..92256295 100644 --- a/src/app/(outerbase)/nav-layout.tsx +++ b/src/app/(outerbase)/nav-layout.tsx @@ -1,22 +1,13 @@ "use client"; -import { - SidebarMenuHeader, - SidebarMenuItem, - SidebarMenuLoadingItem, -} from "@/components/sidebar-menu"; +import { SidebarMenuHeader, SidebarMenuItem } from "@/components/sidebar-menu"; import { cn } from "@/lib/utils"; import { Database, List } from "@phosphor-icons/react"; -import { useParams, usePathname, useRouter } from "next/navigation"; +import { usePathname } from "next/navigation"; import { PropsWithChildren, useState } from "react"; -import { useWorkspaces } from "./workspace-provider"; export default function NavigationLayout({ children }: PropsWithChildren) { - const router = useRouter(); const [mobileToggle, setMobileToggle] = useState(false); - - const { workspaces, loading: workspaceLoading } = useWorkspaces(); const pathname = usePathname(); - const { workspaceId } = useParams<{ workspaceId?: string }>(); return (
@@ -55,40 +46,6 @@ export default function NavigationLayout({ children }: PropsWithChildren) { icon={Database} href="/local" /> - - {workspaces.map((workspace) => { - return ( - { - router.push(`/w/${workspace.short_name}`); - } - } - selected={workspace.short_name === workspaceId} - badge={ - !workspace.is_enterprise && - workspace.subscription.plan === "starter" ? ( - - Free - - ) : undefined - } - /> - ); - })} - - {workspaceLoading && ( - <> - - - - - )}
From a40e9695b1820547f840302dbaf9849d11125d75 Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 09:01:18 +0000 Subject: [PATCH 07/10] chore: remove unused component --- src/app/(dark-only)/new-workspace/page.tsx | 97 --------------------- src/app/(dark-only)/spaceship-container.tsx | 15 ---- 2 files changed, 112 deletions(-) delete mode 100644 src/app/(dark-only)/new-workspace/page.tsx delete mode 100644 src/app/(dark-only)/spaceship-container.tsx diff --git a/src/app/(dark-only)/new-workspace/page.tsx b/src/app/(dark-only)/new-workspace/page.tsx deleted file mode 100644 index cb104ac0..00000000 --- a/src/app/(dark-only)/new-workspace/page.tsx +++ /dev/null @@ -1,97 +0,0 @@ -"use client"; -import { useWorkspaces } from "@/app/(outerbase)/workspace-provider"; -import OuterbaseLogo from "@/components/icons/outerbase"; -import { Button } from "@/components/orbit/button"; -import { Input } from "@/components/orbit/input"; -import { Label } from "@/components/orbit/label"; -import { strippedWorkspaceName } from "@/lib/utils"; -import { createOuterbaseWorkspace } from "@/outerbase-cloud/api-workspace"; -import useOuterbaseMutation from "@/outerbase-cloud/hook"; -import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; - -const FRIENDLY_ERROR_NAME: Record = { - SHORT_NAME_TAKEN: "Workspace URL is unavailable.", -}; - -export default function NewWorkspacePage() { - const { - loading, - error, - trigger: createWorkspace, - } = useOuterbaseMutation(createOuterbaseWorkspace); - - const router = useRouter(); - const { refreshPartial } = useWorkspaces(); - const [name, setName] = useState(""); - const [shortName, setShortName] = useState(""); - - const finalShortName = shortName || strippedWorkspaceName(name); - - const onCreateClicked = useCallback(() => { - createWorkspace({ - name, - short_name: finalShortName, - }).then((workspace) => { - if (workspace) { - refreshPartial(workspace); - router.push(`/w/${workspace.short_name}`); - } - }); - }, [name, finalShortName, createWorkspace, refreshPartial, router]); - - return ( -
-
-
-
- -
- -

- New Workspace -

- - - - - - {error && ( -

- {FRIENDLY_ERROR_NAME[error.message] ?? error.message} -

- )} - -
- -
-
-
-
-
- ); -} diff --git a/src/app/(dark-only)/spaceship-container.tsx b/src/app/(dark-only)/spaceship-container.tsx deleted file mode 100644 index d177e24c..00000000 --- a/src/app/(dark-only)/spaceship-container.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { PropsWithChildren } from "react"; - -export function SpaceshipContentContainer({ children }: PropsWithChildren) { - return ( -
- {children} -
- ); -} From 026d4e3117cc096f206730fbc2d0686f88e16848 Mon Sep 17 00:00:00 2001 From: Visal In Date: Thu, 15 Jan 2026 09:04:23 +0000 Subject: [PATCH 08/10] chore: remove api tracking --- src/app/(outerbase)/nav-profile.tsx | 143 ------------------- src/app/(theme)/theme_layout.tsx | 2 - src/app/api/events/insert-tracking-record.ts | 46 ------ src/app/api/events/route.ts | 74 ---------- src/components/gui/database-gui.tsx | 15 -- src/components/page-tracker.tsx | 92 ------------ 6 files changed, 372 deletions(-) delete mode 100644 src/app/(outerbase)/nav-profile.tsx delete mode 100644 src/app/api/events/insert-tracking-record.ts delete mode 100644 src/app/api/events/route.ts delete mode 100644 src/components/page-tracker.tsx diff --git a/src/app/(outerbase)/nav-profile.tsx b/src/app/(outerbase)/nav-profile.tsx deleted file mode 100644 index 1ef1787f..00000000 --- a/src/app/(outerbase)/nav-profile.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { Avatar } from "@/components/orbit/avatar"; -import { buttonVariants } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { cn } from "@/lib/utils"; -import { - CaretDown, - Gear, - SignOut, - ToggleLeft, - ToggleRight, -} from "@phosphor-icons/react"; -import { useTheme } from "next-themes"; -import { useRouter } from "next/navigation"; -import { useCallback } from "react"; -import { localSettingDialog } from "./local-setting-dialog"; -import { useSession } from "./session-provider"; - -export default function NavigationProfile() { - const { resolvedTheme, forcedTheme, setTheme } = useTheme(); - const { session, isLoading } = useSession(); - const router = useRouter(); - - const theme = forcedTheme ?? resolvedTheme; - - const onLogoutClicked = useCallback(() => { - router.push("/signout"); - }, [router]); - - const onThemeToggleClicked = useCallback( - (e: React.MouseEvent) => { - setTheme(theme === "dark" ? "light" : "dark"); - - // We don't want the dropdown to close - e.stopPropagation(); - e.preventDefault(); - }, - [theme, setTheme] - ); - - return ( - - -
- - {!isLoading && ( -
- {session - ? session.user.first_name + " " + session?.user.last_name - : "Guest"} -
- )} - - {isLoading && ( -
- )} -
- -
-
- - -
- - -
-
- {session - ? session.user.first_name + " " + session?.user.last_name - : "Guest"} -
- {session &&
{session.user.email}
} -
-
- -
- { - localSettingDialog.show({}).then().catch(); - }} - > - Local Setting - - - - {session && ( - { - router.push(`/account`); - }} - > - Account Setting - - - )} - - Theme - {theme === "dark" ? ( - - ) : ( - - )} - - {session && ( - - Log out - - )} - {!session && ( - { - router.push("/signin"); - }} - className="justify-between" - > - Log in - - )} -
-
- - ); -} diff --git a/src/app/(theme)/theme_layout.tsx b/src/app/(theme)/theme_layout.tsx index 5eb02b08..e2165577 100644 --- a/src/app/(theme)/theme_layout.tsx +++ b/src/app/(theme)/theme_layout.tsx @@ -1,5 +1,4 @@ "use client"; -import PageTracker from "@/components/page-tracker"; import { Toaster } from "@/components/ui/sonner"; import { TooltipProvider } from "@radix-ui/react-tooltip"; import { ThemeProvider } from "next-themes"; @@ -34,7 +33,6 @@ export default function ThemeLayout({ -