refactor: component manager usecases (#2354)

This commit is contained in:
Mo
2023-07-13 05:46:52 -05:00
committed by GitHub
parent ecc5b5e503
commit 2c68ea1d76
52 changed files with 1454 additions and 1078 deletions

View File

@@ -0,0 +1,77 @@
import {
AnyFeatureDescription,
ComponentArea,
EditorFeatureDescription,
IframeComponentFeatureDescription,
NoteType,
UIFeatureDescriptionTypes,
} from '@standardnotes/features'
import {
isUIFeatureAnIframeFeature,
isComponentOrFeatureDescriptionAComponent,
isComponentOrFeatureDescriptionAFeatureDescription,
} from './TypeGuards'
import { UIFeature } from './UIFeature'
import { ComponentInterface } from '../../Syncable/Component'
import { ContentType } from '@standardnotes/domain-core'
describe('TypeGuards', () => {
describe('isUIFeatureAnIframeFeature', () => {
it('should return true if feature is IframeUIFeature', () => {
const x: UIFeature<IframeComponentFeatureDescription> = {
featureDescription: {
content_type: ContentType.TYPES.Component,
area: ComponentArea.Editor,
},
} as jest.Mocked<UIFeature<IframeComponentFeatureDescription>>
expect(isUIFeatureAnIframeFeature(x)).toBe(true)
})
it('should return false if feature is not IframeUIFeature', () => {
const x: UIFeature<EditorFeatureDescription> = {
featureDescription: {
note_type: NoteType.Super,
},
} as jest.Mocked<UIFeature<EditorFeatureDescription>>
expect(isUIFeatureAnIframeFeature(x)).toBe(false)
})
})
describe('isFeatureAComponent', () => {
it('should return true if feature is a Component', () => {
const x: ComponentInterface | UIFeatureDescriptionTypes = {
uuid: 'abc-123',
} as ComponentInterface
expect(isComponentOrFeatureDescriptionAComponent(x)).toBe(true)
})
it('should return false if feature description is not a component', () => {
const x: EditorFeatureDescription = {
note_type: NoteType.Super,
} as jest.Mocked<EditorFeatureDescription>
expect(isComponentOrFeatureDescriptionAComponent(x)).toBe(false)
})
})
describe('isComponentOrFeatureDescriptionAFeatureDescription', () => {
it('should return true if x is a feature description', () => {
const x: AnyFeatureDescription = {
content_type: 'TestContentType',
} as AnyFeatureDescription
expect(isComponentOrFeatureDescriptionAFeatureDescription(x)).toBe(true)
})
it('should return false if x is a component', () => {
const x: ComponentInterface = {
uuid: 'abc-123',
} as ComponentInterface
expect(isComponentOrFeatureDescriptionAFeatureDescription(x)).toBe(false)
})
})
})

View File

@@ -0,0 +1,27 @@
import {
AnyFeatureDescription,
EditorFeatureDescription,
IframeComponentFeatureDescription,
UIFeatureDescriptionTypes,
isIframeComponentFeatureDescription,
} from '@standardnotes/features'
import { UIFeatureInterface } from './UIFeatureInterface'
import { ComponentInterface } from '../../Syncable/Component'
export function isUIFeatureAnIframeFeature(
x: UIFeatureInterface<EditorFeatureDescription | IframeComponentFeatureDescription>,
): x is UIFeatureInterface<IframeComponentFeatureDescription> {
return isIframeComponentFeatureDescription(x.featureDescription)
}
export function isComponentOrFeatureDescriptionAComponent(
x: ComponentInterface | UIFeatureDescriptionTypes,
): x is ComponentInterface {
return 'uuid' in x
}
export function isComponentOrFeatureDescriptionAFeatureDescription(
x: ComponentInterface | AnyFeatureDescription,
): x is AnyFeatureDescription {
return !('uuid' in x)
}

View File

@@ -0,0 +1,167 @@
import {
ComponentArea,
ComponentPermission,
EditorFeatureDescription,
FeatureIdentifier,
NoteType,
ThemeDockIcon,
UIFeatureDescriptionTypes,
isEditorFeatureDescription,
isIframeComponentFeatureDescription,
isThemeFeatureDescription,
} from '@standardnotes/features'
import { ComponentInterface } from '../../Syncable/Component/ComponentInterface'
import { isTheme } from '../../Syncable/Theme'
import {
isComponentOrFeatureDescriptionAComponent,
isComponentOrFeatureDescriptionAFeatureDescription,
} from './TypeGuards'
import { UIFeatureInterface } from './UIFeatureInterface'
export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeatureInterface<F> {
constructor(public readonly item: ComponentInterface | F) {}
get isComponent(): boolean {
return isComponentOrFeatureDescriptionAComponent(this.item)
}
get isFeatureDescription(): boolean {
return isComponentOrFeatureDescriptionAFeatureDescription(this.item)
}
get isThemeComponent(): boolean {
return isComponentOrFeatureDescriptionAComponent(this.item) && isTheme(this.item)
}
get asComponent(): ComponentInterface {
if (isComponentOrFeatureDescriptionAComponent(this.item)) {
return this.item
}
throw new Error('Cannot cast item to component')
}
get asFeatureDescription(): F {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item
}
throw new Error('Cannot cast item to feature description')
}
get uniqueIdentifier(): string {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item.identifier
} else {
return this.item.uuid
}
}
get featureIdentifier(): FeatureIdentifier {
return this.item.identifier
}
get noteType(): NoteType {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item) && isEditorFeatureDescription(this.item)) {
return this.item.note_type ?? NoteType.Unknown
} else if (isComponentOrFeatureDescriptionAComponent(this.item)) {
return this.item.noteType
}
throw new Error('Invalid component or feature description')
}
get fileType(): EditorFeatureDescription['file_type'] {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item) && isEditorFeatureDescription(this.item)) {
return this.item.file_type
} else if (
isComponentOrFeatureDescriptionAComponent(this.item) &&
isEditorFeatureDescription(this.item.package_info)
) {
return this.item.package_info?.file_type ?? 'txt'
}
throw new Error('Invalid component or feature description')
}
get displayName(): string {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item.name ?? ''
} else {
return this.item.displayName
}
}
get description(): string {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item.description ?? ''
} else {
return this.item.package_info.description ?? ''
}
}
get deprecationMessage(): string | undefined {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item.deprecation_message
} else {
return this.item.deprecationMessage
}
}
get expirationDate(): Date | undefined {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item.expires_at ? new Date(this.item.expires_at) : undefined
} else {
return this.item.valid_until
}
}
get featureDescription(): F {
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
return this.item
} else {
return this.item.package_info as F
}
}
get acquiredPermissions(): ComponentPermission[] {
if (
isComponentOrFeatureDescriptionAFeatureDescription(this.item) &&
isIframeComponentFeatureDescription(this.item)
) {
return this.item.component_permissions ?? []
} else if (isComponentOrFeatureDescriptionAComponent(this.item)) {
return this.item.permissions
}
throw new Error('Invalid component or feature description')
}
get area(): ComponentArea {
if ('area' in this.item) {
return this.item.area
}
return ComponentArea.Editor
}
get layerable(): boolean {
if (isComponentOrFeatureDescriptionAComponent(this.item) && isTheme(this.item)) {
return this.item.layerable
} else if (isThemeFeatureDescription(this.asFeatureDescription)) {
return this.asFeatureDescription.layerable ?? false
}
return false
}
get dockIcon(): ThemeDockIcon | undefined {
if (isComponentOrFeatureDescriptionAComponent(this.item) && isTheme(this.item)) {
return this.item.package_info.dock_icon
} else if (isThemeFeatureDescription(this.asFeatureDescription)) {
return this.asFeatureDescription.dock_icon
}
return undefined
}
}

View File

@@ -0,0 +1,32 @@
import {
ComponentArea,
ComponentPermission,
EditorFeatureDescription,
FeatureIdentifier,
NoteType,
ThemeDockIcon,
UIFeatureDescriptionTypes,
} from '@standardnotes/features'
import { ComponentInterface } from '../../Syncable/Component'
export interface UIFeatureInterface<F extends UIFeatureDescriptionTypes> {
item: ComponentInterface | F
get isComponent(): boolean
get isFeatureDescription(): boolean
get isThemeComponent(): boolean
get asComponent(): ComponentInterface
get asFeatureDescription(): F
get uniqueIdentifier(): string
get featureIdentifier(): FeatureIdentifier
get noteType(): NoteType
get fileType(): EditorFeatureDescription['file_type']
get displayName(): string
get description(): string
get deprecationMessage(): string | undefined
get expirationDate(): Date | undefined
get featureDescription(): F
get acquiredPermissions(): ComponentPermission[]
get area(): ComponentArea
get layerable(): boolean
get dockIcon(): ThemeDockIcon | undefined
}