mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-31 22:43:11 +02:00
Better curl import
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useClipboardText } from '../hooks/useClipboardText';
|
import { useCopy } from '../hooks/useCopy';
|
||||||
import { useTimedBoolean } from '../hooks/useTimedBoolean';
|
import { useTimedBoolean } from '../hooks/useTimedBoolean';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
@@ -8,7 +8,7 @@ interface Props extends ButtonProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function CopyButton({ text, ...props }: Props) {
|
export function CopyButton({ text, ...props }: Props) {
|
||||||
const [, copy] = useClipboardText({ disableToast: true });
|
const copy = useCopy({ disableToast: true });
|
||||||
const [copied, setCopied] = useTimedBoolean();
|
const [copied, setCopied] = useTimedBoolean();
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
|||||||
import type { Model } from '@yaakapp/api';
|
import type { Model } from '@yaakapp/api';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useAtiveWorkspaceChangedToast } from '../hooks/useAtiveWorkspaceChangedToast';
|
import { useAtiveWorkspaceChangedToast } from '../hooks/useAtiveWorkspaceChangedToast';
|
||||||
import { useClipboardText } from '../hooks/useClipboardText';
|
|
||||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
|
||||||
import { cookieJarsQueryKey } from '../hooks/useCookieJars';
|
import { cookieJarsQueryKey } from '../hooks/useCookieJars';
|
||||||
|
import { useCopy } from '../hooks/useCopy';
|
||||||
import { environmentsQueryKey } from '../hooks/useEnvironments';
|
import { environmentsQueryKey } from '../hooks/useEnvironments';
|
||||||
import { foldersQueryKey } from '../hooks/useFolders';
|
import { foldersQueryKey } from '../hooks/useFolders';
|
||||||
import { grpcConnectionsQueryKey } from '../hooks/useGrpcConnections';
|
import { grpcConnectionsQueryKey } from '../hooks/useGrpcConnections';
|
||||||
@@ -23,6 +22,7 @@ import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
|||||||
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
||||||
import { settingsQueryKey, useSettings } from '../hooks/useSettings';
|
import { settingsQueryKey, useSettings } from '../hooks/useSettings';
|
||||||
import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
|
import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
|
||||||
|
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
||||||
import { workspacesQueryKey } from '../hooks/useWorkspaces';
|
import { workspacesQueryKey } from '../hooks/useWorkspaces';
|
||||||
import { useZoom } from '../hooks/useZoom';
|
import { useZoom } from '../hooks/useZoom';
|
||||||
import { modelsEq } from '../lib/models';
|
import { modelsEq } from '../lib/models';
|
||||||
@@ -159,7 +159,7 @@ export function GlobalHooks() {
|
|||||||
useHotKey('app.zoom_reset', () => zoom.zoomReset);
|
useHotKey('app.zoom_reset', () => zoom.zoomReset);
|
||||||
useListenToTauriEvent('zoom_reset', () => zoom.zoomReset);
|
useListenToTauriEvent('zoom_reset', () => zoom.zoomReset);
|
||||||
|
|
||||||
const [, copy] = useClipboardText();
|
const copy = useCopy();
|
||||||
useListenToTauriEvent('generate_theme_css', () => {
|
useListenToTauriEvent('generate_theme_css', () => {
|
||||||
const themesCss = [
|
const themesCss = [
|
||||||
yaakDark,
|
yaakDark,
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
|
import { clear, readText } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useClipboardText } from '../hooks/useClipboardText';
|
|
||||||
import { useImportCurl } from '../hooks/useImportCurl';
|
import { useImportCurl } from '../hooks/useImportCurl';
|
||||||
|
import { useWindowFocus } from '../hooks/useWindowFocus';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
|
|
||||||
export function ImportCurlButton() {
|
export function ImportCurlButton() {
|
||||||
const [clipboardText] = useClipboardText();
|
const focused = useWindowFocus();
|
||||||
const importCurl = useImportCurl({ clearClipboard: true });
|
const [clipboardText, setClipboardText] = useState('');
|
||||||
|
|
||||||
|
const importCurl = useImportCurl();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
readText().then(setClipboardText);
|
||||||
|
}, [focused]);
|
||||||
|
|
||||||
if (!clipboardText?.trim().startsWith('curl ')) {
|
if (!clipboardText?.trim().startsWith('curl ')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -26,14 +33,17 @@ export function ImportCurlButton() {
|
|||||||
color="primary"
|
color="primary"
|
||||||
leftSlot={<Icon icon="paste" size="sm" />}
|
leftSlot={<Icon icon="paste" size="sm" />}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
importCurl
|
try {
|
||||||
.mutateAsync({
|
await importCurl.mutateAsync({ command: clipboardText });
|
||||||
requestId: null, // Create request
|
await clear(); // Clear the clipboard so the button goes away
|
||||||
command: clipboardText,
|
setClipboardText('');
|
||||||
})
|
} catch (e) {
|
||||||
.finally(() => setIsLoading(false));
|
// Nothing
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Import Curl
|
Import Curl
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { HttpRequest, HttpRequestHeader, HttpUrlParameter } from '@yaakapp/api';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import React, { memo, useCallback, useMemo, useState } from 'react';
|
import React, { memo, useCallback, useMemo, useState } from 'react';
|
||||||
@@ -12,7 +13,6 @@ import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
|||||||
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { tryFormatJson } from '../lib/formatters';
|
import { tryFormatJson } from '../lib/formatters';
|
||||||
import type { HttpRequest, HttpRequestHeader, HttpUrlParameter } from '@yaakapp/api';
|
|
||||||
import {
|
import {
|
||||||
AUTH_TYPE_BASIC,
|
AUTH_TYPE_BASIC,
|
||||||
AUTH_TYPE_BEARER,
|
AUTH_TYPE_BEARER,
|
||||||
@@ -268,7 +268,7 @@ export const RequestPane = memo(function RequestPane({
|
|||||||
|
|
||||||
const isLoading = useIsResponseLoading(activeRequestId ?? null);
|
const isLoading = useIsResponseLoading(activeRequestId ?? null);
|
||||||
const { updateKey } = useRequestUpdateKey(activeRequestId ?? null);
|
const { updateKey } = useRequestUpdateKey(activeRequestId ?? null);
|
||||||
const importCurl = useImportCurl({ clearClipboard: true });
|
const importCurl = useImportCurl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -282,11 +282,11 @@ export const RequestPane = memo(function RequestPane({
|
|||||||
url={activeRequest.url}
|
url={activeRequest.url}
|
||||||
method={activeRequest.method}
|
method={activeRequest.method}
|
||||||
placeholder="https://example.com"
|
placeholder="https://example.com"
|
||||||
onPaste={async (command) => {
|
onPaste={(command) => {
|
||||||
if (!command.startsWith('curl ')) {
|
if (!command.startsWith('curl ')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
importCurl.mutate({ requestId: activeRequestId, command });
|
importCurl.mutate({ overwriteRequestId: activeRequestId, command });
|
||||||
}}
|
}}
|
||||||
autocomplete={{
|
autocomplete={{
|
||||||
minMatch: 3,
|
minMatch: 3,
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import { clear, readText, writeText } from '@tauri-apps/plugin-clipboard-manager';
|
|
||||||
import { useCallback, useEffect } from 'react';
|
|
||||||
import { createGlobalState } from 'react-use';
|
|
||||||
import { useToast } from '../components/ToastContext';
|
|
||||||
import { useWindowFocus } from './useWindowFocus';
|
|
||||||
|
|
||||||
const useClipboardTextState = createGlobalState<string>('');
|
|
||||||
|
|
||||||
export function useClipboardText({ disableToast }: { disableToast?: boolean } = {}) {
|
|
||||||
const [value, setValue] = useClipboardTextState();
|
|
||||||
const focused = useWindowFocus();
|
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
readText()
|
|
||||||
.then(setValue)
|
|
||||||
.catch(() => {
|
|
||||||
// Clipboard probably empty
|
|
||||||
setValue('');
|
|
||||||
});
|
|
||||||
}, [focused, setValue]);
|
|
||||||
|
|
||||||
const setText = useCallback(
|
|
||||||
(text: string | null) => {
|
|
||||||
if (text == null) {
|
|
||||||
clear().catch(console.error);
|
|
||||||
} else {
|
|
||||||
writeText(text).catch(console.error);
|
|
||||||
}
|
|
||||||
if (text != '' && !disableToast) {
|
|
||||||
toast.show({
|
|
||||||
id: 'copied',
|
|
||||||
variant: 'copied',
|
|
||||||
message: 'Copied to clipboard',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setValue(text || '');
|
|
||||||
},
|
|
||||||
[disableToast, setValue, toast],
|
|
||||||
);
|
|
||||||
|
|
||||||
return [value, setText] as const;
|
|
||||||
}
|
|
||||||
27
src-web/hooks/useCopy.ts
Normal file
27
src-web/hooks/useCopy.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { clear, writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useToast } from '../components/ToastContext';
|
||||||
|
|
||||||
|
export function useCopy({ disableToast }: { disableToast?: boolean } = {}) {
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const copy = useCallback(
|
||||||
|
(text: string | null) => {
|
||||||
|
if (text == null) {
|
||||||
|
clear().catch(console.error);
|
||||||
|
} else {
|
||||||
|
writeText(text).catch(console.error);
|
||||||
|
}
|
||||||
|
if (text != '' && !disableToast) {
|
||||||
|
toast.show({
|
||||||
|
id: 'copied',
|
||||||
|
variant: 'copied',
|
||||||
|
message: 'Copied to clipboard',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[disableToast, toast],
|
||||||
|
);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||||
import { useClipboardText } from './useClipboardText';
|
import { useCopy } from './useCopy';
|
||||||
|
|
||||||
export function useCopyAsCurl(requestId: string) {
|
export function useCopyAsCurl(requestId: string) {
|
||||||
const [, copy] = useClipboardText();
|
const copy = useCopy();
|
||||||
const environmentId = useActiveEnvironmentId();
|
const environmentId = useActiveEnvironmentId();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ['copy_as_curl', requestId],
|
mutationKey: ['copy_as_curl', requestId],
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import { useToast } from '../components/ToastContext';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||||
|
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||||
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
||||||
import { useToast } from '../components/ToastContext';
|
|
||||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
|
||||||
import { useClipboardText } from './useClipboardText';
|
|
||||||
|
|
||||||
export function useImportCurl({ clearClipboard }: { clearClipboard?: boolean } = {}) {
|
export function useImportCurl() {
|
||||||
const workspaceId = useActiveWorkspaceId();
|
const workspaceId = useActiveWorkspaceId();
|
||||||
const updateRequest = useUpdateAnyHttpRequest();
|
const updateRequest = useUpdateAnyHttpRequest();
|
||||||
const createRequest = useCreateHttpRequest();
|
const createRequest = useCreateHttpRequest();
|
||||||
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [, setClipboardText] = useClipboardText();
|
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ['import_curl'],
|
mutationKey: ['import_curl'],
|
||||||
mutationFn: async ({ requestId, command }: { requestId: string | null; command: string }) => {
|
mutationFn: async ({
|
||||||
|
overwriteRequestId,
|
||||||
|
command,
|
||||||
|
}: {
|
||||||
|
overwriteRequestId?: string;
|
||||||
|
command: string;
|
||||||
|
}) => {
|
||||||
const request: Record<string, unknown> = await invokeCmd('cmd_curl_to_request', {
|
const request: Record<string, unknown> = await invokeCmd('cmd_curl_to_request', {
|
||||||
command,
|
command,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -25,23 +29,19 @@ export function useImportCurl({ clearClipboard }: { clearClipboard?: boolean } =
|
|||||||
delete request.id;
|
delete request.id;
|
||||||
|
|
||||||
let verb;
|
let verb;
|
||||||
if (requestId == null) {
|
if (overwriteRequestId == null) {
|
||||||
verb = 'Created';
|
verb = 'Created';
|
||||||
await createRequest.mutateAsync(request);
|
await createRequest.mutateAsync(request);
|
||||||
} else {
|
} else {
|
||||||
verb = 'Updated';
|
verb = 'Updated';
|
||||||
await updateRequest.mutateAsync({ id: requestId, update: request });
|
await updateRequest.mutateAsync({ id: overwriteRequestId, update: request });
|
||||||
setTimeout(() => wasUpdatedExternally(requestId), 100);
|
setTimeout(() => wasUpdatedExternally(overwriteRequestId), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.show({
|
toast.show({
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
message: `${verb} request from Curl`,
|
message: `${verb} request from Curl`,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (clearClipboard) {
|
|
||||||
setClipboardText(null);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user