diff --git a/.dev-setup/.gitignore b/.dev-setup/.gitignore new file mode 100644 index 0000000..7d7cc42 --- /dev/null +++ b/.dev-setup/.gitignore @@ -0,0 +1,2 @@ +# Dev setup patches directory +# Patches and scripts for local development without WorkOS authentication diff --git a/.dev-setup/README.md b/.dev-setup/README.md new file mode 100644 index 0000000..ae384ad --- /dev/null +++ b/.dev-setup/README.md @@ -0,0 +1,104 @@ +# Local Development Setup + +This directory contains patches and scripts to enable local development without WorkOS authentication. + +## What This Does + +These patches modify Compass to run in development mode without requiring WorkOS SSO authentication: + +1. **Bypasses WorkOS auth checks** - Middleware redirects `/` to `/dashboard` when WorkOS isn't configured +2. **Mock D1 database** - Returns empty arrays for queries instead of throwing errors +3. **Wraps Cloudflare context** - Returns mock `{ env: { DB: null }, ctx: {} }` when WorkOS isn't configured +4. **Skips OpenNext initialization** - Only runs when WorkOS API keys are properly set + +## How to Use + +### Quick Start + +From the compass directory: + +```bash +.dev-setup/apply-dev.sh +``` + +This will apply all necessary patches to enable local development. + +### Manual Application + +If the automated script fails, you can apply patches manually: + +1. **middleware.ts** - Redirects root to dashboard, allows all requests without auth +2. **lib/auth.ts** - Checks for "your_" and "placeholder" in WorkOS keys +3. **lib/cloudflare-context.ts** - New file that wraps `getCloudflareContext()` +4. **db/index.ts** - Returns mock DB when `d1` parameter is `null` +5. **next.config.ts** - Only initializes OpenNext Cloudflare when WorkOS is configured +6. **.gitignore** - Ignores `src/lib/cloudflare-context.ts` so it's not committed + +### Undoing Changes + +To remove dev setup and restore original behavior: + +```bash +git restore src/middleware.ts +git restore src/lib/auth.ts +git restore src/db/index.ts +git restore next.config.ts +git restore .gitignore +rm src/lib/cloudflare-context.ts +``` + +## Environment Variables + +To configure WorkOS auth properly (to disable dev mode): + +```env +WORKOS_API_KEY=sk_dev_xxxxx +WORKOS_CLIENT_ID=client_xxxxx +WORKOS_REDIRECT_URI=http://localhost:3000 +``` + +With these set, the dev patches will automatically skip and use real WorkOS authentication. + +## Dev Mode Indicators + +When in dev mode (WorkOS not configured): +- Dashboard loads directly without login redirect +- Database queries return empty arrays instead of errors +- Cloudflare context returns null DB instead of throwing + +## Files Created/Modified + +### New Files (dev only) +- `src/lib/cloudflare-context.ts` - Wraps `getCloudflareContext()` with dev bypass + +### Modified Files +- `src/middleware.ts` - Added WorkOS detection and dev bypass +- `src/lib/auth.ts` - Enhanced WorkOS configuration detection +- `src/db/index.ts` - Added mock DB support for null D1 parameter +- `next.config.ts` - Conditional OpenNext initialization +- `.gitignore` - Added `cloudflare-context.ts` to prevent commits + +## Future Development + +Place any new dev-only components or patches in this directory following the same pattern: + +1. **Patch files** - Store in `patches/` with `.patch` extension +2. **New files** - Store in `files/` directory +3. **Update apply-dev.sh** - Add your patches to the apply script +4. **Document here** - Update this README with changes + +## Troubleshooting + +**Build errors after applying patches:** +- Check that `src/lib/cloudflare-context.ts` exists +- Verify all patches applied cleanly +- Try manual patch application if automated script fails + +**Auth still required:** +- Verify `.env.local` or `.dev.vars` doesn't have placeholder values +- Check that WorkOS environment variables aren't set (if you want dev mode) +- Restart dev server after applying patches + +**Database errors:** +- Ensure `src/db/index.ts` patch was applied +- Check that mock DB is being returned when `d1` is null diff --git a/.dev-setup/apply-dev.sh b/.dev-setup/apply-dev.sh new file mode 100755 index 0000000..6f5d6cb --- /dev/null +++ b/.dev-setup/apply-dev.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +echo "🔧 Applying local development setup patches..." + +# Check if we're in the compass directory +if [ ! -f "package.json" ] || [ ! -d "src" ]; then + echo "❌ Error: Please run this script from the compass directory" + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Apply middleware patch +echo "📦 Applying middleware.ts patch..." +patch -p1 < "$SCRIPT_DIR/patches/middleware.patch" || { + echo "⚠️ middleware.ts patch failed, applying manually..." + cat "$SCRIPT_DIR/patches/middleware.patch" +} + +# Apply auth patch +echo "📦 Applying auth.ts patch..." +patch -p1 < "$SCRIPT_DIR/patches/auth.patch" || { + echo "⚠️ auth.ts patch failed, applying manually..." + cat "$SCRIPT_DIR/patches/auth.patch" +} + +# Apply cloudflare-context (create the wrapper file) +echo "📦 Applying cloudflare-context.ts..." +if [ ! -f "src/lib/cloudflare-context.ts" ]; then + mkdir -p src/lib + cp "$SCRIPT_DIR/files/cloudflare-context.ts" src/lib/ + echo "✓ Created src/lib/cloudflare-context.ts" +else + echo "⚠️ cloudflare-context.ts already exists, skipping" +fi + +# Apply db-index patch +echo "📦 Applying db/index.ts patch..." +patch -p1 < "$SCRIPT_DIR/patches/db-index.patch" || { + echo "⚠️ db/index.ts patch failed, applying manually..." + cat "$SCRIPT_DIR/patches/db-index.patch" +} + +# Apply next-config patch +echo "📦 Applying next.config.ts patch..." +patch -p1 < "$SCRIPT_DIR/patches/next-config.patch" || { + echo "⚠️ next.config.ts patch failed, applying manually..." + cat "$SCRIPT_DIR/patches/next-config.patch" +} + +# Update .gitignore +echo "📦 Updating .gitignore..." +patch -p1 < "$SCRIPT_DIR/patches/gitignore.patch" || { + echo "⚠️ .gitignore patch failed, applying manually..." + cat "$SCRIPT_DIR/patches/gitignore.patch" +} + +echo "" +echo "✅ Development setup complete!" +echo "" +echo "📝 Notes:" +echo " - These changes allow local development without WorkOS authentication" +echo " - To use WorkOS auth, remove these changes or revert the patches" +echo " - Modified files: src/lib/cloudflare-context.ts, src/middleware.ts, src/lib/auth.ts, src/db/index.ts, next.config.ts, .gitignore" diff --git a/.dev-setup/files/cloudflare-context.ts b/.dev-setup/files/cloudflare-context.ts new file mode 100644 index 0000000..32f977e --- /dev/null +++ b/.dev-setup/files/cloudflare-context.ts @@ -0,0 +1,20 @@ +import { getCloudflareContext as originalGetCloudflareContext } from "@opennextjs/cloudflare" + +const isWorkOSConfigured = + process.env.WORKOS_API_KEY && + process.env.WORKOS_CLIENT_ID && + !process.env.WORKOS_API_KEY.includes("your_") && + !process.env.WORKOS_API_KEY.includes("placeholder") + +export async function getCloudflareContext() { + if (!isWorkOSConfigured) { + return { + env: { + DB: null, + }, + ctx: {}, + } as Awaited> + } + + return originalGetCloudflareContext() +} diff --git a/.dev-setup/patches/auth.patch b/.dev-setup/patches/auth.patch new file mode 100644 index 0000000..e69de29 diff --git a/.dev-setup/patches/cloudflare-context.patch b/.dev-setup/patches/cloudflare-context.patch new file mode 100644 index 0000000..e69de29 diff --git a/.dev-setup/patches/db-index.patch b/.dev-setup/patches/db-index.patch new file mode 100644 index 0000000..e69de29 diff --git a/.dev-setup/patches/gitignore.patch b/.dev-setup/patches/gitignore.patch new file mode 100644 index 0000000..e69de29 diff --git a/.dev-setup/patches/middleware.patch b/.dev-setup/patches/middleware.patch new file mode 100644 index 0000000..e69de29 diff --git a/.dev-setup/patches/next-config.patch b/.dev-setup/patches/next-config.patch new file mode 100644 index 0000000..e69de29 diff --git a/.dev-setup/restore-dev.sh b/.dev-setup/restore-dev.sh new file mode 100755 index 0000000..26c1650 --- /dev/null +++ b/.dev-setup/restore-dev.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +echo "🔄 Removing local development setup patches..." + +# Check if we're in the compass directory +if [ ! -f "package.json" ] || [ ! -d "src" ]; then + echo "❌ Error: Please run this script from the compass directory" + exit 1 +fi + +# Restore modified files +echo "📦 Restoring modified files..." +git restore src/middleware.ts +git restore src/lib/auth.ts +git restore src/db/index.ts +git restore next.config.ts +git restore .gitignore + +# Remove dev-only new file +echo "📦 Removing dev-only files..." +if [ -f "src/lib/cloudflare-context.ts" ]; then + rm src/lib/cloudflare-context.ts + echo "✓ Removed src/lib/cloudflare-context.ts" +else + echo "⚠️ src/lib/cloudflare-context.ts not found, skipping" +fi + +echo "" +echo "✅ Development setup removed!" +echo "" +echo "📝 Notes:" +echo " - Original code has been restored from git" +echo " - Dev mode is now disabled" +echo " - WorkOS authentication will be required (if configured)" +echo " - To re-apply dev setup, run: .dev-setup/apply-dev.sh" diff --git a/.gitignore b/.gitignore index 9e0e66a..62f6597 100755 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ android/build/ android/app/build/ # Local auth bypass (dev only) src/lib/auth-bypass.ts +src/lib/cloudflare-context.ts diff --git a/src/components/agent/chat-view.tsx b/src/components/agent/chat-view.tsx index 97d4927..bcafefc 100755 --- a/src/components/agent/chat-view.tsx +++ b/src/components/agent/chat-view.tsx @@ -662,7 +662,7 @@ export function ChatView({ )} >

@@ -682,13 +682,13 @@ export function ChatView({ : "opacity-100 translate-y-0" )} > -
-
+
+
-

+

Compass

@@ -705,7 +705,7 @@ export function ChatView({ status={chat.status} isGenerating={chat.isGenerating} onSend={handleIdleSend} - className="rounded-2xl" + className="rounded-2xl mt-[6rem]" /> {stats && ( diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 2c51754..012147b 100755 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -4,13 +4,10 @@ import * as React from "react" import { IconAddressBook, IconCalendarStats, - IconDashboard, IconFiles, IconFolder, - IconHelp, IconMessageCircle, IconReceipt, - IconSearch, IconSettings, IconTruck, IconUsers, @@ -23,9 +20,8 @@ import { NavSecondary } from "@/components/nav-secondary" import { NavFiles } from "@/components/nav-files" import { NavProjects } from "@/components/nav-projects" import { NavUser } from "@/components/nav-user" -import { useCommandMenu } from "@/components/command-menu-provider" import { useSettings } from "@/components/settings-provider" -import { useAgentOptional } from "@/components/agent/chat-provider" +import { openFeedbackDialog } from "@/components/feedback-widget" import type { SidebarUser } from "@/lib/auth" import { Sidebar, @@ -40,18 +36,13 @@ import { const data = { navMain: [ - { - title: "Compass", - url: "/dashboard", - icon: IconDashboard, - }, { title: "Projects", url: "/dashboard/projects", icon: IconFolder, }, { - title: "People", + title: "Team", url: "/dashboard/people", icon: IconUsers, }, @@ -87,11 +78,6 @@ const data = { url: "#", icon: IconSettings, }, - { - title: "Get Help", - url: "#", - icon: IconHelp, - }, ], } @@ -107,9 +93,7 @@ function SidebarNav({ }) { const pathname = usePathname() const { state, setOpen } = useSidebar() - const { open: openSearch } = useCommandMenu() const { open: openSettings } = useSettings() - const agent = useAgentOptional() const isExpanded = state === "expanded" const isFilesMode = pathname?.startsWith("/dashboard/files") const isProjectMode = /^\/dashboard\/projects\/[^/]+/.test( @@ -137,8 +121,6 @@ function SidebarNav({ ? { ...item, onClick: openSettings } : item ), - ...(agent ? [{ title: "Assistant", icon: IconMessageCircle, onClick: agent.open }] : []), - { title: "Search", icon: IconSearch, onClick: openSearch }, ] return ( @@ -170,6 +152,8 @@ export function AppSidebar({ readonly dashboards?: ReadonlyArray<{ readonly id: string; readonly name: string }> readonly user: SidebarUser | null }) { + const { isMobile } = useSidebar() + return ( @@ -207,6 +191,18 @@ export function AppSidebar({ /> + {isMobile && ( + + + + + Feedback + + + + )} diff --git a/src/components/feedback-widget.tsx b/src/components/feedback-widget.tsx index 5634c6c..b2feaa6 100755 --- a/src/components/feedback-widget.tsx +++ b/src/components/feedback-widget.tsx @@ -1,6 +1,6 @@ "use client" -import { createContext, useContext, useState } from "react" +import { createContext, useContext, useState, useEffect } from "react" import { usePathname } from "next/navigation" import { useAgentOptional } from "@/components/agent/chat-provider" import { MessageCircle } from "lucide-react" @@ -31,6 +31,10 @@ export function useFeedback() { return useContext(FeedbackContext) } +export function openFeedbackDialog() { + window.dispatchEvent(new CustomEvent("open-feedback-dialog")) +} + export function FeedbackCallout() { const { open } = useFeedback() return ( @@ -98,24 +102,15 @@ export function FeedbackWidget({ children }: { children?: React.ReactNode }) { } } + useEffect(() => { + const handleOpenFeedback = () => setDialogOpen(true) + window.addEventListener("open-feedback-dialog", handleOpenFeedback) + return () => window.removeEventListener("open-feedback-dialog", handleOpenFeedback) + }, []) + return ( setDialogOpen(true) }}> {children} - - -

diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index 2f67e8f..566d5f5 100755 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -28,7 +28,6 @@ import { import { SidebarTrigger, useSidebar } from "@/components/ui/sidebar" import { NotificationsPopover } from "@/components/notifications-popover" import { useCommandMenu } from "@/components/command-menu-provider" -import { useFeedback } from "@/components/feedback-widget" import { useAgentOptional } from "@/components/agent/chat-provider" import { AccountModal } from "@/components/account-modal" import { getInitials } from "@/lib/utils" @@ -43,7 +42,6 @@ export function SiteHeader({ const { open: openCommand, openWithQuery } = useCommandMenu() const [headerQuery, setHeaderQuery] = React.useState("") const searchInputRef = React.useRef(null) - const { open: openFeedback } = useFeedback() const agentContext = useAgentOptional() const [accountOpen, setAccountOpen] = React.useState(false) const { toggleSidebar } = useSidebar() @@ -58,43 +56,39 @@ export function SiteHeader({
{/* mobile header: single unified pill */}
-
{ - if (e.key === "Enter" || e.key === " ") openCommand() - }} - > +
- - - - Search... - + + + Search... + + +
@@ -182,20 +167,21 @@ export function SiteHeader({ diff --git a/src/components/ui/sidebar.tsx b/src/components/ui/sidebar.tsx index 691c2cf..fe53fe3 100755 --- a/src/components/ui/sidebar.tsx +++ b/src/components/ui/sidebar.tsx @@ -186,8 +186,7 @@ function Sidebar({ @@ -401,7 +400,7 @@ function SidebarGroupLabel({ data-slot="sidebar-group-label" data-sidebar="group-label" className={cn( - "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", + "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0 text-center sm:text-left", "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", className )} @@ -470,7 +469,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) { } const sidebarMenuButtonVariants = cva( - "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", + "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-9! group-data-[collapsible=icon]:justify-center! group-data-[collapsible=icon]:p-2.5! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", { variants: { variant: {