Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class NativeFeatureIdentifier extends ValueObject<NativeFeatureIdentifier

Clipper: 'org.standardnotes.clipper',

Vaults: 'org.standardnotes.vaults',
SharedVaults: 'org.standardnotes.shared-vaults',

DeprecatedMarkdownVisualEditor: 'org.standardnotes.markdown-visual-editor',
Expand Down Expand Up @@ -74,4 +75,4 @@ export class NativeFeatureIdentifier extends ValueObject<NativeFeatureIdentifier
/**
* Identifier for standalone filesafe instance offered as legacy installable via extensions-server
*/
export const ExperimentalFeatures = []
export const ExperimentalFeatures = [NativeFeatureIdentifier.TYPES.Vaults]
13 changes: 12 additions & 1 deletion packages/features/src/Domain/Lists/ExperimentalFeatures.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { RoleName } from '@standardnotes/domain-core'
import { AnyFeatureDescription } from '../Feature/AnyFeatureDescription'
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
import { PermissionName } from '../Permission/PermissionName'

export function experimentalFeatures(): AnyFeatureDescription[] {
return []
return [
{
name: 'Private vaults',
description: 'Private vaults allow you to store notes, files and tags into separate, encrypted vaults.',
availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
identifier: NativeFeatureIdentifier.TYPES.Vaults,
permission_name: PermissionName.Vaults,
},
]
}
1 change: 1 addition & 0 deletions packages/features/src/Domain/Permission/PermissionName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ export enum PermissionName {
SubscriptionSharing = 'server:subscription-sharing',
SuperEditor = 'editor:super-editor',
Clipper = 'app:clipper',
Vaults = 'app:vaults',
SharedVaults = 'server:shared-vaults',
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
) : null}
</>
)}
{application.featuresController.isEntitledToVaults() && (
{application.featuresController.isVaultsEnabled() && (
<AddToVaultMenuOption
iconClassName={iconClass}
items={selectedFiles}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const VaultSelectionButton = ({ isMobileNavigation = false }: { isMobileNavigati
const [isOpen, setIsOpen] = useState(false)
const toggleMenu = () => setIsOpen(!isOpen)

if (!application.featuresController.isEntitledToVaults()) {
if (!application.featuresController.isVaultsEnabled()) {
return null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => {
)}
<HorizontalSeparator classes="my-2" />

{application.featuresController.isEntitledToVaults() && (
{application.featuresController.isVaultsEnabled() && (
<AddToVaultMenuOption iconClassName={iconClass} items={notes} disabled={!hasAdminPermissionForAllSharedNotes} />
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class PasswordWizard extends AbstractComponent<Props, State> {
continueTitle: DEFAULT_CONTINUE_TITLE,
}

if (props.application.featuresController.isEntitledToVaults()) {
if (props.application.featuresController.isVaultsEnabled()) {
this.state = {
...baseState,
lockContinue: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class PreferencesSessionController {
? PREFERENCES_MENU_ITEMS.slice()
: READY_PREFERENCES_MENU_ITEMS.slice()

if (application.featuresController.isEntitledToVaults()) {
if (application.featuresController.isVaultsEnabled()) {
menuItems.push({ id: 'vaults', label: 'Vaults', icon: 'safe-square', order: 5 })
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const Vaults = observer(() => {
const application = useApplication()

const hasAccount = application.hasAccount()
const isSharedVaultsEnabled = application.featuresController.isEntitledToSharedVaults()

const [vaults, setVaults] = useState<VaultListingInterface[]>([])
const [canCreateMoreVaults, setCanCreateMoreVaults] = useState(true)
Expand Down Expand Up @@ -163,7 +164,7 @@ const Vaults = observer(() => {
</PreferencesSegment>
</PreferencesGroup>
)}
{hasAccount && (
{hasAccount && isSharedVaultsEnabled && (
<PreferencesGroup>
<PreferencesSegment>
<Title>Contacts</Title>
Expand All @@ -180,7 +181,7 @@ const Vaults = observer(() => {
</PreferencesSegment>
</PreferencesGroup>
)}
{hasAccount && (
{hasAccount && isSharedVaultsEnabled && (
<PreferencesGroup>
<PreferencesSegment>
<Title>CollaborationID</Title>
Expand Down Expand Up @@ -235,13 +236,15 @@ const Vaults = observer(() => {
{canCreateMoreVaults ? (
<div className="mt-2.5 flex gap-3">
<Button label="Create Vault" onClick={createNewVault} />
{hasAccount && <Button label="Create Shared Vault" onClick={createNewSharedVault} />}
{hasAccount && isSharedVaultsEnabled && (
<Button label="Create Shared Vault" onClick={createNewSharedVault} />
)}
</div>
) : (
<div className="mt-3.5">
<NoProSubscription
application={application}
text={<span>Please upgrade in order to increase your shared vault limit.</span>}
text={<span>Please upgrade in order to increase your vault limit.</span>}
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type Props = {
const VaultItem = ({ vault }: Props) => {
const application = useApplication()

const canEnableCollaboration = application.hasAccount() && application.featuresController.isEntitledToSharedVaults()

const [isInviteModalOpen, setIsAddContactModalOpen] = useState(false)
const closeInviteModal = () => setIsAddContactModalOpen(false)

Expand Down Expand Up @@ -128,7 +130,7 @@ const VaultItem = ({ vault }: Props) => {
{isCurrentUserAdmin ? (
vault.isSharedVaultListing() ? (
<Button colorStyle="info" label="Invite Contacts" onClick={openInviteModal} />
) : application.hasAccount() ? (
) : canEnableCollaboration ? (
<Button colorStyle="info" label="Enable Collaboration" onClick={convertToSharedVault} />
) : null
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const Navigation = forwardRef<HTMLDivElement, Props>(({ application, className,
)}
<PreferencesButton openPreferences={() => application.preferencesController.openPreferences()} />
<QuickSettingsButton application={application} isMobileNavigation />
{application.featuresController.isEntitledToVaults() && <VaultSelectionButton isMobileNavigation />}
{application.featuresController.isVaultsEnabled() && <VaultSelectionButton isMobileNavigation />}
</div>
{children}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
iconGridClassName="max-h-30"
/>
<HorizontalSeparator classes="my-2" />
{application.featuresController.isEntitledToVaults() && (
{application.featuresController.isVaultsEnabled() && (
<AddToVaultMenuOption iconClassName="mr-2 text-neutral" items={[selectedTag]} />
)}
<MenuItem className={'justify-between py-1.5'} onClick={onClickStar}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const AddToVaultMenuOption = ({
setIsSubMenuOpen((isOpen) => !isOpen)
}, [])

if (!application.featuresController.isEntitledToVaults()) {
if (!application.featuresController.isVaultsEnabled()) {
return null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ export class FeaturesController extends AbstractViewController implements Intern
return status === FeatureStatus.Entitled
}

isEntitledToVaults(): boolean {
isVaultsEnabled(): boolean {
const enabled = this.features.isExperimentalFeatureEnabled(NativeFeatureIdentifier.TYPES.Vaults)
return featureTrunkVaultsEnabled() || enabled
}

isEntitledToSharedVaults(): boolean {
const status = this.features.getFeatureStatus(
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SharedVaults).getValue(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ describe('LinkingController', () => {
application.getPreference = jest.fn()
application.addSingleEventObserver = jest.fn()
application.sync.sync = jest.fn()
application.featuresController.isEntitledToVaults = jest.fn().mockReturnValue(true)
application.featuresController.isVaultsEnabled = jest.fn().mockReturnValue(true)
application.featuresController.isEntitledToSharedVaults = jest.fn().mockReturnValue(true)

Object.defineProperty(application, 'items', { value: {} as jest.Mocked<ItemManagerInterface> })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export class LinkingController extends AbstractViewController implements Interna
const linkNoteAndFile = async (note: SNNote, file: FileItem) => {
const updatedFile = await this.mutator.associateFileWithNote(file, note)

if (this.featuresController.isEntitledToVaults()) {
if (this.featuresController.isVaultsEnabled()) {
if (updatedFile) {
const noteVault = this.vaults.getItemVault(note)
const fileVault = this.vaults.getItemVault(updatedFile)
Expand Down
3 changes: 2 additions & 1 deletion packages/web/src/javascripts/FeatureTrunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export function featureTrunkEnabled(trunk: FeatureTrunkName): boolean {
}

export function featureTrunkVaultsEnabled(): boolean {
return InternalFeatureService.get().isFeatureEnabled(InternalFeature.Vaults)
// return InternalFeatureService.get().isFeatureEnabled(InternalFeature.Vaults)
return false
}

export function featureTrunkHomeServerEnabled(): boolean {
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/javascripts/Hooks/useItemVaultInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const useItemVaultInfo = (item: DecryptedItemInterface): ItemVaultInfo =>
const [sharedByContact, setSharedByContact] = useState<TrustedContactInterface>()

const updateInfo = useCallback(() => {
if (!application.featuresController.isEntitledToVaults()) {
if (!application.featuresController.isVaultsEnabled()) {
return
}

Expand Down