Allow opening workspace if sync dir not empty

This commit is contained in:
Gregory Schier
2025-02-25 06:54:30 -08:00
parent 2db72fe6ef
commit 7af8c95fea
5 changed files with 48 additions and 24 deletions

View File

@@ -1,20 +1,11 @@
import { open } from '@tauri-apps/plugin-dialog';
import { applySync, calculateSyncFsOnly } from '@yaakapp-internal/sync'; import { applySync, calculateSyncFsOnly } from '@yaakapp-internal/sync';
import { createFastMutation } from '../hooks/useFastMutation'; import { createFastMutation } from '../hooks/useFastMutation';
import { showSimpleAlert } from '../lib/alert'; import { showSimpleAlert } from '../lib/alert';
import { router } from '../lib/router'; import { router } from '../lib/router';
export const openWorkspaceFromSyncDir = createFastMutation<void>({ export const openWorkspaceFromSyncDir = createFastMutation<void, void, string>({
mutationKey: [], mutationKey: [],
mutationFn: async () => { mutationFn: async (dir) => {
const dir = await open({
title: 'Select Workspace Directory',
directory: true,
multiple: false,
});
if (dir == null) return;
const ops = await calculateSyncFsOnly(dir); const ops = await calculateSyncFsOnly(dir);
const workspace = ops const workspace = ops

View File

@@ -20,7 +20,7 @@ export function CreateWorkspaceDialog({ hide }: Props) {
const [syncConfig, setSyncConfig] = useState<{ const [syncConfig, setSyncConfig] = useState<{
filePath: string | null; filePath: string | null;
initGit?: boolean; initGit?: boolean;
}>({ filePath: null, initGit: true }); }>({ filePath: null, initGit: false });
return ( return (
<VStack <VStack
@@ -62,8 +62,8 @@ export function CreateWorkspaceDialog({ hide }: Props) {
<SyncToFilesystemSetting <SyncToFilesystemSetting
onChange={setSyncConfig} onChange={setSyncConfig}
onCreateNewWorkspace={hide}
value={syncConfig} value={syncConfig}
allowNonEmptyDirectory // Will do initial import when the workspace is created
/> />
<Button type="submit" color="primary" className="ml-auto mt-3"> <Button type="submit" color="primary" className="ml-auto mt-3">
Create Workspace Create Workspace

View File

@@ -1,33 +1,54 @@
import { readDir } from '@tauri-apps/plugin-fs'; import { readDir } from '@tauri-apps/plugin-fs';
import { useState } from 'react'; import { useState } from 'react';
import { openWorkspaceFromSyncDir } from '../commands/openWorkspaceFromSyncDir';
import { Banner } from './core/Banner'; import { Banner } from './core/Banner';
import { Button } from './core/Button';
import { Checkbox } from './core/Checkbox'; import { Checkbox } from './core/Checkbox';
import { VStack } from './core/Stacks'; import { VStack } from './core/Stacks';
import { SelectFile } from './SelectFile'; import { SelectFile } from './SelectFile';
export interface SyncToFilesystemSettingProps { export interface SyncToFilesystemSettingProps {
onChange: (args: { filePath: string | null; initGit?: boolean }) => void; onChange: (args: { filePath: string | null; initGit?: boolean }) => void;
onCreateNewWorkspace: () => void;
value: { filePath: string | null; initGit?: boolean }; value: { filePath: string | null; initGit?: boolean };
allowNonEmptyDirectory?: boolean;
forceOpen?: boolean; forceOpen?: boolean;
} }
export function SyncToFilesystemSetting({ export function SyncToFilesystemSetting({
onChange, onChange,
onCreateNewWorkspace,
value, value,
allowNonEmptyDirectory,
forceOpen, forceOpen,
}: SyncToFilesystemSettingProps) { }: SyncToFilesystemSettingProps) {
const [error, setError] = useState<string | null>(null); const [isNonEmpty, setIsNonEmpty] = useState<string | null>(null);
return ( return (
<details open={forceOpen || !!value.filePath} className="w-full"> <details open={forceOpen || !!value.filePath} className="w-full">
<summary>Data directory {typeof value.initGit === 'boolean' && ' and Git'}</summary> <summary>Data directory {typeof value.initGit === 'boolean' && ' and Git'}</summary>
<VStack className="my-2" space={3}> <VStack className="my-2" space={3}>
<Banner color="info"> {isNonEmpty ? (
Sync workspace data to folder as plain text files, ideal for backup and Git collaboration. <Banner color="notice" className="flex flex-col gap-1.5">
Environments are excluded in order to keep your secrets private. <p>The selected directory must be empty. Did you want to open it instead?</p>
</Banner> <div>
{error && <div className="text-danger">{error}</div>} <Button
variant="border"
color="notice"
size="xs"
type="button"
onClick={() => {
openWorkspaceFromSyncDir.mutate(isNonEmpty);
onCreateNewWorkspace();
}}
>
Open Workspace
</Button>
</div>
</Banner>
) : (
<Banner color="info">
Sync workspace data to folder as plain text files, ideal for backup and Git
collaboration. Environments are excluded in order to keep your secrets private.
</Banner>
)}
<SelectFile <SelectFile
directory directory
@@ -37,12 +58,13 @@ export function SyncToFilesystemSetting({
onChange={async ({ filePath }) => { onChange={async ({ filePath }) => {
if (filePath != null) { if (filePath != null) {
const files = await readDir(filePath); const files = await readDir(filePath);
if (files.length > 0 && !allowNonEmptyDirectory) { if (files.length > 0) {
setError('The directory must be empty'); setIsNonEmpty(filePath);
return; return;
} }
} }
setIsNonEmpty(null);
onChange({ ...value, filePath }); onChange({ ...value, filePath });
}} }}
/> />

View File

@@ -1,3 +1,4 @@
import {open} from "@tauri-apps/plugin-dialog";
import { revealItemInDir } from '@tauri-apps/plugin-opener'; import { revealItemInDir } from '@tauri-apps/plugin-opener';
import classNames from 'classnames'; import classNames from 'classnames';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
@@ -75,7 +76,16 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
{ {
label: 'Open Existing Workspace', label: 'Open Existing Workspace',
leftSlot: <Icon icon="folder_open" />, leftSlot: <Icon icon="folder_open" />,
onSelect: openWorkspaceFromSyncDir.mutate, onSelect: async () => {
const dir = await open({
title: 'Select Workspace Directory',
directory: true,
multiple: false,
});
if (dir == null) return;
openWorkspaceFromSyncDir.mutate(dir);
},
}, },
]; ];

View File

@@ -63,6 +63,7 @@ export function WorkspaceSettingsDialog({ workspaceId, hide, openSyncMenu }: Pro
<SyncToFilesystemSetting <SyncToFilesystemSetting
value={{ filePath: workspaceMeta.settingSyncDir }} value={{ filePath: workspaceMeta.settingSyncDir }}
forceOpen={openSyncMenu} forceOpen={openSyncMenu}
onCreateNewWorkspace={hide}
onChange={({ filePath }) => { onChange={({ filePath }) => {
upsertWorkspaceMeta.mutate({ ...workspaceMeta, settingSyncDir: filePath }); upsertWorkspaceMeta.mutate({ ...workspaceMeta, settingSyncDir: filePath });
}} }}