diff --git a/src/layout/Dashboard.tsx b/src/layout/Dashboard.tsx index 58d8c9b..2b6f3ba 100644 --- a/src/layout/Dashboard.tsx +++ b/src/layout/Dashboard.tsx @@ -20,7 +20,9 @@ const useStyles = makeStyles()(theme => ({ }, fileManagerOn: { - padding: '0px', + padding: '0px !important', + margin: '0px !important', + maxWidth: '100% !important', }, })) diff --git a/src/modules/filemanager/components/ConfirmModal/ConfirmModal.scss b/src/modules/filemanager/components/ConfirmModal/ConfirmModal.scss index d270a71..3c70df7 100644 --- a/src/modules/filemanager/components/ConfirmModal/ConfirmModal.scss +++ b/src/modules/filemanager/components/ConfirmModal/ConfirmModal.scss @@ -7,8 +7,6 @@ } .fm-modal-container .fm-modal-window-body .fm-modal-white-section { - max-height: 50vh; - overflow: auto; word-break: break-word; padding: 12px 14px; border-radius: 8px; diff --git a/src/modules/filemanager/components/ConfirmModal/ConfirmModal.tsx b/src/modules/filemanager/components/ConfirmModal/ConfirmModal.tsx index 836154b..9c86632 100644 --- a/src/modules/filemanager/components/ConfirmModal/ConfirmModal.tsx +++ b/src/modules/filemanager/components/ConfirmModal/ConfirmModal.tsx @@ -41,19 +41,20 @@ export function ConfirmModal({
{title}
- -
- {isProgress ? ( -
-
-
{spinnerMessage || 'Working…'}
-
+
+
+ {isProgress ? ( +
+
+
{spinnerMessage || 'Working…'}
+
+
+ {showMinimize &&
- {showMinimize &&
- ) : ( -
{message}
- )} + ) : ( +
{message}
+ )} +
{showFooter && (onCancel || onConfirm) && ( diff --git a/src/modules/filemanager/components/CreateDriveModal/CreateDriveModal.tsx b/src/modules/filemanager/components/CreateDriveModal/CreateDriveModal.tsx index b096f20..f83cf82 100644 --- a/src/modules/filemanager/components/CreateDriveModal/CreateDriveModal.tsx +++ b/src/modules/filemanager/components/CreateDriveModal/CreateDriveModal.tsx @@ -139,87 +139,89 @@ export function CreateDriveModal({
Create new drive
-
-
- - setDriveName(e.target.value)} - onBlur={() => setDuplicate(true)} - maxLength={maxDriveNameLength} - /> - {validationError &&
{validationError}
} -
-
- - -
-
- Drive sizes are calculated automatically from your current stamp configuration. -
-
- - -
-
- - setErasureCodeLevel(value)} - minValue={minMarkValue} - maxValue={maxMarkValue} - step={1} - /> -
- -
-
-
Estimated Cost:
-
- {cost} BZZ {isBalanceSufficient ? '' : '(Insufficient balance)'} - {isxDaiBalanceSufficient ? '' : ' (Insufficient xDAI balance)'} -
- +
+
+
+ + setDriveName(e.target.value)} + onBlur={() => setDuplicate(true)} + maxLength={maxDriveNameLength} + /> + {validationError &&
{validationError}
}
-
(Based on current network conditions)
- {isUltraLightNode && ( -
- Creating a drive requires running a light node. Please{' '} - - upgrade - {' '} - to continue. +
+ + +
+
+ Drive sizes are calculated automatically from your current stamp configuration. +
+
+ + +
+
+ + setErasureCodeLevel(value)} + minValue={minMarkValue} + maxValue={maxMarkValue} + step={1} + /> +
+ +
+
+
Estimated Cost:
+
+ {cost} BZZ {isBalanceSufficient ? '' : '(Insufficient balance)'} + {isxDaiBalanceSufficient ? '' : ' (Insufficient xDAI balance)'} +
+
- )} +
(Based on current network conditions)
+ {isUltraLightNode && ( +
+ Creating a drive requires running a light node. Please{' '} + + upgrade + {' '} + to continue. +
+ )} +
diff --git a/src/modules/filemanager/components/DeleteFileModal/DeleteFileModal.tsx b/src/modules/filemanager/components/DeleteFileModal/DeleteFileModal.tsx index a4e234d..3327666 100644 --- a/src/modules/filemanager/components/DeleteFileModal/DeleteFileModal.tsx +++ b/src/modules/filemanager/components/DeleteFileModal/DeleteFileModal.tsx @@ -42,79 +42,82 @@ export function DeleteFileModal({
{headerText}
+
+
+ {isBulk && ( +
    + {names.map(n => ( +
  • + {n} +
  • + ))} +
+ )} + +
+
+ setValue(FileAction.Trash)} />} + label={ +
+
+ Move to Trash + +
+
e.preventDefault()}> + Moves {subjectNoun} to the trash. It will still take up space on{' '} + {currentDriveName ?? 'this drive'} and expire along with it. You can restore it later. +
+
+ } + /> +
-
- {isBulk && ( -
    - {names.map(n => ( -
  • - {n} -
  • - ))} -
- )} - -
-
- setValue(FileAction.Trash)} />} - label={ -
-
- Move to Trash - +
+ setValue(FileAction.Forget)} /> + } + label={ +
+
+ Forget + +
+
e.preventDefault()}> + Removes {subjectNoun} from your view. The data will remain on Swarm until{' '} + {currentDriveName ?? 'the drive'} expires. This action cannot be easily undone. +
-
e.preventDefault()}> - Moves {subjectNoun} to the trash. It will still take up space on{' '} - {currentDriveName ?? 'this drive'} and expire along with it. You can restore it later. -
-
- } - /> -
+ } + /> +
-
- setValue(FileAction.Forget)} />} - label={ -
-
- Forget - +
+ setValue(FileAction.Destroy)} /> + } + label={ +
+
+ Destroy entire drive {currentDriveName ? `‘${currentDriveName}’` : ''} to delete this{' '} + {subjectNoun} +
+
e.preventDefault()}> + + Warning: This will make all files on this drive inaccessible. This action is irreversible. +
-
e.preventDefault()}> - Removes {subjectNoun} from your view. The data will remain on Swarm until{' '} - {currentDriveName ?? 'the drive'} expires. This action cannot be easily undone. -
-
- } - /> + } + /> +
- -
- setValue(FileAction.Destroy)} /> - } - label={ -
-
- Destroy entire drive {currentDriveName ? `‘${currentDriveName}’` : ''} to delete this{' '} - {subjectNoun} -
-
e.preventDefault()}> - - Warning: This will make all files on this drive inaccessible. This action is irreversible. -
-
- } - /> -
-
- + +
diff --git a/src/modules/filemanager/components/DestroyDriveModal/DestroyDriveModal.tsx b/src/modules/filemanager/components/DestroyDriveModal/DestroyDriveModal.tsx index d58c9e1..c15dc1c 100644 --- a/src/modules/filemanager/components/DestroyDriveModal/DestroyDriveModal.tsx +++ b/src/modules/filemanager/components/DestroyDriveModal/DestroyDriveModal.tsx @@ -23,20 +23,22 @@ export function ProgressDestroyModal({ drive, onMinimize }: ProgressDestroyModal return createPortal(
-
-
Destroying Drive
-
-
-
Drive "{drive.name}" is being destroyed
-
Please wait while the operation completes...
-
-
- Destroying drive... +
+
+
Destroying Drive
+
+
+
Drive "{drive.name}" is being destroyed
+
Please wait while the operation completes...
+
+
+ Destroying drive... +
-
-
-
, @@ -57,28 +59,32 @@ export function DestroyDriveModal({ drive, onCancelClick, doDestroy }: DestroyDr
Destroy entire drive
-
-
-
Destroy Drive? This Action Is Permanent
-
All files stored only on this drive will become inaccessible.
-
- While the data may still temporarily persist on Swarm, it will be permanently removed once the storage - expires and the data is garbage collected by the network. The File Manager will no longer recognise or - recover these files. -
-
Confirmation:
-
Requires typing a fixed expression to prevent accidental deletion. This action cannot be undone.
-
- Type: {destroyDriveText} -
-
- setDriveNameInput(e.target.value)} - /> +
+
+
+
Destroy Drive? This Action Is Permanent
+
All files stored only on this drive will become inaccessible.
+
+ While the data may still temporarily persist on Swarm, it will be permanently removed once the storage + expires and the data is garbage collected by the network. The File Manager will no longer recognise or + recover these files. +
+
Confirmation:
+
+ Requires typing a fixed expression to prevent accidental deletion. This action cannot be undone. +
+
+ Type: {destroyDriveText} +
+
+ setDriveNameInput(e.target.value)} + /> +
diff --git a/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModal.tsx b/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModal.tsx index 34e2d5e..6915325 100644 --- a/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModal.tsx +++ b/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModal.tsx @@ -1,17 +1,15 @@ import { PostageBatch } from '@ethersphere/bee-js' -import { Warning } from '@mui/icons-material' import { DriveInfo, FileInfo } from '@solarpunkltd/file-manager-lib' import { ReactElement, useEffect, useMemo, useState } from 'react' import { createPortal } from 'react-dom' import AlertIcon from 'remixicon-react/AlertLineIcon' -import CalendarIcon from 'remixicon-react/CalendarLineIcon' -import DriveIcon from 'remixicon-react/HardDrive2LineIcon' -import { calculateStampCapacityMetrics } from '../../utils/bee' import { getDaysLeft } from '../../utils/common' import { Button } from '../Button/Button' import { UpgradeDriveModal } from '../UpgradeDriveModal/UpgradeDriveModal' +import { ExpiringNotificationModalItem } from './ExpiringNotificationModalItem/ExpiringNotificationModalItem' + import './ExpiringNotificationModal.scss' import '../../styles/global.scss' @@ -67,62 +65,24 @@ export function ExpiringNotificationModal({ Drives Expiring soon
The following drives will expire soon. Extend them to keep your data accessible.
- -
- {paginatedStamps.map((stamp, index) => { - const daysLeft = getDaysLeft(stamp.duration.toEndDate()) - let daysClass = '' - - const drive = drives.find(d => d.batchId.toString() === stamp.batchID.toString()) - - if (!drive) return null - - const filesPerDrive = files.filter(fi => fi.driveId === drive.id.toString()) - - const { usedSize, stampSize } = calculateStampCapacityMetrics(stamp, filesPerDrive, drive.redundancyLevel) - - if (daysLeft < 10) { - daysClass = 'fm-red-font' - } else if (daysLeft < 30) { - daysClass = 'fm-swarm-orange-font' - } - - return ( -
+
+ {paginatedStamps.map((stamp, index) => ( + -
- -
-
- {stamp.label} {drive.isAdmin && } -
-
- {usedSize} / {stampSize} -
-
-
-
-
- Expiry date: {stamp.duration.toEndDate().toLocaleDateString()} -
-
{daysLeft} days left
-
-
-
-
- ) - })} + stamp={stamp} + drives={drives} + files={files} + currentPage={currentPage} + index={index} + onUpgradeClick={(stamp, drive) => { + setActualStamp(stamp) + setActualDrive(drive) + setShowUpgradeDriveModal(true) + }} + /> + ))} +
diff --git a/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModalItem/ExpiringNotificationModalItem.scss b/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModalItem/ExpiringNotificationModalItem.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModalItem/ExpiringNotificationModalItem.tsx b/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModalItem/ExpiringNotificationModalItem.tsx new file mode 100644 index 0000000..2bbccb7 --- /dev/null +++ b/src/modules/filemanager/components/ExpiringNotificationModal/ExpiringNotificationModalItem/ExpiringNotificationModalItem.tsx @@ -0,0 +1,75 @@ +import { PostageBatch } from '@ethersphere/bee-js' +import { Warning } from '@mui/icons-material' +import { DriveInfo, FileInfo } from '@solarpunkltd/file-manager-lib' +import { ReactElement } from 'react' +import CalendarIcon from 'remixicon-react/CalendarLineIcon' +import DriveIcon from 'remixicon-react/HardDrive2LineIcon' + +import { calculateStampCapacityMetrics } from '../../../utils/bee' +import { getDaysLeft } from '../../../utils/common' +import { Button } from '../../Button/Button' + +import '../../../styles/global.scss' + +interface ExpiringNotificationModalItemProps { + stamp: PostageBatch + drives: DriveInfo[] + files: FileInfo[] + currentPage: number + index: number + onUpgradeClick: (stamp: PostageBatch, drive: DriveInfo) => void +} + +export function ExpiringNotificationModalItem({ + stamp, + drives, + files, + currentPage, + index, + onUpgradeClick, +}: ExpiringNotificationModalItemProps): ReactElement | null { + const daysLeft = getDaysLeft(stamp.duration.toEndDate()) + let daysClass = '' + + const drive = drives.find(d => d.batchId.toString() === stamp.batchID.toString()) + + if (!drive) return null + + const filesPerDrive = files.filter(fi => fi.driveId === drive.id.toString()) + + const { usedSize, stampSize } = calculateStampCapacityMetrics(stamp, filesPerDrive, drive.redundancyLevel) + + if (daysLeft < 10) { + daysClass = 'fm-red-font' + } else if (daysLeft < 30) { + daysClass = 'fm-swarm-orange-font' + } + + return ( +
+
+ +
+
+ {stamp.label} {drive.isAdmin && } +
+
+ {usedSize} / {stampSize} +
+
+
+
+
+ Expiry date: {stamp.duration.toEndDate().toLocaleDateString()} +
+
{daysLeft} days left
+
+
+
+
+ ) +} diff --git a/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.scss b/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.scss index baf9185..eea7a92 100644 --- a/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.scss +++ b/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.scss @@ -5,6 +5,11 @@ bottom: 45px; background-color: white; z-index: 1200; + max-height: calc(100vh - 275px); + min-height: 170px; + overflow: hidden; + display: flex; + flex-direction: column; } .fm-file-progress-window-header { @@ -15,65 +20,143 @@ border-bottom: 1px solid rgb(209, 213, 219); } -.fm-file-progress-window-header-actions { display: inline-flex; gap: 6px; } +.fm-file-progress-window-header-actions { + display: inline-flex; + gap: 6px; +} .fm-file-progress-window-header-btn { - width: 22px; height: 22px; display: inline-grid; place-items: center; - padding: 0; margin: 0; background: #f0f0f0; color: #4b5563; - border: none; border-radius: 4px; cursor: pointer; - &:hover { background: #e5e7eb; } &:active { background: #d1d5db; } - &:disabled { cursor: default; opacity: .6; filter: grayscale(.3); } + width: 22px; + height: 22px; + display: inline-grid; + place-items: center; + padding: 0; + margin: 0; + background: #f0f0f0; + color: #4b5563; + border: none; + border-radius: 4px; + cursor: pointer; + &:hover { + background: #e5e7eb; + } + &:active { + background: #d1d5db; + } + &:disabled { + cursor: default; + opacity: 0.6; + filter: grayscale(0.3); + } } .fm-file-progress-window-file-item { - display: flex; align-items: flex-start; gap: 8px; - padding: 12px; border-bottom: 1px solid rgb(243, 244, 246); + display: flex; + align-items: flex-start; + gap: 8px; + padding: 12px; + border-bottom: 1px solid rgb(243, 244, 246); } -.fm-file-progress-window-file-type-icon { margin-top: 4px; } +.fm-file-progress-window-file-type-icon { + margin-top: 4px; +} .fm-file-progress-window-file-datas { - display: flex; flex-direction: column; gap: 8px; width: 100%; + display: flex; + flex-direction: column; + gap: 8px; + width: 100%; } .fm-file-progress-window-file-item-header { - display: grid; grid-template-columns: 1fr auto auto; - align-items: center; gap: 8px; min-width: 0; + display: grid; + grid-template-columns: 1fr auto auto; + align-items: center; + gap: 8px; + min-width: 0; } -.fm-file-progress-window-name { min-width: 0; } +.fm-file-progress-window-name { + min-width: 0; +} .fm-file-progress-window-name-text { - overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.fm-drive-line { + margin-top: 2px; } -.fm-drive-line { margin-top: 2px; } -.fm-file-progress-window-percent { white-space: nowrap; } +.fm-file-progress-window-percent { + white-space: nowrap; +} .fm-file-progress-window-file-item-footer { - display: grid; grid-template-columns: auto 1fr auto; - align-items: center; column-gap: 8px; font-size: 11px; + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + column-gap: 8px; + font-size: 11px; +} +.fm-file-progress-window-size { + white-space: nowrap; +} +.fm-file-progress-window-center { + justify-self: center; + white-space: nowrap; +} +.fm-file-progress-window-status { + justify-self: end; + white-space: nowrap; } -.fm-file-progress-window-size { white-space: nowrap; } -.fm-file-progress-window-center { justify-self: center; white-space: nowrap; } -.fm-file-progress-window-status { justify-self: end; white-space: nowrap; } .fm-file-progress-window-row-close { - width: 20px; height: 20px; display: inline-grid; place-items: center; - padding: 0; margin: 0; background: #f0f0f0; color: #4b5563; - border: none; border-radius: 4px; cursor: pointer; - &:hover { background: #e5e7eb; } &:active { background: #d1d5db; } - &:disabled { cursor: default; opacity: .6; filter: grayscale(.3); } + width: 20px; + height: 20px; + display: inline-grid; + place-items: center; + padding: 0; + margin: 0; + background: #f0f0f0; + color: #4b5563; + border: none; + border-radius: 4px; + cursor: pointer; + &:hover { + background: #e5e7eb; + } + &:active { + background: #d1d5db; + } + &:disabled { + cursor: default; + opacity: 0.6; + filter: grayscale(0.3); + } } .fm-drive-chip { - display: inline-block; margin-left: 0; padding: 2px 6px; - border-radius: 999px; font-size: 11px; line-height: 1; - background: rgba(0,0,0,.06); color: #333; vertical-align: middle; + display: inline-block; + margin-left: 0; + padding: 2px 6px; + border-radius: 999px; + font-size: 11px; + line-height: 1; + background: rgba(0, 0, 0, 0.06); + color: #333; + vertical-align: middle; +} +.fm-eta { + font-size: 12px; + opacity: 0.8; +} +.fm-file-subtext { + line-height: 1.2; } -.fm-eta { font-size: 12px; opacity: .8; } -.fm-file-subtext { line-height: 1.2; } .fm-file-progress-window-list { overflow-y: auto; overscroll-behavior: contain; -} \ No newline at end of file +} diff --git a/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.tsx b/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.tsx index bbf92ec..3ab10e4 100644 --- a/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.tsx +++ b/src/modules/filemanager/components/FileProgressWindow/FileProgressWindow.tsx @@ -1,4 +1,4 @@ -import { ReactElement, useLayoutEffect, useRef } from 'react' +import { ReactElement } from 'react' import ArrowDownIcon from 'remixicon-react/ArrowDownSLineIcon' import CloseIcon from 'remixicon-react/CloseLineIcon' @@ -44,8 +44,6 @@ export function FileProgressWindow({ onRowClose, onCloseAll, }: FileProgressWindowProps): ReactElement | null { - const listRef = useRef(null) - const firstRowRef = useRef(null) const count = items?.length ?? 0 const rows: ProgressItem[] = items ?? [] @@ -73,17 +71,6 @@ export function FileProgressWindow({ ) }) - useLayoutEffect(() => { - const rowEl = firstRowRef.current - const listEl = listRef.current - - if (!rowEl || !listEl) return - - const rowH = rowEl.getBoundingClientRect().height - const safeRowH = rowH > 0 ? rowH : 72 - listEl.style.maxHeight = `${safeRowH * 5}px` - }, [rows.length]) - return (
@@ -113,7 +100,7 @@ export function FileProgressWindow({
-
+
{rows.map((item, idx) => { const pctNum = Number.isFinite(item.percent) ? Math.max(0, Math.min(100, Math.round(item.percent as number))) @@ -140,11 +127,7 @@ export function FileProgressWindow({ const centerDisplay = getCenterText() || '\u00A0' return ( -
+
diff --git a/src/modules/filemanager/components/InitialModal/InitialModal.tsx b/src/modules/filemanager/components/InitialModal/InitialModal.tsx index dc865ea..aeb1d7c 100644 --- a/src/modules/filemanager/components/InitialModal/InitialModal.tsx +++ b/src/modules/filemanager/components/InitialModal/InitialModal.tsx @@ -294,71 +294,73 @@ export function InitialModal({
Welcome to your Swarm File Manager
{initText} the File Manager
- {nonFullStamps.length > 0 && ( -
-
- { - setSelectedBatchIndex(index) +
+ {nonFullStamps.length > 0 && ( +
+
+ { + setSelectedBatchIndex(index) - if (index === -1) { - setSelectedBatch(null) - } - }} - placeholder={BATCH_ID_PLACEHOLDER} - /> - {selectedBatch && ( -
-
- Capacity {usedSize} / {stampSize} + if (index === -1) { + setSelectedBatch(null) + } + }} + placeholder={BATCH_ID_PLACEHOLDER} + /> + {selectedBatch && ( +
+
+ Capacity {usedSize} / {stampSize} +
+
+ Expiry date: {selectedBatch.duration.toEndDate().toLocaleDateString()} +
-
- Expiry date: {selectedBatch.duration.toEndDate().toLocaleDateString()} -
-
- )} - {selectedBatch && setSecurityLevel(setErasureCodeLevel)} -
-
- )} - {!selectedBatch && ( -
-
- - -
- {setSecurityLevel(setErasureCodeLevel)} -
-
-
Estimated Cost:
-
- {cost} BZZ {isBalanceSufficient ? '' : '(Insufficient balance)'} - {isxDaiBalanceSufficient ? '' : ' (Insufficient xDAI balance)'} -
- + )} + {selectedBatch && setSecurityLevel(setErasureCodeLevel)}
-
(Based on current network conditions)
- {renderUltraLightNodeWarning()} - {isNodeSyncing && !selectedBatch && ( -
- Node is syncing. Please wait until sync completes before purchasing a stamp. -
- )}
-
- )} + )} + {!selectedBatch && ( +
+
+ + +
+ {setSecurityLevel(setErasureCodeLevel)} +
+
+
Estimated Cost:
+
+ {cost} BZZ {isBalanceSufficient ? '' : '(Insufficient balance)'} + {isxDaiBalanceSufficient ? '' : ' (Insufficient xDAI balance)'} +
+ +
+
(Based on current network conditions)
+ {renderUltraLightNodeWarning()} + {isNodeSyncing && !selectedBatch && ( +
+ Node is syncing. Please wait until sync completes before purchasing a stamp. +
+ )} +
+
+ )} +
+
Choose extension period and additional storage for your drive.
-
Choose extension period and additional storage for your drive.
diff --git a/src/modules/filemanager/components/UploadConflictModal/UploadConflictModal.tsx b/src/modules/filemanager/components/UploadConflictModal/UploadConflictModal.tsx index 70f170d..227ff00 100644 --- a/src/modules/filemanager/components/UploadConflictModal/UploadConflictModal.tsx +++ b/src/modules/filemanager/components/UploadConflictModal/UploadConflictModal.tsx @@ -39,63 +39,64 @@ export function UploadConflictModal({ File already exists
- -
-
-
-
A file named “{filename}” already exists in this drive.
-
What would you like to do?
-
- -
-
Keep both
-
- Upload the new file as a separate item with a different name. +
+
+
+
+
A file named “{filename}” already exists in this drive.
+
What would you like to do?
-
- - setCustomName(e.target.value)} - className="fm-input" - placeholder={suggestedName} + +
+
Keep both
+
+ Upload the new file as a separate item with a different name. +
+
+ + setCustomName(e.target.value)} + className="fm-input" + placeholder={suggestedName} + /> + {!isNameValid && customName.trim().length > 0 && existingNames.has(customName.trim()) && ( +
+ That name already exists. +
+ )} +
+
-
-
+
-
-
Replace
-
- Replace the existing file by uploading this as a new version of “{filename}”. +
+
Replace
+
+ Replace the existing file by uploading this as a new version of “{filename}”. +
+
-
+ {isTrashedExisting && ( +
+ + + + + Heads up: The existing '{filename}' is currently in Trash. + +
+ )}
- {isTrashedExisting && ( -
- - - - - Heads up: The existing '{filename}' is currently in Trash. - -
- )}
diff --git a/src/modules/filemanager/components/VersionHistoryModal/VersionHistoryModal.tsx b/src/modules/filemanager/components/VersionHistoryModal/VersionHistoryModal.tsx index 6401745..327ce7b 100644 --- a/src/modules/filemanager/components/VersionHistoryModal/VersionHistoryModal.tsx +++ b/src/modules/filemanager/components/VersionHistoryModal/VersionHistoryModal.tsx @@ -293,60 +293,61 @@ export function VersionHistoryModal({ fileInfo, onCancelClick, onDownload }: Ver
+
+
+ {error &&
{error}
} -
- {error &&
{error}
} + {loading &&
Loading…
} + {!error && !loading && pageVersions.length === 0 && ( +
No versions found for this file.
+ )} + {conflictWarning && ( +
+ {conflictWarning} +
+ )} - {loading &&
Loading…
} - {!error && !loading && pageVersions.length === 0 && ( -
No versions found for this file.
- )} - {conflictWarning && ( -
- {conflictWarning} -
- )} + {renameConfirm && ( + + Restore this version? + + + } + message={ + <> + Restoring will rename:  + + {truncateNameMiddle(renameConfirm.headName)} + {' '} + →{' '} + + {truncateNameMiddle(renameConfirm.targetName)} + + . + + } + confirmLabel="Restore" + cancelLabel="Cancel" + onConfirm={async () => { + await doRestore(renameConfirm.version) + setRenameConfirm(null) + }} + onCancel={() => setRenameConfirm(null)} + /> + )} - {renameConfirm && ( - - Restore this version? - - - } - message={ - <> - Restoring will rename:  - - {truncateNameMiddle(renameConfirm.headName)} - {' '} - →{' '} - - {truncateNameMiddle(renameConfirm.targetName)} - - . - - } - confirmLabel="Restore" - cancelLabel="Cancel" - onConfirm={async () => { - await doRestore(renameConfirm.version) - setRenameConfirm(null) - }} - onCancel={() => setRenameConfirm(null)} + - )} - - +
diff --git a/src/modules/filemanager/styles/global.scss b/src/modules/filemanager/styles/global.scss index c19f1ec..95b0e6f 100644 --- a/src/modules/filemanager/styles/global.scss +++ b/src/modules/filemanager/styles/global.scss @@ -1,3 +1,5 @@ +$fm-modal-vertical-offset: 48px; + .fm-modal-container { position: absolute; top: 0; @@ -25,6 +27,7 @@ flex-direction: column; gap: 24px; justify-content: center; + max-height: calc(100vh - #{$fm-modal-vertical-offset}); } .fm-modal-window-header { @@ -38,6 +41,15 @@ font-weight: 700; } +.fm-modal-window-scrollable { + overflow-y: auto; + overflow-x: hidden; + + &::-webkit-scrollbar { + width: 6px; + } +} + .fm-modal-window-body { display: flex; flex-direction: column;