fix: show files option in linking menu even if not entitled
This commit is contained in:
@@ -39,6 +39,7 @@ import { AndroidBackHandler } from '@/NativeMobileWeb/AndroidBackHandler'
|
||||
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||
import { setCustomViewportHeight } from '@/setViewportHeightWithFallback'
|
||||
import { WebServices } from './WebServices'
|
||||
import { FeatureName } from '@/Controllers/FeatureName'
|
||||
|
||||
export type WebEventObserver = (event: WebAppEvent, data?: unknown) => void
|
||||
|
||||
@@ -347,6 +348,14 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
return this.hasValidSubscription()
|
||||
}
|
||||
|
||||
get entitledToFiles(): boolean {
|
||||
return this.getViewControllerManager().featuresController.entitledToFiles
|
||||
}
|
||||
|
||||
showPremiumModal(featureName: FeatureName): void {
|
||||
void this.getViewControllerManager().featuresController.showPremiumAlert(featureName)
|
||||
}
|
||||
|
||||
hasValidSubscription(): boolean {
|
||||
return this.getViewControllerManager().subscriptionController.hasValidSubscription()
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { useFileDragNDrop } from '../FileDragNDropProvider/FileDragNDropProvider
|
||||
import { LinkingController } from '@/Controllers/LinkingController'
|
||||
import DailyContentList from './Daily/DailyContentList'
|
||||
import { ListableContentItem } from './Types/ListableContentItem'
|
||||
import { FeatureName } from '@/Controllers/FeatureName'
|
||||
|
||||
type Props = {
|
||||
accountMenuController: AccountMenuController
|
||||
@@ -123,6 +124,11 @@ const ContentListView: FunctionComponent<Props> = ({
|
||||
|
||||
const addNewItem = useCallback(async () => {
|
||||
if (isFilesSmartView) {
|
||||
if (!application.entitledToFiles) {
|
||||
application.showPremiumModal(FeatureName.Files)
|
||||
return
|
||||
}
|
||||
|
||||
if (StreamingFileReader.available()) {
|
||||
void filesController.uploadNewFile()
|
||||
return
|
||||
@@ -133,7 +139,7 @@ const ContentListView: FunctionComponent<Props> = ({
|
||||
await createNewNote()
|
||||
toggleAppPane(AppPaneId.Editor)
|
||||
}
|
||||
}, [isFilesSmartView, filesController, createNewNote, toggleAppPane])
|
||||
}, [isFilesSmartView, filesController, createNewNote, toggleAppPane, application])
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
|
||||
@@ -153,7 +153,7 @@ const ContentListHeader = ({
|
||||
}, [OptionsMenu, AddButton, FolderName])
|
||||
|
||||
return (
|
||||
<div className="section-title-bar-header items-start gap-1 overflow-hidden">
|
||||
<div className="section-title-bar-header items-start gap-1">
|
||||
{!isTablet && PhoneAndDesktopLayout}
|
||||
{isTablet && TabletLayout}
|
||||
</div>
|
||||
|
||||
@@ -188,7 +188,7 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
|
||||
|
||||
resetState()
|
||||
|
||||
if (!featuresController.hasFiles) {
|
||||
if (!featuresController.entitledToFiles) {
|
||||
premiumModal.activate('Files')
|
||||
return
|
||||
}
|
||||
@@ -217,7 +217,7 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
|
||||
dragCounter.current = 0
|
||||
}
|
||||
},
|
||||
[application, featuresController.hasFiles, filesController, premiumModal, resetState],
|
||||
[application, featuresController.entitledToFiles, filesController, premiumModal, resetState],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,156 +1,17 @@
|
||||
import { FeatureName } from '@/Controllers/FeatureName'
|
||||
import { FeaturesController } from '@/Controllers/FeaturesController'
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import { LinkingController } from '@/Controllers/LinkingController'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import { formatDateForContextMenu } from '@/Utils/DateUtils'
|
||||
import { getIconForItem } from '@/Utils/Items/Icons/getIconForItem'
|
||||
import { getLinkingSearchResults } from '@/Utils/Items/Search/getSearchResults'
|
||||
import { LinkableItem } from '@/Utils/Items/Search/LinkableItem'
|
||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||
import { FileItem } from '@standardnotes/snjs'
|
||||
import { KeyboardKey } from '@standardnotes/ui-services'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { ChangeEventHandler, useEffect, useRef, useState } from 'react'
|
||||
import { useApplication } from '../ApplicationView/ApplicationProvider'
|
||||
import { PopoverFileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction'
|
||||
import ClearInputButton from '../ClearInputButton/ClearInputButton'
|
||||
import Icon from '../Icon/Icon'
|
||||
import DecoratedInput from '../Input/DecoratedInput'
|
||||
import MenuItem from '../Menu/MenuItem'
|
||||
import { MenuItemType } from '../Menu/MenuItemType'
|
||||
import Popover from '../Popover/Popover'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import LinkedFileMenuOptions from './LinkedFileMenuOptions'
|
||||
import LinkedItemMeta from './LinkedItemMeta'
|
||||
import LinkedItemSearchResults from './LinkedItemSearchResults'
|
||||
|
||||
const LinkedItemsSectionItem = ({
|
||||
activateItem,
|
||||
item,
|
||||
searchQuery,
|
||||
unlinkItem,
|
||||
handleFileAction,
|
||||
}: {
|
||||
activateItem: LinkingController['activateItem']
|
||||
item: LinkableItem
|
||||
searchQuery?: string
|
||||
unlinkItem: () => void
|
||||
handleFileAction: FilesController['handleFileAction']
|
||||
}) => {
|
||||
const menuButtonRef = useRef<HTMLButtonElement>(null)
|
||||
const application = useApplication()
|
||||
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||
const toggleMenu = () => setIsMenuOpen((open) => !open)
|
||||
|
||||
const [isRenamingFile, setIsRenamingFile] = useState(false)
|
||||
|
||||
const [icon, className] = getIconForItem(item, application)
|
||||
const title = item.title ?? ''
|
||||
|
||||
const renameFile = async (name: string) => {
|
||||
if (!(item instanceof FileItem)) {
|
||||
return
|
||||
}
|
||||
await handleFileAction({
|
||||
type: PopoverFileItemActionType.RenameFile,
|
||||
payload: {
|
||||
file: item,
|
||||
name: name,
|
||||
},
|
||||
})
|
||||
setIsRenamingFile(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center justify-between">
|
||||
{isRenamingFile && item instanceof FileItem ? (
|
||||
<div className="flex flex-grow items-center gap-4 py-2 pl-3 pr-12">
|
||||
<Icon type={icon} className={classNames('flex-shrink-0', className)} />
|
||||
<input
|
||||
className="min-w-0 flex-grow text-sm"
|
||||
defaultValue={title}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === KeyboardKey.Escape) {
|
||||
setIsRenamingFile(false)
|
||||
} else if (event.key === KeyboardKey.Enter) {
|
||||
const newTitle = event.currentTarget.value
|
||||
void renameFile(newTitle)
|
||||
}
|
||||
}}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
node.focus()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className="flex max-w-full flex-grow items-center justify-between gap-4 py-2 pl-3 pr-12 text-sm hover:bg-info-backdrop focus:bg-info-backdrop"
|
||||
onClick={() => activateItem(item)}
|
||||
onContextMenu={(event) => {
|
||||
event.preventDefault()
|
||||
toggleMenu()
|
||||
}}
|
||||
>
|
||||
<LinkedItemMeta item={item} searchQuery={searchQuery} />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="absolute right-3 top-1/2 h-7 w-7 -translate-y-1/2 cursor-pointer rounded-full border-0 bg-transparent p-1 hover:bg-contrast"
|
||||
onClick={toggleMenu}
|
||||
ref={menuButtonRef}
|
||||
>
|
||||
<Icon type="more" className="text-neutral" />
|
||||
</button>
|
||||
<Popover
|
||||
open={isMenuOpen}
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={menuButtonRef.current}
|
||||
side="bottom"
|
||||
align="center"
|
||||
className="py-2"
|
||||
>
|
||||
<MenuItem
|
||||
type={MenuItemType.IconButton}
|
||||
onClick={() => {
|
||||
unlinkItem()
|
||||
toggleMenu()
|
||||
}}
|
||||
>
|
||||
<Icon type="link-off" className="mr-2 text-danger" />
|
||||
Unlink
|
||||
</MenuItem>
|
||||
{item instanceof FileItem && (
|
||||
<LinkedFileMenuOptions
|
||||
file={item}
|
||||
closeMenu={toggleMenu}
|
||||
handleFileAction={handleFileAction}
|
||||
setIsRenamingFile={setIsRenamingFile}
|
||||
/>
|
||||
)}
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
<div className="mt-1 px-3 py-1 text-xs font-medium text-neutral">
|
||||
<div className="mb-1">
|
||||
<span className="font-semibold">Created at:</span> {formatDateForContextMenu(item.created_at)}
|
||||
</div>
|
||||
<div className="mb-1">
|
||||
<span className="font-semibold">Modified at:</span> {formatDateForContextMenu(item.userModifiedDate)}
|
||||
</div>
|
||||
<div className="mb-1">
|
||||
<span className="font-semibold">ID:</span> {item.uuid}
|
||||
</div>
|
||||
{item instanceof FileItem && (
|
||||
<div>
|
||||
<span className="font-semibold">Size:</span> {formatSizeToReadableString(item.decryptedSize)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import { LinkedItemsSectionItem } from './LinkedItemsSectionItem'
|
||||
|
||||
const LinkedItemsPanel = ({
|
||||
linkingController,
|
||||
@@ -178,7 +39,7 @@ const LinkedItemsPanel = ({
|
||||
activeItem,
|
||||
} = linkingController
|
||||
|
||||
const { hasFiles } = featuresController
|
||||
const { entitledToFiles } = featuresController
|
||||
const application = useApplication()
|
||||
|
||||
const fileInputRef = useRef<HTMLInputElement | null>(null)
|
||||
@@ -214,6 +75,11 @@ const LinkedItemsPanel = ({
|
||||
}
|
||||
|
||||
const selectAndUploadFiles = () => {
|
||||
if (!entitledToFiles) {
|
||||
void featuresController.showPremiumAlert(FeatureName.Files)
|
||||
return
|
||||
}
|
||||
|
||||
if (!fileInputRef.current) {
|
||||
return
|
||||
}
|
||||
@@ -307,37 +173,37 @@ const LinkedItemsPanel = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(!!linkedFiles.length || hasFiles) && (
|
||||
<div>
|
||||
<div className="mt-3 mb-1 px-3 text-menu-item font-semibold uppercase text-passive-0">Linked Files</div>
|
||||
<div className="my-1">
|
||||
<input
|
||||
type="file"
|
||||
className="absolute top-0 left-0 -z-50 h-px w-px opacity-0"
|
||||
multiple
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileInputChange}
|
||||
|
||||
<div>
|
||||
<div className="mt-3 mb-1 px-3 text-menu-item font-semibold uppercase text-passive-0">Linked Files</div>
|
||||
<div className="my-1">
|
||||
<input
|
||||
type="file"
|
||||
className="absolute top-0 left-0 -z-50 h-px w-px opacity-0"
|
||||
multiple
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileInputChange}
|
||||
/>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center gap-3 bg-transparent px-3 py-2 text-left text-base text-text hover:bg-info-backdrop hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
|
||||
onClick={selectAndUploadFiles}
|
||||
>
|
||||
<Icon type="add" />
|
||||
Upload and link file(s)
|
||||
</button>
|
||||
{linkedFiles.map((link) => (
|
||||
<LinkedItemsSectionItem
|
||||
key={link.id}
|
||||
item={link.item}
|
||||
searchQuery={searchQuery}
|
||||
unlinkItem={() => unlinkItemFromSelectedItem(link.item)}
|
||||
activateItem={activateItem}
|
||||
handleFileAction={filesController.handleFileAction}
|
||||
/>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center gap-3 bg-transparent px-3 py-2 text-left text-base text-text hover:bg-info-backdrop hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
|
||||
onClick={selectAndUploadFiles}
|
||||
>
|
||||
<Icon type="add" />
|
||||
Upload and link file(s)
|
||||
</button>
|
||||
{linkedFiles.map((link) => (
|
||||
<LinkedItemsSectionItem
|
||||
key={link.id}
|
||||
item={link.item}
|
||||
searchQuery={searchQuery}
|
||||
unlinkItem={() => unlinkItemFromSelectedItem(link.item)}
|
||||
activateItem={activateItem}
|
||||
handleFileAction={filesController.handleFileAction}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!!filesLinkingToActiveItem.length && (
|
||||
<div>
|
||||
<div className="mt-3 mb-1 px-3 text-menu-item font-semibold uppercase text-passive-0">
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import { FilesController } from '@/Controllers/FilesController'
|
||||
import { LinkingController } from '@/Controllers/LinkingController'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import { formatDateForContextMenu } from '@/Utils/DateUtils'
|
||||
import { getIconForItem } from '@/Utils/Items/Icons/getIconForItem'
|
||||
import { LinkableItem } from '@/Utils/Items/Search/LinkableItem'
|
||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||
import { FileItem } from '@standardnotes/snjs'
|
||||
import { KeyboardKey } from '@standardnotes/ui-services'
|
||||
import { useRef, useState } from 'react'
|
||||
import { useApplication } from '../ApplicationView/ApplicationProvider'
|
||||
import { PopoverFileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction'
|
||||
import Icon from '../Icon/Icon'
|
||||
import MenuItem from '../Menu/MenuItem'
|
||||
import { MenuItemType } from '../Menu/MenuItemType'
|
||||
import Popover from '../Popover/Popover'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import LinkedFileMenuOptions from './LinkedFileMenuOptions'
|
||||
import LinkedItemMeta from './LinkedItemMeta'
|
||||
|
||||
export const LinkedItemsSectionItem = ({
|
||||
activateItem,
|
||||
item,
|
||||
searchQuery,
|
||||
unlinkItem,
|
||||
handleFileAction,
|
||||
}: {
|
||||
activateItem: LinkingController['activateItem']
|
||||
item: LinkableItem
|
||||
searchQuery?: string
|
||||
unlinkItem: () => void
|
||||
handleFileAction: FilesController['handleFileAction']
|
||||
}) => {
|
||||
const menuButtonRef = useRef<HTMLButtonElement>(null)
|
||||
const application = useApplication()
|
||||
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||
const toggleMenu = () => setIsMenuOpen((open) => !open)
|
||||
|
||||
const [isRenamingFile, setIsRenamingFile] = useState(false)
|
||||
|
||||
const [icon, className] = getIconForItem(item, application)
|
||||
const title = item.title ?? ''
|
||||
|
||||
const renameFile = async (name: string) => {
|
||||
if (!(item instanceof FileItem)) {
|
||||
return
|
||||
}
|
||||
await handleFileAction({
|
||||
type: PopoverFileItemActionType.RenameFile,
|
||||
payload: {
|
||||
file: item,
|
||||
name: name,
|
||||
},
|
||||
})
|
||||
setIsRenamingFile(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center justify-between">
|
||||
{isRenamingFile && item instanceof FileItem ? (
|
||||
<div className="flex flex-grow items-center gap-4 py-2 pl-3 pr-12">
|
||||
<Icon type={icon} className={classNames('flex-shrink-0', className)} />
|
||||
<input
|
||||
className="min-w-0 flex-grow text-sm"
|
||||
defaultValue={title}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === KeyboardKey.Escape) {
|
||||
setIsRenamingFile(false)
|
||||
} else if (event.key === KeyboardKey.Enter) {
|
||||
const newTitle = event.currentTarget.value
|
||||
void renameFile(newTitle)
|
||||
}
|
||||
}}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
node.focus()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className="flex max-w-full flex-grow items-center justify-between gap-4 py-2 pl-3 pr-12 text-sm hover:bg-info-backdrop focus:bg-info-backdrop"
|
||||
onClick={() => activateItem(item)}
|
||||
onContextMenu={(event) => {
|
||||
event.preventDefault()
|
||||
toggleMenu()
|
||||
}}
|
||||
>
|
||||
<LinkedItemMeta item={item} searchQuery={searchQuery} />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="absolute right-3 top-1/2 h-7 w-7 -translate-y-1/2 cursor-pointer rounded-full border-0 bg-transparent p-1 hover:bg-contrast"
|
||||
onClick={toggleMenu}
|
||||
ref={menuButtonRef}
|
||||
>
|
||||
<Icon type="more" className="text-neutral" />
|
||||
</button>
|
||||
<Popover
|
||||
open={isMenuOpen}
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={menuButtonRef.current}
|
||||
side="bottom"
|
||||
align="center"
|
||||
className="py-2"
|
||||
>
|
||||
<MenuItem
|
||||
type={MenuItemType.IconButton}
|
||||
onClick={() => {
|
||||
unlinkItem()
|
||||
toggleMenu()
|
||||
}}
|
||||
>
|
||||
<Icon type="link-off" className="mr-2 text-danger" />
|
||||
Unlink
|
||||
</MenuItem>
|
||||
{item instanceof FileItem && (
|
||||
<LinkedFileMenuOptions
|
||||
file={item}
|
||||
closeMenu={toggleMenu}
|
||||
handleFileAction={handleFileAction}
|
||||
setIsRenamingFile={setIsRenamingFile}
|
||||
/>
|
||||
)}
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
<div className="mt-1 px-3 py-1 text-xs font-medium text-neutral">
|
||||
<div className="mb-1">
|
||||
<span className="font-semibold">Created at:</span> {formatDateForContextMenu(item.created_at)}
|
||||
</div>
|
||||
<div className="mb-1">
|
||||
<span className="font-semibold">Modified at:</span> {formatDateForContextMenu(item.userModifiedDate)}
|
||||
</div>
|
||||
<div className="mb-1">
|
||||
<span className="font-semibold">ID:</span> {item.uuid}
|
||||
</div>
|
||||
{item instanceof FileItem && (
|
||||
<div>
|
||||
<span className="font-semibold">Size:</span> {formatSizeToReadableString(item.decryptedSize)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -29,7 +29,7 @@ const AccountPreferences = ({ application, viewControllerManager }: Props) => (
|
||||
)}
|
||||
<Subscription application={application} viewControllerManager={viewControllerManager} />
|
||||
<SubscriptionSharing application={application} viewControllerManager={viewControllerManager} />
|
||||
{application.hasAccount() && viewControllerManager.featuresController.hasFiles && (
|
||||
{application.hasAccount() && viewControllerManager.featuresController.entitledToFiles && (
|
||||
<FilesSection application={application} />
|
||||
)}
|
||||
{application.hasAccount() && <Email application={application} />}
|
||||
|
||||
@@ -5,10 +5,11 @@ import { WebApplication } from '@/Application/Application'
|
||||
import { openSubscriptionDashboard } from '@/Utils/ManageSubscription'
|
||||
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
|
||||
import { PremiumFeatureModalType } from './PremiumFeatureModalType'
|
||||
import { FeatureName } from '@/Controllers/FeatureName'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
featureName: string
|
||||
featureName: FeatureName | string
|
||||
hasSubscription: boolean
|
||||
hasAccount: boolean
|
||||
onClose: () => void
|
||||
|
||||
3
packages/web/src/javascripts/Controllers/FeatureName.ts
Normal file
3
packages/web/src/javascripts/Controllers/FeatureName.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export enum FeatureName {
|
||||
Files = 'Encrypted File Storage',
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FeatureName } from './FeatureName'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { PremiumFeatureModalType } from '@/Components/PremiumFeaturesModal/PremiumFeatureModalType'
|
||||
import { destroyAllObjectProperties } from '@/Utils'
|
||||
@@ -15,7 +16,7 @@ import { CrossControllerEvent } from './CrossControllerEvent'
|
||||
export class FeaturesController extends AbstractViewController {
|
||||
hasFolders: boolean
|
||||
hasSmartViews: boolean
|
||||
hasFiles: boolean
|
||||
entitledToFiles: boolean
|
||||
premiumAlertFeatureName: string | undefined
|
||||
premiumAlertType: PremiumFeatureModalType | undefined = undefined
|
||||
|
||||
@@ -25,7 +26,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
;(this.closePremiumAlert as unknown) = undefined
|
||||
;(this.hasFolders as unknown) = undefined
|
||||
;(this.hasSmartViews as unknown) = undefined
|
||||
;(this.hasFiles as unknown) = undefined
|
||||
;(this.entitledToFiles as unknown) = undefined
|
||||
;(this.premiumAlertFeatureName as unknown) = undefined
|
||||
;(this.premiumAlertType as unknown) = undefined
|
||||
|
||||
@@ -37,7 +38,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
|
||||
this.hasFolders = this.isEntitledToFolders()
|
||||
this.hasSmartViews = this.isEntitledToSmartViews()
|
||||
this.hasFiles = this.isEntitledToFiles()
|
||||
this.entitledToFiles = this.isEntitledToFiles()
|
||||
this.premiumAlertFeatureName = undefined
|
||||
|
||||
eventBus.addEventHandler(this, CrossControllerEvent.DisplayPremiumModal)
|
||||
@@ -45,7 +46,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
makeObservable(this, {
|
||||
hasFolders: observable,
|
||||
hasSmartViews: observable,
|
||||
hasFiles: observable,
|
||||
entitledToFiles: observable,
|
||||
premiumAlertType: observable,
|
||||
premiumAlertFeatureName: observable,
|
||||
showPremiumAlert: action,
|
||||
@@ -67,7 +68,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
runInAction(() => {
|
||||
this.hasFolders = this.isEntitledToFolders()
|
||||
this.hasSmartViews = this.isEntitledToSmartViews()
|
||||
this.hasFiles = this.isEntitledToFiles()
|
||||
this.entitledToFiles = this.isEntitledToFiles()
|
||||
})
|
||||
}
|
||||
}),
|
||||
@@ -81,7 +82,7 @@ export class FeaturesController extends AbstractViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public async showPremiumAlert(featureName: string): Promise<void> {
|
||||
public async showPremiumAlert(featureName: FeatureName | string): Promise<void> {
|
||||
this.premiumAlertFeatureName = featureName
|
||||
this.premiumAlertType = PremiumFeatureModalType.UpgradePrompt
|
||||
|
||||
|
||||
Reference in New Issue
Block a user