mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-15 05:33:29 +01:00
- Move active tab persistence into Tabs component with storageKey + activeTabKey props - Change value prop to defaultValue so callers don't manage tab state - Add TabsRef with setActiveTab method for programmatic tab switching - Restore request_pane.focus_tab listener for :param placeholder clicks - Update all Tab consumers to use new pattern Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
143 lines
4.8 KiB
TypeScript
143 lines
4.8 KiB
TypeScript
import { createWorkspaceModel, foldersAtom, patchModel } from '@yaakapp-internal/models';
|
|
import { useAtomValue } from 'jotai';
|
|
import { useMemo } from 'react';
|
|
import { useAuthTab } from '../hooks/useAuthTab';
|
|
import { useEnvironmentsBreakdown } from '../hooks/useEnvironmentsBreakdown';
|
|
import { useHeadersTab } from '../hooks/useHeadersTab';
|
|
import { useInheritedHeaders } from '../hooks/useInheritedHeaders';
|
|
import { Button } from './core/Button';
|
|
import { CountBadge } from './core/CountBadge';
|
|
import { Input } from './core/Input';
|
|
import { Link } from './core/Link';
|
|
import { VStack } from './core/Stacks';
|
|
import type { TabItem } from './core/Tabs/Tabs';
|
|
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
|
import { EmptyStateText } from './EmptyStateText';
|
|
import { EnvironmentEditor } from './EnvironmentEditor';
|
|
import { HeadersEditor } from './HeadersEditor';
|
|
import { HttpAuthenticationEditor } from './HttpAuthenticationEditor';
|
|
import { MarkdownEditor } from './MarkdownEditor';
|
|
|
|
interface Props {
|
|
folderId: string | null;
|
|
tab?: FolderSettingsTab;
|
|
}
|
|
|
|
const TAB_AUTH = 'auth';
|
|
const TAB_HEADERS = 'headers';
|
|
const TAB_VARIABLES = 'variables';
|
|
const TAB_GENERAL = 'general';
|
|
|
|
export type FolderSettingsTab =
|
|
| typeof TAB_AUTH
|
|
| typeof TAB_HEADERS
|
|
| typeof TAB_GENERAL
|
|
| typeof TAB_VARIABLES;
|
|
|
|
export function FolderSettingsDialog({ folderId, tab }: Props) {
|
|
const folders = useAtomValue(foldersAtom);
|
|
const folder = folders.find((f) => f.id === folderId) ?? null;
|
|
const authTab = useAuthTab(TAB_AUTH, folder);
|
|
const headersTab = useHeadersTab(TAB_HEADERS, folder);
|
|
const inheritedHeaders = useInheritedHeaders(folder);
|
|
const environments = useEnvironmentsBreakdown();
|
|
const folderEnvironment = environments.allEnvironments.find(
|
|
(e) => e.parentModel === 'folder' && e.parentId === folderId,
|
|
);
|
|
const numVars = (folderEnvironment?.variables ?? []).filter((v) => v.name).length;
|
|
|
|
const tabs = useMemo<TabItem[]>(() => {
|
|
if (folder == null) return [];
|
|
|
|
return [
|
|
{
|
|
value: TAB_GENERAL,
|
|
label: 'General',
|
|
},
|
|
...headersTab,
|
|
...authTab,
|
|
{
|
|
value: TAB_VARIABLES,
|
|
label: 'Variables',
|
|
rightSlot: numVars > 0 ? <CountBadge count={numVars} /> : null,
|
|
},
|
|
];
|
|
}, [authTab, folder, headersTab, numVars]);
|
|
|
|
if (folder == null) return null;
|
|
|
|
return (
|
|
<Tabs
|
|
defaultValue={tab ?? TAB_GENERAL}
|
|
label="Folder Settings"
|
|
className="pt-2 pb-2 pl-3 pr-1"
|
|
layout="horizontal"
|
|
addBorders
|
|
tabs={tabs}
|
|
>
|
|
<TabContent value={TAB_AUTH} className="overflow-y-auto h-full px-4">
|
|
<HttpAuthenticationEditor model={folder} />
|
|
</TabContent>
|
|
<TabContent value={TAB_GENERAL} className="overflow-y-auto h-full px-4">
|
|
<VStack space={3} className="pb-3 h-full">
|
|
<Input
|
|
label="Folder Name"
|
|
defaultValue={folder.name}
|
|
onChange={(name) => patchModel(folder, { name })}
|
|
stateKey={`name.${folder.id}`}
|
|
/>
|
|
<MarkdownEditor
|
|
name="folder-description"
|
|
placeholder="Folder description"
|
|
className="border border-border px-2"
|
|
defaultValue={folder.description}
|
|
stateKey={`description.${folder.id}`}
|
|
onChange={(description) => patchModel(folder, { description })}
|
|
/>
|
|
</VStack>
|
|
</TabContent>
|
|
<TabContent value={TAB_HEADERS} className="overflow-y-auto h-full px-4">
|
|
<HeadersEditor
|
|
inheritedHeaders={inheritedHeaders}
|
|
forceUpdateKey={folder.id}
|
|
headers={folder.headers}
|
|
onChange={(headers) => patchModel(folder, { headers })}
|
|
stateKey={`headers.${folder.id}`}
|
|
/>
|
|
</TabContent>
|
|
<TabContent value={TAB_VARIABLES} className="overflow-y-auto h-full px-4">
|
|
{folderEnvironment == null ? (
|
|
<EmptyStateText>
|
|
<VStack alignItems="center" space={1.5}>
|
|
<p>
|
|
Override{' '}
|
|
<Link href="https://yaak.app/docs/using-yaak/environments-and-variables">
|
|
Variables
|
|
</Link>{' '}
|
|
for requests within this folder.
|
|
</p>
|
|
<Button
|
|
variant="border"
|
|
size="sm"
|
|
onClick={async () => {
|
|
await createWorkspaceModel({
|
|
workspaceId: folder.workspaceId,
|
|
parentModel: 'folder',
|
|
parentId: folder.id,
|
|
model: 'environment',
|
|
name: 'Folder Environment',
|
|
});
|
|
}}
|
|
>
|
|
Create Folder Environment
|
|
</Button>
|
|
</VStack>
|
|
</EmptyStateText>
|
|
) : (
|
|
<EnvironmentEditor hideName environment={folderEnvironment} />
|
|
)}
|
|
</TabContent>
|
|
</Tabs>
|
|
);
|
|
}
|