import { workspacesAtom } from '@yaakapp-internal/models'; import classNames from 'classnames'; import { useAtomValue } from 'jotai'; import * as m from 'motion/react-m'; import type { CSSProperties } from 'react'; import { useCallback, useMemo, useRef, useState } from 'react'; import { useEnsureActiveCookieJar, useSubscribeActiveCookieJarId, } from '../hooks/useActiveCookieJar'; import { activeEnvironmentAtom, useSubscribeActiveEnvironmentId, } from '../hooks/useActiveEnvironment'; import { activeFolderAtom } from '../hooks/useActiveFolder'; import { useSubscribeActiveFolderId } from '../hooks/useActiveFolderId'; import { activeRequestAtom } from '../hooks/useActiveRequest'; import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId'; import { activeWorkspaceAtom } from '../hooks/useActiveWorkspace'; import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden'; import { useHotKey } from '../hooks/useHotKey'; import { useSubscribeRecentCookieJars } from '../hooks/useRecentCookieJars'; import { useSubscribeRecentEnvironments } from '../hooks/useRecentEnvironments'; import { useSubscribeRecentRequests } from '../hooks/useRecentRequests'; import { useSubscribeRecentWorkspaces } from '../hooks/useRecentWorkspaces'; import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar'; import { useSidebarHidden } from '../hooks/useSidebarHidden'; import { useSidebarWidth } from '../hooks/useSidebarWidth'; import { useSyncWorkspaceRequestTitle } from '../hooks/useSyncWorkspaceRequestTitle'; import { duplicateRequestOrFolderAndNavigate } from '../lib/duplicateRequestOrFolderAndNavigate'; import { importData } from '../lib/importData'; import { jotaiStore } from '../lib/jotai'; import { CreateDropdown } from './CreateDropdown'; import { Banner } from './core/Banner'; import { Button } from './core/Button'; import { HotkeyList } from './core/HotkeyList'; import { FeedbackLink } from './core/Link'; import { HStack } from './core/Stacks'; import { ErrorBoundary } from './ErrorBoundary'; import { FolderLayout } from './FolderLayout'; import { GrpcConnectionLayout } from './GrpcConnectionLayout'; import { HeaderSize } from './HeaderSize'; import { HttpRequestLayout } from './HttpRequestLayout'; import { Overlay } from './Overlay'; import type { ResizeHandleEvent } from './ResizeHandle'; import { ResizeHandle } from './ResizeHandle'; import Sidebar from './Sidebar'; import { SidebarActions } from './SidebarActions'; import { WebsocketRequestLayout } from './WebsocketRequestLayout'; import { WorkspaceHeader } from './WorkspaceHeader'; const side = { gridArea: 'side' }; const head = { gridArea: 'head' }; const body = { gridArea: 'body' }; const drag = { gridArea: 'drag' }; export function Workspace() { // First, subscribe to some things applicable to workspaces useGlobalWorkspaceHooks(); const workspaces = useAtomValue(workspacesAtom); const [width, setWidth, resetWidth] = useSidebarWidth(); const [sidebarHidden, setSidebarHidden] = useSidebarHidden(); const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden(); const activeEnvironment = useAtomValue(activeEnvironmentAtom); const floating = useShouldFloatSidebar(); const [isResizing, setIsResizing] = useState(false); const startWidth = useRef(null); const handleResizeMove = useCallback( async ({ x, xStart }: ResizeHandleEvent) => { if (width == null || startWidth.current == null) return; const newWidth = startWidth.current + (x - xStart); if (newWidth < 50) { if (!sidebarHidden) await setSidebarHidden(true); resetWidth(); } else { if (sidebarHidden) await setSidebarHidden(false); setWidth(newWidth); } }, [width, sidebarHidden, setSidebarHidden, resetWidth, setWidth], ); const handleResizeStart = useCallback(() => { startWidth.current = width ?? null; setIsResizing(true); }, [width]); const handleResizeEnd = useCallback(() => { setIsResizing(false); startWidth.current = null; }, []); const sideWidth = sidebarHidden ? 0 : width; const styles = useMemo( () => ({ gridTemplate: floating ? ` ' ${head.gridArea}' auto ' ${body.gridArea}' minmax(0,1fr) / 1fr` : ` ' ${head.gridArea} ${head.gridArea} ${head.gridArea}' auto ' ${side.gridArea} ${drag.gridArea} ${body.gridArea}' minmax(0,1fr) / ${sideWidth}px 0 1fr`, }), [sideWidth, floating], ); const environmentBgStyle = useMemo(() => { if (activeEnvironment?.color == null) return undefined; const background = `linear-gradient(to right, ${activeEnvironment.color} 15%, transparent 40%)`; return { background }; }, [activeEnvironment?.color]); // We're loading still if (workspaces.length === 0) { return null; } return (
{floating ? ( setFloatingSidebarHidden(true)} > ) : ( <>
)}
); } function WorkspaceBody() { const activeRequest = useAtomValue(activeRequestAtom); const activeFolder = useAtomValue(activeFolderAtom); const activeWorkspace = useAtomValue(activeWorkspaceAtom); if (activeWorkspace == null) { return ( The active workspace was not found. Select a workspace from the header menu or report this bug to ); } if (activeRequest?.model === 'grpc_request') { return ; } if (activeRequest?.model === 'websocket_request') { return ; } if (activeRequest?.model === 'http_request') { return ; } if (activeFolder != null) { return ; } return ( } /> ); } function useGlobalWorkspaceHooks() { useEnsureActiveCookieJar(); useSubscribeActiveRequestId(); useSubscribeActiveFolderId(); useSubscribeActiveEnvironmentId(); useSubscribeActiveCookieJarId(); useSubscribeRecentRequests(); useSubscribeRecentWorkspaces(); useSubscribeRecentEnvironments(); useSubscribeRecentCookieJars(); useSyncWorkspaceRequestTitle(); useHotKey('model.duplicate', () => duplicateRequestOrFolderAndNavigate(jotaiStore.get(activeRequestAtom)), ); }