mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-21 08:21:19 +02:00
Fixed the circular imports and things
This commit is contained in:
@@ -8,6 +8,7 @@ module.exports = {
|
|||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'eslint-config-prettier',
|
'eslint-config-prettier',
|
||||||
],
|
],
|
||||||
|
plugins: ['react-refresh'],
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: ['./tsconfig.json'],
|
project: ['./tsconfig.json'],
|
||||||
@@ -32,6 +33,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
|
'react-refresh/only-export-components': 'error',
|
||||||
'jsx-a11y/no-autofocus': 'off',
|
'jsx-a11y/no-autofocus': 'off',
|
||||||
'react/react-in-jsx-scope': 'off',
|
'react/react-in-jsx-scope': 'off',
|
||||||
'import/no-unresolved': 'off',
|
'import/no-unresolved': 'off',
|
||||||
|
|||||||
53
package-lock.json
generated
53
package-lock.json
generated
@@ -1826,15 +1826,6 @@
|
|||||||
"react": ">=16.8"
|
"react": ">=16.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@remix-run/router": {
|
|
||||||
"version": "1.19.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz",
|
|
||||||
"integrity": "sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/plugin-virtual": {
|
"node_modules/@rollup/plugin-virtual": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz",
|
||||||
@@ -6580,6 +6571,16 @@
|
|||||||
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-plugin-react-refresh": {
|
||||||
|
"version": "0.4.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.16.tgz",
|
||||||
|
"integrity": "sha512-slterMlxAhov/DZO8NScf6mEeMBBXodFUolijDvrtTxyezyLoTQaa73FyYus/VbTdftd8wBgBxPMRk3poleXNQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": ">=8.40"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint-plugin-react/node_modules/brace-expansion": {
|
"node_modules/eslint-plugin-react/node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
@@ -12323,38 +12324,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
|
||||||
"version": "6.26.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.2.tgz",
|
|
||||||
"integrity": "sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@remix-run/router": "1.19.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=16.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-router-dom": {
|
|
||||||
"version": "6.26.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.2.tgz",
|
|
||||||
"integrity": "sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@remix-run/router": "1.19.2",
|
|
||||||
"react-router": "6.26.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=16.8",
|
|
||||||
"react-dom": ">=16.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-universal-interface": {
|
"node_modules/react-universal-interface": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
|
||||||
@@ -16001,7 +15970,6 @@
|
|||||||
"react-helmet-async": "^2.0.5",
|
"react-helmet-async": "^2.0.5",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-pdf": "^9.1.0",
|
"react-pdf": "^9.1.0",
|
||||||
"react-router-dom": "^6.26.2",
|
|
||||||
"react-use": "^17.5.1",
|
"react-use": "^17.5.1",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
@@ -16026,6 +15994,7 @@
|
|||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"decompress": "^4.2.1",
|
"decompress": "^4.2.1",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.16",
|
||||||
"internal-ip": "^8.0.0",
|
"internal-ip": "^8.0.0",
|
||||||
"postcss": "^8.4.45",
|
"postcss": "^8.4.45",
|
||||||
"postcss-nesting": "^13.0.0",
|
"postcss-nesting": "^13.0.0",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { fuzzyFilter } from 'fuzzbunny';
|
import { fuzzyFilter } from 'fuzzbunny';
|
||||||
import type { KeyboardEvent, ReactNode } from 'react';
|
import type { KeyboardEvent, ReactNode } from 'react';
|
||||||
@@ -11,6 +12,7 @@ import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
|
|||||||
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||||
import { useDebouncedState } from '../hooks/useDebouncedState';
|
import { useDebouncedState } from '../hooks/useDebouncedState';
|
||||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||||
|
import { useDialog } from '../hooks/useDialog';
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
import type { HotkeyAction } from '../hooks/useHotKey';
|
import type { HotkeyAction } from '../hooks/useHotKey';
|
||||||
import { useHotKey } from '../hooks/useHotKey';
|
import { useHotKey } from '../hooks/useHotKey';
|
||||||
@@ -27,8 +29,6 @@ import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
|||||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import { CookieDialog } from './CookieDialog';
|
import { CookieDialog } from './CookieDialog';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Heading } from './core/Heading';
|
import { Heading } from './core/Heading';
|
||||||
@@ -37,7 +37,6 @@ import { HttpMethodTag } from './core/HttpMethodTag';
|
|||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { PlainInput } from './core/PlainInput';
|
import { PlainInput } from './core/PlainInput';
|
||||||
import { HStack } from './core/Stacks';
|
import { HStack } from './core/Stacks';
|
||||||
import { useDialog } from './DialogContext';
|
|
||||||
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
||||||
|
|
||||||
interface CommandPaletteGroup {
|
interface CommandPaletteGroup {
|
||||||
@@ -78,6 +77,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
||||||
const [, setSidebarHidden] = useSidebarHidden();
|
const [, setSidebarHidden] = useSidebarHidden();
|
||||||
const openSettings = useOpenSettings();
|
const openSettings = useOpenSettings();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const workspaceCommands = useMemo<CommandPaletteItem[]>(() => {
|
const workspaceCommands = useMemo<CommandPaletteItem[]>(() => {
|
||||||
const commands: CommandPaletteItem[] = [
|
const commands: CommandPaletteItem[] = [
|
||||||
@@ -267,9 +267,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
<div className="truncate">{fallbackRequestName(r)}</div>
|
<div className="truncate">{fallbackRequestName(r)}</div>
|
||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
onSelect: () => {
|
onSelect: async () => {
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: {
|
params: {
|
||||||
workspaceId: r.workspaceId,
|
workspaceId: r.workspaceId,
|
||||||
requestId: r.id,
|
requestId: r.id,
|
||||||
@@ -315,8 +315,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
|||||||
}, [
|
}, [
|
||||||
workspaceCommands,
|
workspaceCommands,
|
||||||
sortedRequests,
|
sortedRequests,
|
||||||
activeEnvironment?.id,
|
navigate,
|
||||||
sortedEnvironments,
|
sortedEnvironments,
|
||||||
|
activeEnvironment?.id,
|
||||||
setActiveEnvironmentId,
|
setActiveEnvironmentId,
|
||||||
sortedWorkspaces,
|
sortedWorkspaces,
|
||||||
openWorkspace,
|
openWorkspace,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Dropdown, type DropdownItem } from './core/Dropdown';
|
|||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
|
|
||||||
export function CookieDropdown() {
|
export function CookieDropdown() {
|
||||||
const cookieJars = useCookieJars() ?? [];
|
const cookieJars = useCookieJars() ?? [];
|
||||||
|
|||||||
@@ -1,80 +1,5 @@
|
|||||||
import React, { createContext, useContext, useMemo, useState } from 'react';
|
import { createContext } from 'react';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import type { DialogState } from './Dialogs';
|
||||||
import type { DialogProps } from './core/Dialog';
|
|
||||||
import { Dialog } from './core/Dialog';
|
|
||||||
|
|
||||||
type DialogEntry = {
|
|
||||||
id: string;
|
|
||||||
render: ({ hide }: { hide: () => void }) => React.ReactNode;
|
|
||||||
} & Omit<DialogProps, 'open' | 'children'>;
|
|
||||||
|
|
||||||
interface State {
|
|
||||||
dialogs: DialogEntry[];
|
|
||||||
actions: Actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Actions {
|
|
||||||
show: (d: DialogEntry) => void;
|
|
||||||
toggle: (d: DialogEntry) => void;
|
|
||||||
hide: (id: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const DialogContext = createContext<State>({} as State);
|
export const DialogContext = createContext<DialogState>({} as DialogState);
|
||||||
|
|
||||||
export const DialogProvider = ({ children }: { children: React.ReactNode }) => {
|
|
||||||
const [dialogs, setDialogs] = useState<State['dialogs']>([]);
|
|
||||||
const actions = useMemo<Actions>(
|
|
||||||
() => ({
|
|
||||||
show({ id, ...props }: DialogEntry) {
|
|
||||||
trackEvent('dialog', 'show', { id });
|
|
||||||
setDialogs((a) => [...a.filter((d) => d.id !== id), { id, ...props }]);
|
|
||||||
},
|
|
||||||
toggle({ id, ...props }: DialogEntry) {
|
|
||||||
if (dialogs.some((d) => d.id === id)) this.hide(id);
|
|
||||||
else this.show({ id, ...props });
|
|
||||||
},
|
|
||||||
hide: (id: string) => {
|
|
||||||
setDialogs((a) => a.filter((d) => d.id !== id));
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[dialogs],
|
|
||||||
);
|
|
||||||
|
|
||||||
const state: State = {
|
|
||||||
dialogs,
|
|
||||||
actions,
|
|
||||||
};
|
|
||||||
|
|
||||||
return <DialogContext.Provider value={state}>{children}</DialogContext.Provider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
function DialogInstance({ id, render, onClose, ...props }: DialogEntry) {
|
|
||||||
const { actions } = useContext(DialogContext);
|
|
||||||
const children = render({ hide: () => actions.hide(id) });
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
open
|
|
||||||
onClose={() => {
|
|
||||||
onClose?.();
|
|
||||||
actions.hide(id);
|
|
||||||
}}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useDialog = () => useContext(DialogContext).actions;
|
|
||||||
|
|
||||||
export function Dialogs() {
|
|
||||||
const { dialogs } = useContext(DialogContext);
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{dialogs.map((props: DialogEntry) => (
|
|
||||||
<DialogInstance key={props.id} {...props} />
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
75
src-web/components/Dialogs.tsx
Normal file
75
src-web/components/Dialogs.tsx
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import React, { useContext, useMemo, useState } from 'react';
|
||||||
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { Dialog, type DialogProps } from './core/Dialog';
|
||||||
|
import { DialogContext } from './DialogContext';
|
||||||
|
|
||||||
|
type DialogEntry = {
|
||||||
|
id: string;
|
||||||
|
render: ({ hide }: { hide: () => void }) => React.ReactNode;
|
||||||
|
} & Omit<DialogProps, 'open' | 'children'>;
|
||||||
|
|
||||||
|
export interface DialogState {
|
||||||
|
dialogs: DialogEntry[];
|
||||||
|
actions: Actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Actions {
|
||||||
|
show: (d: DialogEntry) => void;
|
||||||
|
toggle: (d: DialogEntry) => void;
|
||||||
|
hide: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DialogProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const [dialogs, setDialogs] = useState<DialogState['dialogs']>([]);
|
||||||
|
const actions = useMemo<Actions>(
|
||||||
|
() => ({
|
||||||
|
show({ id, ...props }: DialogEntry) {
|
||||||
|
trackEvent('dialog', 'show', { id });
|
||||||
|
setDialogs((a) => [...a.filter((d) => d.id !== id), { id, ...props }]);
|
||||||
|
},
|
||||||
|
toggle({ id, ...props }: DialogEntry) {
|
||||||
|
if (dialogs.some((d) => d.id === id)) this.hide(id);
|
||||||
|
else this.show({ id, ...props });
|
||||||
|
},
|
||||||
|
hide: (id: string) => {
|
||||||
|
setDialogs((a) => a.filter((d) => d.id !== id));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[dialogs],
|
||||||
|
);
|
||||||
|
|
||||||
|
const state: DialogState = {
|
||||||
|
dialogs,
|
||||||
|
actions,
|
||||||
|
};
|
||||||
|
|
||||||
|
return <DialogContext.Provider value={state}>{children}</DialogContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DialogInstance({ id, render, onClose, ...props }: DialogEntry) {
|
||||||
|
const { actions } = useContext(DialogContext);
|
||||||
|
const children = render({ hide: () => actions.hide(id) });
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open
|
||||||
|
onClose={() => {
|
||||||
|
onClose?.();
|
||||||
|
actions.hide(id);
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Dialogs() {
|
||||||
|
const { dialogs } = useContext(DialogContext);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{dialogs.map((props: DialogEntry) => (
|
||||||
|
<DialogInstance key={props.id} {...props} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import { Button } from './core/Button';
|
|||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { updateSchema } from 'cm6-graphql';
|
import { updateSchema } from 'cm6-graphql';
|
||||||
import type { EditorView } from 'codemirror';
|
import type { EditorView } from 'codemirror';
|
||||||
|
|
||||||
|
import { formatSdl } from 'format-graphql';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useLocalStorage } from 'react-use';
|
import { useLocalStorage } from 'react-use';
|
||||||
import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL';
|
import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL';
|
||||||
import { tryFormatJson } from '../lib/formatters';
|
import { tryFormatJson } from '../lib/formatters';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import type { EditorProps } from './core/Editor';
|
import type { EditorProps } from './core/Editor/Editor';
|
||||||
import { Editor, formatGraphQL } from './core/Editor';
|
import { Editor } from './core/Editor/Editor';
|
||||||
import { FormattedError } from './core/FormattedError';
|
import { FormattedError } from './core/FormattedError';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { Separator } from './core/Separator';
|
import { Separator } from './core/Separator';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
|
|
||||||
type Props = Pick<EditorProps, 'heightMode' | 'className' | 'forceUpdateKey'> & {
|
type Props = Pick<EditorProps, 'heightMode' | 'className' | 'forceUpdateKey'> & {
|
||||||
baseRequest: HttpRequest;
|
baseRequest: HttpRequest;
|
||||||
@@ -168,7 +170,7 @@ export function GraphQLEditor({ body, onChange, baseRequest, ...extraEditorProps
|
|||||||
<Editor
|
<Editor
|
||||||
language="graphql"
|
language="graphql"
|
||||||
heightMode="auto"
|
heightMode="auto"
|
||||||
format={formatGraphQL}
|
format={formatSdl}
|
||||||
defaultValue={currentBody.query}
|
defaultValue={currentBody.query}
|
||||||
onChange={handleChangeQuery}
|
onChange={handleChangeQuery}
|
||||||
placeholder="..."
|
placeholder="..."
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import { tryFormatJson } from '../lib/formatters';
|
|||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { count } from '../lib/pluralize';
|
import { count } from '../lib/pluralize';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import type { EditorProps } from './core/Editor';
|
|
||||||
import { Editor } from './core/Editor';
|
|
||||||
import { FormattedError } from './core/FormattedError';
|
import { FormattedError } from './core/FormattedError';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
import { GrpcProtoSelection } from './GrpcProtoSelection';
|
import { GrpcProtoSelection } from './GrpcProtoSelection';
|
||||||
|
import type { EditorProps} from './core/Editor/Editor';
|
||||||
|
import {Editor} from './core/Editor/Editor';
|
||||||
|
|
||||||
type Props = Pick<EditorProps, 'heightMode' | 'onChange' | 'className'> & {
|
type Props = Pick<EditorProps, 'heightMode' | 'onChange' | 'className'> & {
|
||||||
services: ReflectResponseService[] | null;
|
services: ReflectResponseService[] | null;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { HTMLAttributes, ReactNode } from 'react';
|
import type { HTMLAttributes, ReactNode } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSettings } from '../hooks/useSettings';
|
|
||||||
import { useOsInfo } from '../hooks/useOsInfo';
|
import { useOsInfo } from '../hooks/useOsInfo';
|
||||||
|
import { useSettings } from '../hooks/useSettings';
|
||||||
import { useStoplightsVisible } from '../hooks/useStoplightsVisible';
|
import { useStoplightsVisible } from '../hooks/useStoplightsVisible';
|
||||||
import { WINDOW_CONTROLS_WIDTH, WindowControls } from './WindowControls';
|
import { HEADER_SIZE_LG, HEADER_SIZE_MD, WINDOW_CONTROLS_WIDTH } from '../lib/constants';
|
||||||
|
import { WindowControls } from './WindowControls';
|
||||||
|
|
||||||
interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
|
interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
@@ -13,9 +14,6 @@ interface HeaderSizeProps extends HTMLAttributes<HTMLDivElement> {
|
|||||||
onlyXWindowControl?: boolean;
|
onlyXWindowControl?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HEADER_SIZE_MD = '27px';
|
|
||||||
export const HEADER_SIZE_LG = '38px';
|
|
||||||
|
|
||||||
export function HeaderSize({
|
export function HeaderSize({
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
@@ -33,7 +31,8 @@ export function HeaderSize({
|
|||||||
style={{
|
style={{
|
||||||
...style,
|
...style,
|
||||||
// Add padding for macOS stoplights, but keep it the same width (account for the interface scale)
|
// Add padding for macOS stoplights, but keep it the same width (account for the interface scale)
|
||||||
paddingLeft: (stoplightsVisible && !ignoreControlsSpacing) ? 72 / settings.interfaceScale : undefined,
|
paddingLeft:
|
||||||
|
stoplightsVisible && !ignoreControlsSpacing ? 72 / settings.interfaceScale : undefined,
|
||||||
...(size === 'md' ? { height: HEADER_SIZE_MD } : {}),
|
...(size === 'md' ? { height: HEADER_SIZE_MD } : {}),
|
||||||
...(size === 'lg' ? { height: HEADER_SIZE_LG } : {}),
|
...(size === 'lg' ? { height: HEADER_SIZE_LG } : {}),
|
||||||
...(osInfo.osType === 'macos' || ignoreControlsSpacing
|
...(osInfo.osType === 'macos' || ignoreControlsSpacing
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useLicense } from '@yaakapp-internal/license';
|
|||||||
import { useOpenSettings } from '../hooks/useOpenSettings';
|
import { useOpenSettings } from '../hooks/useOpenSettings';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { SettingsTab } from './Settings/Settings';
|
import {SettingsTab} from "./Settings/SettingsTab";
|
||||||
|
|
||||||
const details: Record<
|
const details: Record<
|
||||||
LicenseCheckStatus['type'],
|
LicenseCheckStatus['type'],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useRef } from 'react';
|
|||||||
import Markdown from 'react-markdown';
|
import Markdown from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import { useKeyValue } from '../hooks/useKeyValue';
|
import { useKeyValue } from '../hooks/useKeyValue';
|
||||||
import { Editor } from './core/Editor';
|
import {Editor} from "./core/Editor/Editor";
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
import { SplitLayout } from './core/SplitLayout';
|
import { SplitLayout } from './core/SplitLayout';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { useToast } from '../hooks/useToast';
|
||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/index';
|
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
import { Select } from './core/Select';
|
import { Select } from './core/Select';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
import { useToast } from './ToastContext';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
activeWorkspaceId: string;
|
activeWorkspaceId: string;
|
||||||
@@ -23,6 +22,7 @@ export function MoveToWorkspaceDialog({ onDone, request, activeWorkspaceId }: Pr
|
|||||||
const updateHttpRequest = useUpdateAnyHttpRequest();
|
const updateHttpRequest = useUpdateAnyHttpRequest();
|
||||||
const updateGrpcRequest = useUpdateAnyGrpcRequest();
|
const updateGrpcRequest = useUpdateAnyGrpcRequest();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string>(activeWorkspaceId);
|
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string>(activeWorkspaceId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -69,10 +69,10 @@ export function MoveToWorkspaceDialog({ onDone, request, activeWorkspaceId }: Pr
|
|||||||
size="xs"
|
size="xs"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
className="mr-auto min-w-[5rem]"
|
className="mr-auto min-w-[5rem]"
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
toast.hide('workspace-moved');
|
toast.hide('workspace-moved');
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: selectedWorkspaceId },
|
params: { workspaceId: selectedWorkspaceId },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useMemo, useRef } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import { useKeyPressEvent } from 'react-use';
|
import { useKeyPressEvent } from 'react-use';
|
||||||
@@ -7,8 +8,6 @@ import { useHotKey } from '../hooks/useHotKey';
|
|||||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||||
import { useRequests } from '../hooks/useRequests';
|
import { useRequests } from '../hooks/useRequests';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import type { DropdownItem, DropdownRef } from './core/Dropdown';
|
import type { DropdownItem, DropdownRef } from './core/Dropdown';
|
||||||
@@ -22,6 +21,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
|||||||
const allRecentRequestIds = useRecentRequests();
|
const allRecentRequestIds = useRecentRequests();
|
||||||
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
||||||
const requests = useRequests();
|
const requests = useRequests();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// Handle key-up
|
// Handle key-up
|
||||||
useKeyPressEvent('Control', undefined, () => {
|
useKeyPressEvent('Control', undefined, () => {
|
||||||
@@ -52,9 +52,9 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
|||||||
label: fallbackRequestName(request),
|
label: fallbackRequestName(request),
|
||||||
// leftSlot: <CountBadge className="!ml-0 px-0 w-5" count={recentRequestItems.length} />,
|
// leftSlot: <CountBadge className="!ml-0 px-0 w-5" count={recentRequestItems.length} />,
|
||||||
leftSlot: <HttpMethodTag className="text-right" shortNames request={request} />,
|
leftSlot: <HttpMethodTag className="text-right" shortNames request={request} />,
|
||||||
onSelect: () => {
|
onSelect: async () => {
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: {
|
params: {
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
workspaceId: activeWorkspace.id,
|
workspaceId: activeWorkspace.id,
|
||||||
@@ -77,7 +77,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
|||||||
}
|
}
|
||||||
|
|
||||||
return recentRequestItems.slice(0, 20);
|
return recentRequestItems.slice(0, 20);
|
||||||
}, [activeWorkspace, recentRequestIds, requests]);
|
}, [activeWorkspace, navigate, recentRequestIds, requests]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown ref={dropdownRef} items={items}>
|
<Dropdown ref={dropdownRef} items={items}>
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { getRecentCookieJars } from '../hooks/useRecentCookieJars';
|
import { getRecentCookieJars } from '../hooks/useRecentCookieJars';
|
||||||
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
|
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
|
||||||
import { getRecentRequests } from '../hooks/useRecentRequests';
|
import { getRecentRequests } from '../hooks/useRecentRequests';
|
||||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route as WorkspaceRoute } from '../routes/workspaces/$workspaceId';
|
|
||||||
import { Route as RequestRoute } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
|
|
||||||
export function RedirectToLatestWorkspace() {
|
export function RedirectToLatestWorkspace() {
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const recentWorkspaces = useRecentWorkspaces();
|
const recentWorkspaces = useRecentWorkspaces();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (workspaces.length === 0) {
|
if (workspaces.length === 0) {
|
||||||
@@ -25,20 +24,20 @@ export function RedirectToLatestWorkspace() {
|
|||||||
const requestId = (await getRecentRequests(workspaceId))[0] ?? null;
|
const requestId = (await getRecentRequests(workspaceId))[0] ?? null;
|
||||||
|
|
||||||
if (workspaceId != null && requestId != null) {
|
if (workspaceId != null && requestId != null) {
|
||||||
await router.navigate({
|
await navigate({
|
||||||
to: RequestRoute.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: { workspaceId, requestId },
|
params: { workspaceId, requestId },
|
||||||
search: { cookieJarId, environmentId },
|
search: { cookieJarId, environmentId },
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await router.navigate({
|
await navigate({
|
||||||
to: WorkspaceRoute.fullPath,
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId },
|
params: { workspaceId },
|
||||||
search: { cookieJarId, environmentId },
|
search: { cookieJarId, environmentId },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [recentWorkspaces, workspaces, workspaces.length]);
|
}, [navigate, recentWorkspaces, workspaces, workspaces.length]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { getHttpRequest } from '../lib/store';
|
|||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
import { FolderSettingsDialog } from './FolderSettingsDialog';
|
import { FolderSettingsDialog } from './FolderSettingsDialog';
|
||||||
import type { SidebarTreeNode } from './Sidebar';
|
import type { SidebarTreeNode } from './Sidebar';
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useRequestEditor, useRequestEditorEvent } from '../hooks/useRequestEdit
|
|||||||
import { useRequests } from '../hooks/useRequests';
|
import { useRequests } from '../hooks/useRequests';
|
||||||
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
||||||
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
||||||
|
import { useToast } from '../hooks/useToast';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { languageFromContentType } from '../lib/contentType';
|
import { languageFromContentType } from '../lib/contentType';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
@@ -34,7 +35,7 @@ import { BasicAuth } from './BasicAuth';
|
|||||||
import { BearerAuth } from './BearerAuth';
|
import { BearerAuth } from './BearerAuth';
|
||||||
import { BinaryFileEditor } from './BinaryFileEditor';
|
import { BinaryFileEditor } from './BinaryFileEditor';
|
||||||
import { CountBadge } from './core/CountBadge';
|
import { CountBadge } from './core/CountBadge';
|
||||||
import { Editor } from './core/Editor';
|
import { Editor } from './core/Editor/Editor';
|
||||||
import type {
|
import type {
|
||||||
GenericCompletionConfig,
|
GenericCompletionConfig,
|
||||||
GenericCompletionOption,
|
GenericCompletionOption,
|
||||||
@@ -50,7 +51,6 @@ import { FormUrlencodedEditor } from './FormUrlencodedEditor';
|
|||||||
import { GraphQLEditor } from './GraphQLEditor';
|
import { GraphQLEditor } from './GraphQLEditor';
|
||||||
import { HeadersEditor } from './HeadersEditor';
|
import { HeadersEditor } from './HeadersEditor';
|
||||||
import { MarkdownEditor } from './MarkdownEditor';
|
import { MarkdownEditor } from './MarkdownEditor';
|
||||||
import { useToast } from './ToastContext';
|
|
||||||
import { UrlBar } from './UrlBar';
|
import { UrlBar } from './UrlBar';
|
||||||
import { UrlParametersEditor } from './UrlParameterEditor';
|
import { UrlParametersEditor } from './UrlParameterEditor';
|
||||||
|
|
||||||
@@ -446,25 +446,28 @@ export const RequestPane = memo(function RequestPane({
|
|||||||
<EmptyStateText>Empty Body</EmptyStateText>
|
<EmptyStateText>Empty Body</EmptyStateText>
|
||||||
)}
|
)}
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value={TAB_DESCRIPTION}><div className="grid grid-rows-[auto_minmax(0,1fr)] h-full">
|
<TabContent value={TAB_DESCRIPTION}>
|
||||||
<PlainInput
|
<div className="grid grid-rows-[auto_minmax(0,1fr)] h-full">
|
||||||
label="Request Name"
|
<PlainInput
|
||||||
hideLabel
|
label="Request Name"
|
||||||
defaultValue={activeRequest.name}
|
hideLabel
|
||||||
className="font-sans !text-xl !px-0"
|
defaultValue={activeRequest.name}
|
||||||
containerClassName="border-0"
|
className="font-sans !text-xl !px-0"
|
||||||
placeholder={fallbackRequestName(activeRequest)}
|
containerClassName="border-0"
|
||||||
onChange={(name) => updateRequest.mutate({ id: activeRequestId, update: { name } })}
|
placeholder={fallbackRequestName(activeRequest)}
|
||||||
/>
|
onChange={(name) =>
|
||||||
<MarkdownEditor
|
updateRequest.mutate({ id: activeRequestId, update: { name } })
|
||||||
name="request-description"
|
}
|
||||||
placeholder="A Markdown description of this request."
|
/>
|
||||||
defaultValue={activeRequest.description}
|
<MarkdownEditor
|
||||||
onChange={(description) =>
|
name="request-description"
|
||||||
updateRequest.mutate({ id: activeRequestId, update: { description } })
|
placeholder="A Markdown description of this request."
|
||||||
}
|
defaultValue={activeRequest.description}
|
||||||
/>
|
onChange={(description) =>
|
||||||
</div>
|
updateRequest.mutate({ id: activeRequestId, update: { description } })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import { useRouteError } from 'react-router-dom';
|
import { useRouteError } from 'react-router-dom';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces';
|
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { FormattedError } from './core/FormattedError';
|
import { FormattedError } from './core/FormattedError';
|
||||||
import { Heading } from './core/Heading';
|
import { Heading } from './core/Heading';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
|
|
||||||
export default function RouteError() {
|
export default function RouteError() {
|
||||||
|
const navigate = useNavigate();
|
||||||
const error = useRouteError();
|
const error = useRouteError();
|
||||||
console.log('Error', error);
|
console.log('Error', error);
|
||||||
const stringified = JSON.stringify(error);
|
const stringified = JSON.stringify(error);
|
||||||
@@ -20,8 +20,8 @@ export default function RouteError() {
|
|||||||
<VStack space={2}>
|
<VStack space={2}>
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
router.navigate({ to: Route.fullPath });
|
await navigate({ to: '/workspaces' });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Go Home
|
Go Home
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useSearch } from '@tanstack/react-router';
|
||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
@@ -12,18 +13,10 @@ import { SettingsGeneral } from './SettingsGeneral';
|
|||||||
import { SettingsLicense } from './SettingsLicense';
|
import { SettingsLicense } from './SettingsLicense';
|
||||||
import { SettingsPlugins } from './SettingsPlugins';
|
import { SettingsPlugins } from './SettingsPlugins';
|
||||||
import { SettingsProxy } from './SettingsProxy';
|
import { SettingsProxy } from './SettingsProxy';
|
||||||
|
import { SettingsTab } from './SettingsTab';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
hide?: () => void;
|
hide?: () => void;
|
||||||
defaultTab?: SettingsTab;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SettingsTab {
|
|
||||||
General = 'general',
|
|
||||||
Proxy = 'proxy',
|
|
||||||
Appearance = 'appearance',
|
|
||||||
Plugins = 'plugins',
|
|
||||||
License = 'license',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
@@ -34,9 +27,10 @@ const tabs = [
|
|||||||
SettingsTab.License,
|
SettingsTab.License,
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Settings({ hide, defaultTab }: Props) {
|
export default function Settings({ hide }: Props) {
|
||||||
const osInfo = useOsInfo();
|
const osInfo = useOsInfo();
|
||||||
const [tab, setTab] = useState<string>(defaultTab ?? SettingsTab.General);
|
const { tab: tabFromQuery } = useSearch({ from: '/workspaces/$workspaceId/settings' });
|
||||||
|
const [tab, setTab] = useState<string>(tabFromQuery ?? SettingsTab.General);
|
||||||
|
|
||||||
// Close settings window on escape
|
// Close settings window on escape
|
||||||
// TODO: Could this be put in a better place? Eg. in Rust key listener when creating the window
|
// TODO: Could this be put in a better place? Eg. in Rust key listener when creating the window
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getThemes } from '../../lib/theme/themes';
|
|||||||
import { isThemeDark } from '../../lib/theme/window';
|
import { isThemeDark } from '../../lib/theme/window';
|
||||||
import type { ButtonProps } from '../core/Button';
|
import type { ButtonProps } from '../core/Button';
|
||||||
import { Checkbox } from '../core/Checkbox';
|
import { Checkbox } from '../core/Checkbox';
|
||||||
import { Editor } from '../core/Editor';
|
import {Editor} from "../core/Editor/Editor";
|
||||||
import type { IconProps } from '../core/Icon';
|
import type { IconProps } from '../core/Icon';
|
||||||
import { Icon } from '../core/Icon';
|
import { Icon } from '../core/Icon';
|
||||||
import { IconButton } from '../core/IconButton';
|
import { IconButton } from '../core/IconButton';
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { yaakDark } from '../../lib/theme/themes/yaak';
|
|||||||
import { getThemeCSS } from '../../lib/theme/window';
|
import { getThemeCSS } from '../../lib/theme/window';
|
||||||
import { Banner } from '../core/Banner';
|
import { Banner } from '../core/Banner';
|
||||||
import { Button } from '../core/Button';
|
import { Button } from '../core/Button';
|
||||||
import { Editor } from '../core/Editor';
|
import {Editor} from "../core/Editor/Editor";
|
||||||
import type { IconProps } from '../core/Icon';
|
import type { IconProps } from '../core/Icon';
|
||||||
import { Icon } from '../core/Icon';
|
import { Icon } from '../core/Icon';
|
||||||
import { IconButton } from '../core/IconButton';
|
import { IconButton } from '../core/IconButton';
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function SettingsGeneral() {
|
|||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const updateSettings = useUpdateSettings();
|
const updateSettings = useUpdateSettings();
|
||||||
const appInfo = useAppInfo();
|
const appInfo = useAppInfo();
|
||||||
const checkForUpdates = useCheckForUpdates();
|
const checkForUpdates = useCheckForUpdates();
|
||||||
|
|
||||||
if (settings == null || workspace == null) {
|
if (settings == null || workspace == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
8
src-web/components/Settings/SettingsTab.ts
Normal file
8
src-web/components/Settings/SettingsTab.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
export enum SettingsTab {
|
||||||
|
General = 'general',
|
||||||
|
Proxy = 'proxy',
|
||||||
|
Appearance = 'appearance',
|
||||||
|
Plugins = 'plugins',
|
||||||
|
License = 'license',
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import type { DropdownRef } from './core/Dropdown';
|
|||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { IconButton } from './core/IconButton';
|
import { IconButton } from './core/IconButton';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
import { KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';
|
import { KeyboardShortcutsDialog } from './KeyboardShortcutsDialog';
|
||||||
|
|
||||||
export function SettingsDropdown() {
|
export function SettingsDropdown() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp-internal/models';
|
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp-internal/models';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { atom, useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
|
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { useKey, useKeyPressEvent } from 'react-use';
|
import { useKey, useKeyPressEvent } from 'react-use';
|
||||||
import { getActiveRequest } from '../hooks/useActiveRequest';
|
import { getActiveRequest } from '../hooks/useActiveRequest';
|
||||||
@@ -16,9 +17,8 @@ import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
|||||||
import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
|
import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
|
||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
|
import { sidebarSelectedIdAtom } from './SidebarAtoms';
|
||||||
import type { SidebarItemProps } from './SidebarItem';
|
import type { SidebarItemProps } from './SidebarItem';
|
||||||
import { SidebarItems } from './SidebarItems';
|
import { SidebarItems } from './SidebarItems';
|
||||||
|
|
||||||
@@ -32,9 +32,6 @@ export interface SidebarTreeNode {
|
|||||||
depth: number;
|
depth: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an atom so we can use it in the child items to avoid re-rendering the entire list
|
|
||||||
export const sidebarSelectedIdAtom = atom<string | null>(null);
|
|
||||||
|
|
||||||
export const Sidebar = memo(function Sidebar({ className }: Props) {
|
export const Sidebar = memo(function Sidebar({ className }: Props) {
|
||||||
const [hidden, setHidden] = useSidebarHidden();
|
const [hidden, setHidden] = useSidebarHidden();
|
||||||
const sidebarRef = useRef<HTMLLIElement>(null);
|
const sidebarRef = useRef<HTMLLIElement>(null);
|
||||||
@@ -52,6 +49,7 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
|
|||||||
const [draggingId, setDraggingId] = useState<string | null>(null);
|
const [draggingId, setDraggingId] = useState<string | null>(null);
|
||||||
const [hoveredTree, setHoveredTree] = useState<SidebarTreeNode | null>(null);
|
const [hoveredTree, setHoveredTree] = useState<SidebarTreeNode | null>(null);
|
||||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||||||
|
const navigate = useNavigate();
|
||||||
const { value: collapsed, set: setCollapsed } = useKeyValue<Record<string, boolean>>({
|
const { value: collapsed, set: setCollapsed } = useKeyValue<Record<string, boolean>>({
|
||||||
key: ['sidebar_collapsed', activeWorkspace?.id ?? 'n/a'],
|
key: ['sidebar_collapsed', activeWorkspace?.id ?? 'n/a'],
|
||||||
fallback: {},
|
fallback: {},
|
||||||
@@ -165,8 +163,8 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
|
|||||||
if (item.model === 'folder') {
|
if (item.model === 'folder') {
|
||||||
await setCollapsed((c) => ({ ...c, [item.id]: !c[item.id] }));
|
await setCollapsed((c) => ({ ...c, [item.id]: !c[item.id] }));
|
||||||
} else {
|
} else {
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: {
|
params: {
|
||||||
requestId: id,
|
requestId: id,
|
||||||
workspaceId: item.workspaceId,
|
workspaceId: item.workspaceId,
|
||||||
@@ -179,7 +177,7 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
|
|||||||
setSelectedTree(tree);
|
setSelectedTree(tree);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[treeParentMap, setCollapsed, setHasFocus, setSelectedId],
|
[treeParentMap, setCollapsed, navigate, setSelectedId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClearSelected = useCallback(() => {
|
const handleClearSelected = useCallback(() => {
|
||||||
@@ -214,7 +212,7 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
useKeyPressEvent('Enter', (e) => {
|
useKeyPressEvent('Enter', async (e) => {
|
||||||
if (!hasFocus) return;
|
if (!hasFocus) return;
|
||||||
const selected = selectableRequests.find((r) => r.id === selectedId);
|
const selected = selectableRequests.find((r) => r.id === selectedId);
|
||||||
if (!selected || activeWorkspace == null) {
|
if (!selected || activeWorkspace == null) {
|
||||||
@@ -222,8 +220,8 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: {
|
params: {
|
||||||
requestId: selected.id,
|
requestId: selected.id,
|
||||||
workspaceId: activeWorkspace?.id ?? null,
|
workspaceId: activeWorkspace?.id ?? null,
|
||||||
|
|||||||
5
src-web/components/SidebarAtoms.ts
Normal file
5
src-web/components/SidebarAtoms.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
// This is an atom so we can use it in the child items to avoid re-rendering the entire list
|
||||||
|
import {atom} from "jotai/index";
|
||||||
|
|
||||||
|
export const sidebarSelectedIdAtom = atom<string | null>(null);
|
||||||
@@ -8,14 +8,14 @@ import { activeRequestAtom } from '../hooks/useActiveRequest';
|
|||||||
import { useScrollIntoView } from '../hooks/useScrollIntoView';
|
import { useScrollIntoView } from '../hooks/useScrollIntoView';
|
||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { isResponseLoading } from '../lib/model_util';
|
import { isResponseLoading } from '../lib/model_util';
|
||||||
import { jotaiStore } from '../routes/__root';
|
|
||||||
import { HttpMethodTag } from './core/HttpMethodTag';
|
import { HttpMethodTag } from './core/HttpMethodTag';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { StatusTag } from './core/StatusTag';
|
import { StatusTag } from './core/StatusTag';
|
||||||
import { RequestContextMenu } from './RequestContextMenu';
|
import { RequestContextMenu } from './RequestContextMenu';
|
||||||
import type { SidebarTreeNode } from './Sidebar';
|
import type { SidebarTreeNode } from './Sidebar';
|
||||||
import { sidebarSelectedIdAtom } from './Sidebar';
|
import {sidebarSelectedIdAtom} from "./SidebarAtoms";
|
||||||
import type { SidebarItemsProps } from './SidebarItems';
|
import type { SidebarItemsProps } from './SidebarItems';
|
||||||
|
|
||||||
enum ItemTypes {
|
enum ItemTypes {
|
||||||
@@ -42,7 +42,7 @@ type DragItem = {
|
|||||||
itemName: string;
|
itemName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function SidebarItem_({
|
export const SidebarItem = memo(function SidebarItem({
|
||||||
itemName,
|
itemName,
|
||||||
itemId,
|
itemId,
|
||||||
itemModel,
|
itemModel,
|
||||||
@@ -106,7 +106,7 @@ function SidebarItem_({
|
|||||||
const [selected, setSelected] = useState<boolean>(
|
const [selected, setSelected] = useState<boolean>(
|
||||||
jotaiStore.get(sidebarSelectedIdAtom) == itemId,
|
jotaiStore.get(sidebarSelectedIdAtom) == itemId,
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
jotaiStore.sub(sidebarSelectedIdAtom, () => {
|
jotaiStore.sub(sidebarSelectedIdAtom, () => {
|
||||||
const value = jotaiStore.get(sidebarSelectedIdAtom);
|
const value = jotaiStore.get(sidebarSelectedIdAtom);
|
||||||
setSelected(value === itemId);
|
setSelected(value === itemId);
|
||||||
@@ -262,17 +262,4 @@ function SidebarItem_({
|
|||||||
{children}
|
{children}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
export const SidebarItem = memo<SidebarItemProps>(SidebarItem_, (a, b) => {
|
|
||||||
const different = [];
|
|
||||||
for (const key of Object.keys(a) as (keyof SidebarItemProps)[]) {
|
|
||||||
if (a[key] !== b[key]) {
|
|
||||||
different.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (different.length > 0) {
|
|
||||||
console.log('ITEM DIFFERENT -------------------', different.join(', '));
|
|
||||||
}
|
|
||||||
return different.length === 0;
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export interface SidebarItemsProps {
|
|||||||
grpcConnections: GrpcConnection[];
|
grpcConnections: GrpcConnection[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function SidebarItems_({
|
export const SidebarItems = memo(function SidebarItems({
|
||||||
tree,
|
tree,
|
||||||
selectedTree,
|
selectedTree,
|
||||||
draggingId,
|
draggingId,
|
||||||
@@ -102,17 +102,4 @@ function SidebarItems_({
|
|||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
}
|
})
|
||||||
|
|
||||||
export const SidebarItems = memo<SidebarItemsProps>(SidebarItems_, (a, b) => {
|
|
||||||
const different = [];
|
|
||||||
for (const key of Object.keys(a) as (keyof SidebarItemsProps)[]) {
|
|
||||||
if (a[key] !== b[key]) {
|
|
||||||
different.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (different.length > 0) {
|
|
||||||
console.log('ITEMS DIFFERENT -------------------', different.join(', '));
|
|
||||||
}
|
|
||||||
return different.length === 0;
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,105 +1,4 @@
|
|||||||
import type { ShowToastRequest } from '@yaakapp-internal/plugin';
|
import { createContext } from 'react';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import type { ToastState } from './Toasts';
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
|
|
||||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
|
||||||
import { generateId } from '../lib/generateId';
|
|
||||||
import type { ToastProps } from './core/Toast';
|
|
||||||
import { Toast } from './core/Toast';
|
|
||||||
import { Portal } from './Portal';
|
|
||||||
|
|
||||||
type ToastEntry = {
|
export const ToastContext = createContext<ToastState>({} as ToastState);
|
||||||
id?: string;
|
|
||||||
message: ReactNode;
|
|
||||||
timeout?: 3000 | 5000 | 8000 | null;
|
|
||||||
onClose?: ToastProps['onClose'];
|
|
||||||
} & Omit<ToastProps, 'onClose' | 'open' | 'children' | 'timeout'>;
|
|
||||||
|
|
||||||
type PrivateToastEntry = ToastEntry & {
|
|
||||||
id: string;
|
|
||||||
timeout: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface State {
|
|
||||||
toasts: PrivateToastEntry[];
|
|
||||||
actions: Actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Actions {
|
|
||||||
show: (d: ToastEntry) => void;
|
|
||||||
hide: (id: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const ToastContext = createContext<State>({} as State);
|
|
||||||
|
|
||||||
export const ToastProvider = ({ children }: { children: React.ReactNode }) => {
|
|
||||||
const [toasts, setToasts] = useState<State['toasts']>([]);
|
|
||||||
const timeoutRef = useRef<NodeJS.Timeout>();
|
|
||||||
const actions = useMemo<Actions>(
|
|
||||||
() => ({
|
|
||||||
show({ id, timeout = 5000, ...props }: ToastEntry) {
|
|
||||||
id = id ?? generateId();
|
|
||||||
if (timeout != null) {
|
|
||||||
timeoutRef.current = setTimeout(() => this.hide(id), timeout);
|
|
||||||
}
|
|
||||||
setToasts((a) => {
|
|
||||||
if (a.some((v) => v.id === id)) {
|
|
||||||
// It's already visible with this id
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
return [...a, { id, timeout, ...props }];
|
|
||||||
});
|
|
||||||
return id;
|
|
||||||
},
|
|
||||||
hide: (id: string) => {
|
|
||||||
setToasts((all) => {
|
|
||||||
const t = all.find((t) => t.id === id);
|
|
||||||
t?.onClose?.();
|
|
||||||
return all.filter((t) => t.id !== id);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
useListenToTauriEvent<ShowToastRequest>('show_toast', (event) => {
|
|
||||||
actions.show({ ...event.payload });
|
|
||||||
});
|
|
||||||
|
|
||||||
const state: State = { toasts, actions };
|
|
||||||
return <ToastContext.Provider value={state}>{children}</ToastContext.Provider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
function ToastInstance({ id, message, timeout, ...props }: PrivateToastEntry) {
|
|
||||||
const { actions } = useContext(ToastContext);
|
|
||||||
return (
|
|
||||||
<Toast
|
|
||||||
open
|
|
||||||
timeout={timeout}
|
|
||||||
{...props}
|
|
||||||
// We call onClose inside actions.hide instead of passing to toast so that
|
|
||||||
// it gets called from external close calls as well
|
|
||||||
onClose={() => actions.hide(id)}
|
|
||||||
>
|
|
||||||
{message}
|
|
||||||
</Toast>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useToast = () => useContext(ToastContext).actions;
|
|
||||||
|
|
||||||
export const Toasts = () => {
|
|
||||||
const { toasts } = useContext(ToastContext);
|
|
||||||
return (
|
|
||||||
<Portal name="toasts">
|
|
||||||
<div className="absolute right-0 bottom-0 z-20">
|
|
||||||
<AnimatePresence>
|
|
||||||
{toasts.map((props: PrivateToastEntry) => (
|
|
||||||
<ToastInstance key={props.id} {...props} />
|
|
||||||
))}
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
|
||||||
</Portal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
100
src-web/components/Toasts.tsx
Normal file
100
src-web/components/Toasts.tsx
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import type { ShowToastRequest } from '@yaakapp-internal/plugin';
|
||||||
|
import { AnimatePresence } from 'framer-motion';
|
||||||
|
import React, {type ReactNode, useContext, useMemo, useRef, useState} from 'react';
|
||||||
|
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||||
|
import { generateId } from '../lib/generateId';
|
||||||
|
import {Toast, type ToastProps} from './core/Toast';
|
||||||
|
import { Portal } from './Portal';
|
||||||
|
import { ToastContext } from './ToastContext';
|
||||||
|
|
||||||
|
type ToastEntry = {
|
||||||
|
id?: string;
|
||||||
|
message: ReactNode;
|
||||||
|
timeout?: 3000 | 5000 | 8000 | null;
|
||||||
|
onClose?: ToastProps['onClose'];
|
||||||
|
} & Omit<ToastProps, 'onClose' | 'open' | 'children' | 'timeout'>;
|
||||||
|
|
||||||
|
type PrivateToastEntry = ToastEntry & {
|
||||||
|
id: string;
|
||||||
|
timeout: number | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ToastState {
|
||||||
|
toasts: PrivateToastEntry[];
|
||||||
|
actions: Actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Actions {
|
||||||
|
show: (d: ToastEntry) => void;
|
||||||
|
hide: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const ToastProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const [toasts, setToasts] = useState<ToastState['toasts']>([]);
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout>();
|
||||||
|
const actions = useMemo<Actions>(
|
||||||
|
() => ({
|
||||||
|
show({ id, timeout = 5000, ...props }: ToastEntry) {
|
||||||
|
id = id ?? generateId();
|
||||||
|
if (timeout != null) {
|
||||||
|
timeoutRef.current = setTimeout(() => this.hide(id), timeout);
|
||||||
|
}
|
||||||
|
setToasts((a) => {
|
||||||
|
if (a.some((v) => v.id === id)) {
|
||||||
|
// It's already visible with this id
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return [...a, { id, timeout, ...props }];
|
||||||
|
});
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
hide: (id: string) => {
|
||||||
|
setToasts((all) => {
|
||||||
|
const t = all.find((t) => t.id === id);
|
||||||
|
t?.onClose?.();
|
||||||
|
return all.filter((t) => t.id !== id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
useListenToTauriEvent<ShowToastRequest>('show_toast', (event) => {
|
||||||
|
actions.show({ ...event.payload });
|
||||||
|
});
|
||||||
|
|
||||||
|
const state: ToastState = { toasts, actions };
|
||||||
|
return <ToastContext.Provider value={state}>{children}</ToastContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ToastInstance({ id, message, timeout, ...props }: PrivateToastEntry) {
|
||||||
|
const { actions } = useContext(ToastContext);
|
||||||
|
return (
|
||||||
|
<Toast
|
||||||
|
open
|
||||||
|
timeout={timeout}
|
||||||
|
{...props}
|
||||||
|
// We call onClose inside actions.hide instead of passing to toast so that
|
||||||
|
// it gets called from external close calls as well
|
||||||
|
onClose={() => actions.hide(id)}
|
||||||
|
>
|
||||||
|
{message}
|
||||||
|
</Toast>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Toasts = () => {
|
||||||
|
const { toasts } = useContext(ToastContext);
|
||||||
|
return (
|
||||||
|
<Portal name="toasts">
|
||||||
|
<div className="absolute right-0 bottom-0 z-20">
|
||||||
|
<AnimatePresence>
|
||||||
|
{toasts.map((props: PrivateToastEntry) => (
|
||||||
|
<ToastInstance key={props.id} {...props} />
|
||||||
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useOsInfo } from '../hooks/useOsInfo';
|
import { useOsInfo } from '../hooks/useOsInfo';
|
||||||
|
import {WINDOW_CONTROLS_WIDTH} from "../lib/constants";
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { HStack } from './core/Stacks';
|
import { HStack } from './core/Stacks';
|
||||||
|
|
||||||
@@ -11,8 +12,6 @@ interface Props {
|
|||||||
macos?: boolean;
|
macos?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WINDOW_CONTROLS_WIDTH = '10.5rem';
|
|
||||||
|
|
||||||
export function WindowControls({ className, onlyX }: Props) {
|
export function WindowControls({ className, onlyX }: Props) {
|
||||||
const [maximized, setMaximized] = useState<boolean>(false);
|
const [maximized, setMaximized] = useState<boolean>(false);
|
||||||
const osInfo = useOsInfo();
|
const osInfo = useOsInfo();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||||
@@ -41,10 +41,6 @@ export function Workspace() {
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('RENDER WORKSPACE');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const unsub = () => {
|
const unsub = () => {
|
||||||
if (moveState.current !== null) {
|
if (moveState.current !== null) {
|
||||||
document.documentElement.removeEventListener('mousemove', moveState.current.move);
|
document.documentElement.removeEventListener('mousemove', moveState.current.move);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import type { DropdownItem } from './core/Dropdown';
|
|||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import type { RadioDropdownItem } from './core/RadioDropdown';
|
import type { RadioDropdownItem } from './core/RadioDropdown';
|
||||||
import { RadioDropdown } from './core/RadioDropdown';
|
import { RadioDropdown } from './core/RadioDropdown';
|
||||||
import { useDialog } from './DialogContext';
|
import { useDialog } from '../hooks/useDialog';
|
||||||
import { OpenWorkspaceDialog } from './OpenWorkspaceDialog';
|
import { OpenWorkspaceDialog } from './OpenWorkspaceDialog';
|
||||||
import { WorkspaceSettingsDialog } from './WorkpaceSettingsDialog';
|
import { WorkspaceSettingsDialog } from './WorkpaceSettingsDialog';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { Editor } from './Editor';
|
import {Editor} from "./Editor/Editor";
|
||||||
import type { PairEditorProps } from './PairEditor';
|
import type { PairEditorProps } from './PairEditor';
|
||||||
|
|
||||||
type Props = PairEditorProps;
|
type Props = PairEditorProps;
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useActiveEnvironmentVariables } from '../../../hooks/useActiveEnvironmentVariables';
|
import { useActiveEnvironmentVariables } from '../../../hooks/useActiveEnvironmentVariables';
|
||||||
|
import {useDialog} from "../../../hooks/useDialog";
|
||||||
import { parseTemplate } from '../../../hooks/useParseTemplate';
|
import { parseTemplate } from '../../../hooks/useParseTemplate';
|
||||||
import { useRequestEditor } from '../../../hooks/useRequestEditor';
|
import { useRequestEditor } from '../../../hooks/useRequestEditor';
|
||||||
import { useSettings } from '../../../hooks/useSettings';
|
import { useSettings } from '../../../hooks/useSettings';
|
||||||
import { useTemplateFunctions } from '../../../hooks/useTemplateFunctions';
|
import { useTemplateFunctions } from '../../../hooks/useTemplateFunctions';
|
||||||
import { useDialog } from '../../DialogContext';
|
|
||||||
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
||||||
import { TemplateVariableDialog } from '../../TemplateVariableDialog';
|
import { TemplateVariableDialog } from '../../TemplateVariableDialog';
|
||||||
import { IconButton } from '../IconButton';
|
import { IconButton } from '../IconButton';
|
||||||
@@ -33,11 +33,6 @@ import { baseExtensions, getLanguageExtension, multiLineExtensions } from './ext
|
|||||||
import type { GenericCompletionConfig } from './genericCompletion';
|
import type { GenericCompletionConfig } from './genericCompletion';
|
||||||
import { singleLineExt } from './singleLine';
|
import { singleLineExt } from './singleLine';
|
||||||
|
|
||||||
// Export some things so all the code-split parts are in this file
|
|
||||||
export { buildClientSchema, getIntrospectionQuery } from 'graphql/utilities';
|
|
||||||
export { graphql } from 'cm6-graphql';
|
|
||||||
export { formatSdl } from 'format-graphql';
|
|
||||||
|
|
||||||
export interface EditorProps {
|
export interface EditorProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import type { EnvironmentVariable } from '@yaakapp-internal/models';
|
|||||||
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
import type { TemplateFunction } from '@yaakapp-internal/plugin';
|
||||||
import { graphql } from 'cm6-graphql';
|
import { graphql } from 'cm6-graphql';
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import type { EditorProps } from './index';
|
import type {EditorProps} from "./Editor";
|
||||||
import { pairs } from './pairs/extension';
|
import { pairs } from './pairs/extension';
|
||||||
import { text } from './text/extension';
|
import { text } from './text/extension';
|
||||||
import { twig } from './twig/extension';
|
import { twig } from './twig/extension';
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import * as editor from './Editor';
|
|
||||||
|
|
||||||
export type { EditorProps } from './Editor';
|
|
||||||
// TODO: Figure out why code-splitting breaks production build from
|
|
||||||
// showing any content
|
|
||||||
// const editor = await import('./Editor');
|
|
||||||
|
|
||||||
export const Editor = editor.Editor;
|
|
||||||
export const graphql = editor.graphql;
|
|
||||||
export const getIntrospectionQuery = editor.getIntrospectionQuery;
|
|
||||||
export const buildClientSchema = editor.buildClientSchema;
|
|
||||||
export const formatGraphQL = editor.formatSdl;
|
|
||||||
@@ -3,8 +3,8 @@ import type { EditorView } from 'codemirror';
|
|||||||
import type { HTMLAttributes, ReactNode } from 'react';
|
import type { HTMLAttributes, ReactNode } from 'react';
|
||||||
import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
|
import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import { useStateWithDeps } from '../../hooks/useStateWithDeps';
|
import { useStateWithDeps } from '../../hooks/useStateWithDeps';
|
||||||
import type { EditorProps } from './Editor';
|
import type { EditorProps } from './Editor/Editor';
|
||||||
import { Editor } from './Editor';
|
import { Editor } from './Editor/Editor';
|
||||||
import { IconButton } from './IconButton';
|
import { IconButton } from './IconButton';
|
||||||
import { HStack } from './Stacks';
|
import { HStack } from './Stacks';
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { useFormatText } from '../../hooks/useFormatText';
|
|||||||
import { useResponseBodyEventSource } from '../../hooks/useResponseBodyEventSource';
|
import { useResponseBodyEventSource } from '../../hooks/useResponseBodyEventSource';
|
||||||
import { isJSON } from '../../lib/contentType';
|
import { isJSON } from '../../lib/contentType';
|
||||||
import { Button } from '../core/Button';
|
import { Button } from '../core/Button';
|
||||||
import type { EditorProps } from '../core/Editor';
|
import type { EditorProps } from '../core/Editor/Editor';
|
||||||
import { Editor } from '../core/Editor';
|
import { Editor } from '../core/Editor/Editor';
|
||||||
import { Icon } from '../core/Icon';
|
import { Icon } from '../core/Icon';
|
||||||
import { InlineCode } from '../core/InlineCode';
|
import { InlineCode } from '../core/InlineCode';
|
||||||
import { Separator } from '../core/Separator';
|
import { Separator } from '../core/Separator';
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import { useToggle } from '../../hooks/useToggle';
|
|||||||
import { CopyButton } from '../CopyButton';
|
import { CopyButton } from '../CopyButton';
|
||||||
import { Banner } from '../core/Banner';
|
import { Banner } from '../core/Banner';
|
||||||
import { Button } from '../core/Button';
|
import { Button } from '../core/Button';
|
||||||
import type { EditorProps } from '../core/Editor';
|
|
||||||
import { Editor } from '../core/Editor';
|
|
||||||
import { hyperlink } from '../core/Editor/hyperlink/extension';
|
import { hyperlink } from '../core/Editor/hyperlink/extension';
|
||||||
import { IconButton } from '../core/IconButton';
|
import { IconButton } from '../core/IconButton';
|
||||||
import { InlineCode } from '../core/InlineCode';
|
import { InlineCode } from '../core/InlineCode';
|
||||||
import { Input } from '../core/Input';
|
import { Input } from '../core/Input';
|
||||||
import { SizeTag } from '../core/SizeTag';
|
import { SizeTag } from '../core/SizeTag';
|
||||||
import { HStack } from '../core/Stacks';
|
import { HStack } from '../core/Stacks';
|
||||||
|
import type { EditorProps } from '../core/Editor/Editor';
|
||||||
|
import { Editor } from '../core/Editor/Editor';
|
||||||
|
|
||||||
const extraExtensions = [hyperlink];
|
const extraExtensions = [hyperlink];
|
||||||
const LARGE_RESPONSE_BYTES = 2 * 1000 * 1000;
|
const LARGE_RESPONSE_BYTES = 2 * 1000 * 1000;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useSearch } from '@tanstack/react-router';
|
import { getRouteApi, useSearch } from '@tanstack/react-router';
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { Route } from '../routes/workspaces/$workspaceId';
|
|
||||||
import { useCookieJars } from './useCookieJars';
|
import { useCookieJars } from './useCookieJars';
|
||||||
|
|
||||||
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
||||||
@@ -39,13 +38,18 @@ export function useEnsureActiveCookieJar() {
|
|||||||
}, [activeCookieJarId, cookieJars, setActiveCookieJarId]);
|
}, [activeCookieJarId, cookieJars, setActiveCookieJarId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const routeApi = getRouteApi('/workspaces/$workspaceId/');
|
||||||
|
|
||||||
function useActiveCookieJarId() {
|
function useActiveCookieJarId() {
|
||||||
// NOTE: This query param is accessed from Rust side, so do not change
|
// NOTE: This query param is accessed from Rust side, so do not change
|
||||||
const navigate = Route.useNavigate();
|
|
||||||
const { cookieJarId: id } = useSearch({ strict: false });
|
const { cookieJarId: id } = useSearch({ strict: false });
|
||||||
|
const navigate = routeApi.useNavigate();
|
||||||
|
|
||||||
const setId = useCallback(
|
const setId = useCallback(
|
||||||
(id: string) => navigate({ search: (prev) => ({ ...prev, cookieJarId: id }) }),
|
(id: string) =>
|
||||||
|
navigate({
|
||||||
|
search: (prev) => ({ ...prev, cookieJarId: id }),
|
||||||
|
}),
|
||||||
[navigate],
|
[navigate],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useSearch } from '@tanstack/react-router';
|
import { getRouteApi, useSearch } from '@tanstack/react-router';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { Route } from '../routes/workspaces/$workspaceId';
|
|
||||||
import { useEnvironments } from './useEnvironments';
|
import { useEnvironments } from './useEnvironments';
|
||||||
|
|
||||||
export function useActiveEnvironment() {
|
export function useActiveEnvironment() {
|
||||||
@@ -15,14 +14,18 @@ export function useActiveEnvironment() {
|
|||||||
|
|
||||||
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
||||||
|
|
||||||
|
const routeApi = getRouteApi('/workspaces/$workspaceId/');
|
||||||
|
|
||||||
function useActiveEnvironmentId() {
|
function useActiveEnvironmentId() {
|
||||||
// NOTE: This query param is accessed from Rust side, so do not change
|
// NOTE: This query param is accessed from Rust side, so do not change
|
||||||
const navigate = Route.useNavigate();
|
|
||||||
const { environmentId: id } = useSearch({ strict: false });
|
const { environmentId: id } = useSearch({ strict: false });
|
||||||
|
const navigate = routeApi.useNavigate();
|
||||||
|
|
||||||
const setId = useCallback(
|
const setId = useCallback(
|
||||||
(environment_id: string | null) =>
|
(environment_id: string | null) =>
|
||||||
navigate({ search: (prev) => ({ ...prev, environment_id: environment_id ?? undefined }) }),
|
navigate({
|
||||||
|
search: (prev) => ({ ...prev, environment_id: environment_id ?? undefined }),
|
||||||
|
}),
|
||||||
[navigate],
|
[navigate],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { atom, useAtomValue } from 'jotai';
|
import { atom, useAtomValue } from 'jotai';
|
||||||
import { jotaiStore } from '../routes/__root';
|
import {jotaiStore} from "../lib/jotai";
|
||||||
import { activeRequestIdAtom } from './useActiveRequestId';
|
import { activeRequestIdAtom } from './useActiveRequestId';
|
||||||
import { grpcRequestsAtom } from './useGrpcRequests';
|
import { grpcRequestsAtom } from './useGrpcRequests';
|
||||||
import { httpRequestsAtom } from './useHttpRequests';
|
import { httpRequestsAtom } from './useHttpRequests';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useParams } from '@tanstack/react-router';
|
import { useParams } from '@tanstack/react-router';
|
||||||
import { atom, useAtomValue } from 'jotai';
|
import { atom, useAtomValue } from 'jotai';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { jotaiStore } from '../routes/__root';
|
import {jotaiStore} from "../lib/jotai";
|
||||||
|
|
||||||
export const activeRequestIdAtom = atom<string>();
|
export const activeRequestIdAtom = atom<string>();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useParams } from '@tanstack/react-router';
|
|||||||
import type { Workspace } from '@yaakapp-internal/models';
|
import type { Workspace } from '@yaakapp-internal/models';
|
||||||
import { atom, useAtomValue } from 'jotai/index';
|
import { atom, useAtomValue } from 'jotai/index';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { jotaiStore } from '../routes/__root';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { useWorkspaces } from './useWorkspaces';
|
import { useWorkspaces } from './useWorkspaces';
|
||||||
|
|
||||||
export const activeWorkspaceIdAtom = atom<string>();
|
export const activeWorkspaceIdAtom = atom<string>();
|
||||||
@@ -17,6 +17,10 @@ function useActiveWorkspaceId(): string | null {
|
|||||||
return useAtomValue(activeWorkspaceIdAtom) ?? null;
|
return useAtomValue(activeWorkspaceIdAtom) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getActiveWorkspaceId() {
|
||||||
|
return jotaiStore.get(activeWorkspaceIdAtom);
|
||||||
|
}
|
||||||
|
|
||||||
export function useSubscribeActiveWorkspaceId() {
|
export function useSubscribeActiveWorkspaceId() {
|
||||||
const { workspaceId } = useParams({ strict: false });
|
const { workspaceId } = useParams({ strict: false });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { useToast } from '../components/ToastContext';
|
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
import { useToast } from './useToast';
|
||||||
|
|
||||||
export function useActiveWorkspaceChangedToast() {
|
export function useActiveWorkspaceChangedToast() {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import type { DialogProps } from '../components/core/Dialog';
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
import { useDialog } from '../components/DialogContext';
|
|
||||||
import type { AlertProps } from './Alert';
|
import type { AlertProps } from './Alert';
|
||||||
import { Alert } from './Alert';
|
import { Alert } from './Alert';
|
||||||
|
import {useDialog} from "./useDialog";
|
||||||
|
|
||||||
interface AlertArg {
|
interface AlertArg {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useAppInfo } from './useAppInfo';
|
|||||||
export function useCheckForUpdates() {
|
export function useCheckForUpdates() {
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
const appInfo = useAppInfo();
|
const appInfo = useAppInfo();
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ['check_for_updates'],
|
mutationKey: ['check_for_updates'],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { DialogProps } from '../components/core/Dialog';
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
import { useDialog } from '../components/DialogContext';
|
|
||||||
import type { ConfirmProps } from './Confirm';
|
import type { ConfirmProps } from './Confirm';
|
||||||
import { Confirm } from './Confirm';
|
import { Confirm } from './Confirm';
|
||||||
|
import { useDialog } from './useDialog';
|
||||||
|
|
||||||
export function useConfirm() {
|
export function useConfirm() {
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { clear, writeText } from '@tauri-apps/plugin-clipboard-manager';
|
import { clear, writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from './useToast';
|
||||||
|
|
||||||
export function useCopy({ disableToast }: { disableToast?: boolean } = {}) {
|
export function useCopy({ disableToast }: { disableToast?: boolean } = {}) {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import { getActiveRequest } from './useActiveRequest';
|
import { getActiveRequest } from './useActiveRequest';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { grpcRequestsAtom } from './useGrpcRequests';
|
import { grpcRequestsAtom } from './useGrpcRequests';
|
||||||
import { updateModelList } from './useSyncModelStores';
|
import { updateModelList } from './useSyncModelStores';
|
||||||
|
|
||||||
export function useCreateGrpcRequest() {
|
export function useCreateGrpcRequest() {
|
||||||
const workspace = useActiveWorkspace();
|
const workspace = useActiveWorkspace();
|
||||||
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
|
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return useFastMutation<
|
return useFastMutation<
|
||||||
GrpcRequest,
|
GrpcRequest,
|
||||||
@@ -46,8 +46,8 @@ export function useCreateGrpcRequest() {
|
|||||||
// Optimistic update
|
// Optimistic update
|
||||||
setGrpcRequests(updateModelList(request));
|
setGrpcRequests(updateModelList(request));
|
||||||
|
|
||||||
router.navigate({
|
navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: {
|
params: {
|
||||||
workspaceId: request.workspaceId,
|
workspaceId: request.workspaceId,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
|
||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { useSetAtom } from 'jotai/index';
|
import { useSetAtom } from 'jotai/index';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import { getActiveRequest } from './useActiveRequest';
|
import { getActiveRequest } from './useActiveRequest';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { httpRequestsAtom } from './useHttpRequests';
|
import { httpRequestsAtom } from './useHttpRequests';
|
||||||
import { updateModelList } from './useSyncModelStores';
|
import { updateModelList } from './useSyncModelStores';
|
||||||
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
|
|
||||||
export function useCreateHttpRequest() {
|
export function useCreateHttpRequest() {
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const setHttpRequests = useSetAtom(httpRequestsAtom);
|
const setHttpRequests = useSetAtom(httpRequestsAtom);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return useFastMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
return useFastMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
||||||
mutationKey: ['create_http_request'],
|
mutationKey: ['create_http_request'],
|
||||||
@@ -40,8 +40,8 @@ export function useCreateHttpRequest() {
|
|||||||
// Optimistic update
|
// Optimistic update
|
||||||
setHttpRequests(updateModelList(request));
|
setHttpRequests(updateModelList(request));
|
||||||
|
|
||||||
await router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: { workspaceId: request.workspaceId, requestId: request.id },
|
params: { workspaceId: request.workspaceId, requestId: request.id },
|
||||||
search: (prev) => ({ ...prev }),
|
search: (prev) => ({ ...prev }),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { Workspace } from '@yaakapp-internal/models';
|
import type { Workspace } from '@yaakapp-internal/models';
|
||||||
import { useSetAtom } from 'jotai/index';
|
import { useSetAtom } from 'jotai/index';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { Route } from '../routes/workspaces/$workspaceId';
|
|
||||||
import { usePrompt } from './usePrompt';
|
import { usePrompt } from './usePrompt';
|
||||||
import { updateModelList } from './useSyncModelStores';
|
import { updateModelList } from './useSyncModelStores';
|
||||||
import { workspacesAtom } from './useWorkspaces';
|
import { workspacesAtom } from './useWorkspaces';
|
||||||
@@ -11,6 +10,7 @@ import { workspacesAtom } from './useWorkspaces';
|
|||||||
export function useCreateWorkspace() {
|
export function useCreateWorkspace() {
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
const setWorkspaces = useSetAtom(workspacesAtom);
|
const setWorkspaces = useSetAtom(workspacesAtom);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return useFastMutation<Workspace | null, void, void>({
|
return useFastMutation<Workspace | null, void, void>({
|
||||||
mutationKey: ['create_workspace'],
|
mutationKey: ['create_workspace'],
|
||||||
@@ -34,8 +34,8 @@ export function useCreateWorkspace() {
|
|||||||
// Optimistic update
|
// Optimistic update
|
||||||
setWorkspaces(updateModelList(workspace));
|
setWorkspaces(updateModelList(workspace));
|
||||||
|
|
||||||
router.navigate({
|
navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: workspace.id },
|
params: { workspaceId: workspace.id },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { Workspace } from '@yaakapp-internal/models';
|
import type { Workspace } from '@yaakapp-internal/models';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
|
||||||
import { Route } from '../routes/workspaces';
|
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { removeModelById } from './useSyncModelStores';
|
import { removeModelById } from './useSyncModelStores';
|
||||||
import { workspacesAtom } from './useWorkspaces';
|
import { workspacesAtom } from './useWorkspaces';
|
||||||
|
|
||||||
@@ -15,6 +14,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
|||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const setWorkspaces = useSetAtom(workspacesAtom);
|
const setWorkspaces = useSetAtom(workspacesAtom);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return useFastMutation<Workspace | null, string>({
|
return useFastMutation<Workspace | null, string>({
|
||||||
mutationKey: ['delete_workspace', workspace?.id],
|
mutationKey: ['delete_workspace', workspace?.id],
|
||||||
@@ -41,7 +41,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
|||||||
|
|
||||||
const { id: workspaceId } = workspace;
|
const { id: workspaceId } = workspace;
|
||||||
if (workspaceId === activeWorkspace?.id) {
|
if (workspaceId === activeWorkspace?.id) {
|
||||||
router.navigate({ to: Route.fullPath });
|
navigate({ to: '/workspaces' });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
6
src-web/hooks/useDialog.ts
Normal file
6
src-web/hooks/useDialog.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { DialogContext } from '../components/DialogContext';
|
||||||
|
|
||||||
|
export function useDialog() {
|
||||||
|
return useContext(DialogContext).actions;
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import { getGrpcProtoFiles, setGrpcProtoFiles } from './useGrpcProtoFiles';
|
import { getGrpcProtoFiles, setGrpcProtoFiles } from './useGrpcProtoFiles';
|
||||||
|
|
||||||
export function useDuplicateGrpcRequest({
|
export function useDuplicateGrpcRequest({
|
||||||
@@ -13,6 +12,7 @@ export function useDuplicateGrpcRequest({
|
|||||||
id: string | null;
|
id: string | null;
|
||||||
navigateAfter: boolean;
|
navigateAfter: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const navigate = useNavigate();
|
||||||
return useFastMutation<GrpcRequest, string>({
|
return useFastMutation<GrpcRequest, string>({
|
||||||
mutationKey: ['duplicate_grpc_request', id],
|
mutationKey: ['duplicate_grpc_request', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -28,8 +28,8 @@ export function useDuplicateGrpcRequest({
|
|||||||
await setGrpcProtoFiles(request.id, protoFiles);
|
await setGrpcProtoFiles(request.id, protoFiles);
|
||||||
|
|
||||||
if (navigateAfter) {
|
if (navigateAfter) {
|
||||||
await router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: { workspaceId: request.workspaceId, requestId: request.id },
|
params: { workspaceId: request.workspaceId, requestId: request.id },
|
||||||
search: (prev) => ({ ...prev }),
|
search: (prev) => ({ ...prev }),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { Route } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
|
|
||||||
export function useDuplicateHttpRequest({
|
export function useDuplicateHttpRequest({
|
||||||
id,
|
id,
|
||||||
@@ -12,6 +11,7 @@ export function useDuplicateHttpRequest({
|
|||||||
id: string | null;
|
id: string | null;
|
||||||
navigateAfter: boolean;
|
navigateAfter: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
const navigate = useNavigate();
|
||||||
return useFastMutation<HttpRequest, string>({
|
return useFastMutation<HttpRequest, string>({
|
||||||
mutationKey: ['duplicate_http_request', id],
|
mutationKey: ['duplicate_http_request', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -21,8 +21,8 @@ export function useDuplicateHttpRequest({
|
|||||||
onSettled: () => trackEvent('http_request', 'duplicate'),
|
onSettled: () => trackEvent('http_request', 'duplicate'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
if (navigateAfter) {
|
if (navigateAfter) {
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
params: {
|
params: {
|
||||||
workspaceId: request.workspaceId,
|
workspaceId: request.workspaceId,
|
||||||
requestId: request.id,
|
requestId: request.id,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
import {useDialog} from "./useDialog";
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { useDialog } from '../components/DialogContext';
|
|
||||||
import { ExportDataDialog } from '../components/ExportDataDialog';
|
import { ExportDataDialog } from '../components/ExportDataDialog';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
import { useAlert } from './useAlert';
|
||||||
import { useWorkspaces } from './useWorkspaces';
|
import { useWorkspaces } from './useWorkspaces';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from './useToast';
|
||||||
|
|
||||||
export function useExportData() {
|
export function useExportData() {
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import type { EditorProps } from '../components/core/Editor';
|
|
||||||
import { tryFormatJson, tryFormatXml } from '../lib/formatters';
|
import { tryFormatJson, tryFormatXml } from '../lib/formatters';
|
||||||
|
import type { EditorProps } from '../components/core/Editor/Editor';
|
||||||
|
|
||||||
export function useFormatText({
|
export function useFormatText({
|
||||||
text,
|
text,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from './useToast';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate } from '@tanstack/react-router';
|
||||||
import type {
|
import type {
|
||||||
Environment,
|
Environment,
|
||||||
Folder,
|
Folder,
|
||||||
@@ -9,19 +9,19 @@ import type {
|
|||||||
import { Button } from '../components/core/Button';
|
import { Button } from '../components/core/Button';
|
||||||
import { FormattedError } from '../components/core/FormattedError';
|
import { FormattedError } from '../components/core/FormattedError';
|
||||||
import { VStack } from '../components/core/Stacks';
|
import { VStack } from '../components/core/Stacks';
|
||||||
import { useDialog } from '../components/DialogContext';
|
|
||||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||||
import { count } from '../lib/pluralize';
|
import { count } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { Route } from '../routes/workspaces/$workspaceId';
|
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
import { useAlert } from './useAlert';
|
||||||
import { router } from '../main';
|
import { useDialog } from './useDialog';
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useImportData() {
|
export function useImportData() {
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const importData = async (filePath: string): Promise<boolean> => {
|
const importData = async (filePath: string): Promise<boolean> => {
|
||||||
const imported: {
|
const imported: {
|
||||||
@@ -65,8 +65,8 @@ export function useImportData() {
|
|||||||
|
|
||||||
if (importedWorkspace != null) {
|
if (importedWorkspace != null) {
|
||||||
const environmentId = imported.environments[0]?.id ?? null;
|
const environmentId = imported.environments[0]?.id ?? null;
|
||||||
router.navigate({
|
await navigate({
|
||||||
to: Route.fullPath,
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: importedWorkspace.id },
|
params: { workspaceId: importedWorkspace.id },
|
||||||
search: { environmentId },
|
search: { environmentId },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import type { HttpUrlParameter } from '@yaakapp-internal/models';
|
import type { HttpUrlParameter } from '@yaakapp-internal/models';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from './useToast';
|
||||||
import { pluralize } from '../lib/pluralize';
|
import { pluralize } from '../lib/pluralize';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import { useRequestEditor } from './useRequestEditor';
|
import { useRequestEditor } from './useRequestEditor';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import type { IntrospectionQuery } from 'graphql';
|
import { buildClientSchema, getIntrospectionQuery, type IntrospectionQuery } from 'graphql';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
|
||||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||||
import { getResponseBodyText } from '../lib/responseBody';
|
import { getResponseBodyText } from '../lib/responseBody';
|
||||||
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
|
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import {useDialog} from "./useDialog";
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useDialog } from '../components/DialogContext';
|
|
||||||
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useRequests } from './useRequests';
|
import { useRequests } from './useRequests';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { open } from '@tauri-apps/plugin-shell';
|
import { open } from '@tauri-apps/plugin-shell';
|
||||||
import { Button } from '../components/core/Button';
|
import { Button } from '../components/core/Button';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from './useToast';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useListenToTauriEvent } from './useListenToTauriEvent';
|
import { useListenToTauriEvent } from './useListenToTauriEvent';
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useRouter } from '@tanstack/react-router';
|
||||||
import { SettingsTab } from '../components/Settings/Settings';
|
import { SettingsTab } from '../components/Settings/SettingsTab';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { Route as SettingsRoute } from '../routes/workspaces/settings';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
|
||||||
|
|
||||||
export function useOpenSettings(tab = SettingsTab.General) {
|
export function useOpenSettings(tab = SettingsTab.General) {
|
||||||
const workspace = useActiveWorkspace();
|
const router = useRouter();
|
||||||
|
|
||||||
return useFastMutation({
|
return useFastMutation({
|
||||||
mutationKey: ['open_settings'],
|
mutationKey: ['open_settings'],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
if (workspace == null) return;
|
const workspaceId = getActiveWorkspaceId();
|
||||||
|
if (workspaceId == null) return;
|
||||||
|
|
||||||
trackEvent('dialog', 'show', { id: 'settings', tab: `${tab}` });
|
trackEvent('dialog', 'show', { id: 'settings', tab: `${tab}` });
|
||||||
const location = router.buildLocation({
|
const location = router.buildLocation({
|
||||||
to: SettingsRoute.fullPath,
|
to: '/workspaces/$workspaceId/settings',
|
||||||
params: { workspaceId: workspace.id },
|
params: { workspaceId },
|
||||||
search: { tab },
|
search: { tab },
|
||||||
});
|
});
|
||||||
await invokeCmd('cmd_new_child_window', {
|
await invokeCmd('cmd_new_child_window', {
|
||||||
url: location,
|
url: location.href,
|
||||||
label: 'settings',
|
label: 'settings',
|
||||||
title: 'Yaak Settings',
|
title: 'Yaak Settings',
|
||||||
innerSize: [600, 550],
|
innerSize: [600, 550],
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { useFastMutation } from './useFastMutation';
|
import { useNavigate, useRouter } from '@tanstack/react-router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { router } from '../main';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { Route as WorkspaceRoute } from '../routes/workspaces/$workspaceId';
|
|
||||||
import { Route as RequestRoute } from '../routes/workspaces/$workspaceId/requests/$requestId';
|
|
||||||
import { getRecentCookieJars } from './useRecentCookieJars';
|
import { getRecentCookieJars } from './useRecentCookieJars';
|
||||||
import { getRecentEnvironments } from './useRecentEnvironments';
|
import { getRecentEnvironments } from './useRecentEnvironments';
|
||||||
import { getRecentRequests } from './useRecentRequests';
|
import { getRecentRequests } from './useRecentRequests';
|
||||||
|
|
||||||
export function useOpenWorkspace() {
|
export function useOpenWorkspace() {
|
||||||
|
const router = useRouter();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return useFastMutation({
|
return useFastMutation({
|
||||||
mutationKey: ['open_workspace'],
|
mutationKey: ['open_workspace'],
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
@@ -24,18 +25,22 @@ export function useOpenWorkspace() {
|
|||||||
|
|
||||||
if (inNewWindow) {
|
if (inNewWindow) {
|
||||||
const location = router.buildLocation({
|
const location = router.buildLocation({
|
||||||
to: WorkspaceRoute.fullPath,
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId },
|
params: { workspaceId },
|
||||||
search,
|
search,
|
||||||
});
|
});
|
||||||
await invokeCmd('cmd_new_main_window', { url: location });
|
await invokeCmd('cmd_new_main_window', { url: location.href });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestId != null) {
|
if (requestId != null) {
|
||||||
router.navigate({ to: RequestRoute.fullPath, params: { workspaceId, requestId }, search });
|
await navigate({
|
||||||
|
to: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
|
params: { workspaceId, requestId },
|
||||||
|
search,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
router.navigate({ to: WorkspaceRoute.fullPath, params: { workspaceId }, search });
|
await navigate({ to: '/workspaces/$workspaceId', params: { workspaceId }, search });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { DialogProps } from '../components/core/Dialog';
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
import { useDialog } from '../components/DialogContext';
|
|
||||||
import type { PromptProps } from './Prompt';
|
import type { PromptProps } from './Prompt';
|
||||||
import { Prompt } from './Prompt';
|
import { Prompt } from './Prompt';
|
||||||
|
import {useDialog} from "./useDialog";
|
||||||
|
|
||||||
type Props = Pick<DialogProps, 'title' | 'description'> &
|
type Props = Pick<DialogProps, 'title' | 'description'> &
|
||||||
Omit<PromptProps, 'onClose' | 'onCancel' | 'onResult'> & { id: string };
|
Omit<PromptProps, 'onClose' | 'onCancel' | 'onResult'> & { id: string };
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { save } from '@tauri-apps/plugin-dialog';
|
|||||||
import mime from 'mime';
|
import mime from 'mime';
|
||||||
import slugify from 'slugify';
|
import slugify from 'slugify';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { useToast } from '../components/ToastContext';
|
import { useToast } from './useToast';
|
||||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||||
import { getContentTypeHeader } from '../lib/model_util';
|
import { getContentTypeHeader } from '../lib/model_util';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||||
import type { AnyModel } from '@yaakapp-internal/models';
|
import type { AnyModel } from '@yaakapp-internal/models';
|
||||||
import { useSetAtom } from 'jotai/index';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { extractKeyValue } from '../lib/keyValueStore';
|
import { extractKeyValue } from '../lib/keyValueStore';
|
||||||
import { modelsEq } from '../lib/model_util';
|
import { modelsEq } from '../lib/model_util';
|
||||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||||
@@ -30,17 +30,6 @@ export function useSyncModelStores() {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
||||||
|
|
||||||
const setSettings = useSetAtom(settingsAtom);
|
|
||||||
const setWorkspaces = useSetAtom(workspacesAtom);
|
|
||||||
const setCookieJars = useSetAtom(cookieJarsAtom);
|
|
||||||
const setFolders = useSetAtom(foldersAtom);
|
|
||||||
const setPlugins = useSetAtom(pluginsAtom);
|
|
||||||
const setHttpRequests = useSetAtom(httpRequestsAtom);
|
|
||||||
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
|
||||||
const setGrpcConnections = useSetAtom(grpcConnectionsAtom);
|
|
||||||
const setGrpcRequests = useSetAtom(grpcRequestsAtom);
|
|
||||||
const setEnvironments = useSetAtom(environmentsAtom);
|
|
||||||
|
|
||||||
useListenToTauriEvent<ModelPayload>('upserted_model', ({ payload }) => {
|
useListenToTauriEvent<ModelPayload>('upserted_model', ({ payload }) => {
|
||||||
const { model, windowLabel } = payload;
|
const { model, windowLabel } = payload;
|
||||||
const queryKey =
|
const queryKey =
|
||||||
@@ -63,25 +52,25 @@ export function useSyncModelStores() {
|
|||||||
if (shouldIgnoreModel(model, windowLabel)) return;
|
if (shouldIgnoreModel(model, windowLabel)) return;
|
||||||
|
|
||||||
if (model.model === 'workspace') {
|
if (model.model === 'workspace') {
|
||||||
setWorkspaces(updateModelList(model));
|
jotaiStore.set(workspacesAtom, updateModelList(model));
|
||||||
} else if (model.model === 'plugin') {
|
} else if (model.model === 'plugin') {
|
||||||
setPlugins(updateModelList(model));
|
jotaiStore.set(pluginsAtom, updateModelList(model));
|
||||||
} else if (model.model === 'http_request') {
|
} else if (model.model === 'http_request') {
|
||||||
setHttpRequests(updateModelList(model));
|
jotaiStore.set(httpRequestsAtom, updateModelList(model));
|
||||||
} else if (model.model === 'folder') {
|
} else if (model.model === 'folder') {
|
||||||
setFolders(updateModelList(model));
|
jotaiStore.set(foldersAtom, updateModelList(model));
|
||||||
} else if (model.model === 'http_response') {
|
} else if (model.model === 'http_response') {
|
||||||
setHttpResponses(updateModelList(model));
|
jotaiStore.set(httpResponsesAtom, updateModelList(model));
|
||||||
} else if (model.model === 'grpc_request') {
|
} else if (model.model === 'grpc_request') {
|
||||||
setGrpcRequests(updateModelList(model));
|
jotaiStore.set(grpcRequestsAtom, updateModelList(model));
|
||||||
} else if (model.model === 'grpc_connection') {
|
} else if (model.model === 'grpc_connection') {
|
||||||
setGrpcConnections(updateModelList(model));
|
jotaiStore.set(grpcConnectionsAtom, updateModelList(model));
|
||||||
} else if (model.model === 'environment') {
|
} else if (model.model === 'environment') {
|
||||||
setEnvironments(updateModelList(model));
|
jotaiStore.set(environmentsAtom, updateModelList(model));
|
||||||
} else if (model.model === 'cookie_jar') {
|
} else if (model.model === 'cookie_jar') {
|
||||||
setCookieJars(updateModelList(model));
|
jotaiStore.set(cookieJarsAtom, updateModelList(model));
|
||||||
} else if (model.model === 'settings') {
|
} else if (model.model === 'settings') {
|
||||||
setSettings(model);
|
jotaiStore.set(settingsAtom, model);
|
||||||
} else if (queryKey != null) {
|
} else if (queryKey != null) {
|
||||||
// TODO: Convert all models to use Jotai
|
// TODO: Convert all models to use Jotai
|
||||||
queryClient.setQueryData(queryKey, (current: unknown) => {
|
queryClient.setQueryData(queryKey, (current: unknown) => {
|
||||||
@@ -104,27 +93,27 @@ export function useSyncModelStores() {
|
|||||||
console.log('Delete model', payload);
|
console.log('Delete model', payload);
|
||||||
|
|
||||||
if (model.model === 'workspace') {
|
if (model.model === 'workspace') {
|
||||||
setWorkspaces(removeModelById(model));
|
jotaiStore.set(workspacesAtom, removeModelById(model));
|
||||||
} else if (model.model === 'plugin') {
|
} else if (model.model === 'plugin') {
|
||||||
setPlugins(removeModelById(model));
|
jotaiStore.set(pluginsAtom, removeModelById(model));
|
||||||
} else if (model.model === 'http_request') {
|
} else if (model.model === 'http_request') {
|
||||||
setHttpRequests(removeModelById(model));
|
jotaiStore.set(httpRequestsAtom, removeModelById(model));
|
||||||
} else if (model.model === 'http_response') {
|
} else if (model.model === 'http_response') {
|
||||||
setHttpResponses(removeModelById(model));
|
jotaiStore.set(httpResponsesAtom, removeModelById(model));
|
||||||
} else if (model.model === 'folder') {
|
} else if (model.model === 'folder') {
|
||||||
setFolders(removeModelById(model));
|
jotaiStore.set(foldersAtom, removeModelById(model));
|
||||||
} else if (model.model === 'environment') {
|
} else if (model.model === 'environment') {
|
||||||
setEnvironments(removeModelById(model));
|
jotaiStore.set(environmentsAtom, removeModelById(model));
|
||||||
} else if (model.model === 'grpc_request') {
|
} else if (model.model === 'grpc_request') {
|
||||||
setGrpcRequests(removeModelById(model));
|
jotaiStore.set(grpcRequestsAtom, removeModelById(model));
|
||||||
} else if (model.model === 'grpc_connection') {
|
} else if (model.model === 'grpc_connection') {
|
||||||
setGrpcConnections(removeModelById(model));
|
jotaiStore.set(grpcConnectionsAtom, removeModelById(model));
|
||||||
} else if (model.model === 'grpc_event') {
|
} else if (model.model === 'grpc_event') {
|
||||||
queryClient.setQueryData(grpcEventsQueryKey(model), removeModelById(model));
|
queryClient.setQueryData(grpcEventsQueryKey(model), removeModelById(model));
|
||||||
} else if (model.model === 'key_value') {
|
} else if (model.model === 'key_value') {
|
||||||
queryClient.setQueryData(keyValueQueryKey(model), undefined);
|
queryClient.setQueryData(keyValueQueryKey(model), undefined);
|
||||||
} else if (model.model === 'cookie_jar') {
|
} else if (model.model === 'cookie_jar') {
|
||||||
setCookieJars(removeModelById(model));
|
jotaiStore.set(cookieJarsAtom, removeModelById(model));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
6
src-web/hooks/useToast.ts
Normal file
6
src-web/hooks/useToast.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { ToastContext } from '../components/ToastContext';
|
||||||
|
|
||||||
|
export function useToast() {
|
||||||
|
return useContext(ToastContext).actions;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { CommandPalette } from '../components/CommandPalette';
|
import { CommandPalette } from '../components/CommandPalette';
|
||||||
import { useDialog } from '../components/DialogContext';
|
import { useDialog } from './useDialog';
|
||||||
|
|
||||||
export function useToggleCommandPalette() {
|
export function useToggleCommandPalette() {
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
|
|||||||
5
src-web/lib/constants.ts
Normal file
5
src-web/lib/constants.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
export const HEADER_SIZE_MD = '27px';
|
||||||
|
export const HEADER_SIZE_LG = '38px';
|
||||||
|
|
||||||
|
export const WINDOW_CONTROLS_WIDTH = '10.5rem';
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { EditorProps } from '../components/core/Editor';
|
import type { EditorProps } from '../components/core/Editor/Editor';
|
||||||
|
|
||||||
export function languageFromContentType(
|
export function languageFromContentType(
|
||||||
contentType: string | null,
|
contentType: string | null,
|
||||||
|
|||||||
3
src-web/lib/jotai.ts
Normal file
3
src-web/lib/jotai.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { createStore } from 'jotai/index';
|
||||||
|
|
||||||
|
export const jotaiStore = createStore();
|
||||||
12
src-web/lib/router.ts
Normal file
12
src-web/lib/router.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Create a new router instance
|
||||||
|
import {createRouter} from "@tanstack/react-router";
|
||||||
|
import {routeTree} from "../routeTree.gen";
|
||||||
|
|
||||||
|
export const router = createRouter({ routeTree });
|
||||||
|
|
||||||
|
// Register the router instance for type safety
|
||||||
|
declare module '@tanstack/react-router' {
|
||||||
|
interface Register {
|
||||||
|
router: typeof router;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import './main.css';
|
import './main.css';
|
||||||
import { createRouter, RouterProvider } from '@tanstack/react-router';
|
import { RouterProvider } from '@tanstack/react-router';
|
||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||||
import { type } from '@tauri-apps/plugin-os';
|
import { type } from '@tauri-apps/plugin-os';
|
||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { routeTree } from './routeTree.gen';
|
import { router } from './lib/router';
|
||||||
|
|
||||||
import('react-pdf').then(({ pdfjs }) => {
|
import('react-pdf').then(({ pdfjs }) => {
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||||
@@ -25,18 +25,7 @@ window.addEventListener('keydown', (e) => {
|
|||||||
if (e.key === 'Backspace' && e.target === document.body) e.preventDefault();
|
if (e.key === 'Backspace' && e.target === document.body) e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a new router instance
|
console.log('Creating React root');
|
||||||
export const router = createRouter({
|
|
||||||
routeTree,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register the router instance for type safety
|
|
||||||
declare module '@tanstack/react-router' {
|
|
||||||
interface Register {
|
|
||||||
router: typeof router;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createRoot(document.getElementById('root') as HTMLElement).render(
|
createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev --force",
|
"dev": "vite dev --force --debug hmr",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"lint": "tsc --noEmit && eslint . --ext .ts,.tsx"
|
"lint": "tsc --noEmit && eslint . --ext .ts,.tsx"
|
||||||
},
|
},
|
||||||
@@ -54,7 +54,6 @@
|
|||||||
"react-helmet-async": "^2.0.5",
|
"react-helmet-async": "^2.0.5",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-pdf": "^9.1.0",
|
"react-pdf": "^9.1.0",
|
||||||
"react-router-dom": "^6.26.2",
|
|
||||||
"react-use": "^17.5.1",
|
"react-use": "^17.5.1",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
@@ -79,6 +78,7 @@
|
|||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"decompress": "^4.2.1",
|
"decompress": "^4.2.1",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.16",
|
||||||
"internal-ip": "^8.0.0",
|
"internal-ip": "^8.0.0",
|
||||||
"postcss": "^8.4.45",
|
"postcss": "^8.4.45",
|
||||||
"postcss-nesting": "^13.0.0",
|
"postcss-nesting": "^13.0.0",
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
import { Route as rootRoute } from './routes/__root'
|
import { Route as rootRoute } from './routes/__root'
|
||||||
import { Route as IndexImport } from './routes/index'
|
import { Route as IndexImport } from './routes/index'
|
||||||
import { Route as WorkspacesIndexImport } from './routes/workspaces/index'
|
import { Route as WorkspacesIndexImport } from './routes/workspaces/index'
|
||||||
import { Route as WorkspacesSettingsImport } from './routes/workspaces/settings'
|
|
||||||
import { Route as WorkspacesWorkspaceIdIndexImport } from './routes/workspaces/$workspaceId/index'
|
import { Route as WorkspacesWorkspaceIdIndexImport } from './routes/workspaces/$workspaceId/index'
|
||||||
|
import { Route as WorkspacesWorkspaceIdSettingsImport } from './routes/workspaces/$workspaceId/settings'
|
||||||
import { Route as WorkspacesWorkspaceIdRequestsRequestIdImport } from './routes/workspaces/$workspaceId/requests/$requestId'
|
import { Route as WorkspacesWorkspaceIdRequestsRequestIdImport } from './routes/workspaces/$workspaceId/requests/$requestId'
|
||||||
|
|
||||||
// Create/Update Routes
|
// Create/Update Routes
|
||||||
@@ -31,12 +31,6 @@ const WorkspacesIndexRoute = WorkspacesIndexImport.update({
|
|||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
const WorkspacesSettingsRoute = WorkspacesSettingsImport.update({
|
|
||||||
id: '/workspaces/settings',
|
|
||||||
path: '/workspaces/settings',
|
|
||||||
getParentRoute: () => rootRoute,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
const WorkspacesWorkspaceIdIndexRoute = WorkspacesWorkspaceIdIndexImport.update(
|
const WorkspacesWorkspaceIdIndexRoute = WorkspacesWorkspaceIdIndexImport.update(
|
||||||
{
|
{
|
||||||
id: '/workspaces/$workspaceId/',
|
id: '/workspaces/$workspaceId/',
|
||||||
@@ -45,6 +39,13 @@ const WorkspacesWorkspaceIdIndexRoute = WorkspacesWorkspaceIdIndexImport.update(
|
|||||||
} as any,
|
} as any,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const WorkspacesWorkspaceIdSettingsRoute =
|
||||||
|
WorkspacesWorkspaceIdSettingsImport.update({
|
||||||
|
id: '/workspaces/$workspaceId/settings',
|
||||||
|
path: '/workspaces/$workspaceId/settings',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const WorkspacesWorkspaceIdRequestsRequestIdRoute =
|
const WorkspacesWorkspaceIdRequestsRequestIdRoute =
|
||||||
WorkspacesWorkspaceIdRequestsRequestIdImport.update({
|
WorkspacesWorkspaceIdRequestsRequestIdImport.update({
|
||||||
id: '/workspaces/$workspaceId/requests/$requestId',
|
id: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
@@ -63,13 +64,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexImport
|
preLoaderRoute: typeof IndexImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
'/workspaces/settings': {
|
|
||||||
id: '/workspaces/settings'
|
|
||||||
path: '/workspaces/settings'
|
|
||||||
fullPath: '/workspaces/settings'
|
|
||||||
preLoaderRoute: typeof WorkspacesSettingsImport
|
|
||||||
parentRoute: typeof rootRoute
|
|
||||||
}
|
|
||||||
'/workspaces/': {
|
'/workspaces/': {
|
||||||
id: '/workspaces/'
|
id: '/workspaces/'
|
||||||
path: '/workspaces'
|
path: '/workspaces'
|
||||||
@@ -77,6 +71,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof WorkspacesIndexImport
|
preLoaderRoute: typeof WorkspacesIndexImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/workspaces/$workspaceId/settings': {
|
||||||
|
id: '/workspaces/$workspaceId/settings'
|
||||||
|
path: '/workspaces/$workspaceId/settings'
|
||||||
|
fullPath: '/workspaces/$workspaceId/settings'
|
||||||
|
preLoaderRoute: typeof WorkspacesWorkspaceIdSettingsImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
'/workspaces/$workspaceId/': {
|
'/workspaces/$workspaceId/': {
|
||||||
id: '/workspaces/$workspaceId/'
|
id: '/workspaces/$workspaceId/'
|
||||||
path: '/workspaces/$workspaceId'
|
path: '/workspaces/$workspaceId'
|
||||||
@@ -98,16 +99,16 @@ declare module '@tanstack/react-router' {
|
|||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/workspaces/settings': typeof WorkspacesSettingsRoute
|
|
||||||
'/workspaces': typeof WorkspacesIndexRoute
|
'/workspaces': typeof WorkspacesIndexRoute
|
||||||
|
'/workspaces/$workspaceId/settings': typeof WorkspacesWorkspaceIdSettingsRoute
|
||||||
'/workspaces/$workspaceId': typeof WorkspacesWorkspaceIdIndexRoute
|
'/workspaces/$workspaceId': typeof WorkspacesWorkspaceIdIndexRoute
|
||||||
'/workspaces/$workspaceId/requests/$requestId': typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
'/workspaces/$workspaceId/requests/$requestId': typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/workspaces/settings': typeof WorkspacesSettingsRoute
|
|
||||||
'/workspaces': typeof WorkspacesIndexRoute
|
'/workspaces': typeof WorkspacesIndexRoute
|
||||||
|
'/workspaces/$workspaceId/settings': typeof WorkspacesWorkspaceIdSettingsRoute
|
||||||
'/workspaces/$workspaceId': typeof WorkspacesWorkspaceIdIndexRoute
|
'/workspaces/$workspaceId': typeof WorkspacesWorkspaceIdIndexRoute
|
||||||
'/workspaces/$workspaceId/requests/$requestId': typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
'/workspaces/$workspaceId/requests/$requestId': typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
||||||
}
|
}
|
||||||
@@ -115,8 +116,8 @@ export interface FileRoutesByTo {
|
|||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRoute
|
__root__: typeof rootRoute
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/workspaces/settings': typeof WorkspacesSettingsRoute
|
|
||||||
'/workspaces/': typeof WorkspacesIndexRoute
|
'/workspaces/': typeof WorkspacesIndexRoute
|
||||||
|
'/workspaces/$workspaceId/settings': typeof WorkspacesWorkspaceIdSettingsRoute
|
||||||
'/workspaces/$workspaceId/': typeof WorkspacesWorkspaceIdIndexRoute
|
'/workspaces/$workspaceId/': typeof WorkspacesWorkspaceIdIndexRoute
|
||||||
'/workspaces/$workspaceId/requests/$requestId': typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
'/workspaces/$workspaceId/requests/$requestId': typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
||||||
}
|
}
|
||||||
@@ -125,22 +126,22 @@ export interface FileRouteTypes {
|
|||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths:
|
fullPaths:
|
||||||
| '/'
|
| '/'
|
||||||
| '/workspaces/settings'
|
|
||||||
| '/workspaces'
|
| '/workspaces'
|
||||||
|
| '/workspaces/$workspaceId/settings'
|
||||||
| '/workspaces/$workspaceId'
|
| '/workspaces/$workspaceId'
|
||||||
| '/workspaces/$workspaceId/requests/$requestId'
|
| '/workspaces/$workspaceId/requests/$requestId'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to:
|
||||||
| '/'
|
| '/'
|
||||||
| '/workspaces/settings'
|
|
||||||
| '/workspaces'
|
| '/workspaces'
|
||||||
|
| '/workspaces/$workspaceId/settings'
|
||||||
| '/workspaces/$workspaceId'
|
| '/workspaces/$workspaceId'
|
||||||
| '/workspaces/$workspaceId/requests/$requestId'
|
| '/workspaces/$workspaceId/requests/$requestId'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
| '/'
|
| '/'
|
||||||
| '/workspaces/settings'
|
|
||||||
| '/workspaces/'
|
| '/workspaces/'
|
||||||
|
| '/workspaces/$workspaceId/settings'
|
||||||
| '/workspaces/$workspaceId/'
|
| '/workspaces/$workspaceId/'
|
||||||
| '/workspaces/$workspaceId/requests/$requestId'
|
| '/workspaces/$workspaceId/requests/$requestId'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
@@ -148,16 +149,16 @@ export interface FileRouteTypes {
|
|||||||
|
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
WorkspacesSettingsRoute: typeof WorkspacesSettingsRoute
|
|
||||||
WorkspacesIndexRoute: typeof WorkspacesIndexRoute
|
WorkspacesIndexRoute: typeof WorkspacesIndexRoute
|
||||||
|
WorkspacesWorkspaceIdSettingsRoute: typeof WorkspacesWorkspaceIdSettingsRoute
|
||||||
WorkspacesWorkspaceIdIndexRoute: typeof WorkspacesWorkspaceIdIndexRoute
|
WorkspacesWorkspaceIdIndexRoute: typeof WorkspacesWorkspaceIdIndexRoute
|
||||||
WorkspacesWorkspaceIdRequestsRequestIdRoute: typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
WorkspacesWorkspaceIdRequestsRequestIdRoute: typeof WorkspacesWorkspaceIdRequestsRequestIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
WorkspacesSettingsRoute: WorkspacesSettingsRoute,
|
|
||||||
WorkspacesIndexRoute: WorkspacesIndexRoute,
|
WorkspacesIndexRoute: WorkspacesIndexRoute,
|
||||||
|
WorkspacesWorkspaceIdSettingsRoute: WorkspacesWorkspaceIdSettingsRoute,
|
||||||
WorkspacesWorkspaceIdIndexRoute: WorkspacesWorkspaceIdIndexRoute,
|
WorkspacesWorkspaceIdIndexRoute: WorkspacesWorkspaceIdIndexRoute,
|
||||||
WorkspacesWorkspaceIdRequestsRequestIdRoute:
|
WorkspacesWorkspaceIdRequestsRequestIdRoute:
|
||||||
WorkspacesWorkspaceIdRequestsRequestIdRoute,
|
WorkspacesWorkspaceIdRequestsRequestIdRoute,
|
||||||
@@ -174,8 +175,8 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "__root.tsx",
|
"filePath": "__root.tsx",
|
||||||
"children": [
|
"children": [
|
||||||
"/",
|
"/",
|
||||||
"/workspaces/settings",
|
|
||||||
"/workspaces/",
|
"/workspaces/",
|
||||||
|
"/workspaces/$workspaceId/settings",
|
||||||
"/workspaces/$workspaceId/",
|
"/workspaces/$workspaceId/",
|
||||||
"/workspaces/$workspaceId/requests/$requestId"
|
"/workspaces/$workspaceId/requests/$requestId"
|
||||||
]
|
]
|
||||||
@@ -183,12 +184,12 @@ export const routeTree = rootRoute
|
|||||||
"/": {
|
"/": {
|
||||||
"filePath": "index.tsx"
|
"filePath": "index.tsx"
|
||||||
},
|
},
|
||||||
"/workspaces/settings": {
|
|
||||||
"filePath": "workspaces/settings.tsx"
|
|
||||||
},
|
|
||||||
"/workspaces/": {
|
"/workspaces/": {
|
||||||
"filePath": "workspaces/index.tsx"
|
"filePath": "workspaces/index.tsx"
|
||||||
},
|
},
|
||||||
|
"/workspaces/$workspaceId/settings": {
|
||||||
|
"filePath": "workspaces/$workspaceId/settings.tsx"
|
||||||
|
},
|
||||||
"/workspaces/$workspaceId/": {
|
"/workspaces/$workspaceId/": {
|
||||||
"filePath": "workspaces/$workspaceId/index.tsx"
|
"filePath": "workspaces/$workspaceId/index.tsx"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,15 +2,16 @@ import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-qu
|
|||||||
import { createRootRoute, Outlet } from '@tanstack/react-router';
|
import { createRootRoute, Outlet } from '@tanstack/react-router';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { MotionConfig } from 'framer-motion';
|
import { MotionConfig } from 'framer-motion';
|
||||||
import { createStore, Provider as JotaiProvider } from 'jotai';
|
import { Provider as JotaiProvider } from 'jotai';
|
||||||
import React, { Suspense } from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
import { DialogProvider, Dialogs } from '../components/DialogContext';
|
|
||||||
import { GlobalHooks } from '../components/GlobalHooks';
|
import { GlobalHooks } from '../components/GlobalHooks';
|
||||||
import { ToastProvider, Toasts } from '../components/ToastContext';
|
|
||||||
import { useOsInfo } from '../hooks/useOsInfo';
|
import { useOsInfo } from '../hooks/useOsInfo';
|
||||||
|
import { jotaiStore } from '../lib/jotai';
|
||||||
|
import { ToastProvider, Toasts } from '../components/Toasts';
|
||||||
|
import { DialogProvider, Dialogs } from '../components/Dialogs';
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
queryCache: new QueryCache({
|
queryCache: new QueryCache({
|
||||||
@@ -53,8 +54,6 @@ export const Route = createRootRoute({
|
|||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const jotaiStore = createStore();
|
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const osInfo = useOsInfo();
|
const osInfo = useOsInfo();
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
import Settings, { SettingsTab } from '../../components/Settings/Settings'
|
import Settings from '../../../components/Settings/Settings'
|
||||||
|
import { SettingsTab } from '../../../components/Settings/SettingsTab'
|
||||||
|
|
||||||
interface SettingsSearchSchema {
|
interface SettingsSearchSchema {
|
||||||
tab?: SettingsTab
|
tab?: SettingsTab
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Route = createFileRoute('/workspaces/settings')({
|
export const Route = createFileRoute('/workspaces/$workspaceId/settings')({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
validateSearch: (search: Record<string, unknown>): SettingsSearchSchema => ({
|
validateSearch: (search: Record<string, unknown>): SettingsSearchSchema => ({
|
||||||
tab: (search.tab ?? SettingsTab.General) as SettingsTab,
|
tab: (search.tab ?? SettingsTab.General) as SettingsTab,
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"autoCodeSplitting": true
|
"autoCodeSplitting": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TanStackRouterVite } from '@tanstack/router-plugin/vite';
|
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import { internalIpV4 } from 'internal-ip';
|
import { internalIpV4 } from 'internal-ip';
|
||||||
import { createRequire } from 'node:module';
|
import { createRequire } from 'node:module';
|
||||||
@@ -7,6 +7,8 @@ import { defineConfig, normalizePath } from 'vite';
|
|||||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||||
import svgr from 'vite-plugin-svgr';
|
import svgr from 'vite-plugin-svgr';
|
||||||
import topLevelAwait from 'vite-plugin-top-level-await';
|
import topLevelAwait from 'vite-plugin-top-level-await';
|
||||||
|
// @ts-ignore
|
||||||
|
import { TanStackRouterVite } from '@tanstack/router-plugin/vite';
|
||||||
|
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
const cMapsDir = normalizePath(
|
const cMapsDir = normalizePath(
|
||||||
@@ -21,6 +23,7 @@ const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM ?? '');
|
|||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(async () => ({
|
export default defineConfig(async () => ({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
reactRefresh.configs.vite,
|
||||||
TanStackRouterVite({
|
TanStackRouterVite({
|
||||||
routesDirectory: './routes',
|
routesDirectory: './routes',
|
||||||
generatedRouteTree: './routeTree.gen.ts',
|
generatedRouteTree: './routeTree.gen.ts',
|
||||||
|
|||||||
Reference in New Issue
Block a user