mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-25 02:41:07 +01:00
Filesystem Sync (#142)
This commit is contained in:
@@ -1,21 +1,28 @@
|
||||
import { applySync, calculateSync } from '@yaakapp-internal/sync';
|
||||
import classNames from 'classnames';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useConfirm } from '../hooks/useConfirm';
|
||||
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
|
||||
import { useDialog } from '../hooks/useDialog';
|
||||
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
|
||||
import { useSettings } from '../hooks/useSettings';
|
||||
import { useToast } from '../hooks/useToast';
|
||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import { pluralizeCount } from '../lib/pluralize';
|
||||
import { getWorkspace } from '../lib/store';
|
||||
import type { ButtonProps } from './core/Button';
|
||||
import { Button } from './core/Button';
|
||||
import type { DropdownItem } from './core/Dropdown';
|
||||
import { Icon } from './core/Icon';
|
||||
import { InlineCode } from './core/InlineCode';
|
||||
import type { RadioDropdownItem } from './core/RadioDropdown';
|
||||
import { RadioDropdown } from './core/RadioDropdown';
|
||||
import { VStack } from './core/Stacks';
|
||||
import { OpenWorkspaceDialog } from './OpenWorkspaceDialog';
|
||||
import { WorkspaceSettingsDialog } from './WorkpaceSettingsDialog';
|
||||
import { WorkspaceSettingsDialog } from './WorkspaceSettingsDialog';
|
||||
|
||||
type Props = Pick<ButtonProps, 'className' | 'justify' | 'forDropdown' | 'leftSlot'>;
|
||||
|
||||
@@ -25,10 +32,11 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
}: Props) {
|
||||
const workspaces = useWorkspaces();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const activeWorkspaceId = activeWorkspace?.id ?? null;
|
||||
const { mutate: createWorkspace } = useCreateWorkspace();
|
||||
const createWorkspace = useCreateWorkspace();
|
||||
const { mutate: deleteSendHistory } = useDeleteSendHistory();
|
||||
const dialog = useDialog();
|
||||
const confirm = useConfirm();
|
||||
const toast = useToast();
|
||||
const settings = useSettings();
|
||||
const openWorkspace = useOpenWorkspace();
|
||||
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
|
||||
@@ -46,7 +54,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
key: w.id,
|
||||
label: w.name,
|
||||
value: w.id,
|
||||
leftSlot: w.id === activeWorkspaceId ? <Icon icon="check" /> : <Icon icon="empty" />,
|
||||
leftSlot: w.id === activeWorkspace?.id ? <Icon icon="check" /> : <Icon icon="empty" />,
|
||||
}));
|
||||
|
||||
const extraItems: DropdownItem[] = [
|
||||
@@ -54,6 +62,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
key: 'workspace-settings',
|
||||
label: 'Workspace Settings',
|
||||
leftSlot: <Icon icon="settings" />,
|
||||
hotKeyAction: 'workspace_settings.show',
|
||||
onSelect: async () => {
|
||||
dialog.show({
|
||||
id: 'workspace-settings',
|
||||
@@ -63,6 +72,96 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'sync',
|
||||
label: 'Sync Workspace',
|
||||
leftSlot: <Icon icon="folder_sync" />,
|
||||
hidden: !activeWorkspace?.settingSyncDir,
|
||||
onSelect: async () => {
|
||||
if (activeWorkspace == null) return;
|
||||
|
||||
const ops = await calculateSync(activeWorkspace);
|
||||
if (ops.length === 0) {
|
||||
toast.show({
|
||||
id: 'no-sync-changes',
|
||||
message: 'No changes detected for sync',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const dbChanges = ops.filter((o) => o.type.startsWith('db'));
|
||||
|
||||
if (dbChanges.length === 0) {
|
||||
await applySync(activeWorkspace, ops);
|
||||
toast.show({
|
||||
id: 'applied-sync-changes',
|
||||
message: `Applied ${pluralizeCount('change', ops.length)}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await confirm({
|
||||
id: 'commit-sync',
|
||||
title: 'Filesystem Changes Detected',
|
||||
confirmText: 'Apply Changes',
|
||||
description: (
|
||||
<VStack space={3}>
|
||||
<p>
|
||||
Some files in the directory have changed. Do you want to apply the updates to your
|
||||
workspace?
|
||||
</p>
|
||||
<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>
|
||||
</VStack>
|
||||
),
|
||||
});
|
||||
if (confirmed) {
|
||||
await applySync(activeWorkspace, ops);
|
||||
toast.show({
|
||||
id: 'applied-confirmed-sync-changes',
|
||||
message: `Applied ${pluralizeCount('change', ops.length)}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'delete-responses',
|
||||
label: 'Clear Send History',
|
||||
@@ -80,12 +179,13 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
|
||||
return { workspaceItems, extraItems };
|
||||
}, [
|
||||
activeWorkspace?.id,
|
||||
activeWorkspaceId,
|
||||
createWorkspace,
|
||||
deleteSendHistory,
|
||||
dialog,
|
||||
orderedWorkspaces,
|
||||
activeWorkspace,
|
||||
deleteSendHistory,
|
||||
createWorkspace,
|
||||
dialog,
|
||||
confirm,
|
||||
toast,
|
||||
]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
@@ -115,7 +215,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
items={workspaceItems}
|
||||
extraItems={extraItems}
|
||||
onChange={handleChange}
|
||||
value={activeWorkspaceId}
|
||||
value={activeWorkspace?.id ?? null}
|
||||
>
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user