chore: break up file backups into two components
This commit is contained in:
@@ -16,6 +16,7 @@ import { PopoverFileItemAction, PopoverFileItemActionType } from './PopoverFileI
|
||||
import { AttachedFilesPopover } from './AttachedFilesPopover'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
import { PopoverTabs } from './PopoverTabs'
|
||||
import { isHandlingFileDrag } from '@/Utils/DragTypeCheck'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -23,21 +24,6 @@ type Props = {
|
||||
onClickPreprocessing?: () => Promise<void>
|
||||
}
|
||||
|
||||
const isHandlingFileDrag = (event: DragEvent, application: WebApplication) => {
|
||||
const items = event.dataTransfer?.items
|
||||
|
||||
if (!items) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Array.from(items).some((item) => {
|
||||
const isFile = item.kind === 'file'
|
||||
const fileName = item.getAsFile()?.name || ''
|
||||
const isBackupMetadataFile = application.files.isFileNameFileBackupMetadataFile(fileName)
|
||||
return isFile && !isBackupMetadataFile
|
||||
})
|
||||
}
|
||||
|
||||
export const AttachedFilesButton: FunctionComponent<Props> = observer(
|
||||
({ application, appState, onClickPreprocessing }) => {
|
||||
const premiumModal = usePremiumModal()
|
||||
|
||||
@@ -1,156 +1,14 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
Title,
|
||||
Text,
|
||||
Subtitle,
|
||||
} from '@/Components/Preferences/PreferencesComponents'
|
||||
import { PreferencesSegment, Title, Text, Subtitle } from '@/Components/Preferences/PreferencesComponents'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'preact/hooks'
|
||||
import { Button } from '@/Components/Button/Button'
|
||||
import { FileBackupMetadataFile, FileBackupsConstantsV1, FileContent, FileHandleRead } from '@standardnotes/snjs'
|
||||
import { Switch } from '@/Components/Switch'
|
||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||
import { EncryptionStatusItem } from '../Security/Encryption'
|
||||
import { EncryptionStatusItem } from '../../Security/Encryption'
|
||||
import { Icon } from '@/Components/Icon'
|
||||
import { StreamingFileApi } from '@standardnotes/filepicker'
|
||||
import { FunctionComponent } from 'preact'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
export const FileBackups = observer(({ application }: Props) => {
|
||||
const [backupsEnabled, setBackupsEnabled] = useState(false)
|
||||
const [backupsLocation, setBackupsLocation] = useState('')
|
||||
const backupsService = useMemo(() => application.fileBackups, [application.fileBackups])
|
||||
|
||||
if (!backupsService) {
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>File Backups</Title>
|
||||
<Subtitle>Automatically save encrypted backups of files uploaded to any device to this computer.</Subtitle>
|
||||
<Text className="mt-3">To enable file backups, use the Standard Notes desktop application.</Text>
|
||||
</PreferencesSegment>
|
||||
<PreferencesSegment>
|
||||
<BackupsDropZone application={application} />
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
void backupsService.isFilesBackupsEnabled().then(setBackupsEnabled)
|
||||
}, [backupsService])
|
||||
|
||||
useEffect(() => {
|
||||
if (backupsEnabled) {
|
||||
void backupsService.getFilesBackupsLocation().then(setBackupsLocation)
|
||||
}
|
||||
}, [backupsService, backupsEnabled])
|
||||
|
||||
const changeBackupsLocation = useCallback(async () => {
|
||||
await backupsService.changeFilesBackupsLocation()
|
||||
|
||||
setBackupsLocation(await backupsService.getFilesBackupsLocation())
|
||||
}, [backupsService])
|
||||
|
||||
const openBackupsLocation = useCallback(async () => {
|
||||
await backupsService.openFilesBackupsLocation()
|
||||
}, [backupsService])
|
||||
|
||||
const toggleBackups = useCallback(async () => {
|
||||
if (backupsEnabled) {
|
||||
await backupsService.disableFilesBackups()
|
||||
} else {
|
||||
await backupsService.enableFilesBackups()
|
||||
}
|
||||
|
||||
setBackupsEnabled(await backupsService.isFilesBackupsEnabled())
|
||||
}, [backupsService, backupsEnabled])
|
||||
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>File Backups</Title>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col mr-10">
|
||||
<Subtitle>
|
||||
Automatically save encrypted backups of files uploaded on any device to this computer.
|
||||
</Subtitle>
|
||||
</div>
|
||||
<Switch onChange={toggleBackups} checked={backupsEnabled} />
|
||||
</div>
|
||||
|
||||
{!backupsEnabled && (
|
||||
<>
|
||||
<HorizontalSeparator classes="mt-5 mb-4" />
|
||||
<Text>File backups are not enabled. Enable to choose where your files are backed up.</Text>
|
||||
</>
|
||||
)}
|
||||
</PreferencesSegment>
|
||||
|
||||
{backupsEnabled && (
|
||||
<>
|
||||
<PreferencesSegment>
|
||||
<>
|
||||
<Text className="mb-3">
|
||||
Files backups are enabled. When you upload a new file on any device and open this application, files
|
||||
will be backed up in encrypted form to:
|
||||
</Text>
|
||||
|
||||
<EncryptionStatusItem
|
||||
status={backupsLocation}
|
||||
icon={[<Icon type="attachment-file" className="min-w-5 min-h-5" />]}
|
||||
checkmark={false}
|
||||
/>
|
||||
<div className="flex flex-row mt-5">
|
||||
<Button
|
||||
variant="normal"
|
||||
label="Open Backups Location"
|
||||
className={'mr-3 text-xs'}
|
||||
onClick={openBackupsLocation}
|
||||
/>
|
||||
<Button
|
||||
variant="normal"
|
||||
label="Change Backups Location"
|
||||
className={'mr-3 text-xs'}
|
||||
onClick={changeBackupsLocation}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</PreferencesSegment>
|
||||
</>
|
||||
)}
|
||||
|
||||
<PreferencesSegment>
|
||||
<BackupsDropZone application={application} />
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
const isHandlingBackupDrag = (event: DragEvent, application: WebApplication) => {
|
||||
const items = event.dataTransfer?.items
|
||||
|
||||
if (!items) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Array.from(items).every((item) => {
|
||||
const isFile = item.kind === 'file'
|
||||
const fileName = item.getAsFile()?.name || ''
|
||||
const isBackupMetadataFile = application.files.isFileNameFileBackupMetadataFile(fileName)
|
||||
return isFile && isBackupMetadataFile
|
||||
})
|
||||
}
|
||||
import { Props } from './FileBackups'
|
||||
import { isHandlingBackupDrag } from '@/Utils/DragTypeCheck'
|
||||
|
||||
export const BackupsDropZone: FunctionComponent<Props> = ({ application }) => {
|
||||
const [droppedFile, setDroppedFile] = useState<FileBackupMetadataFile | undefined>(undefined)
|
||||
@@ -0,0 +1,136 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
Title,
|
||||
Text,
|
||||
Subtitle,
|
||||
} from '@/Components/Preferences/PreferencesComponents'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'preact/hooks'
|
||||
import { Button } from '@/Components/Button/Button'
|
||||
import { Switch } from '@/Components/Switch'
|
||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||
import { EncryptionStatusItem } from '../../Security/Encryption'
|
||||
import { Icon } from '@/Components/Icon'
|
||||
import { BackupsDropZone } from './BackupsDropZone'
|
||||
|
||||
export type Props = {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
export const FileBackups = observer(({ application }: Props) => {
|
||||
const [backupsEnabled, setBackupsEnabled] = useState(false)
|
||||
const [backupsLocation, setBackupsLocation] = useState('')
|
||||
const backupsService = useMemo(() => application.fileBackups, [application.fileBackups])
|
||||
|
||||
if (!backupsService) {
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>File Backups</Title>
|
||||
<Subtitle>Automatically save encrypted backups of files uploaded to any device to this computer.</Subtitle>
|
||||
<Text className="mt-3">To enable file backups, use the Standard Notes desktop application.</Text>
|
||||
</PreferencesSegment>
|
||||
<PreferencesSegment>
|
||||
<BackupsDropZone application={application} />
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
void backupsService.isFilesBackupsEnabled().then(setBackupsEnabled)
|
||||
}, [backupsService])
|
||||
|
||||
useEffect(() => {
|
||||
if (backupsEnabled) {
|
||||
void backupsService.getFilesBackupsLocation().then(setBackupsLocation)
|
||||
}
|
||||
}, [backupsService, backupsEnabled])
|
||||
|
||||
const changeBackupsLocation = useCallback(async () => {
|
||||
await backupsService.changeFilesBackupsLocation()
|
||||
|
||||
setBackupsLocation(await backupsService.getFilesBackupsLocation())
|
||||
}, [backupsService])
|
||||
|
||||
const openBackupsLocation = useCallback(async () => {
|
||||
await backupsService.openFilesBackupsLocation()
|
||||
}, [backupsService])
|
||||
|
||||
const toggleBackups = useCallback(async () => {
|
||||
if (backupsEnabled) {
|
||||
await backupsService.disableFilesBackups()
|
||||
} else {
|
||||
await backupsService.enableFilesBackups()
|
||||
}
|
||||
|
||||
setBackupsEnabled(await backupsService.isFilesBackupsEnabled())
|
||||
}, [backupsService, backupsEnabled])
|
||||
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>File Backups</Title>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col mr-10">
|
||||
<Subtitle>
|
||||
Automatically save encrypted backups of files uploaded on any device to this computer.
|
||||
</Subtitle>
|
||||
</div>
|
||||
<Switch onChange={toggleBackups} checked={backupsEnabled} />
|
||||
</div>
|
||||
|
||||
{!backupsEnabled && (
|
||||
<>
|
||||
<HorizontalSeparator classes="mt-5 mb-4" />
|
||||
<Text>File backups are not enabled. Enable to choose where your files are backed up.</Text>
|
||||
</>
|
||||
)}
|
||||
</PreferencesSegment>
|
||||
|
||||
{backupsEnabled && (
|
||||
<>
|
||||
<PreferencesSegment>
|
||||
<>
|
||||
<Text className="mb-3">
|
||||
Files backups are enabled. When you upload a new file on any device and open this application, files
|
||||
will be backed up in encrypted form to:
|
||||
</Text>
|
||||
|
||||
<EncryptionStatusItem
|
||||
status={backupsLocation}
|
||||
icon={[<Icon type="attachment-file" className="min-w-5 min-h-5" />]}
|
||||
checkmark={false}
|
||||
/>
|
||||
<div className="flex flex-row mt-5">
|
||||
<Button
|
||||
variant="normal"
|
||||
label="Open Backups Location"
|
||||
className={'mr-3 text-xs'}
|
||||
onClick={openBackupsLocation}
|
||||
/>
|
||||
<Button
|
||||
variant="normal"
|
||||
label="Change Backups Location"
|
||||
className={'mr-3 text-xs'}
|
||||
onClick={changeBackupsLocation}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</PreferencesSegment>
|
||||
</>
|
||||
)}
|
||||
|
||||
<PreferencesSegment>
|
||||
<BackupsDropZone application={application} />
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
</>
|
||||
)
|
||||
})
|
||||
@@ -5,7 +5,7 @@ import { PreferencesPane } from '@/Components/Preferences/PreferencesComponents'
|
||||
import { CloudLink } from './CloudBackups'
|
||||
import { DataBackups } from './DataBackups'
|
||||
import { EmailBackups } from './EmailBackups'
|
||||
import { FileBackups } from './FileBackups'
|
||||
import { FileBackups } from './Files/FileBackups'
|
||||
|
||||
interface Props {
|
||||
appState: AppState
|
||||
|
||||
31
app/assets/javascripts/Utils/DragTypeCheck.tsx
Normal file
31
app/assets/javascripts/Utils/DragTypeCheck.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { WebApplication } from '@/UIModels/Application'
|
||||
|
||||
export const isHandlingFileDrag = (event: DragEvent, application: WebApplication) => {
|
||||
const items = event.dataTransfer?.items
|
||||
|
||||
if (!items) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Array.from(items).some((item) => {
|
||||
const isFile = item.kind === 'file'
|
||||
const fileName = item.getAsFile()?.name || ''
|
||||
const isBackupMetadataFile = application.files.isFileNameFileBackupMetadataFile(fileName)
|
||||
return isFile && !isBackupMetadataFile
|
||||
})
|
||||
}
|
||||
|
||||
export const isHandlingBackupDrag = (event: DragEvent, application: WebApplication) => {
|
||||
const items = event.dataTransfer?.items
|
||||
|
||||
if (!items) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Array.from(items).every((item) => {
|
||||
const isFile = item.kind === 'file'
|
||||
const fileName = item.getAsFile()?.name || ''
|
||||
const isBackupMetadataFile = application.files.isFileNameFileBackupMetadataFile(fileName)
|
||||
return isFile && isBackupMetadataFile
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user