mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-06 19:35:44 +02:00
commit
70ca18a7fa
9 changed files with 67 additions and 129 deletions
|
|
@ -24,7 +24,7 @@ import { init as initAgentRunner } from "@x/core/dist/agent-schedule/runner.js";
|
||||||
import { init as initAgentNotes } from "@x/core/dist/knowledge/agent_notes.js";
|
import { init as initAgentNotes } from "@x/core/dist/knowledge/agent_notes.js";
|
||||||
import { initConfigs } from "@x/core/dist/config/initConfigs.js";
|
import { initConfigs } from "@x/core/dist/config/initConfigs.js";
|
||||||
import started from "electron-squirrel-startup";
|
import started from "electron-squirrel-startup";
|
||||||
import { execSync, exec } from "node:child_process";
|
import { execSync, exec, execFileSync } from "node:child_process";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import { init as initChromeSync } from "@x/core/dist/knowledge/chrome-extension/server/server.js";
|
import { init as initChromeSync } from "@x/core/dist/knowledge/chrome-extension/server/server.js";
|
||||||
|
|
||||||
|
|
@ -38,25 +38,30 @@ if (started) app.quit();
|
||||||
|
|
||||||
// Fix PATH for packaged Electron apps on macOS/Linux.
|
// Fix PATH for packaged Electron apps on macOS/Linux.
|
||||||
// Packaged apps inherit a minimal environment that doesn't include paths from
|
// Packaged apps inherit a minimal environment that doesn't include paths from
|
||||||
// the user's shell profile (nvm, Homebrew, etc.). Spawn the user's login shell
|
// the user's shell profile (such as those provided by nvm, Homebrew, etc.).
|
||||||
// to resolve the full PATH, using delimiters to safely extract it from any
|
// The function below spawns the user's login shell and runs a Node.js one-liner
|
||||||
// surrounding shell output (motd, greeting messages, etc.).
|
// to print the full environment as JSON, then merges it into process.env.
|
||||||
if (process.platform !== 'win32') {
|
// This ensures the Electron app has the same PATH and environment as user shell
|
||||||
|
// (helping find tools installed via Homebrew/nvm/npm, etc.)
|
||||||
|
function initializeExecutionEnvironment(): void {
|
||||||
|
if (process.platform === 'win32') return;
|
||||||
|
|
||||||
|
const shell = process.env.SHELL || '/bin/zsh';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userShell = process.env.SHELL || '/bin/zsh';
|
const stdout = execFileSync(
|
||||||
const delimiter = '__ROWBOAT_PATH__';
|
shell,
|
||||||
const output = execSync(
|
['-l', '-c', `node -p "JSON.stringify(process.env)"`],
|
||||||
`${userShell} -lc 'echo -n "${delimiter}$PATH${delimiter}"'`,
|
{ encoding: 'utf8' }
|
||||||
{ encoding: 'utf-8', timeout: 5000 },
|
).trim();
|
||||||
);
|
|
||||||
const match = output.match(new RegExp(`${delimiter}(.+?)${delimiter}`));
|
const env = JSON.parse(stdout) as Record<string, string>;
|
||||||
if (match?.[1]) {
|
process.env = { ...env, ...process.env };
|
||||||
process.env.PATH = match[1];
|
} catch (error) {
|
||||||
}
|
console.error('Failed to load shell environment', error);
|
||||||
} catch {
|
|
||||||
// Silently fall back to the existing PATH if shell resolution fails
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initializeExecutionEnvironment();
|
||||||
|
|
||||||
// Path resolution differs between development and production:
|
// Path resolution differs between development and production:
|
||||||
const preloadPath = app.isPackaged
|
const preloadPath = app.isPackaged
|
||||||
|
|
@ -107,6 +112,8 @@ function createWindow() {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 1280,
|
width: 1280,
|
||||||
height: 800,
|
height: 800,
|
||||||
|
minWidth: 600,
|
||||||
|
minHeight: 480,
|
||||||
show: false, // Don't show until ready
|
show: false, // Don't show until ready
|
||||||
backgroundColor: "#252525", // Prevent white flash (matches dark mode)
|
backgroundColor: "#252525", // Prevent white flash (matches dark mode)
|
||||||
titleBarStyle: "hiddenInset",
|
titleBarStyle: "hiddenInset",
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,8 @@ const TITLEBAR_BUTTON_PX = 32
|
||||||
const TITLEBAR_BUTTON_GAP_PX = 4
|
const TITLEBAR_BUTTON_GAP_PX = 4
|
||||||
const TITLEBAR_HEADER_GAP_PX = 8
|
const TITLEBAR_HEADER_GAP_PX = 8
|
||||||
const TITLEBAR_TOGGLE_MARGIN_LEFT_PX = 12
|
const TITLEBAR_TOGGLE_MARGIN_LEFT_PX = 12
|
||||||
const TITLEBAR_BUTTONS_COLLAPSED = 5
|
const TITLEBAR_BUTTONS_COLLAPSED = 4
|
||||||
const TITLEBAR_BUTTON_GAPS_COLLAPSED = 4
|
const TITLEBAR_BUTTON_GAPS_COLLAPSED = 3
|
||||||
const GRAPH_TAB_PATH = '__rowboat_graph_view__'
|
const GRAPH_TAB_PATH = '__rowboat_graph_view__'
|
||||||
const BASES_DEFAULT_TAB_PATH = '__rowboat_bases_default__'
|
const BASES_DEFAULT_TAB_PATH = '__rowboat_bases_default__'
|
||||||
|
|
||||||
|
|
@ -446,12 +446,8 @@ function viewStatesEqual(a: ViewState, b: ViewState): boolean {
|
||||||
return true // both graph
|
return true // both graph
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sidebar toggle + back/forward nav */
|
/** Sidebar toggle + utility buttons (fixed position, top-left) */
|
||||||
function FixedSidebarToggle({
|
function FixedSidebarToggle({
|
||||||
onNavigateBack,
|
|
||||||
onNavigateForward,
|
|
||||||
canNavigateBack,
|
|
||||||
canNavigateForward,
|
|
||||||
onNewChat,
|
onNewChat,
|
||||||
onOpenSearch,
|
onOpenSearch,
|
||||||
meetingState,
|
meetingState,
|
||||||
|
|
@ -460,10 +456,6 @@ function FixedSidebarToggle({
|
||||||
onToggleMeeting,
|
onToggleMeeting,
|
||||||
leftInsetPx,
|
leftInsetPx,
|
||||||
}: {
|
}: {
|
||||||
onNavigateBack: () => void
|
|
||||||
onNavigateForward: () => void
|
|
||||||
canNavigateBack: boolean
|
|
||||||
canNavigateForward: boolean
|
|
||||||
onNewChat: () => void
|
onNewChat: () => void
|
||||||
onOpenSearch: () => void
|
onOpenSearch: () => void
|
||||||
meetingState: MeetingTranscriptionState
|
meetingState: MeetingTranscriptionState
|
||||||
|
|
@ -472,8 +464,7 @@ function FixedSidebarToggle({
|
||||||
onToggleMeeting: () => void
|
onToggleMeeting: () => void
|
||||||
leftInsetPx: number
|
leftInsetPx: number
|
||||||
}) {
|
}) {
|
||||||
const { toggleSidebar, state } = useSidebar()
|
const { toggleSidebar } = useSidebar()
|
||||||
const isCollapsed = state === "collapsed"
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed left-0 top-0 z-50 flex h-10 items-center" style={{ WebkitAppRegion: 'no-drag' } as React.CSSProperties}>
|
<div className="fixed left-0 top-0 z-50 flex h-10 items-center" style={{ WebkitAppRegion: 'no-drag' } as React.CSSProperties}>
|
||||||
<div aria-hidden="true" className="h-10 shrink-0" style={{ width: leftInsetPx }} />
|
<div aria-hidden="true" className="h-10 shrink-0" style={{ width: leftInsetPx }} />
|
||||||
|
|
@ -536,30 +527,6 @@ function FixedSidebarToggle({
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{/* Back / Forward navigation */}
|
|
||||||
{isCollapsed && (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={onNavigateBack}
|
|
||||||
disabled={!canNavigateBack}
|
|
||||||
className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground transition-colors disabled:opacity-30 disabled:pointer-events-none"
|
|
||||||
style={{ marginLeft: TITLEBAR_BUTTON_GAP_PX }}
|
|
||||||
aria-label="Go back"
|
|
||||||
>
|
|
||||||
<ChevronLeftIcon className="size-5" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={onNavigateForward}
|
|
||||||
disabled={!canNavigateForward}
|
|
||||||
className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground transition-colors disabled:opacity-30 disabled:pointer-events-none"
|
|
||||||
aria-label="Go forward"
|
|
||||||
>
|
|
||||||
<ChevronRightIcon className="size-5" />
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -584,15 +551,14 @@ function ContentHeader({
|
||||||
const isCollapsed = state === "collapsed"
|
const isCollapsed = state === "collapsed"
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className={cn(
|
className="titlebar-drag-region flex h-10 shrink-0 items-stretch border-b border-border bg-sidebar overflow-hidden"
|
||||||
"titlebar-drag-region flex h-10 shrink-0 items-stretch border-b border-border px-3 bg-sidebar transition-[padding] duration-200 ease-linear overflow-hidden",
|
style={{
|
||||||
// When the sidebar is collapsed the content area shifts left, so we need enough left padding
|
paddingLeft: isCollapsed ? (collapsedLeftPaddingPx ?? 196) : 12,
|
||||||
// to avoid overlapping the fixed traffic-lights/toggle/back/forward controls.
|
paddingRight: 12,
|
||||||
isCollapsed && !collapsedLeftPaddingPx && "pl-[196px]"
|
transition: 'padding-left 200ms linear',
|
||||||
)}
|
}}
|
||||||
style={isCollapsed && collapsedLeftPaddingPx ? { paddingLeft: collapsedLeftPaddingPx } : undefined}
|
|
||||||
>
|
>
|
||||||
{!isCollapsed && onNavigateBack && onNavigateForward ? (
|
{onNavigateBack && onNavigateForward ? (
|
||||||
<div className="titlebar-no-drag flex items-center gap-1 pr-2 shrink-0">
|
<div className="titlebar-no-drag flex items-center gap-1 pr-2 shrink-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -4553,10 +4519,6 @@ function App() {
|
||||||
)}
|
)}
|
||||||
{/* Rendered last so its no-drag region paints over the sidebar drag region */}
|
{/* Rendered last so its no-drag region paints over the sidebar drag region */}
|
||||||
<FixedSidebarToggle
|
<FixedSidebarToggle
|
||||||
onNavigateBack={() => { void navigateBack() }}
|
|
||||||
onNavigateForward={() => { void navigateForward() }}
|
|
||||||
canNavigateBack={canNavigateBack}
|
|
||||||
canNavigateForward={canNavigateForward}
|
|
||||||
onNewChat={handleNewChatTab}
|
onNewChat={handleNewChatTab}
|
||||||
onOpenSearch={() => setIsSearchOpen(true)}
|
onOpenSearch={() => setIsSearchOpen(true)}
|
||||||
meetingState={meetingTranscription.state}
|
meetingState={meetingTranscription.state}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export function HelpPopover({ children, tooltip }: HelpPopoverProps) {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
const handleDiscordClick = () => {
|
const handleDiscordClick = () => {
|
||||||
window.open("https://discord.gg/htdKpBZF", "_blank")
|
window.open("https://discord.com/invite/wajrgmJQ6b", "_blank")
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ function formatRunTime(ts: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SyncStatusBar() {
|
function SyncStatusBar() {
|
||||||
const { state, isMobile } = useSidebar()
|
const { state } = useSidebar()
|
||||||
const [activeServices, setActiveServices] = useState<Map<string, string>>(new Map())
|
const [activeServices, setActiveServices] = useState<Map<string, string>>(new Map())
|
||||||
const [popoverOpen, setPopoverOpen] = useState(false)
|
const [popoverOpen, setPopoverOpen] = useState(false)
|
||||||
const [logEvents, setLogEvents] = useState<ServiceEventType[]>([])
|
const [logEvents, setLogEvents] = useState<ServiceEventType[]>([])
|
||||||
|
|
@ -301,7 +301,7 @@ function SyncStatusBar() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!isMobile && isCollapsed && isSyncing && (
|
{isCollapsed && isSyncing && (
|
||||||
<div
|
<div
|
||||||
className="fixed bottom-4 z-40 flex h-8 w-8 items-center justify-center rounded-full border border-border bg-background shadow-sm"
|
className="fixed bottom-4 z-40 flex h-8 w-8 items-center justify-center rounded-full border border-border bg-background shadow-sm"
|
||||||
style={{ left: "0.5rem" }}
|
style={{ left: "0.5rem" }}
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,10 @@ import { Slot } from "@radix-ui/react-slot"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
import { PanelLeftIcon } from "lucide-react"
|
import { PanelLeftIcon } from "lucide-react"
|
||||||
|
|
||||||
import { useIsMobile } from "@/hooks/use-mobile"
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import {
|
|
||||||
Sheet,
|
|
||||||
SheetContent,
|
|
||||||
SheetDescription,
|
|
||||||
SheetHeader,
|
|
||||||
SheetTitle,
|
|
||||||
} from "@/components/ui/sheet"
|
|
||||||
import { Skeleton } from "@/components/ui/skeleton"
|
import { Skeleton } from "@/components/ui/skeleton"
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
|
@ -28,17 +20,14 @@ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
|
||||||
const SIDEBAR_WIDTH = 256 // 16rem in pixels
|
const SIDEBAR_WIDTH = 256 // 16rem in pixels
|
||||||
const SIDEBAR_WIDTH_MIN = 200
|
const SIDEBAR_WIDTH_MIN = 200
|
||||||
const SIDEBAR_WIDTH_MAX = 480
|
const SIDEBAR_WIDTH_MAX = 480
|
||||||
const SIDEBAR_WIDTH_MOBILE = "18rem"
|
|
||||||
const SIDEBAR_WIDTH_ICON = "3rem"
|
const SIDEBAR_WIDTH_ICON = "3rem"
|
||||||
const SIDEBAR_OFFSET = "0px" // Default offset for nested sidebars
|
const SIDEBAR_OFFSET = "0px" // Default offset for nested sidebars
|
||||||
|
const SIDEBAR_AUTO_COLLAPSE_WIDTH = 760 // Auto-collapse when window narrower than this
|
||||||
|
|
||||||
type SidebarContextProps = {
|
type SidebarContextProps = {
|
||||||
state: "expanded" | "collapsed"
|
state: "expanded" | "collapsed"
|
||||||
open: boolean
|
open: boolean
|
||||||
setOpen: (open: boolean) => void
|
setOpen: (open: boolean) => void
|
||||||
openMobile: boolean
|
|
||||||
setOpenMobile: (open: boolean) => void
|
|
||||||
isMobile: boolean
|
|
||||||
toggleSidebar: () => void
|
toggleSidebar: () => void
|
||||||
sidebarWidth: number
|
sidebarWidth: number
|
||||||
setSidebarWidth: (width: number) => void
|
setSidebarWidth: (width: number) => void
|
||||||
|
|
@ -70,8 +59,6 @@ function SidebarProvider({
|
||||||
open?: boolean
|
open?: boolean
|
||||||
onOpenChange?: (open: boolean) => void
|
onOpenChange?: (open: boolean) => void
|
||||||
}) {
|
}) {
|
||||||
const isMobile = useIsMobile()
|
|
||||||
const [openMobile, setOpenMobile] = React.useState(false)
|
|
||||||
const [sidebarWidth, setSidebarWidth] = React.useState(SIDEBAR_WIDTH)
|
const [sidebarWidth, setSidebarWidth] = React.useState(SIDEBAR_WIDTH)
|
||||||
const [isResizing, setIsResizing] = React.useState(false)
|
const [isResizing, setIsResizing] = React.useState(false)
|
||||||
|
|
||||||
|
|
@ -94,10 +81,20 @@ function SidebarProvider({
|
||||||
[setOpenProp, open]
|
[setOpenProp, open]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Auto-collapse sidebar when window crosses below the threshold
|
||||||
|
React.useEffect(() => {
|
||||||
|
const mql = window.matchMedia(`(max-width: ${SIDEBAR_AUTO_COLLAPSE_WIDTH - 1}px)`)
|
||||||
|
const onChange = () => {
|
||||||
|
if (mql.matches) setOpen(false)
|
||||||
|
}
|
||||||
|
mql.addEventListener("change", onChange)
|
||||||
|
return () => mql.removeEventListener("change", onChange)
|
||||||
|
}, [setOpen])
|
||||||
|
|
||||||
// Helper to toggle the sidebar.
|
// Helper to toggle the sidebar.
|
||||||
const toggleSidebar = React.useCallback(() => {
|
const toggleSidebar = React.useCallback(() => {
|
||||||
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
|
return setOpen((open) => !open)
|
||||||
}, [isMobile, setOpen, setOpenMobile])
|
}, [setOpen])
|
||||||
|
|
||||||
// We add a state so that we can do data-state="expanded" or "collapsed".
|
// We add a state so that we can do data-state="expanded" or "collapsed".
|
||||||
// This makes it easier to style the sidebar with Tailwind classes.
|
// This makes it easier to style the sidebar with Tailwind classes.
|
||||||
|
|
@ -108,16 +105,13 @@ function SidebarProvider({
|
||||||
state,
|
state,
|
||||||
open,
|
open,
|
||||||
setOpen,
|
setOpen,
|
||||||
isMobile,
|
|
||||||
openMobile,
|
|
||||||
setOpenMobile,
|
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
sidebarWidth,
|
sidebarWidth,
|
||||||
setSidebarWidth,
|
setSidebarWidth,
|
||||||
isResizing,
|
isResizing,
|
||||||
setIsResizing,
|
setIsResizing,
|
||||||
}),
|
}),
|
||||||
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar, sidebarWidth, isResizing]
|
[state, open, setOpen, toggleSidebar, sidebarWidth, isResizing]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -161,7 +155,7 @@ function Sidebar({
|
||||||
variant?: "sidebar" | "floating" | "inset"
|
variant?: "sidebar" | "floating" | "inset"
|
||||||
collapsible?: "offcanvas" | "icon" | "none"
|
collapsible?: "offcanvas" | "icon" | "none"
|
||||||
}) {
|
}) {
|
||||||
const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
const { state } = useSidebar()
|
||||||
|
|
||||||
if (collapsible === "none") {
|
if (collapsible === "none") {
|
||||||
return (
|
return (
|
||||||
|
|
@ -178,34 +172,9 @@ function Sidebar({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
return (
|
|
||||||
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
|
|
||||||
<SheetContent
|
|
||||||
data-sidebar="sidebar"
|
|
||||||
data-slot="sidebar"
|
|
||||||
data-mobile="true"
|
|
||||||
className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
|
|
||||||
style={
|
|
||||||
{
|
|
||||||
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
|
|
||||||
} as React.CSSProperties
|
|
||||||
}
|
|
||||||
side={side}
|
|
||||||
>
|
|
||||||
<SheetHeader className="sr-only">
|
|
||||||
<SheetTitle>Sidebar</SheetTitle>
|
|
||||||
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
|
|
||||||
</SheetHeader>
|
|
||||||
<div className="flex h-full w-full flex-col">{children}</div>
|
|
||||||
</SheetContent>
|
|
||||||
</Sheet>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="group peer text-sidebar-foreground hidden md:block"
|
className="group peer text-sidebar-foreground block"
|
||||||
data-state={state}
|
data-state={state}
|
||||||
data-collapsible={state === "collapsed" ? collapsible : ""}
|
data-collapsible={state === "collapsed" ? collapsible : ""}
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
|
|
@ -217,7 +186,7 @@ function Sidebar({
|
||||||
data-slot="sidebar-gap"
|
data-slot="sidebar-gap"
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative w-(--sidebar-width) bg-transparent",
|
"relative w-(--sidebar-width) bg-transparent",
|
||||||
"[[data-resizing=false]_&]:transition-[width] [[data-resizing=false]_&]:duration-200 [[data-resizing=false]_&]:ease-linear",
|
"in-data-[resizing=false]:transition-[width] in-data-[resizing=false]:duration-200 in-data-[resizing=false]:ease-linear",
|
||||||
"group-data-[collapsible=offcanvas]:w-0",
|
"group-data-[collapsible=offcanvas]:w-0",
|
||||||
"group-data-[side=right]:rotate-180",
|
"group-data-[side=right]:rotate-180",
|
||||||
variant === "floating" || variant === "inset"
|
variant === "floating" || variant === "inset"
|
||||||
|
|
@ -228,10 +197,10 @@ function Sidebar({
|
||||||
<div
|
<div
|
||||||
data-slot="sidebar-container"
|
data-slot="sidebar-container"
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) md:flex",
|
"fixed inset-y-0 z-10 flex h-svh w-(--sidebar-width)",
|
||||||
"[[data-resizing=false]_&]:transition-[left,right,width] [[data-resizing=false]_&]:duration-200 [[data-resizing=false]_&]:ease-linear",
|
"in-data-[resizing=false]:transition-[left,right,width] in-data-[resizing=false]:duration-200 in-data-[resizing=false]:ease-linear",
|
||||||
side === "left"
|
side === "left"
|
||||||
? "left-[var(--sidebar-offset)] group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-offset)-var(--sidebar-width))]"
|
? "left-(--sidebar-offset) group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-offset)-var(--sidebar-width))]"
|
||||||
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
||||||
// Adjust the padding for floating and inset variants.
|
// Adjust the padding for floating and inset variants.
|
||||||
variant === "floating" || variant === "inset"
|
variant === "floating" || variant === "inset"
|
||||||
|
|
@ -347,7 +316,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
||||||
data-slot="sidebar-inset"
|
data-slot="sidebar-inset"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-background relative flex w-full flex-1 flex-col",
|
"bg-background relative flex w-full flex-1 flex-col",
|
||||||
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
|
"peer-data-[variant=inset]:m-2 peer-data-[variant=inset]:ml-0 peer-data-[variant=inset]:rounded-xl peer-data-[variant=inset]:shadow-sm peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -546,7 +515,7 @@ function SidebarMenuButton({
|
||||||
tooltip?: string | React.ComponentProps<typeof TooltipContent>
|
tooltip?: string | React.ComponentProps<typeof TooltipContent>
|
||||||
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
||||||
const Comp = asChild ? Slot : "button"
|
const Comp = asChild ? Slot : "button"
|
||||||
const { isMobile, state } = useSidebar()
|
const { state } = useSidebar()
|
||||||
|
|
||||||
const button = (
|
const button = (
|
||||||
<Comp
|
<Comp
|
||||||
|
|
@ -575,7 +544,7 @@ function SidebarMenuButton({
|
||||||
<TooltipContent
|
<TooltipContent
|
||||||
side="right"
|
side="right"
|
||||||
align="center"
|
align="center"
|
||||||
hidden={state !== "collapsed" || isMobile}
|
hidden={state !== "collapsed"}
|
||||||
{...tooltip}
|
{...tooltip}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ const API_DELAY_MS = 1000; // 1 second delay between API calls
|
||||||
const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit
|
const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit
|
||||||
const MAX_RETRIES = 3; // Maximum retries for rate-limited requests
|
const MAX_RETRIES = 3; // Maximum retries for rate-limited requests
|
||||||
const MAX_BATCH_SIZE = 10; // Process max 10 documents per folder per sync
|
const MAX_BATCH_SIZE = 10; // Process max 10 documents per folder per sync
|
||||||
const LOOKBACK_DAYS = 30; // Only sync documents from the last 30 days
|
const LOOKBACK_DAYS = 7; // Only sync documents from the last 1 week
|
||||||
|
|
||||||
// --- Wake Signal for Immediate Sync Trigger ---
|
// --- Wake Signal for Immediate Sync Trigger ---
|
||||||
let wakeResolve: (() => void) | null = null;
|
let wakeResolve: (() => void) | null = null;
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import { composioAccountsRepo } from '../composio/repo.js';
|
||||||
// Configuration
|
// Configuration
|
||||||
const SYNC_DIR = path.join(WorkDir, 'calendar_sync');
|
const SYNC_DIR = path.join(WorkDir, 'calendar_sync');
|
||||||
const SYNC_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes
|
const SYNC_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes
|
||||||
const LOOKBACK_DAYS = 14;
|
const LOOKBACK_DAYS = 7;
|
||||||
const COMPOSIO_LOOKBACK_DAYS = 14;
|
const COMPOSIO_LOOKBACK_DAYS = 7;
|
||||||
const REQUIRED_SCOPES = [
|
const REQUIRED_SCOPES = [
|
||||||
'https://www.googleapis.com/auth/calendar.events.readonly',
|
'https://www.googleapis.com/auth/calendar.events.readonly',
|
||||||
'https://www.googleapis.com/auth/drive.readonly'
|
'https://www.googleapis.com/auth/drive.readonly'
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { limitEventItems } from './limit_event_items.js';
|
||||||
const SYNC_DIR = path.join(WorkDir, 'knowledge', 'Meetings', 'fireflies');
|
const SYNC_DIR = path.join(WorkDir, 'knowledge', 'Meetings', 'fireflies');
|
||||||
const SYNC_INTERVAL_MS = 30 * 60 * 1000; // Check every 30 minutes (reduced from 1 minute)
|
const SYNC_INTERVAL_MS = 30 * 60 * 1000; // Check every 30 minutes (reduced from 1 minute)
|
||||||
const STATE_FILE = path.join(WorkDir, 'fireflies_sync_state.json');
|
const STATE_FILE = path.join(WorkDir, 'fireflies_sync_state.json');
|
||||||
const LOOKBACK_DAYS = 30; // Last 1 month
|
const LOOKBACK_DAYS = 7; // Last 1 week
|
||||||
const API_DELAY_MS = 2000; // 2 second delay between API calls
|
const API_DELAY_MS = 2000; // 2 second delay between API calls
|
||||||
const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit
|
const RATE_LIMIT_RETRY_DELAY_MS = 60 * 1000; // Wait 1 minute on rate limit
|
||||||
const MAX_RETRIES = 3; // Maximum retries for rate-limited requests
|
const MAX_RETRIES = 3; // Maximum retries for rate-limited requests
|
||||||
|
|
|
||||||
|
|
@ -410,7 +410,7 @@ async function partialSync(auth: OAuth2Client, startHistoryId: string, syncDir:
|
||||||
}
|
}
|
||||||
|
|
||||||
async function performSync() {
|
async function performSync() {
|
||||||
const LOOKBACK_DAYS = 30; // Default to 1 month
|
const LOOKBACK_DAYS = 7; // Default to 1 week
|
||||||
const ATTACHMENTS_DIR = path.join(SYNC_DIR, 'attachments');
|
const ATTACHMENTS_DIR = path.join(SYNC_DIR, 'attachments');
|
||||||
const STATE_FILE = path.join(SYNC_DIR, 'sync_state.json');
|
const STATE_FILE = path.join(SYNC_DIR, 'sync_state.json');
|
||||||
|
|
||||||
|
|
@ -444,7 +444,7 @@ async function performSync() {
|
||||||
|
|
||||||
// --- Composio-based Sync ---
|
// --- Composio-based Sync ---
|
||||||
|
|
||||||
const COMPOSIO_LOOKBACK_DAYS = 30;
|
const COMPOSIO_LOOKBACK_DAYS = 7;
|
||||||
|
|
||||||
interface ComposioSyncState {
|
interface ComposioSyncState {
|
||||||
last_sync: string; // ISO string
|
last_sync: string; // ISO string
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue