Import Cloud Library

Currently, you can import a cloud library, however it seems that the data, such as locations, is not transferring correctly.
This commit is contained in:
Arnab Chakraborty 2024-06-08 17:17:29 +05:30
parent 4657d3eebf
commit f34fbbde0f
4 changed files with 243 additions and 5 deletions

View file

@ -1,7 +1,7 @@
import { useDrawerStatus } from '@react-navigation/drawer';
import { useNavigation } from '@react-navigation/native';
import { MotiView } from 'moti';
import { CaretRight, Gear, Lock, Plus } from 'phosphor-react-native';
import { CaretRight, CloudArrowDown, Gear, Lock, Plus } from 'phosphor-react-native';
import { useEffect, useRef, useState } from 'react';
import { Alert, Pressable, Text, View } from 'react-native';
import { useClientContext } from '@sd/client';
@ -12,6 +12,7 @@ import { AnimatedHeight } from '../animation/layout';
import { ModalRef } from '../layout/Modal';
import CreateLibraryModal from '../modal/CreateLibraryModal';
import { Divider } from '../primitive/Divider';
import ImportModalLibrary from '../modal/ImportLibraryModal';
const DrawerLibraryManager = () => {
const [dropdownClosed, setDropdownClosed] = useState(true);
@ -91,6 +92,14 @@ const DrawerLibraryManager = () => {
<Text style={tw`text-sm font-semibold text-white`}>New Library</Text>
</Pressable>
<CreateLibraryModal ref={modalRef} />
<Pressable
style={tw`flex flex-row items-center px-1.5 py-[8px]`}
onPress={() => modalRef.current?.present()}
>
<CloudArrowDown size={18} weight="bold" color="white" style={tw`mr-2`} />
<Text style={tw`text-sm font-semibold text-white`}>Import Library</Text>
</Pressable>
<ImportModalLibrary ref={modalRef} />
{/* Manage Library */}
<Pressable
onPress={() => {

View file

@ -0,0 +1,163 @@
import { useNavigation } from '@react-navigation/native';
import { useQueryClient } from '@tanstack/react-query';
import { forwardRef, useState } from 'react';
import { Text, View } from 'react-native';
import {
insertLibrary,
useBridgeMutation,
useBridgeQuery,
useClientContext,
usePlausibleEvent
} from '@sd/client';
import { Modal, ModalRef } from '~/components/layout/Modal';
import { Button } from '~/components/primitive/Button';
import { ModalInput } from '~/components/primitive/Input';
import useForwardedRef from '~/hooks/useForwardedRef';
import { tw } from '~/lib/tailwind';
import { currentLibraryStore } from '~/utils/nav';
const ImportModalLibrary = forwardRef<ModalRef, unknown>((_, ref) => {
const navigation = useNavigation();
const modalRef = useForwardedRef(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
ref={modalRef}
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}
enableContentPanningGesture={false}
>
<View style={tw`px-4`}>
<Text>Loading...</Text>
<Button
variant="accent"
onPress={() => console.log('TODO')}
style={tw`mt-4`}
disabled
>
<Text style={tw`text-sm font-medium text-white`}>Import</Text>
</Button>
</View>
</Modal>
);
return (
<Modal
ref={modalRef}
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}
enableContentPanningGesture={false}
>
<View style={tw`gap-y-2 px-4`}>
{cloudLibraries.data
?.filter(
(cloudLibrary) => !libraries.data?.find((l) => l.uuid === cloudLibrary.uuid)
)
.map((cloudLibrary) => (
<View
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>
<View style={tw`flex flex-row gap-2`}>
<Button
variant="accent"
disabled={joinLibrary.isLoading}
onPress={async () => {
const library = await joinLibrary.mutateAsync(
cloudLibrary.uuid
);
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];
}
);
currentLibraryStore.id = library.uuid;
navigation.navigate('Root', {
screen: 'Home',
params: {
screen: 'OverviewStack',
params: {
screen: 'Overview'
}
}
});
modalRef.current?.dismiss();
}}
>
<Text style={tw`text-sm font-medium text-white`}>
{joinLibrary.isLoading &&
joinLibrary.variables === cloudLibrary.uuid
? 'Joining...'
: 'Join'}
</Text>
</Button>
</View>
</View>
))}
</View>
</Modal>
);
});
export default ImportModalLibrary;

View file

@ -1,4 +1,5 @@
import { Linking, Text, View } from 'react-native';
import { useLibraryContext, useLibraryMutation, useLibraryQuery } from '@sd/client';
import ScreenContainer from '~/components/layout/ScreenContainer';
import { Button } from '~/components/primitive/Button';
import { tw } from '~/lib/tailwind';
@ -24,9 +25,74 @@ const Cloud = ({ navigation }: SettingsStackScreenProps<'Cloud'>) => {
};
const Authenticated = () => {
const { library } = useLibraryContext();
const cloudLibrary = useLibraryQuery(['cloud.library.get'], { suspense: true, retry: false });
const createLibrary = useLibraryMutation(['cloud.library.create']);
const syncLibrary = useLibraryMutation(['cloud.library.sync']);
const thisInstance = cloudLibrary.data?.instances.find(
(instance) => instance.uuid === library.instance_id
);
return (
<ScreenContainer scrollview={false} style={tw`gap-0 px-6`}>
<Text style={tw`text-ink`}>You are authenticated!</Text>
{cloudLibrary.data ? (
<View style={tw`flex flex-col items-start space-y-2`}>
<View>
<Text style={tw`text-ink`}>Library</Text>
<Text style={tw`text-ink`}>Name: {cloudLibrary.data.name}</Text>
</View>
<Button
disabled={syncLibrary.isLoading}
onPress={() => {
syncLibrary.mutateAsync(null);
}}
>
<Text style={tw`text-ink`}>Sync Library</Text>
</Button>
{thisInstance && (
<View>
<Text style={tw`text-ink`}>This Instance</Text>
<Text style={tw`text-ink`}>Id: {thisInstance.id}</Text>
<Text style={tw`text-ink`}>UUID: {thisInstance.uuid}</Text>
<Text style={tw`text-ink`}>Public Key: {thisInstance.identity}</Text>
</View>
)}
<View>
<Text style={tw`text-ink`}>Instances</Text>
<View style={tw`space-y-4 pl-4`}>
{cloudLibrary.data.instances
.filter((instance) => instance.uuid !== library.instance_id)
.map((instance) => (
<View key={instance.id}>
<Text style={tw`text-ink`}>Id: {instance.id}</Text>
<Text style={tw`text-ink`}>UUID: {instance.uuid}</Text>
<Text style={tw`text-ink`}>Public Key: {instance.identity}</Text>
</View>
))}
</View>
</View>
</View>
) : (
<View style={tw`relative`}>
<Button
disabled={createLibrary.isLoading}
onPress={() => {
createLibrary.mutateAsync(null);
}}
>
{createLibrary.isLoading ? (
<Text style={tw`text-ink`}>Connecting library to Spacedrive Cloud...</Text>
) : (
<Text style={tw`text-ink`}>Connect library to Spacedrive Cloud</Text>
)}
</Button>
</View>
)}
</ScreenContainer>
);
};
@ -43,7 +109,7 @@ const Login = () => {
await login();
}}
>
{authState.status !== 'loggingIn' ? <Text>Login</Text> : <Text>Logging In</Text>}
{authState.status !== 'loggingIn' ? <Text style={tw`text-ink`}>Login</Text> : <Text style={tw`text-ink`}>Logging In</Text>}
</Button>
{authState.status === 'loggingIn' && (
<Button
@ -54,7 +120,7 @@ const Login = () => {
}}
style={tw`text-sm text-ink-faint`}
>
<Text>Cancel</Text>
<Text style={tw`text-ink`}>Cancel</Text>
</Button>
)}
</View>

View file

@ -107,7 +107,7 @@ const SyncSettingsScreen = ({ navigation }: SettingsStackScreenProps<'SyncSettin
<OnlineIndicator online={data[ACTORS.CloudIngest] ?? false} />
</Text>
<View>
{data[ACTORS.CloudReceive] ? (
{data[ACTORS.CloudIngest] ? (
<StopButton name={ACTORS.CloudIngest} />
) : (
<StartButton name={ACTORS.CloudIngest} />