feat(web): extract ui-services package
This commit is contained in:
@@ -19,9 +19,12 @@ import * as Settings from '@standardnotes/settings'
|
||||
import * as Files from '@standardnotes/files'
|
||||
import { Subscription } from '@standardnotes/security'
|
||||
import { UuidString, ApplicationEventPayload } from '../Types'
|
||||
import { ApplicationEvent, applicationEventForSyncEvent } from '@Lib/Application/Event'
|
||||
import { applicationEventForSyncEvent } from '@Lib/Application/Event'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
ApplicationEventCallback,
|
||||
ChallengeValidation,
|
||||
ComponentManagerInterface,
|
||||
DiagnosticInfo,
|
||||
Environment,
|
||||
isDesktopDevice,
|
||||
@@ -36,7 +39,7 @@ import {
|
||||
} from '@standardnotes/services'
|
||||
import { SNLog } from '../Log'
|
||||
import { useBoolean } from '@standardnotes/utils'
|
||||
import { DecryptedItemInterface, EncryptedItemInterface } from '@standardnotes/models'
|
||||
import { BackupFile, DecryptedItemInterface, EncryptedItemInterface, ItemStream } from '@standardnotes/models'
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { Challenge, ChallengeResponse } from '../Services'
|
||||
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
|
||||
@@ -49,20 +52,11 @@ type LaunchCallback = {
|
||||
receiveChallenge: (challenge: Challenge) => void
|
||||
}
|
||||
|
||||
type ApplicationEventCallback = (event: ApplicationEvent, data?: unknown) => Promise<void>
|
||||
|
||||
type ApplicationObserver = {
|
||||
singleEvent?: ApplicationEvent
|
||||
callback: ApplicationEventCallback
|
||||
}
|
||||
|
||||
type ItemStream<I extends DecryptedItemInterface> = (data: {
|
||||
changed: I[]
|
||||
inserted: I[]
|
||||
removed: (Models.DeletedItemInterface | Models.EncryptedItemInterface)[]
|
||||
source: Models.PayloadEmitSource
|
||||
}) => void
|
||||
|
||||
type ObserverRemover = () => void
|
||||
|
||||
export class SNApplication
|
||||
@@ -97,7 +91,7 @@ export class SNApplication
|
||||
private syncService!: InternalServices.SNSyncService
|
||||
private challengeService!: InternalServices.ChallengeService
|
||||
public singletonManager!: InternalServices.SNSingletonManager
|
||||
public componentManager!: InternalServices.SNComponentManager
|
||||
public componentManagerService!: InternalServices.SNComponentManager
|
||||
public protectionService!: InternalServices.SNProtectionService
|
||||
public actionsManager!: InternalServices.SNActionsService
|
||||
public historyManager!: InternalServices.SNHistoryManager
|
||||
@@ -192,11 +186,11 @@ export class SNApplication
|
||||
return this.fileService
|
||||
}
|
||||
|
||||
public get features(): InternalServices.FeaturesClientInterface {
|
||||
public get features(): ExternalServices.FeaturesClientInterface {
|
||||
return this.featuresService
|
||||
}
|
||||
|
||||
public get items(): InternalServices.ItemsClientInterface {
|
||||
public get items(): ExternalServices.ItemsClientInterface {
|
||||
return this.itemManager
|
||||
}
|
||||
|
||||
@@ -216,7 +210,7 @@ export class SNApplication
|
||||
return this.settingsService
|
||||
}
|
||||
|
||||
public get mutator(): InternalServices.MutatorClientInterface {
|
||||
public get mutator(): ExternalServices.MutatorClientInterface {
|
||||
return this.mutatorService
|
||||
}
|
||||
|
||||
@@ -232,6 +226,10 @@ export class SNApplication
|
||||
return this.filesBackupService
|
||||
}
|
||||
|
||||
public get componentManager(): ComponentManagerInterface {
|
||||
return this.componentManagerService
|
||||
}
|
||||
|
||||
public computePrivateWorkspaceIdentifier(userphrase: string, name: string): Promise<string | undefined> {
|
||||
return Encryption.ComputePrivateWorkspaceIdentifier(this.options.crypto, userphrase, name)
|
||||
}
|
||||
@@ -659,11 +657,11 @@ export class SNApplication
|
||||
return this.listedService.getListedAccountInfo(account, inContextOfItem)
|
||||
}
|
||||
|
||||
public async createEncryptedBackupFileForAutomatedDesktopBackups(): Promise<Encryption.BackupFile | undefined> {
|
||||
public async createEncryptedBackupFileForAutomatedDesktopBackups(): Promise<BackupFile | undefined> {
|
||||
return this.protocolService.createEncryptedBackupFile()
|
||||
}
|
||||
|
||||
public async createEncryptedBackupFile(): Promise<Encryption.BackupFile | undefined> {
|
||||
public async createEncryptedBackupFile(): Promise<BackupFile | undefined> {
|
||||
if (!(await this.protectionService.authorizeBackupCreation())) {
|
||||
return
|
||||
}
|
||||
@@ -671,7 +669,7 @@ export class SNApplication
|
||||
return this.protocolService.createEncryptedBackupFile()
|
||||
}
|
||||
|
||||
public async createDecryptedBackupFile(): Promise<Encryption.BackupFile | undefined> {
|
||||
public async createDecryptedBackupFile(): Promise<BackupFile | undefined> {
|
||||
if (!(await this.protectionService.authorizeBackupCreation())) {
|
||||
return
|
||||
}
|
||||
@@ -1070,7 +1068,7 @@ export class SNApplication
|
||||
;(this.syncService as unknown) = undefined
|
||||
;(this.challengeService as unknown) = undefined
|
||||
;(this.singletonManager as unknown) = undefined
|
||||
;(this.componentManager as unknown) = undefined
|
||||
;(this.componentManagerService as unknown) = undefined
|
||||
;(this.protectionService as unknown) = undefined
|
||||
;(this.actionsManager as unknown) = undefined
|
||||
;(this.historyManager as unknown) = undefined
|
||||
@@ -1161,11 +1159,11 @@ export class SNApplication
|
||||
this.serviceObservers.push(
|
||||
this.featuresService.addEventObserver((event) => {
|
||||
switch (event) {
|
||||
case InternalServices.FeaturesEvent.UserRolesChanged: {
|
||||
case ExternalServices.FeaturesEvent.UserRolesChanged: {
|
||||
void this.notifyEvent(ApplicationEvent.UserRolesChanged)
|
||||
break
|
||||
}
|
||||
case InternalServices.FeaturesEvent.FeaturesUpdated: {
|
||||
case ExternalServices.FeaturesEvent.FeaturesUpdated: {
|
||||
void this.notifyEvent(ApplicationEvent.FeaturesUpdated)
|
||||
break
|
||||
}
|
||||
@@ -1268,7 +1266,7 @@ export class SNApplication
|
||||
const MaybeSwappedComponentManager = this.getClass<typeof InternalServices.SNComponentManager>(
|
||||
InternalServices.SNComponentManager,
|
||||
)
|
||||
this.componentManager = new MaybeSwappedComponentManager(
|
||||
this.componentManagerService = new MaybeSwappedComponentManager(
|
||||
this.itemManager,
|
||||
this.syncService,
|
||||
this.featuresService,
|
||||
@@ -1278,7 +1276,7 @@ export class SNApplication
|
||||
this.platform,
|
||||
this.internalEventBus,
|
||||
)
|
||||
this.services.push(this.componentManager)
|
||||
this.services.push(this.componentManagerService)
|
||||
}
|
||||
|
||||
private createHttpManager() {
|
||||
@@ -1533,7 +1531,7 @@ export class SNApplication
|
||||
this.protocolService,
|
||||
this.payloadManager,
|
||||
this.challengeService,
|
||||
this.componentManager,
|
||||
this.componentManagerService,
|
||||
this.historyManager,
|
||||
this.internalEventBus,
|
||||
)
|
||||
|
||||
@@ -1,72 +1,6 @@
|
||||
import { SyncEvent } from '@standardnotes/services'
|
||||
import { ApplicationEvent, SyncEvent } from '@standardnotes/services'
|
||||
export { SyncEvent }
|
||||
|
||||
export enum ApplicationEvent {
|
||||
SignedIn = 2,
|
||||
SignedOut = 3,
|
||||
|
||||
/** When a full, potentially multi-page sync completes */
|
||||
CompletedFullSync = 5,
|
||||
|
||||
FailedSync = 6,
|
||||
HighLatencySync = 7,
|
||||
EnteredOutOfSync = 8,
|
||||
ExitedOutOfSync = 9,
|
||||
|
||||
/**
|
||||
* The application has finished it `prepareForLaunch` state and is now ready for unlock
|
||||
* Called when the application has initialized and is ready for launch, but before
|
||||
* the application has been unlocked, if applicable. Use this to do pre-launch
|
||||
* configuration, but do not attempt to access user data like notes or tags.
|
||||
*/
|
||||
Started = 10,
|
||||
|
||||
/**
|
||||
* The applicaiton is fully unlocked and ready for i/o
|
||||
* Called when the application has been fully decrypted and unlocked. Use this to
|
||||
* to begin streaming data like notes and tags.
|
||||
*/
|
||||
Launched = 11,
|
||||
LocalDataLoaded = 12,
|
||||
|
||||
/**
|
||||
* When the root key or root key wrapper changes. Includes events like account state
|
||||
* changes (registering, signing in, changing pw, logging out) and passcode state
|
||||
* changes (adding, removing, changing).
|
||||
*/
|
||||
KeyStatusChanged = 13,
|
||||
|
||||
MajorDataChange = 14,
|
||||
CompletedRestart = 15,
|
||||
LocalDataIncrementalLoad = 16,
|
||||
SyncStatusChanged = 17,
|
||||
WillSync = 18,
|
||||
InvalidSyncSession = 19,
|
||||
LocalDatabaseReadError = 20,
|
||||
LocalDatabaseWriteError = 21,
|
||||
|
||||
/** When a single roundtrip completes with sync, in a potentially multi-page sync request.
|
||||
* If just a single roundtrip, this event will be triggered, along with CompletedFullSync */
|
||||
CompletedIncrementalSync = 22,
|
||||
|
||||
/**
|
||||
* The application has loaded all pending migrations (but not run any, except for the base one),
|
||||
* and consumers may now call `hasPendingMigrations`
|
||||
*/
|
||||
MigrationsLoaded = 23,
|
||||
|
||||
/** When StorageService is ready to start servicing read/write requests */
|
||||
StorageReady = 24,
|
||||
|
||||
PreferencesChanged = 25,
|
||||
UnprotectedSessionBegan = 26,
|
||||
UserRolesChanged = 27,
|
||||
FeaturesUpdated = 28,
|
||||
UnprotectedSessionExpired = 29,
|
||||
/** Called when the app first launches and after first sync request made after sign in */
|
||||
CompletedInitialSync = 30,
|
||||
}
|
||||
|
||||
export function applicationEventForSyncEvent(syncEvent: SyncEvent) {
|
||||
return (
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { ApplicationEvent } from '../Application/Event'
|
||||
import { FileItem, PrefKey, SNNote } from '@standardnotes/models'
|
||||
import { removeFromArray } from '@standardnotes/utils'
|
||||
import { ApplicationEvent } from '@standardnotes/services'
|
||||
|
||||
import { SNApplication } from '../Application/Application'
|
||||
|
||||
import { NoteViewController } from './NoteViewController'
|
||||
import { FileViewController } from './FileViewController'
|
||||
import { TemplateNoteViewControllerOptions } from './TemplateNoteViewControllerOptions'
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { ApplicationEvent } from '@Lib/Application/Event'
|
||||
import { AbstractService, InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { SNApplication } from '../../Application/Application'
|
||||
import {
|
||||
AbstractService,
|
||||
ApplicationEvent,
|
||||
ApplicationInterface,
|
||||
InternalEventBusInterface,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
export class ApplicationService extends AbstractService {
|
||||
private unsubApp!: () => void
|
||||
|
||||
constructor(protected application: SNApplication, protected override internalEventBus: InternalEventBusInterface) {
|
||||
constructor(
|
||||
protected application: ApplicationInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
this.addAppEventObserverAfterSubclassesFinishConstructing()
|
||||
}
|
||||
|
||||
@@ -10,10 +10,15 @@ import {
|
||||
FindNativeFeature,
|
||||
FeatureIdentifier,
|
||||
} from '@standardnotes/features'
|
||||
import { DesktopManagerInterface } from '@Lib/Services/ComponentManager/Types'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { GenericItem, SNComponent } from '@standardnotes/models'
|
||||
import { InternalEventBusInterface, Environment, Platform, AlertService } from '@standardnotes/services'
|
||||
import {
|
||||
DesktopManagerInterface,
|
||||
InternalEventBusInterface,
|
||||
Environment,
|
||||
Platform,
|
||||
AlertService,
|
||||
} from '@standardnotes/services'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { SNComponentManager } from './ComponentManager'
|
||||
@@ -34,7 +39,10 @@ describe('featuresService', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
syncComponentsInstallation() {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
registerUpdateObserver() {},
|
||||
registerUpdateObserver(_callback: (component: SNComponent) => void) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
return () => {}
|
||||
},
|
||||
getExtServerHost() {
|
||||
return desktopExtHost
|
||||
},
|
||||
|
||||
@@ -3,21 +3,28 @@ import { SNPreferencesService } from '../Preferences/PreferencesService'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { ContentType, DisplayStringForContentType } from '@standardnotes/common'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { SNNote, SNTheme, SNComponent, ComponentMutator, PayloadEmitSource } from '@standardnotes/models'
|
||||
import {
|
||||
ActionObserver,
|
||||
SNNote,
|
||||
SNTheme,
|
||||
SNComponent,
|
||||
ComponentMutator,
|
||||
PayloadEmitSource,
|
||||
PermissionDialog,
|
||||
} from '@standardnotes/models'
|
||||
import { SNSyncService } from '@Lib/Services/Sync/SyncService'
|
||||
import find from 'lodash/find'
|
||||
import uniq from 'lodash/uniq'
|
||||
import { ComponentArea, ComponentAction, ComponentPermission, FindNativeFeature } from '@standardnotes/features'
|
||||
import { Copy, filterFromArray, removeFromArray, sleep, assert } from '@standardnotes/utils'
|
||||
import { UuidString } from '@Lib/Types/UuidString'
|
||||
import {
|
||||
PermissionDialog,
|
||||
DesktopManagerInterface,
|
||||
AllowedBatchContentTypes,
|
||||
} from '@Lib/Services/ComponentManager/Types'
|
||||
import { ActionObserver, ComponentViewer } from '@Lib/Services/ComponentManager/ComponentViewer'
|
||||
import { AllowedBatchContentTypes } from '@Lib/Services/ComponentManager/Types'
|
||||
import { ComponentViewer } from '@Lib/Services/ComponentManager/ComponentViewer'
|
||||
import {
|
||||
AbstractService,
|
||||
ComponentManagerInterface,
|
||||
ComponentViewerInterface,
|
||||
DesktopManagerInterface,
|
||||
InternalEventBusInterface,
|
||||
Environment,
|
||||
Platform,
|
||||
@@ -42,7 +49,7 @@ export enum ComponentManagerEvent {
|
||||
}
|
||||
|
||||
export type EventData = {
|
||||
componentViewer?: ComponentViewer
|
||||
componentViewer?: ComponentViewerInterface
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,9 +57,12 @@ export type EventData = {
|
||||
* and other components. The component manager primarily deals with iframes, and orchestrates
|
||||
* sending and receiving messages to and from frames via the postMessage API.
|
||||
*/
|
||||
export class SNComponentManager extends AbstractService<ComponentManagerEvent, EventData> {
|
||||
export class SNComponentManager
|
||||
extends AbstractService<ComponentManagerEvent, EventData>
|
||||
implements ComponentManagerInterface
|
||||
{
|
||||
private desktopManager?: DesktopManagerInterface
|
||||
private viewers: ComponentViewer[] = []
|
||||
private viewers: ComponentViewerInterface[] = []
|
||||
private removeItemObserver!: () => void
|
||||
private permissionDialogs: PermissionDialog[] = []
|
||||
|
||||
@@ -137,7 +147,7 @@ export class SNComponentManager extends AbstractService<ComponentManagerEvent, E
|
||||
contextItem?: UuidString,
|
||||
actionObserver?: ActionObserver,
|
||||
urlOverride?: string,
|
||||
): ComponentViewer {
|
||||
): ComponentViewerInterface {
|
||||
const viewer = new ComponentViewer(
|
||||
component,
|
||||
this.itemManager,
|
||||
@@ -159,7 +169,7 @@ export class SNComponentManager extends AbstractService<ComponentManagerEvent, E
|
||||
return viewer
|
||||
}
|
||||
|
||||
public destroyComponentViewer(viewer: ComponentViewer): void {
|
||||
public destroyComponentViewer(viewer: ComponentViewerInterface): void {
|
||||
viewer.destroy()
|
||||
removeFromArray(this.viewers, viewer)
|
||||
}
|
||||
@@ -316,11 +326,11 @@ export class SNComponentManager extends AbstractService<ComponentManagerEvent, E
|
||||
return this.itemManager.findItem<SNComponent>(uuid)
|
||||
}
|
||||
|
||||
findComponentViewer(identifier: string): ComponentViewer | undefined {
|
||||
findComponentViewer(identifier: string): ComponentViewerInterface | undefined {
|
||||
return this.viewers.find((viewer) => viewer.identifier === identifier)
|
||||
}
|
||||
|
||||
componentViewerForSessionKey(key: string): ComponentViewer | undefined {
|
||||
componentViewerForSessionKey(key: string): ComponentViewerInterface | undefined {
|
||||
return this.viewers.find((viewer) => viewer.sessionKey === key)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { SNPreferencesService } from '../Preferences/PreferencesService'
|
||||
import { FeatureStatus, FeaturesEvent } from '@Lib/Services/Features'
|
||||
import { Environment, Platform, AlertService } from '@standardnotes/services'
|
||||
import {
|
||||
ComponentViewerInterface,
|
||||
ComponentViewerError,
|
||||
Environment,
|
||||
FeatureStatus,
|
||||
FeaturesEvent,
|
||||
Platform,
|
||||
AlertService,
|
||||
} from '@standardnotes/services'
|
||||
import { SNFeaturesService } from '@Lib/Services'
|
||||
import {
|
||||
ActionObserver,
|
||||
ComponentEventObserver,
|
||||
ComponentViewerEvent,
|
||||
ComponentMessage,
|
||||
SNComponent,
|
||||
PrefKey,
|
||||
NoteContent,
|
||||
@@ -21,6 +32,8 @@ import {
|
||||
ComponentDataDomain,
|
||||
PayloadEmitSource,
|
||||
PayloadTimestampDefaults,
|
||||
IncomingComponentItemPayload,
|
||||
MessageData,
|
||||
} from '@standardnotes/models'
|
||||
import find from 'lodash/find'
|
||||
import uniq from 'lodash/uniq'
|
||||
@@ -28,12 +41,10 @@ import remove from 'lodash/remove'
|
||||
import { SNSyncService } from '@Lib/Services/Sync/SyncService'
|
||||
import { environmentToString, platformToString } from '@Lib/Application/Platforms'
|
||||
import {
|
||||
ComponentMessage,
|
||||
OutgoingItemMessagePayload,
|
||||
MessageReply,
|
||||
StreamItemsMessageData,
|
||||
AllowedBatchContentTypes,
|
||||
IncomingComponentItemPayload,
|
||||
DeleteItemsMessageData,
|
||||
MessageReplyData,
|
||||
} from './Types'
|
||||
@@ -53,7 +64,6 @@ import {
|
||||
sureSearchArray,
|
||||
isNotUndefined,
|
||||
} from '@standardnotes/utils'
|
||||
import { MessageData } from '..'
|
||||
|
||||
type RunWithPermissionsCallback = (
|
||||
componentUuid: UuidString,
|
||||
@@ -76,21 +86,9 @@ const ReadwriteActions = [
|
||||
ComponentAction.SetComponentData,
|
||||
]
|
||||
|
||||
export type ActionObserver = (action: ComponentAction, messageData: MessageData) => void
|
||||
|
||||
export enum ComponentViewerEvent {
|
||||
FeatureStatusUpdated = 'FeatureStatusUpdated',
|
||||
}
|
||||
type EventObserver = (event: ComponentViewerEvent) => void
|
||||
|
||||
export enum ComponentViewerError {
|
||||
OfflineRestricted = 'OfflineRestricted',
|
||||
MissingUrl = 'MissingUrl',
|
||||
}
|
||||
|
||||
type Writeable<T> = { -readonly [P in keyof T]: T[P] }
|
||||
|
||||
export class ComponentViewer {
|
||||
export class ComponentViewer implements ComponentViewerInterface {
|
||||
private streamItems?: ContentType[]
|
||||
private streamContextItemOriginalMessage?: ComponentMessage
|
||||
private streamItemsOriginalMessage?: ComponentMessage
|
||||
@@ -101,7 +99,7 @@ export class ComponentViewer {
|
||||
public overrideContextItem?: DecryptedItemInterface
|
||||
private featureStatus: FeatureStatus
|
||||
private removeFeaturesObserver: () => void
|
||||
private eventObservers: EventObserver[] = []
|
||||
private eventObservers: ComponentEventObserver[] = []
|
||||
private dealloced = false
|
||||
|
||||
private window?: Window
|
||||
@@ -189,7 +187,7 @@ export class ComponentViewer {
|
||||
;(this.removeItemObserver as unknown) = undefined
|
||||
}
|
||||
|
||||
public addEventObserver(observer: EventObserver): () => void {
|
||||
public addEventObserver(observer: ComponentEventObserver): () => void {
|
||||
this.eventObservers.push(observer)
|
||||
|
||||
const thislessChangeObservers = this.eventObservers
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
import {
|
||||
ComponentArea,
|
||||
ComponentAction,
|
||||
ComponentPermission,
|
||||
FeatureIdentifier,
|
||||
LegacyFileSafeIdentifier,
|
||||
} from '@standardnotes/features'
|
||||
import { ItemContent, SNComponent, DecryptedTransferPayload } from '@standardnotes/models'
|
||||
import { ComponentArea, ComponentAction, FeatureIdentifier, LegacyFileSafeIdentifier } from '@standardnotes/features'
|
||||
import { ComponentMessage, ItemContent, MessageData } from '@standardnotes/models'
|
||||
import { UuidString } from '@Lib/Types/UuidString'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
|
||||
export interface DesktopManagerInterface {
|
||||
syncComponentsInstallation(components: SNComponent[]): void
|
||||
registerUpdateObserver(callback: (component: SNComponent) => void): void
|
||||
getExtServerHost(): string
|
||||
}
|
||||
|
||||
export type IncomingComponentItemPayload = DecryptedTransferPayload & {
|
||||
clientData: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type OutgoingItemMessagePayload = {
|
||||
uuid: string
|
||||
content_type: ContentType
|
||||
@@ -63,46 +47,6 @@ export type StreamObserver = {
|
||||
contentTypes?: ContentType[]
|
||||
}
|
||||
|
||||
export type PermissionDialog = {
|
||||
component: SNComponent
|
||||
permissions: ComponentPermission[]
|
||||
permissionsString: string
|
||||
actionBlock: (approved: boolean) => void
|
||||
callback: (approved: boolean) => void
|
||||
}
|
||||
|
||||
export enum KeyboardModifier {
|
||||
Shift = 'Shift',
|
||||
Ctrl = 'Control',
|
||||
Meta = 'Meta',
|
||||
}
|
||||
|
||||
export type MessageData = Partial<{
|
||||
/** Related to the stream-item-context action */
|
||||
item?: IncomingComponentItemPayload
|
||||
/** Related to the stream-items action */
|
||||
content_types?: ContentType[]
|
||||
items?: IncomingComponentItemPayload[]
|
||||
/** Related to the request-permission action */
|
||||
permissions?: ComponentPermission[]
|
||||
/** Related to the component-registered action */
|
||||
componentData?: Record<string, unknown>
|
||||
uuid?: UuidString
|
||||
environment?: string
|
||||
platform?: string
|
||||
activeThemeUrls?: string[]
|
||||
/** Related to set-size action */
|
||||
width?: string | number
|
||||
height?: string | number
|
||||
type?: string
|
||||
/** Related to themes action */
|
||||
themes?: string[]
|
||||
/** Related to clear-selection action */
|
||||
content_type?: ContentType
|
||||
/** Related to key-pressed action */
|
||||
keyboardModifier?: KeyboardModifier
|
||||
}>
|
||||
|
||||
export type MessageReplyData = {
|
||||
approved?: boolean
|
||||
deleted?: boolean
|
||||
@@ -120,13 +64,6 @@ export type DeleteItemsMessageData = MessageData & {
|
||||
items: OutgoingItemMessagePayload[]
|
||||
}
|
||||
|
||||
export type ComponentMessage = {
|
||||
action: ComponentAction
|
||||
sessionKey?: string
|
||||
componentData?: Record<string, unknown>
|
||||
data: MessageData
|
||||
}
|
||||
|
||||
export type MessageReply = {
|
||||
action: ComponentAction
|
||||
original: ComponentMessage
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { FeatureStatus, SetOfflineFeaturesFunctionResponse } from './Types'
|
||||
import { FeatureDescription, FeatureIdentifier } from '@standardnotes/features'
|
||||
import { SNComponent } from '@standardnotes/models'
|
||||
import { RoleName } from '@standardnotes/common'
|
||||
|
||||
export interface FeaturesClientInterface {
|
||||
downloadExternalFeature(urlOrCode: string): Promise<SNComponent | undefined>
|
||||
|
||||
getUserFeature(featureId: FeatureIdentifier): FeatureDescription | undefined
|
||||
|
||||
getFeatureStatus(featureId: FeatureIdentifier): FeatureStatus
|
||||
|
||||
hasMinimumRole(role: RoleName): boolean
|
||||
|
||||
setOfflineFeaturesCode(code: string): Promise<SetOfflineFeaturesFunctionResponse>
|
||||
|
||||
hasOfflineRepo(): boolean
|
||||
|
||||
deleteOfflineFeatureRepo(): Promise<void>
|
||||
|
||||
isThirdPartyFeature(identifier: string): boolean
|
||||
|
||||
toggleExperimentalFeature(identifier: FeatureIdentifier): void
|
||||
|
||||
getExperimentalFeatures(): FeatureIdentifier[]
|
||||
|
||||
getEnabledExperimentalFeatures(): FeatureIdentifier[]
|
||||
|
||||
enableExperimentalFeature(identifier: FeatureIdentifier): void
|
||||
|
||||
disableExperimentalFeature(identifier: FeatureIdentifier): void
|
||||
|
||||
isExperimentalFeatureEnabled(identifier: FeatureIdentifier): boolean
|
||||
|
||||
isExperimentalFeature(identifier: FeatureIdentifier): boolean
|
||||
}
|
||||
@@ -10,14 +10,14 @@ import {
|
||||
DiskStorageService,
|
||||
StorageKey,
|
||||
} from '@Lib/index'
|
||||
import { FeatureStatus, SNFeaturesService } from '@Lib/Services/Features'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features'
|
||||
import { ContentType, RoleName } from '@standardnotes/common'
|
||||
import { FeatureDescription, FeatureIdentifier, GetFeatures } from '@standardnotes/features'
|
||||
import { SNWebSocketsService } from '../Api/WebsocketsService'
|
||||
import { SNSettingsService } from '../Settings'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { convertTimestampToMilliseconds } from '@standardnotes/utils'
|
||||
import { InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { FeatureStatus, InternalEventBusInterface } from '@standardnotes/services'
|
||||
|
||||
describe('featuresService', () => {
|
||||
let storageService: DiskStorageService
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
} from '@standardnotes/utils'
|
||||
import { ClientDisplayableError, UserFeaturesResponse } from '@standardnotes/responses'
|
||||
import { ContentType, RoleName } from '@standardnotes/common'
|
||||
import { FeaturesClientInterface } from './ClientInterface'
|
||||
import { FillItemContent, PayloadEmitSource } from '@standardnotes/models'
|
||||
import { ItemManager } from '../Items/ItemManager'
|
||||
import { LEGACY_PROD_EXT_ORIGIN, PROD_OFFLINE_FEATURES_URL } from '../../Hosts'
|
||||
@@ -27,20 +26,30 @@ import { UuidString } from '@Lib/Types/UuidString'
|
||||
import * as FeaturesImports from '@standardnotes/features'
|
||||
import * as Messages from '@Lib/Services/Api/Messages'
|
||||
import * as Models from '@standardnotes/models'
|
||||
import * as Services from '@standardnotes/services'
|
||||
import {
|
||||
AbstractService,
|
||||
AlertService,
|
||||
ApiServiceEvent,
|
||||
ApplicationStage,
|
||||
ButtonType,
|
||||
DiagnosticInfo,
|
||||
FeaturesClientInterface,
|
||||
FeaturesEvent,
|
||||
FeatureStatus,
|
||||
InternalEventBusInterface,
|
||||
InternalEventHandlerInterface,
|
||||
InternalEventInterface,
|
||||
MetaReceivedData,
|
||||
OfflineSubscriptionEntitlements,
|
||||
SetOfflineFeaturesFunctionResponse,
|
||||
} from './Types'
|
||||
import { DiagnosticInfo } from '@standardnotes/services'
|
||||
StorageKey,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
type GetOfflineSubscriptionDetailsResponse = OfflineSubscriptionEntitlements | ClientDisplayableError
|
||||
|
||||
export class SNFeaturesService
|
||||
extends Services.AbstractService<FeaturesEvent>
|
||||
implements FeaturesClientInterface, Services.InternalEventHandlerInterface
|
||||
extends AbstractService<FeaturesEvent>
|
||||
implements FeaturesClientInterface, InternalEventHandlerInterface
|
||||
{
|
||||
private deinited = false
|
||||
private roles: RoleName[] = []
|
||||
@@ -60,10 +69,10 @@ export class SNFeaturesService
|
||||
private settingsService: SNSettingsService,
|
||||
private userService: UserService,
|
||||
private syncService: SNSyncService,
|
||||
private alertService: Services.AlertService,
|
||||
private alertService: AlertService,
|
||||
private sessionManager: SNSessionManager,
|
||||
private crypto: PureCryptoInterface,
|
||||
protected override internalEventBus: Services.InternalEventBusInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
|
||||
@@ -109,8 +118,8 @@ export class SNFeaturesService
|
||||
})
|
||||
}
|
||||
|
||||
async handleEvent(event: Services.InternalEventInterface): Promise<void> {
|
||||
if (event.type === Services.ApiServiceEvent.MetaReceived) {
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApiServiceEvent.MetaReceived) {
|
||||
if (!this.syncService) {
|
||||
this.log('[Features Service] Handling events interrupted. Sync service is not yet initialized.', event)
|
||||
|
||||
@@ -126,7 +135,7 @@ export class SNFeaturesService
|
||||
return
|
||||
}
|
||||
|
||||
const { userUuid, userRoles } = event.payload as Services.MetaReceivedData
|
||||
const { userUuid, userRoles } = event.payload as MetaReceivedData
|
||||
await this.updateRolesAndFetchFeatures(
|
||||
userUuid,
|
||||
userRoles.map((role) => role.name),
|
||||
@@ -134,9 +143,9 @@ export class SNFeaturesService
|
||||
}
|
||||
}
|
||||
|
||||
override async handleApplicationStage(stage: Services.ApplicationStage): Promise<void> {
|
||||
override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
await super.handleApplicationStage(stage)
|
||||
if (stage === Services.ApplicationStage.FullSyncCompleted_13) {
|
||||
if (stage === ApplicationStage.FullSyncCompleted_13) {
|
||||
if (!this.hasOnlineSubscription()) {
|
||||
const offlineRepo = this.getOfflineRepo()
|
||||
if (offlineRepo) {
|
||||
@@ -154,7 +163,7 @@ export class SNFeaturesService
|
||||
|
||||
this.enabledExperimentalFeatures.push(identifier)
|
||||
|
||||
void this.storageService.setValue(Services.StorageKey.ExperimentalFeatures, this.enabledExperimentalFeatures)
|
||||
void this.storageService.setValue(StorageKey.ExperimentalFeatures, this.enabledExperimentalFeatures)
|
||||
|
||||
void this.mapRemoteNativeFeaturesToItems([feature])
|
||||
void this.notifyEvent(FeaturesEvent.FeaturesUpdated)
|
||||
@@ -168,7 +177,7 @@ export class SNFeaturesService
|
||||
|
||||
removeFromArray(this.enabledExperimentalFeatures, identifier)
|
||||
|
||||
void this.storageService.setValue(Services.StorageKey.ExperimentalFeatures, this.enabledExperimentalFeatures)
|
||||
void this.storageService.setValue(StorageKey.ExperimentalFeatures, this.enabledExperimentalFeatures)
|
||||
|
||||
const component = this.itemManager
|
||||
.getItems<Models.SNComponent | Models.SNTheme>([ContentType.Component, ContentType.Theme])
|
||||
@@ -248,7 +257,7 @@ export class SNFeaturesService
|
||||
await this.itemManager.setItemToBeDeleted(repo)
|
||||
void this.syncService.sync()
|
||||
}
|
||||
await this.storageService.removeValue(Services.StorageKey.UserFeatures)
|
||||
await this.storageService.removeValue(StorageKey.UserFeatures)
|
||||
}
|
||||
|
||||
private parseOfflineEntitlementsCode(code: string): GetOfflineSubscriptionDetailsResponse | ClientDisplayableError {
|
||||
@@ -322,15 +331,11 @@ export class SNFeaturesService
|
||||
}
|
||||
|
||||
public initializeFromDisk(): void {
|
||||
this.roles = this.storageService.getValue<RoleName[]>(Services.StorageKey.UserRoles, undefined, [])
|
||||
this.roles = this.storageService.getValue<RoleName[]>(StorageKey.UserRoles, undefined, [])
|
||||
|
||||
this.features = this.storageService.getValue(Services.StorageKey.UserFeatures, undefined, [])
|
||||
this.features = this.storageService.getValue(StorageKey.UserFeatures, undefined, [])
|
||||
|
||||
this.enabledExperimentalFeatures = this.storageService.getValue(
|
||||
Services.StorageKey.ExperimentalFeatures,
|
||||
undefined,
|
||||
[],
|
||||
)
|
||||
this.enabledExperimentalFeatures = this.storageService.getValue(StorageKey.ExperimentalFeatures, undefined, [])
|
||||
}
|
||||
|
||||
public async updateRolesAndFetchFeatures(userUuid: UuidString, roles: RoleName[]): Promise<void> {
|
||||
@@ -361,7 +366,7 @@ export class SNFeaturesService
|
||||
if (!arraysEqual(this.roles, roles)) {
|
||||
void this.notifyEvent(FeaturesEvent.UserRolesChanged)
|
||||
}
|
||||
await this.storageService.setValue(Services.StorageKey.UserRoles, this.roles)
|
||||
await this.storageService.setValue(StorageKey.UserRoles, this.roles)
|
||||
}
|
||||
|
||||
public async didDownloadFeatures(features: FeaturesImports.FeatureDescription[]): Promise<void> {
|
||||
@@ -372,7 +377,7 @@ export class SNFeaturesService
|
||||
this.features = features
|
||||
this.completedSuccessfulFeaturesRetrieval = true
|
||||
void this.notifyEvent(FeaturesEvent.FeaturesUpdated)
|
||||
void this.storageService.setValue(Services.StorageKey.UserFeatures, this.features)
|
||||
void this.storageService.setValue(StorageKey.UserFeatures, this.features)
|
||||
|
||||
await this.mapRemoteNativeFeaturesToItems(features)
|
||||
}
|
||||
@@ -607,7 +612,7 @@ export class SNFeaturesService
|
||||
Messages.API_MESSAGE_UNTRUSTED_EXTENSIONS_WARNING,
|
||||
'Install extension from an untrusted source?',
|
||||
'Proceed to install',
|
||||
Services.ButtonType.Danger,
|
||||
ButtonType.Danger,
|
||||
'Cancel',
|
||||
)
|
||||
if (didConfirm) {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
|
||||
export type SetOfflineFeaturesFunctionResponse = ClientDisplayableError | undefined
|
||||
|
||||
export type OfflineSubscriptionEntitlements = {
|
||||
featuresUrl: string
|
||||
extensionKey: string
|
||||
}
|
||||
|
||||
export enum FeaturesEvent {
|
||||
UserRolesChanged = 'UserRolesChanged',
|
||||
FeaturesUpdated = 'FeaturesUpdated',
|
||||
}
|
||||
|
||||
export enum FeatureStatus {
|
||||
NoUserSubscription = 'NoUserSubscription',
|
||||
NotInCurrentPlan = 'NotInCurrentPlan',
|
||||
InCurrentPlanButExpired = 'InCurrentPlanButExpired',
|
||||
Entitled = 'Entitled',
|
||||
}
|
||||
@@ -1,3 +1 @@
|
||||
export * from './ClientInterface'
|
||||
export * from './FeaturesService'
|
||||
export * from './Types'
|
||||
|
||||
@@ -3,13 +3,11 @@ import { assert, naturalSort, removeFromArray, UuidGenerator, Uuids } from '@sta
|
||||
import { ItemsKeyMutator, SNItemsKey } from '@standardnotes/encryption'
|
||||
import { PayloadManager } from '../Payloads/PayloadManager'
|
||||
import { TagsToFoldersMigrationApplicator } from '../../Migrations/Applicators/TagsToFolders'
|
||||
import { TransactionalMutation } from './TransactionalMutation'
|
||||
import { UuidString } from '../../Types/UuidString'
|
||||
import * as Models from '@standardnotes/models'
|
||||
import * as Services from '@standardnotes/services'
|
||||
import { ItemsClientInterface } from './ItemsClientInterface'
|
||||
import { PayloadManagerChangeData } from '../Payloads'
|
||||
import { DiagnosticInfo } from '@standardnotes/services'
|
||||
import { DiagnosticInfo, ItemsClientInterface } from '@standardnotes/services'
|
||||
import { ApplicationDisplayOptions } from '@Lib/Application/Options/OptionalOptions'
|
||||
import { CollectionSort } from '@standardnotes/models'
|
||||
|
||||
@@ -578,7 +576,7 @@ export class ItemManager
|
||||
* runs the same mutation on all items.
|
||||
*/
|
||||
public async runTransactionalMutations(
|
||||
transactions: TransactionalMutation[],
|
||||
transactions: Models.TransactionalMutation[],
|
||||
emitSource = Models.PayloadEmitSource.LocalChanged,
|
||||
payloadSourceKey?: string,
|
||||
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
|
||||
@@ -607,7 +605,7 @@ export class ItemManager
|
||||
}
|
||||
|
||||
public async runTransactionalMutation(
|
||||
transaction: TransactionalMutation,
|
||||
transaction: Models.TransactionalMutation,
|
||||
emitSource = Models.PayloadEmitSource.LocalChanged,
|
||||
payloadSourceKey?: string,
|
||||
): Promise<Models.DecryptedItemInterface | undefined> {
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
import { SNItemsKey } from '@standardnotes/encryption'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import {
|
||||
SNNote,
|
||||
FileItem,
|
||||
SNTag,
|
||||
SmartView,
|
||||
TagNoteCountChangeObserver,
|
||||
DecryptedPayloadInterface,
|
||||
EncryptedItemInterface,
|
||||
DecryptedTransferPayload,
|
||||
PredicateInterface,
|
||||
DecryptedItemInterface,
|
||||
SNComponent,
|
||||
SNTheme,
|
||||
DisplayOptions,
|
||||
} from '@standardnotes/models'
|
||||
import { UuidString } from '@Lib/Types'
|
||||
|
||||
export interface ItemsClientInterface {
|
||||
get invalidItems(): EncryptedItemInterface[]
|
||||
|
||||
associateFileWithNote(file: FileItem, note: SNNote): Promise<FileItem>
|
||||
|
||||
disassociateFileWithNote(file: FileItem, note: SNNote): Promise<FileItem>
|
||||
|
||||
getFilesForNote(note: SNNote): FileItem[]
|
||||
|
||||
renameFile(file: FileItem, name: string): Promise<FileItem>
|
||||
|
||||
addTagToNote(note: SNNote, tag: SNTag, addHierarchy: boolean): Promise<SNTag[]>
|
||||
|
||||
/** Creates an unmanaged, un-inserted item from a payload. */
|
||||
createItemFromPayload(payload: DecryptedPayloadInterface): DecryptedItemInterface
|
||||
|
||||
createPayloadFromObject(object: DecryptedTransferPayload): DecryptedPayloadInterface
|
||||
|
||||
get trashedItems(): SNNote[]
|
||||
|
||||
setPrimaryItemDisplayOptions(options: DisplayOptions): void
|
||||
|
||||
getDisplayableNotes(): SNNote[]
|
||||
|
||||
getDisplayableTags(): SNTag[]
|
||||
|
||||
getDisplayableItemsKeys(): SNItemsKey[]
|
||||
|
||||
getDisplayableFiles(): FileItem[]
|
||||
|
||||
getDisplayableNotesAndFiles(): (SNNote | FileItem)[]
|
||||
|
||||
getDisplayableComponents(): (SNComponent | SNTheme)[]
|
||||
|
||||
getItems<T extends DecryptedItemInterface>(contentType: ContentType | ContentType[]): T[]
|
||||
|
||||
notesMatchingSmartView(view: SmartView): SNNote[]
|
||||
|
||||
addNoteCountChangeObserver(observer: TagNoteCountChangeObserver): () => void
|
||||
|
||||
allCountableNotesCount(): number
|
||||
|
||||
countableNotesForTag(tag: SNTag | SmartView): number
|
||||
|
||||
findTagByTitle(title: string): SNTag | undefined
|
||||
|
||||
getTagPrefixTitle(tag: SNTag): string | undefined
|
||||
|
||||
getTagLongTitle(tag: SNTag): string
|
||||
|
||||
hasTagsNeedingFoldersMigration(): boolean
|
||||
|
||||
referencesForItem(itemToLookupUuidFor: DecryptedItemInterface, contentType?: ContentType): DecryptedItemInterface[]
|
||||
|
||||
itemsReferencingItem(itemToLookupUuidFor: DecryptedItemInterface, contentType?: ContentType): DecryptedItemInterface[]
|
||||
|
||||
/**
|
||||
* Finds tags with title or component starting with a search query and (optionally) not associated with a note
|
||||
* @param searchQuery - The query string to match
|
||||
* @param note - The note whose tags should be omitted from results
|
||||
* @returns Array containing tags matching search query and not associated with note
|
||||
*/
|
||||
searchTags(searchQuery: string, note?: SNNote): SNTag[]
|
||||
|
||||
isValidTagParent(parentTagToLookUpUuidFor: SNTag, childToLookUpUuidFor: SNTag): boolean
|
||||
|
||||
/**
|
||||
* Returns the parent for a tag
|
||||
*/
|
||||
getTagParent(itemToLookupUuidFor: SNTag): SNTag | undefined
|
||||
|
||||
/**
|
||||
* Returns the hierarchy of parents for a tag
|
||||
* @returns Array containing all parent tags
|
||||
*/
|
||||
getTagParentChain(itemToLookupUuidFor: SNTag): SNTag[]
|
||||
|
||||
/**
|
||||
* Returns all descendants for a tag
|
||||
* @returns Array containing all descendant tags
|
||||
*/
|
||||
getTagChildren(itemToLookupUuidFor: SNTag): SNTag[]
|
||||
|
||||
/**
|
||||
* Get tags for a note sorted in natural order
|
||||
* @param note - The note whose tags will be returned
|
||||
* @returns Array containing tags associated with a note
|
||||
*/
|
||||
getSortedTagsForNote(note: SNNote): SNTag[]
|
||||
|
||||
isSmartViewTitle(title: string): boolean
|
||||
|
||||
getSmartViews(): SmartView[]
|
||||
|
||||
getNoteCount(): number
|
||||
|
||||
/**
|
||||
* Finds an item by UUID.
|
||||
*/
|
||||
findItem<T extends DecryptedItemInterface = DecryptedItemInterface>(uuid: UuidString): T | undefined
|
||||
|
||||
/**
|
||||
* Finds an item by predicate.
|
||||
*/
|
||||
findItems<T extends DecryptedItemInterface>(uuids: UuidString[]): T[]
|
||||
|
||||
findSureItem<T extends DecryptedItemInterface = DecryptedItemInterface>(uuid: UuidString): T
|
||||
|
||||
/**
|
||||
* Finds an item by predicate.
|
||||
*/
|
||||
itemsMatchingPredicate<T extends DecryptedItemInterface>(
|
||||
contentType: ContentType,
|
||||
predicate: PredicateInterface<T>,
|
||||
): T[]
|
||||
|
||||
/**
|
||||
* @param item item to be checked
|
||||
* @returns Whether the item is a template (unmanaged)
|
||||
*/
|
||||
isTemplateItem(item: DecryptedItemInterface): boolean
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import * as Models from '@standardnotes/models'
|
||||
import { UuidString } from '../../Types/UuidString'
|
||||
|
||||
export type TransactionalMutation = {
|
||||
itemUuid: UuidString
|
||||
mutate: (mutator: Models.ItemMutator) => void
|
||||
mutationType?: Models.MutationType
|
||||
}
|
||||
@@ -1,3 +1 @@
|
||||
export * from './ItemsClientInterface'
|
||||
export * from './ItemManager'
|
||||
export * from './TransactionalMutation'
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ApplicationEvent } from '../../Application/Event'
|
||||
import { BaseMigration } from '@Lib/Migrations/Base'
|
||||
import { compareSemVersions } from '@Lib/Version'
|
||||
import { lastElement } from '@standardnotes/utils'
|
||||
@@ -7,6 +6,7 @@ import { MigrationServices } from '../../Migrations/MigrationServices'
|
||||
import {
|
||||
RawStorageKey,
|
||||
namespacedKey,
|
||||
ApplicationEvent,
|
||||
ApplicationStage,
|
||||
AbstractService,
|
||||
DiagnosticInfo,
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { ChallengeReason, SyncOptions } from '@standardnotes/services'
|
||||
import { TransactionalMutation } from '../Items'
|
||||
import * as Models from '@standardnotes/models'
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { BackupFile } from '@standardnotes/encryption'
|
||||
|
||||
export interface MutatorClientInterface {
|
||||
/**
|
||||
* Inserts the input item by its payload properties, and marks the item as dirty.
|
||||
* A sync is not performed after an item is inserted. This must be handled by the caller.
|
||||
*/
|
||||
insertItem(item: Models.DecryptedItemInterface): Promise<Models.DecryptedItemInterface>
|
||||
|
||||
/**
|
||||
* Mutates a pre-existing item, marks it as dirty, and syncs it
|
||||
*/
|
||||
changeAndSaveItem<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
|
||||
itemToLookupUuidFor: Models.DecryptedItemInterface,
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps?: boolean,
|
||||
emitSource?: Models.PayloadEmitSource,
|
||||
syncOptions?: SyncOptions,
|
||||
): Promise<Models.DecryptedItemInterface | undefined>
|
||||
|
||||
/**
|
||||
* Mutates pre-existing items, marks them as dirty, and syncs
|
||||
*/
|
||||
changeAndSaveItems<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
|
||||
itemsToLookupUuidsFor: Models.DecryptedItemInterface[],
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps?: boolean,
|
||||
emitSource?: Models.PayloadEmitSource,
|
||||
syncOptions?: SyncOptions,
|
||||
): Promise<void>
|
||||
|
||||
/**
|
||||
* Mutates a pre-existing item and marks it as dirty. Does not sync changes.
|
||||
*/
|
||||
changeItem<M extends Models.DecryptedItemMutator>(
|
||||
itemToLookupUuidFor: Models.DecryptedItemInterface,
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps?: boolean,
|
||||
): Promise<Models.DecryptedItemInterface | undefined>
|
||||
|
||||
/**
|
||||
* Mutates a pre-existing items and marks them as dirty. Does not sync changes.
|
||||
*/
|
||||
changeItems<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
|
||||
itemsToLookupUuidsFor: Models.DecryptedItemInterface[],
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps?: boolean,
|
||||
): Promise<(Models.DecryptedItemInterface | undefined)[]>
|
||||
|
||||
/**
|
||||
* Run unique mutations per each item in the array, then only propagate all changes
|
||||
* once all mutations have been run. This differs from `changeItems` in that changeItems
|
||||
* runs the same mutation on all items.
|
||||
*/
|
||||
runTransactionalMutations(
|
||||
transactions: TransactionalMutation[],
|
||||
emitSource?: Models.PayloadEmitSource,
|
||||
payloadSourceKey?: string,
|
||||
): Promise<(Models.DecryptedItemInterface | undefined)[]>
|
||||
|
||||
runTransactionalMutation(
|
||||
transaction: TransactionalMutation,
|
||||
emitSource?: Models.PayloadEmitSource,
|
||||
payloadSourceKey?: string,
|
||||
): Promise<Models.DecryptedItemInterface | undefined>
|
||||
|
||||
protectItems<
|
||||
_M extends Models.DecryptedItemMutator<Models.ItemContent>,
|
||||
I extends Models.DecryptedItemInterface<Models.ItemContent>,
|
||||
>(
|
||||
items: I[],
|
||||
): Promise<I[]>
|
||||
|
||||
unprotectItems<
|
||||
_M extends Models.DecryptedItemMutator<Models.ItemContent>,
|
||||
I extends Models.DecryptedItemInterface<Models.ItemContent>,
|
||||
>(
|
||||
items: I[],
|
||||
reason: ChallengeReason,
|
||||
): Promise<I[] | undefined>
|
||||
|
||||
protectNote(note: Models.SNNote): Promise<Models.SNNote>
|
||||
|
||||
unprotectNote(note: Models.SNNote): Promise<Models.SNNote | undefined>
|
||||
|
||||
protectNotes(notes: Models.SNNote[]): Promise<Models.SNNote[]>
|
||||
|
||||
unprotectNotes(notes: Models.SNNote[]): Promise<Models.SNNote[]>
|
||||
|
||||
protectFile(file: Models.FileItem): Promise<Models.FileItem>
|
||||
|
||||
unprotectFile(file: Models.FileItem): Promise<Models.FileItem | undefined>
|
||||
|
||||
/**
|
||||
* Takes the values of the input item and emits it onto global state.
|
||||
*/
|
||||
mergeItem(
|
||||
item: Models.DecryptedItemInterface,
|
||||
source: Models.PayloadEmitSource,
|
||||
): Promise<Models.DecryptedItemInterface>
|
||||
|
||||
/**
|
||||
* Creates an unmanaged item that can be added later.
|
||||
*/
|
||||
createTemplateItem<
|
||||
C extends Models.ItemContent = Models.ItemContent,
|
||||
I extends Models.DecryptedItemInterface<C> = Models.DecryptedItemInterface<C>,
|
||||
>(
|
||||
contentType: ContentType,
|
||||
content?: C,
|
||||
): I
|
||||
|
||||
/**
|
||||
* @param isUserModified Whether to change the modified date the user
|
||||
* sees of the item.
|
||||
*/
|
||||
setItemNeedsSync(
|
||||
item: Models.DecryptedItemInterface,
|
||||
isUserModified?: boolean,
|
||||
): Promise<Models.DecryptedItemInterface | undefined>
|
||||
|
||||
setItemsNeedsSync(items: Models.DecryptedItemInterface[]): Promise<(Models.DecryptedItemInterface | undefined)[]>
|
||||
|
||||
deleteItem(item: Models.DecryptedItemInterface | Models.EncryptedItemInterface): Promise<void>
|
||||
|
||||
deleteItems(items: (Models.DecryptedItemInterface | Models.EncryptedItemInterface)[]): Promise<void>
|
||||
|
||||
emptyTrash(): Promise<void>
|
||||
|
||||
duplicateItem<T extends Models.DecryptedItemInterface>(item: T, additionalContent?: Partial<T['content']>): Promise<T>
|
||||
|
||||
/**
|
||||
* Migrates any tags containing a '.' character to sa chema-based heirarchy, removing
|
||||
* the dot from the tag's title.
|
||||
*/
|
||||
migrateTagsToFolders(): Promise<unknown>
|
||||
|
||||
/**
|
||||
* Establishes a hierarchical relationship between two tags.
|
||||
*/
|
||||
setTagParent(parentTag: Models.SNTag, childTag: Models.SNTag): Promise<void>
|
||||
|
||||
/**
|
||||
* Remove the tag parent.
|
||||
*/
|
||||
unsetTagParent(childTag: Models.SNTag): Promise<void>
|
||||
|
||||
findOrCreateTag(title: string): Promise<Models.SNTag>
|
||||
|
||||
/** Creates and returns the tag but does not run sync. Callers must perform sync. */
|
||||
createTagOrSmartView(title: string): Promise<Models.SNTag | Models.SmartView>
|
||||
|
||||
/**
|
||||
* Activates or deactivates a component, depending on its
|
||||
* current state, and syncs.
|
||||
*/
|
||||
toggleComponent(component: Models.SNComponent): Promise<void>
|
||||
|
||||
toggleTheme(theme: Models.SNComponent): Promise<void>
|
||||
|
||||
/**
|
||||
* @returns
|
||||
* .affectedItems: Items that were either created or dirtied by this import
|
||||
* .errorCount: The number of items that were not imported due to failure to decrypt.
|
||||
*/
|
||||
importData(
|
||||
data: BackupFile,
|
||||
awaitSync?: boolean,
|
||||
): Promise<
|
||||
| {
|
||||
affectedItems: Models.DecryptedItemInterface[]
|
||||
errorCount: number
|
||||
}
|
||||
| {
|
||||
error: ClientDisplayableError
|
||||
}
|
||||
>
|
||||
}
|
||||
@@ -6,25 +6,42 @@ import {
|
||||
ChallengeValidation,
|
||||
ChallengePrompt,
|
||||
ChallengeReason,
|
||||
MutatorClientInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { BackupFile, EncryptionProvider } from '@standardnotes/encryption'
|
||||
import { EncryptionProvider } from '@standardnotes/encryption'
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { ContentType, ProtocolVersion, compareVersions } from '@standardnotes/common'
|
||||
import { ItemManager, TransactionalMutation } from '../Items'
|
||||
import { MutatorClientInterface } from './MutatorClientInterface'
|
||||
import { ItemManager } from '../Items'
|
||||
import { PayloadManager } from '../Payloads/PayloadManager'
|
||||
import { SNComponentManager } from '../ComponentManager/ComponentManager'
|
||||
import { SNProtectionService } from '../Protection/ProtectionService'
|
||||
import { SNSyncService } from '../Sync'
|
||||
import { Strings } from '../../Strings'
|
||||
import { TagsToFoldersMigrationApplicator } from '@Lib/Migrations/Applicators/TagsToFolders'
|
||||
import * as Models from '@standardnotes/models'
|
||||
import { Challenge, ChallengeService } from '../Challenge'
|
||||
import {
|
||||
BackupFile,
|
||||
BackupFileDecryptedContextualPayload,
|
||||
ComponentContent,
|
||||
CopyPayloadWithContentOverride,
|
||||
CreateDecryptedBackupFileContextPayload,
|
||||
CreateDecryptedMutatorForItem,
|
||||
CreateEncryptedBackupFileContextPayload,
|
||||
DecryptedItemInterface,
|
||||
DecryptedItemMutator,
|
||||
DecryptedPayloadInterface,
|
||||
EncryptedItemInterface,
|
||||
FileItem,
|
||||
isDecryptedPayload,
|
||||
isEncryptedTransferPayload,
|
||||
ItemContent,
|
||||
MutationType,
|
||||
PayloadEmitSource,
|
||||
SmartView,
|
||||
SNComponent,
|
||||
SNNote,
|
||||
SNTag,
|
||||
TransactionalMutation,
|
||||
} from '@standardnotes/models'
|
||||
|
||||
export class MutatorService extends AbstractService implements MutatorClientInterface {
|
||||
@@ -54,106 +71,101 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
;(this.historyService as unknown) = undefined
|
||||
}
|
||||
|
||||
public async insertItem(item: Models.DecryptedItemInterface): Promise<Models.DecryptedItemInterface> {
|
||||
const mutator = Models.CreateDecryptedMutatorForItem(item, Models.MutationType.UpdateUserTimestamps)
|
||||
public async insertItem(item: DecryptedItemInterface): Promise<DecryptedItemInterface> {
|
||||
const mutator = CreateDecryptedMutatorForItem(item, MutationType.UpdateUserTimestamps)
|
||||
const dirtiedPayload = mutator.getResult()
|
||||
const insertedItem = await this.itemManager.emitItemFromPayload(
|
||||
dirtiedPayload,
|
||||
Models.PayloadEmitSource.LocalInserted,
|
||||
)
|
||||
const insertedItem = await this.itemManager.emitItemFromPayload(dirtiedPayload, PayloadEmitSource.LocalInserted)
|
||||
return insertedItem
|
||||
}
|
||||
|
||||
public async changeAndSaveItem<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
|
||||
itemToLookupUuidFor: Models.DecryptedItemInterface,
|
||||
public async changeAndSaveItem<M extends DecryptedItemMutator = DecryptedItemMutator>(
|
||||
itemToLookupUuidFor: DecryptedItemInterface,
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps = true,
|
||||
emitSource?: Models.PayloadEmitSource,
|
||||
emitSource?: PayloadEmitSource,
|
||||
syncOptions?: SyncOptions,
|
||||
): Promise<Models.DecryptedItemInterface | undefined> {
|
||||
): Promise<DecryptedItemInterface | undefined> {
|
||||
await this.itemManager.changeItems(
|
||||
[itemToLookupUuidFor],
|
||||
mutate,
|
||||
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
|
||||
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
|
||||
emitSource,
|
||||
)
|
||||
await this.syncService.sync(syncOptions)
|
||||
return this.itemManager.findItem(itemToLookupUuidFor.uuid)
|
||||
}
|
||||
|
||||
public async changeAndSaveItems<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
|
||||
itemsToLookupUuidsFor: Models.DecryptedItemInterface[],
|
||||
public async changeAndSaveItems<M extends DecryptedItemMutator = DecryptedItemMutator>(
|
||||
itemsToLookupUuidsFor: DecryptedItemInterface[],
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps = true,
|
||||
emitSource?: Models.PayloadEmitSource,
|
||||
emitSource?: PayloadEmitSource,
|
||||
syncOptions?: SyncOptions,
|
||||
): Promise<void> {
|
||||
await this.itemManager.changeItems(
|
||||
itemsToLookupUuidsFor,
|
||||
mutate,
|
||||
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
|
||||
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
|
||||
emitSource,
|
||||
)
|
||||
await this.syncService.sync(syncOptions)
|
||||
}
|
||||
|
||||
public async changeItem<M extends Models.DecryptedItemMutator>(
|
||||
itemToLookupUuidFor: Models.DecryptedItemInterface,
|
||||
public async changeItem<M extends DecryptedItemMutator>(
|
||||
itemToLookupUuidFor: DecryptedItemInterface,
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps = true,
|
||||
): Promise<Models.DecryptedItemInterface | undefined> {
|
||||
): Promise<DecryptedItemInterface | undefined> {
|
||||
await this.itemManager.changeItems(
|
||||
[itemToLookupUuidFor],
|
||||
mutate,
|
||||
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
|
||||
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
|
||||
)
|
||||
return this.itemManager.findItem(itemToLookupUuidFor.uuid)
|
||||
}
|
||||
|
||||
public async changeItems<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
|
||||
itemsToLookupUuidsFor: Models.DecryptedItemInterface[],
|
||||
public async changeItems<M extends DecryptedItemMutator = DecryptedItemMutator>(
|
||||
itemsToLookupUuidsFor: DecryptedItemInterface[],
|
||||
mutate: (mutator: M) => void,
|
||||
updateTimestamps = true,
|
||||
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
|
||||
): Promise<(DecryptedItemInterface | undefined)[]> {
|
||||
return this.itemManager.changeItems(
|
||||
itemsToLookupUuidsFor,
|
||||
mutate,
|
||||
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
|
||||
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
|
||||
)
|
||||
}
|
||||
|
||||
public async runTransactionalMutations(
|
||||
transactions: TransactionalMutation[],
|
||||
emitSource = Models.PayloadEmitSource.LocalChanged,
|
||||
emitSource = PayloadEmitSource.LocalChanged,
|
||||
payloadSourceKey?: string,
|
||||
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
|
||||
): Promise<(DecryptedItemInterface | undefined)[]> {
|
||||
return this.itemManager.runTransactionalMutations(transactions, emitSource, payloadSourceKey)
|
||||
}
|
||||
|
||||
public async runTransactionalMutation(
|
||||
transaction: TransactionalMutation,
|
||||
emitSource = Models.PayloadEmitSource.LocalChanged,
|
||||
emitSource = PayloadEmitSource.LocalChanged,
|
||||
payloadSourceKey?: string,
|
||||
): Promise<Models.DecryptedItemInterface | undefined> {
|
||||
): Promise<DecryptedItemInterface | undefined> {
|
||||
return this.itemManager.runTransactionalMutation(transaction, emitSource, payloadSourceKey)
|
||||
}
|
||||
|
||||
async protectItems<M extends Models.DecryptedItemMutator, I extends Models.DecryptedItemInterface>(
|
||||
items: I[],
|
||||
): Promise<I[]> {
|
||||
async protectItems<M extends DecryptedItemMutator, I extends DecryptedItemInterface>(items: I[]): Promise<I[]> {
|
||||
const protectedItems = await this.itemManager.changeItems<M, I>(
|
||||
items,
|
||||
(mutator) => {
|
||||
mutator.protected = true
|
||||
},
|
||||
Models.MutationType.NoUpdateUserTimestamps,
|
||||
MutationType.NoUpdateUserTimestamps,
|
||||
)
|
||||
|
||||
void this.syncService.sync()
|
||||
return protectedItems
|
||||
}
|
||||
|
||||
async unprotectItems<M extends Models.DecryptedItemMutator, I extends Models.DecryptedItemInterface>(
|
||||
async unprotectItems<M extends DecryptedItemMutator, I extends DecryptedItemInterface>(
|
||||
items: I[],
|
||||
reason: ChallengeReason,
|
||||
): Promise<I[] | undefined> {
|
||||
@@ -166,74 +178,69 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
(mutator) => {
|
||||
mutator.protected = false
|
||||
},
|
||||
Models.MutationType.NoUpdateUserTimestamps,
|
||||
MutationType.NoUpdateUserTimestamps,
|
||||
)
|
||||
|
||||
void this.syncService.sync()
|
||||
return unprotectedItems
|
||||
}
|
||||
|
||||
public async protectNote(note: Models.SNNote): Promise<Models.SNNote> {
|
||||
public async protectNote(note: SNNote): Promise<SNNote> {
|
||||
const result = await this.protectItems([note])
|
||||
return result[0]
|
||||
}
|
||||
|
||||
public async unprotectNote(note: Models.SNNote): Promise<Models.SNNote | undefined> {
|
||||
public async unprotectNote(note: SNNote): Promise<SNNote | undefined> {
|
||||
const result = await this.unprotectItems([note], ChallengeReason.UnprotectNote)
|
||||
return result ? result[0] : undefined
|
||||
}
|
||||
|
||||
public async protectNotes(notes: Models.SNNote[]): Promise<Models.SNNote[]> {
|
||||
public async protectNotes(notes: SNNote[]): Promise<SNNote[]> {
|
||||
return this.protectItems(notes)
|
||||
}
|
||||
|
||||
public async unprotectNotes(notes: Models.SNNote[]): Promise<Models.SNNote[]> {
|
||||
public async unprotectNotes(notes: SNNote[]): Promise<SNNote[]> {
|
||||
const results = await this.unprotectItems(notes, ChallengeReason.UnprotectNote)
|
||||
return results || []
|
||||
}
|
||||
|
||||
async protectFile(file: Models.FileItem): Promise<Models.FileItem> {
|
||||
async protectFile(file: FileItem): Promise<FileItem> {
|
||||
const result = await this.protectItems([file])
|
||||
return result[0]
|
||||
}
|
||||
|
||||
async unprotectFile(file: Models.FileItem): Promise<Models.FileItem | undefined> {
|
||||
async unprotectFile(file: FileItem): Promise<FileItem | undefined> {
|
||||
const result = await this.unprotectItems([file], ChallengeReason.UnprotectFile)
|
||||
return result ? result[0] : undefined
|
||||
}
|
||||
|
||||
public async mergeItem(
|
||||
item: Models.DecryptedItemInterface,
|
||||
source: Models.PayloadEmitSource,
|
||||
): Promise<Models.DecryptedItemInterface> {
|
||||
public async mergeItem(item: DecryptedItemInterface, source: PayloadEmitSource): Promise<DecryptedItemInterface> {
|
||||
return this.itemManager.emitItemFromPayload(item.payloadRepresentation(), source)
|
||||
}
|
||||
|
||||
public createTemplateItem<
|
||||
C extends Models.ItemContent = Models.ItemContent,
|
||||
I extends Models.DecryptedItemInterface<C> = Models.DecryptedItemInterface<C>,
|
||||
C extends ItemContent = ItemContent,
|
||||
I extends DecryptedItemInterface<C> = DecryptedItemInterface<C>,
|
||||
>(contentType: ContentType, content?: C): I {
|
||||
return this.itemManager.createTemplateItem(contentType, content)
|
||||
}
|
||||
|
||||
public async setItemNeedsSync(
|
||||
item: Models.DecryptedItemInterface,
|
||||
item: DecryptedItemInterface,
|
||||
updateTimestamps = false,
|
||||
): Promise<Models.DecryptedItemInterface | undefined> {
|
||||
): Promise<DecryptedItemInterface | undefined> {
|
||||
return this.itemManager.setItemDirty(item, updateTimestamps)
|
||||
}
|
||||
|
||||
public async setItemsNeedsSync(
|
||||
items: Models.DecryptedItemInterface[],
|
||||
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
|
||||
public async setItemsNeedsSync(items: DecryptedItemInterface[]): Promise<(DecryptedItemInterface | undefined)[]> {
|
||||
return this.itemManager.setItemsDirty(items)
|
||||
}
|
||||
|
||||
public async deleteItem(item: Models.DecryptedItemInterface | Models.EncryptedItemInterface): Promise<void> {
|
||||
public async deleteItem(item: DecryptedItemInterface | EncryptedItemInterface): Promise<void> {
|
||||
return this.deleteItems([item])
|
||||
}
|
||||
|
||||
public async deleteItems(items: (Models.DecryptedItemInterface | Models.EncryptedItemInterface)[]): Promise<void> {
|
||||
public async deleteItems(items: (DecryptedItemInterface | EncryptedItemInterface)[]): Promise<void> {
|
||||
await this.itemManager.setItemsToBeDeleted(items)
|
||||
await this.syncService.sync()
|
||||
}
|
||||
@@ -243,7 +250,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
await this.syncService.sync()
|
||||
}
|
||||
|
||||
public duplicateItem<T extends Models.DecryptedItemInterface>(
|
||||
public duplicateItem<T extends DecryptedItemInterface>(
|
||||
item: T,
|
||||
additionalContent?: Partial<T['content']>,
|
||||
): Promise<T> {
|
||||
@@ -257,29 +264,29 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
return this.syncService.sync()
|
||||
}
|
||||
|
||||
public async setTagParent(parentTag: Models.SNTag, childTag: Models.SNTag): Promise<void> {
|
||||
public async setTagParent(parentTag: SNTag, childTag: SNTag): Promise<void> {
|
||||
await this.itemManager.setTagParent(parentTag, childTag)
|
||||
}
|
||||
|
||||
public async unsetTagParent(childTag: Models.SNTag): Promise<void> {
|
||||
public async unsetTagParent(childTag: SNTag): Promise<void> {
|
||||
await this.itemManager.unsetTagParent(childTag)
|
||||
}
|
||||
|
||||
public async findOrCreateTag(title: string): Promise<Models.SNTag> {
|
||||
public async findOrCreateTag(title: string): Promise<SNTag> {
|
||||
return this.itemManager.findOrCreateTagByTitle(title)
|
||||
}
|
||||
|
||||
/** Creates and returns the tag but does not run sync. Callers must perform sync. */
|
||||
public async createTagOrSmartView(title: string): Promise<Models.SNTag | Models.SmartView> {
|
||||
public async createTagOrSmartView(title: string): Promise<SNTag | SmartView> {
|
||||
return this.itemManager.createTagOrSmartView(title)
|
||||
}
|
||||
|
||||
public async toggleComponent(component: Models.SNComponent): Promise<void> {
|
||||
public async toggleComponent(component: SNComponent): Promise<void> {
|
||||
await this.componentManager.toggleComponent(component.uuid)
|
||||
await this.syncService.sync()
|
||||
}
|
||||
|
||||
public async toggleTheme(theme: Models.SNComponent): Promise<void> {
|
||||
public async toggleTheme(theme: SNComponent): Promise<void> {
|
||||
await this.componentManager.toggleTheme(theme.uuid)
|
||||
await this.syncService.sync()
|
||||
}
|
||||
@@ -289,7 +296,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
awaitSync = false,
|
||||
): Promise<
|
||||
| {
|
||||
affectedItems: Models.DecryptedItemInterface[]
|
||||
affectedItems: DecryptedItemInterface[]
|
||||
errorCount: number
|
||||
}
|
||||
| {
|
||||
@@ -342,7 +349,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
if (isEncryptedTransferPayload(item)) {
|
||||
return CreateEncryptedBackupFileContextPayload(item)
|
||||
} else {
|
||||
return CreateDecryptedBackupFileContextPayload(item as Models.BackupFileDecryptedContextualPayload)
|
||||
return CreateDecryptedBackupFileContextPayload(item as BackupFileDecryptedContextualPayload)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -355,9 +362,9 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
const validPayloads = decryptedPayloadsOrError.filter(isDecryptedPayload).map((payload) => {
|
||||
/* Don't want to activate any components during import process in
|
||||
* case of exceptions breaking up the import proccess */
|
||||
if (payload.content_type === ContentType.Component && (payload.content as Models.ComponentContent).active) {
|
||||
const typedContent = payload as Models.DecryptedPayloadInterface<Models.ComponentContent>
|
||||
return Models.CopyPayloadWithContentOverride(typedContent, {
|
||||
if (payload.content_type === ContentType.Component && (payload.content as ComponentContent).active) {
|
||||
const typedContent = payload as DecryptedPayloadInterface<ComponentContent>
|
||||
return CopyPayloadWithContentOverride(typedContent, {
|
||||
active: false,
|
||||
})
|
||||
} else {
|
||||
@@ -376,7 +383,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
|
||||
await promise
|
||||
}
|
||||
|
||||
const affectedItems = this.itemManager.findItems(affectedUuids) as Models.DecryptedItemInterface[]
|
||||
const affectedItems = this.itemManager.findItems(affectedUuids) as DecryptedItemInterface[]
|
||||
|
||||
return {
|
||||
affectedItems: affectedItems,
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './MutatorClientInterface'
|
||||
export * from './MutatorService'
|
||||
|
||||
Reference in New Issue
Block a user