mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-29 21:51:59 +02:00
OAuth 2 (#158)
This commit is contained in:
@@ -26,7 +26,6 @@ export function useCreateDropdownItems({
|
||||
|
||||
return [
|
||||
{
|
||||
key: 'create-http-request',
|
||||
label: 'HTTP Request',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => {
|
||||
@@ -34,7 +33,6 @@ export function useCreateDropdownItems({
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'create-graphql-request',
|
||||
label: 'GraphQL Query',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () =>
|
||||
@@ -46,7 +44,6 @@ export function useCreateDropdownItems({
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: 'create-grpc-request',
|
||||
label: 'gRPC Call',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createGrpcRequest({ folderId }),
|
||||
@@ -54,11 +51,8 @@ export function useCreateDropdownItems({
|
||||
...((hideFolder
|
||||
? []
|
||||
: [
|
||||
{ type: 'separator' },
|
||||
{
|
||||
type: 'separator',
|
||||
},
|
||||
{
|
||||
key: 'create-folder',
|
||||
label: 'Folder',
|
||||
leftSlot: hideIcons ? undefined : <Icon icon="plus" />,
|
||||
onSelect: () => createFolder.mutate({ folderId }),
|
||||
|
||||
@@ -1,39 +1,42 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { GetHttpAuthenticationResponse } from '@yaakapp-internal/plugins';
|
||||
import type { GetHttpAuthenticationSummaryResponse } from '@yaakapp-internal/plugins';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { atom, useSetAtom } from 'jotai/index';
|
||||
import { atom } from 'jotai/index';
|
||||
import { useState } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { showErrorToast } from '../lib/toast';
|
||||
import { usePluginsKey } from './usePlugins';
|
||||
|
||||
const httpAuthenticationAtom = atom<GetHttpAuthenticationResponse[]>([]);
|
||||
const httpAuthenticationSummariesAtom = atom<GetHttpAuthenticationSummaryResponse[]>([]);
|
||||
const orderedHttpAuthenticationAtom = atom((get) =>
|
||||
get(httpAuthenticationAtom).sort((a, b) => a.name.localeCompare(b.name)),
|
||||
get(httpAuthenticationSummariesAtom)?.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
);
|
||||
|
||||
export function useHttpAuthentication() {
|
||||
export function useHttpAuthenticationSummaries() {
|
||||
return useAtomValue(orderedHttpAuthenticationAtom);
|
||||
}
|
||||
|
||||
export function useSubscribeHttpAuthentication() {
|
||||
const [numResults, setNumResults] = useState<number>(0);
|
||||
const setAtom = useSetAtom(httpAuthenticationAtom);
|
||||
const pluginsKey = usePluginsKey();
|
||||
|
||||
useQuery({
|
||||
queryKey: ['http_authentication'],
|
||||
queryKey: ['http_authentication_summaries', pluginsKey],
|
||||
// Fetch periodically until functions are returned
|
||||
// NOTE: visibilitychange (refetchOnWindowFocus) does not work on Windows, so we'll rely on this logic
|
||||
// to refetch things until that's working again
|
||||
// TODO: Update plugin system to wait for plugins to initialize before sending the first event to them
|
||||
refetchInterval: numResults > 0 ? Infinity : 1000,
|
||||
refetchOnMount: true,
|
||||
placeholderData: (prev) => prev, // Keep previous data on refetch
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const result = await invokeCmd<GetHttpAuthenticationResponse[]>(
|
||||
'cmd_get_http_authentication',
|
||||
const result = await invokeCmd<GetHttpAuthenticationSummaryResponse[]>(
|
||||
'cmd_get_http_authentication_summaries',
|
||||
);
|
||||
setNumResults(result.length);
|
||||
setAtom(result);
|
||||
jotaiStore.set(httpAuthenticationSummariesAtom, result);
|
||||
return result;
|
||||
} catch (err) {
|
||||
showErrorToast('http-authentication-error', err);
|
||||
|
||||
59
src-web/hooks/useHttpAuthenticationConfig.ts
Normal file
59
src-web/hooks/useHttpAuthenticationConfig.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||
import type { GetHttpAuthenticationConfigResponse, JsonPrimitive } from '@yaakapp-internal/plugins';
|
||||
import { md5 } from 'js-md5';
|
||||
import { useState } from 'react';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useHttpResponses } from './useHttpResponses';
|
||||
|
||||
export function useHttpAuthenticationConfig(
|
||||
authName: string | null,
|
||||
values: Record<string, JsonPrimitive>,
|
||||
requestId: string,
|
||||
) {
|
||||
const responses = useHttpResponses();
|
||||
const [forceRefreshCounter, setForceRefreshCounter] = useState<number>(0);
|
||||
|
||||
// Some auth handlers like OAuth 2.0 show the current token after a successful request. To
|
||||
// handle that, we'll force the auth to re-fetch after each new response closes
|
||||
const responseKey = md5(
|
||||
responses
|
||||
.filter((r) => r.state === 'closed')
|
||||
.map((r) => r.id)
|
||||
.join(':'),
|
||||
);
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['http_authentication_config', requestId, authName, values, responseKey, forceRefreshCounter],
|
||||
placeholderData: (prev) => prev, // Keep previous data on refetch
|
||||
queryFn: async () => {
|
||||
const config = await invokeCmd<GetHttpAuthenticationConfigResponse>(
|
||||
'cmd_get_http_authentication_config',
|
||||
{
|
||||
authName,
|
||||
values,
|
||||
requestId,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
...config,
|
||||
actions: config.actions?.map((a, i) => ({
|
||||
...a,
|
||||
call: async ({ id: requestId }: HttpRequest | GrpcRequest) => {
|
||||
await invokeCmd('cmd_call_http_authentication_action', {
|
||||
pluginRefId: config.pluginRefId,
|
||||
actionIndex: i,
|
||||
authName,
|
||||
values,
|
||||
requestId,
|
||||
});
|
||||
|
||||
// Ensure the config is refreshed after the action is done
|
||||
setForceRefreshCounter((c) => c + 1);
|
||||
},
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -5,11 +5,11 @@ import type {
|
||||
GetHttpRequestActionsResponse,
|
||||
HttpRequestAction,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
import { useMemo } from 'react';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { usePluginsKey } from './usePlugins';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export type CallableHttpRequestAction = Pick<HttpRequestAction, 'key' | 'label' | 'icon'> & {
|
||||
export type CallableHttpRequestAction = Pick<HttpRequestAction, 'label' | 'icon'> & {
|
||||
call: (httpRequest: HttpRequest) => Promise<void>;
|
||||
};
|
||||
|
||||
@@ -24,13 +24,12 @@ export function useHttpRequestActions() {
|
||||
);
|
||||
|
||||
return responses.flatMap((r) =>
|
||||
r.actions.map((a) => ({
|
||||
key: a.key,
|
||||
r.actions.map((a, i) => ({
|
||||
label: a.label,
|
||||
icon: a.icon,
|
||||
call: async (httpRequest: HttpRequest) => {
|
||||
const payload: CallHttpRequestActionRequest = {
|
||||
key: a.key,
|
||||
index: i,
|
||||
pluginRefId: r.pluginRefId,
|
||||
args: { httpRequest },
|
||||
};
|
||||
|
||||
@@ -25,7 +25,6 @@ export function useNotificationToast() {
|
||||
id: payload.id,
|
||||
timeout: null,
|
||||
message: payload.message,
|
||||
color: 'custom',
|
||||
onClose: () => markRead(payload.id),
|
||||
action: ({ hide }) =>
|
||||
actionLabel && actionUrl ? (
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { GetTemplateFunctionsResponse, TemplateFunction } from '@yaakapp-in
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { useMemo, useState } from 'react';
|
||||
import type {TwigCompletionOption} from "../components/core/Editor/twig/completion";
|
||||
import type { TwigCompletionOption } from '../components/core/Editor/twig/completion';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { usePluginsKey } from './usePlugins';
|
||||
|
||||
@@ -17,8 +17,9 @@ export function useTemplateFunctionCompletionOptions(
|
||||
return (
|
||||
templateFunctions.map((fn) => {
|
||||
const NUM_ARGS = 2;
|
||||
const argsWithName = fn.args.filter((a) => 'name' in a);
|
||||
const shortArgs =
|
||||
fn.args
|
||||
argsWithName
|
||||
.slice(0, NUM_ARGS)
|
||||
.map((a) => a.name)
|
||||
.join(', ') + (fn.args.length > NUM_ARGS ? ', …' : '');
|
||||
@@ -27,7 +28,7 @@ export function useTemplateFunctionCompletionOptions(
|
||||
aliases: fn.aliases,
|
||||
type: 'function',
|
||||
description: fn.description,
|
||||
args: fn.args.map((a) => ({ name: a.name })),
|
||||
args: argsWithName.map((a) => ({ name: a.name })),
|
||||
value: null,
|
||||
label: `${fn.name}(${shortArgs})`,
|
||||
onClick: (rawTag: string, startPos: number) => onClick(fn, rawTag, startPos),
|
||||
|
||||
Reference in New Issue
Block a user