Add prompt() plugin API (#121)

This commit is contained in:
Gregory Schier
2024-10-01 08:32:42 -07:00
committed by GitHub
parent be60e4648a
commit 7e4f807f75
26 changed files with 220 additions and 82 deletions

View File

@@ -59,8 +59,8 @@ export function CookieDropdown() {
Enter a new name for <InlineCode>{activeCookieJar?.name}</InlineCode>
</>
),
name: 'name',
label: 'Name',
confirmText: 'Save',
placeholder: 'New name',
defaultValue: activeCookieJar?.name,
});

View File

@@ -274,8 +274,8 @@ function SidebarButton({
Enter a new name for <InlineCode>{environment.name}</InlineCode>
</>
),
name: 'name',
label: 'Name',
confirmText: 'Save',
placeholder: 'New Name',
defaultValue: environment.name,
});

View File

@@ -1,6 +1,8 @@
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 { useSetAtom } from 'jotai';
import { useEffect } from 'react';
import { useEnsureActiveCookieJar, useMigrateActiveCookieJarId } from '../hooks/useActiveCookieJar';
@@ -19,6 +21,7 @@ import { keyValueQueryKey } from '../hooks/useKeyValue';
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
import { useNotificationToast } from '../hooks/useNotificationToast';
import { pluginsAtom } from '../hooks/usePlugins';
import { usePrompt } from '../hooks/usePrompt';
import { useRecentCookieJars } from '../hooks/useRecentCookieJars';
import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
import { useRecentRequests } from '../hooks/useRecentRequests';
@@ -176,6 +179,16 @@ export function GlobalHooks() {
useHotKey('app.zoom_reset', zoom.zoomReset);
useListenToTauriEvent('zoom_reset', zoom.zoomReset);
const prompt = usePrompt();
useListenToTauriEvent<{ replyId: string; args: ShowPromptRequest }>(
'show_prompt',
async (event) => {
const value = await prompt(event.payload.args);
const result: ShowPromptResponse = { value };
await emit(event.payload.replyId, result);
},
);
const copy = useCopy();
useListenToTauriEvent('generate_theme_css', () => {
const themesCss = [

View File

@@ -43,9 +43,9 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
const newMethod = await prompt({
id: 'custom-method',
label: 'Http Method',
name: 'httpMethod',
defaultValue: '',
title: 'Custom Method',
confirmText: 'Save',
description: 'Enter a custom method name',
placeholder: 'CUSTOM',
});

View File

@@ -762,7 +762,7 @@ function SidebarItem({
Enter a new name for <InlineCode>{itemName}</InlineCode>
</>
),
name: 'name',
confirmText: 'Save',
label: 'Name',
placeholder: 'New Name',
defaultValue: itemName,

View File

@@ -93,6 +93,7 @@ export function TemplateFunctionDialog({ templateFunction, hide, initialTokens,
return (
<VStack className="pb-3" space={4}>
<h1 className="font-mono !text-base">{templateFunction.name}()</h1>
<VStack space={2}>
{templateFunction.args.map((a: TemplateFunctionArg, i: number) => {
switch (a.type) {

View File

@@ -62,7 +62,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
Enter a new name for <InlineCode>{activeWorkspace?.name}</InlineCode>
</>
),
name: 'name',
label: 'Name',
placeholder: 'New Name',
defaultValue: activeWorkspace?.name,

View File

@@ -13,7 +13,7 @@ export type TwigCompletionOptionNamespace = {
export type TwigCompletionOptionFunction = {
args: { name: string }[];
aliases: string[];
aliases?: string[];
type: 'function';
};
@@ -65,7 +65,7 @@ export function twigCompletion({ options }: TwigCompletionConfig) {
if (matchSegments.length < optionSegments.length) {
return [
{
label: optionSegments.slice(0, matchSegments.length).join('.'),
label: optionSegments.slice(0, matchSegments.length).join('.') + '…',
apply: optionSegments.slice(0, matchSegments.length).join('.'),
type: 'namespace',
},

View File

@@ -24,7 +24,7 @@ export type InputProps = Omit<
| 'onKeyDown'
| 'readOnly'
> & {
name: string;
name?: string;
type?: 'text' | 'password';
label: string;
hideLabel?: boolean;
@@ -41,7 +41,7 @@ export type InputProps = Omit<
rightSlot?: ReactNode;
size?: 'xs' | 'sm' | 'md' | 'auto';
className?: string;
placeholder: string;
placeholder?: string;
validate?: boolean | ((v: string) => boolean);
require?: boolean;
wrapLines?: boolean;

View File

@@ -519,8 +519,7 @@ function PairEditorRow({
label: 'Content-Type',
placeholder: 'text/plain',
defaultValue: pairContainer.pair.contentType ?? '',
name: 'content-type',
confirmLabel: 'Set',
confirmText: 'Set',
description: 'Leave blank to auto-detect',
});
handleChangeValueContentType(v);

View File

@@ -1,30 +1,25 @@
import type { FormEvent } from 'react';
import type { ShowPromptRequest } from '@yaakapp-internal/plugin';
import type { FormEvent, ReactNode } from 'react';
import { useCallback, useState } from 'react';
import { Button } from '../components/core/Button';
import type { InputProps } from '../components/core/Input';
import { PlainInput } from '../components/core/PlainInput';
import { HStack } from '../components/core/Stacks';
export interface PromptProps {
export type PromptProps = Omit<ShowPromptRequest, 'id' | 'title' | 'description'> & {
description?: ReactNode;
onHide: () => void;
onResult: (value: string) => void;
label: InputProps['label'];
name: InputProps['name'];
defaultValue: InputProps['defaultValue'];
placeholder: InputProps['placeholder'];
require?: InputProps['require'];
confirmLabel?: string;
}
};
export function Prompt({
onHide,
label,
name,
defaultValue,
placeholder,
onResult,
require = true,
confirmLabel = 'Save',
require,
confirmText,
cancelText,
}: PromptProps) {
const [value, setValue] = useState<string>(defaultValue ?? '');
const handleSubmit = useCallback(
@@ -45,18 +40,17 @@ export function Prompt({
hideLabel
autoSelect
require={require}
placeholder={placeholder}
placeholder={placeholder ?? 'Enter text'}
label={label}
name={name}
defaultValue={defaultValue}
onChange={setValue}
/>
<HStack space={2} justifyContent="end">
<Button onClick={onHide} variant="border" color="secondary">
Cancel
{cancelText || 'Cancel'}
</Button>
<Button type="submit" color="primary">
{confirmLabel}
{confirmText || 'Done'}
</Button>
</HStack>
</form>

View File

@@ -17,9 +17,9 @@ export function useCreateCookieJar() {
}
const name = await prompt({
id: 'new-cookie-jar',
name: 'name',
title: 'New CookieJar',
placeholder: 'My Jar',
confirmText: 'Create',
label: 'Name',
defaultValue: 'My Jar',
});

View File

@@ -16,12 +16,12 @@ export function useCreateEnvironment() {
mutationFn: async () => {
const name = await prompt({
id: 'new-environment',
name: 'name',
title: 'New Environment',
description: 'Create multiple environments with different sets of variables',
label: 'Name',
placeholder: 'My Environment',
defaultValue: 'My Environment',
confirmText: 'Create',
});
return invokeCmd('cmd_create_environment', {
name,

View File

@@ -19,11 +19,10 @@ export function useCreateFolder() {
patch.name ||
(await prompt({
id: 'new-folder',
name: 'name',
label: 'Name',
defaultValue: 'Folder',
title: 'New Folder',
confirmLabel: 'Create',
confirmText: 'Create',
placeholder: 'Name',
}));
patch.sortPriority = patch.sortPriority || -Date.now();

View File

@@ -12,12 +12,11 @@ export function useCreateWorkspace() {
mutationFn: async () => {
const name = await prompt({
id: 'new-workspace',
name: 'name',
label: 'Name',
defaultValue: 'My Workspace',
title: 'New Workspace',
confirmLabel: 'Create',
placeholder: 'My Workspace',
confirmText: 'Create',
});
return invokeCmd('cmd_create_workspace', { name });
},

View File

@@ -16,6 +16,7 @@ export function useHttpRequestActions() {
const responses = (await invokeCmd(
'cmd_http_request_actions',
)) as GetHttpRequestActionsResponse[];
console.log('REQUEST ACTIONS', responses);
return responses;
},
});

View File

@@ -3,20 +3,12 @@ import { useDialog } from '../components/DialogContext';
import type { PromptProps } from './Prompt';
import { Prompt } from './Prompt';
type Props = Pick<DialogProps, 'title' | 'description'> &
Omit<PromptProps, 'onResult' | 'onHide'> & { id: string };
export function usePrompt() {
const dialog = useDialog();
return ({
id,
title,
description,
name,
label,
defaultValue,
placeholder,
confirmLabel,
require,
}: Pick<DialogProps, 'title' | 'description'> &
Omit<PromptProps, 'onResult' | 'onHide'> & { id: string }) =>
return ({ id, title, description, ...props }: Props) =>
new Promise((onResult: PromptProps['onResult']) => {
dialog.show({
id,
@@ -24,17 +16,7 @@ export function usePrompt() {
description,
hideX: true,
size: 'sm',
render: ({ hide }) =>
Prompt({
onHide: hide,
onResult,
name,
label,
defaultValue,
placeholder,
confirmLabel,
require,
}),
render: ({ hide: onHide }) => Prompt({ onHide, onResult, ...props }),
});
});
}

View File

@@ -28,10 +28,10 @@ export function useRenameRequest(requestId: string | null) {
Enter a new name for <InlineCode>{request.name}</InlineCode>
</>
),
name: 'name',
label: 'Name',
placeholder: 'New Name',
defaultValue: request.name,
confirmText: 'Save',
});
if (request.model === 'http_request') {
updateHttpRequest.mutate({ id: request.id, update: (r: HttpRequest) => ({ ...r, name }) });