Upgrade to Tauri 2.0 (#23)

This commit is contained in:
Gregory Schier
2024-05-04 14:14:19 -07:00
committed by GitHub
parent 7f02060b9c
commit 896e3d5831
128 changed files with 20477 additions and 4114 deletions

View File

@@ -1,4 +1,4 @@
import { open } from '@tauri-apps/api/dialog';
import { open } from '@tauri-apps/plugin-dialog';
import mime from 'mime';
import { useKeyValue } from '../hooks/useKeyValue';
import type { HttpRequest } from '../lib/models';

View File

@@ -1,5 +1,5 @@
import { invoke } from '@tauri-apps/api';
import { save } from '@tauri-apps/api/dialog';
import { invoke } from '@tauri-apps/api/core';
import { save } from '@tauri-apps/plugin-dialog';
import { useState } from 'react';
import slugify from 'slugify';
import type { Workspace } from '../lib/models';

View File

@@ -1,9 +1,10 @@
import { useQueryClient } from '@tanstack/react-query';
import { appWindow } from '@tauri-apps/api/window';
import { getCurrent } from '@tauri-apps/api/webviewWindow';
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { useCommandPalette } from '../hooks/useCommandPalette';
import { cookieJarsQueryKey } from '../hooks/useCookieJars';
import { foldersQueryKey } from '../hooks/useFolders';
import { useGlobalCommands } from '../hooks/useGlobalCommands';
import { grpcConnectionsQueryKey } from '../hooks/useGrpcConnections';
import { grpcEventsQueryKey } from '../hooks/useGrpcEvents';
@@ -47,93 +48,110 @@ export function GlobalHooks() {
setPathname(location.pathname).catch(console.error);
}, [location.pathname]);
useListenToTauriEvent<Model>('upserted_model', ({ payload, windowLabel }) => {
interface ModelPayload {
model: Model;
windowLabel: string;
}
useListenToTauriEvent<ModelPayload>('upserted_model', ({ payload }) => {
const { model, windowLabel } = payload;
const queryKey =
payload.model === 'http_request'
? httpRequestsQueryKey(payload)
: payload.model === 'http_response'
? httpResponsesQueryKey(payload)
: payload.model === 'grpc_connection'
? grpcConnectionsQueryKey(payload)
: payload.model === 'grpc_event'
? grpcEventsQueryKey(payload)
: payload.model === 'grpc_request'
? grpcRequestsQueryKey(payload)
: payload.model === 'workspace'
? workspacesQueryKey(payload)
: payload.model === 'key_value'
? keyValueQueryKey(payload)
: payload.model === 'cookie_jar'
? cookieJarsQueryKey(payload)
: payload.model === 'settings'
model.model === 'http_request'
? httpRequestsQueryKey(model)
: model.model === 'http_response'
? httpResponsesQueryKey(model)
: model.model === 'folder'
? foldersQueryKey(model)
: model.model === 'grpc_connection'
? grpcConnectionsQueryKey(model)
: model.model === 'grpc_event'
? grpcEventsQueryKey(model)
: model.model === 'grpc_request'
? grpcRequestsQueryKey(model)
: model.model === 'workspace'
? workspacesQueryKey(model)
: model.model === 'key_value'
? keyValueQueryKey(model)
: model.model === 'cookie_jar'
? cookieJarsQueryKey(model)
: model.model === 'settings'
? settingsQueryKey()
: null;
if (queryKey === null) {
console.log('Unrecognized updated model:', payload);
console.log('Unrecognized updated model:', model);
return;
}
if (payload.model === 'http_request' && windowLabel !== appWindow.label) {
wasUpdatedExternally(payload.id);
if (model.model === 'http_request' && windowLabel !== getCurrent().label) {
wasUpdatedExternally(model.id);
}
const pushToFront = (['http_response', 'grpc_connection'] as Model['model'][]).includes(
payload.model,
model.model,
);
if (shouldIgnoreModel(payload)) return;
if (shouldIgnoreModel(model)) return;
queryClient.setQueryData<Model[]>(queryKey, (values = []) => {
const index = values.findIndex((v) => modelsEq(v, payload)) ?? -1;
const index = values.findIndex((v) => modelsEq(v, model)) ?? -1;
if (index >= 0) {
// console.log('UPDATED', payload);
return [...values.slice(0, index), payload, ...values.slice(index + 1)];
return [...values.slice(0, index), model, ...values.slice(index + 1)];
} else {
// console.log('CREATED', payload);
return pushToFront ? [payload, ...(values ?? [])] : [...(values ?? []), payload];
return pushToFront ? [model, ...(values ?? [])] : [...(values ?? []), model];
}
});
});
useListenToTauriEvent<Model>('deleted_model', ({ payload }) => {
if (shouldIgnoreModel(payload)) return;
useListenToTauriEvent<ModelPayload>('deleted_model', ({ payload }) => {
const { model } = payload;
if (shouldIgnoreModel(model)) return;
if (payload.model === 'workspace') {
queryClient.setQueryData(workspacesQueryKey(), removeById(payload));
} else if (payload.model === 'http_request') {
queryClient.setQueryData(httpRequestsQueryKey(payload), removeById(payload));
} else if (payload.model === 'http_response') {
queryClient.setQueryData(httpResponsesQueryKey(payload), removeById(payload));
} else if (payload.model === 'grpc_request') {
queryClient.setQueryData(grpcRequestsQueryKey(payload), removeById(payload));
} else if (payload.model === 'grpc_connection') {
queryClient.setQueryData(grpcConnectionsQueryKey(payload), removeById(payload));
} else if (payload.model === 'grpc_event') {
queryClient.setQueryData(grpcEventsQueryKey(payload), removeById(payload));
} else if (payload.model === 'key_value') {
queryClient.setQueryData(keyValueQueryKey(payload), undefined);
} else if (payload.model === 'cookie_jar') {
queryClient.setQueryData(cookieJarsQueryKey(payload), undefined);
} else if (payload.model === 'settings') {
if (model.model === 'workspace') {
queryClient.setQueryData(workspacesQueryKey(), removeById(model));
} else if (model.model === 'http_request') {
queryClient.setQueryData(httpRequestsQueryKey(model), removeById(model));
} else if (model.model === 'http_response') {
queryClient.setQueryData(httpResponsesQueryKey(model), removeById(model));
} else if (model.model === 'folder') {
queryClient.setQueryData(foldersQueryKey(model), removeById(model));
} else if (model.model === 'grpc_request') {
queryClient.setQueryData(grpcRequestsQueryKey(model), removeById(model));
} else if (model.model === 'grpc_connection') {
queryClient.setQueryData(grpcConnectionsQueryKey(model), removeById(model));
} else if (model.model === 'grpc_event') {
queryClient.setQueryData(grpcEventsQueryKey(model), removeById(model));
} else if (model.model === 'key_value') {
queryClient.setQueryData(keyValueQueryKey(model), undefined);
} else if (model.model === 'cookie_jar') {
queryClient.setQueryData(cookieJarsQueryKey(model), undefined);
} else if (model.model === 'settings') {
queryClient.setQueryData(settingsQueryKey(), undefined);
}
});
useListenToTauriEvent<number>('zoom', ({ payload: zoomDelta, windowLabel }) => {
if (windowLabel !== appWindow.label) return;
const fontSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
let newFontSize;
if (zoomDelta === 0) {
newFontSize = DEFAULT_FONT_SIZE;
} else if (zoomDelta > 0) {
newFontSize = Math.min(fontSize * 1.1, DEFAULT_FONT_SIZE * 5);
} else if (zoomDelta < 0) {
newFontSize = Math.max(fontSize * 0.9, DEFAULT_FONT_SIZE * 0.4);
}
useListenToTauriEvent<number>(
'zoom',
({ payload: zoomDelta }) => {
const fontSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
document.documentElement.style.fontSize = `${newFontSize}px`;
});
let newFontSize;
if (zoomDelta === 0) {
newFontSize = DEFAULT_FONT_SIZE;
} else if (zoomDelta > 0) {
newFontSize = Math.min(fontSize * 1.1, DEFAULT_FONT_SIZE * 5);
} else if (zoomDelta < 0) {
newFontSize = Math.max(fontSize * 0.9, DEFAULT_FONT_SIZE * 0.4);
}
document.documentElement.style.fontSize = `${newFontSize}px`;
},
{
target: { kind: 'WebviewWindow', label: getCurrent().label },
},
);
return null;
}

View File

@@ -1,4 +1,4 @@
import { open } from '@tauri-apps/api/dialog';
import { open } from '@tauri-apps/plugin-dialog';
import { useGrpc } from '../hooks/useGrpc';
import { useGrpcProtoFiles } from '../hooks/useGrpcProtoFiles';
import { useGrpcRequest } from '../hooks/useGrpcRequest';
@@ -47,8 +47,10 @@ export function GrpcProtoSelection({ requestId }: Props) {
multiple: true,
filters: [{ name: 'Proto Files', extensions: ['proto'] }],
});
if (files == null || typeof files === 'string') return;
const newFiles = files.filter((f) => !protoFiles.includes(f));
if (files == null) {
return;
}
const newFiles = files.map((f) => f.path).filter((p) => !protoFiles.includes(p));
await protoFilesKv.set([...protoFiles, ...newFiles]);
await grpc.reflect.refetch();
}}

View File

@@ -19,6 +19,7 @@ const radioItems: RadioDropdownItem<string>[] = [
'PATCH',
'DELETE',
'OPTIONS',
'QUERY',
'HEAD',
].map((m) => ({
value: m,
@@ -33,7 +34,6 @@ export const RequestMethodDropdown = memo(function RequestMethodDropdown({
const prompt = usePrompt();
const extraItems = useMemo<DropdownItem[]>(
() => [
{ type: 'separator' },
{
key: 'custom',
label: 'CUSTOM',

View File

@@ -1,4 +1,4 @@
import { shell } from '@tauri-apps/api';
import { open } from '@tauri-apps/plugin-shell';
import type { HttpResponse } from '../lib/models';
import { IconButton } from './core/IconButton';
import { KeyValueRow, KeyValueRows } from './core/KeyValueRow';
@@ -28,7 +28,7 @@ export function ResponseHeaders({ response }: Props) {
iconSize="sm"
className="inline-block w-auto ml-1 !h-auto opacity-50 hover:opacity-100"
icon="externalLink"
onClick={() => shell.open(response.url)}
onClick={() => open(response.url)}
title="Open in browser"
/>
</div>

View File

@@ -1,4 +1,4 @@
import { shell } from '@tauri-apps/api';
import { open } from '@tauri-apps/plugin-shell';
import { useRef, useState } from 'react';
import { useAppInfo } from '../hooks/useAppInfo';
import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
@@ -26,6 +26,17 @@ export function SettingsDropdown() {
setShowChangelog(true);
});
const showSettings = () => {
dialog.show({
id: 'settings',
size: 'md',
title: 'Settings',
render: () => <SettingsDialog />,
});
};
useListenToTauriEvent('settings', showSettings);
return (
<Dropdown
ref={dropdownRef}
@@ -36,14 +47,7 @@ export function SettingsDropdown() {
label: 'Settings',
hotKeyAction: 'settings.show',
leftSlot: <Icon icon="settings" />,
onSelect: () => {
dialog.show({
id: 'settings',
size: 'md',
title: 'Settings',
render: () => <SettingsDialog />,
});
},
onSelect: showSettings,
},
{
key: 'hotkeys',
@@ -83,7 +87,7 @@ export function SettingsDropdown() {
label: 'Feedback',
leftSlot: <Icon icon="chat" />,
rightSlot: <Icon icon="externalLink" />,
onSelect: () => shell.open('https://yaak.canny.io'),
onSelect: () => open('https://yaak.canny.io'),
},
{
key: 'changelog',
@@ -91,7 +95,7 @@ export function SettingsDropdown() {
variant: showChangelog ? 'notify' : 'default',
leftSlot: <Icon icon="cake" />,
rightSlot: <Icon icon="externalLink" />,
onSelect: () => shell.open(`https://yaak.app/changelog/${appInfo.data?.version}`),
onSelect: () => open(`https://yaak.app/changelog/${appInfo.data?.version}`),
},
]}
>

View File

@@ -211,7 +211,7 @@ interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
function HeaderSize({ className, style, ...props }: HeaderSizeProps) {
const platform = useOsInfo();
const fullscreen = useIsFullscreen();
const stoplightsVisible = platform?.osType === 'Darwin' && !fullscreen;
const stoplightsVisible = platform?.osType === 'macos' && !fullscreen;
return (
<div
style={style}

View File

@@ -1,4 +1,4 @@
import { invoke } from '@tauri-apps/api';
import { invoke } from '@tauri-apps/api/core';
import classNames from 'classnames';
import { memo, useMemo } from 'react';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';

View File

@@ -1,6 +1,9 @@
import { getCurrent } from '@tauri-apps/api/webviewWindow';
import classNames from 'classnames';
import React, { memo, useState } from 'react';
import { useOsInfo } from '../hooks/useOsInfo';
import { CookieDropdown } from './CookieDropdown';
import { Button } from './core/Button';
import { Icon } from './core/Icon';
import { HStack } from './core/Stacks';
import { EnvironmentActionsDropdown } from './EnvironmentActionsDropdown';
@@ -8,9 +11,6 @@ import { RecentRequestsDropdown } from './RecentRequestsDropdown';
import { SettingsDropdown } from './SettingsDropdown';
import { SidebarActions } from './SidebarActions';
import { WorkspaceActionsDropdown } from './WorkspaceActionsDropdown';
import { useOsInfo } from '../hooks/useOsInfo';
import { Button } from './core/Button';
import { appWindow } from '@tauri-apps/api/window';
interface Props {
className?: string;
@@ -40,11 +40,11 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
</div>
<div className="flex-1 flex items-center h-full justify-end pointer-events-none">
<SettingsDropdown />
{(osInfo?.osType === 'Linux' || osInfo?.osType === 'Windows_NT') && (
{(osInfo?.osType === 'linux' || osInfo?.osType === 'windows') && (
<HStack className="ml-4" alignItems="center">
<Button
className="px-4 !text-gray-600 rounded-none"
onClick={() => appWindow.minimize()}
onClick={() => getCurrent().minimize()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M14 8v1H3V8z" />
@@ -53,8 +53,9 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
<Button
className="px-4 !text-gray-600 rounded-none"
onClick={async () => {
await appWindow.toggleMaximize();
setMaximized(await appWindow.isMaximized());
const w = getCurrent();
await w.toggleMaximize();
setMaximized(await w.isMaximized());
}}
>
{maximized ? (
@@ -73,7 +74,7 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
<Button
color="custom"
className="px-4 text-gray-600 rounded-none hocus:bg-red-200 hocus:text-gray-800"
onClick={() => appWindow.close()}
onClick={() => getCurrent().close()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path

View File

@@ -1,4 +1,4 @@
import { open } from '@tauri-apps/api/dialog';
import { open } from '@tauri-apps/plugin-dialog';
import classNames from 'classnames';
import type { EditorView } from 'codemirror';
import { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';

View File

@@ -1,4 +1,4 @@
import { convertFileSrc } from '@tauri-apps/api/tauri';
import { convertFileSrc } from '@tauri-apps/api/core';
import classNames from 'classnames';
import { useState } from 'react';
import type { HttpResponse } from '../../lib/models';