fix: circular dependencies (#1040)

This commit is contained in:
Karol Sójko
2022-05-23 14:18:36 +02:00
committed by GitHub
parent 51248f2588
commit 0e258856d8
28 changed files with 134 additions and 107 deletions

View File

@@ -10,13 +10,7 @@ import { CreateAccount } from './CreateAccount'
import { ConfirmPassword } from './ConfirmPassword'
import { JSXInternal } from 'preact/src/jsx'
import { ApplicationGroup } from '@/UIModels/ApplicationGroup'
export enum AccountMenuPane {
GeneralMenu,
SignIn,
Register,
ConfirmPassword,
}
import { AccountMenuPane } from './AccountMenuPane'
type Props = {
appState: AppState

View File

@@ -0,0 +1,6 @@
export enum AccountMenuPane {
GeneralMenu,
SignIn,
Register,
ConfirmPassword,
}

View File

@@ -4,7 +4,7 @@ import { AppState } from '@/UIModels/AppState'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
import { AccountMenuPane } from './AccountMenu'
import { AccountMenuPane } from './AccountMenuPane'
import { Button } from '@/Components/Button/Button'
import { Checkbox } from '@/Components/Checkbox/Checkbox'
import { DecoratedPasswordInput } from '@/Components/Input/DecoratedPasswordInput'

View File

@@ -3,7 +3,7 @@ import { AppState } from '@/UIModels/AppState'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { StateUpdater, useCallback, useEffect, useRef, useState } from 'preact/hooks'
import { AccountMenuPane } from './AccountMenu'
import { AccountMenuPane } from './AccountMenuPane'
import { Button } from '@/Components/Button/Button'
import { DecoratedInput } from '@/Components/Input/DecoratedInput'
import { DecoratedPasswordInput } from '@/Components/Input/DecoratedPasswordInput'

View File

@@ -6,7 +6,7 @@ import { formatLastSyncDate } from '@/Components/Preferences/Panes/Account/Sync'
import { SyncQueueStrategy } from '@standardnotes/snjs'
import { STRING_GENERIC_SYNC_ERROR } from '@/Strings'
import { useCallback, useMemo, useState } from 'preact/hooks'
import { AccountMenuPane } from './AccountMenu'
import { AccountMenuPane } from './AccountMenuPane'
import { FunctionComponent } from 'preact'
import { Menu } from '@/Components/Menu/Menu'
import { MenuItem, MenuItemSeparator, MenuItemType } from '@/Components/Menu/MenuItem'

View File

@@ -4,7 +4,7 @@ import { isDev } from '@/Utils'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
import { AccountMenuPane } from './AccountMenu'
import { AccountMenuPane } from './AccountMenuPane'
import { Button } from '@/Components/Button/Button'
import { Checkbox } from '@/Components/Checkbox/Checkbox'
import { DecoratedInput } from '@/Components/Input/DecoratedInput'

View File

@@ -1,11 +1,6 @@
import { Icon } from '@/Components/Icon/Icon'
import { Menu } from '@/Components/Menu/Menu'
import { MenuItem, MenuItemType } from '@/Components/Menu/MenuItem'
import {
reloadFont,
transactionForAssociateComponentWithCurrentNote,
transactionForDisassociateComponentWithCurrentNote,
} from '@/Components/NoteView/NoteView'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { STRING_EDIT_LOCKED_ATTEMPT } from '@/Strings'
import { WebApplication } from '@/UIModels/Application'
@@ -23,6 +18,11 @@ import { useCallback, useEffect, useState } from 'preact/hooks'
import { EditorMenuItem, EditorMenuGroup } from '@/Components/NotesOptions/ChangeEditorOption'
import { createEditorMenuGroups } from './createEditorMenuGroups'
import { PLAIN_EDITOR_NAME } from '@/Constants'
import {
transactionForAssociateComponentWithCurrentNote,
transactionForDisassociateComponentWithCurrentNote,
} from '../NoteView/TransactionFunctions'
import { reloadFont } from '../NoteView/FontFunctions'
type ChangeEditorMenuProps = {
application: WebApplication

View File

@@ -11,12 +11,13 @@ import {
STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON,
} from '@/Strings'
import { alertDialog, confirmDialog } from '@/Services/AlertService'
import { AccountMenu, AccountMenuPane } from '@/Components/AccountMenu/AccountMenu'
import { AccountMenu } from '@/Components/AccountMenu/AccountMenu'
import { AppStateEvent, EventSource } from '@/UIModels/AppState'
import { Icon } from '@/Components/Icon/Icon'
import { QuickSettingsMenu } from '@/Components/QuickSettingsMenu/QuickSettingsMenu'
import { SyncResolutionMenu } from '@/Components/SyncResolutionMenu/SyncResolutionMenu'
import { Fragment } from 'preact'
import { AccountMenuPane } from '../AccountMenu/AccountMenuPane'
type Props = {
application: WebApplication

View File

@@ -0,0 +1,9 @@
export const reloadFont = (monospaceFont?: boolean) => {
const root = document.querySelector(':root') as HTMLElement
const propertyName = '--sn-stylekit-editor-font-family'
if (monospaceFont) {
root.style.setProperty(propertyName, 'var(--sn-stylekit-monospace-font)')
} else {
root.style.setProperty(propertyName, 'var(--sn-stylekit-sans-serif-font)')
}
}

View File

@@ -9,10 +9,7 @@ import {
SNNote,
ComponentArea,
PrefKey,
ComponentMutator,
ComponentViewer,
TransactionalMutation,
ItemMutator,
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction,
NoteViewController,
PayloadEmitSource,
@@ -33,6 +30,11 @@ import { PanelSide, PanelResizer, PanelResizeType } from '@/Components/PanelResi
import { ElementIds } from '@/ElementIDs'
import { ChangeEditorButton } from '@/Components/ChangeEditor/ChangeEditorButton'
import { AttachedFilesButton } from '@/Components/AttachedFilesPopover/AttachedFilesButton'
import {
transactionForAssociateComponentWithCurrentNote,
transactionForDisassociateComponentWithCurrentNote,
} from './TransactionFunctions'
import { reloadFont } from './FontFunctions'
const MINIMUM_STATUS_DURATION = 400
const TEXTAREA_DEBOUNCE = 100
@@ -47,40 +49,6 @@ function sortAlphabetically(array: SNComponent[]): SNComponent[] {
return array.sort((a, b) => (a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1))
}
export const transactionForAssociateComponentWithCurrentNote = (component: SNComponent, note: SNNote) => {
const transaction: TransactionalMutation = {
itemUuid: component.uuid,
mutate: (m: ItemMutator) => {
const mutator = m as ComponentMutator
mutator.removeDisassociatedItemId(note.uuid)
mutator.associateWithItem(note.uuid)
},
}
return transaction
}
export const transactionForDisassociateComponentWithCurrentNote = (component: SNComponent, note: SNNote) => {
const transaction: TransactionalMutation = {
itemUuid: component.uuid,
mutate: (m: ItemMutator) => {
const mutator = m as ComponentMutator
mutator.removeAssociatedItemId(note.uuid)
mutator.disassociateWithItem(note.uuid)
},
}
return transaction
}
export const reloadFont = (monospaceFont?: boolean) => {
const root = document.querySelector(':root') as HTMLElement
const propertyName = '--sn-stylekit-editor-font-family'
if (monospaceFont) {
root.style.setProperty(propertyName, 'var(--sn-stylekit-monospace-font)')
} else {
root.style.setProperty(propertyName, 'var(--sn-stylekit-sans-serif-font)')
}
}
type State = {
availableStackComponents: SNComponent[]
editorComponentViewer?: ComponentViewer

View File

@@ -0,0 +1,25 @@
import { SNComponent, SNNote, ComponentMutator, TransactionalMutation, ItemMutator } from '@standardnotes/snjs'
export const transactionForAssociateComponentWithCurrentNote = (component: SNComponent, note: SNNote) => {
const transaction: TransactionalMutation = {
itemUuid: component.uuid,
mutate: (m: ItemMutator) => {
const mutator = m as ComponentMutator
mutator.removeDisassociatedItemId(note.uuid)
mutator.associateWithItem(note.uuid)
},
}
return transaction
}
export const transactionForDisassociateComponentWithCurrentNote = (component: SNComponent, note: SNNote) => {
const transaction: TransactionalMutation = {
itemUuid: component.uuid,
mutate: (m: ItemMutator) => {
const mutator = m as ComponentMutator
mutator.removeAssociatedItemId(note.uuid)
mutator.disassociateWithItem(note.uuid)
},
}
return transaction
}

View File

@@ -1,4 +1,3 @@
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenu'
import { Button } from '@/Components/Button/Button'
import { PreferencesGroup, PreferencesSegment, Text, Title } from '@/Components/Preferences/PreferencesComponents'
import { WebApplication } from '@/UIModels/Application'
@@ -6,6 +5,7 @@ import { AppState } from '@/UIModels/AppState'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { AccountIllustration } from '@standardnotes/icons'
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
export const Authentication: FunctionComponent<{
application: WebApplication

View File

@@ -3,7 +3,7 @@ import { LinkButton, Text } from '@/Components/Preferences/PreferencesComponents
import { Button } from '@/Components/Button/Button'
import { WebApplication } from '@/UIModels/Application'
import { useState } from 'preact/hooks'
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowWrapper'
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowFunctions'
export const NoSubscription: FunctionalComponent<{
application: WebApplication

View File

@@ -1,14 +1,14 @@
import { Button } from '@/Components/Button/Button'
import { WebApplication } from '@/UIModels/Application'
import { AppState } from '@/UIModels/AppState'
import { PurchaseFlowPane } from '@/UIModels/AppState/PurchaseFlowState'
import { PurchaseFlowPane } from '@/UIModels/AppState/PurchaseFlowPane'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { useEffect, useRef, useState } from 'preact/hooks'
import { FloatingLabelInput } from '@/Components/Input/FloatingLabelInput'
import { isEmailValid } from '@/Utils'
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowWrapper'
import { BlueDotIcon, CircleIcon, DiamondIcon, CreateAccountIllustration } from '@standardnotes/icons'
import { loadPurchaseFlowUrl } from '../PurchaseFlowFunctions'
type Props = {
appState: AppState

View File

@@ -1,14 +1,14 @@
import { Button } from '@/Components/Button/Button'
import { WebApplication } from '@/UIModels/Application'
import { AppState } from '@/UIModels/AppState'
import { PurchaseFlowPane } from '@/UIModels/AppState/PurchaseFlowState'
import { PurchaseFlowPane } from '@/UIModels/AppState/PurchaseFlowPane'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { useEffect, useRef, useState } from 'preact/hooks'
import { FloatingLabelInput } from '@/Components/Input/FloatingLabelInput'
import { isEmailValid } from '@/Utils'
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowWrapper'
import { BlueDotIcon, CircleIcon, DiamondIcon } from '@standardnotes/icons'
import { loadPurchaseFlowUrl } from '../PurchaseFlowFunctions'
type Props = {
appState: AppState

View File

@@ -0,0 +1,27 @@
import { WebApplication } from '@/UIModels/Application'
import { getWindowUrlParams, isDesktopApplication } from '@/Utils'
export const getPurchaseFlowUrl = async (application: WebApplication): Promise<string | undefined> => {
const currentUrl = window.location.origin
const successUrl = isDesktopApplication() ? 'standardnotes://' : currentUrl
if (application.noAccount()) {
return `${window.purchaseUrl}/offline?&success_url=${successUrl}`
}
const token = await application.getNewSubscriptionToken()
if (token) {
return `${window.purchaseUrl}?subscription_token=${token}&success_url=${successUrl}`
}
return undefined
}
export const loadPurchaseFlowUrl = async (application: WebApplication): Promise<boolean> => {
const url = await getPurchaseFlowUrl(application)
const params = getWindowUrlParams()
const period = params.get('period') ? `&period=${params.get('period')}` : ''
const plan = params.get('plan') ? `&plan=${params.get('plan')}` : ''
if (url) {
window.location.assign(`${url}${period}${plan}`)
return true
}
return false
}

View File

@@ -1,6 +1,6 @@
import { WebApplication } from '@/UIModels/Application'
import { AppState } from '@/UIModels/AppState'
import { PurchaseFlowPane } from '@/UIModels/AppState/PurchaseFlowState'
import { PurchaseFlowPane } from '@/UIModels/AppState/PurchaseFlowPane'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { CreateAccount } from './Panes/CreateAccount'

View File

@@ -1,6 +1,5 @@
import { WebApplication } from '@/UIModels/Application'
import { AppState } from '@/UIModels/AppState'
import { getWindowUrlParams, isDesktopApplication } from '@/Utils'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { PurchaseFlowView } from './PurchaseFlowView'
@@ -10,31 +9,6 @@ export type PurchaseFlowWrapperProps = {
application: WebApplication
}
export const getPurchaseFlowUrl = async (application: WebApplication): Promise<string | undefined> => {
const currentUrl = window.location.origin
const successUrl = isDesktopApplication() ? 'standardnotes://' : currentUrl
if (application.noAccount()) {
return `${window.purchaseUrl}/offline?&success_url=${successUrl}`
}
const token = await application.getNewSubscriptionToken()
if (token) {
return `${window.purchaseUrl}?subscription_token=${token}&success_url=${successUrl}`
}
return undefined
}
export const loadPurchaseFlowUrl = async (application: WebApplication): Promise<boolean> => {
const url = await getPurchaseFlowUrl(application)
const params = getWindowUrlParams()
const period = params.get('period') ? `&period=${params.get('period')}` : ''
const plan = params.get('plan') ? `&plan=${params.get('plan')}` : ''
if (url) {
window.location.assign(`${url}${period}${plan}`)
return true
}
return false
}
export const PurchaseFlowWrapper: FunctionComponent<PurchaseFlowWrapperProps> = observer(
({ appState, application }) => {
if (!appState.purchaseFlow.isOpen) {

View File

@@ -2,7 +2,7 @@ import { destroyAllObjectProperties, isDev } from '@/Utils'
import { action, computed, makeObservable, observable, runInAction } from 'mobx'
import { ApplicationEvent, ContentType, DeinitSource, SNNote, SNTag } from '@standardnotes/snjs'
import { WebApplication } from '@/UIModels/Application'
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenu'
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
import { AbstractState } from './AbstractState'
type StructuredItemsCount = {

View File

@@ -30,17 +30,7 @@ import { FilePreviewModalState } from './FilePreviewModalState'
import { AbstractState } from './AbstractState'
import { SelectedItemsState } from './SelectedItemsState'
import { ListableContentItem } from '@/Components/ContentListView/Types/ListableContentItem'
export enum AppStateEvent {
TagChanged,
ActiveEditorChanged,
PanelResized,
EditorFocused,
BeganBackupDownload,
EndedBackupDownload,
WindowDidFocus,
WindowDidBlur,
}
import { AppStateEvent } from './AppStateEvent'
export type PanelResizedData = {
panel: string

View File

@@ -0,0 +1,10 @@
export enum AppStateEvent {
TagChanged,
ActiveEditorChanged,
PanelResized,
EditorFocused,
BeganBackupDownload,
EndedBackupDownload,
WindowDidFocus,
WindowDidBlur,
}

View File

@@ -15,9 +15,10 @@ import {
DisplayOptions,
} from '@standardnotes/snjs'
import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'
import { AppState, AppStateEvent } from '.'
import { WebApplication } from '../Application'
import { AbstractState } from './AbstractState'
import { AppState } from './AppState'
import { AppStateEvent } from './AppStateEvent'
import { WebDisplayOptions } from './WebDisplayOptions'
const MinNoteCellHeight = 51.0

View File

@@ -0,0 +1,4 @@
export enum PurchaseFlowPane {
SignIn,
CreateAccount,
}

View File

@@ -1,12 +1,8 @@
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowWrapper'
import { loadPurchaseFlowUrl } from '@/Components/PurchaseFlow/PurchaseFlowFunctions'
import { action, makeObservable, observable } from 'mobx'
import { WebApplication } from '../Application'
import { AbstractState } from './AbstractState'
export enum PurchaseFlowPane {
SignIn,
CreateAccount,
}
import { PurchaseFlowPane } from './PurchaseFlowPane'
export class PurchaseFlowState extends AbstractState {
isOpen = false

View File

@@ -1 +1,3 @@
export { AppState, AppStateEvent, EventSource, PanelResizedData } from './AppState'
export { AppState, EventSource, PanelResizedData } from './AppState'
export * from './AppStateEvent'
export * from './PurchaseFlowPane'

View File

@@ -34,6 +34,7 @@
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"babel-loader": "^8.2.5",
"circular-dependency-plugin": "^5.2.2",
"css-loader": "^6.7.1",
"dotenv": "^16.0.0",
"eslint": "^8.13.0",

View File

@@ -1,6 +1,7 @@
const path = require('path')
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CircularDependencyPlugin = require('circular-dependency-plugin')
const mergeWithEnvDefaults = require('./webpack-defaults')
require('dotenv').config()
@@ -12,6 +13,19 @@ module.exports = (env) => {
filename: './javascripts/app.js',
},
plugins: [
new CircularDependencyPlugin({
// exclude detection of files based on a RegExp
exclude: /a\.js|node_modules/,
// include specific files based on a RegExp
include: /app\/assets\/javascripts/,
// add errors to webpack instead of warnings
failOnError: true,
// allow import cycles that include an asyncronous import,
// e.g. via import(/* webpackMode: "weak" */ './file.js')
allowAsyncCycles: false,
// set the current working directory for displaying module paths
cwd: process.cwd(),
}),
new webpack.DefinePlugin({
__VERSION__: JSON.stringify(require('./package.json').version),
__WEB__: JSON.stringify(env.platform === 'web'),

View File

@@ -3884,6 +3884,11 @@ cint@^8.2.1:
resolved "https://registry.yarnpkg.com/cint/-/cint-8.2.1.tgz#70386b1b48e2773d0d63166a55aff94ef4456a12"
integrity sha1-cDhrG0jidz0NYxZqVa/5TvRFahI=
circular-dependency-plugin@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600"
integrity sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==
cjs-module-lexer@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"