mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-11 20:00:29 +01:00
Add back creation items to context menu
This commit is contained in:
@@ -25,8 +25,9 @@ import { activeCookieJarAtom } from '../hooks/useActiveCookieJar';
|
||||
import { activeEnvironmentAtom } from '../hooks/useActiveEnvironment';
|
||||
import { activeFolderIdAtom } from '../hooks/useActiveFolderId';
|
||||
import { activeRequestIdAtom } from '../hooks/useActiveRequestId';
|
||||
import { activeWorkspaceAtom } from '../hooks/useActiveWorkspace';
|
||||
import { activeWorkspaceAtom, activeWorkspaceIdAtom } from '../hooks/useActiveWorkspace';
|
||||
import { allRequestsAtom } from '../hooks/useAllRequests';
|
||||
import { getCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
||||
import { getGrpcRequestActions } from '../hooks/useGrpcRequestActions';
|
||||
import { useHotKey } from '../hooks/useHotKey';
|
||||
import { getHttpRequestActions } from '../hooks/useHttpRequestActions';
|
||||
@@ -52,80 +53,9 @@ import { Tree } from './core/tree/Tree';
|
||||
import type { TreeItemProps } from './core/tree/TreeItem';
|
||||
import { GitDropdown } from './GitDropdown';
|
||||
|
||||
type Model = Workspace | Folder | HttpRequest | GrpcRequest | WebsocketRequest;
|
||||
type SidebarModel = Workspace | Folder | HttpRequest | GrpcRequest | WebsocketRequest;
|
||||
|
||||
const opacitySubtle = 'opacity-80';
|
||||
|
||||
function getItemKey(item: Model) {
|
||||
const responses = jotaiStore.get(httpResponsesAtom);
|
||||
const latestResponse = responses.find((r) => r.requestId === item.id) ?? null;
|
||||
const url = 'url' in item ? item.url : 'n/a';
|
||||
const method = 'method' in item ? item.method : 'n/a';
|
||||
return [
|
||||
item.id,
|
||||
item.name,
|
||||
url,
|
||||
method,
|
||||
latestResponse?.elapsed,
|
||||
latestResponse?.id ?? 'n/a',
|
||||
].join('::');
|
||||
}
|
||||
|
||||
const SidebarLeftSlot = memo(function SidebarLeftSlot({
|
||||
treeId,
|
||||
item,
|
||||
}: {
|
||||
treeId: string;
|
||||
item: Model;
|
||||
}) {
|
||||
if (item.model === 'folder') {
|
||||
return <Icon icon="folder" />;
|
||||
} else if (item.model === 'workspace') {
|
||||
return null;
|
||||
} else {
|
||||
const isSelected = jotaiStore.get(isSelectedFamily({ treeId, itemId: item.id }));
|
||||
return (
|
||||
<HttpMethodTag
|
||||
short
|
||||
className={classNames('text-xs', !isSelected && opacitySubtle)}
|
||||
request={item}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const SidebarInnerItem = memo(function SidebarInnerItem({ item }: { treeId: string; item: Model }) {
|
||||
const response = useAtomValue(
|
||||
useMemo(
|
||||
() =>
|
||||
selectAtom(
|
||||
atom((get) => [
|
||||
...get(grpcConnectionsAtom),
|
||||
...get(httpResponsesAtom),
|
||||
...get(websocketConnectionsAtom),
|
||||
]),
|
||||
(responses) => responses.find((r) => r.requestId === item.id),
|
||||
(a, b) => a?.state === b?.state && a?.id === b?.id, // Only update when the response state changes updated
|
||||
),
|
||||
[item.id],
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 min-w-0 h-full w-full text-left">
|
||||
<div className="truncate">{resolvedModelName(item)}</div>
|
||||
{response != null && (
|
||||
<div className="ml-auto">
|
||||
{response.state !== 'closed' ? (
|
||||
<LoadingIcon size="sm" className="text-text-subtlest" />
|
||||
) : response.model === 'http_response' ? (
|
||||
<HttpStatusTag short className="text-xs" response={response} />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
const OPACITY_SUBTLE = 'opacity-80';
|
||||
|
||||
function NewSidebar({ className }: { className?: string }) {
|
||||
const [hidden, setHidden] = useSidebarHidden();
|
||||
@@ -161,13 +91,13 @@ function NewSidebar({ className }: { className?: string }) {
|
||||
children,
|
||||
insertAt,
|
||||
}: {
|
||||
items: Model[];
|
||||
parent: Model;
|
||||
children: Model[];
|
||||
items: SidebarModel[];
|
||||
parent: SidebarModel;
|
||||
children: SidebarModel[];
|
||||
insertAt: number;
|
||||
}) {
|
||||
const prev = children[insertAt - 1] as Exclude<Model, Workspace>;
|
||||
const next = children[insertAt] as Exclude<Model, Workspace>;
|
||||
const prev = children[insertAt - 1] as Exclude<SidebarModel, Workspace>;
|
||||
const next = children[insertAt] as Exclude<SidebarModel, Workspace>;
|
||||
const folderId = parent.model === 'folder' ? parent.id : null;
|
||||
|
||||
const beforePriority = prev?.sortPriority ?? 0;
|
||||
@@ -248,8 +178,8 @@ const activeIdAtom = atom<string | null>((get) => {
|
||||
});
|
||||
|
||||
function getEditOptions(
|
||||
item: Model,
|
||||
): ReturnType<NonNullable<TreeItemProps<Model>['getEditOptions']>> {
|
||||
item: SidebarModel,
|
||||
): ReturnType<NonNullable<TreeItemProps<SidebarModel>['getEditOptions']>> {
|
||||
return {
|
||||
onChange: handleSubmitEdit,
|
||||
defaultValue: resolvedModelName(item),
|
||||
@@ -257,18 +187,18 @@ function getEditOptions(
|
||||
};
|
||||
}
|
||||
|
||||
async function handleSubmitEdit(item: Model, text: string) {
|
||||
async function handleSubmitEdit(item: SidebarModel, text: string) {
|
||||
await patchModel(item, { name: text });
|
||||
}
|
||||
|
||||
function handleActivate(item: Model) {
|
||||
function handleActivate(item: SidebarModel) {
|
||||
// TODO: Add folder layout support
|
||||
if (item.model !== 'folder' && item.model !== 'workspace') {
|
||||
navigateToRequestOrFolderOrWorkspace(item.id, item.model);
|
||||
}
|
||||
}
|
||||
|
||||
const allPotentialChildrenAtom = atom<Model[]>((get) => {
|
||||
const allPotentialChildrenAtom = atom<SidebarModel[]>((get) => {
|
||||
const requests = get(allRequestsAtom);
|
||||
const folders = get(foldersAtom);
|
||||
return [...requests, ...folders];
|
||||
@@ -280,7 +210,7 @@ const sidebarTreeAtom = atom((get) => {
|
||||
const allModels = get(memoAllPotentialChildrenAtom);
|
||||
const activeWorkspace = get(activeWorkspaceAtom);
|
||||
|
||||
const childrenMap: Record<string, Exclude<Model, Workspace>[]> = {};
|
||||
const childrenMap: Record<string, Exclude<SidebarModel, Workspace>[]> = {};
|
||||
for (const item of allModels) {
|
||||
if ('folderId' in item && item.folderId == null) {
|
||||
childrenMap[item.workspaceId] = childrenMap[item.workspaceId] ?? [];
|
||||
@@ -291,14 +221,14 @@ const sidebarTreeAtom = atom((get) => {
|
||||
}
|
||||
}
|
||||
|
||||
const treeParentMap: Record<string, TreeNode<Model>> = {};
|
||||
const treeParentMap: Record<string, TreeNode<SidebarModel>> = {};
|
||||
|
||||
if (activeWorkspace == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Put requests and folders into a tree structure
|
||||
const next = (node: TreeNode<Model>, depth: number): TreeNode<Model> => {
|
||||
const next = (node: TreeNode<SidebarModel>, depth: number): TreeNode<SidebarModel> => {
|
||||
const childItems = childrenMap[node.item.id] ?? [];
|
||||
|
||||
// Recurse to children
|
||||
@@ -326,10 +256,10 @@ const sidebarTreeAtom = atom((get) => {
|
||||
});
|
||||
|
||||
const actions = {
|
||||
'sidebar.delete_selected_item': async function (items: Model[]) {
|
||||
'sidebar.delete_selected_item': async function (items: SidebarModel[]) {
|
||||
await deleteModelWithConfirm(items);
|
||||
},
|
||||
'model.duplicate': async function (items: Model[]) {
|
||||
'model.duplicate': async function (items: SidebarModel[]) {
|
||||
if (items.length === 1) {
|
||||
const item = items[0]!;
|
||||
const newId = await duplicateModel(item);
|
||||
@@ -338,22 +268,29 @@ const actions = {
|
||||
await Promise.all(items.map(duplicateModel));
|
||||
}
|
||||
},
|
||||
'request.send': async function (items: Model[]) {
|
||||
'request.send': async function (items: SidebarModel[]) {
|
||||
await Promise.all(
|
||||
items.filter((i) => i.model === 'http_request').map((i) => sendAnyHttpRequest.mutate(i.id)),
|
||||
);
|
||||
},
|
||||
} as const;
|
||||
|
||||
const hotkeys: TreeProps<Model>['hotkeys'] = {
|
||||
const hotkeys: TreeProps<SidebarModel>['hotkeys'] = {
|
||||
priority: 10, // So these ones take precedence over global hotkeys when the sidebar is focused
|
||||
actions,
|
||||
enable: () => isSidebarFocused(),
|
||||
};
|
||||
|
||||
async function getContextMenu(items: Model[]): Promise<DropdownItem[]> {
|
||||
async function getContextMenu(items: SidebarModel[]): Promise<DropdownItem[]> {
|
||||
const workspaceId = jotaiStore.get(activeWorkspaceIdAtom);
|
||||
const child = items[0];
|
||||
if (child == null) return [];
|
||||
|
||||
// No children means we're in the root
|
||||
if (child == null) {
|
||||
console.log('HELLO', child);
|
||||
return getCreateDropdownItems({ workspaceId, activeRequest: null, folderId: null });
|
||||
}
|
||||
|
||||
const workspaces = jotaiStore.get(workspacesAtom);
|
||||
const onlyHttpRequests = items.every((i) => i.model === 'http_request');
|
||||
|
||||
@@ -411,7 +348,13 @@ async function getContextMenu(items: Model[]): Promise<DropdownItem[]> {
|
||||
},
|
||||
})),
|
||||
];
|
||||
|
||||
const modelCreationItems: DropdownItem[] =
|
||||
items.length === 1 && child.model === 'folder'
|
||||
? [
|
||||
{ type: 'separator' },
|
||||
...getCreateDropdownItems({ workspaceId, activeRequest: null, folderId: child.id }),
|
||||
]
|
||||
: [];
|
||||
const menuItems: ContextMenuProps['items'] = [
|
||||
...initialItems,
|
||||
{ type: 'separator', hidden: initialItems.filter((v) => !v.hidden).length === 0 },
|
||||
@@ -455,6 +398,83 @@ async function getContextMenu(items: Model[]): Promise<DropdownItem[]> {
|
||||
leftSlot: <Icon icon="trash" />,
|
||||
onSelect: () => actions['sidebar.delete_selected_item'](items),
|
||||
},
|
||||
...modelCreationItems,
|
||||
];
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
function getItemKey(item: SidebarModel) {
|
||||
const responses = jotaiStore.get(httpResponsesAtom);
|
||||
const latestResponse = responses.find((r) => r.requestId === item.id) ?? null;
|
||||
const url = 'url' in item ? item.url : 'n/a';
|
||||
const method = 'method' in item ? item.method : 'n/a';
|
||||
return [
|
||||
item.id,
|
||||
item.name,
|
||||
url,
|
||||
method,
|
||||
latestResponse?.elapsed,
|
||||
latestResponse?.id ?? 'n/a',
|
||||
].join('::');
|
||||
}
|
||||
|
||||
const SidebarLeftSlot = memo(function SidebarLeftSlot({
|
||||
treeId,
|
||||
item,
|
||||
}: {
|
||||
treeId: string;
|
||||
item: SidebarModel;
|
||||
}) {
|
||||
if (item.model === 'folder') {
|
||||
return <Icon icon="folder" />;
|
||||
} else if (item.model === 'workspace') {
|
||||
return null;
|
||||
} else {
|
||||
const isSelected = jotaiStore.get(isSelectedFamily({ treeId, itemId: item.id }));
|
||||
return (
|
||||
<HttpMethodTag
|
||||
short
|
||||
className={classNames('text-xs', !isSelected && OPACITY_SUBTLE)}
|
||||
request={item}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const SidebarInnerItem = memo(function SidebarInnerItem({
|
||||
item,
|
||||
}: {
|
||||
treeId: string;
|
||||
item: SidebarModel;
|
||||
}) {
|
||||
const response = useAtomValue(
|
||||
useMemo(
|
||||
() =>
|
||||
selectAtom(
|
||||
atom((get) => [
|
||||
...get(grpcConnectionsAtom),
|
||||
...get(httpResponsesAtom),
|
||||
...get(websocketConnectionsAtom),
|
||||
]),
|
||||
(responses) => responses.find((r) => r.requestId === item.id),
|
||||
(a, b) => a?.state === b?.state && a?.id === b?.id, // Only update when the response state changes updated
|
||||
),
|
||||
[item.id],
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 min-w-0 h-full w-full text-left">
|
||||
<div className="truncate">{resolvedModelName(item)}</div>
|
||||
{response != null && (
|
||||
<div className="ml-auto">
|
||||
{response.state !== 'closed' ? (
|
||||
<LoadingIcon size="sm" className="text-text-subtlest" />
|
||||
) : response.model === 'http_response' ? (
|
||||
<HttpStatusTag short className="text-xs" response={response} />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -9,14 +9,23 @@ import {
|
||||
} from '@dnd-kit/core';
|
||||
import { type } from '@tauri-apps/plugin-os';
|
||||
import classNames from 'classnames';
|
||||
import type { ComponentType, ReactElement, Ref, RefAttributes } from 'react';
|
||||
import { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef } from 'react';
|
||||
import type { ComponentType, MouseEvent, ReactElement, Ref, RefAttributes } from 'react';
|
||||
import React, {
|
||||
forwardRef,
|
||||
memo,
|
||||
useCallback,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useKey, useKeyPressEvent } from 'react-use';
|
||||
import type { HotkeyAction, HotKeyOptions } from '../../../hooks/useHotKey';
|
||||
import { useHotKey } from '../../../hooks/useHotKey';
|
||||
import { computeSideForDragMove } from '../../../lib/dnd';
|
||||
import { jotaiStore } from '../../../lib/jotai';
|
||||
import type { ContextMenuProps } from '../Dropdown';
|
||||
import type { ContextMenuProps, DropdownItem } from '../Dropdown';
|
||||
import { ContextMenu } from '../Dropdown';
|
||||
import {
|
||||
collapsedFamily,
|
||||
draggingIdsFamily,
|
||||
@@ -73,6 +82,15 @@ function TreeInner<T extends { id: string }>(
|
||||
) {
|
||||
const treeRef = useRef<HTMLDivElement>(null);
|
||||
const selectableItems = useSelectableItems(root);
|
||||
const [showContextMenu, setShowContextMenu] = useState<{
|
||||
items: DropdownItem[];
|
||||
x: number;
|
||||
y: number;
|
||||
} | null>(null);
|
||||
|
||||
const handleCloseContextMenu = useCallback(() => {
|
||||
setShowContextMenu(null);
|
||||
}, []);
|
||||
|
||||
const tryFocus = useCallback(() => {
|
||||
treeRef.current?.querySelector<HTMLButtonElement>('.tree-item button[tabindex="0"]')?.focus();
|
||||
@@ -403,11 +421,30 @@ function TreeInner<T extends { id: string }>(
|
||||
ItemLeftSlot,
|
||||
};
|
||||
|
||||
const handleContextMenu = useCallback(
|
||||
async (e: MouseEvent<HTMLElement>) => {
|
||||
if (getContextMenu == null) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const items = await getContextMenu([]);
|
||||
setShowContextMenu({ items, x: e.clientX, y: e.clientY });
|
||||
},
|
||||
[getContextMenu],
|
||||
);
|
||||
|
||||
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));
|
||||
|
||||
return (
|
||||
<>
|
||||
<TreeHotKeys treeId={treeId} hotkeys={hotkeys} selectableItems={selectableItems} />
|
||||
{showContextMenu && (
|
||||
<ContextMenu
|
||||
items={showContextMenu.items}
|
||||
triggerPosition={showContextMenu}
|
||||
onClose={handleCloseContextMenu}
|
||||
/>
|
||||
)}
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
collisionDetection={pointerWithin}
|
||||
@@ -429,8 +466,6 @@ function TreeInner<T extends { id: string }>(
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'[&_.tree-item-inner]:bg-surface',
|
||||
'[&_.tree-item-selectable.selected]:text-text',
|
||||
'[&:focus-within]:[&_.tree-item.selected]:bg-surface-active',
|
||||
'[&:not(:focus-within)]:[&_.tree-item.selected]:bg-surface-highlight',
|
||||
|
||||
@@ -446,7 +481,7 @@ function TreeInner<T extends { id: string }>(
|
||||
<TreeItemList nodes={selectableItems} treeId={treeId} {...treeItemListProps} />
|
||||
</div>
|
||||
{/* Assign root ID so we can reuse our same move/end logic */}
|
||||
<DropRegionAfterList id={root.item.id} />
|
||||
<DropRegionAfterList id={root.item.id} onContextMenu={handleContextMenu} />
|
||||
</div>
|
||||
<TreeDragOverlay
|
||||
treeId={treeId}
|
||||
@@ -476,9 +511,15 @@ export const Tree = memo(
|
||||
},
|
||||
) as typeof Tree_;
|
||||
|
||||
function DropRegionAfterList({ id }: { id: string }) {
|
||||
function DropRegionAfterList({
|
||||
id,
|
||||
onContextMenu,
|
||||
}: {
|
||||
id: string;
|
||||
onContextMenu?: (e: MouseEvent<HTMLDivElement>) => void;
|
||||
}) {
|
||||
const { setNodeRef } = useDroppable({ id });
|
||||
return <div ref={setNodeRef} />;
|
||||
return <div ref={setNodeRef} onContextMenu={onContextMenu} />;
|
||||
}
|
||||
|
||||
interface TreeHotKeyProps<T extends { id: string }> extends HotKeyOptions {
|
||||
|
||||
@@ -242,7 +242,6 @@ function TreeItem_<T extends { id: string }>({
|
||||
<TreeIndentGuide treeId={treeId} depth={depth} />
|
||||
<div
|
||||
className={classNames(
|
||||
'tree-item-selectable',
|
||||
'text-text-subtle',
|
||||
'grid grid-cols-[auto_minmax(0,1fr)] items-center rounded-md',
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { HttpRequest, WebsocketRequest } from '@yaakapp-internal/models';
|
||||
import type { GrpcRequest } from '@yaakapp-internal/sync';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useMemo } from 'react';
|
||||
import { createFolder } from '../commands/commands';
|
||||
@@ -5,7 +7,6 @@ import type { DropdownItem } from '../components/core/Dropdown';
|
||||
import { Icon } from '../components/core/Icon';
|
||||
import { createRequestAndNavigate } from '../lib/createRequestAndNavigate';
|
||||
import { generateId } from '../lib/generateId';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
||||
import { activeRequestAtom } from './useActiveRequest';
|
||||
import { activeWorkspaceIdAtom } from './useActiveWorkspace';
|
||||
@@ -13,62 +14,78 @@ import { activeWorkspaceIdAtom } from './useActiveWorkspace';
|
||||
export function useCreateDropdownItems({
|
||||
hideFolder,
|
||||
hideIcons,
|
||||
folderId: folderIdOption,
|
||||
folderId,
|
||||
}: {
|
||||
hideFolder?: boolean;
|
||||
hideIcons?: boolean;
|
||||
folderId?: string | null | 'active-folder';
|
||||
} = {}): DropdownItem[] {
|
||||
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
|
||||
const activeRequest = useAtomValue(activeRequestAtom);
|
||||
|
||||
const items = useMemo((): DropdownItem[] => {
|
||||
const activeRequest = jotaiStore.get(activeRequestAtom);
|
||||
const folderId =
|
||||
(folderIdOption === 'active-folder' ? activeRequest?.folderId : folderIdOption) ?? null;
|
||||
if (workspaceId == null) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
label: 'HTTP',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createRequestAndNavigate({ model: 'http_request', workspaceId, folderId }),
|
||||
},
|
||||
{
|
||||
label: 'GraphQL',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
createRequestAndNavigate({
|
||||
model: 'http_request',
|
||||
workspaceId,
|
||||
folderId,
|
||||
bodyType: BODY_TYPE_GRAPHQL,
|
||||
method: 'POST',
|
||||
headers: [{ name: 'Content-Type', value: 'application/json', id: generateId() }],
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'gRPC',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createRequestAndNavigate({ model: 'grpc_request', workspaceId, folderId }),
|
||||
},
|
||||
{
|
||||
label: 'WebSocket',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
createRequestAndNavigate({ model: 'websocket_request', workspaceId, folderId }),
|
||||
},
|
||||
...((hideFolder
|
||||
? []
|
||||
: [
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Folder',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createFolder.mutate({ folderId }),
|
||||
},
|
||||
]) as DropdownItem[]),
|
||||
];
|
||||
}, [folderIdOption, hideFolder, hideIcons, workspaceId]);
|
||||
return getCreateDropdownItems({ hideFolder, hideIcons, folderId, activeRequest, workspaceId });
|
||||
}, [activeRequest, folderId, hideFolder, hideIcons, workspaceId]);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export function getCreateDropdownItems({
|
||||
hideFolder,
|
||||
hideIcons,
|
||||
folderId: folderIdOption,
|
||||
workspaceId,
|
||||
activeRequest,
|
||||
}: {
|
||||
hideFolder?: boolean;
|
||||
hideIcons?: boolean;
|
||||
folderId?: string | null | 'active-folder';
|
||||
workspaceId: string | null;
|
||||
activeRequest: HttpRequest | GrpcRequest | WebsocketRequest | null;
|
||||
}): DropdownItem[] {
|
||||
const folderId =
|
||||
(folderIdOption === 'active-folder' ? activeRequest?.folderId : folderIdOption) ?? null;
|
||||
if (workspaceId == null) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
label: 'HTTP',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createRequestAndNavigate({ model: 'http_request', workspaceId, folderId }),
|
||||
},
|
||||
{
|
||||
label: 'GraphQL',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
createRequestAndNavigate({
|
||||
model: 'http_request',
|
||||
workspaceId,
|
||||
folderId,
|
||||
bodyType: BODY_TYPE_GRAPHQL,
|
||||
method: 'POST',
|
||||
headers: [{ name: 'Content-Type', value: 'application/json', id: generateId() }],
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'gRPC',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createRequestAndNavigate({ model: 'grpc_request', workspaceId, folderId }),
|
||||
},
|
||||
{
|
||||
label: 'WebSocket',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
createRequestAndNavigate({ model: 'websocket_request', workspaceId, folderId }),
|
||||
},
|
||||
...((hideFolder
|
||||
? []
|
||||
: [
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Folder',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createFolder.mutate({ folderId }),
|
||||
},
|
||||
]) as DropdownItem[]),
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user