mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-04-28 02:18:01 -04:00
* Update pnpm version
* Fix autoformat
* Improve autoformat msg
* Attempt to fix autoformat 2
* Fix autoformat
* Ignore deleted files in auto-format
* Fix diff filter
* Autoformat whole codebase
* Improve error message for autoformat CI
* Test autoformat CI
* Revert "Test autoformat CI"
This reverts commit 0bf2f46d1a.
229 lines
5.1 KiB
TypeScript
229 lines
5.1 KiB
TypeScript
import { inferSubscriptionResult } from '@oscartbeaumont-sd/rspc-client';
|
|
import clsx from 'clsx';
|
|
import { useEffect, useState } from 'react';
|
|
import {
|
|
Procedures,
|
|
useFeatureFlag,
|
|
useLibraryMutation,
|
|
useLibraryQuery,
|
|
useLibrarySubscription,
|
|
useZodForm
|
|
} from '@sd/client';
|
|
import { Button, Dialog, dialogManager, useDialog, UseDialogProps, z } from '@sd/ui';
|
|
import { useLocale } from '~/hooks';
|
|
|
|
import { Heading } from '../Layout';
|
|
import Setting from '../Setting';
|
|
|
|
const ACTORS = {
|
|
Ingest: 'Sync Ingest',
|
|
CloudSend: 'Cloud Sync Sender',
|
|
CloudReceive: 'Cloud Sync Receiver',
|
|
CloudIngest: 'Cloud Sync Ingest'
|
|
};
|
|
|
|
export const Component = () => {
|
|
const { t } = useLocale();
|
|
|
|
const syncEnabled = useLibraryQuery(['sync.enabled']);
|
|
|
|
const backfillSync = useLibraryMutation(['sync.backfill'], {
|
|
onSuccess: async () => {
|
|
await syncEnabled.refetch();
|
|
}
|
|
});
|
|
|
|
const [data, setData] = useState<inferSubscriptionResult<Procedures, 'library.actors'>>({});
|
|
|
|
useLibrarySubscription(['library.actors'], { onData: setData });
|
|
|
|
const cloudSync = useFeatureFlag('cloudSync');
|
|
|
|
return (
|
|
<>
|
|
<Heading title={t('sync')} description={t('sync_description')} />
|
|
{syncEnabled.data === false ? (
|
|
<Setting mini title={t('enable_sync')} description={t('enable_sync_description')}>
|
|
<div>
|
|
<Button
|
|
className="text-nowrap"
|
|
variant="accent"
|
|
onClick={() => {
|
|
dialogManager.create((dialogProps) => (
|
|
<SyncBackfillDialog
|
|
onEnabled={() => syncEnabled.refetch()}
|
|
{...dialogProps}
|
|
/>
|
|
));
|
|
}}
|
|
disabled={backfillSync.isLoading}
|
|
>
|
|
{t('enable_sync')}
|
|
</Button>
|
|
</div>
|
|
</Setting>
|
|
) : (
|
|
<>
|
|
<Setting
|
|
mini
|
|
title={
|
|
<>
|
|
{t('ingester')}
|
|
<OnlineIndicator online={data[ACTORS.Ingest] ?? false} />
|
|
</>
|
|
}
|
|
description={t('injester_description')}
|
|
>
|
|
<div>
|
|
{data[ACTORS.Ingest] ? (
|
|
<StopButton name={ACTORS.Ingest} />
|
|
) : (
|
|
<StartButton name={ACTORS.Ingest} />
|
|
)}
|
|
</div>
|
|
</Setting>
|
|
|
|
{cloudSync && <CloudSync data={data} />}
|
|
</>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
function SyncBackfillDialog(props: UseDialogProps & { onEnabled: () => void }) {
|
|
const form = useZodForm({ schema: z.object({}) });
|
|
const dialog = useDialog(props);
|
|
const { t } = useLocale();
|
|
|
|
const enableSync = useLibraryMutation(['sync.backfill'], {});
|
|
|
|
// dialog is in charge of enabling sync
|
|
useEffect(() => {
|
|
form.handleSubmit(
|
|
async () => {
|
|
await enableSync.mutateAsync(null).then(() => (dialog.state.open = false));
|
|
await props.onEnabled();
|
|
},
|
|
() => {}
|
|
)();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
return (
|
|
<Dialog
|
|
title={t('backfill_sync')}
|
|
description={t('backfill_sync_description')}
|
|
form={form}
|
|
dialog={dialog}
|
|
hideButtons
|
|
ignoreClickOutside
|
|
/>
|
|
);
|
|
}
|
|
|
|
function CloudSync({ data }: { data: inferSubscriptionResult<Procedures, 'library.actors'> }) {
|
|
const { t } = useLocale();
|
|
return (
|
|
<>
|
|
<div>
|
|
<h1 className="mb-0.5 text-lg font-bold text-ink">{t('cloud_sync')}</h1>
|
|
<p className="text-sm text-ink-faint">{t('cloud_sync_description')}</p>
|
|
</div>
|
|
<Setting
|
|
mini
|
|
title={
|
|
<>
|
|
{t('sender')} <OnlineIndicator online={data[ACTORS.CloudSend] ?? false} />
|
|
</>
|
|
}
|
|
description={t('sender_description')}
|
|
>
|
|
<div>
|
|
{data[ACTORS.CloudSend] ? (
|
|
<StopButton name={ACTORS.CloudSend} />
|
|
) : (
|
|
<StartButton name={ACTORS.CloudSend} />
|
|
)}
|
|
</div>
|
|
</Setting>
|
|
<Setting
|
|
mini
|
|
title={
|
|
<>
|
|
{t('receiver')}
|
|
<OnlineIndicator online={data[ACTORS.CloudReceive] ?? false} />
|
|
</>
|
|
}
|
|
description={t('receiver_description')}
|
|
>
|
|
<div>
|
|
{data[ACTORS.CloudReceive] ? (
|
|
<StopButton name={ACTORS.CloudReceive} />
|
|
) : (
|
|
<StartButton name={ACTORS.CloudReceive} />
|
|
)}
|
|
</div>
|
|
</Setting>
|
|
<Setting
|
|
mini
|
|
title={
|
|
<>
|
|
{t('ingester')}
|
|
<OnlineIndicator online={data[ACTORS.CloudIngest] ?? false} />
|
|
</>
|
|
}
|
|
description={t('ingester_description')}
|
|
>
|
|
<div>
|
|
{data[ACTORS.CloudIngest] ? (
|
|
<StopButton name={ACTORS.CloudIngest} />
|
|
) : (
|
|
<StartButton name={ACTORS.CloudIngest} />
|
|
)}
|
|
</div>
|
|
</Setting>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function StartButton({ name }: { name: string }) {
|
|
const startActor = useLibraryMutation(['library.startActor']);
|
|
const { t } = useLocale();
|
|
|
|
return (
|
|
<Button
|
|
variant="accent"
|
|
disabled={startActor.isLoading}
|
|
onClick={() => startActor.mutate(name)}
|
|
>
|
|
{startActor.isLoading ? t('starting') : t('start')}
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
function StopButton({ name }: { name: string }) {
|
|
const stopActor = useLibraryMutation(['library.stopActor']);
|
|
const { t } = useLocale();
|
|
|
|
return (
|
|
<Button
|
|
variant="accent"
|
|
disabled={stopActor.isLoading}
|
|
onClick={() => stopActor.mutate(name)}
|
|
>
|
|
{stopActor.isLoading ? t('stopping') : t('stop')}
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
function OnlineIndicator({ online }: { online: boolean }) {
|
|
return (
|
|
<div
|
|
className={clsx(
|
|
'ml-1.5 inline-block size-2.5 rounded-full',
|
|
online ? 'bg-green-500' : 'bg-red-500'
|
|
)}
|
|
/>
|
|
);
|
|
}
|