fix: running tests and adding tests to CI & CD (#1047)
* fix: running tests and adding tests to CI & CD * fix: yarn.lock * fix: alert service * fix: ts-jest utils import
This commit is contained in:
14
.github/workflows/beta.yml
vendored
14
.github/workflows/beta.yml
vendored
@@ -6,23 +6,23 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tsc:
|
test:
|
||||||
name: Check types & lint
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
- name: Typescript
|
- name: Bundle
|
||||||
run: yarn tsc
|
run: yarn bundle
|
||||||
- name: ESLint
|
- name: ESLint
|
||||||
run: yarn lint --quiet
|
run: yarn lint
|
||||||
|
- name: Test
|
||||||
|
run: yarn test
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: tsc
|
needs: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
21
.github/workflows/dev.yml
vendored
21
.github/workflows/dev.yml
vendored
@@ -10,31 +10,26 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test:
|
||||||
tsc:
|
|
||||||
|
|
||||||
name: Check types & lint
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
|
- name: Bundle
|
||||||
- name: Typescript
|
run: yarn bundle
|
||||||
run: yarn tsc
|
|
||||||
|
|
||||||
- name: ESLint
|
- name: ESLint
|
||||||
run: yarn lint --quiet
|
run: yarn lint
|
||||||
|
- name: Test
|
||||||
|
run: yarn test
|
||||||
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
needs: tsc
|
needs: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
17
.github/workflows/pr.yml
vendored
17
.github/workflows/pr.yml
vendored
@@ -7,21 +7,16 @@ on:
|
|||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test:
|
||||||
tsc:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
|
- name: Bundle
|
||||||
- name: Typescript
|
run: yarn bundle
|
||||||
run: yarn tsc
|
|
||||||
|
|
||||||
- name: ESLint
|
- name: ESLint
|
||||||
run: yarn lint --quiet
|
run: yarn lint
|
||||||
|
- name: Test
|
||||||
|
run: yarn test
|
||||||
|
|||||||
21
.github/workflows/prod.yml
vendored
21
.github/workflows/prod.yml
vendored
@@ -9,32 +9,25 @@ on:
|
|||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test:
|
||||||
tsc:
|
|
||||||
|
|
||||||
name: Check types & lint
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --pure-lockfile
|
run: yarn install --pure-lockfile
|
||||||
|
- name: Bundle
|
||||||
- name: Typescript
|
run: yarn bundle
|
||||||
run: yarn tsc
|
|
||||||
|
|
||||||
- name: ESLint
|
- name: ESLint
|
||||||
run: yarn lint --quiet
|
run: yarn lint
|
||||||
|
- name: Test
|
||||||
|
run: yarn test
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
needs: tsc
|
needs: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
@@ -2,173 +2,175 @@
|
|||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { NoteView } from './NoteView'
|
import { WebApplication } from '@/UIModels/Application'
|
||||||
|
import { AppState } from '@/UIModels/AppState'
|
||||||
|
import { NotesState } from '@/UIModels/AppState/NotesState'
|
||||||
import {
|
import {
|
||||||
ApplicationEvent,
|
ApplicationEvent,
|
||||||
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction,
|
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction,
|
||||||
} from '@standardnotes/snjs/'
|
NoteViewController,
|
||||||
|
SNNote,
|
||||||
|
} from '@standardnotes/snjs'
|
||||||
|
|
||||||
describe('editor-view', () => {
|
import { NoteView } from './NoteView'
|
||||||
let ctrl: NoteView
|
|
||||||
let setShowProtectedWarningSpy: jest.SpyInstance
|
|
||||||
|
|
||||||
beforeEach(() => {
|
describe('NoteView', () => {
|
||||||
ctrl = new NoteView({} as any)
|
let noteViewController: NoteViewController
|
||||||
|
let application: WebApplication
|
||||||
|
let appState: AppState
|
||||||
|
let notesState: NotesState
|
||||||
|
|
||||||
setShowProtectedWarningSpy = jest.spyOn(ctrl, 'setShowProtectedOverlay')
|
const createNoteView = () =>
|
||||||
|
new NoteView({
|
||||||
Object.defineProperties(ctrl, {
|
controller: noteViewController,
|
||||||
application: {
|
application,
|
||||||
value: {
|
|
||||||
getAppState: () => {
|
|
||||||
return {
|
|
||||||
notes: {
|
|
||||||
setShowProtectedWarning: jest.fn(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hasProtectionSources: () => true,
|
|
||||||
authorizeNoteAccess: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
removeComponentsObserver: {
|
|
||||||
value: jest.fn(),
|
|
||||||
writable: true,
|
|
||||||
},
|
|
||||||
removeTrashKeyObserver: {
|
|
||||||
value: jest.fn(),
|
|
||||||
writable: true,
|
|
||||||
},
|
|
||||||
unregisterComponent: {
|
|
||||||
value: jest.fn(),
|
|
||||||
writable: true,
|
|
||||||
},
|
|
||||||
editor: {
|
|
||||||
value: {
|
|
||||||
clearNoteChangeListener: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers()
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
noteViewController = {} as jest.Mocked<NoteViewController>
|
||||||
|
|
||||||
|
notesState = {} as jest.Mocked<NotesState>
|
||||||
|
notesState.setShowProtectedWarning = jest.fn()
|
||||||
|
|
||||||
|
appState = {
|
||||||
|
notes: notesState,
|
||||||
|
} as jest.Mocked<AppState>
|
||||||
|
|
||||||
|
application = {} as jest.Mocked<WebApplication>
|
||||||
|
application.getAppState = jest.fn().mockReturnValue(appState)
|
||||||
|
application.hasProtectionSources = jest.fn().mockReturnValue(true)
|
||||||
|
application.authorizeNoteAccess = jest.fn()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.useRealTimers()
|
jest.useRealTimers()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
ctrl.deinit()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('note is protected', () => {
|
describe('note is protected', () => {
|
||||||
beforeEach(() => {
|
|
||||||
Object.defineProperty(ctrl, 'note', {
|
|
||||||
value: {
|
|
||||||
protected: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should hide the note if at the time of the session expiration the note wasn't edited for longer than the allowed idle time", async () => {
|
it("should hide the note if at the time of the session expiration the note wasn't edited for longer than the allowed idle time", async () => {
|
||||||
jest
|
const secondsElapsedSinceLastEdit = ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction + 5
|
||||||
.spyOn(ctrl, 'getSecondsElapsedSinceLastEdit')
|
|
||||||
.mockImplementation(() => ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction + 5)
|
|
||||||
|
|
||||||
await ctrl.onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
noteViewController.note = {
|
||||||
|
protected: true,
|
||||||
|
userModifiedDate: new Date(Date.now() - secondsElapsedSinceLastEdit * 1000),
|
||||||
|
} as jest.Mocked<SNNote>
|
||||||
|
|
||||||
expect(setShowProtectedWarningSpy).toHaveBeenCalledWith(true)
|
await createNoteView().onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
||||||
|
|
||||||
|
expect(notesState.setShowProtectedWarning).toHaveBeenCalledWith(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should postpone the note hiding by correct time if the time passed after its last modification is less than the allowed idle time', async () => {
|
it('should postpone the note hiding by correct time if the time passed after its last modification is less than the allowed idle time', async () => {
|
||||||
const secondsElapsedSinceLastEdit = ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction - 3
|
const secondsElapsedSinceLastEdit = ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction - 3
|
||||||
|
|
||||||
Object.defineProperty(ctrl.note, 'userModifiedDate', {
|
noteViewController.note = {
|
||||||
value: new Date(Date.now() - secondsElapsedSinceLastEdit * 1000),
|
protected: true,
|
||||||
configurable: true,
|
userModifiedDate: new Date(Date.now() - secondsElapsedSinceLastEdit * 1000),
|
||||||
})
|
} as jest.Mocked<SNNote>
|
||||||
|
|
||||||
await ctrl.onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
await createNoteView().onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
||||||
|
|
||||||
const secondsAfterWhichTheNoteShouldHide =
|
const secondsAfterWhichTheNoteShouldHide =
|
||||||
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction - secondsElapsedSinceLastEdit
|
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction - secondsElapsedSinceLastEdit
|
||||||
|
|
||||||
jest.advanceTimersByTime((secondsAfterWhichTheNoteShouldHide - 1) * 1000)
|
jest.advanceTimersByTime((secondsAfterWhichTheNoteShouldHide - 1) * 1000)
|
||||||
expect(setShowProtectedWarningSpy).not.toHaveBeenCalled()
|
|
||||||
|
expect(notesState.setShowProtectedWarning).not.toHaveBeenCalled()
|
||||||
|
|
||||||
jest.advanceTimersByTime(1 * 1000)
|
jest.advanceTimersByTime(1 * 1000)
|
||||||
expect(setShowProtectedWarningSpy).toHaveBeenCalledWith(true)
|
|
||||||
|
expect(notesState.setShowProtectedWarning).toHaveBeenCalledWith(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should postpone the note hiding by correct time if the user continued editing it even after the protection session has expired', async () => {
|
it('should postpone the note hiding by correct time if the user continued editing it even after the protection session has expired', async () => {
|
||||||
const secondsElapsedSinceLastModification = 3
|
const secondsElapsedSinceLastModification = 3
|
||||||
Object.defineProperty(ctrl.note, 'userModifiedDate', {
|
|
||||||
value: new Date(Date.now() - secondsElapsedSinceLastModification * 1000),
|
|
||||||
configurable: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
await ctrl.onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
noteViewController.note = {
|
||||||
|
protected: true,
|
||||||
|
userModifiedDate: new Date(Date.now() - secondsElapsedSinceLastModification * 1000),
|
||||||
|
} as jest.Mocked<SNNote>
|
||||||
|
|
||||||
|
await createNoteView().onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
||||||
|
|
||||||
let secondsAfterWhichTheNoteShouldHide =
|
let secondsAfterWhichTheNoteShouldHide =
|
||||||
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction - secondsElapsedSinceLastModification
|
ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction - secondsElapsedSinceLastModification
|
||||||
jest.advanceTimersByTime((secondsAfterWhichTheNoteShouldHide - 1) * 1000)
|
jest.advanceTimersByTime((secondsAfterWhichTheNoteShouldHide - 1) * 1000)
|
||||||
|
|
||||||
// A new modification has just happened
|
noteViewController.note = {
|
||||||
Object.defineProperty(ctrl.note, 'userModifiedDate', {
|
protected: true,
|
||||||
value: new Date(),
|
userModifiedDate: new Date(),
|
||||||
configurable: true,
|
} as jest.Mocked<SNNote>
|
||||||
})
|
|
||||||
|
|
||||||
secondsAfterWhichTheNoteShouldHide = ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction
|
secondsAfterWhichTheNoteShouldHide = ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction
|
||||||
jest.advanceTimersByTime((secondsAfterWhichTheNoteShouldHide - 1) * 1000)
|
jest.advanceTimersByTime((secondsAfterWhichTheNoteShouldHide - 1) * 1000)
|
||||||
expect(setShowProtectedWarningSpy).not.toHaveBeenCalled()
|
expect(notesState.setShowProtectedWarning).not.toHaveBeenCalled()
|
||||||
|
|
||||||
jest.advanceTimersByTime(1 * 1000)
|
jest.advanceTimersByTime(1 * 1000)
|
||||||
expect(setShowProtectedWarningSpy).toHaveBeenCalledWith(true)
|
expect(notesState.setShowProtectedWarning).toHaveBeenCalledWith(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('note is unprotected', () => {
|
describe('note is unprotected', () => {
|
||||||
it('should not call any hiding logic', async () => {
|
it('should not call any hiding logic', async () => {
|
||||||
Object.defineProperty(ctrl, 'note', {
|
noteViewController.note = {
|
||||||
value: {
|
protected: false,
|
||||||
protected: false,
|
} as jest.Mocked<SNNote>
|
||||||
},
|
|
||||||
})
|
|
||||||
const hideProtectedNoteIfInactiveSpy = jest.spyOn(ctrl, 'hideProtectedNoteIfInactive')
|
|
||||||
|
|
||||||
await ctrl.onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
await createNoteView().onAppEvent(ApplicationEvent.UnprotectedSessionExpired)
|
||||||
|
|
||||||
expect(hideProtectedNoteIfInactiveSpy).not.toHaveBeenCalled()
|
expect(notesState.setShowProtectedWarning).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('dismissProtectedWarning', () => {
|
describe('dismissProtectedWarning', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
noteViewController.note = {
|
||||||
|
protected: false,
|
||||||
|
} as jest.Mocked<SNNote>
|
||||||
|
})
|
||||||
|
|
||||||
describe('the note has protection sources', () => {
|
describe('the note has protection sources', () => {
|
||||||
it('should reveal note contents if the authorization has been passed', async () => {
|
it('should reveal note contents if the authorization has been passed', async () => {
|
||||||
jest.spyOn(ctrl['application'], 'authorizeNoteAccess').mockImplementation(async () => Promise.resolve(true))
|
application.authorizeNoteAccess = jest.fn().mockReturnValue(true)
|
||||||
|
|
||||||
await ctrl.dismissProtectedWarning()
|
const noteView = new NoteView({
|
||||||
|
controller: noteViewController,
|
||||||
|
application,
|
||||||
|
})
|
||||||
|
|
||||||
expect(setShowProtectedWarningSpy).toHaveBeenCalledWith(false)
|
await noteView.dismissProtectedWarning()
|
||||||
|
|
||||||
|
expect(notesState.setShowProtectedWarning).toHaveBeenCalledWith(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not reveal note contents if the authorization has not been passed', async () => {
|
it('should not reveal note contents if the authorization has not been passed', async () => {
|
||||||
jest.spyOn(ctrl['application'], 'authorizeNoteAccess').mockImplementation(async () => Promise.resolve(false))
|
application.authorizeNoteAccess = jest.fn().mockReturnValue(false)
|
||||||
|
|
||||||
await ctrl.dismissProtectedWarning()
|
const noteView = new NoteView({
|
||||||
|
controller: noteViewController,
|
||||||
|
application,
|
||||||
|
})
|
||||||
|
|
||||||
expect(setShowProtectedWarningSpy).not.toHaveBeenCalled()
|
await noteView.dismissProtectedWarning()
|
||||||
|
|
||||||
|
expect(notesState.setShowProtectedWarning).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('the note does not have protection sources', () => {
|
describe('the note does not have protection sources', () => {
|
||||||
it('should reveal note contents', async () => {
|
it('should reveal note contents', async () => {
|
||||||
jest.spyOn(ctrl['application'], 'hasProtectionSources').mockImplementation(() => false)
|
application.hasProtectionSources = jest.fn().mockReturnValue(false)
|
||||||
|
|
||||||
await ctrl.dismissProtectedWarning()
|
const noteView = new NoteView({
|
||||||
|
controller: noteViewController,
|
||||||
|
application,
|
||||||
|
})
|
||||||
|
|
||||||
expect(setShowProtectedWarningSpy).toHaveBeenCalledWith(false)
|
await noteView.dismissProtectedWarning()
|
||||||
|
|
||||||
|
expect(notesState.setShowProtectedWarning).toHaveBeenCalledWith(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { WebApplication } from '@/UIModels/Application'
|
|
||||||
import { createRef, JSX, RefObject } from 'preact'
|
import { createRef, JSX, RefObject } from 'preact'
|
||||||
import {
|
import {
|
||||||
ApplicationEvent,
|
ApplicationEvent,
|
||||||
@@ -15,8 +14,8 @@ import {
|
|||||||
PayloadEmitSource,
|
PayloadEmitSource,
|
||||||
} from '@standardnotes/snjs'
|
} from '@standardnotes/snjs'
|
||||||
import { debounce, isDesktopApplication } from '@/Utils'
|
import { debounce, isDesktopApplication } from '@/Utils'
|
||||||
|
import { EventSource } from '../../UIModels/AppState/EventSource'
|
||||||
import { KeyboardModifier, KeyboardKey } from '@/Services/IOService'
|
import { KeyboardModifier, KeyboardKey } from '@/Services/IOService'
|
||||||
import { EventSource } from '@/UIModels/AppState'
|
|
||||||
import { STRING_DELETE_PLACEHOLDER_ATTEMPT, STRING_DELETE_LOCKED_ATTEMPT, StringDeleteNote } from '@/Strings'
|
import { STRING_DELETE_PLACEHOLDER_ATTEMPT, STRING_DELETE_LOCKED_ATTEMPT, StringDeleteNote } from '@/Strings'
|
||||||
import { confirmDialog } from '@/Services/AlertService'
|
import { confirmDialog } from '@/Services/AlertService'
|
||||||
import { PureComponent } from '@/Components/Abstract/PureComponent'
|
import { PureComponent } from '@/Components/Abstract/PureComponent'
|
||||||
@@ -35,6 +34,7 @@ import {
|
|||||||
transactionForDisassociateComponentWithCurrentNote,
|
transactionForDisassociateComponentWithCurrentNote,
|
||||||
} from './TransactionFunctions'
|
} from './TransactionFunctions'
|
||||||
import { reloadFont } from './FontFunctions'
|
import { reloadFont } from './FontFunctions'
|
||||||
|
import { NoteViewProps } from './NoteViewProps'
|
||||||
|
|
||||||
const MINIMUM_STATUS_DURATION = 400
|
const MINIMUM_STATUS_DURATION = 400
|
||||||
const TEXTAREA_DEBOUNCE = 100
|
const TEXTAREA_DEBOUNCE = 100
|
||||||
@@ -78,12 +78,7 @@ type State = {
|
|||||||
rightResizerOffset: number
|
rightResizerOffset: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
export class NoteView extends PureComponent<NoteViewProps, State> {
|
||||||
application: WebApplication
|
|
||||||
controller: NoteViewController
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NoteView extends PureComponent<Props, State> {
|
|
||||||
readonly controller!: NoteViewController
|
readonly controller!: NoteViewController
|
||||||
|
|
||||||
private statusTimeout?: NodeJS.Timeout
|
private statusTimeout?: NodeJS.Timeout
|
||||||
@@ -101,7 +96,7 @@ export class NoteView extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
private editorContentRef: RefObject<HTMLDivElement>
|
private editorContentRef: RefObject<HTMLDivElement>
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: NoteViewProps) {
|
||||||
super(props, props.application)
|
super(props, props.application)
|
||||||
|
|
||||||
this.controller = props.controller
|
this.controller = props.controller
|
||||||
@@ -217,7 +212,7 @@ export class NoteView extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override componentDidUpdate(_prevProps: Props, prevState: State): void {
|
override componentDidUpdate(_prevProps: NoteViewProps, prevState: State): void {
|
||||||
if (
|
if (
|
||||||
this.state.showProtectedWarning != undefined &&
|
this.state.showProtectedWarning != undefined &&
|
||||||
prevState.showProtectedWarning !== this.state.showProtectedWarning
|
prevState.showProtectedWarning !== this.state.showProtectedWarning
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { NoteViewController } from '@standardnotes/snjs'
|
||||||
|
|
||||||
|
import { WebApplication } from '@/UIModels/Application'
|
||||||
|
|
||||||
|
export interface NoteViewProps {
|
||||||
|
application: WebApplication
|
||||||
|
controller: NoteViewController
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ButtonType, sanitizeHtmlString, AlertService } from '@standardnotes/snjs'
|
import { ButtonType, sanitizeHtmlString } from '@standardnotes/snjs'
|
||||||
|
import { AlertService } from '@standardnotes/services'
|
||||||
import { SKAlert } from '@standardnotes/stylekit'
|
import { SKAlert } from '@standardnotes/stylekit'
|
||||||
|
|
||||||
/** @returns a promise resolving to true if the user confirmed, false if they canceled */
|
/** @returns a promise resolving to true if the user confirmed, false if they canceled */
|
||||||
|
|||||||
@@ -31,17 +31,13 @@ import { AbstractState } from './AbstractState'
|
|||||||
import { SelectedItemsState } from './SelectedItemsState'
|
import { SelectedItemsState } from './SelectedItemsState'
|
||||||
import { ListableContentItem } from '@/Components/ContentListView/Types/ListableContentItem'
|
import { ListableContentItem } from '@/Components/ContentListView/Types/ListableContentItem'
|
||||||
import { AppStateEvent } from './AppStateEvent'
|
import { AppStateEvent } from './AppStateEvent'
|
||||||
|
import { EventSource } from './EventSource'
|
||||||
|
|
||||||
export type PanelResizedData = {
|
export type PanelResizedData = {
|
||||||
panel: string
|
panel: string
|
||||||
collapsed: boolean
|
collapsed: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EventSource {
|
|
||||||
UserInteraction,
|
|
||||||
Script,
|
|
||||||
}
|
|
||||||
|
|
||||||
type ObserverCallback = (event: AppStateEvent, data?: unknown) => Promise<void>
|
type ObserverCallback = (event: AppStateEvent, data?: unknown) => Promise<void>
|
||||||
|
|
||||||
export class AppState extends AbstractState {
|
export class AppState extends AbstractState {
|
||||||
|
|||||||
4
app/assets/javascripts/UIModels/AppState/EventSource.ts
Normal file
4
app/assets/javascripts/UIModels/AppState/EventSource.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export enum EventSource {
|
||||||
|
UserInteraction,
|
||||||
|
Script,
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export { AppState, EventSource, PanelResizedData } from './AppState'
|
export { AppState, PanelResizedData } from './AppState'
|
||||||
export * from './AppStateEvent'
|
export * from './AppStateEvent'
|
||||||
|
export * from './EventSource'
|
||||||
export * from './PurchaseFlowPane'
|
export * from './PurchaseFlowPane'
|
||||||
|
|||||||
@@ -25,4 +25,12 @@ module.exports = {
|
|||||||
'^.+\\.(ts|tsx)?$': 'ts-jest',
|
'^.+\\.(ts|tsx)?$': 'ts-jest',
|
||||||
'\\.svg$': 'svg-jest',
|
'\\.svg$': 'svg-jest',
|
||||||
},
|
},
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
branches: 3,
|
||||||
|
functions: 5,
|
||||||
|
lines: 21,
|
||||||
|
statements: 22,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
"setup": "bundle install && yarn install --frozen-lockfile && bundle exec rails assets:precompile && yarn bundle",
|
"setup": "bundle install && yarn install --frozen-lockfile && bundle exec rails assets:precompile && yarn bundle",
|
||||||
"lint": "eslint --fix app/assets/javascripts",
|
"lint": "eslint --fix app/assets/javascripts",
|
||||||
"tsc": "tsc --project app/assets/javascripts/tsconfig.json",
|
"tsc": "tsc --project app/assets/javascripts/tsconfig.json",
|
||||||
"test": "jest --config app/assets/javascripts/jest.config.js",
|
"test": "jest --config app/assets/javascripts/jest.config.js --coverage",
|
||||||
"test:coverage": "yarn test --coverage",
|
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"postinstall": "yarn run ncu -loglevel verbose --packageFile package.json",
|
"postinstall": "yarn run ncu -loglevel verbose --packageFile package.json",
|
||||||
"upgrade:snjs": "ncu -u '@standardnotes/*' && yarn"
|
"upgrade:snjs": "ncu -u '@standardnotes/*' && yarn"
|
||||||
@@ -73,8 +72,9 @@
|
|||||||
"@standardnotes/components": "1.8.1",
|
"@standardnotes/components": "1.8.1",
|
||||||
"@standardnotes/filepicker": "1.16.0",
|
"@standardnotes/filepicker": "1.16.0",
|
||||||
"@standardnotes/icons": "^1.1.7",
|
"@standardnotes/icons": "^1.1.7",
|
||||||
|
"@standardnotes/services": "^1.13.1",
|
||||||
"@standardnotes/sncrypto-web": "1.10.1",
|
"@standardnotes/sncrypto-web": "1.10.1",
|
||||||
"@standardnotes/snjs": "2.113.2",
|
"@standardnotes/snjs": "^2.113.2",
|
||||||
"@standardnotes/stylekit": "5.29.0",
|
"@standardnotes/stylekit": "5.29.0",
|
||||||
"@zip.js/zip.js": "^2.4.10",
|
"@zip.js/zip.js": "^2.4.10",
|
||||||
"mobx": "^6.5.0",
|
"mobx": "^6.5.0",
|
||||||
|
|||||||
@@ -2402,7 +2402,7 @@
|
|||||||
buffer "^6.0.3"
|
buffer "^6.0.3"
|
||||||
libsodium-wrappers "^0.7.9"
|
libsodium-wrappers "^0.7.9"
|
||||||
|
|
||||||
"@standardnotes/snjs@2.113.2":
|
"@standardnotes/snjs@^2.113.2":
|
||||||
version "2.113.2"
|
version "2.113.2"
|
||||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.113.2.tgz#efcd435c7e699397f94caa76273440ff56f3f91f"
|
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.113.2.tgz#efcd435c7e699397f94caa76273440ff56f3f91f"
|
||||||
integrity sha512-P93YfvJJJsntiILezwQUkx0ta5Amjd3Pte9+KkUFcLGBL1pkdtoY5lHc1oreWMElYuPTA+K9WrU6/tWa2OVa5A==
|
integrity sha512-P93YfvJJJsntiILezwQUkx0ta5Amjd3Pte9+KkUFcLGBL1pkdtoY5lHc1oreWMElYuPTA+K9WrU6/tWa2OVa5A==
|
||||||
|
|||||||
Reference in New Issue
Block a user