feat: files related improvements
This commit is contained in:
@@ -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(() => {
|
||||||
|
|||||||
@@ -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()}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user