Import from Curl

This commit is contained in:
Gregory Schier
2024-05-09 07:31:52 -07:00
parent c64c794f86
commit bf4eee72df
9 changed files with 131 additions and 38 deletions

View File

@@ -38,6 +38,8 @@ import { GraphQLEditor } from './GraphQLEditor';
import { HeadersEditor } from './HeadersEditor';
import { UrlBar } from './UrlBar';
import { UrlParametersEditor } from './UrlParameterEditor';
import { useCurlToRequest } from '../hooks/useCurlToRequest';
import { useConfirm } from '../hooks/useConfirm';
interface Props {
style: CSSProperties;
@@ -227,6 +229,9 @@ export const RequestPane = memo(function RequestPane({
[updateRequest],
);
const importCurl = useCurlToRequest();
const confirm = useConfirm();
const isLoading = useIsResponseLoading(activeRequestId ?? null);
const { updateKey } = useRequestUpdateKey(activeRequestId ?? null);
@@ -241,6 +246,22 @@ export const RequestPane = memo(function RequestPane({
url={activeRequest.url}
method={activeRequest.method}
placeholder="https://example.com"
onPaste={async (command) => {
if (!command.startsWith('curl ')) {
return;
}
if (
await confirm({
id: 'paste-curl',
title: 'Import from Curl?',
description:
'Do you want to overwrite the current request with the Curl command?',
confirmText: 'Overwrite',
})
) {
importCurl.mutate({ requestId: activeRequestId, command });
}
}}
onSend={handleSend}
onCancel={handleCancel}
onMethodChange={handleMethodChange}

View File

@@ -14,6 +14,7 @@ type Props = Pick<HttpRequest, 'url'> & {
placeholder: string;
onSend: () => void;
onUrlChange: (url: string) => void;
onPaste?: (v: string) => void;
onCancel: () => void;
submitIcon?: IconProps['icon'] | null;
onMethodChange?: (method: string) => void;
@@ -31,6 +32,7 @@ export const UrlBar = memo(function UrlBar({
onSend,
onCancel,
onMethodChange,
onPaste,
submitIcon = 'sendHorizontal',
isLoading,
}: Props) {
@@ -66,6 +68,7 @@ export const UrlBar = memo(function UrlBar({
forceUpdateKey={forceUpdateKey}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onPaste={onPaste}
containerClassName="shadow shadow-gray-100 dark:shadow-gray-50"
onChange={onUrlChange}
defaultValue={url}

View File

@@ -44,6 +44,7 @@ export interface EditorProps {
tooltipContainer?: HTMLElement;
useTemplating?: boolean;
onChange?: (value: string) => void;
onPaste?: (value: string) => void;
onFocus?: () => void;
onBlur?: () => void;
onKeyDown?: (e: KeyboardEvent) => void;
@@ -69,6 +70,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
defaultValue,
forceUpdateKey,
onChange,
onPaste,
onFocus,
onBlur,
onKeyDown,
@@ -91,25 +93,31 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
const cm = useRef<{ view: EditorView; languageCompartment: Compartment } | null>(null);
useImperativeHandle(ref, () => cm.current?.view);
// Use ref so we can update the onChange handler without re-initializing the editor
// Use ref so we can update the handler without re-initializing the editor
const handleChange = useRef<EditorProps['onChange']>(onChange);
useEffect(() => {
handleChange.current = onChange;
}, [onChange]);
// Use ref so we can update the onChange handler without re-initializing the editor
// Use ref so we can update the handler without re-initializing the editor
const handlePaste = useRef<EditorProps['onPaste']>(onPaste);
useEffect(() => {
handlePaste.current = onPaste;
}, [onPaste]);
// Use ref so we can update the handler without re-initializing the editor
const handleFocus = useRef<EditorProps['onFocus']>(onFocus);
useEffect(() => {
handleFocus.current = onFocus;
}, [onFocus]);
// Use ref so we can update the onChange handler without re-initializing the editor
// Use ref so we can update the handler without re-initializing the editor
const handleBlur = useRef<EditorProps['onBlur']>(onBlur);
useEffect(() => {
handleBlur.current = onBlur;
}, [onBlur]);
// Use ref so we can update the onChange handler without re-initializing the editor
// Use ref so we can update the handler without re-initializing the editor
const handleKeyDown = useRef<EditorProps['onKeyDown']>(onKeyDown);
useEffect(() => {
handleKeyDown.current = onKeyDown;
@@ -187,6 +195,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
readOnly,
singleLine,
onChange: handleChange,
onPaste: handlePaste,
onFocus: handleFocus,
onBlur: handleBlur,
onKeyDown: handleKeyDown,
@@ -299,12 +308,14 @@ function getExtensions({
readOnly,
singleLine,
onChange,
onPaste,
onFocus,
onBlur,
onKeyDown,
}: Pick<EditorProps, 'singleLine' | 'readOnly'> & {
container: HTMLDivElement | null;
onChange: MutableRefObject<EditorProps['onChange']>;
onPaste: MutableRefObject<EditorProps['onPaste']>;
onFocus: MutableRefObject<EditorProps['onFocus']>;
onBlur: MutableRefObject<EditorProps['onBlur']>;
onKeyDown: MutableRefObject<EditorProps['onKeyDown']>;
@@ -321,6 +332,7 @@ function getExtensions({
focus: () => onFocus.current?.(),
blur: () => onBlur.current?.(),
keydown: (e) => onKeyDown.current?.(e),
paste: (e) => onPaste.current?.(e.clipboardData?.getData('text/plain') ?? ''),
}),
tooltips({ parent }),
keymap.of(singleLine ? defaultKeymap.filter((k) => k.key !== 'Enter') : defaultKeymap),

View File

@@ -10,7 +10,7 @@ import { HStack } from './Stacks';
export type InputProps = Omit<
HTMLAttributes<HTMLInputElement>,
'onChange' | 'onFocus' | 'onKeyDown'
'onChange' | 'onFocus' | 'onKeyDown' | 'onPaste'
> &
Pick<
EditorProps,
@@ -33,6 +33,7 @@ export type InputProps = Omit<
onChange?: (value: string) => void;
onFocus?: () => void;
onBlur?: () => void;
onPaste?: (value: string) => void;
defaultValue?: string;
leftSlot?: ReactNode;
rightSlot?: ReactNode;
@@ -59,6 +60,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
onBlur,
onChange,
onFocus,
onPaste,
placeholder,
require,
rightSlot,
@@ -172,6 +174,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
forceUpdateKey={forceUpdateKey}
placeholder={placeholder}
onChange={handleChange}
onPaste={onPaste}
className={editorClassName}
onFocus={handleFocus}
onBlur={handleBlur}

View File

@@ -6,6 +6,7 @@ export interface ConfirmProps {
onHide: () => void;
onResult: (result: boolean) => void;
variant?: 'delete' | 'confirm';
confirmText?: string;
}
const colors: Record<NonNullable<ConfirmProps['variant']>, ButtonProps['color']> = {
@@ -18,7 +19,7 @@ const confirmButtonTexts: Record<NonNullable<ConfirmProps['variant']>, string> =
confirm: 'Confirm',
};
export function Confirm({ onHide, onResult, variant = 'confirm' }: ConfirmProps) {
export function Confirm({ onHide, onResult, confirmText, variant = 'confirm' }: ConfirmProps) {
const handleHide = () => {
onResult(false);
onHide();
@@ -32,7 +33,7 @@ export function Confirm({ onHide, onResult, variant = 'confirm' }: ConfirmProps)
return (
<HStack space={2} justifyContent="start" className="mt-2 mb-4 flex-row-reverse">
<Button className="focus" color={colors[variant]} onClick={handleSuccess}>
{confirmButtonTexts[variant]}
{confirmText ?? confirmButtonTexts[variant]}
</Button>
<Button className="focus" color="gray" onClick={handleHide}>
Cancel

View File

@@ -10,11 +10,13 @@ export function useConfirm() {
title,
description,
variant,
confirmText,
}: {
id: string;
title: DialogProps['title'];
description?: DialogProps['description'];
variant: ConfirmProps['variant'];
variant?: ConfirmProps['variant'];
confirmText?: ConfirmProps['confirmText'];
}) =>
new Promise((onResult: ConfirmProps['onResult']) => {
dialog.show({
@@ -23,7 +25,7 @@ export function useConfirm() {
description,
hideX: true,
size: 'sm',
render: ({ hide }) => Confirm({ onHide: hide, variant, onResult }),
render: ({ hide }) => Confirm({ onHide: hide, variant, onResult, confirmText }),
});
});
}

View File

@@ -0,0 +1,24 @@
import { invoke } from '@tauri-apps/api/core';
import { useMutation } from '@tanstack/react-query';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useRequestUpdateKey } from './useRequestUpdateKey';
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
export function useCurlToRequest() {
const workspaceId = useActiveWorkspaceId();
const updateRequest = useUpdateAnyHttpRequest();
const { wasUpdatedExternally } = useRequestUpdateKey(null);
return useMutation({
mutationFn: async ({ requestId, command }: { requestId: string; command: string }) => {
const request: Record<string, unknown> = await invoke('cmd_curl_to_request', {
command,
workspaceId,
});
delete request.id;
await updateRequest.mutateAsync({ id: requestId, update: request });
wasUpdatedExternally(requestId);
console.log('FOO', request);
},
});
}