mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-19 05:45:01 -04:00
add device popup modal
This commit is contained in:
@@ -3,6 +3,7 @@ import clsx from 'clsx';
|
||||
import { useClientContext } from '@sd/client';
|
||||
import { dialogManager, Dropdown, DropdownMenu } from '@sd/ui';
|
||||
import JoinDialog from '~/app/$libraryId/settings/node/libraries/JoinDialog';
|
||||
import RequestAddDialog from '~/components/RequestAddDialog';
|
||||
import { useLocale } from '~/hooks';
|
||||
|
||||
import CreateDialog from '../../../settings/node/libraries/CreateDialog';
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useNavigate } from 'react-router';
|
||||
import {
|
||||
LibraryConfigWrapped,
|
||||
useBridgeMutation,
|
||||
useBridgeQuery,
|
||||
useClientContext,
|
||||
useLibraryContext,
|
||||
usePlausibleEvent,
|
||||
useZodForm
|
||||
} from '@sd/client';
|
||||
import { Button, Dialog, Select, SelectOption, toast, useDialog, UseDialogProps, z } from '@sd/ui';
|
||||
import { LibraryConfigWrapped, useBridgeMutation, useBridgeQuery, useZodForm } from '@sd/client';
|
||||
import { Dialog, Loader, Select, SelectOption, toast, useDialog, UseDialogProps, z } from '@sd/ui';
|
||||
import { useLocale } from '~/hooks';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
|
||||
@@ -67,7 +59,12 @@ export default (props: UseDialogProps & { librariesCtx: LibraryConfigWrapped[] |
|
||||
ctaLabel={form.formState.isSubmitting ? t('joining') : t('join')}
|
||||
>
|
||||
<div className="mt-5 space-y-4">
|
||||
{cloudLibraries.isLoading && <span>{t('loading')}...</span>}
|
||||
{cloudLibraries.isLoading && (
|
||||
<div className="mt-4 flex flex-col items-center justify-center gap-2">
|
||||
<Loader className="size-5"></Loader>
|
||||
<span className="text-xs text-ink-faint">{t('loading')}...</span>
|
||||
</div>
|
||||
)}
|
||||
{cloudLibraries.data && (
|
||||
<Select
|
||||
value={form.watch('libraryId')}
|
||||
|
||||
89
interface/components/RequestAddDialog.tsx
Normal file
89
interface/components/RequestAddDialog.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { ArrowRight } from '@phosphor-icons/react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { HardwareModel, useBridgeMutation, useZodForm } from '@sd/client';
|
||||
import { Dialog, toast, useDialog, UseDialogProps, z } from '@sd/ui';
|
||||
import { Icon } from '~/components';
|
||||
import { useLocale } from '~/hooks';
|
||||
import { hardwareModelToIcon } from '~/util/hardware';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
|
||||
export default (props: UseDialogProps) => {
|
||||
// PROPS = device_name, device_model, library_name
|
||||
// you will probably have to change the props to accept the library id and device id to pair them properly. Omitted for now as
|
||||
// unsure what the data will look like when the backend is populated
|
||||
|
||||
const joinLibrary = useBridgeMutation(['cloud.library.join']);
|
||||
|
||||
const { t } = useLocale();
|
||||
const navigate = useNavigate();
|
||||
const platform = usePlatform();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const form = useZodForm({ defaultValues: { libraryId: 'select_library' } });
|
||||
|
||||
// adapted from another dialog - we can change the form submit/remove form if needed but didn't want to
|
||||
// unnecessarily remove code
|
||||
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];
|
||||
});
|
||||
|
||||
if (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('request_add_device')}
|
||||
cancelLabel={t('cancel')}
|
||||
cancelDanger={true}
|
||||
cancelBtn={true}
|
||||
onCancelled={false}
|
||||
description={t('request_add_device_description')}
|
||||
ignoreClickOutside={true}
|
||||
ctaLabel={form.formState.isSubmitting ? t('accepting') : t('accept')}
|
||||
>
|
||||
{/* device */}
|
||||
<div className="my-6 flex items-center justify-center gap-10">
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Icon
|
||||
// once backend endpoint is populated need to check if this is working correctly i.e fetching correct icons for devices
|
||||
name={hardwareModelToIcon(props.device_model as HardwareModel)}
|
||||
alt="Device icon"
|
||||
size={48}
|
||||
className="mr-2"
|
||||
/>
|
||||
<p className="text-sm text-ink-dull">{props.device_name}</p>
|
||||
</div>
|
||||
<ArrowRight color="#ABACBA" size={18}></ArrowRight>
|
||||
{/* library */}
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<Icon
|
||||
// once backend endpoint is populated need to check if this is working correctly i.e fetching correct icons for devices
|
||||
name={'Book'}
|
||||
alt="Device icon"
|
||||
size={48}
|
||||
className="mr-2"
|
||||
/>
|
||||
<p className="text-sm text-ink-dull">{props.library_name}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
useInvalidateQuery,
|
||||
useLoadBackendFeatureFlags
|
||||
} from '@sd/client';
|
||||
import { toast, TooltipProvider } from '@sd/ui';
|
||||
import { dialogManager, toast, TooltipProvider } from '@sd/ui';
|
||||
import RequestAddDialog from '~/components/RequestAddDialog';
|
||||
|
||||
import { createRoutes } from './app';
|
||||
import { SpacedropProvider } from './app/$libraryId/Spacedrop';
|
||||
@@ -92,10 +93,16 @@ export function SpacedriveInterfaceRoot({ children }: PropsWithChildren) {
|
||||
console.log('Received cloud service notification', d);
|
||||
switch (d.kind) {
|
||||
case 'ReceivedJoinSyncGroupRequest':
|
||||
// TODO: Show modal to accept or reject
|
||||
dialogManager.create((dp) => (
|
||||
<RequestAddDialog
|
||||
device_model={'Macbook Pro'}
|
||||
device_name={"Arnab's Macbook"}
|
||||
library_name={"Arnab's Library"}
|
||||
{...dp}
|
||||
/>
|
||||
));
|
||||
break;
|
||||
default:
|
||||
// TODO: Show notification/toast for other kinds
|
||||
toast({ title: 'Cloud Service Notification', body: d.kind }, { type: 'info' });
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"about_vision_title": "Vision",
|
||||
"accept": "Accept",
|
||||
"accept_files": "Accept files",
|
||||
"accepting": "Accepting...",
|
||||
"accessed": "Accessed",
|
||||
"account": "Account",
|
||||
"actions": "Actions",
|
||||
@@ -617,6 +618,8 @@
|
||||
"rename": "Rename",
|
||||
"rename_object": "Rename object",
|
||||
"replica": "Replica",
|
||||
"request_add_device": "Library Join Request",
|
||||
"request_add_device_description": "A device is requesting to join one of your libraries. Please review the device and the library it is requesting to join below.",
|
||||
"rescan": "Rescan",
|
||||
"rescan_directory": "Rescan Directory",
|
||||
"rescan_location": "Rescan Location",
|
||||
|
||||
@@ -124,6 +124,7 @@ export interface DialogProps<S extends FieldValues>
|
||||
onSubmitSecond?: ReturnType<UseFormHandleSubmit<S>>;
|
||||
children?: ReactNode;
|
||||
ctaDanger?: boolean;
|
||||
cancelDanger?: boolean;
|
||||
closeLabel?: string;
|
||||
cancelLabel?: string;
|
||||
cancelBtn?: boolean;
|
||||
@@ -167,8 +168,9 @@ export function Dialog<S extends FieldValues>({
|
||||
<RDialog.Close asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="gray"
|
||||
variant={props.cancelDanger ? 'colored' : 'gray'}
|
||||
onClick={typeof onCancelled === 'function' ? onCancelled : undefined}
|
||||
className={clsx(props.cancelDanger && 'border-red-500 bg-red-500')}
|
||||
>
|
||||
{props.cancelLabel || 'Cancel'}
|
||||
</Button>
|
||||
@@ -180,7 +182,7 @@ export function Dialog<S extends FieldValues>({
|
||||
<Button
|
||||
disabled={props.loading}
|
||||
size="sm"
|
||||
variant="gray"
|
||||
variant={'gray'}
|
||||
onClick={typeof onCancelled === 'function' ? onCancelled : undefined}
|
||||
>
|
||||
{props.closeLabel || 'Close'}
|
||||
|
||||
Reference in New Issue
Block a user