fix: link_randomuuid_cache (#718)

* fix: [SPDV-828] use react router link instead of href
* fix: auto import issue
* fix: replace randomuuid with getRandomValues=
* fix: reset FM states if state is invalid
* fix: use no-cache for stamp fetch
* fix: clear cache and reload message
* fix: shallReset flag
* fix: identify browser platform and set help url accordingly
* fix: edge browser detection
* fix: use fallback chrome and verify for safari

---------

Co-authored-by: Nandor Komlodi <nandor.komlodi@gmail.com>
Co-authored-by: Balint Ujvari <balint.ujvari@solarpunk.buzz>
This commit is contained in:
Ferenc Sárai
2026-02-17 17:19:10 +01:00
committed by GitHub
parent beacd5b98e
commit 9e1036ac29
9 changed files with 78 additions and 9 deletions
@@ -12,6 +12,7 @@ import { UpgradeDriveModal } from '../UpgradeDriveModal/UpgradeDriveModal'
import { UpgradeTimeoutModal } from '../UpgradeTimeoutModal/UpgradeTimeoutModal'
import { FILE_MANAGER_EVENTS, POLLING_TIMEOUT_MS } from '../../constants/common'
import { useStampPolling } from '../../hooks/useStampPolling'
import { TOOLTIPS } from '../../constants/tooltips'
interface AdminStatusBarProps {
adminStamp: PostageBatch | null
@@ -226,10 +227,7 @@ export function AdminStatusBar({
<div>File Manager Available: Until: {expiresAt}</div>
<Tooltip
label="The File Manager works only while your storage remains valid. If it expires, all catalogue metadata is
permanently lost."
/>
<Tooltip label={TOOLTIPS.ADMIN_STATUS_WARNING} />
</div>
{renderModalsAndOverlays()}
@@ -2,6 +2,7 @@ import { useState, ReactElement, useEffect } from 'react'
import './PrivateKeyModal.scss'
import { Button } from '../Button/Button'
import { setSignerPk, getSigner } from '../../utils/common'
import { uuidV4 } from '../../../../utils'
import { PrivateKey } from '@ethersphere/bee-js'
import ClipboardIcon from 'remixicon-react/FileCopyLineIcon'
import CheckDoubleLineIcon from 'remixicon-react/CheckDoubleLineIcon'
@@ -31,7 +32,7 @@ export function PrivateKeyModal({ onSaved }: Props): ReactElement {
}
const handleGenerateNew = () => {
const id = crypto.randomUUID()
const id = uuidV4()
const signer = getSigner(id)
const privKey = signer.toHex()
@@ -53,6 +53,8 @@ This action will do two things:
ADMIN_PURCHASE_BUTTON_ALREADY_EXISTED_ADMIN_DRIVE: `${getTitleWithStyle('Create Admin Drive')}
It will create the Admin Drive.`,
ADMIN_STATUS_WARNING:
'The File Manager works only while your storage remains valid. If it expires, all catalogue metadata is permanently lost.',
// Drive Creation
DRIVE_NAME: `${getTitleWithStyle('About Drive Name')}
+1
View File
@@ -172,6 +172,7 @@ export const handleCreateDrive = async (options: CreateDriveOptions): Promise<vo
batchId = await beeApi.buyStorage(size, duration, { label }, undefined, encryption, redundancyLevel)
} else {
// TODO: redundant, fm checks for stamp validtiy
const isValid = await validateStampStillExists(beeApi, existingBatch.batchID)
if (!isValid) {
+24 -2
View File
@@ -8,6 +8,7 @@ import { AdminStatusBar } from '../../modules/filemanager/components/AdminStatus
import { FileBrowser } from '../../modules/filemanager/components/FileBrowser/FileBrowser'
import { InitialModal } from '../../modules/filemanager/components/InitialModal/InitialModal'
import { Context as FMContext } from '../../providers/FileManager'
import { BrowserPlatform, cacheClearUrls, detectBrowser } from '../../providers/Platform'
import { Context as SettingsContext } from '../../providers/Settings'
import { Context as BeeContext, CheckState } from '../../providers/Bee'
import { PrivateKeyModal } from '../../modules/filemanager/components/PrivateKeyModal/PrivateKeyModal'
@@ -28,6 +29,7 @@ export function FileManagerPage(): ReactElement {
const [showResetModal, setShowResetModal] = useState<boolean>(false)
const [isCreationInProgress, setIsCreationInProgress] = useState<boolean>(false)
const [showConnectionError, setShowConnectionError] = useState<boolean>(false)
const [cacheHelpUrl, setCacheHelpUrl] = useState<string>(cacheClearUrls[BrowserPlatform.Chrome])
const { status } = useContext(BeeContext)
const { beeApi } = useContext(SettingsContext)
@@ -36,6 +38,13 @@ export function FileManagerPage(): ReactElement {
useEffect(() => {
isMountedRef.current = true
const getBrowserPlatform = async () => {
const browserPlatform = await detectBrowser()
setCacheHelpUrl(cacheClearUrls[browserPlatform])
}
getBrowserPlatform()
return () => {
isMountedRef.current = false
}
@@ -162,8 +171,21 @@ export function FileManagerPage(): ReactElement {
<div className="fm-main">
<ConfirmModal
title="Reset File Manager State"
message="Your File Manager state appears invalid. Please reset it to continue."
confirmLabel="Proceed"
message={
<span>
Your File Manager state appears invalid. Please{' '}
<a
href={cacheHelpUrl}
target="_blank"
rel="noopener noreferrer"
style={{ display: 'inline', textDecoration: 'underline' }}
>
clear the browser cache
</a>{' '}
and reload the page. Then you can reset the File Manager to continue.
</span>
}
confirmLabel="Continue"
onConfirm={() => {
setShowResetModal(false)
}}
+3 -1
View File
@@ -1,13 +1,15 @@
import { ReactElement } from 'react'
import { HistoryHeader } from '../../components/HistoryHeader'
import { Typography } from '@material-ui/core'
import { Link } from 'react-router-dom'
import { ROUTES } from '../../routes'
export default function PageNotFound(): ReactElement {
return (
<div>
<HistoryHeader>Page not found</HistoryHeader>
<Typography>
The given url is invalid. Please go back or <a href="/">navigate to Home screen.</a>
The given url is invalid. Please go back or <Link to={ROUTES.INFO}>navigate to Home screen.</Link>
</Typography>
</div>
)
+7 -1
View File
@@ -5,8 +5,8 @@ import { FileManagerBase, FileManagerEvents } from '@solarpunkltd/file-manager-l
import { Context as SettingsContext } from './Settings'
import { DriveInfo } from '@solarpunkltd/file-manager-lib'
import { getSignerPk } from '../modules/filemanager/utils/common'
import { getUsableStamps } from '../../src/modules/filemanager/utils/bee'
import { FILE_MANAGER_EVENTS } from '../modules/filemanager/constants/common'
import { getUsableStamps } from '../modules/filemanager/utils/bee'
interface ContextInterface {
fm: FileManagerBase | null
@@ -256,6 +256,12 @@ export function Provider({ children }: Props) {
const handleResetState = (isInvalid: boolean) => {
setShallReset(isInvalid)
setFiles([])
setDrives([])
setExpiredDrives([])
setAdminDrive(null)
setCurrentDrive(undefined)
setCurrentStamp(undefined)
}
manager.emitter.on(FileManagerEvents.STATE_INVALID, handleResetState)
+36
View File
@@ -55,6 +55,42 @@ function getOS(): Platforms | null {
return null
}
export enum BrowserPlatform {
Chrome = 'chrome',
Firefox = 'firefox',
Safari = 'safari',
Brave = 'brave',
Edge = 'edge',
}
export async function isBraveBrowser(): Promise<boolean> {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return (window.navigator.brave && (await window.navigator.brave.isBrave())) === true
}
export async function detectBrowser(): Promise<BrowserPlatform> {
const ua = window.navigator.userAgent.toLowerCase()
if (ua.includes('edge') || ua.includes('edg/')) return BrowserPlatform.Edge
if (ua.includes('chrome') && (await isBraveBrowser())) return BrowserPlatform.Brave
if (ua.includes('firefox')) return BrowserPlatform.Firefox
if (ua.includes('safari') && !ua.includes('chrome')) return BrowserPlatform.Safari
return BrowserPlatform.Chrome
}
export const cacheClearUrls = {
chrome: 'https://support.google.com/accounts/answer/32050?hl=en&co=GENIE.Platform%3DDesktop',
brave: 'https://support.brave.app/hc/en-us/articles/360048833872-How-Do-I-Clear-Cookies-And-Site-Data-In-Brave',
firefox: 'https://support.mozilla.org/en-US/kb/how-clear-firefox-cache',
safari: 'https://support.apple.com/en-il/guide/safari/sfri47acf5d6/mac',
edge: 'https://support.microsoft.com/en-us/microsoft-edge/view-and-delete-browser-history-in-microsoft-edge-00cf7943-a9e1-975a-a33d-ac10ce454ca4',
}
export function Provider({ children }: Props): ReactElement {
const [platform, setPlatform] = useState<SupportedPlatforms>(SupportedPlatforms.Linux)
+1
View File
@@ -211,6 +211,7 @@ interface Options {
timeout?: number
}
// TODO: merge this with FM component getUsableStamps()
export function waitUntilStampUsable(batchId: BatchId | string, bee: Bee, options?: Options): Promise<PostageBatch> {
return waitForStamp(batchId, bee, options)
}