Co-authored-by: ConnorYoh <[email protected]>
Co-authored-by: Connor Yoh <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
Anthony Stirling
2026-03-25 11:00:40 +00:00
committed by GitHub
co-authored by ConnorYoh Connor Yoh EthanHealy01 Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
parent 47cad0a131
commit 28613caf8a
181 changed files with 25715 additions and 124 deletions
@@ -0,0 +1,149 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Modal, Stack, Text, Button, Group, Alert } from '@mantine/core';
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import { useTranslation } from 'react-i18next';
import { alert } from '@app/components/toast';
import { Z_INDEX_OVER_FILE_MANAGER_MODAL } from '@app/styles/zIndex';
import type { StirlingFileStub } from '@app/types/fileContext';
import { uploadHistoryChains } from '@app/services/serverStorageUpload';
import { fileStorage } from '@app/services/fileStorage';
import { useFileActions } from '@app/contexts/FileContext';
import type { FileId } from '@app/types/file';
interface BulkUploadToServerModalProps {
opened: boolean;
onClose: () => void;
files: StirlingFileStub[];
onUploaded?: () => Promise<void> | void;
}
const BulkUploadToServerModal: React.FC<BulkUploadToServerModalProps> = ({
opened,
onClose,
files,
onUploaded,
}) => {
const { t } = useTranslation();
const { actions } = useFileActions();
const [isUploading, setIsUploading] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const fileNames = useMemo(() => files.map((file) => file.name), [files]);
const displayNames = useMemo(() => fileNames.slice(0, 3), [fileNames]);
useEffect(() => {
if (!opened) {
setIsUploading(false);
setErrorMessage(null);
}
}, [opened]);
const handleUpload = useCallback(async () => {
setIsUploading(true);
setErrorMessage(null);
try {
const rootIds = Array.from(
new Set(files.map((file) => (file.originalFileId || file.id) as FileId))
);
const remoteIds = Array.from(
new Set(files.map((file) => file.remoteStorageId).filter(Boolean) as number[])
);
const existingRemoteId = remoteIds.length === 1 ? remoteIds[0] : undefined;
const { remoteId, updatedAt, chain } = await uploadHistoryChains(
rootIds,
existingRemoteId
);
for (const stub of chain) {
actions.updateStirlingFileStub(stub.id, {
remoteStorageId: remoteId,
remoteStorageUpdatedAt: updatedAt,
remoteOwnedByCurrentUser: true,
remoteSharedViaLink: false,
});
await fileStorage.updateFileMetadata(stub.id, {
remoteStorageId: remoteId,
remoteStorageUpdatedAt: updatedAt,
remoteOwnedByCurrentUser: true,
remoteSharedViaLink: false,
});
}
alert({
alertType: 'success',
title: t('storageUpload.success', 'Uploaded to server'),
expandable: false,
durationMs: 3000,
});
if (onUploaded) {
await onUploaded();
}
onClose();
} catch (error) {
console.error('Failed to upload files to server:', error);
setErrorMessage(
t('storageUpload.failure', 'Upload failed. Please check your login and storage settings.')
);
} finally {
setIsUploading(false);
}
}, [actions, files, onClose, onUploaded, t]);
return (
<Modal
opened={opened}
onClose={onClose}
centered
title={t('storageUpload.bulkTitle', 'Upload selected files')}
zIndex={Z_INDEX_OVER_FILE_MANAGER_MODAL}
>
<Stack gap="sm">
<Text size="sm">
{t(
'storageUpload.bulkDescription',
'This uploads the selected files to your server storage.'
)}
</Text>
<Text size="sm" c="dimmed">
{t('storageUpload.fileCount', '{{count}} files selected', {
count: files.length,
})}
</Text>
{displayNames.length > 0 && (
<Text size="xs" c="dimmed">
{displayNames.join(', ')}
{fileNames.length > displayNames.length
? t('storageUpload.more', ' +{{count}} more', {
count: fileNames.length - displayNames.length,
})
: ''}
</Text>
)}
{errorMessage && (
<Alert color="red" title={t('storageUpload.errorTitle', 'Upload failed')}>
{errorMessage}
</Alert>
)}
<Group justify="flex-end" gap="sm">
<Button variant="default" onClick={onClose} disabled={isUploading}>
{t('cancel', 'Cancel')}
</Button>
<Button
leftSection={<CloudUploadIcon style={{ fontSize: 18 }} />}
onClick={handleUpload}
loading={isUploading}
>
{t('storageUpload.uploadButton', 'Upload to Server')}
</Button>
</Group>
</Stack>
</Modal>
);
};
export default BulkUploadToServerModal;