import { applySync, calculateSync } from '@yaakapp-internal/sync'; import classNames from 'classnames'; import { memo, useCallback, useMemo } from 'react'; import { useActiveWorkspace } from '../hooks/useActiveWorkspace'; import { useConfirm } from '../hooks/useConfirm'; import { useCreateWorkspace } from '../hooks/useCreateWorkspace'; import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory'; import { useDialog } from '../hooks/useDialog'; import { useOpenWorkspace } from '../hooks/useOpenWorkspace'; import { useSettings } from '../hooks/useSettings'; import { useToast } from '../hooks/useToast'; import { useWorkspaces } from '../hooks/useWorkspaces'; import { fallbackRequestName } from '../lib/fallbackRequestName'; import { pluralizeCount } from '../lib/pluralize'; import { getWorkspace } from '../lib/store'; import type { ButtonProps } from './core/Button'; import { Button } from './core/Button'; import type { DropdownItem } from './core/Dropdown'; import { Icon } from './core/Icon'; import { InlineCode } from './core/InlineCode'; import type { RadioDropdownItem } from './core/RadioDropdown'; import { RadioDropdown } from './core/RadioDropdown'; import { VStack } from './core/Stacks'; import { OpenWorkspaceDialog } from './OpenWorkspaceDialog'; import { WorkspaceSettingsDialog } from './WorkspaceSettingsDialog'; type Props = Pick; export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({ className, ...buttonProps }: Props) { const workspaces = useWorkspaces(); const activeWorkspace = useActiveWorkspace(); const createWorkspace = useCreateWorkspace(); const { mutate: deleteSendHistory } = useDeleteSendHistory(); const dialog = useDialog(); const confirm = useConfirm(); const toast = useToast(); const settings = useSettings(); const openWorkspace = useOpenWorkspace(); const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null; const orderedWorkspaces = useMemo( () => [...workspaces].sort((a, b) => (a.name.localeCompare(b.name) > 0 ? 1 : -1)), [workspaces], ); const { workspaceItems, extraItems } = useMemo<{ workspaceItems: RadioDropdownItem[]; extraItems: DropdownItem[]; }>(() => { const workspaceItems: RadioDropdownItem[] = orderedWorkspaces.map((w) => ({ key: w.id, label: w.name, value: w.id, leftSlot: w.id === activeWorkspace?.id ? : , })); const extraItems: DropdownItem[] = [ { key: 'workspace-settings', label: 'Workspace Settings', leftSlot: , hotKeyAction: 'workspace_settings.show', onSelect: async () => { dialog.show({ id: 'workspace-settings', title: 'Workspace Settings', size: 'md', render: ({ hide }) => ( ), }); }, }, { key: 'sync', label: 'Sync Workspace', leftSlot: , hidden: !activeWorkspace?.settingSyncDir, onSelect: async () => { if (activeWorkspace == null) return; const ops = await calculateSync(activeWorkspace); if (ops.length === 0) { toast.show({ id: 'no-sync-changes', message: 'No changes to sync', }); return; } const dbChanges = ops.filter((o) => o.type.startsWith('db')); if (dbChanges.length === 0) { await applySync(activeWorkspace, ops); toast.show({ id: 'applied-sync-changes', message: `Wrote ${pluralizeCount('change', ops.length)}`, }); return; } const confirmed = await confirm({ id: 'commit-sync', title: 'Filesystem Changes Detected', confirmText: 'Apply Changes', description: (

Some files in the directory have changed. Do you want to apply the updates to your workspace?

{dbChanges.map((op, i) => { let name = ''; let label = ''; let color = ''; if (op.type === 'dbCreate') { label = 'create'; name = fallbackRequestName(op.fs.model); color = 'text-success'; } else if (op.type === 'dbUpdate') { label = 'update'; name = fallbackRequestName(op.fs.model); color = 'text-info'; } else if (op.type === 'dbDelete') { label = 'delete'; name = fallbackRequestName(op.model); color = 'text-danger'; } else { return null; } return ( ); })}
Name Operation
{name} {label}
), }); if (confirmed) { await applySync(activeWorkspace, ops); toast.show({ id: 'applied-confirmed-sync-changes', message: `Wrote ${pluralizeCount('change', ops.length)}`, }); } }, }, { key: 'delete-responses', label: 'Clear Send History', leftSlot: , onSelect: deleteSendHistory, }, { type: 'separator' }, { key: 'create-workspace', label: 'New Workspace', leftSlot: , onSelect: createWorkspace, }, ]; return { workspaceItems, extraItems }; }, [ orderedWorkspaces, activeWorkspace, deleteSendHistory, createWorkspace, dialog, confirm, toast, ]); const handleChange = useCallback( async (workspaceId: string | null) => { if (workspaceId == null) return; if (typeof openWorkspaceNewWindow === 'boolean') { openWorkspace.mutate({ workspaceId, inNewWindow: openWorkspaceNewWindow }); return; } const workspace = await getWorkspace(workspaceId); if (workspace == null) return; dialog.show({ id: 'open-workspace', size: 'sm', title: 'Open Workspace', render: ({ hide }) => , }); }, [dialog, openWorkspace, openWorkspaceNewWindow], ); return ( ); });