mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-17 14:29:46 +02:00
Ability to open workspace from directory, WorkspaceMeta, and many sync improvements
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { createFolder } from '../commands/commands';
|
||||
import type { DropdownItem } from '../components/core/Dropdown';
|
||||
import { Icon } from '../components/core/Icon';
|
||||
import { createFolder } from '../lib/commands';
|
||||
import { generateId } from '../lib/generateId';
|
||||
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
||||
import { getActiveRequest } from './useActiveRequest';
|
||||
|
||||
@@ -36,6 +36,8 @@ export function createFastMutation<TData = unknown, TError = unknown, TVariables
|
||||
} finally {
|
||||
onSettled?.();
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const mutate = (
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
import type {EventCallback, EventName} from '@tauri-apps/api/event';
|
||||
import {listen} from '@tauri-apps/api/event';
|
||||
import {getCurrentWebviewWindow} from '@tauri-apps/api/webviewWindow';
|
||||
import {useEffect} from 'react';
|
||||
import type { EventCallback, EventName } from '@tauri-apps/api/event';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* React hook to listen to a Tauri event.
|
||||
*/
|
||||
export function useListenToTauriEvent<T>(event: EventName, fn: EventCallback<T>) {
|
||||
useEffect(() => {
|
||||
const unlisten = listen<T>(
|
||||
event,
|
||||
fn,
|
||||
// Listen to `emit_all()` events or events specific to the current window
|
||||
{ target: { label: getCurrentWebviewWindow().label, kind: 'Window' } },
|
||||
);
|
||||
|
||||
return () => {
|
||||
unlisten.then((fn) => fn());
|
||||
}
|
||||
}, [event, fn]);
|
||||
useEffect(() => listenToTauriEvent(event, fn), [event, fn]);
|
||||
}
|
||||
|
||||
export function listenToTauriEvent<T>(event: EventName, fn: EventCallback<T>) {
|
||||
const unlisten = listen<T>(
|
||||
event,
|
||||
fn,
|
||||
// Listen to `emit_all()` events or events specific to the current window
|
||||
{ target: { label: getCurrentWebviewWindow().label, kind: 'Window' } },
|
||||
);
|
||||
|
||||
return () => {
|
||||
unlisten.then((fn) => fn());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getRecentCookieJars } from './useRecentCookieJars';
|
||||
import { getRecentEnvironments } from './useRecentEnvironments';
|
||||
import { getRecentRequests } from './useRecentRequests';
|
||||
|
||||
export function useOpenWorkspace() {
|
||||
export function useSwitchWorkspace() {
|
||||
return useFastMutation({
|
||||
mutationKey: ['open_workspace'],
|
||||
mutationFn: async ({
|
||||
@@ -19,6 +19,7 @@ import { useListenToTauriEvent } from './useListenToTauriEvent';
|
||||
import { pluginsAtom } from './usePlugins';
|
||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||
import { settingsAtom } from './useSettings';
|
||||
import { workspaceMetaAtom } from './useWorkspaceMeta';
|
||||
import { workspacesAtom } from './useWorkspaces';
|
||||
|
||||
export function useSyncModelStores() {
|
||||
@@ -51,6 +52,8 @@ export function useSyncModelStores() {
|
||||
|
||||
if (payload.model.model === 'workspace') {
|
||||
jotaiStore.set(workspacesAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'workspace_meta') {
|
||||
jotaiStore.set(workspaceMetaAtom, payload.model);
|
||||
} else if (payload.model.model === 'plugin') {
|
||||
jotaiStore.set(pluginsAtom, updateModelList(payload.model));
|
||||
} else if (payload.model.model === 'http_request') {
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
import { debounce } from '@yaakapp-internal/lib';
|
||||
import type { Workspace } from '@yaakapp-internal/models';
|
||||
import { applySync, calculateSync } from '@yaakapp-internal/sync';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { VStack } from '../components/core/Stacks';
|
||||
import {showConfirm} from "../lib/confirm";
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
|
||||
export function useSyncWorkspace(
|
||||
workspace: Workspace | null,
|
||||
{
|
||||
debounceMillis = 1000,
|
||||
}: {
|
||||
debounceMillis?: number;
|
||||
} = {},
|
||||
) {
|
||||
const sync = useCallback(async () => {
|
||||
if (workspace == null || !workspace.settingSyncDir) return;
|
||||
|
||||
const ops = await calculateSync(workspace) ?? [];
|
||||
if (ops.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dbChanges = ops.filter((o) => o.type.startsWith('db'));
|
||||
|
||||
if (dbChanges.length === 0) {
|
||||
await applySync(workspace, ops);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Filesystem changes detected", dbChanges);
|
||||
|
||||
const confirmed = await showConfirm({
|
||||
id: 'commit-sync',
|
||||
title: 'Filesystem Changes Detected',
|
||||
confirmText: 'Apply Changes',
|
||||
description: (
|
||||
<VStack space={3}>
|
||||
<p>
|
||||
{pluralizeCount('file', dbChanges.length)} in the directory have changed. Do you want to
|
||||
apply the updates to your workspace?
|
||||
</p>
|
||||
<div className="overflow-y-auto max-h-[10rem]">
|
||||
<table className="w-full text-sm mb-auto min-w-full max-w-full divide-y divide-surface-highlight">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="py-1 text-left">Name</th>
|
||||
<th className="py-1 text-right pl-4">Operation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-surface-highlight">
|
||||
{dbChanges.map((op, i) => {
|
||||
let name = '';
|
||||
let label = '';
|
||||
let color = '';
|
||||
|
||||
if (op.type === 'dbCreate') {
|
||||
label = 'create';
|
||||
name = fallbackRequestName(op.fs.model);
|
||||
color = 'text-success';
|
||||
} else if (op.type === 'dbUpdate') {
|
||||
label = 'update';
|
||||
name = fallbackRequestName(op.fs.model);
|
||||
color = 'text-info';
|
||||
} else if (op.type === 'dbDelete') {
|
||||
label = 'delete';
|
||||
name = fallbackRequestName(op.model);
|
||||
color = 'text-danger';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={i} className="text-text">
|
||||
<td className="py-1">{name}</td>
|
||||
<td className="py-1 pl-4 text-right">
|
||||
<InlineCode className={color}>{label}</InlineCode>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</VStack>
|
||||
),
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
await applySync(workspace, ops);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
const debouncedSync = useMemo(() => {
|
||||
return debounce(sync, debounceMillis);
|
||||
}, [debounceMillis, sync]);
|
||||
|
||||
return { sync, debouncedSync };
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { WorkspaceMeta } from '@yaakapp-internal/models';
|
||||
import { useEffect } from 'react';
|
||||
import { jotaiStore } from '../lib/jotai';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
@@ -10,6 +11,7 @@ import { grpcRequestsAtom } from './useGrpcRequests';
|
||||
import { httpRequestsAtom } from './useHttpRequests';
|
||||
import { httpResponsesAtom } from './useHttpResponses';
|
||||
import { keyValuesAtom } from './useKeyValue';
|
||||
import { workspaceMetaAtom } from './useWorkspaceMeta';
|
||||
|
||||
export function useSyncWorkspaceChildModels() {
|
||||
useEffect(() => {
|
||||
@@ -39,4 +41,7 @@ async function sync() {
|
||||
jotaiStore.set(httpResponsesAtom, await invokeCmd('cmd_list_http_responses', args));
|
||||
jotaiStore.set(grpcConnectionsAtom, await invokeCmd('cmd_list_grpc_connections', args));
|
||||
jotaiStore.set(environmentsAtom, await invokeCmd('cmd_list_environments', args));
|
||||
|
||||
// Single models
|
||||
jotaiStore.set(workspaceMetaAtom, await invokeCmd<WorkspaceMeta>('cmd_get_workspace_meta', args));
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
import type { Workspace } from '@yaakapp-internal/models';
|
||||
import {useSetAtom} from "jotai/index";
|
||||
import { getWorkspace } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import {updateModelList} from "./useSyncModelStores";
|
||||
import {workspacesAtom} from "./useWorkspaces";
|
||||
import { useFastMutation } from './useFastMutation';
|
||||
|
||||
export function useUpdateWorkspace(id: string | null) {
|
||||
const setWorkspaces = useSetAtom(workspacesAtom);
|
||||
return useFastMutation<Workspace, unknown, Partial<Workspace> | ((w: Workspace) => Workspace)>({
|
||||
mutationKey: ['update_workspace', id],
|
||||
mutationFn: async (v) => {
|
||||
@@ -19,8 +15,5 @@ export function useUpdateWorkspace(id: string | null) {
|
||||
const newWorkspace = typeof v === 'function' ? v(workspace) : { ...workspace, ...v };
|
||||
return invokeCmd('cmd_update_workspace', { workspace: newWorkspace });
|
||||
},
|
||||
onSuccess: async (workspace) => {
|
||||
setWorkspaces(updateModelList(workspace));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
13
src-web/hooks/useWorkspaceMeta.ts
Normal file
13
src-web/hooks/useWorkspaceMeta.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { WorkspaceMeta } from '@yaakapp-internal/models';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
|
||||
export const workspaceMetaAtom = atom<WorkspaceMeta>();
|
||||
|
||||
export function useWorkspaceMeta() {
|
||||
const workspaceMeta = useAtomValue(workspaceMetaAtom);
|
||||
if (!workspaceMeta) {
|
||||
throw new Error('WorkspaceMeta not found');
|
||||
}
|
||||
|
||||
return workspaceMeta;
|
||||
}
|
||||
Reference in New Issue
Block a user