Files
spacedrive/interface/app/$libraryId/Explorer/File/EncryptDialog.tsx
Brendan Allan 99a31de824 [ENG-380] Interface code structure improvement (#581)
* beginnings of app directory

* settings mostly good

* colocate way more components

* flatten components folder

* reexport QueryClientProvider from client

* move CodeBlock back to interface

* colocate Explorer, KeyManager + more

* goddamn captialisation

* get toasts out of components

* please eslint

* no more src directory

* $ instead of :

* added back RowHeader component

* fix settings modal padding

* more spacing, less margin

* fix sidebar locations button

* fix tags sidebar link

* clean up back button

* added margin to explorer context menu to prevent contact with edge of viewport

* don't export QueryClientProvider from @sd/client

* basic guidelines

* import interface correctly

* remove old demo data

* fix onboarding layout

* fix onboarding navigation

* fix key manager settings button

---------

Co-authored-by: Jamie Pine <ijamespine@me.com>
2023-02-27 21:29:48 -08:00

177 lines
5.1 KiB
TypeScript

import {
Algorithm,
hashingAlgoSlugSchema,
slugFromHashingAlgo,
useLibraryMutation,
useLibraryQuery
} from '@sd/client';
import { Button, Dialog, Select, SelectOption, UseDialogProps, useDialog } from '@sd/ui';
import { CheckBox, useZodForm, z } from '@sd/ui/src/forms';
import { showAlertDialog } from '~/components/AlertDialog';
import { usePlatform } from '~/util/Platform';
import { KeyListSelectOptions } from '../../KeyManager/List';
interface Props extends UseDialogProps {
location_id: number;
path_id: number;
}
const schema = z.object({
key: z.string(),
encryptionAlgo: z.string(),
hashingAlgo: hashingAlgoSlugSchema,
metadata: z.boolean(),
previewMedia: z.boolean(),
outputPath: z.string()
});
export default (props: Props) => {
const dialog = useDialog(props);
const platform = usePlatform();
const UpdateKey = (uuid: string) => {
form.setValue('key', uuid);
const hashAlg = keys.data?.find((key) => {
return key.uuid === uuid;
})?.hashing_algorithm;
hashAlg && form.setValue('hashingAlgo', slugFromHashingAlgo(hashAlg));
};
const keys = useLibraryQuery(['keys.list']);
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
onSuccess: (data) => {
UpdateKey(data[0] ?? '');
}
});
const encryptFile = useLibraryMutation('files.encryptFiles', {
onSuccess: () => {
showAlertDialog({
title: 'Success',
value:
'The encryption job has started successfully. You may track the progress in the job overview panel.'
});
},
onError: () => {
showAlertDialog({
title: 'Error',
value: 'The encryption job failed to start.'
});
}
});
const form = useZodForm({
defaultValues: { encryptionAlgo: 'XChaCha20Poly1305', outputPath: '' },
schema
});
const onSubmit = form.handleSubmit((data) =>
encryptFile.mutateAsync({
algorithm: data.encryptionAlgo as Algorithm,
key_uuid: data.key,
location_id: props.location_id,
path_id: props.path_id,
metadata: data.metadata,
preview_media: data.previewMedia,
output_path: data.outputPath || null
})
);
return (
<Dialog
form={form}
onSubmit={onSubmit}
dialog={dialog}
title="Encrypt a file"
description="Configure your encryption settings. Leave the output file blank for the default."
loading={encryptFile.isLoading}
ctaLabel="Encrypt"
>
<div className="mt-4 mb-3 grid w-full grid-cols-2 gap-4">
<div className="flex flex-col">
<span className="text-xs font-bold">Key</span>
<Select
className="mt-2"
value={form.watch('key')}
onChange={(e) => {
UpdateKey(e);
}}
>
{mountedUuids.data && <KeyListSelectOptions keys={mountedUuids.data} />}
</Select>
</div>
<div className="flex flex-col">
<span className="text-xs font-bold">Output file</span>
<Button
size="sm"
variant={form.watch('outputPath') !== '' ? 'accent' : 'gray'}
className="mt-2 h-[23px] text-xs leading-3"
type="button"
onClick={() => {
// if we allow the user to encrypt multiple files simultaneously, this should become a directory instead
if (!platform.saveFilePickerDialog) {
// TODO: Support opening locations on web
showAlertDialog({
title: 'Error',
description: '',
value: "System dialogs aren't supported on this platform.",
inputBox: false
});
return;
}
platform.saveFilePickerDialog().then((result) => {
if (result) form.setValue('outputPath', result as string);
});
}}
>
Select
</Button>
</div>
</div>
<div className="mt-4 mb-3 grid w-full grid-cols-2 gap-4">
<div className="flex flex-col">
<span className="text-xs font-bold">Encryption</span>
<Select
className="mt-2"
value={form.watch('encryptionAlgo')}
onChange={(e) => form.setValue('encryptionAlgo', e)}
>
<SelectOption value="XChaCha20Poly1305">XChaCha20-Poly1305</SelectOption>
<SelectOption value="Aes256Gcm">AES-256-GCM</SelectOption>
</Select>
</div>
<div className="flex flex-col">
<span className="text-xs font-bold">Hashing</span>
<Select
className="mt-2 text-gray-400/80"
onChange={() => {}}
value={form.watch('hashingAlgo')}
disabled
>
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
</Select>
</div>
</div>
<div className="mt-4 mb-3 grid w-full grid-cols-2 gap-4">
<div className="flex">
<span className="mr-3 ml-0.5 mt-0.5 text-sm font-bold">Metadata</span>
<CheckBox {...form.register('metadata')} />
</div>
<div className="flex">
<span className="mr-3 ml-0.5 mt-0.5 text-sm font-bold">Preview Media</span>
<CheckBox {...form.register('previewMedia')} />
</div>
</div>
</Dialog>
);
};