Files
spacedrive/interface/app/$libraryId/debug/cloud.tsx
Arnab Chakraborty e2d1862766 Migrate all cloud routes to the new API system
All cloud routes are now migrated to the new system in the backend.

The old routes are still available, as the frontend has not been modified to use the new ones yet.
2024-08-07 17:55:22 +03:00

257 lines
7.6 KiB
TypeScript

import { CheckCircle, XCircle } from '@phosphor-icons/react';
import { Suspense, useMemo } from 'react';
import {
auth,
HardwareModel,
useBridgeQuery,
useLibraryContext,
useLibraryMutation,
useLibraryQuery
} from '@sd/client';
import { Button, Card, Loader, tw } from '@sd/ui';
import { Icon } from '~/components';
import { AuthRequiredOverlay } from '~/components/AuthRequiredOverlay';
import { LoginButton } from '~/components/LoginButton';
import { useLocale, useRouteTitle } from '~/hooks';
import { hardwareModelToIcon } from '~/util/hardware';
const DataBox = tw.div`max-w-[300px] rounded-md border border-app-line/50 bg-app-lightBox/20 p-2`;
const Count = tw.div`min-w-[20px] flex h-[20px] px-1 items-center justify-center rounded-full border border-app-button/40 text-[9px]`;
export const Component = () => {
useRouteTitle('Cloud');
const authState = auth.useStateSnapshot();
const authSensitiveChild = () => {
if (authState.status === 'loggedIn') return <Authenticated />;
if (authState.status === 'notLoggedIn' || authState.status === 'loggingIn')
return (
<div className="flex size-full items-center justify-center">
<DataBox className="flex flex-col items-center gap-5 !p-6">
<div className="flex flex-col items-center gap-1">
<Icon name="Sync" size={60} />
<p className="max-w-[75%] text-center text-sm">
To access cloud related features, please login
</p>
</div>
<LoginButton />
</DataBox>
</div>
);
return null;
};
return <div className="flex size-full flex-col items-start p-4">{authSensitiveChild()}</div>;
};
// million-ignore
function Authenticated() {
const { library } = useLibraryContext();
const cloudLibrary: any = useLibraryQuery(['cloud.library.get'], {
suspense: true,
retry: false
});
const cloudLibraryList = useBridgeQuery(['cloud.library.list'], {
suspense: true,
retry: false
});
console.log('[DEBUG] cloudLibraryList', cloudLibraryList);
const createLibrary = useLibraryMutation(['cloud.library.create']);
const { t } = useLocale();
const thisInstance = useMemo(() => {
if (!cloudLibrary.data) return undefined;
return cloudLibrary.data.instances.find(
(instance: any) => instance.uuid === library.instance_id
);
}, [cloudLibrary.data, library.instance_id]);
return (
<Suspense
fallback={
<div className="flex size-full items-center justify-center">
<Loader />
</div>
}
>
{cloudLibrary.data ? (
<div className="flex flex-col items-start gap-10">
<Library thisInstance={thisInstance} cloudLibrary={cloudLibrary.data} />
{thisInstance && <ThisInstance instance={thisInstance} />}
<Instances instances={cloudLibrary.data.instances} />
</div>
) : (
<div className="relative flex size-full flex-col items-center justify-center">
<AuthRequiredOverlay />
<DataBox className="flex min-w-[400px] flex-col items-center gap-5 p-6">
<div className="flex flex-col items-center gap-2">
<Icon name="CloudSync" size={60} />
<p className="max-w-[60%] text-center text-sm text-ink">
{t('cloud_connect_description')}
</p>
</div>
<Button
className="h-8"
disabled={createLibrary.isLoading}
variant="accent"
onClick={() => {
createLibrary.mutateAsync(null);
}}
>
{createLibrary.isLoading ? (
<div className="flex h-4 flex-row items-center gap-2">
<Loader className="w-5" color="white" />
<p className="text-xs">{t('Connecting' + '...')}</p>
</div>
) : (
t('Connect')
)}
</Button>
</DataBox>
</div>
)}
</Suspense>
);
}
// million-ignore
const Instances = ({ instances }: { instances: any[] }) => {
const { library } = useLibraryContext();
const filteredInstances = instances.filter((instance) => instance.uuid !== library.instance_id);
return (
<div className="flex flex-col gap-3">
<div className="flex flex-row items-center gap-3">
<p className="text-medium font-bold">Instances</p>
<Count>{filteredInstances.length}</Count>
</div>
<div className="flex flex-row flex-wrap gap-2">
{filteredInstances.map((instance) => (
<Card
key={instance.id}
className="flex-col items-center gap-4 bg-app-box/50 !p-5"
>
<div className="flex flex-col items-center gap-2">
<Icon
name={
hardwareModelToIcon(
instance.metadata.device_model as HardwareModel
) as any
}
size={70}
/>
<p className="max-w-[250px] truncate text-xs font-medium">
{instance.metadata.name}
</p>
</div>
<div className="flex flex-col gap-1.5">
<DataBox>
<p className="truncate text-xs font-medium">
Id:{' '}
<span className="font-normal text-ink-dull">{instance.id}</span>
</p>
</DataBox>
<DataBox>
<p className="truncate text-xs font-medium">
UUID:{' '}
<span className="font-normal text-ink-dull">
{instance.uuid}
</span>
</p>
</DataBox>
<DataBox>
<p className="truncate text-xs font-medium">
Public Key:{' '}
<span className="font-normal text-ink-dull">
{instance.identity}
</span>
</p>
</DataBox>
</div>
</Card>
))}
</div>
</div>
);
};
interface LibraryProps {
cloudLibrary: any;
thisInstance: any | undefined;
}
// million-ignore
const Library = ({ thisInstance, cloudLibrary }: LibraryProps) => {
const syncLibrary = useLibraryMutation(['cloud.library.sync']);
return (
<div className="flex flex-col gap-3">
<p className="text-medium font-bold">Library</p>
<Card className="flex-row items-center gap-6 !px-2">
<p className="font-medium">
Name: <span className="font-normal text-ink-dull">{cloudLibrary.name}</span>
</p>
<Button
disabled={syncLibrary.isLoading || thisInstance !== undefined}
variant={thisInstance === undefined ? 'accent' : 'gray'}
className="flex flex-row items-center gap-1 !text-ink"
onClick={() => syncLibrary.mutateAsync(null)}
>
{thisInstance === undefined ? (
<XCircle weight="fill" size={15} className="text-red-400" />
) : (
<CheckCircle weight="fill" size={15} className="text-green-400" />
)}
{thisInstance === undefined ? 'Sync Library' : 'Library synced'}
</Button>
</Card>
</div>
);
};
interface ThisInstanceProps {
instance: any;
}
// million-ignore
const ThisInstance = ({ instance }: ThisInstanceProps) => {
return (
<div className="flex flex-col gap-3">
<p className="text-medium font-bold">This Instance</p>
<Card className="flex-col items-center gap-4 bg-app-box/50 !p-5">
<div className="flex flex-col items-center gap-2">
<Icon
name={
hardwareModelToIcon(
instance.metadata.device_model as HardwareModel
) as any
}
size={70}
/>
<p className="max-w-[160px] truncate text-xs font-medium">
{instance.metadata.name}
</p>
</div>
<div className="flex flex-col gap-1.5">
<DataBox>
<p className="truncate text-xs font-medium">
Id: <span className="font-normal text-ink-dull">{instance.id}</span>
</p>
</DataBox>
<DataBox>
<p className="truncate text-xs font-medium">
UUID: <span className="font-normal text-ink-dull">{instance.uuid}</span>
</p>
</DataBox>
<DataBox>
<p className="truncate text-xs font-medium">
Public Key:{' '}
<span className="font-normal text-ink-dull">{instance.identity}</span>
</p>
</DataBox>
</div>
</Card>
</div>
);
};