feat: files related improvements

This commit is contained in:
Mo
2022-05-10 10:32:05 -05:00
parent 026a26ac04
commit d7ba3935ed
7 changed files with 42 additions and 46 deletions

View File

@@ -72,7 +72,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
}, [application, note]) }, [application, note])
const toggleAttachedFilesMenu = useCallback(async () => { const toggleAttachedFilesMenu = useCallback(async () => {
if (!appState.features.isEntitledToFiles) { if (!appState.features.hasFiles) {
premiumModal.activate('Files') premiumModal.activate('Files')
return return
} }
@@ -99,7 +99,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
setOpen(newOpenState) setOpen(newOpenState)
} }
}, [appState.features.isEntitledToFiles, onClickPreprocessing, open, premiumModal]) }, [appState.features.hasFiles, onClickPreprocessing, open, premiumModal])
const deleteFile = async (file: SNFile) => { const deleteFile = async (file: SNFile) => {
const shouldDelete = await confirmDialog({ const shouldDelete = await confirmDialog({
@@ -294,6 +294,10 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
setIsDraggingFiles(false) setIsDraggingFiles(false)
if (!appState.features.hasFiles) {
return
}
if (event.dataTransfer?.items.length) { if (event.dataTransfer?.items.length) {
Array.from(event.dataTransfer.items).forEach(async (item) => { Array.from(event.dataTransfer.items).forEach(async (item) => {
const fileOrHandle = StreamingFileReader.available() const fileOrHandle = StreamingFileReader.available()
@@ -321,7 +325,7 @@ export const AttachedFilesButton: FunctionComponent<Props> = observer(
dragCounter.current = 0 dragCounter.current = 0
} }
}, },
[appState.files, attachFileToNote, currentTab], [appState.files, appState.features.hasFiles, attachFileToNote, currentTab],
) )
useEffect(() => { useEffect(() => {

View File

@@ -18,7 +18,10 @@ export const FilePreviewInfoPanel: FunctionComponent<Props> = ({ file }) => {
<span className="font-semibold">Type:</span> {file.mimeType} <span className="font-semibold">Type:</span> {file.mimeType}
</div> </div>
<div className="mb-3"> <div className="mb-3">
<span className="font-semibold">Size:</span> {formatSizeToReadableString(file.decryptedSize)} <span className="font-semibold">Decrypted Size:</span> {formatSizeToReadableString(file.decryptedSize)}
</div>
<div className="mb-3">
<span className="font-semibold">Encrypted Size:</span> {formatSizeToReadableString(file.encryptedSize)}
</div> </div>
<div className="mb-3"> <div className="mb-3">
<span className="font-semibold">Created:</span> {file.created_at.toLocaleString()} <span className="font-semibold">Created:</span> {file.created_at.toLocaleString()}

View File

@@ -947,15 +947,13 @@ export class NoteView extends PureComponent<Props, State> {
{this.state.noteStatus?.desc && <div className="desc">{this.state.noteStatus.desc}</div>} {this.state.noteStatus?.desc && <div className="desc">{this.state.noteStatus.desc}</div>}
</div> </div>
</div> </div>
{this.appState.features.isFilesEnabled && ( <div className="mr-3">
<div className="mr-3"> <AttachedFilesButton
<AttachedFilesButton application={this.application}
application={this.application} appState={this.appState}
appState={this.appState} onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction}
onClickPreprocessing={this.ensureNoteIsInsertedBeforeUIAction} />
/> </div>
</div>
)}
<div className="mr-3"> <div className="mr-3">
<ChangeEditorButton <ChangeEditorButton
application={this.application} application={this.application}

View File

@@ -49,6 +49,7 @@ export const NotesListItem: FunctionComponent<Props> = ({
tags, tags,
}) => { }) => {
const flags = flagsForNote(note) const flags = flagsForNote(note)
const hasFiles = application.items.getFilesForNote(note).length > 0
const showModifiedDate = sortedBy === CollectionSort.UpdatedAt const showModifiedDate = sortedBy === CollectionSort.UpdatedAt
const editorForNote = application.componentManager.editorForNote(note) const editorForNote = application.componentManager.editorForNote(note)
const editorName = editorForNote?.name ?? PLAIN_EDITOR_NAME const editorName = editorForNote?.name ?? PLAIN_EDITOR_NAME
@@ -132,6 +133,11 @@ export const NotesListItem: FunctionComponent<Props> = ({
<Icon ariaLabel="Pinned" type="pin-filled" className="sn-icon--small color-info" /> <Icon ariaLabel="Pinned" type="pin-filled" className="sn-icon--small color-info" />
</span> </span>
)} )}
{hasFiles && (
<span title="Files">
<Icon ariaLabel="Files" type="attachment-file" className="sn-icon--small color-info" />
</span>
)}
</div> </div>
</div> </div>
) )

View File

@@ -25,7 +25,7 @@ export const AccountPreferences = observer(({ application, appState }: Props) =>
</> </>
)} )}
<Subscription application={application} appState={appState} /> <Subscription application={application} appState={appState} />
{application.hasAccount() && appState.features.isEntitledToFiles && <FilesSection application={application} />} {application.hasAccount() && appState.features.hasFiles && <FilesSection application={application} />}
<SignOutWrapper application={application} appState={appState} /> <SignOutWrapper application={application} appState={appState} />
</PreferencesPane> </PreferencesPane>
)) ))

View File

@@ -48,10 +48,10 @@ export const PremiumFeaturesModal: FunctionalComponent<Props> = ({
<div className="flex items-center justify-center p-1" aria-hidden={true}> <div className="flex items-center justify-center p-1" aria-hidden={true}>
<PremiumIllustration className="mb-2" /> <PremiumIllustration className="mb-2" />
</div> </div>
<div className="text-lg text-center font-bold mb-1">Enable Premium Features</div> <div className="text-lg text-center font-bold mb-1">Enable Advanced Features</div>
</AlertDialogLabel> </AlertDialogLabel>
<AlertDialogDescription className="text-sm text-center color-grey-1 px-4.5 mb-2"> <AlertDialogDescription className="text-sm text-center color-grey-1 px-4.5 mb-2">
In order to use <span className="font-semibold">{featureName}</span> and other premium features, please In order to use <span className="font-semibold">{featureName}</span> and other advanced features, please
purchase a subscription or upgrade your current plan. purchase a subscription or upgrade your current plan.
</AlertDialogDescription> </AlertDialogDescription>
<div className="p-4"> <div className="p-4">

View File

@@ -1,27 +1,23 @@
import { WebApplication } from '@/UIModels/Application' import { WebApplication } from '@/UIModels/Application'
import { isDev } from '@/Utils'
import { ApplicationEvent, FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs' import { ApplicationEvent, FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
import { action, computed, makeObservable, observable, runInAction, when } from 'mobx' import { action, makeObservable, observable, runInAction, when } from 'mobx'
export class FeaturesState { export class FeaturesState {
hasFolders: boolean hasFolders: boolean
hasSmartViews: boolean hasSmartViews: boolean
hasFilesBeta: boolean hasFiles: boolean
premiumAlertFeatureName: string | undefined premiumAlertFeatureName: string | undefined
constructor(private application: WebApplication, appObservers: (() => void)[]) { constructor(private application: WebApplication, appObservers: (() => void)[]) {
this.hasFolders = this.hasNativeFolders() this.hasFolders = this.isEntitledToFolders()
this.hasSmartViews = this.hasNativeSmartViews() this.hasSmartViews = this.isEntitledToSmartViews()
this.hasFilesBeta = this.isEntitledToFilesBeta() this.hasFiles = this.isEntitledToFiles()
this.premiumAlertFeatureName = undefined this.premiumAlertFeatureName = undefined
makeObservable(this, { makeObservable(this, {
hasFolders: observable, hasFolders: observable,
hasSmartViews: observable, hasSmartViews: observable,
hasFiles: observable,
hasFilesBeta: observable,
isFilesEnabled: computed,
isEntitledToFiles: computed,
premiumAlertFeatureName: observable, premiumAlertFeatureName: observable,
showPremiumAlert: action, showPremiumAlert: action,
@@ -37,9 +33,9 @@ export class FeaturesState {
case ApplicationEvent.FeaturesUpdated: case ApplicationEvent.FeaturesUpdated:
case ApplicationEvent.Launched: case ApplicationEvent.Launched:
runInAction(() => { runInAction(() => {
this.hasFolders = this.hasNativeFolders() this.hasFolders = this.isEntitledToFolders()
this.hasSmartViews = this.hasNativeSmartViews() this.hasSmartViews = this.isEntitledToSmartViews()
this.hasFilesBeta = this.isEntitledToFilesBeta() this.hasFiles = this.isEntitledToFiles()
}) })
} }
}), }),
@@ -55,32 +51,21 @@ export class FeaturesState {
this.premiumAlertFeatureName = undefined this.premiumAlertFeatureName = undefined
} }
get isFilesEnabled(): boolean { private isEntitledToFiles(): boolean {
return this.hasFilesBeta || window.enabledUnfinishedFeatures || isDev const status = this.application.features.getFeatureStatus(FeatureIdentifier.Files)
return status === FeatureStatus.Entitled
} }
get isEntitledToFiles(): boolean { private isEntitledToFolders(): boolean {
return this.hasFilesBeta
}
private hasNativeFolders(): boolean {
const status = this.application.features.getFeatureStatus(FeatureIdentifier.TagNesting) const status = this.application.features.getFeatureStatus(FeatureIdentifier.TagNesting)
return status === FeatureStatus.Entitled return status === FeatureStatus.Entitled
} }
private hasNativeSmartViews(): boolean { private isEntitledToSmartViews(): boolean {
const status = this.application.features.getFeatureStatus(FeatureIdentifier.SmartFilters) const status = this.application.features.getFeatureStatus(FeatureIdentifier.SmartFilters)
return status === FeatureStatus.Entitled return status === FeatureStatus.Entitled
} }
private isEntitledToFilesBeta(): boolean {
if (isDev && this.application.hasAccount()) {
return true
}
const status = this.application.features.getFeatureStatus(FeatureIdentifier.FilesBeta)
return status === FeatureStatus.Entitled
}
} }