import { workspacesAtom } from '@yaakapp-internal/models'; import classNames from 'classnames'; import { useAtomValue } from 'jotai'; import * as m from 'motion/react-m'; import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react'; import { useCallback, useMemo, useRef, useState } from 'react'; import { useEnsureActiveCookieJar, useSubscribeActiveCookieJarId, } from '../hooks/useActiveCookieJar'; import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment'; 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 { useImportData } from '../hooks/useImportData'; 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 { useToggleCommandPalette } from '../hooks/useToggleCommandPalette'; import { duplicateRequestAndNavigate } from '../lib/duplicateRequestAndNavigate'; import { jotaiStore } from '../lib/jotai'; 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 { CreateDropdown } from './CreateDropdown'; import { GrpcConnectionLayout } from './GrpcConnectionLayout'; import { HeaderSize } from './HeaderSize'; import { HttpRequestLayout } from './HttpRequestLayout'; import { Overlay } from './Overlay'; import { ResizeHandle } from './ResizeHandle'; import { Sidebar } from './sidebar/Sidebar'; import { SidebarActions } from './sidebar/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 { setWidth, width, resetWidth } = useSidebarWidth(); const [sidebarHidden, setSidebarHidden] = useSidebarHidden(); const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden(); const floating = useShouldFloatSidebar(); const [isResizing, setIsResizing] = useState(false); const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>( null, ); const unsub = () => { if (moveState.current !== null) { document.documentElement.removeEventListener('mousemove', moveState.current.move); document.documentElement.removeEventListener('mouseup', moveState.current.up); } }; const handleResizeStart = useCallback( (e: ReactMouseEvent) => { if (width === undefined) return; unsub(); const mouseStartX = e.clientX; const startWidth = width; moveState.current = { move: async (e: MouseEvent) => { e.preventDefault(); // Prevent text selection and things const newWidth = startWidth + (e.clientX - mouseStartX); if (newWidth < 50) { await setSidebarHidden(true); resetWidth(); } else { await setSidebarHidden(false); setWidth(newWidth); } }, up: (e: MouseEvent) => { e.preventDefault(); unsub(); setIsResizing(false); }, }; document.documentElement.addEventListener('mousemove', moveState.current.move); document.documentElement.addEventListener('mouseup', moveState.current.up); setIsResizing(true); }, [width, setSidebarHidden, resetWidth, setWidth], ); 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], ); // We're loading still if (workspaces.length === 0) { return null; } return (
{floating ? ( setFloatingSidebarHidden(true)} > ) : ( <>
)}
); } function WorkspaceBody() { const activeRequest = useAtomValue(activeRequestAtom); const activeWorkspace = useAtomValue(activeWorkspaceAtom); const importData = useImportData(); if (activeWorkspace == null) { return (
The active workspace was not found. Select a workspace from the header menu or report this bug to
); } if (activeRequest == null) { return ( } /> ); } if (activeRequest.model === 'grpc_request') { return ; } else if (activeRequest.model === 'websocket_request') { return ; } else { return ; } } function useGlobalWorkspaceHooks() { useEnsureActiveCookieJar(); useSubscribeActiveRequestId(); useSubscribeActiveEnvironmentId(); useSubscribeActiveCookieJarId(); useSubscribeRecentRequests(); useSubscribeRecentWorkspaces(); useSubscribeRecentEnvironments(); useSubscribeRecentCookieJars(); useSyncWorkspaceRequestTitle(); const toggleCommandPalette = useToggleCommandPalette(); useHotKey('command_palette.toggle', toggleCommandPalette); useHotKey('http_request.duplicate', () => duplicateRequestAndNavigate(jotaiStore.get(activeRequestAtom)), ); }