chore: legacy fixes (#2343)

This commit is contained in:
Mo
2023-07-03 08:03:25 -05:00
committed by GitHub
parent 6d5cbcb396
commit d79e7b14b1
14 changed files with 148 additions and 95 deletions

View File

@@ -0,0 +1,43 @@
import { InternalFeature, InternalFeatureService } from '@standardnotes/snjs'
import { WebApplicationInterface } from '@standardnotes/ui-services'
export class DevMode {
constructor(private application: WebApplicationInterface) {
InternalFeatureService.get().enableFeature(InternalFeature.Vaults)
}
/** Valid only when running a mock event publisher on port 3124 */
async purchaseMockSubscription() {
const subscriptionId = 2000
const email = this.application.getUser()?.email
const response = await fetch('http://localhost:3124/events', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
eventType: 'SUBSCRIPTION_PURCHASED',
eventPayload: {
userEmail: email,
subscriptionId: subscriptionId,
subscriptionName: 'PRO_PLAN',
subscriptionExpiresAt: (new Date().getTime() + 3_600_000) * 1_000,
timestamp: Date.now(),
offline: false,
discountCode: null,
limitedDiscountPurchased: false,
newSubscriber: true,
totalActiveSubscriptionsCount: 1,
userRegisteredAt: 1,
billingFrequency: 12,
payAmount: 59.0,
},
}),
})
if (!response.ok) {
console.error(`Failed to publish mocked event: ${response.status} ${response.statusText}`)
}
}
}

View File

@@ -51,18 +51,21 @@ import { FeatureName } from '@/Controllers/FeatureName'
import { ItemGroupController } from '@/Components/NoteView/Controller/ItemGroupController'
import { VisibilityObserver } from './VisibilityObserver'
import { MomentsService } from '@/Controllers/Moments/MomentsService'
import { purchaseMockSubscription } from '@/Utils/Dev/PurchaseMockSubscription'
import { DevMode } from './DevMode'
export type WebEventObserver = (event: WebAppEvent, data?: unknown) => void
export class WebApplication extends SNApplication implements WebApplicationInterface {
private webServices!: WebServices
private webEventObservers: WebEventObserver[] = []
public itemControllerGroup: ItemGroupController
private mobileWebReceiver?: MobileWebReceiver
private androidBackHandler?: AndroidBackHandler
public readonly itemControllerGroup: ItemGroupController
public readonly routeService: RouteServiceInterface
private visibilityObserver?: VisibilityObserver
private readonly webServices!: WebServices
private readonly webEventObservers: WebEventObserver[] = []
private readonly mobileWebReceiver?: MobileWebReceiver
private readonly androidBackHandler?: AndroidBackHandler
private readonly visibilityObserver?: VisibilityObserver
public readonly devMode?: DevMode
constructor(
deviceInterface: WebOrDesktopDevice,
@@ -91,6 +94,10 @@ export class WebApplication extends SNApplication implements WebApplicationInter
u2fAuthenticatorVerificationPromptFunction: startAuthentication,
})
if (isDev) {
this.devMode = new DevMode(this)
}
makeObservable(this, {
dealloced: observable,
})
@@ -152,7 +159,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
;(service as { application?: WebApplication }).application = undefined
}
this.webServices = {} as WebServices
;(this.webServices as unknown) = undefined
this.itemControllerGroup.deinit()
;(this.itemControllerGroup as unknown) = undefined
@@ -165,7 +172,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
if (this.visibilityObserver) {
this.visibilityObserver.deinit()
this.visibilityObserver = undefined
;(this.visibilityObserver as unknown) = undefined
}
} catch (error) {
console.error('Error while deiniting application', error)
@@ -458,12 +465,4 @@ export class WebApplication extends SNApplication implements WebApplicationInter
generateUUID(): string {
return this.options.crypto.generateUUID()
}
dev__purchaseMockSubscription() {
if (!isDev) {
throw new Error('This method is only available in dev mode')
}
void purchaseMockSubscription(this.getUser()?.email as string, 2000)
}
}

View File

@@ -9,7 +9,7 @@ import PreferencesViewWrapper from '@/Components/Preferences/PreferencesViewWrap
import ChallengeModal from '@/Components/ChallengeModal/ChallengeModal'
import NotesContextMenu from '@/Components/NotesContextMenu/NotesContextMenu'
import PurchaseFlowWrapper from '@/Components/PurchaseFlow/PurchaseFlowWrapper'
import { FunctionComponent, useCallback, useEffect, useMemo, useState, lazy } from 'react'
import { FunctionComponent, useCallback, useEffect, useMemo, useState, lazy, useRef } from 'react'
import RevisionHistoryModal from '@/Components/RevisionHistoryModal/RevisionHistoryModal'
import PremiumModalProvider from '@/Hooks/usePremiumModal'
import ConfirmSignoutContainer from '@/Components/ConfirmSignoutModal/ConfirmSignoutModal'
@@ -44,6 +44,9 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
const [needsUnlock, setNeedsUnlock] = useState(true)
const [challenges, setChallenges] = useState<Challenge[]>([])
const currentWriteErrorDialog = useRef<Promise<void> | null>(null)
const currentLoadErrorDialog = useRef<Promise<void> | null>(null)
const viewControllerManager = application.getViewControllerManager()
useEffect(() => {
@@ -120,13 +123,25 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
} else if (eventName === ApplicationEvent.Launched) {
onAppLaunch()
} else if (eventName === ApplicationEvent.LocalDatabaseReadError) {
alertDialog({
text: 'Unable to load local database. Please restart the app and try again.',
}).catch(console.error)
if (!currentLoadErrorDialog.current) {
alertDialog({
text: 'Unable to load local database. Please restart the app and try again.',
})
.then(() => {
currentLoadErrorDialog.current = null
})
.catch(console.error)
}
} else if (eventName === ApplicationEvent.LocalDatabaseWriteError) {
alertDialog({
text: 'Unable to write to local database. Please restart the app and try again.',
}).catch(console.error)
if (!currentWriteErrorDialog.current) {
currentWriteErrorDialog.current = alertDialog({
text: 'Unable to write to local database. Please restart the app and try again.',
})
.then(() => {
currentWriteErrorDialog.current = null
})
.catch(console.error)
}
} else if (eventName === ApplicationEvent.BiometricsSoftLockEngaged) {
setNeedsUnlock(true)
} else if (eventName === ApplicationEvent.BiometricsSoftLockDisengaged) {

View File

@@ -45,17 +45,17 @@ const READY_PREFERENCES_MENU_ITEMS: PreferencesMenuItem[] = [
{ id: 'help-feedback', label: 'Help & feedback', icon: 'help' },
]
if (featureTrunkVaultsEnabled()) {
PREFERENCES_MENU_ITEMS.splice(3, 0, { id: 'vaults', label: 'Vaults', icon: 'safe-square' })
READY_PREFERENCES_MENU_ITEMS.splice(3, 0, { id: 'vaults', label: 'Vaults', icon: 'safe-square' })
}
export class PreferencesMenu {
private _selectedPane: PreferenceId = 'account'
private _menu: PreferencesMenuItem[]
private _extensionLatestVersions: PackageProvider = new PackageProvider(new Map())
constructor(private application: WebApplication, private readonly _enableUnfinishedFeatures: boolean) {
if (featureTrunkVaultsEnabled()) {
PREFERENCES_MENU_ITEMS.splice(3, 0, { id: 'vaults', label: 'Vaults', icon: 'safe-square' })
READY_PREFERENCES_MENU_ITEMS.splice(3, 0, { id: 'vaults', label: 'Vaults', icon: 'safe-square' })
}
this._menu = this._enableUnfinishedFeatures ? PREFERENCES_MENU_ITEMS : READY_PREFERENCES_MENU_ITEMS
this.loadLatestVersions()

View File

@@ -62,12 +62,12 @@ describe('LinkingController', () => {
alerts: {} as jest.Mocked<WebApplication['alerts']>,
sync: {} as jest.Mocked<WebApplication['sync']>,
mutator: {} as jest.Mocked<WebApplication['mutator']>,
itemControllerGroup: {} as jest.Mocked<WebApplication['itemControllerGroup']>,
} as unknown as jest.Mocked<WebApplication>
application.getPreference = jest.fn()
application.addSingleEventObserver = jest.fn()
application.streamItems = jest.fn()
application.itemControllerGroup = {} as jest.Mocked<WebApplication['itemControllerGroup']>
application.sync.sync = jest.fn()
Object.defineProperty(application, 'items', { value: {} as jest.Mocked<ItemManagerInterface> })

View File

@@ -197,11 +197,13 @@ export class LinkingController extends AbstractViewController {
const linkNoteAndFile = async (note: SNNote, file: FileItem) => {
const updatedFile = await this.application.mutator.associateFileWithNote(file, note)
if (updatedFile && featureTrunkVaultsEnabled()) {
const noteVault = this.application.vaults.getItemVault(note)
const fileVault = this.application.vaults.getItemVault(updatedFile)
if (noteVault && !fileVault) {
await this.application.vaults.moveItemToVault(noteVault, file)
if (featureTrunkVaultsEnabled()) {
if (updatedFile) {
const noteVault = this.application.vaults.getItemVault(note)
const fileVault = this.application.vaults.getItemVault(updatedFile)
if (noteVault && !fileVault) {
await this.application.vaults.moveItemToVault(noteVault, file)
}
}
}
}

View File

@@ -1,32 +0,0 @@
/** Valid only when running a mock event publisher on port 3124 */
export async function purchaseMockSubscription(email: string, subscriptionId: number) {
const response = await fetch('http://localhost:3124/events', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
eventType: 'SUBSCRIPTION_PURCHASED',
eventPayload: {
userEmail: email,
subscriptionId: subscriptionId,
subscriptionName: 'PRO_PLAN',
subscriptionExpiresAt: (new Date().getTime() + 3_600_000) * 1_000,
timestamp: Date.now(),
offline: false,
discountCode: null,
limitedDiscountPurchased: false,
newSubscriber: true,
totalActiveSubscriptionsCount: 1,
userRegisteredAt: 1,
billingFrequency: 12,
payAmount: 59.0,
},
}),
})
if (!response.ok) {
console.error(`Failed to publish mocked event: ${response.status} ${response.statusText}`)
}
}