mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-07 00:53:28 +00:00
Cloud Sync Done
This commit is contained in:
parent
449fc43d30
commit
442bbe69fc
|
@ -15,6 +15,7 @@ import { ModalInput } from '~/components/primitive/Input';
|
|||
import useForwardedRef from '~/hooks/useForwardedRef';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { currentLibraryStore } from '~/utils/nav';
|
||||
import Card from '../layout/Card';
|
||||
|
||||
const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
|
||||
const navigation = useNavigation();
|
||||
|
@ -22,34 +23,10 @@ const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
|
||||
const queryClient = useQueryClient();
|
||||
const { libraries } = useClientContext();
|
||||
const [libName, setLibName] = useState('');
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const cloudLibraries = useBridgeQuery(['cloud.library.list']);
|
||||
const joinLibrary = useBridgeMutation(['cloud.library.join']);
|
||||
|
||||
// const { mutate: createLibrary, isLoading: createLibLoading } = useBridgeMutation(
|
||||
// 'library.create',
|
||||
// {
|
||||
// onSuccess: (lib) => {
|
||||
// // Reset form
|
||||
// setLibName('');
|
||||
|
||||
// // We do this instead of invalidating the query because it triggers a full app re-render??
|
||||
// insertLibrary(queryClient, lib);
|
||||
|
||||
// // Switch to the new library
|
||||
// currentLibraryStore.id = lib.uuid;
|
||||
|
||||
// submitPlausibleEvent({ event: { type: 'libraryCreate' } });
|
||||
// },
|
||||
// onSettled: () => {
|
||||
// modalRef.current?.dismiss();
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
|
||||
if (cloudLibraries.isLoading)
|
||||
return (
|
||||
<Modal
|
||||
|
@ -57,10 +34,6 @@ const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
snapPoints={['30']}
|
||||
title="Join a Cloud Library"
|
||||
description="Connect to one of your cloud libraries."
|
||||
onDismiss={() => {
|
||||
// Resets form onDismiss
|
||||
setLibName('');
|
||||
}}
|
||||
showCloseButton
|
||||
// Disable panning gestures
|
||||
enableHandlePanningGesture={false}
|
||||
|
@ -86,10 +59,6 @@ const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
snapPoints={['30']}
|
||||
title="Join a Cloud Library"
|
||||
description="Connect to one of your cloud libraries."
|
||||
onDismiss={() => {
|
||||
// Resets form onDismiss
|
||||
setLibName('');
|
||||
}}
|
||||
showCloseButton
|
||||
// Disable panning gestures
|
||||
enableHandlePanningGesture={false}
|
||||
|
@ -101,11 +70,11 @@ const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
(cloudLibrary) => !libraries.data?.find((l) => l.uuid === cloudLibrary.uuid)
|
||||
)
|
||||
.map((cloudLibrary) => (
|
||||
<View
|
||||
<Card
|
||||
key={cloudLibrary.uuid}
|
||||
style={tw`flex flex-row items-center gap-2 rounded-lg bg-gray-600 p-2`}
|
||||
>
|
||||
<Text style={tw`text-xl font-bold text-ink`}>{cloudLibrary.name}</Text>
|
||||
<Text style={tw`text-lg font-bold text-ink`}>{cloudLibrary.name}</Text>
|
||||
<View style={tw`flex flex-row gap-2`}>
|
||||
<Button
|
||||
variant="accent"
|
||||
|
@ -153,7 +122,7 @@ const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
</Text>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</Card>
|
||||
))}
|
||||
</View>
|
||||
</Modal>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Gear, Lock, Plus } from '@phosphor-icons/react';
|
||||
import { CloudArrowDown, Gear, Lock, Plus } from '@phosphor-icons/react';
|
||||
import clsx from 'clsx';
|
||||
import { useClientContext } from '@sd/client';
|
||||
import { dialogManager, Dropdown, DropdownMenu } from '@sd/ui';
|
||||
|
@ -6,6 +6,7 @@ import { useLocale } from '~/hooks';
|
|||
|
||||
import CreateDialog from '../../../settings/node/libraries/CreateDialog';
|
||||
import { useSidebarContext } from './Context';
|
||||
import JoinDialog from '~/app/$libraryId/settings/node/libraries/JoinDialog';
|
||||
|
||||
export default () => {
|
||||
const { library, libraries, currentLibraryId } = useClientContext();
|
||||
|
@ -62,6 +63,13 @@ export default () => {
|
|||
onClick={() => dialogManager.create((dp) => <CreateDialog {...dp} />)}
|
||||
className="font-medium"
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
label={t('join_library')}
|
||||
icon={CloudArrowDown}
|
||||
iconProps={{ weight: 'bold', size: 16 }}
|
||||
onClick={() => dialogManager.create((dp) => <JoinDialog librariesCtx={libraries.data} {...dp} />)}
|
||||
className="font-medium"
|
||||
/>
|
||||
<DropdownMenu.Item
|
||||
label={t('manage_library')}
|
||||
icon={Gear}
|
||||
|
|
105
interface/app/$libraryId/settings/node/libraries/JoinDialog.tsx
Normal file
105
interface/app/$libraryId/settings/node/libraries/JoinDialog.tsx
Normal file
|
@ -0,0 +1,105 @@
|
|||
import {
|
||||
LibraryConfigWrapped,
|
||||
useBridgeMutation,
|
||||
useBridgeQuery,
|
||||
useClientContext,
|
||||
useLibraryContext,
|
||||
usePlausibleEvent,
|
||||
useZodForm
|
||||
} from '@sd/client';
|
||||
import { Button, Dialog, Select, SelectOption, toast, useDialog, UseDialogProps, z } from '@sd/ui';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useLocale } from '~/hooks';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
|
||||
const schema = z.object({
|
||||
libraryId: z.string().refine((value) => value !== 'select_library', {
|
||||
message: 'Please select a library'
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
export default (props: UseDialogProps & { librariesCtx: LibraryConfigWrapped[] | undefined }) => {
|
||||
const cloudLibraries = useBridgeQuery(['cloud.library.list']);
|
||||
const joinLibrary = useBridgeMutation(['cloud.library.join']);
|
||||
|
||||
const { t } = useLocale();
|
||||
const navigate = useNavigate();
|
||||
const platform = usePlatform();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const form = useZodForm({ schema, defaultValues: { libraryId: 'select_library' } });
|
||||
|
||||
// const queryClient = useQueryClient();
|
||||
// const submitPlausibleEvent = usePlausibleEvent();
|
||||
// const platform = usePlatform();
|
||||
|
||||
const onSubmit = form.handleSubmit(async (data) => {
|
||||
try {
|
||||
const library = await joinLibrary.mutateAsync(data.libraryId);
|
||||
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => {
|
||||
// The invalidation system beat us to it
|
||||
if ((libraries || []).find((l: any) => l.uuid === library.uuid)) return libraries;
|
||||
|
||||
return [...(libraries || []), library];
|
||||
});
|
||||
|
||||
platform.refreshMenuBar && platform.refreshMenuBar();
|
||||
|
||||
navigate(`/${library.uuid}`, { replace: true });
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
toast.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
form={form}
|
||||
onSubmit={onSubmit}
|
||||
dialog={useDialog(props)}
|
||||
submitDisabled={!form.formState.isValid}
|
||||
title={t('join_library')}
|
||||
closeLabel={t('close')}
|
||||
cancelLabel={t('cancel')}
|
||||
description={t('join_library_description')}
|
||||
ctaLabel={form.formState.isSubmitting ? t('joining') : t('join')}
|
||||
>
|
||||
<div className="mt-5 space-y-4">
|
||||
{cloudLibraries.isLoading && <span>{t('loading')}...</span>}
|
||||
{cloudLibraries.data && (
|
||||
<Select
|
||||
value={form.watch('libraryId')}
|
||||
size="sm"
|
||||
className="w-full"
|
||||
onChange={(key) => {
|
||||
console.log('Key:', key);
|
||||
// Update the form value
|
||||
form.setValue('libraryId', key, {
|
||||
shouldValidate: true
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SelectOption value="select_library">
|
||||
{t('select_library')}
|
||||
</SelectOption>
|
||||
{cloudLibraries.data
|
||||
.filter(
|
||||
(cloudLibrary) =>
|
||||
!props.librariesCtx?.find(
|
||||
(l: any) => l.uuid === cloudLibrary.uuid
|
||||
)
|
||||
)
|
||||
.map((cloudLibrary) => (
|
||||
<SelectOption key={cloudLibrary.uuid} value={cloudLibrary.uuid}>
|
||||
{cloudLibrary.name}
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
|
@ -1,16 +1,25 @@
|
|||
import { useBridgeQuery, useLibraryContext } from '@sd/client';
|
||||
import { Button, dialogManager } from '@sd/ui';
|
||||
import { useRef } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useBridgeQuery, useClientContext, useFeatureFlag, useLibraryContext, useZodForm } from '@sd/client';
|
||||
import { Button, Dialog, dialogManager, useDialog, z } from '@sd/ui';
|
||||
import { useLocale } from '~/hooks';
|
||||
|
||||
import { Heading } from '../../Layout';
|
||||
import CreateDialog from './CreateDialog';
|
||||
import JoinDialog from './JoinDialog';
|
||||
import ListItem from './ListItem';
|
||||
|
||||
export const Component = () => {
|
||||
const librariesQuery = useBridgeQuery(['library.list']);
|
||||
const cloudLibrariesQuery = useBridgeQuery(['cloud.library.list']);
|
||||
const libraries = librariesQuery.data;
|
||||
const cloudLibraries = cloudLibrariesQuery.data;
|
||||
|
||||
const cloudEnabled = useFeatureFlag('cloudSync');
|
||||
|
||||
const { library } = useLibraryContext();
|
||||
const { libraries: librariesCtx } = useClientContext();
|
||||
const librariesCtxData = librariesCtx.data;
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
|
@ -30,10 +39,20 @@ export const Component = () => {
|
|||
>
|
||||
{t('add_library')}
|
||||
</Button>
|
||||
{cloudEnabled && (
|
||||
<Button
|
||||
variant="accent"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
dialogManager.create((dp) => <JoinDialog librariesCtx={librariesCtxData} {...dp} />);
|
||||
}}
|
||||
>
|
||||
{t('join_library')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="space-y-2">
|
||||
{libraries
|
||||
?.sort((a, b) => {
|
||||
|
@ -49,6 +68,22 @@ export const Component = () => {
|
|||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Heading title={'Cloud Libraries'} description={'Cloud Libraries'} />
|
||||
{cloudLibraries
|
||||
?.sort((a, b) => {
|
||||
if (a.uuid === library.uuid) return -1;
|
||||
if (b.uuid === library.uuid) return 1;
|
||||
return 0;
|
||||
})
|
||||
.map((lib) => (
|
||||
<ListItem
|
||||
current={lib.uuid === library.uuid}
|
||||
key={lib.uuid}
|
||||
library={library}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"join_discord": "Join Discord",
|
||||
"join_library": "Join a Library",
|
||||
"join_library_description": "Libraries are a secure, on-device database. Your files remain where they are, the Library catalogs them and stores all Spacedrive related data.",
|
||||
"joining": "Joining",
|
||||
"key": "Key",
|
||||
"key_manager": "Key Manager",
|
||||
"key_manager_description": "Create encryption keys, mount and unmount your keys to see files decrypted on the fly.",
|
||||
|
@ -629,6 +630,7 @@
|
|||
"size_tb": "TB",
|
||||
"size_tbs": "TBs",
|
||||
"skip_login": "Skip login",
|
||||
"select_library": "Select a Cloud Library",
|
||||
"software": "Software",
|
||||
"sort_by": "Sort by",
|
||||
"spacedrive_account": "Spacedrive Account",
|
||||
|
|
Loading…
Reference in a new issue