Change curl import to post-toast

This commit is contained in:
Gregory Schier
2024-05-10 13:06:40 -07:00
parent 582da26574
commit fd6ad952fe
3 changed files with 107 additions and 98 deletions

View File

@@ -1,6 +1,6 @@
import classNames from 'classnames'; import classNames from 'classnames';
import type { CSSProperties } from 'react'; import type { CSSProperties } from 'react';
import { memo, useCallback, useMemo, useState } from 'react'; import React, { memo, useCallback, useMemo, useState } from 'react';
import { createGlobalState } from 'react-use'; import { createGlobalState } from 'react-use';
import { useCancelHttpResponse } from '../hooks/useCancelHttpResponse'; import { useCancelHttpResponse } from '../hooks/useCancelHttpResponse';
import { useIsResponseLoading } from '../hooks/useIsResponseLoading'; import { useIsResponseLoading } from '../hooks/useIsResponseLoading';
@@ -39,7 +39,8 @@ import { HeadersEditor } from './HeadersEditor';
import { UrlBar } from './UrlBar'; import { UrlBar } from './UrlBar';
import { UrlParametersEditor } from './UrlParameterEditor'; import { UrlParametersEditor } from './UrlParameterEditor';
import { useCurlToRequest } from '../hooks/useCurlToRequest'; import { useCurlToRequest } from '../hooks/useCurlToRequest';
import { useConfirm } from '../hooks/useConfirm'; import { useToast } from './ToastContext';
import { Icon } from './core/Icon';
interface Props { interface Props {
style: CSSProperties; style: CSSProperties;
@@ -230,7 +231,7 @@ export const RequestPane = memo(function RequestPane({
); );
const importCurl = useCurlToRequest(); const importCurl = useCurlToRequest();
const confirm = useConfirm(); const toast = useToast();
const isLoading = useIsResponseLoading(activeRequestId ?? null); const isLoading = useIsResponseLoading(activeRequestId ?? null);
const { updateKey } = useRequestUpdateKey(activeRequestId ?? null); const { updateKey } = useRequestUpdateKey(activeRequestId ?? null);
@@ -250,15 +251,15 @@ export const RequestPane = memo(function RequestPane({
if (!command.startsWith('curl ')) { if (!command.startsWith('curl ')) {
return; return;
} }
const confirmed = await confirm({ importCurl.mutate({ requestId: activeRequestId, command });
id: 'paste-curl', toast.show({
title: 'Import from Curl?', render: () => [
description: 'Do you want to overwrite the current request with the Curl command?', <>
confirmText: 'Overwrite', <Icon icon="info" />
<span>Curl command imported</span>
</>,
],
}); });
if (confirmed) {
importCurl.mutate({ requestId: activeRequestId, command });
}
}} }}
onSend={handleSend} onSend={handleSend}
onCancel={handleCancel} onCancel={handleCancel}

View File

@@ -6,7 +6,7 @@ import type {
MouseEvent as ReactMouseEvent, MouseEvent as ReactMouseEvent,
ReactNode, ReactNode,
} from 'react'; } from 'react';
import { useCallback, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useWindowSize } from 'react-use'; import { useWindowSize } from 'react-use';
import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveRequest } from '../hooks/useActiveRequest';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace'; import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
@@ -34,7 +34,7 @@ import { Sidebar } from './Sidebar';
import { SidebarActions } from './SidebarActions'; import { SidebarActions } from './SidebarActions';
import { WorkspaceHeader } from './WorkspaceHeader'; import { WorkspaceHeader } from './WorkspaceHeader';
import { useClipboardText } from '../hooks/useClipboardText'; import { useClipboardText } from '../hooks/useClipboardText';
import { Portal } from './Portal'; import { useToast } from './ToastContext';
const side = { gridArea: 'side' }; const side = { gridArea: 'side' };
const head = { gridArea: 'head' }; const head = { gridArea: 'head' };
@@ -56,7 +56,24 @@ export default function Workspace() {
const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>( const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>(
null, null,
); );
const isCurlInClipboard = !!useClipboardText()?.startsWith('curl '); const clipboardText = useClipboardText();
const toast = useToast();
useEffect(() => {
const isCurlInClipboard = clipboardText?.startsWith('curl ');
if (!isCurlInClipboard) {
return;
}
toast.show({
render: () => (
<div>
<p>Curl command detected?</p>
<Button color="primary">Import</Button>
</div>
),
});
}, [clipboardText, toast]);
const unsub = () => { const unsub = () => {
if (moveState.current !== null) { if (moveState.current !== null) {
@@ -127,88 +144,83 @@ export default function Workspace() {
} }
return ( return (
<> <div
<Portal name="toast"> style={styles}
{isCurlInClipboard && <div className="static right-0 left-0 w-32 h-10">Import</div>} className={classNames(
</Portal> 'grid w-full h-full',
<div // Animate sidebar width changes but only when not resizing
style={styles} // because it's too slow to animate on mouse move
className={classNames( !isResizing && 'transition-all',
'grid w-full h-full', )}
// Animate sidebar width changes but only when not resizing >
// because it's too slow to animate on mouse move {floating ? (
!isResizing && 'transition-all', <Overlay
)} open={!floatingSidebarHidden}
> portalName="sidebar"
{floating ? ( onClose={() => setFloatingSidebarHidden(true)}
<Overlay >
open={!floatingSidebarHidden} <motion.div
portalName="sidebar" initial={{ opacity: 0, x: -20 }}
onClose={() => setFloatingSidebarHidden(true)} animate={{ opacity: 1, x: 0 }}
className={classNames(
'absolute top-0 left-0 bottom-0 bg-gray-100 border-r border-highlight w-[14rem]',
'grid grid-rows-[auto_1fr]',
)}
> >
<motion.div <HeaderSize className="border-transparent">
initial={{ opacity: 0, x: -20 }} <SidebarActions />
animate={{ opacity: 1, x: 0 }} </HeaderSize>
className={classNames( <Sidebar />
'absolute top-0 left-0 bottom-0 bg-gray-100 border-r border-highlight w-[14rem]', </motion.div>
'grid grid-rows-[auto_1fr]', </Overlay>
)} ) : (
> <>
<HeaderSize className="border-transparent"> <div style={side} className={classNames('overflow-hidden bg-gray-100')}>
<SidebarActions /> <Sidebar className="border-r border-highlight" />
</HeaderSize>
<Sidebar />
</motion.div>
</Overlay>
) : (
<>
<div style={side} className={classNames('overflow-hidden bg-gray-100')}>
<Sidebar className="border-r border-highlight" />
</div>
<ResizeHandle
className="-translate-x-3"
justify="end"
side="right"
isResizing={isResizing}
onResizeStart={handleResizeStart}
onReset={resetWidth}
/>
</>
)}
<HeaderSize data-tauri-drag-region style={head}>
<WorkspaceHeader className="pointer-events-none" />
</HeaderSize>
{activeWorkspace == null ? (
<div className="m-auto">
<Banner color="warning" className="max-w-[30rem]">
The active workspace{' '}
<InlineCode className="text-orange-800">{activeWorkspaceId}</InlineCode> was not
found. Select a workspace from the header menu or report this bug to <FeedbackLink />
</Banner>
</div> </div>
) : activeRequest == null ? ( <ResizeHandle
<HotKeyList className="-translate-x-3"
hotkeys={['http_request.create', 'sidebar.toggle', 'settings.show']} justify="end"
bottomSlot={ side="right"
<HStack space={1} justifyContent="center" className="mt-3"> isResizing={isResizing}
<Button variant="border" size="sm" onClick={() => importData.mutate()}> onResizeStart={handleResizeStart}
Import onReset={resetWidth}
</Button>
<CreateDropdown hideFolder>
<Button variant="border" forDropdown size="sm">
New Request
</Button>
</CreateDropdown>
</HStack>
}
/> />
) : activeRequest.model === 'grpc_request' ? ( </>
<GrpcConnectionLayout style={body} /> )}
) : ( <HeaderSize data-tauri-drag-region style={head}>
<HttpRequestLayout activeRequest={activeRequest} style={body} /> <WorkspaceHeader className="pointer-events-none" />
)} </HeaderSize>
</div> {activeWorkspace == null ? (
</> <div className="m-auto">
<Banner color="warning" className="max-w-[30rem]">
The active workspace{' '}
<InlineCode className="text-orange-800">{activeWorkspaceId}</InlineCode> was not found.
Select a workspace from the header menu or report this bug to <FeedbackLink />
</Banner>
</div>
) : activeRequest == null ? (
<HotKeyList
hotkeys={['http_request.create', 'sidebar.toggle', 'settings.show']}
bottomSlot={
<HStack space={1} justifyContent="center" className="mt-3">
<Button variant="border" size="sm" onClick={() => importData.mutate()}>
Import
</Button>
<CreateDropdown hideFolder>
<Button variant="border" forDropdown size="sm">
New Request
</Button>
</CreateDropdown>
</HStack>
}
/>
) : activeRequest.model === 'grpc_request' ? (
<GrpcConnectionLayout style={body} />
) : (
<HttpRequestLayout activeRequest={activeRequest} style={body} />
)}
</div>
); );
} }

View File

@@ -4,10 +4,6 @@ import { readText } from '@tauri-apps/plugin-clipboard-manager';
export function useClipboardText() { export function useClipboardText() {
return useQuery({ return useQuery({
queryKey: [], queryKey: [],
queryFn: async () => { queryFn: () => readText(),
const text = await readText();
console.log('READ CLIPBOARD', text);
return text;
},
}).data; }).data;
} }