Files
spacedrive/interface/app/$libraryId/Explorer/ContextMenu/FilePath/Items.tsx
Utku 0d5f92667c [ENG-1502] I18n (#1897)
* you know, you could just work on first try

* fix extension

* configure plugin and fix few translation issues

* more

* more keys

* and more

* more keys and sort

* commit msg

* we like keys here

* end my suffering

* jk i just love keys

* key fix

* add turkish

* add german

* Entendido

* Demnächst

* Mettre une étoile sur GitHub

* 成功

* pnpm-lock

* vite plugin

* remove i18next backends

---------

Co-authored-by: Brendan Allan <brendonovich@outlook.com>
2024-01-08 20:26:46 +00:00

300 lines
7.9 KiB
TypeScript

import { Hash, Image, Package, Trash, TrashSimple } from '@phosphor-icons/react';
import { libraryClient, useLibraryMutation } from '@sd/client';
import { ContextMenu, dialogManager, ModifierKeys, toast } from '@sd/ui';
import { Menu } from '~/components/Menu';
import { useKeysMatcher, useLocale, useOperatingSystem } from '~/hooks';
import { useKeybindFactory } from '~/hooks/useKeybindFactory';
import { useQuickRescan } from '~/hooks/useQuickRescan';
import { isNonEmpty } from '~/util';
import { useExplorerContext } from '../../Context';
import { CopyAsPathBase } from '../../CopyAsPath';
import DeleteDialog from '../../FilePath/DeleteDialog';
import EraseDialog from '../../FilePath/EraseDialog';
import { ConditionalItem } from '../ConditionalItem';
import { useContextMenuContext } from '../context';
export * from './CutCopyItems';
export const Delete = new ConditionalItem({
useCondition: () => {
const { selectedFilePaths, selectedEphemeralPaths } = useContextMenuContext();
if (!isNonEmpty(selectedFilePaths) && !isNonEmpty(selectedEphemeralPaths)) return null;
return { selectedFilePaths, selectedEphemeralPaths };
},
Component: ({ selectedFilePaths, selectedEphemeralPaths }) => {
const { t } = useLocale();
const rescan = useQuickRescan();
const os = useOperatingSystem();
const dirCount =
selectedFilePaths.filter((p) => p.is_dir).length +
selectedEphemeralPaths.filter((p) => p.is_dir).length;
const fileCount =
selectedFilePaths.filter((p) => !p.is_dir).length +
selectedEphemeralPaths.filter((p) => !p.is_dir).length;
const indexedArgs =
isNonEmpty(selectedFilePaths) && selectedFilePaths[0].location_id
? {
locationId: selectedFilePaths[0].location_id,
rescan,
pathIds: selectedFilePaths.map((p) => p.id)
}
: undefined;
const ephemeralArgs = isNonEmpty(selectedEphemeralPaths)
? {
paths: selectedEphemeralPaths.map((p) => p.path)
}
: undefined;
const deleteKeybind = useKeysMatcher(['Meta', 'Backspace']);
return (
<Menu.Item
icon={Trash}
label={t('delete')}
variant="danger"
keybind={
os === 'windows'
? 'Del'
: `${deleteKeybind.Meta.icon}${deleteKeybind.Backspace.icon}`
}
onClick={() =>
dialogManager.create((dp) => (
<DeleteDialog
{...dp}
indexedArgs={indexedArgs}
ephemeralArgs={ephemeralArgs}
dirCount={dirCount}
fileCount={fileCount}
/>
))
}
/>
);
}
});
export const CopyAsPath = new ConditionalItem({
useCondition: () => {
const { selectedFilePaths, selectedEphemeralPaths } = useContextMenuContext();
if (
!isNonEmpty(selectedFilePaths) ||
selectedFilePaths.length > 1 ||
!isNonEmpty(selectedEphemeralPaths) ||
selectedEphemeralPaths.length > 1 ||
(selectedFilePaths.length === 1 && selectedEphemeralPaths.length === 1) // should never happen
)
return null;
return { selectedFilePaths, selectedEphemeralPaths };
},
Component: ({ selectedFilePaths, selectedEphemeralPaths }) => {
if (selectedFilePaths.length === 1) {
return (
<CopyAsPathBase
getPath={() => libraryClient.query(['files.getPath', selectedFilePaths[0].id])}
/>
);
} else if (selectedEphemeralPaths.length === 1) {
return <CopyAsPathBase getPath={async () => selectedEphemeralPaths[0].path} />;
}
}
});
export const Compress = new ConditionalItem({
useCondition: () => {
const { selectedFilePaths } = useContextMenuContext();
if (!isNonEmpty(selectedFilePaths)) return null;
return { selectedFilePaths };
},
Component: ({ selectedFilePaths: _ }) => {
const keybind = useKeybindFactory();
const { t } = useLocale();
return (
<Menu.Item
label={t('compress')}
icon={Package}
keybind={keybind([ModifierKeys.Control], ['B'])}
disabled
/>
);
}
});
export const Crypto = new ConditionalItem({
useCondition: () => {
const { selectedFilePaths } = useContextMenuContext();
if (!isNonEmpty(selectedFilePaths)) return null;
return { selectedFilePaths };
},
Component: ({ selectedFilePaths: _ }) => {
return (
<>
{/* <ContextMenu.Item
label="Encrypt"
icon={LockSimple}
keybind="⌘E"
onClick={() => {
if (keyManagerUnlocked && hasMountedKeys) {
dialogManager.create((dp) => (
<EncryptDialog
{...dp}
location_id={store.locationId!}
path_id={data.item.id}
/>
));
} else if (!keyManagerUnlocked) {
showAlertDialog({
title: 'Key manager locked',
value: 'The key manager is currently locked. Please unlock it and try again.'
});
} else if (!hasMountedKeys) {
showAlertDialog({
title: 'No mounted keys',
value: 'No mounted keys were found. Please mount a key and try again.'
});
}
}}
/> */}
{/* should only be shown if the file is a valid spacedrive-encrypted file (preferably going from the magic bytes) */}
{/* <ContextMenu.Item
label="Decrypt"
icon={LockSimpleOpen}
keybind="⌘D"
onClick={() => {
if (keyManagerUnlocked) {
dialogManager.create((dp) => (
<DecryptDialog
{...dp}
location_id={store.locationId!}
path_id={data.item.id}
/>
));
} else {
showAlertDialog({
title: 'Key manager locked',
value: 'The key manager is currently locked. Please unlock it and try again.'
});
}
}}
/> */}
</>
);
}
});
export const SecureDelete = new ConditionalItem({
useCondition: () => {
const { selectedFilePaths } = useContextMenuContext();
if (!isNonEmpty(selectedFilePaths)) return null;
const locationId = selectedFilePaths[0].location_id;
if (locationId === null) return null;
return { locationId, selectedFilePaths };
},
Component: ({ locationId, selectedFilePaths }) => {
const { t } = useLocale();
return (
<Menu.Item
variant="danger"
label={t('secure_delete')}
icon={TrashSimple}
onClick={() =>
dialogManager.create((dp) => (
<EraseDialog
{...dp}
locationId={locationId}
filePaths={selectedFilePaths}
/>
))
}
disabled
/>
);
}
});
export const ParentFolderActions = new ConditionalItem({
useCondition: () => {
const { parent } = useExplorerContext();
if (parent?.type !== 'Location') return null;
return { parent };
},
Component: ({ parent }) => {
const { selectedFilePaths } = useContextMenuContext();
const fullRescan = useLibraryMutation('locations.fullRescan');
const generateThumbnails = useLibraryMutation('jobs.generateThumbsForLocation');
const generateLabels = useLibraryMutation('jobs.generateLabelsForLocation');
const { t } = useLocale();
return (
<>
<ContextMenu.Item
onClick={async () => {
try {
await fullRescan.mutateAsync({
location_id: parent.location.id,
reidentify_objects: false
});
} catch (error) {
toast.error({
title: t('failed_to_rescan_location'),
body: `Error: ${error}.`
});
}
}}
label={t('rescan_directory')}
icon={Package}
/>
<ContextMenu.Item
onClick={async () => {
try {
await generateThumbnails.mutateAsync({
id: parent.location.id,
path: selectedFilePaths[0]?.materialized_path ?? '/',
regenerate: true
});
} catch (error) {
toast.error({
title: t('failed_to_generate_thumbnails'),
body: `Error: ${error}.`
});
}
}}
label={t('regen_thumbnails')}
icon={Image}
/>
<ContextMenu.Item
onClick={async () => {
try {
await generateLabels.mutateAsync({
id: parent.location.id,
path: selectedFilePaths[0]?.materialized_path ?? '/',
regenerate: true
});
} catch (error) {
toast.error({
title: t('failed_to_generate_labels'),
body: `Error: ${error}.`
});
}
}}
label={t('regen_labels')}
icon={Hash}
/>
</>
);
}
});