refactor: merge themes into components (#2388)

This commit is contained in:
Mo
2023-08-06 08:52:19 -05:00
committed by GitHub
parent 1d60af0243
commit d2f8a36f19
33 changed files with 117 additions and 150 deletions

View File

@@ -12,10 +12,10 @@ import {
isThemeFeatureDescription,
} from '@standardnotes/features'
import { ComponentInterface } from '../../Syncable/Component/ComponentInterface'
import { isTheme } from '../../Syncable/Theme'
import { isItemBasedFeature, isNativeFeature } from './TypeGuards'
import { UIFeatureInterface } from './UIFeatureInterface'
import { Uuid } from '@standardnotes/domain-core'
import { ThemePackageInfo, isTheme } from '../../Syncable/Component'
export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeatureInterface<F> {
constructor(public readonly item: ComponentInterface | F) {}
@@ -40,6 +40,14 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
throw new Error('Cannot cast item to component')
}
get asTheme(): ComponentInterface<ThemePackageInfo> {
if (isItemBasedFeature(this.item)) {
return this.item
}
throw new Error('Cannot cast item to component')
}
get asFeatureDescription(): F {
if (isNativeFeature(this.item)) {
return this.item
@@ -145,7 +153,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
get layerable(): boolean {
if (isItemBasedFeature(this.item) && isTheme(this.item)) {
return this.item.layerable
return this.item.layerableTheme
} else if (isThemeFeatureDescription(this.asFeatureDescription)) {
return this.asFeatureDescription.layerable ?? false
}
@@ -155,7 +163,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
get dockIcon(): ThemeDockIcon | undefined {
if (isItemBasedFeature(this.item) && isTheme(this.item)) {
return this.item.package_info.dock_icon
return this.asTheme.package_info.dock_icon
} else if (isThemeFeatureDescription(this.asFeatureDescription)) {
return this.asFeatureDescription.dock_icon
}

View File

@@ -2,14 +2,14 @@ import { PayloadSource } from './../../Abstract/Payload/Types/PayloadSource'
import { DecryptedPayload } from './../../Abstract/Payload/Implementations/DecryptedPayload'
import { ContentType } from '@standardnotes/domain-core'
import { FillItemContent } from '../../Abstract/Content/ItemContent'
import { SNComponent } from './Component'
import { ComponentItem } from './Component'
import { ComponentContent } from './ComponentContent'
import { PayloadTimestampDefaults } from '../../Abstract/Payload'
import { NoteType } from '@standardnotes/features'
describe('component model', () => {
it('valid hosted url should ignore url', () => {
const component = new SNComponent(
const component = new ComponentItem(
new DecryptedPayload(
{
uuid: String(Math.random()),
@@ -29,7 +29,7 @@ describe('component model', () => {
})
it('invalid hosted url should fallback to url', () => {
const component = new SNComponent(
const component = new ComponentItem(
new DecryptedPayload(
{
uuid: String(Math.random()),
@@ -49,7 +49,7 @@ describe('component model', () => {
})
it('should return noteType as specified in package_info', () => {
const component = new SNComponent(
const component = new ComponentItem(
new DecryptedPayload(
{
uuid: String(Math.random()),
@@ -69,7 +69,7 @@ describe('component model', () => {
})
it('should return unknown as noteType if no note type defined in package_info', () => {
const component = new SNComponent(
const component = new ComponentItem(
new DecryptedPayload(
{
uuid: String(Math.random()),

View File

@@ -17,34 +17,16 @@ import { DecryptedPayloadInterface } from '../../Abstract/Payload/Interfaces/Dec
import { HistoryEntryInterface } from '../../Runtime/History'
import { ItemContent } from '../../Abstract/Content/ItemContent'
import { Predicate } from '../../Runtime/Predicate/Predicate'
import { ItemInterface } from '../../Abstract/Item/Interfaces/ItemInterface'
import { DecryptedItemInterface } from './../../Abstract/Item/Interfaces/DecryptedItem'
import { ComponentPackageInfo } from './PackageInfo'
import { isDecryptedItem } from '../../Abstract/Item'
import { ComponentPackageInfo, ThemePackageInfo } from './PackageInfo'
import { ContentType } from '@standardnotes/domain-core'
export function isComponent(x: ItemInterface): x is ComponentInterface {
if (!isDecryptedItem(x as DecryptedItemInterface)) {
return false
}
return x.content_type === ContentType.TYPES.Component
}
export function isComponentOrTheme(x: ItemInterface): x is ComponentInterface {
if (!isDecryptedItem(x as DecryptedItemInterface)) {
return false
}
return x.content_type === ContentType.TYPES.Component || x.content_type === ContentType.TYPES.Theme
}
/**
* Components are mostly iframe based extensions that communicate with the SN parent
* via the postMessage API. However, a theme can also be a component, which is activated
* only by its url.
*/
export class SNComponent extends DecryptedItem<ComponentContent> implements ComponentInterface {
export class ComponentItem extends DecryptedItem<ComponentContent> implements ComponentInterface {
public readonly legacyComponentData: Record<string, unknown>
/** Items that have requested a component to be disabled in its context */
public readonly disassociatedItemIds: string[]
@@ -61,7 +43,6 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
public readonly valid_until: Date
public readonly legacyActive: boolean
public readonly legacy_url?: string
public readonly isMobileDefault: boolean
constructor(payload: DecryptedPayloadInterface<ComponentContent>) {
super(payload)
@@ -78,13 +59,18 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
this.valid_until = new Date(payload.content.valid_until || 0)
this.offlineOnly = payload.content.offlineOnly ?? false
this.name = payload.content.name
this.area = payload.content.area
if (this.content_type === ContentType.TYPES.Theme) {
this.area = ComponentArea.Themes
} else {
this.area = payload.content.area
}
this.package_info = payload.content.package_info || {}
this.permissions = payload.content.permissions || []
this.autoupdateDisabled = payload.content.autoupdateDisabled ?? false
this.disassociatedItemIds = payload.content.disassociatedItemIds || []
this.associatedItemIds = payload.content.associatedItemIds || []
this.isMobileDefault = payload.content.isMobileDefault ?? false
/**
* @legacy
@@ -116,15 +102,11 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
return FindNativeFeature(this.identifier)?.name || this.name
}
public override singletonPredicate(): Predicate<SNComponent> {
const uniqueIdentifierPredicate = new Predicate<SNComponent>('identifier', '=', this.identifier)
public override singletonPredicate(): Predicate<ComponentItem> {
const uniqueIdentifierPredicate = new Predicate<ComponentItem>('identifier', '=', this.identifier)
return uniqueIdentifierPredicate
}
public isEditor(): boolean {
return this.area === ComponentArea.Editor
}
public isTheme(): boolean {
return this.content_type === ContentType.TYPES.Theme || this.area === ComponentArea.Themes
}
@@ -134,10 +116,6 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
return this.getAppDomainValue(AppDataField.DefaultEditor) === true
}
public getLastSize(): unknown {
return this.getAppDomainValue(AppDataField.LastSize)
}
public hasValidHostedUrl(): boolean {
return (this.hosted_url || this.legacy_url) != undefined
}
@@ -149,19 +127,6 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
return [...componentKeys, ...superKeys] as (keyof ItemContent)[]
}
/**
* An associative component depends on being explicitly activated for a
* given item, compared to a dissaciative component, which is enabled by
* default in areas unrelated to a certain item.
*/
public static associativeAreas(): ComponentArea[] {
return [ComponentArea.Editor]
}
public isAssociative(): boolean {
return SNComponent.associativeAreas().includes(this.area)
}
public isExplicitlyEnabledForItem(uuid: string): boolean {
return this.associatedItemIds.indexOf(uuid) !== -1
}
@@ -199,4 +164,13 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
public get deprecationMessage(): string | undefined {
return this.package_info.deprecation_message
}
get layerableTheme(): boolean {
if (!this.isTheme()) {
return false
}
const themePackageInfo = this.package_info as ThemePackageInfo
return themePackageInfo?.layerable ?? false
}
}

View File

@@ -21,7 +21,6 @@ export type ComponentContentSpecialized = {
valid_until: Date | number
legacy_url?: string
isMobileDefault?: boolean
isDeprecated?: boolean
/** @deprecated */

View File

@@ -1,9 +1,10 @@
import { ComponentArea, ComponentPermission, NoteType, ThirdPartyFeatureDescription } from '@standardnotes/features'
import { ComponentPackageInfo } from './PackageInfo'
import { ComponentPackageInfo, ThemePackageInfo } from './PackageInfo'
import { DecryptedItemInterface } from '../../Abstract/Item'
import { ComponentContent } from './ComponentContent'
export interface ComponentInterface extends DecryptedItemInterface<ComponentContent> {
export interface ComponentInterface<P extends ComponentPackageInfo | ThemePackageInfo = ComponentPackageInfo>
extends DecryptedItemInterface<ComponentContent> {
/** Items that have requested a component to be disabled in its context */
disassociatedItemIds: string[]
@@ -16,16 +17,18 @@ export interface ComponentInterface extends DecryptedItemInterface<ComponentCont
offlineOnly: boolean
name: string
autoupdateDisabled: boolean
package_info: ComponentPackageInfo
package_info: P
area: ComponentArea
permissions: ComponentPermission[]
valid_until: Date
isMobileDefault: boolean
isDeprecated: boolean
isExplicitlyEnabledForItem(uuid: string): boolean
hasValidHostedUrl(): boolean
isTheme(): boolean
get layerableTheme(): boolean
isExplicitlyDisabledForItem(uuid: string): boolean
legacyIsDefaultEditor(): boolean

View File

@@ -1,14 +1,9 @@
import { addIfUnique, removeFromArray } from '@standardnotes/utils'
import { ComponentFeatureDescription, ComponentPermission } from '@standardnotes/features'
import { AppDataField } from '../../Abstract/Item/Types/AppDataField'
import { ComponentContent } from './ComponentContent'
import { DecryptedItemMutator } from '../../Abstract/Item/Mutator/DecryptedItemMutator'
export class ComponentMutator extends DecryptedItemMutator<ComponentContent> {
set isMobileDefault(isMobileDefault: boolean) {
this.mutableContent.isMobileDefault = isMobileDefault
}
set package_info(package_info: ComponentFeatureDescription) {
this.mutableContent.package_info = package_info
}
@@ -56,8 +51,4 @@ export class ComponentMutator extends DecryptedItemMutator<ComponentContent> {
public removeDisassociatedItemId(uuid: string): void {
removeFromArray(this.mutableContent.disassociatedItemIds || [], uuid)
}
public setLastSize(size: string): void {
this.setAppDataItem(AppDataField.LastSize, size)
}
}

View File

@@ -0,0 +1,29 @@
import { ComponentInterface } from './ComponentInterface'
import { ItemInterface } from '../../Abstract/Item/Interfaces/ItemInterface'
import { DecryptedItemInterface } from '../../Abstract/Item/Interfaces/DecryptedItem'
import { isDecryptedItem } from '../../Abstract/Item'
import { ContentType } from '@standardnotes/domain-core'
export function isComponent(x: ItemInterface): x is ComponentInterface {
if (!isDecryptedItem(x as DecryptedItemInterface)) {
return false
}
return x.content_type === ContentType.TYPES.Component
}
export function isTheme(x: ItemInterface): x is ComponentInterface {
if (!isDecryptedItem(x as DecryptedItemInterface)) {
return false
}
return x.content_type === ContentType.TYPES.Theme
}
export function isComponentOrTheme(x: ItemInterface): x is ComponentInterface {
if (!isDecryptedItem(x as DecryptedItemInterface)) {
return false
}
return x.content_type === ContentType.TYPES.Component || x.content_type === ContentType.TYPES.Theme
}

View File

@@ -2,5 +2,5 @@ export * from './Component'
export * from './ComponentMutator'
export * from './ComponentContent'
export * from './ComponentInterface'
export * from '../../Runtime/Feature/UIFeature'
export * from './PackageInfo'
export * from './TypeGuards'

View File

@@ -14,7 +14,7 @@ interface EditorContent extends ItemContent {
/**
* @deprecated
* Editor objects are depracated in favor of SNComponent objects
* Editor objects are depracated in favor of ComponentItem objects
*/
export class SNEditor extends DecryptedItem<EditorContent> {
public readonly notes: SNNote[] = []

View File

@@ -1,18 +0,0 @@
import { ComponentArea } from '@standardnotes/features'
import { SNComponent } from '../Component/Component'
import { ItemInterface } from '../../Abstract/Item'
import { ContentType } from '@standardnotes/domain-core'
import { useBoolean } from '@standardnotes/utils'
import { ThemePackageInfo } from '../Component/PackageInfo'
import { ThemeInterface } from './ThemeInterface'
export const isTheme = (x: ItemInterface): x is ThemeInterface => x.content_type === ContentType.TYPES.Theme
export class SNTheme extends SNComponent implements ThemeInterface {
public override area: ComponentArea = ComponentArea.Themes
public declare readonly package_info: ThemePackageInfo
get layerable(): boolean {
return useBoolean(this.package_info && this.package_info.layerable, false)
}
}

View File

@@ -1,7 +0,0 @@
import { ComponentInterface } from '../Component'
import { ThemePackageInfo } from '../Component/PackageInfo'
export interface ThemeInterface extends ComponentInterface {
get layerable(): boolean
readonly package_info: ThemePackageInfo
}

View File

@@ -1,4 +0,0 @@
import { ComponentContent } from '../Component/ComponentContent'
import { DecryptedItemMutator } from '../../Abstract/Item/Mutator/DecryptedItemMutator'
export class ThemeMutator extends DecryptedItemMutator<ComponentContent> {}

View File

@@ -1,3 +0,0 @@
export * from './Theme'
export * from './ThemeMutator'
export * from './ThemeInterface'

View File

@@ -3,17 +3,15 @@ import { DecryptedPayloadInterface } from '../../Abstract/Payload/Interfaces/Dec
import { FileItem } from '../../Syncable/File/File'
import { SNFeatureRepo } from '../../Syncable/FeatureRepo/FeatureRepo'
import { SNActionsExtension } from '../../Syncable/ActionsExtension/ActionsExtension'
import { SNComponent } from '../../Syncable/Component/Component'
import { ComponentItem } from '../../Syncable/Component/Component'
import { SNEditor } from '../../Syncable/Editor/Editor'
import { DecryptedItem } from '../../Abstract/Item/Implementations/DecryptedItem'
import { SNNote } from '../../Syncable/Note/Note'
import { SmartView } from '../../Syncable/SmartView/SmartView'
import { SNTag } from '../../Syncable/Tag/Tag'
import { SNTheme } from '../../Syncable/Theme/Theme'
import { SNUserPrefs } from '../../Syncable/UserPrefs/UserPrefs'
import { FileMutator } from '../../Syncable/File/FileMutator'
import { MutationType } from '../../Abstract/Item/Types/MutationType'
import { ThemeMutator } from '../../Syncable/Theme/ThemeMutator'
import { UserPrefsMutator } from '../../Syncable/UserPrefs/UserPrefsMutator'
import { ActionsExtensionMutator } from '../../Syncable/ActionsExtension/ActionsExtensionMutator'
import { ComponentMutator } from '../../Syncable/Component/ComponentMutator'
@@ -58,7 +56,7 @@ const ContentTypeClassMapping: Partial<Record<string, MappingEntry>> = {
itemClass: SNActionsExtension,
mutatorClass: ActionsExtensionMutator,
},
[ContentType.TYPES.Component]: { itemClass: SNComponent, mutatorClass: ComponentMutator },
[ContentType.TYPES.Component]: { itemClass: ComponentItem, mutatorClass: ComponentMutator },
[ContentType.TYPES.KeySystemRootKey]: { itemClass: KeySystemRootKey, mutatorClass: KeySystemRootKeyMutator },
[ContentType.TYPES.TrustedContact]: { itemClass: TrustedContact, mutatorClass: TrustedContactMutator },
[ContentType.TYPES.VaultListing]: { itemClass: VaultListing, mutatorClass: VaultListingMutator },
@@ -68,7 +66,7 @@ const ContentTypeClassMapping: Partial<Record<string, MappingEntry>> = {
[ContentType.TYPES.Note]: { itemClass: SNNote, mutatorClass: NoteMutator },
[ContentType.TYPES.SmartView]: { itemClass: SmartView, mutatorClass: SmartViewMutator },
[ContentType.TYPES.Tag]: { itemClass: SNTag, mutatorClass: TagMutator },
[ContentType.TYPES.Theme]: { itemClass: SNTheme, mutatorClass: ThemeMutator },
[ContentType.TYPES.Theme]: { itemClass: ComponentItem, mutatorClass: ComponentMutator },
[ContentType.TYPES.UserPrefs]: { itemClass: SNUserPrefs, mutatorClass: UserPrefsMutator },
} as unknown as Partial<Record<string, MappingEntry>>

View File

@@ -93,7 +93,6 @@ export * from './Syncable/ItemsKey/ItemsKeyMutatorInterface'
export * from './Syncable/Note'
export * from './Syncable/SmartView'
export * from './Syncable/Tag'
export * from './Syncable/Theme'
export * from './Syncable/UserPrefs'
export * from './Syncable/TrustedContact/TrustedContact'

View File

@@ -20,7 +20,6 @@ import {
FileItem,
VaultDisplayOptions,
NotesAndFilesDisplayControllerOptions,
ThemeInterface,
ComponentInterface,
ItemStream,
} from '@standardnotes/models'
@@ -123,7 +122,7 @@ export interface ItemManagerInterface extends AbstractService {
getTagParent(itemToLookupUuidFor: SNTag): SNTag | undefined
isValidTagParent(parentTagToLookUpUuidFor: SNTag, childToLookUpUuidFor: SNTag): boolean
isSmartViewTitle(title: string): boolean
getDisplayableComponents(): (ComponentInterface | ThemeInterface)[]
getDisplayableComponents(): ComponentInterface[]
createItemFromPayload<T extends DecryptedItemInterface>(payload: DecryptedPayloadInterface): T
createPayloadFromObject(object: DecryptedTransferPayload): DecryptedPayloadInterface
getDisplayableFiles(): FileItem[]

View File

@@ -12,7 +12,7 @@ import { SignInWithRecoveryCodes } from '../../Domain/UseCase/SignInWithRecovery
import { ListedService } from '../../Services/Listed/ListedService'
import { MigrationService } from '../../Services/Migration/MigrationService'
import { MfaService } from '../../Services/Mfa/MfaService'
import { SNComponentManager } from '../../Services/ComponentManager/ComponentManager'
import { ComponentManager } from '../../Services/ComponentManager/ComponentManager'
import { FeaturesService } from '@Lib/Services/Features/FeaturesService'
import { SettingsService } from '../../Services/Settings/SNSettingsService'
import { PreferencesService } from '../../Services/Preferences/PreferencesService'
@@ -1107,7 +1107,7 @@ export class Dependencies {
})
this.factory.set(TYPES.ComponentManager, () => {
return new SNComponentManager(
return new ComponentManager(
this.get<ItemManager>(TYPES.ItemManager),
this.get<MutatorService>(TYPES.MutatorService),
this.get<SyncService>(TYPES.SyncService),

View File

@@ -1,7 +1,7 @@
import { ApplicationStage } from '@standardnotes/services'
import { Migration } from '@Lib/Migrations/Migration'
import { ThemeInterface } from '@standardnotes/models'
import { ContentType } from '@standardnotes/domain-core'
import { ComponentInterface } from '@standardnotes/models'
const NoDistractionIdentifier = 'org.standardnotes.theme-no-distraction'
@@ -18,7 +18,7 @@ export class Migration2_42_0 extends Migration {
}
private async deleteNoDistraction(): Promise<void> {
const themes = this.services.itemManager.getItems<ThemeInterface>(ContentType.TYPES.Theme).filter((theme) => {
const themes = this.services.itemManager.getItems<ComponentInterface>(ContentType.TYPES.Theme).filter((theme) => {
return theme.identifier === NoDistractionIdentifier
})

View File

@@ -1,4 +1,4 @@
import { CompoundPredicate, Predicate, SNComponent } from '@standardnotes/models'
import { CompoundPredicate, Predicate, ComponentItem } from '@standardnotes/models'
import { Migration } from '@Lib/Migrations/Migration'
import { ApplicationStage } from '@standardnotes/services'
import { ContentType } from '@standardnotes/domain-core'
@@ -19,8 +19,8 @@ export class Migration2_7_0 extends Migration {
const batchMgrId = 'org.standardnotes.batch-manager'
const batchMgrPred = new CompoundPredicate('and', [
new Predicate<SNComponent>('content_type', '=', ContentType.TYPES.Component),
new Predicate<SNComponent>('identifier', '=', batchMgrId),
new Predicate<ComponentItem>('content_type', '=', ContentType.TYPES.Component),
new Predicate<ComponentItem>('identifier', '=', batchMgrId),
])
const batchMgrSingleton = this.services.singletonManager.findSingleton(ContentType.TYPES.Component, batchMgrPred)

View File

@@ -11,7 +11,7 @@ import {
} from '@standardnotes/services'
import { ItemManager } from '@Lib/Services/Items/ItemManager'
import { FeaturesService } from '@Lib/Services/Features/FeaturesService'
import { SNComponentManager } from './ComponentManager'
import { ComponentManager } from './ComponentManager'
import { SyncService } from '../Sync/SyncService'
import { LoggerInterface } from '@standardnotes/utils'
@@ -27,7 +27,7 @@ describe('featuresService', () => {
let logger: LoggerInterface
const createManager = (environment: Environment, platform: Platform) => {
const manager = new SNComponentManager(
const manager = new ComponentManager(
items,
mutator,
sync,

View File

@@ -69,7 +69,7 @@ declare global {
* 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
export class ComponentManager
extends AbstractService<ComponentManagerEvent, ComponentManagerEventData>
implements ComponentManagerInterface
{

View File

@@ -1,7 +1,7 @@
import { ItemManagerInterface, PreferenceServiceInterface } from '@standardnotes/services'
import { GetDefaultEditorIdentifier } from './GetDefaultEditorIdentifier'
import { ComponentArea, NativeFeatureIdentifier } from '@standardnotes/features'
import { SNComponent, SNTag } from '@standardnotes/models'
import { ComponentItem, SNTag } from '@standardnotes/models'
describe('getDefaultEditorIdentifier', () => {
let usecase: GetDefaultEditorIdentifier
@@ -49,7 +49,7 @@ describe('getDefaultEditorIdentifier', () => {
legacyIsDefaultEditor: jest.fn().mockReturnValue(true),
identifier: NativeFeatureIdentifier.TYPES.MarkdownProEditor,
area: ComponentArea.Editor,
} as unknown as jest.Mocked<SNComponent>
} as unknown as jest.Mocked<ComponentItem>
items.getDisplayableComponents = jest.fn().mockReturnValue([editor])

View File

@@ -13,7 +13,7 @@ import {
Environment,
PayloadTimestampDefaults,
Platform,
SNComponent,
ComponentItem,
UIFeature,
} from '@standardnotes/models'
import { DesktopManagerInterface } from '@standardnotes/services'
@@ -26,7 +26,7 @@ const nativeFeatureAsUIFeature = <F extends UIFeatureDescriptionTypes>(identifie
}
const thirdPartyFeature = () => {
const component = new SNComponent(
const component = new ComponentItem(
new DecryptedPayload({
uuid: '789',
content_type: ContentType.TYPES.Component,
@@ -101,7 +101,7 @@ describe('GetFeatureUrl', () => {
})
it('returns hosted url for third party component with no local_url', () => {
const component = new SNComponent({
const component = new ComponentItem({
uuid: '789',
content_type: ContentType.TYPES.Component,
content: {

View File

@@ -15,7 +15,6 @@ import {
FillItemContent,
PayloadEmitSource,
ComponentInterface,
ThemeInterface,
DecryptedItemInterface,
} from '@standardnotes/models'
import {
@@ -191,7 +190,7 @@ export class FeaturesService
void this.storage.setValue(StorageKey.ExperimentalFeatures, this.enabledExperimentalFeatures)
const component = this.items
.getItems<ComponentInterface | ThemeInterface>([ContentType.TYPES.Component, ContentType.TYPES.Theme])
.getItems<ComponentInterface>([ContentType.TYPES.Component, ContentType.TYPES.Theme])
.find((component) => component.identifier === identifier)
if (!component) {
return

View File

@@ -37,7 +37,7 @@ export class ItemManager extends Services.AbstractService implements Services.It
private tagDisplayController!: Models.ItemDisplayController<Models.SNTag, Models.TagsDisplayOptions>
private itemsKeyDisplayController!: Models.ItemDisplayController<SNItemsKey>
private componentDisplayController!: Models.ItemDisplayController<Models.ComponentInterface>
private themeDisplayController!: Models.ItemDisplayController<Models.ThemeInterface>
private themeDisplayController!: Models.ItemDisplayController<Models.ComponentInterface>
private fileDisplayController!: Models.ItemDisplayController<Models.FileItem>
private smartViewDisplayController!: Models.ItemDisplayController<Models.SmartView>
@@ -225,7 +225,7 @@ export class ItemManager extends Services.AbstractService implements Services.It
return this.itemsKeyDisplayController.items()
}
public getDisplayableComponents(): (Models.ComponentInterface | Models.ThemeInterface)[] {
public getDisplayableComponents(): Models.ComponentInterface[] {
return [...this.componentDisplayController.items(), ...this.themeDisplayController.items()]
}

View File

@@ -1,4 +1,4 @@
import { UIFeature, ThemeInterface } from '@standardnotes/models'
import { UIFeature, ComponentInterface } from '@standardnotes/models'
import { ItemManagerInterface } from '@standardnotes/services'
import { NativeFeatureIdentifier, FindNativeTheme, ThemeFeatureDescription } from '@standardnotes/features'
import { Uuid } from '@standardnotes/domain-core'
@@ -54,7 +54,7 @@ export class ActiveThemeList {
for (const entry of this.list) {
if (entry instanceof Uuid) {
const theme = this.items.findItem<ThemeInterface>(entry.value)
const theme = this.items.findItem<ComponentInterface>(entry.value)
if (theme) {
const uiFeature = new UIFeature<ThemeFeatureDescription>(theme)
results.push(uiFeature)

View File

@@ -1,5 +1,5 @@
import { FindNativeTheme, GetNativeThemes, ThemeFeatureDescription } from '@standardnotes/features'
import { UIFeature, ThemeInterface } from '@standardnotes/models'
import { ComponentInterface, UIFeature } from '@standardnotes/models'
import { ItemManagerInterface } from '@standardnotes/services'
export class GetAllThemesUseCase {
@@ -15,10 +15,10 @@ export class GetAllThemesUseCase {
.getDisplayableComponents()
.filter(
(component) => component.isTheme() && FindNativeTheme(component.identifier) === undefined,
) as ThemeInterface[]
) as ComponentInterface[]
const filteredThirdPartyThemes = allThirdPartyThemes.filter((theme) => {
return options.excludeLayerable ? !theme.layerable : true
return options.excludeLayerable ? !theme.layerableTheme : true
})
return {

View File

@@ -4,8 +4,8 @@ import {
CreateDecryptedLocalStorageContextPayload,
LocalStorageDecryptedContextualPayload,
PrefKey,
ThemeInterface,
PrefDefaults,
ComponentInterface,
} from '@standardnotes/models'
import {
InternalEventBusInterface,
@@ -113,7 +113,7 @@ export class ThemeManager extends AbstractUIServicee {
for (const uuid of uuids) {
if (!this.themesActiveInTheUI.has(uuid)) {
const theme = this.application.items.findItem<ThemeInterface>(uuid.value)
const theme = this.application.items.findItem<ComponentInterface>(uuid.value)
if (theme) {
const uiFeature = new UIFeature<ThemeFeatureDescription>(theme)
this.activateTheme(uiFeature)
@@ -444,7 +444,7 @@ export class ThemeManager extends AbstractUIServicee {
for (const cachedTheme of cachedThemes) {
if ('uuid' in cachedTheme) {
const payload = this.application.items.createPayloadFromObject(cachedTheme)
const theme = this.application.items.createItemFromPayload<ThemeInterface>(payload)
const theme = this.application.items.createItemFromPayload<ComponentInterface>(payload)
features.push(new UIFeature<ThemeFeatureDescription>(theme))
} else if ('identifier' in cachedTheme) {
const feature = FindNativeTheme((cachedTheme as ThemeFeatureDescription).identifier)

View File

@@ -1,6 +1,6 @@
import { HeadlessSuperConverter } from '@/Components/SuperEditor/Tools/HeadlessSuperConverter'
import {
SNComponent,
ComponentItem,
ComponentMutator,
AppDataField,
ApplicationService,
@@ -26,7 +26,7 @@ export class DesktopManager
implements DesktopManagerInterface, DesktopClientRequiresWebMethods
{
updateObservers: {
callback: (component: SNComponent) => void
callback: (component: ComponentItem) => void
}[] = []
dataLoaded = false
@@ -204,7 +204,7 @@ export class DesktopManager
).getValue()
for (const observer of this.updateObservers) {
observer.callback(updatedComponent as SNComponent)
observer.callback(updatedComponent as ComponentItem)
}
}
}

View File

@@ -1,8 +1,8 @@
import { WebApplication } from '@/Application/WebApplication'
import { ContentType } from '@standardnotes/domain-core'
import {
SNComponentManager,
SNComponent,
ComponentManager,
ComponentItem,
SNTag,
SNNote,
Deferred,
@@ -16,7 +16,7 @@ import { NoteViewController } from './NoteViewController'
describe('note view controller', () => {
let application: WebApplication
let componentManager: SNComponentManager
let componentManager: ComponentManager
beforeEach(() => {
application = {
@@ -35,7 +35,7 @@ describe('note view controller', () => {
Object.defineProperty(application, 'sync', { value: {} as jest.Mocked<SyncServiceInterface> })
application.sync.sync = jest.fn().mockReturnValue(Promise.resolve())
componentManager = {} as jest.Mocked<SNComponentManager>
componentManager = {} as jest.Mocked<ComponentManager>
Object.defineProperty(application, 'componentManager', { value: componentManager })
})
@@ -68,7 +68,7 @@ describe('note view controller', () => {
application.items.getDisplayableComponents = jest.fn().mockReturnValue([
{
identifier: NativeFeatureIdentifier.TYPES.MarkdownProEditor,
} as SNComponent,
} as ComponentItem,
])
application.componentManager.getDefaultEditorIdentifier = jest

View File

@@ -1,5 +1,5 @@
import { FunctionComponent, useState } from 'react'
import { ComponentInterface, ComponentMutator, SNComponent } from '@standardnotes/snjs'
import { ComponentInterface, ComponentMutator, ComponentItem } from '@standardnotes/snjs'
import { SubtitleLight } from '@/Components/Preferences/PreferencesComponents/Content'
import Switch from '@/Components/Switch/Switch'
import Button from '@/Components/Button/Button'
@@ -28,7 +28,7 @@ interface PackageEntryProps {
}
const PackageEntry: FunctionComponent<PackageEntryProps> = ({ application, extension, uninstall }) => {
const [offlineOnly, setOfflineOnly] = useState(extension instanceof SNComponent ? extension.offlineOnly : false)
const [offlineOnly, setOfflineOnly] = useState(extension instanceof ComponentItem ? extension.offlineOnly : false)
const [extensionName, setExtensionName] = useState(extension.displayName)
const toggleOfflineOnly = () => {

View File

@@ -45,7 +45,7 @@ const PackagesPreferencesSection: FunctionComponent<Props> = ({
application.alerts
.confirm(
'Are you sure you want to uninstall this plugin? Note that plugins managed by your subscription will automatically be re-installed on application restart.',
'Uninstall Extension?',
'Uninstall Plugin?',
'Uninstall',
ButtonType.Danger,
'Cancel',

View File

@@ -1,3 +1,3 @@
import { ComponentInterface, SNActionsExtension, ThemeInterface } from '@standardnotes/snjs'
import { ComponentInterface, SNActionsExtension } from '@standardnotes/snjs'
export type AnyPackageType = ComponentInterface | ThemeInterface | SNActionsExtension
export type AnyPackageType = ComponentInterface | SNActionsExtension