feat: add features package

This commit is contained in:
Karol Sójko
2022-07-05 14:58:29 +02:00
parent e335d0d2c2
commit 44d3e96468
69 changed files with 2214 additions and 28 deletions

View File

@@ -0,0 +1,58 @@
import { ClientFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { SubscriptionName } from '@standardnotes/common'
export function clientFeatures(): ClientFeatureDescription[] {
return [
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Tag Nesting',
identifier: FeatureIdentifier.TagNesting,
permission_name: PermissionName.TagNesting,
description: 'Organize your tags into folders.',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Smart Filters',
identifier: FeatureIdentifier.SmartFilters,
permission_name: PermissionName.SmartFilters,
description: 'Create smart filters for viewing notes matching specific criteria.',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Encrypted files (coming soon)',
identifier: FeatureIdentifier.Files,
permission_name: PermissionName.Files,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Encrypted files beta',
identifier: FeatureIdentifier.FilesBeta,
permission_name: PermissionName.FilesBeta,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Focus Mode',
identifier: FeatureIdentifier.FocusMode,
permission_name: PermissionName.FocusMode,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Listed Custom Domain',
identifier: FeatureIdentifier.ListedCustomDomain,
permission_name: PermissionName.ListedCustomDomain,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Multiple accounts',
identifier: FeatureIdentifier.AccountSwitcher,
permission_name: PermissionName.AccountSwitcher,
description: '',
},
]
}

View File

@@ -0,0 +1,7 @@
import { GetDeprecatedFeatures } from './DeprecatedFeatures'
it('all deprecated features should have deprecated flag true', async () => {
for (const feature of GetDeprecatedFeatures()) {
expect(feature.deprecated).toEqual(true)
}
})

View File

@@ -0,0 +1,110 @@
import { ContentType, SubscriptionName } from '@standardnotes/common'
import {
EditorFeatureDescription,
IframeComponentFeatureDescription,
FeatureDescription,
} from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NoteType } from '../Component/NoteType'
import { FillEditorComponentDefaults } from './Utilities/FillEditorComponentDefaults'
import { ComponentAction } from '../Component/ComponentAction'
import { ComponentArea } from '../Component/ComponentArea'
export function GetDeprecatedFeatures(): FeatureDescription[] {
const bold: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Alternative Rich Text',
identifier: FeatureIdentifier.DeprecatedBoldEditor,
note_type: NoteType.RichText,
file_type: 'html',
component_permissions: [
{
name: ComponentAction.StreamContextItem,
content_types: [ContentType.Note],
},
{
name: ComponentAction.StreamItems,
content_types: [
ContentType.FilesafeCredentials,
ContentType.FilesafeFileMetadata,
ContentType.FilesafeIntegration,
],
},
],
spellcheckControl: true,
deprecated: true,
permission_name: PermissionName.BoldEditor,
description: 'A simple and peaceful rich editor that helps you write and think clearly.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/bold.jpg',
})
const markdownBasic: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Basic Markdown',
identifier: FeatureIdentifier.DeprecatedMarkdownBasicEditor,
note_type: NoteType.Markdown,
spellcheckControl: true,
file_type: 'md',
deprecated: true,
permission_name: PermissionName.MarkdownBasicEditor,
description: 'A Markdown editor with dynamic split-pane preview.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/simple-markdown.jpg',
})
const markdownMinimist: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Minimal Markdown',
identifier: FeatureIdentifier.DeprecatedMarkdownMinimistEditor,
note_type: NoteType.Markdown,
file_type: 'md',
index_path: 'index.html',
permission_name: PermissionName.MarkdownMinimistEditor,
spellcheckControl: true,
deprecated: true,
description: 'A minimal Markdown editor with live rendering and in-text search via Ctrl/Cmd + F',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/min-markdown.jpg',
})
const markdownMath: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Markdown with Math',
identifier: FeatureIdentifier.DeprecatedMarkdownMathEditor,
spellcheckControl: true,
permission_name: PermissionName.MarkdownMathEditor,
note_type: NoteType.Markdown,
file_type: 'md',
deprecated: true,
index_path: 'index.html',
description: 'A beautiful split-pane Markdown editor with synced-scroll, LaTeX support, and colorful syntax.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/fancy-markdown.jpg',
})
const filesafe: IframeComponentFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'FileSafe',
identifier: FeatureIdentifier.DeprecatedFileSafe,
component_permissions: [
{
name: ComponentAction.StreamContextItem,
content_types: [ContentType.Note],
},
{
name: ComponentAction.StreamItems,
content_types: [
ContentType.FilesafeCredentials,
ContentType.FilesafeFileMetadata,
ContentType.FilesafeIntegration,
],
},
],
permission_name: PermissionName.ComponentFilesafe,
area: ComponentArea.EditorStack,
deprecated: true,
description:
'Encrypted attachments for your notes using your Dropbox, Google Drive, or WebDAV server. Limited to 50MB per file.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/FileSafe-banner.png',
})
return [bold, markdownBasic, markdownMinimist, markdownMath, filesafe]
}

View File

@@ -0,0 +1,105 @@
import { SubscriptionName } from '@standardnotes/common'
import { EditorFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NoteType } from '../Component/NoteType'
import { FillEditorComponentDefaults } from './Utilities/FillEditorComponentDefaults'
export function editors(): EditorFeatureDescription[] {
const code: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Code',
spellcheckControl: true,
identifier: FeatureIdentifier.CodeEditor,
permission_name: PermissionName.CodeEditor,
note_type: NoteType.Code,
file_type: 'txt',
interchangeable: true,
index_path: 'index.html',
description:
'Syntax highlighting and convenient keyboard shortcuts for over 120 programming' +
' languages. Ideal for code snippets and procedures.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/code.jpg',
})
const plus: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Rich Text',
note_type: NoteType.RichText,
file_type: 'html',
identifier: FeatureIdentifier.PlusEditor,
permission_name: PermissionName.PlusEditor,
spellcheckControl: true,
description:
'From highlighting to custom font sizes and colors, to tables and lists, this editor is perfect for crafting any document.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/plus-editor.jpg',
})
const markdown: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Markdown',
identifier: FeatureIdentifier.MarkdownProEditor,
note_type: NoteType.Markdown,
file_type: 'md',
permission_name: PermissionName.MarkdownProEditor,
spellcheckControl: true,
description:
'A fully featured Markdown editor that supports live preview, a styling toolbar, and split pane support.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/adv-markdown.jpg',
})
const markdownAlt: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Markdown Alternative',
identifier: FeatureIdentifier.MarkdownVisualEditor,
note_type: NoteType.Markdown,
file_type: 'md',
permission_name: PermissionName.MarkdownVisualEditor,
spellcheckControl: true,
description:
'A WYSIWYG-style Markdown editor that renders Markdown in preview-mode while you type without displaying any syntax.',
index_path: 'build/index.html',
})
const task: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Checklist',
identifier: FeatureIdentifier.TaskEditor,
note_type: NoteType.Task,
spellcheckControl: true,
file_type: 'md',
interchangeable: false,
permission_name: PermissionName.TaskEditor,
description:
'A great way to manage short-term and long-term to-do"s. You can mark tasks as completed, change their order, and edit the text naturally in place.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/task-editor.jpg',
})
const tokenvault: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Authenticator',
note_type: NoteType.Authentication,
file_type: 'json',
interchangeable: false,
identifier: FeatureIdentifier.TokenVaultEditor,
permission_name: PermissionName.TokenVaultEditor,
description:
'Encrypt and protect your 2FA secrets for all your internet accounts. Authenticator handles your 2FA secrets so that you never lose them again, or have to start over when you get a new device.',
thumbnail_url: 'https://standard-notes.s3.amazonaws.com/screenshots/models/editors/token-vault.png',
})
const spreadsheets: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Spreadsheet',
identifier: FeatureIdentifier.SheetsEditor,
note_type: NoteType.Spreadsheet,
file_type: 'json',
interchangeable: false,
permission_name: PermissionName.SheetsEditor,
description:
'A powerful spreadsheet editor with formatting and formula support. Not recommended for large data sets, as encryption of such data may decrease editor performance.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/spreadsheets.png',
})
return [code, plus, markdown, markdownAlt, task, tokenvault, spreadsheets]
}

View File

@@ -0,0 +1,23 @@
import { SubscriptionName } from '@standardnotes/common'
import { NoteType } from '../Component/NoteType'
import { PermissionName } from '../Permission/PermissionName'
import { EditorFeatureDescription, FeatureDescription } from '../Feature/FeatureDescription'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { FillEditorComponentDefaults } from './Utilities/FillEditorComponentDefaults'
export function experimentalFeatures(): FeatureDescription[] {
const advancedChecklist: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Advanced Checklist [Alpha]',
identifier: FeatureIdentifier.AdvancedChecklist,
note_type: NoteType.Task,
spellcheckControl: true,
file_type: 'json',
interchangeable: false,
permission_name: PermissionName.AdvancedChecklist,
description: 'A task editor with grouping functionality.',
index_path: 'build/index.html',
})
return [advancedChecklist]
}

View File

@@ -0,0 +1,64 @@
import { ServerFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { SubscriptionName } from '@standardnotes/common'
export function serverFeatures(): ServerFeatureDescription[] {
return [
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Two factor authentication',
identifier: FeatureIdentifier.TwoFactorAuth,
permission_name: PermissionName.TwoFactorAuth,
},
{
availableInSubscriptions: [SubscriptionName.ProPlan],
name: 'Unlimited note history',
identifier: FeatureIdentifier.NoteHistoryUnlimited,
permission_name: PermissionName.NoteHistoryUnlimited,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan],
name: '365 days note history',
identifier: FeatureIdentifier.NoteHistory365Days,
permission_name: PermissionName.NoteHistory365Days,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Email backups',
identifier: FeatureIdentifier.DailyEmailBackup,
permission_name: PermissionName.DailyEmailBackup,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Sign-in email alerts',
identifier: FeatureIdentifier.SignInAlerts,
permission_name: PermissionName.SignInAlerts,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
identifier: FeatureIdentifier.DailyDropboxBackup,
permission_name: PermissionName.DailyDropboxBackup,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
identifier: FeatureIdentifier.DailyGDriveBackup,
permission_name: PermissionName.DailyGDriveBackup,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
identifier: FeatureIdentifier.DailyOneDriveBackup,
permission_name: PermissionName.DailyOneDriveBackup,
},
{
availableInSubscriptions: [SubscriptionName.ProPlan],
identifier: FeatureIdentifier.FilesMaximumStorageTier,
permission_name: PermissionName.FilesMaximumStorageTier,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan],
identifier: FeatureIdentifier.FilesLowStorageTier,
permission_name: PermissionName.FilesLowStorageTier,
},
]
}

View File

@@ -0,0 +1,109 @@
import { ThemeFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { FillThemeComponentDefaults } from './Utilities/FillThemeComponentDefaults'
import { SubscriptionName } from '@standardnotes/common'
export function themes(): ThemeFeatureDescription[] {
const midnight: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Midnight',
identifier: FeatureIdentifier.MidnightTheme,
permission_name: PermissionName.MidnightTheme,
description: 'Elegant utilitarianism.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/midnight-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#086DD6',
foreground_color: '#ffffff',
border_color: '#086DD6',
},
})
const futura: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Futura',
identifier: FeatureIdentifier.FuturaTheme,
permission_name: PermissionName.FuturaTheme,
description: 'Calm and relaxed. Take some time off.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/futura-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#fca429',
foreground_color: '#ffffff',
border_color: '#fca429',
},
})
const solarizedDark: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Solarized Dark',
identifier: FeatureIdentifier.SolarizedDarkTheme,
permission_name: PermissionName.SolarizedDarkTheme,
description: 'The perfect theme for any time.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/solarized-dark.jpg',
dock_icon: {
type: 'circle',
background_color: '#2AA198',
foreground_color: '#ffffff',
border_color: '#2AA198',
},
})
const autobiography: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Autobiography',
identifier: FeatureIdentifier.AutobiographyTheme,
permission_name: PermissionName.AutobiographyTheme,
description: 'A theme for writers and readers.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/autobiography.jpg',
dock_icon: {
type: 'circle',
background_color: '#9D7441',
foreground_color: '#ECE4DB',
border_color: '#9D7441',
},
})
const focus: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Focus',
identifier: FeatureIdentifier.FocusedTheme,
permission_name: PermissionName.FocusedTheme,
description: 'For when you need to go in.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/focus-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#a464c2',
foreground_color: '#ffffff',
border_color: '#a464c2',
},
})
const titanium: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Titanium',
identifier: FeatureIdentifier.TitaniumTheme,
permission_name: PermissionName.TitaniumTheme,
description: 'Light on the eyes, heavy on the spirit.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/titanium-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#6e2b9e',
foreground_color: '#ffffff',
border_color: '#6e2b9e',
},
})
const dynamic: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Dynamic Panels',
identifier: FeatureIdentifier.DynamicTheme,
permission_name: PermissionName.ThemeDynamic,
layerable: true,
no_mobile: true,
description: 'A smart theme that minimizes the tags and notes panels when they are not in use.',
})
return [midnight, futura, solarizedDark, autobiography, focus, titanium, dynamic]
}

View File

@@ -0,0 +1,34 @@
import { ComponentAction } from '../../Component/ComponentAction'
import { ContentType } from '@standardnotes/common'
import { EditorFeatureDescription } from '../../Feature/FeatureDescription'
import { ComponentArea } from '../../Component/ComponentArea'
export type RequiredEditorFields = Pick<EditorFeatureDescription, 'availableInSubscriptions'>
export function FillEditorComponentDefaults(
component: Partial<EditorFeatureDescription> & RequiredEditorFields,
): EditorFeatureDescription {
if (!component.index_path) {
component.index_path = 'dist/index.html'
}
if (!component.component_permissions) {
component.component_permissions = [
{
name: ComponentAction.StreamContextItem,
content_types: [ContentType.Note],
},
]
}
component.content_type = ContentType.Component
if (!component.area) {
component.area = ComponentArea.Editor
}
if (component.interchangeable == undefined) {
component.interchangeable = true
}
return component as EditorFeatureDescription
}

View File

@@ -0,0 +1,21 @@
import { ContentType } from '@standardnotes/common'
import { ThemeFeatureDescription } from '../../Feature/FeatureDescription'
import { ComponentArea } from '../../Component/ComponentArea'
type RequiredThemeFields = Pick<ThemeFeatureDescription, 'availableInSubscriptions'>
export function FillThemeComponentDefaults(
theme: Partial<ThemeFeatureDescription> & RequiredThemeFields,
): ThemeFeatureDescription {
if (!theme.index_path) {
theme.index_path = 'dist/dist.css'
}
theme.content_type = ContentType.Theme
if (!theme.area) {
theme.area = ComponentArea.Themes
}
return theme as ThemeFeatureDescription
}