Custom HTTP method names

This commit is contained in:
Gregory Schier
2024-01-17 14:52:19 -08:00
parent 466d412e65
commit 321c3862fe
8 changed files with 128 additions and 77 deletions
+39 -3
View File
@@ -1,5 +1,9 @@
import { memo } from 'react'; import { memo, useMemo } from 'react';
import { usePrompt } from '../hooks/usePrompt';
import { Button } from './core/Button'; import { Button } from './core/Button';
import type { DropdownItem } from './core/Dropdown';
import { Icon } from './core/Icon';
import type { RadioDropdownItem } from './core/RadioDropdown';
import { RadioDropdown } from './core/RadioDropdown'; import { RadioDropdown } from './core/RadioDropdown';
type Props = { type Props = {
@@ -8,7 +12,15 @@ type Props = {
onChange: (method: string) => void; onChange: (method: string) => void;
}; };
const methodItems = ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'].map((m) => ({ const radioItems: RadioDropdownItem<string>[] = [
'GET',
'PUT',
'POST',
'PATCH',
'DELETE',
'OPTIONS',
'HEAD',
].map((m) => ({
value: m, value: m,
label: m, label: m,
})); }));
@@ -18,8 +30,32 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
onChange, onChange,
className, className,
}: Props) { }: Props) {
const prompt = usePrompt();
const extraItems = useMemo<DropdownItem[]>(
() => [
{ type: 'separator' },
{
key: 'custom',
label: 'CUSTOM',
leftSlot: <Icon icon="sparkles" />,
onSelect: async () => {
const newMethod = await prompt({
label: 'Http Method',
name: 'httpMethod',
defaultValue: '',
title: 'Custom Method',
description: 'Enter a custom method name',
placeholder: 'CUSTOM',
});
onChange(newMethod);
},
},
],
[onChange, prompt],
);
return ( return (
<RadioDropdown value={method} items={methodItems} onChange={onChange}> <RadioDropdown value={method} items={radioItems} extraItems={extraItems} onChange={onChange}>
<Button size="xs" className={className}> <Button size="xs" className={className}>
{method.toUpperCase()} {method.toUpperCase()}
</Button> </Button>
+3 -3
View File
@@ -21,7 +21,7 @@ export const SettingsDialog = () => {
return ( return (
<VStack space={2}> <VStack space={2}>
<HStack alignItems="center" space={2}> <HStack className="mt-1" alignItems="center" space={2}>
<div className="w-1/3">Appearance</div> <div className="w-1/3">Appearance</div>
<select <select
value={settings.appearance} value={settings.appearance}
@@ -42,11 +42,11 @@ export const SettingsDialog = () => {
<Heading size={2}> <Heading size={2}>
Workspace{' '} Workspace{' '}
<div className="inline-block ml-1 bg-gray-500 dark:bg-gray-300 px-2 py-0.5 !text-md rounded text-base text-white dark:text-gray-900"> <div className="inline-block ml-1 bg-gray-500 dark:bg-gray-300 px-2 py-0.5 text-sm rounded text-white dark:text-gray-900">
{workspace.name} {workspace.name}
</div> </div>
</Heading> </Heading>
<VStack className="w-full" space={3}> <VStack className="mt-1 w-full" space={3}>
<Input <Input
size="xs" size="xs"
name="requestTimeout" name="requestTimeout"
-6
View File
@@ -656,12 +656,6 @@ const SidebarItem = forwardRef(function SidebarItem(
leftSlot: <Icon icon="sendHorizontal" />, leftSlot: <Icon icon="sendHorizontal" />,
onSelect: () => sendRequest.mutate(), onSelect: () => sendRequest.mutate(),
}, },
{
key: 'sendAndDownloadRequest',
label: 'Send and Download',
leftSlot: <Icon icon="download" />,
onSelect: () => sendAndDownloadRequest.mutate(),
},
{ type: 'separator' }, { type: 'separator' },
{ {
key: 'duplicateRequest', key: 'duplicateRequest',
+1
View File
@@ -31,6 +31,7 @@ const icons = {
sendHorizontal: lucide.SendHorizonalIcon, sendHorizontal: lucide.SendHorizonalIcon,
settings2: lucide.Settings2Icon, settings2: lucide.Settings2Icon,
settings: lucide.SettingsIcon, settings: lucide.SettingsIcon,
sparkles: lucide.SparklesIcon,
trash: lucide.TrashIcon, trash: lucide.TrashIcon,
update: lucide.RefreshCcwIcon, update: lucide.RefreshCcwIcon,
upload: lucide.UploadIcon, upload: lucide.UploadIcon,
+7 -3
View File
@@ -16,18 +16,20 @@ export interface RadioDropdownProps<T = string | null> {
value: T; value: T;
onChange: (value: T) => void; onChange: (value: T) => void;
items: RadioDropdownItem<T>[]; items: RadioDropdownItem<T>[];
extraItems?: DropdownProps['items'];
children: DropdownProps['children']; children: DropdownProps['children'];
} }
export function RadioDropdown<T = string | null>({ export function RadioDropdown<T = string | null>({
value, value,
items, items,
extraItems,
onChange, onChange,
children, children,
}: RadioDropdownProps<T>) { }: RadioDropdownProps<T>) {
const dropdownItems = useMemo( const dropdownItems = useMemo(
() => () => [
items.map((item) => { ...items.map((item) => {
if (item.type === 'separator') { if (item.type === 'separator') {
return item; return item;
} else { } else {
@@ -40,7 +42,9 @@ export function RadioDropdown<T = string | null>({
}; };
} }
}), }),
[items, value, onChange], ...(extraItems ?? []),
],
[items, extraItems, value, onChange],
); );
return <Dropdown items={dropdownItems}>{children}</Dropdown>; return <Dropdown items={dropdownItems}>{children}</Dropdown>;
+4 -2
View File
@@ -10,10 +10,11 @@ export interface PromptProps {
onResult: (value: string) => void; onResult: (value: string) => void;
label: InputProps['label']; label: InputProps['label'];
name: InputProps['name']; name: InputProps['name'];
defaultValue: InputProps['defaultValue']; defaultValue?: InputProps['defaultValue'];
placeholder?: InputProps['placeholder'];
} }
export function Prompt({ onHide, label, name, defaultValue, onResult }: PromptProps) { export function Prompt({ onHide, label, name, defaultValue, placeholder, onResult }: PromptProps) {
const [value, setValue] = useState<string>(defaultValue ?? ''); const [value, setValue] = useState<string>(defaultValue ?? '');
const handleSubmit = useCallback( const handleSubmit = useCallback(
(e: FormEvent<HTMLFormElement>) => { (e: FormEvent<HTMLFormElement>) => {
@@ -33,6 +34,7 @@ export function Prompt({ onHide, label, name, defaultValue, onResult }: PromptPr
hideLabel hideLabel
require require
autoSelect autoSelect
placeholder={placeholder}
label={label} label={label}
name={name} name={name}
defaultValue={defaultValue} defaultValue={defaultValue}
+6 -8
View File
@@ -1,3 +1,4 @@
import { dialog } from '@tauri-apps/api';
import type { DialogProps } from '../components/core/Dialog'; import type { DialogProps } from '../components/core/Dialog';
import { useDialog } from '../components/DialogContext'; import { useDialog } from '../components/DialogContext';
import type { PromptProps } from './Prompt'; import type { PromptProps } from './Prompt';
@@ -11,20 +12,17 @@ export function usePrompt() {
name, name,
label, label,
defaultValue, defaultValue,
}: { placeholder,
title: DialogProps['title']; }: Pick<DialogProps, 'title' | 'description'> &
description?: DialogProps['description']; Pick<PromptProps, 'name' | 'label' | 'defaultValue' | 'placeholder'>) =>
name: PromptProps['name'];
label: PromptProps['label'];
defaultValue: PromptProps['defaultValue'];
}) =>
new Promise((onResult: PromptProps['onResult']) => { new Promise((onResult: PromptProps['onResult']) => {
dialog.show({ dialog.show({
title, title,
description, description,
hideX: true, hideX: true,
size: 'sm', size: 'sm',
render: ({ hide }) => Prompt({ onHide: hide, onResult, name, label, defaultValue }), render: ({ hide }) =>
Prompt({ onHide: hide, onResult, name, label, defaultValue, placeholder }),
}); });
}); });
} }
+16
View File
@@ -101,6 +101,22 @@ export function generateColors(
} }
const lightnessMap: Record<Appearance, Record<AppThemeColorVariant, number>> = { const lightnessMap: Record<Appearance, Record<AppThemeColorVariant, number>> = {
system: {
// Not actually used
0: 1,
50: 1,
100: 0.9,
200: 0.7,
300: 0.4,
400: 0.2,
500: 0,
600: -0.2,
700: -0.4,
800: -0.6,
900: -0.8,
950: -0.9,
1000: -1,
},
light: { light: {
0: 1, 0: 1,
50: 1, 50: 1,