mirror of
https://github.com/standardnotes/app
synced 2026-09-14 03:46:01 -04:00
Compare commits
66
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccb15faff5 | ||
|
|
dc33aef660 | ||
|
|
771758fcd4 | ||
|
|
3fbe28e068 | ||
|
|
e67240821c | ||
|
|
d7c6ef6134 | ||
|
|
8311271a49 | ||
|
|
4e61d9b3e3 | ||
|
|
dd41082e71 | ||
|
|
adc6e9a353 | ||
|
|
bfd9f37331 | ||
|
|
044a4fc36b | ||
|
|
fe4841c631 | ||
|
|
14a98b5736 | ||
|
|
326e1a455b | ||
|
|
c3c8c2b9ce | ||
|
|
5e79cf90f4 | ||
|
|
e798b71b9f | ||
|
|
afd89c387f | ||
|
|
6bf6924a8b | ||
|
|
0f7b1539e0 | ||
|
|
e1c21d5fbd | ||
|
|
52d0fed437 | ||
|
|
caee8f1c6f | ||
|
|
40194d010f | ||
|
|
0373bf9a2d | ||
|
|
d7eb43401a | ||
|
|
a5a866a62a | ||
|
|
6090962b2c | ||
|
|
a9445dfcca | ||
|
|
b3fe769a60 | ||
|
|
fc6d28d166 | ||
|
|
03eac4353d | ||
|
|
58d84c47c1 | ||
|
|
577318e208 | ||
|
|
b8da877804 | ||
|
|
17f4d20fb5 | ||
|
|
4f07b915f0 | ||
|
|
f2f61b18e2 | ||
|
|
9fb506e532 | ||
|
|
3b64acc290 | ||
|
|
e6824a3414 | ||
|
|
08985bb5c8 | ||
|
|
77cb6e7891 | ||
|
|
7e7c5e14ab | ||
|
|
631be2e494 | ||
|
|
fe36009482 | ||
|
|
e77e852801 | ||
|
|
c59d824240 | ||
|
|
2f3bc9b85b | ||
|
|
1ec173dcd6 | ||
|
|
35b00737bf | ||
|
|
f3e147f4c9 | ||
|
|
63fdb328cb | ||
|
|
94c280256e | ||
|
|
cf0dc19f63 | ||
|
|
2696b07759 | ||
|
|
2cc5afb00a | ||
|
|
1828f80ba5 | ||
|
|
9c260c02f1 | ||
|
|
e4b3028d67 | ||
|
|
eceb46bed7 | ||
|
|
b9e0d0d154 | ||
|
|
a7add80633 | ||
|
|
0941183c8b | ||
|
|
c94035c1d6 |
@@ -67,11 +67,11 @@ jobs:
|
||||
uses: convictional/trigger-workflow-and-wait@master
|
||||
with:
|
||||
owner: standardnotes
|
||||
repo: e2e
|
||||
repo: self-hosted
|
||||
github_token: ${{ secrets.CI_PAT_TOKEN }}
|
||||
workflow_file_name: testing-with-stable-server.yml
|
||||
workflow_file_name: testing-with-updating-client-and-server.yml
|
||||
wait_interval: 30
|
||||
client_payload: '{"image_tag": "${{ github.sha }}"}'
|
||||
client_payload: '{"snjs_image_tag": "${{ github.sha }}"}'
|
||||
propagate_failure: true
|
||||
trigger_workflow: true
|
||||
wait_workflow: true
|
||||
|
||||
@@ -43,11 +43,11 @@ jobs:
|
||||
uses: convictional/trigger-workflow-and-wait@master
|
||||
with:
|
||||
owner: standardnotes
|
||||
repo: e2e
|
||||
repo: self-hosted
|
||||
github_token: ${{ secrets.CI_PAT_TOKEN }}
|
||||
workflow_file_name: testing-with-stable-server.yml
|
||||
workflow_file_name: testing-with-updating-client-and-server.yml
|
||||
wait_interval: 30
|
||||
client_payload: '{"image_tag": "${{ github.sha }}"}'
|
||||
client_payload: '{"snjs_image_tag": "${{ github.sha }}"}'
|
||||
propagate_failure: true
|
||||
trigger_workflow: true
|
||||
wait_workflow: true
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.20.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.20.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api:** handling expired token responses ([#2113](https://github.com/standardnotes/app/issues/2113)) ([2696b07](https://github.com/standardnotes/app/commit/2696b07759104fb1d40781897f69e63133ad824a))
|
||||
|
||||
## [1.20.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.20.21",
|
||||
"version": "1.20.23",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -115,7 +115,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
return false
|
||||
}
|
||||
|
||||
const response = (await this.post(joinPaths(this.host, Paths.v1.refreshSession), {
|
||||
const response = (await this.post(Paths.v1.refreshSession, {
|
||||
access_token: this.session.accessToken.value,
|
||||
refresh_token: this.session.refreshToken.value,
|
||||
})) as SessionRefreshResponse
|
||||
@@ -265,13 +265,12 @@ export class HttpService implements HttpServiceInterface {
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
if (httpStatus >= HttpStatusCode.Success && httpStatus < HttpStatusCode.MultipleChoices) {
|
||||
resolve(response)
|
||||
} else {
|
||||
if (httpStatus >= HttpStatusCode.Success && httpStatus < HttpStatusCode.InternalServerError) {
|
||||
if (httpStatus === HttpStatusCode.Forbidden && response.data && response.data.error !== undefined) {
|
||||
;(response.data as HttpErrorResponseBody).error.message = ErrorMessage.RateLimited
|
||||
}
|
||||
|
||||
resolve(response)
|
||||
} else {
|
||||
reject(response)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ export enum HttpStatusCode {
|
||||
Forbidden = 403,
|
||||
Gone = 410,
|
||||
ExpiredAccessToken = 498,
|
||||
InternalServerError = 500,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.12.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/blocks-editor
|
||||
|
||||
# [1.12.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
### Features
|
||||
|
||||
* Clicking the link option in Super notes will automatically add the selected text as the link ([326e1a4](https://github.com/standardnotes/app/commit/326e1a455bb510d795f357123f617618267848cc))
|
||||
|
||||
## [1.11.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/blocks-editor
|
||||
|
||||
## [1.11.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/blocks-editor
|
||||
|
||||
## [1.11.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/blocks-editor
|
||||
|
||||
# [1.11.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
### Features
|
||||
|
||||
* Persist collapsible block state in Super notes ([#2119](https://github.com/standardnotes/app/issues/2119)) ([577318e](https://github.com/standardnotes/app/commit/577318e208367dc52caf2d76fd87419eaead7ed4))
|
||||
|
||||
## [1.10.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/blocks-editor
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/blocks-editor
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@standardnotes/blocks-editor",
|
||||
"version": "1.10.1",
|
||||
"version": "1.12.1",
|
||||
"private": true,
|
||||
"main": "./src/index.ts",
|
||||
"scripts": {
|
||||
"tsc": "tsc -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lexical/react": "^0.6.5",
|
||||
"@lexical/react": "0.7.5",
|
||||
"@standardnotes/icons": "workspace:*",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"lexical": "^0.6.5",
|
||||
"lexical": "0.7.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ import DraggableBlockPlugin from '../Lexical/Plugins/DraggableBlockPlugin';
|
||||
import CodeHighlightPlugin from '../Lexical/Plugins/CodeHighlightPlugin';
|
||||
import FloatingTextFormatToolbarPlugin from '../Lexical/Plugins/FloatingTextFormatToolbarPlugin';
|
||||
import FloatingLinkEditorPlugin from '../Lexical/Plugins/FloatingLinkEditorPlugin';
|
||||
import {TabIndentationPlugin} from '../Lexical/Plugins/TabIndentationPlugin';
|
||||
import {truncateString} from './Utils';
|
||||
import {SuperEditorContentId} from './Constants';
|
||||
import {classNames} from '@standardnotes/utils';
|
||||
@@ -107,7 +108,7 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
placeholder=""
|
||||
placeholder={null}
|
||||
ErrorBoundary={LexicalErrorBoundary}
|
||||
/>
|
||||
<ListPlugin />
|
||||
@@ -125,6 +126,7 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
|
||||
<TwitterPlugin />
|
||||
<YouTubePlugin />
|
||||
<CollapsiblePlugin />
|
||||
<TabIndentationPlugin />
|
||||
{!readonly && floatingAnchorElem && (
|
||||
<>
|
||||
<FloatingTextFormatToolbarPlugin anchorElem={floatingAnchorElem} />
|
||||
|
||||
@@ -192,9 +192,10 @@ export function AutoEmbedDialog({
|
||||
const embedResult =
|
||||
text != null && urlMatch != null ? embedConfig.parseUrl(text) : null;
|
||||
|
||||
const onClick = () => {
|
||||
if (embedResult != null) {
|
||||
embedConfig.insertNode(editor, embedResult);
|
||||
const onClick = async () => {
|
||||
const result = await embedResult;
|
||||
if (result != null) {
|
||||
embedConfig.insertNode(editor, result);
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
+16
-10
@@ -20,6 +20,7 @@ type SerializedCollapsibleContainerNode = Spread<
|
||||
{
|
||||
type: 'collapsible-container';
|
||||
version: 1;
|
||||
open: boolean;
|
||||
},
|
||||
SerializedElementNode
|
||||
>;
|
||||
@@ -29,25 +30,27 @@ export class CollapsibleContainerNode extends ElementNode {
|
||||
|
||||
constructor(open: boolean, key?: NodeKey) {
|
||||
super(key);
|
||||
this.__open = open;
|
||||
this.__open = open ?? false;
|
||||
}
|
||||
|
||||
static getType(): string {
|
||||
static override getType(): string {
|
||||
return 'collapsible-container';
|
||||
}
|
||||
|
||||
static clone(node: CollapsibleContainerNode): CollapsibleContainerNode {
|
||||
static override clone(
|
||||
node: CollapsibleContainerNode,
|
||||
): CollapsibleContainerNode {
|
||||
return new CollapsibleContainerNode(node.__open, node.__key);
|
||||
}
|
||||
|
||||
createDOM(config: EditorConfig): HTMLElement {
|
||||
override createDOM(config: EditorConfig): HTMLElement {
|
||||
const dom = document.createElement('details');
|
||||
dom.classList.add('Collapsible__container');
|
||||
dom.open = this.__open;
|
||||
return dom;
|
||||
}
|
||||
|
||||
updateDOM(
|
||||
override updateDOM(
|
||||
prevNode: CollapsibleContainerNode,
|
||||
dom: HTMLDetailsElement,
|
||||
): boolean {
|
||||
@@ -62,18 +65,19 @@ export class CollapsibleContainerNode extends ElementNode {
|
||||
return {};
|
||||
}
|
||||
|
||||
static importJSON(
|
||||
static override importJSON(
|
||||
serializedNode: SerializedCollapsibleContainerNode,
|
||||
): CollapsibleContainerNode {
|
||||
const node = $createCollapsibleContainerNode();
|
||||
const node = $createCollapsibleContainerNode(serializedNode.open);
|
||||
return node;
|
||||
}
|
||||
|
||||
exportJSON(): SerializedCollapsibleContainerNode {
|
||||
override exportJSON(): SerializedCollapsibleContainerNode {
|
||||
return {
|
||||
...super.exportJSON(),
|
||||
type: 'collapsible-container',
|
||||
version: 1,
|
||||
open: this.__open,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,8 +95,10 @@ export class CollapsibleContainerNode extends ElementNode {
|
||||
}
|
||||
}
|
||||
|
||||
export function $createCollapsibleContainerNode(): CollapsibleContainerNode {
|
||||
return new CollapsibleContainerNode(true);
|
||||
export function $createCollapsibleContainerNode(
|
||||
open: boolean,
|
||||
): CollapsibleContainerNode {
|
||||
return new CollapsibleContainerNode(open);
|
||||
}
|
||||
|
||||
export function $isCollapsibleContainerNode(
|
||||
|
||||
+10
-7
@@ -24,21 +24,24 @@ type SerializedCollapsibleContentNode = Spread<
|
||||
>;
|
||||
|
||||
export class CollapsibleContentNode extends ElementNode {
|
||||
static getType(): string {
|
||||
static override getType(): string {
|
||||
return 'collapsible-content';
|
||||
}
|
||||
|
||||
static clone(node: CollapsibleContentNode): CollapsibleContentNode {
|
||||
static override clone(node: CollapsibleContentNode): CollapsibleContentNode {
|
||||
return new CollapsibleContentNode(node.__key);
|
||||
}
|
||||
|
||||
createDOM(config: EditorConfig): HTMLElement {
|
||||
override createDOM(config: EditorConfig): HTMLElement {
|
||||
const dom = document.createElement('div');
|
||||
dom.classList.add('Collapsible__content');
|
||||
return dom;
|
||||
}
|
||||
|
||||
updateDOM(prevNode: CollapsibleContentNode, dom: HTMLElement): boolean {
|
||||
override updateDOM(
|
||||
prevNode: CollapsibleContentNode,
|
||||
dom: HTMLElement,
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,17 +49,17 @@ export class CollapsibleContentNode extends ElementNode {
|
||||
return {};
|
||||
}
|
||||
|
||||
static importJSON(
|
||||
static override importJSON(
|
||||
serializedNode: SerializedCollapsibleContentNode,
|
||||
): CollapsibleContentNode {
|
||||
return $createCollapsibleContentNode();
|
||||
}
|
||||
|
||||
isShadowRoot(): boolean {
|
||||
override isShadowRoot(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
exportJSON(): SerializedCollapsibleContentNode {
|
||||
override exportJSON(): SerializedCollapsibleContentNode {
|
||||
return {
|
||||
...super.exportJSON(),
|
||||
type: 'collapsible-content',
|
||||
|
||||
+21
-8
@@ -31,21 +31,34 @@ type SerializedCollapsibleTitleNode = Spread<
|
||||
>;
|
||||
|
||||
export class CollapsibleTitleNode extends ElementNode {
|
||||
static getType(): string {
|
||||
static override getType(): string {
|
||||
return 'collapsible-title';
|
||||
}
|
||||
|
||||
static clone(node: CollapsibleTitleNode): CollapsibleTitleNode {
|
||||
static override clone(node: CollapsibleTitleNode): CollapsibleTitleNode {
|
||||
return new CollapsibleTitleNode(node.__key);
|
||||
}
|
||||
|
||||
createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement {
|
||||
override createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement {
|
||||
const dom = document.createElement('summary');
|
||||
dom.classList.add('Collapsible__title');
|
||||
dom.onclick = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
editor.update(() => {
|
||||
const containerNode = this.getParentOrThrow();
|
||||
if ($isCollapsibleContainerNode(containerNode)) {
|
||||
containerNode.toggleOpen();
|
||||
}
|
||||
});
|
||||
};
|
||||
return dom;
|
||||
}
|
||||
|
||||
updateDOM(prevNode: CollapsibleTitleNode, dom: HTMLElement): boolean {
|
||||
override updateDOM(
|
||||
prevNode: CollapsibleTitleNode,
|
||||
dom: HTMLElement,
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -53,13 +66,13 @@ export class CollapsibleTitleNode extends ElementNode {
|
||||
return {};
|
||||
}
|
||||
|
||||
static importJSON(
|
||||
static override importJSON(
|
||||
serializedNode: SerializedCollapsibleTitleNode,
|
||||
): CollapsibleTitleNode {
|
||||
return $createCollapsibleTitleNode();
|
||||
}
|
||||
|
||||
exportJSON(): SerializedCollapsibleTitleNode {
|
||||
override exportJSON(): SerializedCollapsibleTitleNode {
|
||||
return {
|
||||
...super.exportJSON(),
|
||||
type: 'collapsible-title',
|
||||
@@ -67,12 +80,12 @@ export class CollapsibleTitleNode extends ElementNode {
|
||||
};
|
||||
}
|
||||
|
||||
collapseAtStart(_selection: RangeSelection): boolean {
|
||||
override collapseAtStart(_selection: RangeSelection): boolean {
|
||||
this.getParentOrThrow().insertBefore(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
insertNewAfter(): ElementNode {
|
||||
override insertNewAfter(): ElementNode {
|
||||
const containerNode = this.getParentOrThrow();
|
||||
|
||||
if (!$isCollapsibleContainerNode(containerNode)) {
|
||||
|
||||
@@ -204,7 +204,7 @@ export default function CollapsiblePlugin(): JSX.Element | null {
|
||||
const content = $createCollapsibleContentNode().append(
|
||||
$createParagraphNode(),
|
||||
);
|
||||
const container = $createCollapsibleContainerNode().append(
|
||||
const container = $createCollapsibleContainerNode(true).append(
|
||||
title,
|
||||
content,
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@ import {mergeRegister} from '@lexical/utils';
|
||||
import {
|
||||
$getNearestNodeFromDOMNode,
|
||||
$getNodeByKey,
|
||||
$getRoot,
|
||||
COMMAND_PRIORITY_HIGH,
|
||||
COMMAND_PRIORITY_LOW,
|
||||
DRAGOVER_COMMAND,
|
||||
@@ -58,8 +59,7 @@ function getCurrentIndex(keysLength: number): number {
|
||||
}
|
||||
|
||||
function getTopLevelNodeKeys(editor: LexicalEditor): string[] {
|
||||
const root = editor.getEditorState()._nodeMap.get('root');
|
||||
return root ? root.__children : [];
|
||||
return editor.getEditorState().read(() => $getRoot().getChildrenKeys());
|
||||
}
|
||||
|
||||
function elementContainingEventLocation(
|
||||
|
||||
+10
-1
@@ -54,6 +54,7 @@ import {
|
||||
ListNumbered,
|
||||
} from '@standardnotes/icons';
|
||||
import {IconComponent} from '../../Theme/IconComponent';
|
||||
import {sanitizeUrl} from '../../Utils/sanitizeUrl';
|
||||
|
||||
const blockTypeToBlockName = {
|
||||
bullet: 'Bulleted List',
|
||||
@@ -103,7 +104,15 @@ function TextFormatFloatingToolbar({
|
||||
|
||||
const insertLink = useCallback(() => {
|
||||
if (!isLink) {
|
||||
editor.dispatchCommand(TOGGLE_LINK_COMMAND, 'https://');
|
||||
editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
const textContent = selection?.getTextContent();
|
||||
if (!textContent) {
|
||||
editor.dispatchCommand(TOGGLE_LINK_COMMAND, 'https://');
|
||||
return;
|
||||
}
|
||||
editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(textContent));
|
||||
});
|
||||
} else {
|
||||
editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {
|
||||
$getSelection,
|
||||
$isRangeSelection,
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
INDENT_CONTENT_COMMAND,
|
||||
KEY_TAB_COMMAND,
|
||||
OUTDENT_CONTENT_COMMAND,
|
||||
} from 'lexical';
|
||||
import {useEffect} from 'react';
|
||||
|
||||
/**
|
||||
* This plugin adds the ability to indent content using the tab key. Generally, we don't
|
||||
* recommend using this plugin as it could negatively affect acessibility for keyboard
|
||||
* users, causing focus to become trapped within the editor.
|
||||
*/
|
||||
export function TabIndentationPlugin(): null {
|
||||
const [editor] = useLexicalComposerContext();
|
||||
|
||||
useEffect(() => {
|
||||
return editor.registerCommand<KeyboardEvent>(
|
||||
KEY_TAB_COMMAND,
|
||||
(event) => {
|
||||
const selection = $getSelection();
|
||||
|
||||
if (!$isRangeSelection(selection)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
return editor.dispatchCommand(
|
||||
event.shiftKey ? OUTDENT_CONTENT_COMMAND : INDENT_CONTENT_COMMAND,
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
);
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -3,6 +3,94 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.104.53](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.52](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.51](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.50](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.45](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.44](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.43](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.42](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.41](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.40](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.39](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.38](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.37](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.36](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.104.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.104.31",
|
||||
"version": "3.104.53",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.19.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.19.27](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.19.27",
|
||||
"version": "1.19.28",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.27.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.27.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.27.4",
|
||||
"version": "1.27.6",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -46,6 +46,8 @@ function selectFiles(): Promise<File[]> {
|
||||
files.push(file)
|
||||
}
|
||||
resolve(files)
|
||||
// Reset input value so that onchange is triggered again if the same file is selected
|
||||
input.value = ''
|
||||
}
|
||||
input.click()
|
||||
})
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.14.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.14.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.14.4",
|
||||
"version": "1.14.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,94 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.49.50](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.45](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.44](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.43](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.42](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.41](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.40](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.39](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.38](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.37](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.36](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.30](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.49.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
@@ -583,7 +583,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
FBLazyVector: 48289402952f4f7a4e235de70a9a590aa0b79ef4
|
||||
FBReactNativeSpec: dd1186fd05255e3457baa2f4ca65e94c2cd1e3ac
|
||||
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
|
||||
@@ -596,7 +596,7 @@ SPEC CHECKSUMS:
|
||||
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
||||
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
glog: 85ecdd10ee8d8ec362ef519a6a45ff9aa27b2e85
|
||||
hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.49.28",
|
||||
"version": "3.49.50",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.40.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
### Features
|
||||
|
||||
* Allow changing per-view display preferences for system views ([#2120](https://github.com/standardnotes/app/issues/2120)) ([dc33aef](https://github.com/standardnotes/app/commit/dc33aef6608a364107a884ad2f26c14bceea23b7))
|
||||
|
||||
## [1.39.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.39.3",
|
||||
"version": "1.40.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { CollectionSortProperty } from '../../Runtime/Collection/CollectionSort'
|
||||
import { EditorIdentifier, FeatureIdentifier } from '@standardnotes/features'
|
||||
import { SystemViewId } from '../SmartView'
|
||||
import { TagPreferences } from '../Tag'
|
||||
|
||||
export enum PrefKey {
|
||||
TagsPanelWidth = 'tagsPanelWidth',
|
||||
@@ -40,6 +42,7 @@ export enum PrefKey {
|
||||
DarkMode = 'darkMode',
|
||||
DefaultEditorIdentifier = 'defaultEditorIdentifier',
|
||||
MomentsDefaultTagUuid = 'momentsDefaultTagUuid',
|
||||
SystemViewPreferences = 'systemViewPreferences',
|
||||
}
|
||||
|
||||
export enum NewNoteTitleFormat {
|
||||
@@ -105,4 +108,5 @@ export type PrefValue = {
|
||||
[PrefKey.DarkMode]: boolean
|
||||
[PrefKey.DefaultEditorIdentifier]: EditorIdentifier
|
||||
[PrefKey.MomentsDefaultTagUuid]: string | undefined
|
||||
[PrefKey.SystemViewPreferences]: Partial<Record<SystemViewId, TagPreferences>>
|
||||
}
|
||||
|
||||
@@ -3,6 +3,94 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.76](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.75](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.74](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.73](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.72](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.71](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.70](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.69](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.67](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.64](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.62](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.61](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.60](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.59](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.58](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.57](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.56](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.4.54",
|
||||
"version": "1.4.76",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.50.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.50.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.50.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.50.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.50.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.50.7",
|
||||
"version": "1.50.11",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -18,4 +18,5 @@ export interface WebApplicationInterface extends ApplicationInterface {
|
||||
handleAndroidBackButtonPressed(): void
|
||||
addAndroidBackHandlerEventListener(listener: () => boolean): (() => void) | undefined
|
||||
setAndroidBackHandlerFallbackListener(listener: () => boolean): void
|
||||
generateUUID(): string
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ export interface ItemsClientInterface {
|
||||
|
||||
getItems<T extends DecryptedItemInterface>(contentType: ContentType | ContentType[]): T[]
|
||||
|
||||
insertItem(item: DecryptedItemInterface): Promise<DecryptedItemInterface>
|
||||
|
||||
notesMatchingSmartView(view: SmartView): SNNote[]
|
||||
|
||||
addNoteCountChangeObserver(observer: TagItemCountChangeObserver): () => void
|
||||
|
||||
@@ -4,8 +4,6 @@ export const InfoStrings = {
|
||||
'This backup file was created using a newer version of the application and cannot be imported here. Please update your application and try again.',
|
||||
BackupFileMoreRecentThanAccount:
|
||||
"This backup file was created using a newer encryption version than your account's. Please run the available encryption upgrade and try again.",
|
||||
SavingWhileDocumentHidden:
|
||||
'Attempting to save an item while the application is hidden. To protect data integrity, please refresh the application window and try again.',
|
||||
InvalidNote:
|
||||
"The note you are attempting to save can not be found or has been deleted. Changes you make will not be synced. Please copy this note's text and start a new note.",
|
||||
}
|
||||
|
||||
@@ -3,6 +3,42 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.156.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.156.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.156.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **snjs:** skip workspaces tests as they are a pending backlog feature ([8311271](https://github.com/standardnotes/app/commit/8311271a49fe707adc4e26c7b465861e65ee9006))
|
||||
|
||||
## [2.156.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **snjs:** add error log upon not being able to reach the mock event publisher ([dd41082](https://github.com/standardnotes/app/commit/dd41082e7174a6068d1d7741e007867fc03a5da8))
|
||||
|
||||
## [2.156.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Disabled Moments photo capture when app is passcode or biometrics locked ([#2114](https://github.com/standardnotes/app/issues/2114)) ([94c2802](https://github.com/standardnotes/app/commit/94c280256e0a71fb8078f0d0e4d7ad2b6d3c1462))
|
||||
|
||||
## [2.156.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api:** handling expired token responses ([#2113](https://github.com/standardnotes/app/issues/2113)) ([2696b07](https://github.com/standardnotes/app/commit/2696b07759104fb1d40781897f69e63133ad824a))
|
||||
|
||||
## [2.156.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.156.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -178,6 +178,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
private launched = false
|
||||
/** Whether the application has been destroyed via .deinit() */
|
||||
public dealloced = false
|
||||
private isBiometricsSoftLockEngaged = false
|
||||
private revokingSession = false
|
||||
private handledFullSyncStage = false
|
||||
|
||||
@@ -940,11 +941,12 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
return this.protocolService.hasPasscode()
|
||||
}
|
||||
|
||||
isLocked(): Promise<boolean> {
|
||||
async isLocked(): Promise<boolean> {
|
||||
if (!this.started) {
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
return this.challengeService.isPasscodeLocked()
|
||||
const isPasscodeLocked = await this.challengeService.isPasscodeLocked()
|
||||
return isPasscodeLocked || this.isBiometricsSoftLockEngaged
|
||||
}
|
||||
|
||||
public async lock(): Promise<void> {
|
||||
@@ -964,10 +966,12 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
|
||||
void this.promptForCustomChallenge(challenge)
|
||||
|
||||
this.isBiometricsSoftLockEngaged = true
|
||||
void this.notifyEvent(ApplicationEvent.BiometricsSoftLockEngaged)
|
||||
|
||||
this.addChallengeObserver(challenge, {
|
||||
onComplete: () => {
|
||||
this.isBiometricsSoftLockEngaged = false
|
||||
void this.notifyEvent(ApplicationEvent.BiometricsSoftLockDisengaged)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -72,7 +72,7 @@ export function getDefaultHost() {
|
||||
}
|
||||
|
||||
export async function publishMockedEvent(eventType, eventPayload) {
|
||||
await fetch(`${Defaults.getDefaultMockedEventServiceUrl()}/events`, {
|
||||
const response = await fetch(`${Defaults.getDefaultMockedEventServiceUrl()}/events`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
@@ -83,6 +83,10 @@ export async function publishMockedEvent(eventType, eventPayload) {
|
||||
eventPayload,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Failed to publish mocked event: ${response.status} ${response.statusText}`)
|
||||
}
|
||||
}
|
||||
|
||||
export function createApplicationWithFakeCrypto(identifier, environment, platform, host) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe.skip('subscriptions', function () {
|
||||
describe('subscriptions', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let application
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('workspaces', function () {
|
||||
describe.skip('workspaces', function () {
|
||||
this.timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
let ownerContext
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.156.6",
|
||||
"version": "2.156.13",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.21.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.21.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
# [1.21.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
### Features
|
||||
|
||||
* Added FileSend links to general account menu and preferences menu ([4f07b91](https://github.com/standardnotes/app/commit/4f07b915f0a60632a9e537b3b0394290d25fa071))
|
||||
|
||||
## [1.20.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.20.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.20.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.20.2",
|
||||
"version": "1.21.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { AegisToAuthenticatorConverter } from './AegisToAuthenticatorConverter'
|
||||
import data from './testData'
|
||||
|
||||
describe('AegisConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('test'),
|
||||
} as unknown as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse entries', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
|
||||
const result = converter.parseEntries(data)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.length).toBe(2)
|
||||
expect(result?.[0]).toStrictEqual({
|
||||
service: 'TestMail',
|
||||
account: '[email protected]',
|
||||
secret: 'TESTMAILTESTMAILTESTMAILTESTMAIL',
|
||||
notes: 'Some note',
|
||||
})
|
||||
expect(result?.[1]).toStrictEqual({
|
||||
service: 'Some Service',
|
||||
account: '[email protected]',
|
||||
secret: 'SOMESERVICESOMESERVICESOMESERVIC',
|
||||
notes: 'Some other service',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create note from entries with editor info', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
|
||||
const parsedEntries = converter.parseEntries(data)
|
||||
|
||||
const result = converter.createNoteFromEntries(
|
||||
parsedEntries!,
|
||||
{
|
||||
lastModified: 123456789,
|
||||
name: 'test.json',
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result.content_type).toBe('Note')
|
||||
expect(result.created_at).toBeInstanceOf(Date)
|
||||
expect(result.updated_at).toBeInstanceOf(Date)
|
||||
expect(result.uuid).not.toBeNull()
|
||||
expect(result.content.title).toBe('test')
|
||||
expect(result.content.text).toBe(
|
||||
'[{"service":"TestMail","account":"[email protected]","secret":"TESTMAILTESTMAILTESTMAILTESTMAIL","notes":"Some note"},{"service":"Some Service","account":"[email protected]","secret":"SOMESERVICESOMESERVICESOMESERVIC","notes":"Some other service"}]',
|
||||
)
|
||||
expect(result.content.noteType).toBe(NoteType.Authentication)
|
||||
expect(result.content.editorIdentifier).toBe(FeatureIdentifier.TokenVaultEditor)
|
||||
})
|
||||
|
||||
it('should create note from entries without editor info', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
|
||||
const parsedEntries = converter.parseEntries(data)
|
||||
|
||||
const result = converter.createNoteFromEntries(
|
||||
parsedEntries!,
|
||||
{
|
||||
lastModified: 123456789,
|
||||
name: 'test.json',
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result.content_type).toBe('Note')
|
||||
expect(result.created_at).toBeInstanceOf(Date)
|
||||
expect(result.updated_at).toBeInstanceOf(Date)
|
||||
expect(result.uuid).not.toBeNull()
|
||||
expect(result.content.title).toBe('test')
|
||||
expect(result.content.text).toBe(
|
||||
'[{"service":"TestMail","account":"[email protected]","secret":"TESTMAILTESTMAILTESTMAILTESTMAIL","notes":"Some note"},{"service":"Some Service","account":"[email protected]","secret":"SOMESERVICESOMESERVICESOMESERVIC","notes":"Some other service"}]',
|
||||
)
|
||||
expect(result.content.noteType).toBeFalsy()
|
||||
expect(result.content.editorIdentifier).toBeFalsy()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,92 @@
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { Importer } from '../Importer'
|
||||
|
||||
type AegisData = {
|
||||
db: {
|
||||
entries: {
|
||||
issuer: string
|
||||
name: string
|
||||
info: {
|
||||
secret: string
|
||||
}
|
||||
note: string
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
type AuthenticatorEntry = {
|
||||
service: string
|
||||
account: string
|
||||
secret: string
|
||||
notes: string
|
||||
}
|
||||
|
||||
export class AegisToAuthenticatorConverter extends Importer {
|
||||
constructor(protected override application: WebApplicationInterface) {
|
||||
super(application)
|
||||
}
|
||||
|
||||
createNoteFromEntries(
|
||||
entries: AuthenticatorEntry[],
|
||||
file: {
|
||||
lastModified: number
|
||||
name: string
|
||||
},
|
||||
addEditorInfo: boolean,
|
||||
): DecryptedTransferPayload<NoteContent> {
|
||||
return {
|
||||
created_at: new Date(file.lastModified),
|
||||
created_at_timestamp: file.lastModified,
|
||||
updated_at: new Date(file.lastModified),
|
||||
updated_at_timestamp: file.lastModified,
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Note,
|
||||
content: {
|
||||
title: file.name.split('.')[0],
|
||||
text: JSON.stringify(entries),
|
||||
references: [],
|
||||
...(addEditorInfo && {
|
||||
noteType: NoteType.Authentication,
|
||||
editorIdentifier: FeatureIdentifier.TokenVaultEditor,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async convertAegisBackupFileToNote(
|
||||
file: File,
|
||||
addEditorInfo: boolean,
|
||||
): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const entries = this.parseEntries(content)
|
||||
|
||||
if (!entries) {
|
||||
throw new Error('Could not parse entries')
|
||||
}
|
||||
|
||||
return this.createNoteFromEntries(entries, file, addEditorInfo)
|
||||
}
|
||||
|
||||
parseEntries(data: string): AuthenticatorEntry[] | null {
|
||||
try {
|
||||
const json = JSON.parse(data) as AegisData
|
||||
const entries = json.db.entries.map((entry) => {
|
||||
return {
|
||||
service: entry.issuer,
|
||||
account: entry.name,
|
||||
secret: entry.info.secret,
|
||||
notes: entry.note,
|
||||
} as AuthenticatorEntry
|
||||
})
|
||||
return entries
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
const data = {
|
||||
version: 1,
|
||||
header: {
|
||||
slots: null,
|
||||
params: null,
|
||||
},
|
||||
db: {
|
||||
version: 2,
|
||||
entries: [
|
||||
{
|
||||
type: 'totp',
|
||||
uuid: 'c74a11c4-4f23-417b-818a-e11f6a4d51d7',
|
||||
name: '[email protected]',
|
||||
issuer: 'TestMail',
|
||||
note: 'Some note',
|
||||
icon: null,
|
||||
info: {
|
||||
secret: 'TESTMAILTESTMAILTESTMAILTESTMAIL',
|
||||
algo: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'totp',
|
||||
uuid: '803ed58f-b2c4-386c-9aad-645a47309124',
|
||||
name: '[email protected]',
|
||||
issuer: 'Some Service',
|
||||
note: 'Some other service',
|
||||
icon: null,
|
||||
info: {
|
||||
secret: 'SOMESERVICESOMESERVICESOMESERVIC',
|
||||
algo: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export default JSON.stringify(data, null, 2)
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models'
|
||||
import { EvernoteConverter } from './EvernoteConverter'
|
||||
import data from './testData'
|
||||
|
||||
// Mock dayjs so dayjs.extend() doesn't throw an error in EvernoteConverter.ts
|
||||
jest.mock('dayjs', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
default: {
|
||||
extend: jest.fn(),
|
||||
utc: jest.fn().mockReturnValue({
|
||||
toDate: jest.fn().mockReturnValue(new Date()),
|
||||
}),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe('EvernoteConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue(Math.random()),
|
||||
} as any as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse and strip html', () => {
|
||||
const converter = new EvernoteConverter(application)
|
||||
|
||||
const result = converter.parseENEXData(data, true)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.length).toBe(3)
|
||||
expect(result?.[0].content_type).toBe(ContentType.Note)
|
||||
expect((result?.[0] as DecryptedTransferPayload<NoteContent>).content.text).toBe('This is a test.')
|
||||
expect(result?.[1].content_type).toBe(ContentType.Note)
|
||||
expect((result?.[1] as DecryptedTransferPayload<NoteContent>).content.text).toBe(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
)
|
||||
expect(result?.[2].content_type).toBe(ContentType.Tag)
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.title).toBe('evernote')
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.references.length).toBe(2)
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.references[0].uuid).toBe(result?.[0].uuid)
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.references[1].uuid).toBe(result?.[1].uuid)
|
||||
})
|
||||
|
||||
it('should parse and not strip html', () => {
|
||||
const converter = new EvernoteConverter(application)
|
||||
|
||||
const result = converter.parseENEXData(data, false)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.length).toBe(3)
|
||||
expect(result?.[0].content_type).toBe(ContentType.Note)
|
||||
expect((result?.[0] as DecryptedTransferPayload<NoteContent>).content.text).toBe('<div>This is a test.</div>')
|
||||
expect(result?.[1].content_type).toBe(ContentType.Note)
|
||||
expect((result?.[1] as DecryptedTransferPayload<NoteContent>).content.text).toBe(
|
||||
'<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||
)
|
||||
expect(result?.[2].content_type).toBe(ContentType.Tag)
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.title).toBe('evernote')
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.references.length).toBe(2)
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.references[0].uuid).toBe(result?.[0].uuid)
|
||||
expect((result?.[2] as DecryptedTransferPayload<TagContent>).content.references[1].uuid).toBe(result?.[1].uuid)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,164 @@
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { Importer } from '../Importer'
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
dayjs.extend(customParseFormat)
|
||||
dayjs.extend(utc)
|
||||
|
||||
const dateFormat = 'YYYYMMDDTHHmmss'
|
||||
|
||||
export class EvernoteConverter extends Importer {
|
||||
constructor(protected override application: WebApplicationInterface) {
|
||||
super(application)
|
||||
}
|
||||
|
||||
async convertENEXFileToNotesAndTags(file: File, stripHTML: boolean): Promise<DecryptedTransferPayload[]> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const notesAndTags = this.parseENEXData(content, stripHTML)
|
||||
|
||||
return notesAndTags
|
||||
}
|
||||
|
||||
parseENEXData(data: string, stripHTML = false, defaultTagName = 'evernote') {
|
||||
const xmlDoc = this.loadXMLString(data, 'xml')
|
||||
const xmlNotes = xmlDoc.getElementsByTagName('note')
|
||||
const notes: DecryptedTransferPayload<NoteContent>[] = []
|
||||
const tags: DecryptedTransferPayload<TagContent>[] = []
|
||||
let defaultTag: DecryptedTransferPayload<TagContent> | undefined
|
||||
|
||||
if (defaultTagName) {
|
||||
const now = new Date()
|
||||
defaultTag = {
|
||||
created_at: now,
|
||||
created_at_timestamp: now.getTime(),
|
||||
updated_at: now,
|
||||
updated_at_timestamp: now.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Tag,
|
||||
content: {
|
||||
title: defaultTagName,
|
||||
expanded: false,
|
||||
iconString: '',
|
||||
references: [],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function findTag(title: string | null) {
|
||||
return tags.filter(function (tag) {
|
||||
return tag.content.title == title
|
||||
})[0]
|
||||
}
|
||||
|
||||
function addTag(tag: DecryptedTransferPayload<TagContent>) {
|
||||
tags.push(tag)
|
||||
}
|
||||
|
||||
for (const [index, xmlNote] of Array.from(xmlNotes).entries()) {
|
||||
const title = xmlNote.getElementsByTagName('title')[0].textContent
|
||||
const created = xmlNote.getElementsByTagName('created')[0].textContent
|
||||
const updatedNodes = xmlNote.getElementsByTagName('updated')
|
||||
const updated = updatedNodes.length ? updatedNodes[0].textContent : null
|
||||
const contentNode = xmlNote.getElementsByTagName('content')[0]
|
||||
let contentXmlString
|
||||
/** Find the node with the content */
|
||||
for (const node of Array.from(contentNode.childNodes)) {
|
||||
if (node instanceof CDATASection) {
|
||||
contentXmlString = node.nodeValue
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!contentXmlString) {
|
||||
continue
|
||||
}
|
||||
const contentXml = this.loadXMLString(contentXmlString, 'html')
|
||||
let contentHTML = contentXml.getElementsByTagName('en-note')[0].innerHTML
|
||||
if (stripHTML) {
|
||||
contentHTML = contentHTML.replace(/<\/div>/g, '</div>\n')
|
||||
contentHTML = contentHTML.replace(/<li[^>]*>/g, '\n')
|
||||
contentHTML = contentHTML.trim()
|
||||
}
|
||||
const text = stripHTML ? this.stripHTML(contentHTML) : contentHTML
|
||||
const createdAtDate = created ? dayjs.utc(created, dateFormat).toDate() : new Date()
|
||||
const updatedAtDate = updated ? dayjs.utc(updated, dateFormat).toDate() : createdAtDate
|
||||
const note: DecryptedTransferPayload<NoteContent> = {
|
||||
created_at: createdAtDate,
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Note,
|
||||
content: {
|
||||
title: !title ? `Imported note ${index + 1} from Evernote` : title,
|
||||
text,
|
||||
references: [],
|
||||
},
|
||||
}
|
||||
|
||||
if (defaultTag) {
|
||||
defaultTag.content.references.push({
|
||||
content_type: ContentType.Note,
|
||||
uuid: note.uuid,
|
||||
})
|
||||
}
|
||||
|
||||
const xmlTags = xmlNote.getElementsByTagName('tag')
|
||||
for (const tagXml of Array.from(xmlTags)) {
|
||||
const tagName = tagXml.childNodes[0].nodeValue
|
||||
let tag = findTag(tagName)
|
||||
if (!tag) {
|
||||
const now = new Date()
|
||||
tag = {
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Tag,
|
||||
created_at: now,
|
||||
created_at_timestamp: now.getTime(),
|
||||
updated_at: now,
|
||||
updated_at_timestamp: now.getTime(),
|
||||
content: {
|
||||
title: tagName || `Imported tag ${index + 1} from Evernote`,
|
||||
expanded: false,
|
||||
iconString: '',
|
||||
references: [],
|
||||
},
|
||||
}
|
||||
addTag(tag)
|
||||
}
|
||||
|
||||
note.content.references.push({ content_type: tag.content_type, uuid: tag.uuid })
|
||||
tag.content.references.push({ content_type: note.content_type, uuid: note.uuid })
|
||||
}
|
||||
|
||||
notes.push(note)
|
||||
}
|
||||
|
||||
const allItems: DecryptedTransferPayload[] = [...notes, ...tags]
|
||||
if (defaultTag) {
|
||||
allItems.push(defaultTag)
|
||||
}
|
||||
|
||||
return allItems
|
||||
}
|
||||
|
||||
loadXMLString(string: string, type: 'html' | 'xml') {
|
||||
let xmlDoc
|
||||
if (window.DOMParser) {
|
||||
const parser = new DOMParser()
|
||||
xmlDoc = parser.parseFromString(string, `text/${type}`)
|
||||
} else {
|
||||
throw new Error('Could not parse XML string')
|
||||
}
|
||||
return xmlDoc
|
||||
}
|
||||
|
||||
stripHTML(html: string) {
|
||||
const tmp = document.createElement('html')
|
||||
tmp.innerHTML = html
|
||||
return tmp.textContent || tmp.innerText || ''
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export default `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export3.dtd">
|
||||
<en-export export-date="20210408T052957Z" application="Evernote" version="10.8.5">
|
||||
<note>
|
||||
<title>Testing 1</title>
|
||||
<created>20210308T051614Z</created>
|
||||
<updated>20210308T051855Z</updated>
|
||||
<note-attributes>
|
||||
</note-attributes>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>This is a test.</div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
<note>
|
||||
<title></title>
|
||||
<created>20200508T234829Z</created>
|
||||
<updated>20200508T235233Z</updated>
|
||||
<note-attributes>
|
||||
</note-attributes>
|
||||
<content>
|
||||
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div></en-note> ]]>
|
||||
</content>
|
||||
</note>
|
||||
</en-export>`
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { WebApplicationInterface } from '@standardnotes/snjs/dist/@types'
|
||||
import { jsonTestData, htmlTestData } from './testData'
|
||||
import { GoogleKeepConverter } from './GoogleKeepConverter'
|
||||
|
||||
describe('GoogleKeepConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('uuid'),
|
||||
} as unknown as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse json data', () => {
|
||||
const converter = new GoogleKeepConverter(application)
|
||||
|
||||
const result = converter.tryParseAsJson(jsonTestData)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.created_at).toBeInstanceOf(Date)
|
||||
expect(result?.updated_at).toBeInstanceOf(Date)
|
||||
expect(result?.uuid).not.toBeNull()
|
||||
expect(result?.content_type).toBe('Note')
|
||||
expect(result?.content.title).toBe('Testing 1')
|
||||
expect(result?.content.text).toBe('This is a test.')
|
||||
expect(result?.content.trashed).toBe(false)
|
||||
expect(result?.content.archived).toBe(false)
|
||||
expect(result?.content.pinned).toBe(false)
|
||||
})
|
||||
|
||||
it('should parse html data', () => {
|
||||
const converter = new GoogleKeepConverter(application)
|
||||
|
||||
const result = converter.tryParseAsHtml(
|
||||
htmlTestData,
|
||||
{
|
||||
name: 'note-2.html',
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.created_at).toBeInstanceOf(Date)
|
||||
expect(result?.updated_at).toBeInstanceOf(Date)
|
||||
expect(result?.uuid).not.toBeNull()
|
||||
expect(result?.content_type).toBe('Note')
|
||||
expect(result?.content.title).toBe('Testing 2')
|
||||
expect(result?.content.text).toBe('Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,126 @@
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { Importer } from '../Importer'
|
||||
|
||||
type GoogleKeepJsonNote = {
|
||||
color: string
|
||||
isTrashed: boolean
|
||||
isPinned: boolean
|
||||
isArchived: boolean
|
||||
textContent: string
|
||||
title: string
|
||||
userEditedTimestampUsec: number
|
||||
}
|
||||
|
||||
export class GoogleKeepConverter extends Importer {
|
||||
constructor(protected override application: WebApplicationInterface) {
|
||||
super(application)
|
||||
}
|
||||
|
||||
async convertGoogleKeepBackupFileToNote(
|
||||
file: File,
|
||||
stripHtml: boolean,
|
||||
): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const possiblePayloadFromJson = this.tryParseAsJson(content)
|
||||
|
||||
if (possiblePayloadFromJson) {
|
||||
return possiblePayloadFromJson
|
||||
}
|
||||
|
||||
const possiblePayloadFromHtml = this.tryParseAsHtml(content, file, stripHtml)
|
||||
|
||||
if (possiblePayloadFromHtml) {
|
||||
return possiblePayloadFromHtml
|
||||
}
|
||||
|
||||
throw new Error('Could not parse Google Keep backup file')
|
||||
}
|
||||
|
||||
tryParseAsHtml(data: string, file: { name: string }, stripHtml: boolean): DecryptedTransferPayload<NoteContent> {
|
||||
const rootElement = document.createElement('html')
|
||||
rootElement.innerHTML = data
|
||||
|
||||
const contentElement = rootElement.getElementsByClassName('content')[0]
|
||||
let content: string | null
|
||||
|
||||
// Replace <br> with \n so line breaks get recognised
|
||||
contentElement.innerHTML = contentElement.innerHTML.replace(/<br>/g, '\n')
|
||||
|
||||
if (stripHtml) {
|
||||
content = contentElement.textContent
|
||||
} else {
|
||||
content = contentElement.innerHTML
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
throw new Error('Could not parse content')
|
||||
}
|
||||
|
||||
const title = rootElement.getElementsByClassName('title')[0]?.textContent || file.name
|
||||
|
||||
const date = this.getDateFromGKeepNote(data) || new Date()
|
||||
|
||||
return {
|
||||
created_at: date,
|
||||
created_at_timestamp: date.getTime(),
|
||||
updated_at: date,
|
||||
updated_at_timestamp: date.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Note,
|
||||
content: {
|
||||
title: title,
|
||||
text: content,
|
||||
references: [],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
getDateFromGKeepNote(note: string) {
|
||||
const regexWithTitle = /.*(?=<\/div>\n<div class="title">)/
|
||||
const regexWithoutTitle = /.*(?=<\/div>\n\n<div class="content">)/
|
||||
const possibleDateStringWithTitle = regexWithTitle.exec(note)?.[0]
|
||||
const possibleDateStringWithoutTitle = regexWithoutTitle.exec(note)?.[0]
|
||||
if (possibleDateStringWithTitle) {
|
||||
const date = new Date(possibleDateStringWithTitle)
|
||||
if (date.toString() !== 'Invalid Date' && date.toString() !== 'NaN') {
|
||||
return date
|
||||
}
|
||||
}
|
||||
if (possibleDateStringWithoutTitle) {
|
||||
const date = new Date(possibleDateStringWithoutTitle)
|
||||
if (date.toString() !== 'Invalid Date' && date.toString() !== 'NaN') {
|
||||
return date
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
tryParseAsJson(data: string): DecryptedTransferPayload<NoteContent> | null {
|
||||
try {
|
||||
const parsed = JSON.parse(data) as GoogleKeepJsonNote
|
||||
const date = new Date(parsed.userEditedTimestampUsec / 1000)
|
||||
return {
|
||||
created_at: date,
|
||||
created_at_timestamp: date.getTime(),
|
||||
updated_at: date,
|
||||
updated_at_timestamp: date.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Note,
|
||||
content: {
|
||||
title: parsed.title,
|
||||
text: parsed.textContent,
|
||||
references: [],
|
||||
archived: Boolean(parsed.isArchived),
|
||||
trashed: Boolean(parsed.isTrashed),
|
||||
pinned: Boolean(parsed.isPinned),
|
||||
},
|
||||
}
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
const json = {
|
||||
color: 'DEFAULT',
|
||||
isTrashed: false,
|
||||
isPinned: false,
|
||||
isArchived: false,
|
||||
textContent: 'This is a test.',
|
||||
title: 'Testing 1',
|
||||
userEditedTimestampUsec: 1618528050144000,
|
||||
}
|
||||
|
||||
export const jsonTestData = JSON.stringify(json)
|
||||
|
||||
export const htmlTestData = `<?xml version="1.0" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Testing 2</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: 'Roboto Condensed','Droid Sans',arial,sans-serif;
|
||||
font-size: 15px;
|
||||
color: rgba(0,0,0,0.8);
|
||||
word-wrap: break-word;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
border-style: inset dashed;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.note {
|
||||
outline: none;
|
||||
box-shadow: 0 2px 1px rgba(0,0,0,0.08);
|
||||
box-sizing: border-box;
|
||||
|
||||
max-width: 600px;
|
||||
min-width: 240px;
|
||||
margin: 20px;
|
||||
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.note .heading {
|
||||
font-size: 12px;
|
||||
padding: 15px 15px 0 15px;
|
||||
color: rgba(100,100,100,0.8);
|
||||
}
|
||||
|
||||
.note .title {
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
padding: 15px 15px 0 15px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.note .content {
|
||||
padding: 12px 15px 15px 15px;
|
||||
font-family: 'Roboto Slab','Times New Roman',serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.note .attachments {
|
||||
padding: 0 15px 15px 15px;
|
||||
}
|
||||
|
||||
.attachments ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attachments li {
|
||||
list-style-type: none;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.attachments li img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.attachments .audio {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOC4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4KPCFET0NUWVBFIHN2ZyAgUFVCTElDICctLy9XM0MvL0RURCBTVkcgMS4xLy9FTicgICdodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQnPgo8c3ZnIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCAyMCAyMCIgdmVyc2lvbj0iMS4xIiB5PSIwcHgiIHg9IjBweCIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDIwIDIwIj4KPHBhdGggZD0ibTEgN3Y2aDRsNSA1di0xNmwtNSA1aC00em0xMy41IDNjMC0xLjgtMS0zLjMtMi41LTR2OGMxLjUtMC43IDIuNS0yLjIgMi41LTR6bS0yLjUtOC44djIuMWMyLjkgMC45IDUgMy41IDUgNi43cy0yLjEgNS44LTUgNi43djIuMWM0LTAuOSA3LTQuNSA3LTguOHMtMy03LjktNy04Ljh6Ii8+Cjwvc3ZnPgo=);
|
||||
background-size: 18px 18px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.note .list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.note .listitem {
|
||||
}
|
||||
|
||||
.note .listitem .bullet {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.note .listitem .text {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.note .identifier {
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.note .identifier:before {
|
||||
content: "(";
|
||||
}
|
||||
.note .identifier:after {
|
||||
content: ")";
|
||||
}
|
||||
|
||||
/* Only show identifiers when the element is hovered. */
|
||||
.note .listitem .identifier,
|
||||
.note .chip .identifier {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.note .listitem:hover .identifier,
|
||||
.note .chip:hover .identifier {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.note .chips {
|
||||
padding: 12px 15px 15px 15px;
|
||||
}
|
||||
|
||||
.note .chip {
|
||||
display: inline-block;
|
||||
max-width: 198px;
|
||||
margin: 2px 4px 2px 0;
|
||||
padding: 2px 5px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 2px;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
font-size: 11px;
|
||||
font-family: 'Roboto','Droid Sans',arial,sans-serif;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.note .chip a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.chip-icon {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-size: 100%;
|
||||
margin-right: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.annotation.CALENDAR .chip-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMTcgMTJoLTV2NWg1di01ek0xNiAxdjJIOFYxSDZ2Mkg1Yy0xLjExIDAtMS45OS45LTEuOTkgMkwzIDE5YzAgMS4xLjg5IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJoLTFWMWgtMnptMyAxOEg1VjhoMTR2MTF6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPgo=);
|
||||
}
|
||||
|
||||
.annotation.DOCS .chip-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMTkgM0g1Yy0xLjEgMC0yIC45LTIgMnYxNGMwIDEuMS45IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bS0xLjk5IDZIN1Y3aDEwLjAxdjJ6bTAgNEg3di0yaDEwLjAxdjJ6bS0zIDRIN3YtMmg3LjAxdjJ6Ii8+Cjwvc3ZnPgo=);
|
||||
}
|
||||
|
||||
.annotation.GMAIL .chip-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBmaWxsPSJub25lIiBkPSJNLTYxOC0yMTA0SDc4MnYzNjAwSC02MTh6TTAgMGgyNHYyNEgweiIvPgogICAgPHBhdGggZD0iTTIwIDRINGMtMS4xIDAtMiAuOS0yIDJ2MTJjMCAxLjEuOSAyIDIgMmgxNmMxLjEgMCAyLS45IDItMlY2YzAtMS4xLS45LTItMi0yem0wIDE0aC0yVjkuMkwxMiAxMyA2IDkuMlYxOEg0VjZoMS4ybDYuOCA0LjJMMTguOCA2SDIwdjEyeiIvPgo8L3N2Zz4K);
|
||||
}
|
||||
|
||||
.annotation.SHEETS .chip-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMTkgM0g1Yy0xLjEgMC0xLjk5LjktMS45OSAyTDMgOHYxMWMwIDEuMS45IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bTAgOGgtOHY4SDl2LThINVY5aDRWNWgydjRoOHYyeiIvPgo8L3N2Zz4K);
|
||||
}
|
||||
|
||||
.annotation.SLIDES .chip-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMTkgM0g1Yy0xLjEgMC0xLjk5LjktMS45OSAydjE0YzAgMS4xLjg5IDIgMS45OSAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bTAgMTNINVY4aDE0djh6Ii8+Cjwvc3ZnPgo=);
|
||||
}
|
||||
|
||||
.annotation.WEBLINK .chip-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMTkgNEg1Yy0xLjExIDAtMiAuOS0yIDJ2MTJjMCAxLjEuODkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJWNmMwLTEuMS0uODktMi0yLTJ6bTAgMTRINVY4aDE0djEweiIvPgogICAgPHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgweiIvPgo8L3N2Zz4K);
|
||||
}
|
||||
|
||||
.sharees h2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sharees ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 15px 15px 15px;
|
||||
}
|
||||
|
||||
.sharees li {
|
||||
display: inline-block;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
text-indent: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAzYzEuNjYgMCAzIDEuMzQgMyAzcy0xLjM0IDMtMyAzLTMtMS4zNC0zLTMgMS4zNC0zIDMtM3ptMCAxNC4yYy0yLjUgMC00LjcxLTEuMjgtNi0zLjIyLjAzLTEuOTkgNC0zLjA4IDYtMy4wOCAxLjk5IDAgNS45NyAxLjA5IDYgMy4wOC0xLjI5IDEuOTQtMy41IDMuMjItNiAzLjIyeiIvPgogICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPgo8L3N2Zz4K);
|
||||
background-size: 18px 18px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.sharees li.group {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwMCI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMTYgMTFjMS42NiAwIDIuOTktMS4zNCAyLjk5LTNTMTcuNjYgNSAxNiA1Yy0xLjY2IDAtMyAxLjM0LTMgM3MxLjM0IDMgMyAzem0tOCAwYzEuNjYgMCAyLjk5LTEuMzQgMi45OS0zUzkuNjYgNSA4IDVDNi4zNCA1IDUgNi4zNCA1IDhzMS4zNCAzIDMgM3ptMCAyYy0yLjMzIDAtNyAxLjE3LTcgMy41VjE5aDE0di0yLjVjMC0yLjMzLTQuNjctMy41LTctMy41em04IDBjLS4yOSAwLS42Mi4wMi0uOTcuMDUgMS4xNi44NCAxLjk3IDEuOTcgMS45NyAzLjQ1VjE5aDZ2LTIuNWMwLTIuMzMtNC42Ny0zLjUtNy0zLjV6Ii8+Cjwvc3ZnPgo=);
|
||||
}
|
||||
|
||||
.note .meta-icons {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.note .meta-icons span {
|
||||
display: inline-block;
|
||||
background-size: 18px 18px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.meta-icons .pinned {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMHB4IiBoZWlnaHQ9IjIwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzQyODVmNCI+DQogICAgPHBhdGggZD0iTTE2IDVoLjk5TDE3IDNIN3YyaDF2N2wtMiAydjJoNXY2bDEgMSAxLTF2LTZoNXYtMmwtMi0yVjV6Ii8+DQogICAgPHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgweiIvPg0KPC9zdmc+);
|
||||
}
|
||||
|
||||
.meta-icons .archived {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOC4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4KPCFET0NUWVBFIHN2ZyAgUFVCTElDICctLy9XM0MvL0RURCBTVkcgMS4xLy9FTicgICdodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQnPgo8c3ZnIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCAxOCAxOCIgdmVyc2lvbj0iMS4xIiB5PSIwcHgiIHg9IjBweCIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDE4IDE4Ij4KPHBhdGggZD0ibTE2LjYgM2wtMS4yLTEuNWMtMC4yLTAuMy0wLjYtMC41LTEtMC41aC0xMC43Yy0wLjQgMC0wLjggMC4yLTEgMC41bC0xLjMgMS41Yy0wLjIgMC4zLTAuNCAwLjctMC40IDEuMXYxMS4xYzAgMSAwLjggMS44IDEuOCAxLjhoMTIuNGMxIDAgMS44LTAuOCAxLjgtMS44di0xMS4xYzAtMC40LTAuMi0wLjgtMC40LTEuMXptLTcuNiAxMC45bC00LjktNC45aDMuMXYtMS44aDMuNnYxLjhoMy4xbC00LjkgNC45em0tNi4xLTExLjFsMC43LTAuOWgxMC43bDAuOCAwLjloLTEyLjJ6Ii8+Cjwvc3ZnPgo=);
|
||||
}
|
||||
|
||||
.meta-icons .trashed {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE4cHgiIHdpZHRoPSIxOHB4IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0iIzAwMDAwMCI+DQogPHBhdGggZD0ibTEyIDM4YzAgMi4yMSAxLjc5IDQgNCA0aDE2YzIuMjEgMCA0LTEuNzkgNC00di0yNGgtMjR2MjR6bTI2LTMwaC03bC0yLTJoLTEwbC0yIDJoLTd2NGgyOHYtNHoiLz4NCiA8cGF0aCBkPSJtMCAwaDQ4djQ4aC00OHoiIGZpbGw9Im5vbmUiLz4NCjwvc3ZnPg==);
|
||||
}
|
||||
|
||||
.checked {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.RED {
|
||||
background-color: rgb(255, 109, 63) !important;
|
||||
}
|
||||
.ORANGE {
|
||||
background-color: rgb(255, 155, 0) !important;
|
||||
}
|
||||
.YELLOW {
|
||||
background-color: rgb(255, 218, 0) !important;
|
||||
}
|
||||
.GREEN {
|
||||
background-color: rgb(149, 214, 65) !important;
|
||||
}
|
||||
.TEAL {
|
||||
background-color: rgb(28, 232, 181) !important;
|
||||
}
|
||||
.BLUE {
|
||||
background-color: rgb(63, 195, 255) !important;
|
||||
}
|
||||
.GRAY {
|
||||
background-color: rgb(184, 196, 201) !important;
|
||||
}
|
||||
|
||||
/* go/keep-more-colors-eng */
|
||||
.CERULEAN {
|
||||
background-color: rgb(130, 177, 255) !important;
|
||||
}
|
||||
.PURPLE {
|
||||
background-color: rgb(179, 136, 255) !important;
|
||||
}
|
||||
.PINK {
|
||||
background-color: rgb(248, 187, 208) !important;
|
||||
}
|
||||
.BROWN {
|
||||
background-color: rgb(215, 204, 200) !important;
|
||||
}
|
||||
|
||||
</style></head>
|
||||
<body><div class="note"><div class="heading"><div class="meta-icons">
|
||||
|
||||
</div>
|
||||
Apr 15, 2021, 7:07:43 PM</div>
|
||||
<div class="title">Testing 2</div>
|
||||
<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
|
||||
|
||||
|
||||
</div></body></html>`
|
||||
@@ -0,0 +1,14 @@
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { DecryptedTransferPayload } from '@standardnotes/snjs'
|
||||
|
||||
export class Importer {
|
||||
constructor(protected application: WebApplicationInterface) {}
|
||||
|
||||
async importFromTransferPayloads(payloads: DecryptedTransferPayload[]): Promise<void> {
|
||||
for (const payload of payloads) {
|
||||
const itemPayload = this.application.items.createPayloadFromObject(payload)
|
||||
const item = this.application.items.createItemFromPayload(itemPayload)
|
||||
await this.application.mutator.insertItem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { SimplenoteConverter } from './SimplenoteConverter'
|
||||
import data from './testData'
|
||||
|
||||
describe('SimplenoteConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('uuid'),
|
||||
} as any
|
||||
})
|
||||
|
||||
it('should parse', () => {
|
||||
const converter = new SimplenoteConverter(application)
|
||||
|
||||
const result = converter.parse(data)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.length).toBe(3)
|
||||
|
||||
expect(result?.[0].created_at).toBeInstanceOf(Date)
|
||||
expect(result?.[0].updated_at).toBeInstanceOf(Date)
|
||||
expect(result?.[0].uuid).not.toBeNull()
|
||||
expect(result?.[0].content_type).toBe('Note')
|
||||
expect(result?.[0].content.title).toBe('Testing 1')
|
||||
expect(result?.[0].content.text).toBe("This is the 1st note's content.")
|
||||
expect(result?.[0].content.trashed).toBe(false)
|
||||
|
||||
expect(result?.[1].created_at).toBeInstanceOf(Date)
|
||||
expect(result?.[1].updated_at).toBeInstanceOf(Date)
|
||||
expect(result?.[1].uuid).not.toBeNull()
|
||||
expect(result?.[1].content_type).toBe('Note')
|
||||
expect(result?.[1].content.title).toBe('Testing 2')
|
||||
expect(result?.[1].content.text).toBe("This is the 2nd note's content.")
|
||||
expect(result?.[1].content.trashed).toBe(false)
|
||||
|
||||
expect(result?.[2].created_at).toBeInstanceOf(Date)
|
||||
expect(result?.[2].updated_at).toBeInstanceOf(Date)
|
||||
expect(result?.[2].uuid).not.toBeNull()
|
||||
expect(result?.[2].content_type).toBe('Note')
|
||||
expect(result?.[2].content.title).not.toBeFalsy()
|
||||
expect(result?.[2].content.text).toBe('Welcome to Simplenote!')
|
||||
expect(result?.[2].content.trashed).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,78 @@
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { Importer } from '../Importer'
|
||||
|
||||
type SimplenoteItem = {
|
||||
creationDate: string
|
||||
lastModified: string
|
||||
content: string
|
||||
}
|
||||
|
||||
type SimplenoteData = {
|
||||
activeNotes: SimplenoteItem[]
|
||||
trashedNotes: SimplenoteItem[]
|
||||
}
|
||||
|
||||
export class SimplenoteConverter extends Importer {
|
||||
constructor(protected override application: WebApplicationInterface) {
|
||||
super(application)
|
||||
}
|
||||
|
||||
createNoteFromItem(item: SimplenoteItem, trashed: boolean): DecryptedTransferPayload<NoteContent> {
|
||||
const createdAtDate = new Date(item.creationDate)
|
||||
const updatedAtDate = new Date(item.lastModified)
|
||||
|
||||
const splitItemContent = item.content.split('\r\n')
|
||||
const hasTitleAndContent = splitItemContent.length === 2
|
||||
const title =
|
||||
hasTitleAndContent && splitItemContent[0].length ? splitItemContent[0] : createdAtDate.toLocaleString()
|
||||
const content = hasTitleAndContent && splitItemContent[1].length ? splitItemContent[1] : item.content
|
||||
|
||||
return {
|
||||
created_at: createdAtDate,
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Note,
|
||||
content: {
|
||||
title,
|
||||
text: content,
|
||||
references: [],
|
||||
trashed,
|
||||
appData: {
|
||||
'org.standardnotes.sn': {
|
||||
client_updated_at: updatedAtDate,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async convertSimplenoteBackupFileToNotes(file: File): Promise<DecryptedTransferPayload<NoteContent>[]> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const notes = this.parse(content)
|
||||
|
||||
if (!notes) {
|
||||
throw new Error('Could not parse notes')
|
||||
}
|
||||
|
||||
return notes
|
||||
}
|
||||
|
||||
parse(data: string) {
|
||||
try {
|
||||
const parsed = JSON.parse(data) as SimplenoteData
|
||||
const activeNotes = parsed.activeNotes.reverse().map((item) => this.createNoteFromItem(item, false))
|
||||
const trashedNotes = parsed.trashedNotes.reverse().map((item) => this.createNoteFromItem(item, true))
|
||||
|
||||
return [...activeNotes, ...trashedNotes]
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
const data = {
|
||||
activeNotes: [
|
||||
{
|
||||
id: '43349052-4efa-48c2-bdd6-8323124451b1',
|
||||
content: "Testing 2\r\nThis is the 2nd note's content.",
|
||||
creationDate: '2020-06-08T21:28:43.856Z',
|
||||
lastModified: '2021-04-16T06:21:53.124Z',
|
||||
},
|
||||
{
|
||||
id: '2a338440-4a24-4180-9805-1110d325642c',
|
||||
content: "Testing 1\r\nThis is the 1st note's content.",
|
||||
creationDate: '2020-06-08T21:28:38.241Z',
|
||||
lastModified: '2021-04-16T06:21:58.294Z',
|
||||
},
|
||||
],
|
||||
trashedNotes: [
|
||||
{
|
||||
id: 'agtzaW1wbGUtbm90ZXIRCxIETm90ZRiAgLCvy-3gCAw',
|
||||
content: 'Welcome to Simplenote!',
|
||||
creationDate: '2020-06-08T21:28:28.434Z',
|
||||
lastModified: '2021-04-16T06:20:14.143Z',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default JSON.stringify(data, null, 2)
|
||||
@@ -0,0 +1,13 @@
|
||||
export const readFileAsText = (file: File): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
if (e.target?.result) {
|
||||
resolve(e.target.result as string)
|
||||
} else {
|
||||
reject()
|
||||
}
|
||||
}
|
||||
reader.readAsText(file)
|
||||
})
|
||||
}
|
||||
@@ -10,6 +10,7 @@ const PREFERENCE_IDS = [
|
||||
'get-free-month',
|
||||
'help-feedback',
|
||||
'whats-new',
|
||||
'filesend',
|
||||
] as const
|
||||
|
||||
export type PreferenceId = typeof PREFERENCE_IDS[number]
|
||||
|
||||
@@ -32,3 +32,7 @@ export * from './Theme/ThemeManager'
|
||||
export * from './Toast/ToastService'
|
||||
export * from './Toast/ToastServiceInterface'
|
||||
export * from './StatePersistence/StatePersistence'
|
||||
export * from './Import/AegisConverter/AegisToAuthenticatorConverter'
|
||||
export * from './Import/SimplenoteConverter/SimplenoteConverter'
|
||||
export * from './Import/GoogleKeepConverter/GoogleKeepConverter'
|
||||
export * from './Import/EvernoteConverter/EvernoteConverter'
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
|
||||
@@ -3,6 +3,115 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.129.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
### Features
|
||||
|
||||
* Allow changing per-view display preferences for system views ([#2120](https://github.com/standardnotes/app/issues/2120)) ([dc33aef](https://github.com/standardnotes/app/commit/dc33aef6608a364107a884ad2f26c14bceea23b7))
|
||||
|
||||
## [3.128.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where right-clicking system view would open "Edit smart view" modal ([044a4fc](https://github.com/standardnotes/app/commit/044a4fc36b1af773ed490943e5a02a6e4c442252))
|
||||
|
||||
## [3.128.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where adding child tag to note would also add all parent tags even though the related setting was turned off ([e798b71](https://github.com/standardnotes/app/commit/e798b71b9fb2cb566be2043f9873bcbf3cea2d25))
|
||||
|
||||
## [3.128.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.128.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
# [3.128.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
### Features
|
||||
|
||||
* Added FileSend links to general account menu and preferences menu ([4f07b91](https://github.com/standardnotes/app/commit/4f07b915f0a60632a9e537b3b0394290d25fa071))
|
||||
|
||||
## [3.127.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.127.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where navigating to a Daily Notebook on iOS would cause editor panel to be offscreen ([fe36009](https://github.com/standardnotes/app/commit/fe36009482ff1615612ca965abb956318d8bc626))
|
||||
|
||||
## [3.127.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Made Moments-related toast messages dismissable ([c59d824](https://github.com/standardnotes/app/commit/c59d82424012f98638625e057f88124982ad0734))
|
||||
|
||||
## [3.127.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where Super note would convert whole line into tag even after closing menu ([35b0073](https://github.com/standardnotes/app/commit/35b00737bf13ceb8e66d64c67925f2fe9df2587c))
|
||||
|
||||
## [3.127.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Disabled Moments photo capture when app is passcode or biometrics locked ([#2114](https://github.com/standardnotes/app/issues/2114)) ([94c2802](https://github.com/standardnotes/app/commit/94c280256e0a71fb8078f0d0e4d7ad2b6d3c1462))
|
||||
|
||||
## [3.127.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.127.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where Moments-related toasts would not get correctly dismissed ([eceb46b](https://github.com/standardnotes/app/commit/eceb46bed7117c8bf5ea34d87a800f8bf02881ac))
|
||||
* Increased interval between Moments capturing photos ([e4b3028](https://github.com/standardnotes/app/commit/e4b3028d673a037f2740939b294cf6301db0d529))
|
||||
|
||||
## [3.127.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Added potential fix for issue where some video would show as not supported ([a7add80](https://github.com/standardnotes/app/commit/a7add80633ea603f7883db2dbc1f886d40450979))
|
||||
|
||||
## [3.127.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.127.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user