Stubbed out global commands helper

This commit is contained in:
Gregory Schier
2024-03-16 09:46:11 -07:00
parent 40f8a41a8d
commit 49da0e5aa8
8 changed files with 104 additions and 59 deletions

View File

@@ -1,10 +1,9 @@
import { createBrowserRouter, Navigate, Outlet, RouterProvider, useParams } from 'react-router-dom'; import { createBrowserRouter, Navigate, RouterProvider, useParams } from 'react-router-dom';
import { routePaths, useAppRoutes } from '../hooks/useAppRoutes'; import { routePaths, useAppRoutes } from '../hooks/useAppRoutes';
import { DialogProvider } from './DialogContext'; import { DefaultLayout } from './DefaultLayout';
import { GlobalHooks } from './GlobalHooks'; import { RedirectToLatestWorkspace } from './RedirectToLatestWorkspace';
import RouteError from './RouteError'; import RouteError from './RouteError';
import Workspace from './Workspace'; import Workspace from './Workspace';
import { RedirectToLatestWorkspace } from './RedirectToLatestWorkspace';
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
@@ -58,7 +57,7 @@ function RedirectLegacyEnvironmentURLs() {
}>(); }>();
const environmentId = rawEnvironmentId === '__default__' ? undefined : rawEnvironmentId; const environmentId = rawEnvironmentId === '__default__' ? undefined : rawEnvironmentId;
let to = '/'; let to;
if (workspaceId != null && requestId != null) { if (workspaceId != null && requestId != null) {
to = routes.paths.request({ workspaceId, environmentId, requestId }); to = routes.paths.request({ workspaceId, environmentId, requestId });
} else if (workspaceId != null) { } else if (workspaceId != null) {
@@ -69,12 +68,3 @@ function RedirectLegacyEnvironmentURLs() {
return <Navigate to={to} />; return <Navigate to={to} />;
} }
function DefaultLayout() {
return (
<DialogProvider>
<Outlet />
<GlobalHooks />
</DialogProvider>
);
}

View File

@@ -0,0 +1,12 @@
import { Outlet } from 'react-router-dom';
import { DialogProvider } from './DialogContext';
import { GlobalHooks } from './GlobalHooks';
export function DefaultLayout() {
return (
<DialogProvider>
<Outlet />
<GlobalHooks />
</DialogProvider>
);
}

View File

@@ -3,6 +3,7 @@ import { appWindow } from '@tauri-apps/api/window';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { cookieJarsQueryKey } from '../hooks/useCookieJars'; import { cookieJarsQueryKey } from '../hooks/useCookieJars';
import { useGlobalCommands } from '../hooks/useGlobalCommands';
import { grpcConnectionsQueryKey } from '../hooks/useGrpcConnections'; import { grpcConnectionsQueryKey } from '../hooks/useGrpcConnections';
import { grpcEventsQueryKey } from '../hooks/useGrpcEvents'; import { grpcEventsQueryKey } from '../hooks/useGrpcEvents';
import { grpcRequestsQueryKey } from '../hooks/useGrpcRequests'; import { grpcRequestsQueryKey } from '../hooks/useGrpcRequests';
@@ -32,8 +33,8 @@ export function GlobalHooks() {
useRecentRequests(); useRecentRequests();
useSyncAppearance(); useSyncAppearance();
useSyncWindowTitle(); useSyncWindowTitle();
useGlobalCommands();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { wasUpdatedExternally } = useRequestUpdateKey(null); const { wasUpdatedExternally } = useRequestUpdateKey(null);

View File

@@ -24,7 +24,7 @@ export function RedirectToLatestWorkspace() {
navigate(routes.paths.workspace({ workspaceId, environmentId })); navigate(routes.paths.workspace({ workspaceId, environmentId }));
} }
})(); })();
}, [navigate, routes.paths, workspaces, workspaces.length]); }, [navigate, recentWorkspaces, routes.paths, workspaces, workspaces.length]);
return <></>; return <></>;
} }

View File

@@ -3,7 +3,7 @@ import classNames from 'classnames';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace'; import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useAppRoutes } from '../hooks/useAppRoutes'; import { useAppRoutes } from '../hooks/useAppRoutes';
import { useCreateWorkspace } from '../hooks/useCreateWorkspace'; import { useCommand } from '../hooks/useCommands';
import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace'; import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace';
import { usePrompt } from '../hooks/usePrompt'; import { usePrompt } from '../hooks/usePrompt';
import { getRecentEnvironments } from '../hooks/useRecentEnvironments'; import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
@@ -30,7 +30,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
const activeWorkspaceId = activeWorkspace?.id ?? null; const activeWorkspaceId = activeWorkspace?.id ?? null;
const updateWorkspace = useUpdateWorkspace(activeWorkspaceId); const updateWorkspace = useUpdateWorkspace(activeWorkspaceId);
const deleteWorkspace = useDeleteWorkspace(activeWorkspace); const deleteWorkspace = useDeleteWorkspace(activeWorkspace);
const createWorkspace = useCreateWorkspace({ navigateAfter: true }); const createWorkspace = useCommand('workspace.create');
const dialog = useDialog(); const dialog = useDialog();
const prompt = usePrompt(); const prompt = usePrompt();
const routes = useAppRoutes(); const routes = useAppRoutes();

View File

@@ -0,0 +1,41 @@
import type { UseMutationOptions } from '@tanstack/react-query';
import { useMutation } from '@tanstack/react-query';
import { useEffect } from 'react';
import { createGlobalState } from 'react-use';
import type { TrackAction, TrackResource } from '../lib/analytics';
import type { Workspace } from '../lib/models';
interface CommandInstance<T, V> extends UseMutationOptions<V, unknown, T> {
track?: [TrackResource, TrackAction];
name: string;
}
export type Commands = {
'workspace.create': CommandInstance<Partial<Pick<Workspace, 'name'>>, Workspace>;
};
const useCommandState = createGlobalState<Commands>();
export function useRegisterCommand<K extends keyof Commands>(action: K, command: Commands[K]) {
const [, setState] = useCommandState();
useEffect(() => {
setState((commands) => {
return { ...commands, [action]: command };
});
// Remove action when it goes out of scope
return () => {
setState((commands) => {
return { ...commands, [action]: undefined };
});
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [action]);
}
export function useCommand<K extends keyof Commands>(action: K) {
const [commands] = useCommandState();
const cmd = commands[action];
return useMutation({ ...cmd });
}

View File

@@ -1,14 +1,18 @@
import { useMutation } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import type { Workspace } from '../lib/models';
import { useAppRoutes } from './useAppRoutes'; import { useAppRoutes } from './useAppRoutes';
import { useRegisterCommand } from './useCommands';
import { usePrompt } from './usePrompt'; import { usePrompt } from './usePrompt';
export function useCreateWorkspace({ navigateAfter }: { navigateAfter: boolean }) { export function useGlobalCommands() {
const routes = useAppRoutes();
const prompt = usePrompt(); const prompt = usePrompt();
return useMutation<Workspace, unknown, Partial<Pick<Workspace, 'name'>>>({ const routes = useAppRoutes();
useRegisterCommand('workspace.create', {
name: 'New Workspace',
track: ['workspace', 'create'],
onSuccess: async (workspace) => {
routes.navigate('workspace', { workspaceId: workspace.id });
},
mutationFn: async ({ name: patchName }) => { mutationFn: async ({ name: patchName }) => {
const name = const name =
patchName ?? patchName ??
@@ -23,11 +27,5 @@ export function useCreateWorkspace({ navigateAfter }: { navigateAfter: boolean }
})); }));
return invoke('cmd_create_workspace', { name }); return invoke('cmd_create_workspace', { name });
}, },
onSettled: () => trackEvent('workspace', 'create'),
onSuccess: async (workspace) => {
if (navigateAfter) {
routes.navigate('workspace', { workspaceId: workspace.id });
}
},
}); });
} }

View File

@@ -1,35 +1,38 @@
import { invoke } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
export function trackEvent( export type TrackResource =
resource: | 'app'
| 'app' | 'cookie_jar'
| 'cookie_jar' | 'dialog'
| 'dialog' | 'environment'
| 'environment' | 'folder'
| 'folder' | 'grpc_connection'
| 'grpc_connection' | 'grpc_event'
| 'grpc_event' | 'grpc_request'
| 'grpc_request' | 'http_request'
| 'http_request' | 'http_response'
| 'http_response' | 'key_value'
| 'key_value' | 'setting'
| 'setting' | 'sidebar'
| 'sidebar' | 'workspace';
| 'workspace',
action:
| 'cancel'
| 'commit'
| 'create'
| 'delete'
| 'delete_many'
| 'duplicate'
| 'hide'
| 'launch'
| 'send'
| 'show'
| 'toggle'
| 'update',
export type TrackAction =
| 'cancel'
| 'commit'
| 'create'
| 'delete'
| 'delete_many'
| 'duplicate'
| 'hide'
| 'launch'
| 'send'
| 'show'
| 'toggle'
| 'update';
export function trackEvent(
resource: TrackResource,
action: TrackAction,
attributes: Record<string, string | number> = {}, attributes: Record<string, string | number> = {},
) { ) {
invoke('cmd_track_event', { invoke('cmd_track_event', {