refactor: native feature management (#2350)

This commit is contained in:
Mo
2023-07-12 12:56:08 -05:00
committed by GitHub
parent 49f7581cd8
commit 078ef3772c
223 changed files with 3996 additions and 3438 deletions

View File

@@ -0,0 +1,14 @@
import { EditorFeatureDescription } from './EditorFeatureDescription'
import { ThemeFeatureDescription } from './ThemeFeatureDescription'
import { ComponentFeatureDescription } from './ComponentFeatureDescription'
import { IframeComponentFeatureDescription } from './IframeComponentFeatureDescription'
import { ClientFeatureDescription } from './ClientFeatureDescription'
import { ServerFeatureDescription } from './ServerFeatureDescription'
export type AnyFeatureDescription =
| ComponentFeatureDescription
| EditorFeatureDescription
| ThemeFeatureDescription
| IframeComponentFeatureDescription
| ClientFeatureDescription
| ServerFeatureDescription

View File

@@ -0,0 +1,24 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { ComponentFlag } from '../Component/ComponentFlag'
import { RoleFields } from './RoleFields'
export type BaseFeatureDescription = RoleFields & {
deletion_warning?: string
deprecated?: boolean
deprecation_message?: string
description?: string
expires_at?: number
/** Whether the client controls availability of this feature (such as the dark theme) */
clientControlled?: boolean
flags?: ComponentFlag[]
identifier: FeatureIdentifier
marketing_url?: string
name: string
no_expire?: boolean
no_mobile?: boolean
thumbnail_url?: string
permission_name: PermissionName
}

View File

@@ -0,0 +1,11 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { RoleFields } from './RoleFields'
export type ClientFeatureDescription = RoleFields & {
identifier: FeatureIdentifier
permission_name: PermissionName
description: string
name: string
deprecated?: boolean
}

View File

@@ -0,0 +1,9 @@
import { ComponentArea } from '../Component/ComponentArea'
import { BaseFeatureDescription } from './BaseFeatureDescription'
export type ComponentFeatureDescription = BaseFeatureDescription & {
/** The relative path of the index.html file or the main css file if theme, within the component folder itself */
index_path: string
content_type: string
area: ComponentArea
}

View File

@@ -0,0 +1,10 @@
import { NoteType } from '../Component/NoteType'
import { BaseFeatureDescription } from './BaseFeatureDescription'
export type EditorFeatureDescription = BaseFeatureDescription & {
file_type: 'txt' | 'html' | 'md' | 'json'
/** Whether an editor is interchangable with another editor that has the same file_type */
interchangeable: boolean
note_type: NoteType
spellcheckControl: boolean
}

View File

@@ -1,81 +0,0 @@
import { ComponentPermission } from '../Component/ComponentPermission'
import { ComponentArea } from '../Component/ComponentArea'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { ComponentFlag } from '../Component/ComponentFlag'
import { NoteType } from '../Component/NoteType'
import { ThemeDockIcon } from '../Component/ThemeDockIcon'
type RoleFields = {
/** Server populated */
role_name?: string
/** Statically populated. Non-influencing; used as a reference by other static consumers (such as email service) */
availableInRoles: string[]
}
export type BaseFeatureDescription = RoleFields & {
deletion_warning?: string
deprecated?: boolean
deprecation_message?: string
description?: string
expires_at?: number
/** Whether the client controls availability of this feature (such as the dark theme) */
clientControlled?: boolean
flags?: ComponentFlag[]
identifier: FeatureIdentifier
marketing_url?: string
name?: string
no_expire?: boolean
no_mobile?: boolean
thumbnail_url?: string
permission_name: PermissionName
}
export type ServerFeatureDescription = RoleFields & {
name?: string
identifier: FeatureIdentifier
permission_name: PermissionName
}
export type ClientFeatureDescription = RoleFields & {
identifier: FeatureIdentifier
permission_name: PermissionName
description: string
name: string
}
export type ComponentFeatureDescription = BaseFeatureDescription & {
/** The relative path of the index.html file or the main css file if theme, within the component folder itself */
index_path: string
content_type: string
area: ComponentArea
}
export type ThirdPartyFeatureDescription = ComponentFeatureDescription & {
url: string
}
export type IframeComponentFeatureDescription = ComponentFeatureDescription & {
component_permissions: ComponentPermission[]
}
export type EditorFeatureDescription = IframeComponentFeatureDescription & {
file_type: 'txt' | 'html' | 'md' | 'json'
/** Whether an editor is interchangable with another editor that has the same file_type */
interchangeable: boolean
note_type: NoteType
spellcheckControl?: boolean
}
export type ThemeFeatureDescription = ComponentFeatureDescription & {
/** Some themes can be layered on top of other themes */
layerable?: boolean
dock_icon?: ThemeDockIcon
isDark?: boolean
}
export type FeatureDescription = BaseFeatureDescription &
Partial<ComponentFeatureDescription & EditorFeatureDescription & ThemeFeatureDescription>

View File

@@ -1,14 +1,51 @@
import { FeatureDescription } from './FeatureDescription'
import { AnyFeatureDescription } from './AnyFeatureDescription'
import { ThemeFeatureDescription } from './ThemeFeatureDescription'
import { EditorFeatureDescription } from './EditorFeatureDescription'
import { FeatureIdentifier } from './FeatureIdentifier'
import { serverFeatures } from '../Lists/ServerFeatures'
import { clientFeatures } from '../Lists/ClientFeatures'
import { GetDeprecatedFeatures } from '../Lists/DeprecatedFeatures'
import { experimentalFeatures } from '../Lists/ExperimentalFeatures'
import { IframeEditors } from '../Lists/IframeEditors'
import { themes } from '../Lists/Themes'
import { nativeEditors } from '../Lists/NativeEditors'
export function GetFeatures(): FeatureDescription[] {
return [...serverFeatures(), ...clientFeatures(), ...experimentalFeatures(), ...GetDeprecatedFeatures()]
export function GetFeatures(): AnyFeatureDescription[] {
return [
...serverFeatures(),
...clientFeatures(),
...themes(),
...nativeEditors(),
...IframeEditors(),
...experimentalFeatures(),
...GetDeprecatedFeatures(),
]
}
export function FindNativeFeature(identifier: FeatureIdentifier): FeatureDescription | undefined {
return GetFeatures().find((f) => f.identifier === identifier)
export function FindNativeFeature<T extends AnyFeatureDescription>(identifier: FeatureIdentifier): T | undefined {
return GetFeatures().find((f) => f.identifier === identifier) as T
}
export function FindNativeTheme(identifier: FeatureIdentifier): ThemeFeatureDescription | undefined {
return themes().find((t) => t.identifier === identifier)
}
export function GetIframeAndNativeEditors(): EditorFeatureDescription[] {
return [...IframeEditors(), ...nativeEditors()]
}
export function GetSuperNoteFeature(): EditorFeatureDescription {
return FindNativeFeature(FeatureIdentifier.SuperEditor) as EditorFeatureDescription
}
export function GetPlainNoteFeature(): EditorFeatureDescription {
return FindNativeFeature(FeatureIdentifier.PlainEditor) as EditorFeatureDescription
}
export function GetNativeThemes(): ThemeFeatureDescription[] {
return themes()
}
export function GetDarkThemeFeature(): ThemeFeatureDescription {
return themes().find((t) => t.identifier === FeatureIdentifier.DarkTheme) as ThemeFeatureDescription
}

View File

@@ -0,0 +1,7 @@
import { ComponentPermission } from '../Component/ComponentPermission'
import { ComponentFeatureDescription } from './ComponentFeatureDescription'
import { EditorFeatureDescription } from './EditorFeatureDescription'
export type IframeComponentFeatureDescription = (EditorFeatureDescription & ComponentFeatureDescription) & {
component_permissions: ComponentPermission[]
}

View File

@@ -0,0 +1,7 @@
export type RoleFields = {
/** Server populated */
role_name?: string
/** Statically populated. Non-influencing; used as a reference by other static consumers (such as email service) */
availableInRoles: string[]
}

View File

@@ -0,0 +1,11 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { RoleFields } from './RoleFields'
export type ServerFeatureDescription = RoleFields & {
name: string
description?: string
identifier: FeatureIdentifier
permission_name: PermissionName
deprecated?: boolean
}

View File

@@ -0,0 +1,9 @@
import { ThemeDockIcon } from '../Component/ThemeDockIcon'
import { ComponentFeatureDescription } from './ComponentFeatureDescription'
export type ThemeFeatureDescription = ComponentFeatureDescription & {
/** Some themes can be layered on top of other themes */
layerable?: boolean
dock_icon?: ThemeDockIcon
isDark?: boolean
}

View File

@@ -0,0 +1,5 @@
import { ComponentFeatureDescription } from './ComponentFeatureDescription'
export type ThirdPartyFeatureDescription = ComponentFeatureDescription & {
url: string
}

View File

@@ -0,0 +1,28 @@
import { ContentType } from '@standardnotes/domain-core'
import { AnyFeatureDescription } from './AnyFeatureDescription'
import { ThemeFeatureDescription } from './ThemeFeatureDescription'
import { EditorFeatureDescription } from './EditorFeatureDescription'
import { IframeComponentFeatureDescription } from './IframeComponentFeatureDescription'
import { ComponentFeatureDescription } from './ComponentFeatureDescription'
import { ComponentArea } from '../Component/ComponentArea'
export function isThemeFeatureDescription(feature: AnyFeatureDescription): feature is ThemeFeatureDescription {
return 'content_type' in feature && feature.content_type === ContentType.TYPES.Theme
}
export function isIframeComponentFeatureDescription(
feature: AnyFeatureDescription,
): feature is IframeComponentFeatureDescription {
return (
'content_type' in feature &&
feature.content_type === ContentType.TYPES.Component &&
[ComponentArea.Editor, ComponentArea.EditorStack].includes(feature.area)
)
}
export function isEditorFeatureDescription(feature: AnyFeatureDescription): feature is EditorFeatureDescription {
return (
(feature as EditorFeatureDescription).note_type != undefined ||
(feature as ComponentFeatureDescription).area === ComponentArea.Editor
)
}

View File

@@ -0,0 +1,10 @@
import { ComponentFeatureDescription } from './ComponentFeatureDescription'
import { EditorFeatureDescription } from './EditorFeatureDescription'
import { IframeComponentFeatureDescription } from './IframeComponentFeatureDescription'
import { ThemeFeatureDescription } from './ThemeFeatureDescription'
export type UIFeatureDescriptionTypes =
| IframeComponentFeatureDescription
| ThemeFeatureDescription
| EditorFeatureDescription
| ComponentFeatureDescription