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 { AttachedFilesPopover } from './AttachedFilesPopover'
|
||||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||||
import { PopoverTabs } from './PopoverTabs'
|
import { PopoverTabs } from './PopoverTabs'
|
||||||
|
import { isHandlingFileDrag } from '@/Utils/DragTypeCheck'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -23,21 +24,6 @@ type Props = {
|
|||||||
onClickPreprocessing?: () => Promise<void>
|
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(
|
export const AttachedFilesButton: FunctionComponent<Props> = observer(
|
||||||
({ application, appState, onClickPreprocessing }) => {
|
({ application, appState, onClickPreprocessing }) => {
|
||||||
const premiumModal = usePremiumModal()
|
const premiumModal = usePremiumModal()
|
||||||
|
|||||||
@@ -1,156 +1,14 @@
|
|||||||
import { WebApplication } from '@/UIModels/Application'
|
import { PreferencesSegment, Title, Text, Subtitle } from '@/Components/Preferences/PreferencesComponents'
|
||||||
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 { useCallback, useEffect, useMemo, useState } from 'preact/hooks'
|
||||||
import { Button } from '@/Components/Button/Button'
|
import { Button } from '@/Components/Button/Button'
|
||||||
import { FileBackupMetadataFile, FileBackupsConstantsV1, FileContent, FileHandleRead } from '@standardnotes/snjs'
|
import { FileBackupMetadataFile, FileBackupsConstantsV1, FileContent, FileHandleRead } from '@standardnotes/snjs'
|
||||||
import { Switch } from '@/Components/Switch'
|
|
||||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||||
import { EncryptionStatusItem } from '../Security/Encryption'
|
import { EncryptionStatusItem } from '../../Security/Encryption'
|
||||||
import { Icon } from '@/Components/Icon'
|
import { Icon } from '@/Components/Icon'
|
||||||
import { StreamingFileApi } from '@standardnotes/filepicker'
|
import { StreamingFileApi } from '@standardnotes/filepicker'
|
||||||
import { FunctionComponent } from 'preact'
|
import { FunctionComponent } from 'preact'
|
||||||
|
import { Props } from './FileBackups'
|
||||||
type Props = {
|
import { isHandlingBackupDrag } from '@/Utils/DragTypeCheck'
|
||||||
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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const BackupsDropZone: FunctionComponent<Props> = ({ application }) => {
|
export const BackupsDropZone: FunctionComponent<Props> = ({ application }) => {
|
||||||
const [droppedFile, setDroppedFile] = useState<FileBackupMetadataFile | undefined>(undefined)
|
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 { CloudLink } from './CloudBackups'
|
||||||
import { DataBackups } from './DataBackups'
|
import { DataBackups } from './DataBackups'
|
||||||
import { EmailBackups } from './EmailBackups'
|
import { EmailBackups } from './EmailBackups'
|
||||||
import { FileBackups } from './FileBackups'
|
import { FileBackups } from './Files/FileBackups'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
appState: AppState
|
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