mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-05-01 21:14:17 +02:00
Make prompt() to return null on cancel
This commit is contained in:
@@ -64,6 +64,7 @@ export function CookieDropdown() {
|
||||
placeholder: 'New name',
|
||||
defaultValue: activeCookieJar?.name,
|
||||
});
|
||||
if (name == null) return;
|
||||
updateCookieJar.mutate({ name });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Dialog } from './core/Dialog';
|
||||
type DialogEntry = {
|
||||
id: string;
|
||||
render: ({ hide }: { hide: () => void }) => React.ReactNode;
|
||||
} & Omit<DialogProps, 'onClose' | 'open' | 'children'>;
|
||||
} & Omit<DialogProps, 'open' | 'children'>;
|
||||
|
||||
interface State {
|
||||
dialogs: DialogEntry[];
|
||||
|
||||
@@ -279,6 +279,7 @@ function SidebarButton({
|
||||
placeholder: 'New Name',
|
||||
defaultValue: environment.name,
|
||||
});
|
||||
if (name == null) return;
|
||||
updateEnvironment.mutate({ name });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useQueryClient } from '@tanstack/react-query';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import type { AnyModel } from '@yaakapp-internal/models';
|
||||
import type { ShowPromptRequest, ShowPromptResponse } from '@yaakapp-internal/plugin';
|
||||
import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugin';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { useEnsureActiveCookieJar, useMigrateActiveCookieJarId } from '../hooks/useActiveCookieJar';
|
||||
@@ -180,11 +180,11 @@ export function GlobalHooks() {
|
||||
useListenToTauriEvent('zoom_reset', zoom.zoomReset);
|
||||
|
||||
const prompt = usePrompt();
|
||||
useListenToTauriEvent<{ replyId: string; args: ShowPromptRequest }>(
|
||||
useListenToTauriEvent<{ replyId: string; args: PromptTextRequest }>(
|
||||
'show_prompt',
|
||||
async (event) => {
|
||||
const value = await prompt(event.payload.args);
|
||||
const result: ShowPromptResponse = { value };
|
||||
const result: PromptTextResponse = { value };
|
||||
await emit(event.payload.replyId, result);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -49,6 +49,7 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
|
||||
description: 'Enter a custom method name',
|
||||
placeholder: 'CUSTOM',
|
||||
});
|
||||
if (newMethod == null) return;
|
||||
onChange(newMethod);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -767,6 +767,7 @@ function SidebarItem({
|
||||
placeholder: 'New Name',
|
||||
defaultValue: itemName,
|
||||
});
|
||||
if (name == null) return;
|
||||
updateAnyFolder.mutate({ id: itemId, update: (f) => ({ ...f, name }) });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,11 +2,13 @@ import type {
|
||||
TemplateFunction,
|
||||
TemplateFunctionArg,
|
||||
TemplateFunctionCheckboxArg,
|
||||
TemplateFunctionFileArg,
|
||||
TemplateFunctionHttpRequestArg,
|
||||
TemplateFunctionSelectArg,
|
||||
TemplateFunctionTextArg,
|
||||
} from '@yaakapp-internal/plugin';
|
||||
import type { FnArg, Tokens } from '@yaakapp-internal/template';
|
||||
import classNames from 'classnames';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useDebouncedValue } from '../hooks/useDebouncedValue';
|
||||
@@ -20,6 +22,7 @@ import { InlineCode } from './core/InlineCode';
|
||||
import { PlainInput } from './core/PlainInput';
|
||||
import { Select } from './core/Select';
|
||||
import { VStack } from './core/Stacks';
|
||||
import { SelectFile } from './SelectFile';
|
||||
|
||||
const NULL_ARG = '__NULL__';
|
||||
|
||||
@@ -50,8 +53,8 @@ export function TemplateFunctionDialog({ templateFunction, hide, initialTokens,
|
||||
return initial;
|
||||
});
|
||||
|
||||
const setArgValue = useCallback((name: string, value: string | boolean) => {
|
||||
setArgValues((v) => ({ ...v, [name]: value }));
|
||||
const setArgValue = useCallback((name: string, value: string | boolean | null) => {
|
||||
setArgValues((v) => ({ ...v, [name]: value == null ? '__NULL__' : value }));
|
||||
}, []);
|
||||
|
||||
const tokens: Tokens = useMemo(() => {
|
||||
@@ -90,6 +93,7 @@ export function TemplateFunctionDialog({ templateFunction, hide, initialTokens,
|
||||
|
||||
const debouncedTagText = useDebouncedValue(tagText.data ?? '', 200);
|
||||
const rendered = useRenderTemplate(debouncedTagText);
|
||||
const tooLarge = (rendered.data ?? '').length > 10000;
|
||||
|
||||
return (
|
||||
<VStack className="pb-3" space={4}>
|
||||
@@ -133,10 +137,29 @@ export function TemplateFunctionDialog({ templateFunction, hide, initialTokens,
|
||||
value={argValues[a.name] ? String(argValues[a.name]) : '__ERROR__'}
|
||||
/>
|
||||
);
|
||||
case 'file':
|
||||
return (
|
||||
<FileArg
|
||||
key={i}
|
||||
arg={a}
|
||||
onChange={(v) => setArgValue(a.name, v)}
|
||||
filePath={argValues[a.name] ? String(argValues[a.name]) : '__ERROR__'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</VStack>
|
||||
<InlineCode className="select-text cursor-text">{rendered.data || <> </>}</InlineCode>
|
||||
<VStack className="w-full">
|
||||
<div className="text-sm text-text-subtle">Preview</div>
|
||||
<InlineCode
|
||||
className={classNames(
|
||||
'whitespace-pre select-text cursor-text max-h-[10rem] overflow-y-auto hide-scrollbars',
|
||||
tooLarge && 'italic text-danger',
|
||||
)}
|
||||
>
|
||||
{tooLarge ? 'too large to preview' : rendered.data || <> </>}
|
||||
</InlineCode>
|
||||
</VStack>
|
||||
<Button color="primary" onClick={handleDone}>
|
||||
Done
|
||||
</Button>
|
||||
@@ -165,7 +188,13 @@ function TextArg({
|
||||
name={arg.name}
|
||||
onChange={handleChange}
|
||||
defaultValue={value === NULL_ARG ? '' : value}
|
||||
label={arg.label ?? arg.name}
|
||||
require={!arg.optional}
|
||||
label={
|
||||
<>
|
||||
{arg.label ?? arg.name}
|
||||
{arg.optional && <span> (optional)</span>}
|
||||
</>
|
||||
}
|
||||
hideLabel={arg.label == null}
|
||||
placeholder={arg.placeholder ?? arg.defaultValue ?? ''}
|
||||
/>
|
||||
@@ -197,6 +226,24 @@ function SelectArg({
|
||||
);
|
||||
}
|
||||
|
||||
function FileArg({
|
||||
arg,
|
||||
filePath,
|
||||
onChange,
|
||||
}: {
|
||||
arg: TemplateFunctionFileArg;
|
||||
filePath: string;
|
||||
onChange: (v: string | null) => void;
|
||||
}) {
|
||||
return (
|
||||
<SelectFile
|
||||
onChange={({ filePath }) => onChange(filePath)}
|
||||
filePath={filePath === '__NULL__' ? null : filePath}
|
||||
directory={!!arg.directory}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function HttpRequestArg({
|
||||
arg,
|
||||
value,
|
||||
|
||||
@@ -59,7 +59,7 @@ export function TemplateVariableDialog({ hide, onChange, initialTokens }: Props)
|
||||
/>
|
||||
</VStack>
|
||||
<VStack>
|
||||
<div className="text-sm text-text-subtle">Render Preview</div>
|
||||
<div className="text-sm text-text-subtle">Preview</div>
|
||||
<InlineCode className="select-text cursor-text">{rendered.data}</InlineCode>
|
||||
</VStack>
|
||||
<Button color="primary" onClick={handleDone}>
|
||||
|
||||
@@ -66,6 +66,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
placeholder: 'New Name',
|
||||
defaultValue: activeWorkspace?.name,
|
||||
});
|
||||
if (name == null) return;
|
||||
updateWorkspace.mutate({ name });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IconButton } from './IconButton';
|
||||
export interface DialogProps {
|
||||
children: ReactNode;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onClose?: () => void;
|
||||
title?: ReactNode;
|
||||
description?: ReactNode;
|
||||
className?: string;
|
||||
@@ -44,7 +44,7 @@ export function Dialog({
|
||||
'Escape',
|
||||
() => {
|
||||
if (!open) return;
|
||||
onClose();
|
||||
onClose?.();
|
||||
},
|
||||
{},
|
||||
[open],
|
||||
|
||||
@@ -26,7 +26,7 @@ export type InputProps = Omit<
|
||||
> & {
|
||||
name?: string;
|
||||
type?: 'text' | 'password';
|
||||
label: string;
|
||||
label: ReactNode;
|
||||
hideLabel?: boolean;
|
||||
labelPosition?: 'top' | 'left';
|
||||
labelClassName?: string;
|
||||
|
||||
@@ -512,7 +512,7 @@ function PairEditorRow({
|
||||
leftSlot: <Icon icon="pencil" />,
|
||||
hidden: !pairContainer.pair.isFile,
|
||||
onSelect: async () => {
|
||||
const v = await prompt({
|
||||
const contentType = await prompt({
|
||||
id: 'content-type',
|
||||
require: false,
|
||||
title: 'Override Content-Type',
|
||||
@@ -522,7 +522,8 @@ function PairEditorRow({
|
||||
confirmText: 'Set',
|
||||
description: 'Leave blank to auto-detect',
|
||||
});
|
||||
handleChangeValueContentType(v);
|
||||
if (contentType == null) return;
|
||||
handleChangeValueContentType(contentType);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user