You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-30 20:39:46 +02:00
Compare commits
83 Commits
user_data
...
plugin-gen
Author | SHA1 | Date | |
---|---|---|---|
|
9f5924984c | ||
|
6db5723a50 | ||
|
1d0bcc435b | ||
|
700158d83c | ||
|
df4e8c9f47 | ||
|
ce6baccd82 | ||
|
0caf1fdd7b | ||
|
2a10cd3333 | ||
|
3ec257abc3 | ||
|
295756a528 | ||
|
5603900fc2 | ||
|
e1195f7370 | ||
|
5625b15cb5 | ||
|
af4147ed58 | ||
|
9e10261e0b | ||
|
487fecb16e | ||
|
e0ce301c3f | ||
|
bb474287e5 | ||
|
583ae0385b | ||
|
35a4eef87b | ||
|
e46ecdcb2b | ||
|
6036420bc6 | ||
|
cd73661200 | ||
|
5dbadbbff6 | ||
|
2dc02fe0f2 | ||
|
a474b403f9 | ||
|
e9a8475ecf | ||
|
0f9bdf1ca0 | ||
|
a7781f2a6b | ||
|
71144bb675 | ||
|
6886f6fd39 | ||
|
83610c01c0 | ||
|
5b18edc8be | ||
|
671fa542b4 | ||
|
4e4685b039 | ||
|
e4023a349f | ||
|
e7c37d17c1 | ||
|
d6c2b64a43 | ||
|
10e49d8cd3 | ||
|
95d83a8ced | ||
|
6b00c4e6ce | ||
|
dc2def403c | ||
|
89e2603f02 | ||
|
35e03e2ad9 | ||
|
12e853b871 | ||
|
5841596acb | ||
|
377e35b1af | ||
|
a3181d4458 | ||
|
e057c7beea | ||
|
60c25f88cf | ||
|
d532b9dffc | ||
|
5a2310ff4d | ||
|
472120d5ec | ||
|
9de83bf922 | ||
|
96bd76e45e | ||
|
5564e2178a | ||
|
9eb643f8f7 | ||
|
c2bdaddcec | ||
|
17888a2da0 | ||
|
eda18c3860 | ||
|
878bf13a0e | ||
|
a8c21b2477 | ||
|
b85bd8d296 | ||
|
eb6d5690aa | ||
|
ebe00ea58b | ||
|
e14a0b54f5 | ||
|
2f0f63e2b1 | ||
|
048100ebb3 | ||
|
7880d07868 | ||
|
9ba42b7919 | ||
|
fcc7ed3ed4 | ||
|
c000d4f4b3 | ||
|
6e0c484441 | ||
|
753a25a5e1 | ||
|
57b4198d2c | ||
|
2078fa4e40 | ||
|
69826610a2 | ||
|
0f9727144f | ||
|
11355bfdc5 | ||
|
4d08d7385f | ||
|
ce7da882ee | ||
|
92c68882e2 | ||
|
6424832984 |
@@ -225,6 +225,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.j
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
|
||||
@@ -356,6 +357,7 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
|
2
.github/workflows/cla.yml
vendored
2
.github/workflows/cla.yml
vendored
@@ -33,5 +33,5 @@ jobs:
|
||||
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
|
||||
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
|
||||
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
|
||||
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
|
||||
lock-pullrequest-aftermerge: false
|
||||
#use-dco-flag: true - If you are using DCO instead of CLA
|
||||
|
32
.github/workflows/github-actions-main.yml
vendored
32
.github/workflows/github-actions-main.yml
vendored
@@ -176,3 +176,35 @@ jobs:
|
||||
# Basic test to ensure that the created build is valid. It should exit with
|
||||
# code 0 if it works.
|
||||
docker run joplin/server:0.0.0-beta node dist/app.js migrate list
|
||||
|
||||
- name: Check HTTP request
|
||||
run: |
|
||||
# Need to pass environment variables:
|
||||
docker run -p 22300:22300 joplin/server:0.0.0-beta node dist/app.js --env dev &
|
||||
|
||||
# Wait for server to start
|
||||
sleep 10
|
||||
|
||||
# Check if status code is correct
|
||||
# if the actual_status DOES NOT include the expected_status
|
||||
# it exits the process with code 1
|
||||
|
||||
expected_status="HTTP/1.1 200 OK"
|
||||
actual_status=$(curl -I -X GET http://localhost:22300/api/ping | head -n 1)
|
||||
if [[ ! "$actual_status" =~ "$expected_status" ]]; then
|
||||
echo 'Failed while checking the status code after request to /api/ping'
|
||||
echo 'expected: ' $expected_status
|
||||
echo 'actual: ' $actual_status
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Check if the body response is correct
|
||||
# if the actual_body is different of expected_body exit with code 1
|
||||
expected_body='{"status":"ok","message":"Joplin Server is running"}'
|
||||
actual_body=$(curl http://localhost:22300/api/ping)
|
||||
|
||||
if [[ "$actual_body" != "$expected_body" ]]; then
|
||||
echo 'Failed while checking the body response after request to /api/ping'
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -210,6 +210,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.j
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
|
||||
@@ -341,6 +342,7 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
|
@@ -36,7 +36,7 @@ index 6afcbbf0cc8ca2d69dd78077d61e59a90b2136bb..9f8d72b4ec5b2b3d290975d6a255917c
|
||||
def kotlin_version = getExtOrDefault('kotlinVersion')
|
||||
|
||||
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d4870cb3f 100644
|
||||
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 100644
|
||||
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@@ -66,7 +66,25 @@ index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d
|
||||
sendEvent("onResult", text)
|
||||
}
|
||||
}
|
||||
@@ -153,6 +165,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@@ -93,12 +105,11 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@ReactMethod
|
||||
fun loadModel(path: String, promise: Promise) {
|
||||
cleanModel();
|
||||
- StorageService.unpack(context, path, "models",
|
||||
- { model: Model? ->
|
||||
- this.model = model
|
||||
- promise.resolve("Model successfully loaded")
|
||||
- }
|
||||
- ) { e: IOException ->
|
||||
+
|
||||
+ try {
|
||||
+ this.model = Model(path);
|
||||
+ promise.resolve("Model successfully loaded")
|
||||
+ } catch (e: IOException) {
|
||||
this.model = null
|
||||
promise.reject(e)
|
||||
}
|
||||
@@ -153,6 +164,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
cleanRecognizer();
|
||||
}
|
||||
|
||||
|
@@ -22,11 +22,11 @@ Three types of applications are available: for **desktop** (Windows, macOS and L
|
||||
|
||||
Operating System | Download
|
||||
---|---
|
||||
Windows (32 and 64-bit) | <a href='https://objects.joplinusercontent.com/v2.10.19/Joplin-Setup-2.10.19.exe?source=JoplinWebsite&type=New'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
|
||||
macOS | <a href='https://objects.joplinusercontent.com/v2.10.19/Joplin-2.10.19.dmg?source=JoplinWebsite&type=New'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
|
||||
Linux | <a href='https://objects.joplinusercontent.com/v2.10.19/Joplin-2.10.19.AppImage?source=JoplinWebsite&type=New'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
|
||||
Windows (32 and 64-bit) | <a href='https://objects.joplinusercontent.com/v2.11.11/Joplin-Setup-2.11.11.exe?source=JoplinWebsite&type=New'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
|
||||
macOS | <a href='https://objects.joplinusercontent.com/v2.11.11/Joplin-2.11.11.dmg?source=JoplinWebsite&type=New'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
|
||||
Linux | <a href='https://objects.joplinusercontent.com/v2.11.11/Joplin-2.11.11.AppImage?source=JoplinWebsite&type=New'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
|
||||
|
||||
**On Windows**, you may also use the <a href='https://objects.joplinusercontent.com/v2.10.19/JoplinPortable.exe?source=JoplinWebsite&type=New'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
**On Windows**, you may also use the <a href='https://objects.joplinusercontent.com/v2.11.11/JoplinPortable.exe?source=JoplinWebsite&type=New'>Portable version</a>. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.
|
||||
|
||||
**On Linux**, the recommended way is to use the following installation script as it will handle the desktop icon too:
|
||||
|
||||
|
@@ -353,5 +353,43 @@
|
||||
"web/bundles/": true,
|
||||
"web/env.php": true,
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "transpile-server",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceFolder}/packages/server && yarn tsc",
|
||||
"group": "build",
|
||||
}
|
||||
]
|
||||
},
|
||||
"launch": {
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Server",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "transpile-server",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js",
|
||||
"!**/node_modules/**"
|
||||
],
|
||||
"program": "${workspaceFolder}/packages/server/src/app.ts",
|
||||
"args": [
|
||||
"--env", "dev"
|
||||
],
|
||||
"env": {
|
||||
"JOPLIN_IS_TESTING": "1",
|
||||
"TERMS_URL": "https://example.com",
|
||||
"PRIVACY_URL": "https://example.com",
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -16,7 +16,7 @@
|
||||
"buildSequential": "yarn workspaces foreach --verbose --interlaced --topological run build && yarn run tsc",
|
||||
"buildApiDoc": "yarn workspace joplin start apidoc ../../readme/api/references/rest_api.md",
|
||||
"buildCommandIndex": "node packages/tools/gulp/tasks/buildCommandIndexRun.js",
|
||||
"buildPluginDoc": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme './Assets/PluginDocTheme/' --readme './Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../joplin-website/docs/api/references/plugin_api packages/lib/services/plugins/api/",
|
||||
"buildPluginDoc": "cd packages/generate-plugin-doc && yarn run buildPluginDoc_",
|
||||
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
|
||||
"updateNews": "node ./packages/tools/website/updateNews",
|
||||
"buildSettingJsonSchema": "yarn workspace joplin start settingschema ../../../joplin-website/docs/schema/settings.json",
|
||||
@@ -84,7 +84,6 @@
|
||||
"lint-staged": "13.2.2",
|
||||
"madge": "6.0.0",
|
||||
"npm-package-json-lint": "6.4.0",
|
||||
"typedoc": "0.17.8",
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@@ -35,15 +35,15 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"bin": "./main.js",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@joplin/utils": "~2.11",
|
||||
"@joplin/lib": "~2.12",
|
||||
"@joplin/renderer": "~2.12",
|
||||
"@joplin/utils": "~2.12",
|
||||
"aws-sdk": "2.1340.0",
|
||||
"chalk": "4.1.2",
|
||||
"compare-version": "0.1.2",
|
||||
@@ -70,7 +70,7 @@
|
||||
"yargs-parser": "21.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "~2.11",
|
||||
"@joplin/tools": "~2.12",
|
||||
"@types/fs-extra": "11.0.1",
|
||||
"@types/jest": "29.5.1",
|
||||
"@types/node": "18.15.13",
|
||||
|
1
packages/app-cli/tests/md_to_html/sanitize_18.html
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_18.html
Normal file
@@ -0,0 +1 @@
|
||||
<a data-from-md title='<style>' href='&#x22&#x2c&#x22&#x61&#x22&#x29&#x3b&#x74&#x6f&#x70&#x2e&#x72&#x65&#x71&#x75&#x69&#x72&#x65&#x28&#x27&#x63&#x68&#x69&#x6c&#x64&#x5f&#x70&#x72&#x6f&#x63&#x65&#x73&#x73&#x27&#x29&#x2e&#x65&#x78&#x65&#x63&#x28&#x27&#x6f&#x70&#x65&#x6e&#x20&#x2f&#x53&#x79&#x73&#x74&#x65&#x6d&#x2f&#x41&#x70&#x70&#x6c&#x69&#x63&#x61&#x74&#x69&#x6f&#x6e&#x73&#x2f&#x43&#x61&#x6c&#x63&#x75&#x6c&#x61&#x74&#x6f&#x72&#x2e&#x61&#x70&#x70&#x27&#x29&#x3b&#x2f&#x2f' onclick='postMessage("&#x22&#x2c&#x22&#x61&#x22&#x29&#x3b&#x74&#x6f&#x70&#x2e&#x72&#x65&#x71&#x75&#x69&#x72&#x65&#x28&#x27&#x63&#x68&#x69&#x6c&#x64&#x5f&#x70&#x72&#x6f&#x63&#x65&#x73&#x73&#x27&#x29&#x2e&#x65&#x78&#x65&#x63&#x28&#x27&#x6f&#x70&#x65&#x6e&#x20&#x2f&#x53&#x79&#x73&#x74&#x65&#x6d&#x2f&#x41&#x70&#x70&#x6c&#x69&#x63&#x61&#x74&#x69&#x6f&#x6e&#x73&#x2f&#x43&#x61&#x6c&#x63&#x75&#x6c&#x61&#x74&#x6f&#x72&#x2e&#x61&#x70&#x70&#x27&#x29&#x3b&#x2f&#x2f", { resourceId: "" }); return false;'>xxxxx</a>
|
1
packages/app-cli/tests/md_to_html/sanitize_18.md
Normal file
1
packages/app-cli/tests/md_to_html/sanitize_18.md
Normal file
@@ -0,0 +1 @@
|
||||
[xxxxx](","a");top.require('child_process').exec('open /System/Applications/Calculator.app');// '<style>')
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper [DEV]",
|
||||
"version": "2.11.2",
|
||||
"version": "2.12.0",
|
||||
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
|
||||
"homepage_url": "https://joplinapp.org",
|
||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
||||
|
@@ -34,7 +34,7 @@ import ShareFolderDialog from '../ShareFolderDialog/ShareFolderDialog';
|
||||
import { ShareInvitation } from '@joplin/lib/services/share/reducer';
|
||||
import removeKeylessItems from '../ResizableLayout/utils/removeKeylessItems';
|
||||
import { localSyncInfoFromState } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { parseCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||
import { isCallbackUrl, parseCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||
import ElectronAppWrapper from '../../ElectronAppWrapper';
|
||||
import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils';
|
||||
import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types';
|
||||
@@ -173,6 +173,7 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private openCallbackUrl(url: string) {
|
||||
if (!isCallbackUrl(url)) throw new Error(`Invalid callback URL: ${url}`);
|
||||
const { command, params } = parseCallbackUrl(url);
|
||||
void CommandService.instance().execute(command.toString(), params.id);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import { loadScript } from '../../../utils/loadScript';
|
||||
import bridge from '../../../../services/bridge';
|
||||
import { TinyMceEditorEvents } from './utils/types';
|
||||
import type { Editor } from 'tinymce';
|
||||
import { joplinCommandToTinyMceCommands, TinyMceCommand } from './utils/joplinCommandToTinyMceCommands';
|
||||
const { clipboard } = require('electron');
|
||||
const supportedLocales = require('./supportedLocales');
|
||||
|
||||
@@ -78,23 +79,6 @@ function stripMarkup(markupLanguage: number, markup: string, options: any = null
|
||||
return markupToHtml_.stripMarkup(markupLanguage, markup, options);
|
||||
}
|
||||
|
||||
interface TinyMceCommand {
|
||||
name: string;
|
||||
value?: any;
|
||||
ui?: boolean;
|
||||
}
|
||||
|
||||
interface JoplinCommandToTinyMceCommands {
|
||||
[key: string]: TinyMceCommand;
|
||||
}
|
||||
|
||||
const joplinCommandToTinyMceCommands: JoplinCommandToTinyMceCommands = {
|
||||
'textBold': { name: 'mceToggleFormat', value: 'bold' },
|
||||
'textItalic': { name: 'mceToggleFormat', value: 'italic' },
|
||||
'textLink': { name: 'mceLink' },
|
||||
'search': { name: 'SearchReplace' },
|
||||
};
|
||||
|
||||
interface LastOnChangeEventInfo {
|
||||
content: string;
|
||||
resourceInfos: ResourceInfos;
|
||||
@@ -274,11 +258,17 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const tinyMceCmd: TinyMceCommand = { ...joplinCommandToTinyMceCommands[cmd.name] };
|
||||
if (!('ui' in tinyMceCmd)) tinyMceCmd.ui = false;
|
||||
if (!('value' in tinyMceCmd)) tinyMceCmd.value = null;
|
||||
if (joplinCommandToTinyMceCommands[cmd.name] === true) {
|
||||
// Already handled in useWindowCommandHandlers.ts
|
||||
} else if (joplinCommandToTinyMceCommands[cmd.name] === false) {
|
||||
// Explicitely not supported
|
||||
} else {
|
||||
const tinyMceCmd: TinyMceCommand = { ...(joplinCommandToTinyMceCommands[cmd.name] as TinyMceCommand) };
|
||||
if (!('ui' in tinyMceCmd)) tinyMceCmd.ui = false;
|
||||
if (!('value' in tinyMceCmd)) tinyMceCmd.value = null;
|
||||
|
||||
editor.execCommand(tinyMceCmd.name, tinyMceCmd.ui, tinyMceCmd.value);
|
||||
editor.execCommand(tinyMceCmd.name, tinyMceCmd.ui, tinyMceCmd.value);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
@@ -603,11 +593,15 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
joplinSup: { inline: 'sup', remove: 'all' },
|
||||
},
|
||||
setup: (editor: Editor) => {
|
||||
editor.addCommand('joplinAttach', () => {
|
||||
insertResourcesIntoContentRef.current();
|
||||
});
|
||||
|
||||
editor.ui.registry.addButton('joplinAttach', {
|
||||
tooltip: _('Attach file'),
|
||||
icon: 'paperclip',
|
||||
onAction: async function() {
|
||||
insertResourcesIntoContentRef.current();
|
||||
editor.execCommand('joplinAttach');
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1112,7 +1106,12 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
}
|
||||
|
||||
function onPasteAsText() {
|
||||
pasteAsPlainText(null);
|
||||
// clipboard.readText returns Markdown instead of text when copying content from
|
||||
// the Rich Text Editor. When the user "Paste as text" he does not expect to see
|
||||
// anything besides text, that is why we are stripping here before pasting
|
||||
// https://github.com/laurent22/joplin/pull/8351
|
||||
const clipboardWithoutMarkdown = stripMarkup(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, clipboard.readText());
|
||||
pasteAsPlainText(clipboardWithoutMarkdown);
|
||||
}
|
||||
|
||||
editor.on(TinyMceEditorEvents.KeyUp, onKeyUp);
|
||||
|
@@ -0,0 +1,22 @@
|
||||
export interface TinyMceCommand {
|
||||
name: string;
|
||||
value?: any;
|
||||
ui?: boolean;
|
||||
}
|
||||
|
||||
interface JoplinCommandToTinyMceCommands {
|
||||
[key: string]: TinyMceCommand | boolean;
|
||||
}
|
||||
|
||||
// If the mapping is simply `true` it means that the command is supported via
|
||||
// useWindowCommandHandlers.ts. We still add it here to have the complete list
|
||||
// of supported commands.
|
||||
export const joplinCommandToTinyMceCommands: JoplinCommandToTinyMceCommands = {
|
||||
'textBold': { name: 'mceToggleFormat', value: 'bold' },
|
||||
'textItalic': { name: 'mceToggleFormat', value: 'italic' },
|
||||
'textCode': { name: 'mceToggleFormat', value: 'code' },
|
||||
'textLink': { name: 'mceLink' },
|
||||
'search': { name: 'SearchReplace' },
|
||||
'attachFile': { name: 'joplinAttach' },
|
||||
'insertDateTime': true,
|
||||
};
|
@@ -4,6 +4,7 @@ import editorCommandDeclarations from '../editorCommandDeclarations';
|
||||
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import time from '@joplin/lib/time';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import { joplinCommandToTinyMceCommands } from '../NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands';
|
||||
|
||||
const commandsWithDependencies = [
|
||||
require('../commands/showLocalSearch'),
|
||||
@@ -24,6 +25,8 @@ interface HookDependencies {
|
||||
}
|
||||
|
||||
function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, setFormNote: Function): CommandRuntime {
|
||||
const markdownEditorOnly = !Object.keys(joplinCommandToTinyMceCommands).includes(declaration.name);
|
||||
|
||||
return {
|
||||
execute: async (_context: CommandContext, ...args: any[]) => {
|
||||
if (!editorRef.current) {
|
||||
@@ -65,7 +68,7 @@ function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, s
|
||||
// currently selected text.
|
||||
//
|
||||
// https://github.com/laurent22/joplin/issues/5707
|
||||
enabledCondition: '(!modalDialogVisible || gotoAnythingVisible) && markdownEditorPaneVisible && oneNoteSelected && noteIsMarkdown',
|
||||
enabledCondition: `(!modalDialogVisible || gotoAnythingVisible) ${markdownEditorOnly ? '&& markdownEditorPaneVisible' : ''} && oneNoteSelected && noteIsMarkdown`,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.11.9",
|
||||
"version": "2.12.0",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
@@ -108,7 +108,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/laurent22/joplin#readme",
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "~2.11",
|
||||
"@joplin/tools": "~2.12",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@types/jest": "29.5.1",
|
||||
"@types/node": "18.15.13",
|
||||
@@ -117,7 +117,6 @@
|
||||
"@types/styled-components": "5.1.26",
|
||||
"electron": "19.1.4",
|
||||
"electron-builder": "22.11.7",
|
||||
"electron-notarize": "1.2.2",
|
||||
"electron-rebuild": "3.2.9",
|
||||
"glob": "8.1.0",
|
||||
"gulp": "4.0.2",
|
||||
@@ -134,11 +133,12 @@
|
||||
"7zip-bin-win": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.0.9",
|
||||
"@electron/notarize": "1.2.4",
|
||||
"@electron/remote": "2.0.10",
|
||||
"@fortawesome/fontawesome-free": "5.15.4",
|
||||
"@joeattardi/emoji-button": "4.6.4",
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@joplin/lib": "~2.12",
|
||||
"@joplin/renderer": "~2.12",
|
||||
"async-mutex": "0.4.0",
|
||||
"codemirror": "5.65.9",
|
||||
"color": "3.2.1",
|
||||
@@ -162,7 +162,7 @@
|
||||
"react": "18.2.0",
|
||||
"react-datetime": "3.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "8.0.5",
|
||||
"react-redux": "8.0.7",
|
||||
"react-select": "5.7.3",
|
||||
"react-toggle-button": "2.2.0",
|
||||
"react-tooltip": "4.5.1",
|
||||
@@ -171,7 +171,7 @@
|
||||
"roboto-fontface": "0.10.0",
|
||||
"smalltalk": "2.5.1",
|
||||
"sqlite3": "5.1.6",
|
||||
"styled-components": "5.3.10",
|
||||
"styled-components": "5.3.11",
|
||||
"styled-system": "5.1.5",
|
||||
"taboverride": "4.0.3",
|
||||
"tinymce": "5.10.6"
|
||||
|
@@ -1,14 +1,23 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const electron_notarize = require('electron-notarize');
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { notarize } from '@electron/notarize';
|
||||
const execCommand = require('./execCommand');
|
||||
|
||||
function isDesktopAppTag(tagName) {
|
||||
function isDesktopAppTag(tagName: string) {
|
||||
if (!tagName) return false;
|
||||
return tagName[0] === 'v';
|
||||
}
|
||||
|
||||
module.exports = async function(params) {
|
||||
interface Params {
|
||||
appOutDir: string;
|
||||
packager: {
|
||||
appInfo: {
|
||||
productFilename: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default async (params: Params) => {
|
||||
if (process.platform !== 'darwin') return;
|
||||
|
||||
console.info('Checking if notarization should be done...');
|
||||
@@ -26,8 +35,8 @@ module.exports = async function(params) {
|
||||
// Same appId in electron-builder.
|
||||
const appId = 'net.cozic.joplin-desktop';
|
||||
|
||||
const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
|
||||
if (!fs.existsSync(appPath)) {
|
||||
const appPath = join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
|
||||
if (!existsSync(appPath)) {
|
||||
throw new Error(`Cannot find application at: ${appPath}`);
|
||||
}
|
||||
|
||||
@@ -40,7 +49,7 @@ module.exports = async function(params) {
|
||||
}, 60000);
|
||||
|
||||
try {
|
||||
await electron_notarize.notarize({
|
||||
await notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
|
||||
@@ -58,7 +67,12 @@ module.exports = async function(params) {
|
||||
// Use this to get it:
|
||||
//
|
||||
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
|
||||
ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
// ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
// In our case, the team ID is the same as the legacy ASC_PROVIDER
|
||||
teamId: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
tool: 'notarytool',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
@@ -110,8 +110,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097712
|
||||
versionName "2.11.27"
|
||||
versionCode 2097716
|
||||
versionName "2.12.0"
|
||||
// ndk {
|
||||
// abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
// }
|
||||
|
@@ -1,7 +0,0 @@
|
||||
French small model for Vosk
|
||||
|
||||
WER
|
||||
|
||||
%WER 23.95 [ 37203 / 155330, 5373 ins, 4427 del, 27403 sub ] exp/chain_a/tdnn/decode_test_cv/wer_12_0.0
|
||||
%WER 19.30 [ 2975 / 15412, 683 ins, 672 del, 1620 sub ] exp/chain_a/tdnn/decode_test_mtedx/wer_10_0.0
|
||||
%WER 27.25 [ 20208 / 74145, 2647 ins, 5852 del, 11709 sub ] exp/chain_a/tdnn/decode_test_podcast_reseg/wer_10_0.0
|
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
--use-energy=false
|
||||
--sample-frequency=16000
|
||||
--num-mel-bins=40
|
||||
--num-ceps=40
|
||||
--low-freq=40
|
||||
--high-freq=-200
|
||||
--allow-upsample=true
|
||||
--allow-downsample=true
|
@@ -1,10 +0,0 @@
|
||||
--min-active=200
|
||||
--max-active=7000
|
||||
--beam=13.0
|
||||
--lattice-beam=4.0
|
||||
--acoustic-scale=1.0
|
||||
--frame-subsampling-factor=3
|
||||
--endpoint.silence-phones=1:2:3:4:5:6:7:8:9:10
|
||||
--endpoint.rule2.min-trailing-silence=0.5
|
||||
--endpoint.rule3.min-trailing-silence=1.0
|
||||
--endpoint.rule4.min-trailing-silence=2.0
|
Binary file not shown.
Binary file not shown.
@@ -1,76 +0,0 @@
|
||||
9365
|
||||
9366
|
||||
9367
|
||||
9368
|
||||
9369
|
||||
9370
|
||||
9371
|
||||
9372
|
||||
9373
|
||||
9374
|
||||
9375
|
||||
9376
|
||||
9377
|
||||
9378
|
||||
9379
|
||||
9380
|
||||
9381
|
||||
9382
|
||||
9383
|
||||
9384
|
||||
9385
|
||||
9386
|
||||
9387
|
||||
9388
|
||||
9389
|
||||
9390
|
||||
9391
|
||||
9392
|
||||
9393
|
||||
9394
|
||||
9395
|
||||
9396
|
||||
9397
|
||||
9398
|
||||
9399
|
||||
9400
|
||||
9401
|
||||
9402
|
||||
9403
|
||||
9404
|
||||
9405
|
||||
9406
|
||||
9407
|
||||
9408
|
||||
9409
|
||||
9410
|
||||
9411
|
||||
9412
|
||||
9413
|
||||
9414
|
||||
9415
|
||||
9416
|
||||
9417
|
||||
9418
|
||||
9419
|
||||
9420
|
||||
9421
|
||||
9422
|
||||
9423
|
||||
9424
|
||||
9425
|
||||
9426
|
||||
9427
|
||||
9428
|
||||
9429
|
||||
9430
|
||||
9431
|
||||
9432
|
||||
9433
|
||||
9434
|
||||
9435
|
||||
9436
|
||||
9437
|
||||
9438
|
||||
9439
|
||||
9440
|
@@ -1,154 +0,0 @@
|
||||
1 nonword
|
||||
2 begin
|
||||
3 end
|
||||
4 internal
|
||||
5 singleton
|
||||
6 nonword
|
||||
7 begin
|
||||
8 end
|
||||
9 internal
|
||||
10 singleton
|
||||
11 begin
|
||||
12 end
|
||||
13 internal
|
||||
14 singleton
|
||||
15 begin
|
||||
16 end
|
||||
17 internal
|
||||
18 singleton
|
||||
19 begin
|
||||
20 end
|
||||
21 internal
|
||||
22 singleton
|
||||
23 begin
|
||||
24 end
|
||||
25 internal
|
||||
26 singleton
|
||||
27 begin
|
||||
28 end
|
||||
29 internal
|
||||
30 singleton
|
||||
31 begin
|
||||
32 end
|
||||
33 internal
|
||||
34 singleton
|
||||
35 begin
|
||||
36 end
|
||||
37 internal
|
||||
38 singleton
|
||||
39 begin
|
||||
40 end
|
||||
41 internal
|
||||
42 singleton
|
||||
43 begin
|
||||
44 end
|
||||
45 internal
|
||||
46 singleton
|
||||
47 begin
|
||||
48 end
|
||||
49 internal
|
||||
50 singleton
|
||||
51 begin
|
||||
52 end
|
||||
53 internal
|
||||
54 singleton
|
||||
55 begin
|
||||
56 end
|
||||
57 internal
|
||||
58 singleton
|
||||
59 begin
|
||||
60 end
|
||||
61 internal
|
||||
62 singleton
|
||||
63 begin
|
||||
64 end
|
||||
65 internal
|
||||
66 singleton
|
||||
67 begin
|
||||
68 end
|
||||
69 internal
|
||||
70 singleton
|
||||
71 begin
|
||||
72 end
|
||||
73 internal
|
||||
74 singleton
|
||||
75 begin
|
||||
76 end
|
||||
77 internal
|
||||
78 singleton
|
||||
79 begin
|
||||
80 end
|
||||
81 internal
|
||||
82 singleton
|
||||
83 begin
|
||||
84 end
|
||||
85 internal
|
||||
86 singleton
|
||||
87 begin
|
||||
88 end
|
||||
89 internal
|
||||
90 singleton
|
||||
91 begin
|
||||
92 end
|
||||
93 internal
|
||||
94 singleton
|
||||
95 begin
|
||||
96 end
|
||||
97 internal
|
||||
98 singleton
|
||||
99 begin
|
||||
100 end
|
||||
101 internal
|
||||
102 singleton
|
||||
103 begin
|
||||
104 end
|
||||
105 internal
|
||||
106 singleton
|
||||
107 begin
|
||||
108 end
|
||||
109 internal
|
||||
110 singleton
|
||||
111 begin
|
||||
112 end
|
||||
113 internal
|
||||
114 singleton
|
||||
115 begin
|
||||
116 end
|
||||
117 internal
|
||||
118 singleton
|
||||
119 begin
|
||||
120 end
|
||||
121 internal
|
||||
122 singleton
|
||||
123 begin
|
||||
124 end
|
||||
125 internal
|
||||
126 singleton
|
||||
127 begin
|
||||
128 end
|
||||
129 internal
|
||||
130 singleton
|
||||
131 begin
|
||||
132 end
|
||||
133 internal
|
||||
134 singleton
|
||||
135 begin
|
||||
136 end
|
||||
137 internal
|
||||
138 singleton
|
||||
139 begin
|
||||
140 end
|
||||
141 internal
|
||||
142 singleton
|
||||
143 begin
|
||||
144 end
|
||||
145 internal
|
||||
146 singleton
|
||||
147 begin
|
||||
148 end
|
||||
149 internal
|
||||
150 singleton
|
||||
151 begin
|
||||
152 end
|
||||
153 internal
|
||||
154 singleton
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
[
|
||||
1.022245e+11 -6.33291e+09 -2.480997e+09 8.290258e+09 -9.084483e+09 -8.092173e+09 -1.4735e+10 -7.041795e+09 -1.171205e+10 -2.976464e+08 -1.009425e+10 -6765179 -7.821326e+09 1.449499e+09 -6.413975e+09 -5.303802e+08 -4.998635e+09 9.521598e+07 -3.073041e+09 1.56756e+08 -1.287956e+09 1.738752e+08 -2.382392e+08 -2.716675e+07 4.404485e+08 -1.913359e+08 7.780919e+08 -4.006922e+08 7.895809e+08 -5.401082e+08 5.17605e+08 -6.227134e+08 6.58271e+08 -6.204593e+07 5.187754e+08 -4.497048e+08 4.219366e+07 -2.78742e+08 -1.797385e+07 -3.604475e+07 1.053647e+09
|
||||
1.040194e+13 6.245521e+11 4.223293e+11 6.831219e+11 6.078478e+11 6.3425e+11 7.943839e+11 6.013323e+11 6.781652e+11 5.272091e+11 5.810814e+11 4.353831e+11 4.473305e+11 3.42063e+11 3.083377e+11 2.14257e+11 1.892057e+11 1.163827e+11 8.367058e+10 4.203224e+10 2.297476e+10 7.596307e+09 1.099877e+09 2.886651e+08 3.797438e+09 9.372847e+09 1.629059e+10 2.196351e+10 2.747149e+10 3.072878e+10 3.238528e+10 3.330232e+10 3.407238e+10 3.230687e+10 2.676914e+10 2.252055e+10 1.914305e+10 1.565974e+10 1.224627e+10 8.415393e+09 0 ]
|
@@ -1,2 +0,0 @@
|
||||
--left-context=3
|
||||
--right-context=3
|
@@ -1 +0,0 @@
|
||||
1b7180e6-e500-4818-adc8-a41fe97a84ce
|
@@ -46,6 +46,7 @@ import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog';
|
||||
import { voskEnabled } from '../../services/voiceTyping/vosk';
|
||||
import { isSupportedLanguage } from '../../services/voiceTyping/vosk.android';
|
||||
const urlUtils = require('@joplin/lib/urlUtils');
|
||||
|
||||
// import Vosk from 'react-native-vosk';
|
||||
@@ -1000,7 +1001,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
|
||||
// Voice typing is enabled only for French language and on Android for now
|
||||
if (voskEnabled && shim.mobilePlatform() === 'android' && currentLocale() === 'fr_FR') {
|
||||
if (voskEnabled && shim.mobilePlatform() === 'android' && isSupportedLanguage(currentLocale())) {
|
||||
output.push({
|
||||
title: _('Voice typing...'),
|
||||
onPress: () => {
|
||||
@@ -1307,7 +1308,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
const renderVoiceTypingDialog = () => {
|
||||
if (!this.state.voiceTypingDialogShown) return null;
|
||||
return <VoiceTypingDialog onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||
return <VoiceTypingDialog locale={currentLocale()} onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||
};
|
||||
|
||||
return (
|
||||
|
@@ -1,12 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Banner, ActivityIndicator } from 'react-native-paper';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { Banner, ActivityIndicator, Modal } from 'react-native-paper';
|
||||
import { _, languageName } from '@joplin/lib/locale';
|
||||
import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffect';
|
||||
import { getVosk, Recorder, startRecording, Vosk } from '../../services/voiceTyping/vosk';
|
||||
import { IconSource } from 'react-native-paper/lib/typescript/src/components/Icon';
|
||||
import { modelIsDownloaded } from '../../services/voiceTyping/vosk.android';
|
||||
|
||||
interface Props {
|
||||
locale: string;
|
||||
onDismiss: ()=> void;
|
||||
onText: (text: string)=> void;
|
||||
}
|
||||
@@ -16,30 +18,39 @@ enum RecorderState {
|
||||
Recording = 2,
|
||||
Processing = 3,
|
||||
Error = 4,
|
||||
Downloading = 5,
|
||||
}
|
||||
|
||||
const useVosk = (): [Error | null, Vosk|null] => {
|
||||
const useVosk = (locale: string): [Error | null, boolean, Vosk|null] => {
|
||||
const [vosk, setVosk] = useState<Vosk>(null);
|
||||
const [error, setError] = useState<Error>(null);
|
||||
const [mustDownloadModel, setMustDownloadModel] = useState<boolean | null>(null);
|
||||
|
||||
useAsyncEffect(async (event: AsyncEffectEvent) => {
|
||||
if (mustDownloadModel === null) return;
|
||||
|
||||
try {
|
||||
const v = await getVosk();
|
||||
const v = await getVosk(locale);
|
||||
if (event.cancelled) return;
|
||||
setVosk(v);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
} finally {
|
||||
setMustDownloadModel(false);
|
||||
}
|
||||
}, []);
|
||||
}, [locale, mustDownloadModel]);
|
||||
|
||||
return [error, vosk];
|
||||
useAsyncEffect(async (_event: AsyncEffectEvent) => {
|
||||
setMustDownloadModel(!(await modelIsDownloaded(locale)));
|
||||
}, [locale]);
|
||||
|
||||
return [error, mustDownloadModel, vosk];
|
||||
};
|
||||
|
||||
export default (props: Props) => {
|
||||
const [recorder, setRecorder] = useState<Recorder>(null);
|
||||
const [recorderState, setRecorderState] = useState<RecorderState>(RecorderState.Loading);
|
||||
|
||||
const [voskError, vosk] = useVosk();
|
||||
const [voskError, mustDownloadModel, vosk] = useVosk(props.locale);
|
||||
|
||||
useEffect(() => {
|
||||
if (voskError) {
|
||||
@@ -49,6 +60,12 @@ export default (props: Props) => {
|
||||
}
|
||||
}, [vosk, voskError]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mustDownloadModel) {
|
||||
setRecorderState(RecorderState.Downloading);
|
||||
}
|
||||
}, [mustDownloadModel]);
|
||||
|
||||
useEffect(() => {
|
||||
if (recorderState === RecorderState.Recording) {
|
||||
setRecorder(startRecording(vosk, {
|
||||
@@ -60,7 +77,7 @@ export default (props: Props) => {
|
||||
}, [recorderState, vosk, props.onText]);
|
||||
|
||||
const onDismiss = useCallback(() => {
|
||||
recorder.cleanup();
|
||||
if (recorder) recorder.cleanup();
|
||||
props.onDismiss();
|
||||
}, [recorder, props.onDismiss]);
|
||||
|
||||
@@ -69,6 +86,7 @@ export default (props: Props) => {
|
||||
[RecorderState.Loading]: () => _('Loading...'),
|
||||
[RecorderState.Recording]: () => _('Please record your voice...'),
|
||||
[RecorderState.Processing]: () => _('Converting speech to text...'),
|
||||
[RecorderState.Downloading]: () => _('Downloading %s language files...', languageName(props.locale)),
|
||||
[RecorderState.Error]: () => _('Error: %s', voskError.message),
|
||||
};
|
||||
|
||||
@@ -80,6 +98,7 @@ export default (props: Props) => {
|
||||
[RecorderState.Loading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
||||
[RecorderState.Recording]: 'microphone',
|
||||
[RecorderState.Processing]: 'microphone',
|
||||
[RecorderState.Downloading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
||||
[RecorderState.Error]: 'alert-circle-outline',
|
||||
};
|
||||
|
||||
@@ -87,16 +106,18 @@ export default (props: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Banner
|
||||
visible={true}
|
||||
icon={renderIcon()}
|
||||
actions={[
|
||||
{
|
||||
label: _('Done'),
|
||||
onPress: onDismiss,
|
||||
},
|
||||
]}>
|
||||
{`${_('Voice typing...')}\n${renderContent()}`}
|
||||
</Banner>
|
||||
<Modal visible={true} style={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
|
||||
<Banner
|
||||
visible={true}
|
||||
icon={renderIcon()}
|
||||
actions={[
|
||||
{
|
||||
label: _('Done'),
|
||||
onPress: onDismiss,
|
||||
},
|
||||
]}>
|
||||
{`${_('Voice typing...')}\n${renderContent()}`}
|
||||
</Banner>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
@@ -517,13 +517,13 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 92;
|
||||
CURRENT_PROJECT_VERSION = 94;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 12.11.3;
|
||||
MARKETING_VERSION = 12.12.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -546,12 +546,12 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 92;
|
||||
CURRENT_PROJECT_VERSION = 94;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 12.11.3;
|
||||
MARKETING_VERSION = 12.12.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -698,14 +698,14 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 92;
|
||||
CURRENT_PROJECT_VERSION = 94;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 12.11.3;
|
||||
MARKETING_VERSION = 12.12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
|
||||
@@ -729,14 +729,14 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 92;
|
||||
CURRENT_PROJECT_VERSION = 94;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 12.11.3;
|
||||
MARKETING_VERSION = 12.12.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@@ -333,7 +333,7 @@ PODS:
|
||||
- React-jsinspector (0.71.10)
|
||||
- React-logger (0.71.10):
|
||||
- glog
|
||||
- react-native-alarm-notification (2.11.0):
|
||||
- react-native-alarm-notification (2.12.0):
|
||||
- React
|
||||
- react-native-camera (4.2.1):
|
||||
- React-Core
|
||||
@@ -347,9 +347,9 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-fingerprint-scanner (6.0.0):
|
||||
- React
|
||||
- react-native-geolocation (2.1.0):
|
||||
- react-native-geolocation (3.0.6):
|
||||
- React-Core
|
||||
- react-native-get-random-values (1.8.0):
|
||||
- react-native-get-random-values (1.9.0):
|
||||
- React-Core
|
||||
- react-native-image-picker (5.3.1):
|
||||
- React-Core
|
||||
@@ -359,7 +359,7 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-rsa-native (2.0.5):
|
||||
- React
|
||||
- react-native-saf-x (2.11.0):
|
||||
- react-native-saf-x (2.12.0):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (4.5.3):
|
||||
- RCT-Folly
|
||||
@@ -465,7 +465,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNCPushNotificationIOS (1.11.0):
|
||||
- React-Core
|
||||
- RNDateTimePicker (7.0.1):
|
||||
- RNDateTimePicker (7.1.0):
|
||||
- React-Core
|
||||
- RNExitApp (1.1.0):
|
||||
- React
|
||||
@@ -483,7 +483,15 @@ PODS:
|
||||
- React-Core
|
||||
- RNVectorIcons (9.2.0):
|
||||
- React-Core
|
||||
- RNZipArchive (6.0.9):
|
||||
- React-Core
|
||||
- RNZipArchive/Core (= 6.0.9)
|
||||
- SSZipArchive (~> 2.2)
|
||||
- RNZipArchive/Core (6.0.9):
|
||||
- React-Core
|
||||
- SSZipArchive (~> 2.2)
|
||||
- SocketRocket (0.6.0)
|
||||
- SSZipArchive (2.4.3)
|
||||
- Yoga (1.14.0)
|
||||
- YogaKit (1.18.1):
|
||||
- Yoga (~> 1.14)
|
||||
@@ -577,6 +585,7 @@ DEPENDENCIES:
|
||||
- RNSecureRandom (from `../node_modules/react-native-securerandom`)
|
||||
- RNShare (from `../node_modules/react-native-share`)
|
||||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
||||
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
@@ -595,6 +604,7 @@ SPEC REPOS:
|
||||
- libevent
|
||||
- OpenSSL-Universal
|
||||
- SocketRocket
|
||||
- SSZipArchive
|
||||
- YogaKit
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -724,6 +734,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-share"
|
||||
RNVectorIcons:
|
||||
:path: "../node_modules/react-native-vector-icons"
|
||||
RNZipArchive:
|
||||
:path: "../node_modules/react-native-zip-archive"
|
||||
Yoga:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
@@ -763,17 +775,17 @@ SPEC CHECKSUMS:
|
||||
React-jsiexecutor: 4bb480a183a354e4dbfb1012936b1a2bb9357de7
|
||||
React-jsinspector: cdc854f8b13abd202afa54bc12578e5afb9cfae1
|
||||
React-logger: ef2269b3afa6ba868da90496c3e17a4ec4f4cee0
|
||||
react-native-alarm-notification: 26527410a6162d07a9dc57f4bbc62e94ff48e65d
|
||||
react-native-alarm-notification: 0732f97be04975a23ba60e675bdb961a0aaf6aa6
|
||||
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
|
||||
react-native-document-picker: 69ca2094d8780cfc1e7e613894d15290fdc54bba
|
||||
react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe
|
||||
react-native-geolocation: 69f4fd37650b8e7fee91816d395e62dd16f5ab8d
|
||||
react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a
|
||||
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
|
||||
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
|
||||
react-native-image-picker: ec9b713e248760bfa0f879f0715391de4651a7cb
|
||||
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
|
||||
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
|
||||
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
|
||||
react-native-saf-x: 9bd5238d3b43d76bbec64aa82c173ac20a4bce9f
|
||||
react-native-saf-x: 129cd2ddf120a1f6164c724b2846d172666b33de
|
||||
react-native-safe-area-context: b8979f5eda6ed5903d4dbc885be3846ea3daa753
|
||||
react-native-slider: 33b8d190b59d4f67a541061bb91775d53d617d9d
|
||||
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
|
||||
@@ -795,7 +807,7 @@ SPEC CHECKSUMS:
|
||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
|
||||
RNDateTimePicker: e073697ac3e8a378968d68ab0581fef542b8af8a
|
||||
RNDateTimePicker: 7ecd54a97fc3749f38c3c89a171f6cbd52f3c142
|
||||
RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3
|
||||
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
|
||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||
@@ -804,7 +816,9 @@ SPEC CHECKSUMS:
|
||||
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
|
||||
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
|
||||
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
|
||||
RNZipArchive: 68a0c6db4b1c103f846f1559622050df254a3ade
|
||||
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
|
||||
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
|
||||
Yoga: e7ea9e590e27460d28911403b894722354d73479
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "@joplin/app-mobile",
|
||||
"description": "Joplin for Mobile",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "BROWSERSLIST_IGNORE_OLD_DATA=true react-native start --reset-cache",
|
||||
@@ -18,13 +18,13 @@
|
||||
"postinstall": "jetify && yarn run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/react-native-alarm-notification": "~2.11",
|
||||
"@joplin/react-native-saf-x": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@joplin/lib": "~2.12",
|
||||
"@joplin/react-native-alarm-notification": "~2.12",
|
||||
"@joplin/react-native-saf-x": "~2.12",
|
||||
"@joplin/renderer": "~2.12",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/datetimepicker": "7.0.1",
|
||||
"@react-native-community/geolocation": "2.1.0",
|
||||
"@react-native-community/datetimepicker": "7.1.0",
|
||||
"@react-native-community/geolocation": "3.0.6",
|
||||
"@react-native-community/netinfo": "9.3.10",
|
||||
"@react-native-community/push-notification-ios": "1.11.0",
|
||||
"@react-native-community/slider": "4.4.2",
|
||||
@@ -50,11 +50,11 @@
|
||||
"react-native-file-viewer": "2.1.5",
|
||||
"react-native-fingerprint-scanner": "6.0.0",
|
||||
"react-native-fs": "2.20.0",
|
||||
"react-native-get-random-values": "1.8.0",
|
||||
"react-native-get-random-values": "1.9.0",
|
||||
"react-native-image-picker": "5.3.1",
|
||||
"react-native-image-resizer": "1.4.5",
|
||||
"react-native-localize": "3.0.0",
|
||||
"react-native-modal-datetime-picker": "14.0.1",
|
||||
"react-native-modal-datetime-picker": "15.0.1",
|
||||
"react-native-paper": "5.8.0",
|
||||
"react-native-popup-menu": "0.16.1",
|
||||
"react-native-quick-actions": "0.3.13",
|
||||
@@ -69,7 +69,8 @@
|
||||
"react-native-version-info": "1.1.1",
|
||||
"react-native-vosk": "0.1.12",
|
||||
"react-native-webview": "12.4.0",
|
||||
"react-redux": "7.2.9",
|
||||
"react-native-zip-archive": "6.0.9",
|
||||
"react-redux": "8.0.7",
|
||||
"redux": "4.2.1",
|
||||
"rn-fetch-blob": "0.12.0",
|
||||
"stream": "0.0.2",
|
||||
@@ -95,7 +96,7 @@
|
||||
"@codemirror/search": "6.3.0",
|
||||
"@codemirror/state": "6.2.0",
|
||||
"@codemirror/view": "6.9.3",
|
||||
"@joplin/tools": "~2.11",
|
||||
"@joplin/tools": "~2.12",
|
||||
"@lezer/highlight": "1.1.4",
|
||||
"@tsconfig/react-native": "2.0.2",
|
||||
"@types/fs-extra": "11.0.1",
|
||||
@@ -116,7 +117,7 @@
|
||||
"metro-react-native-babel-preset": "0.73.9",
|
||||
"nodemon": "2.0.22",
|
||||
"ts-jest": "29.1.0",
|
||||
"ts-loader": "9.4.2",
|
||||
"ts-loader": "9.4.3",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "5.0.2",
|
||||
"uglify-js": "3.17.4",
|
||||
|
@@ -1,17 +1,25 @@
|
||||
import { languageCodeOnly } from '@joplin/lib/locale';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Vosk from 'react-native-vosk';
|
||||
import { unzip } from 'react-native-zip-archive';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
const md5 = require('md5');
|
||||
|
||||
const logger = Logger.create('voiceTyping/vosk');
|
||||
|
||||
enum State {
|
||||
Idle = 0,
|
||||
Recording,
|
||||
Completing,
|
||||
}
|
||||
|
||||
interface StartOptions {
|
||||
onResult: (text: string)=> void;
|
||||
}
|
||||
|
||||
let vosk_: Vosk|null = null;
|
||||
let vosk_: Record<string, Vosk> = {};
|
||||
|
||||
let state_: State = State.Idle;
|
||||
|
||||
export const voskEnabled = true;
|
||||
@@ -23,12 +31,113 @@ export interface Recorder {
|
||||
cleanup: ()=> void;
|
||||
}
|
||||
|
||||
export const getVosk = async () => {
|
||||
if (vosk_) return vosk_;
|
||||
vosk_ = new Vosk();
|
||||
const result = await vosk_.loadModel('model-fr-fr');
|
||||
const supportedLanguages = {
|
||||
'en': 'https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip',
|
||||
'cn': 'https://alphacephei.com/vosk/models/vosk-model-small-cn-0.22.zip',
|
||||
'ru': 'https://alphacephei.com/vosk/models/vosk-model-small-ru-0.22.zip',
|
||||
'fr': 'https://alphacephei.com/vosk/models/vosk-model-small-fr-0.22.zip',
|
||||
'de': 'https://alphacephei.com/vosk/models/vosk-model-small-de-0.15.zip',
|
||||
'es': 'https://alphacephei.com/vosk/models/vosk-model-small-es-0.42.zip',
|
||||
'pt': 'https://alphacephei.com/vosk/models/vosk-model-small-pt-0.3.zip',
|
||||
'tr': 'https://alphacephei.com/vosk/models/vosk-model-small-tr-0.3.zip',
|
||||
'vn': 'https://alphacephei.com/vosk/models/vosk-model-small-vn-0.4.zip',
|
||||
'it': 'https://alphacephei.com/vosk/models/vosk-model-small-it-0.22.zip',
|
||||
'nl': 'https://alphacephei.com/vosk/models/vosk-model-small-nl-0.22.zip',
|
||||
'uk': 'https://alphacephei.com/vosk/models/vosk-model-small-uk-v3-small.zip',
|
||||
'ja': 'https://alphacephei.com/vosk/models/vosk-model-small-ja-0.22.zip',
|
||||
'hi': 'https://alphacephei.com/vosk/models/vosk-model-small-hi-0.22.zip',
|
||||
'cs': 'https://alphacephei.com/vosk/models/vosk-model-small-cs-0.4-rhasspy.zip',
|
||||
'pl': 'https://alphacephei.com/vosk/models/vosk-model-small-pl-0.22.zip',
|
||||
'uz': 'https://alphacephei.com/vosk/models/vosk-model-small-uz-0.22.zip',
|
||||
'ko': 'https://alphacephei.com/vosk/models/vosk-model-small-ko-0.22.zip',
|
||||
};
|
||||
|
||||
export const isSupportedLanguage = (locale: string) => {
|
||||
const l = languageCodeOnly(locale).toLowerCase();
|
||||
return Object.keys(supportedLanguages).includes(l);
|
||||
};
|
||||
|
||||
// Where all the models files for all the languages are
|
||||
const getModelRootDir = () => {
|
||||
return `${RNFetchBlob.fs.dirs.DocumentDir}/vosk-models`;
|
||||
};
|
||||
|
||||
// Where we unzip a model after downloading it
|
||||
const getUnzipDir = (locale: string) => {
|
||||
return `${getModelRootDir()}/${locale}`;
|
||||
};
|
||||
|
||||
// Where the model for a particular language is
|
||||
const getModelDir = (locale: string) => {
|
||||
return `${getUnzipDir(locale)}/model`;
|
||||
};
|
||||
|
||||
const languageModelUrl = (locale: string) => {
|
||||
const l = languageCodeOnly(locale).toLowerCase();
|
||||
if (!(l in supportedLanguages)) throw new Error(`No language file for: ${locale}`);
|
||||
return (supportedLanguages as any)[l];
|
||||
};
|
||||
|
||||
export const modelIsDownloaded = async (locale: string) => {
|
||||
const uuidFile = `${getModelDir(locale)}/uuid`;
|
||||
return shim.fsDriver().exists(uuidFile);
|
||||
};
|
||||
|
||||
export const getVosk = async (locale: string) => {
|
||||
if (vosk_[locale]) return vosk_[locale];
|
||||
|
||||
const vosk = new Vosk();
|
||||
const modelDir = await downloadModel(locale);
|
||||
logger.info(`Loading model from ${modelDir}`);
|
||||
await shim.fsDriver().readDirStats(modelDir);
|
||||
const result = await vosk.loadModel(modelDir);
|
||||
logger.info('getVosk:', result);
|
||||
return vosk_;
|
||||
|
||||
vosk_ = { [locale]: vosk };
|
||||
|
||||
return vosk;
|
||||
};
|
||||
|
||||
const downloadModel = async (locale: string) => {
|
||||
const modelUrl = languageModelUrl(locale);
|
||||
const unzipDir = getUnzipDir(locale);
|
||||
const zipFilePath = `${unzipDir}.zip`;
|
||||
const modelDir = getModelDir(locale);
|
||||
const uuidFile = `${modelDir}/uuid`;
|
||||
|
||||
if (await modelIsDownloaded(locale)) {
|
||||
logger.info(`Model for ${locale} already exists at ${modelDir}`);
|
||||
return modelDir;
|
||||
}
|
||||
|
||||
await shim.fsDriver().remove(unzipDir);
|
||||
|
||||
logger.info(`Downloading model from: ${modelUrl}`);
|
||||
|
||||
await shim.fetchBlob(languageModelUrl(locale), {
|
||||
path: zipFilePath,
|
||||
});
|
||||
|
||||
logger.info(`Unzipping ${zipFilePath} => ${unzipDir}`);
|
||||
|
||||
await unzip(zipFilePath, unzipDir);
|
||||
|
||||
const dirs = await shim.fsDriver().readDirStats(unzipDir);
|
||||
if (dirs.length !== 1) {
|
||||
logger.error('Expected 1 directory but got', dirs);
|
||||
throw new Error(`Expected 1 directory, but got ${dirs.length}`);
|
||||
}
|
||||
|
||||
const fullUnzipPath = `${unzipDir}/${dirs[0].path}`;
|
||||
|
||||
logger.info(`Moving ${fullUnzipPath} => ${modelDir}`);
|
||||
await shim.fsDriver().rename(fullUnzipPath, modelDir);
|
||||
|
||||
await shim.fsDriver().writeFile(uuidFile, md5(modelUrl));
|
||||
|
||||
await shim.fsDriver().remove(zipFilePath);
|
||||
|
||||
return modelDir;
|
||||
};
|
||||
|
||||
export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
||||
@@ -110,8 +219,9 @@ export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
||||
});
|
||||
},
|
||||
cleanup: () => {
|
||||
if (state_ !== State.Idle) {
|
||||
if (state_ === State.Recording) {
|
||||
logger.info('Cancelling...');
|
||||
state_ = State.Completing;
|
||||
vosk.stopOnly();
|
||||
completeRecording('', null);
|
||||
}
|
||||
|
@@ -13,7 +13,15 @@ export interface Recorder {
|
||||
cleanup: ()=> void;
|
||||
}
|
||||
|
||||
export const getVosk = async () => {
|
||||
export const isSupportedLanguage = (_locale: string) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const modelIsDownloaded = async (_locale: string) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const getVosk = async (_locale: string) => {
|
||||
return {} as any;
|
||||
};
|
||||
|
||||
|
@@ -116,6 +116,13 @@ export default class FsDriverRN extends FsDriverBase {
|
||||
return RNFS.moveFile(source, dest);
|
||||
}
|
||||
|
||||
public async rename(source: string, dest: string) {
|
||||
if (isScopedUri(source) || isScopedUri(dest)) {
|
||||
await RNSAF.rename(source, dest);
|
||||
}
|
||||
return RNFS.moveFile(source, dest);
|
||||
}
|
||||
|
||||
public async exists(path: string) {
|
||||
if (isScopedUri(path)) {
|
||||
return RNSAF.exists(path);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"description": "Fast & forgiving HTML/XML/RSS parser",
|
||||
"version": "4.1.43",
|
||||
"version": "4.1.44",
|
||||
"author": "Felix Boehm <me@feedic.com>",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": "2.3.0",
|
||||
"domhandler": "3.3.0",
|
||||
"domhandler": "5.0.3",
|
||||
"domutils": "3.1.0",
|
||||
"entities": "2.2.0"
|
||||
},
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "@joplin/fork-sax",
|
||||
"description": "An evented streaming XML parser in JavaScript",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
||||
"version": "1.2.47",
|
||||
"version": "1.2.48",
|
||||
"main": "lib/sax.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"standard": "17.0.0",
|
||||
"tap": "16.3.4"
|
||||
"tap": "16.3.6"
|
||||
},
|
||||
"gitHead": "eb4b0e64eab40a51b0895d3a40a9d8c3cb7b1b14"
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-uslug",
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"description": "A permissive slug generator that works with unicode.",
|
||||
"author": "Jeremy Selier <jerem.selier@gmail.com>",
|
||||
"publishConfig": {
|
||||
|
3
packages/generate-plugin-doc/README.md
Normal file
3
packages/generate-plugin-doc/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# generate-plugin-doc
|
||||
|
||||
This package is only to run the buildPluginDoc command. The version of typedoc we use needs an old version of typescript, so we cannot put the whole thing at the root, where it used to be.
|
11
packages/generate-plugin-doc/package.json
Normal file
11
packages/generate-plugin-doc/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "generate-plugin-doc",
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"scripts": {
|
||||
"buildPluginDoc_": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme '../../Assets/PluginDocTheme/' --readme '../../Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../../../joplin-website/docs/api/references/plugin_api ../lib/services/plugins/api/"
|
||||
},
|
||||
"dependencies": {
|
||||
"typedoc": "0.17.8",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
@@ -1,71 +1,8 @@
|
||||
# generator-joplin
|
||||
|
||||
Scaffolds out a new Joplin plugin
|
||||
This is the Yeoman generator used to create a Joplin plugin.
|
||||
|
||||
## Installation
|
||||
|
||||
First, install [Yeoman](http://yeoman.io) and generator-joplin using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)).
|
||||
|
||||
```bash
|
||||
npm install -g yo
|
||||
npm install -g generator-joplin
|
||||
```
|
||||
|
||||
Then generate your new project:
|
||||
|
||||
```bash
|
||||
yo joplin
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
To test the generator for development purposes, follow the instructions there: https://yeoman.io/authoring/#running-the-generator
|
||||
This is a template to create a new Joplin plugin.
|
||||
|
||||
## Structure
|
||||
|
||||
The main two files you will want to look at are:
|
||||
|
||||
- `/src/index.ts`, which contains the entry point for the plugin source code.
|
||||
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
|
||||
|
||||
The file `/plugin.config.json` could also be useful if you intend to use [external scripts](#external-script-files), such as content scripts or webview scripts.
|
||||
|
||||
## Building the plugin
|
||||
|
||||
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
|
||||
|
||||
To build the plugin, simply run `npm run dist`.
|
||||
|
||||
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
|
||||
|
||||
## Publishing the plugin
|
||||
|
||||
To publish the plugin, add it to npmjs.com by running `npm publish`. Later on, a script will pick up your plugin and add it automatically to the Joplin plugin repository as long as the package satisfies these conditions:
|
||||
|
||||
- In `package.json`, the name starts with "joplin-plugin-". For example, "joplin-plugin-toc".
|
||||
- In `package.json`, the keywords include "joplin-plugin".
|
||||
- In the `publish/` directory, there should be a .jpl and .json file (which are built by `npm run dist`)
|
||||
|
||||
In general all this is done automatically by the plugin generator, which will set the name and keywords of package.json, and will put the right files in the "publish" directory. But if something doesn't work and your plugin doesn't appear in the repository, double-check the above conditions.
|
||||
|
||||
## Updating the plugin framework
|
||||
|
||||
To update the plugin framework, run `npm run update`.
|
||||
|
||||
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
|
||||
|
||||
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
|
||||
|
||||
## External script files
|
||||
|
||||
By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
|
||||
|
||||
- The script is a TypeScript file - in which case it has to be compiled to JavaScript.
|
||||
|
||||
- The script requires modules you've added to package.json. In that case, the script, whether JS or TS, must be compiled so that the dependencies are bundled with the JPL file.
|
||||
|
||||
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
|
||||
More info in the [Plugin Generator Doc](./generators/app/templates/GENERATOR_DOC.md)
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -12,7 +12,12 @@ module.exports = class extends Generator {
|
||||
|
||||
this.option('silent');
|
||||
this.option('update');
|
||||
this.option('nodePackageManager', 'npm');
|
||||
|
||||
// This appears to be deprecated and undocumented
|
||||
// Maybe need this instead?
|
||||
// https://github.com/yeoman/generator/issues/1294#issuecomment-841668595
|
||||
|
||||
// this.option('nodePackageManager', 'npm');
|
||||
|
||||
if (this.options.update) {
|
||||
// When updating, overwrite files without prompting
|
||||
|
@@ -14,7 +14,7 @@ npm install -g generator-joplin
|
||||
Then generate your new project:
|
||||
|
||||
```bash
|
||||
yo joplin
|
||||
yo --node-package-manager npm joplin
|
||||
```
|
||||
|
||||
## Development
|
||||
@@ -39,6 +39,10 @@ To build the plugin, simply run `npm run dist`.
|
||||
|
||||
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
|
||||
|
||||
## Updating the manifest version number
|
||||
|
||||
You can run `npm run updateVersion` to bump the patch part of the version number, so for example 1.0.3 will become 1.0.4. This script will update both the package.json and manifest.json version numbers so as to keep them in sync.
|
||||
|
||||
## Publishing the plugin
|
||||
|
||||
To publish the plugin, add it to npmjs.com by running `npm publish`. Later on, a script will pick up your plugin and add it automatically to the Joplin plugin repository as long as the package satisfies these conditions:
|
||||
@@ -67,6 +71,13 @@ By default, the compiler (webpack) is going to compile `src/index.ts` only (as w
|
||||
|
||||
To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.
|
||||
|
||||
## More information
|
||||
|
||||
- [Joplin Plugin API](https://joplinapp.org/api/references/plugin_api/classes/joplin.html)
|
||||
- [Joplin Data API](https://joplinapp.org/api/references/rest_api/)
|
||||
- [Joplin Plugin Manifest](https://joplinapp.org/api/references/plugin_manifest/)
|
||||
- Ask for help on the [forum](https://discourse.joplinapp.org/) or our [Discord channel](https://discord.gg/VSj7AFHvpq)
|
||||
|
||||
## License
|
||||
|
||||
MIT © Laurent Cozic
|
||||
|
@@ -1,24 +1,5 @@
|
||||
# Joplin Plugin
|
||||
|
||||
This is a template to create a new Joplin plugin.
|
||||
This is your new Joplin plugin. It is suggested that you use this README file to document your plugin.
|
||||
|
||||
The main two files you will want to look at are:
|
||||
|
||||
- `/src/index.ts`, which contains the entry point for the plugin source code.
|
||||
- `/src/manifest.json`, which is the plugin manifest. It contains information such as the plugin a name, version, etc.
|
||||
|
||||
## Building the plugin
|
||||
|
||||
The plugin is built using Webpack, which creates the compiled code in `/dist`. A JPL archive will also be created at the root, which can use to distribute the plugin.
|
||||
|
||||
To build the plugin, simply run `npm run dist`.
|
||||
|
||||
The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.
|
||||
|
||||
## Updating the plugin framework
|
||||
|
||||
To update the plugin framework, run `npm run update`.
|
||||
|
||||
In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.
|
||||
|
||||
The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.
|
||||
For information on how to build or publish the plugin, please see [GENERATOR_DOC.md](./GENERATOR_DOC.md)
|
||||
|
@@ -4,7 +4,8 @@
|
||||
"scripts": {
|
||||
"dist": "webpack --env joplin-plugin-config=buildMain && webpack --env joplin-plugin-config=buildExtraScripts && webpack --env joplin-plugin-config=createArchive",
|
||||
"prepare": "npm run dist",
|
||||
"update": "npm install -g generator-joplin && yo joplin --update"
|
||||
"updateVersion": "webpack --env joplin-plugin-config=updateVersion",
|
||||
"update": "npm install -g generator-joplin && yo joplin --node-package-manager npm --update"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"id": "<%= pluginId %>",
|
||||
"app_min_version": "2.11",
|
||||
"app_min_version": "2.12",
|
||||
"version": "1.0.0",
|
||||
"name": "<%= pluginName %>",
|
||||
"description": "<%= pluginDescription %>",
|
||||
|
@@ -44,8 +44,12 @@ for (const moduleName of builtinModules) {
|
||||
moduleFallback[moduleName] = false;
|
||||
}
|
||||
|
||||
const getPackageJson = () => {
|
||||
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||
};
|
||||
|
||||
function validatePackageJson() {
|
||||
const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||
const content = getPackageJson();
|
||||
if (!content.name || content.name.indexOf('joplin-plugin-') !== 0) {
|
||||
console.warn(chalk.yellow(`WARNING: To publish the plugin, the package name should start with "joplin-plugin-" (found "${content.name}") in ${packageJsonPath}`));
|
||||
}
|
||||
@@ -102,7 +106,6 @@ function validateScreenshots(screenshots) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function readManifest(manifestPath) {
|
||||
const content = fs.readFileSync(manifestPath, 'utf8');
|
||||
const output = JSON.parse(content);
|
||||
@@ -133,12 +136,16 @@ function createPluginArchive(sourceDir, destPath) {
|
||||
console.info(chalk.cyan(`Plugin archive has been created in ${destPath}`));
|
||||
}
|
||||
|
||||
const writeManifest = (manifestPath, content) => {
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(content, null, '\t'), 'utf8');
|
||||
};
|
||||
|
||||
function createPluginInfo(manifestPath, destPath, jplFilePath) {
|
||||
const contentText = fs.readFileSync(manifestPath, 'utf8');
|
||||
const content = JSON.parse(contentText);
|
||||
content._publish_hash = `sha256:${fileSha256(jplFilePath)}`;
|
||||
content._publish_commit = currentGitInfo();
|
||||
fs.writeFileSync(destPath, JSON.stringify(content, null, '\t'), 'utf8');
|
||||
writeManifest(destPath, content);
|
||||
}
|
||||
|
||||
function onBuildCompleted() {
|
||||
@@ -262,6 +269,32 @@ function buildExtraScriptConfigs(userConfig) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const increaseVersion = version => {
|
||||
try {
|
||||
const s = version.split('.');
|
||||
const d = Number(s[s.length - 1]) + 1;
|
||||
s[s.length - 1] = `${d}`;
|
||||
return s.join('.');
|
||||
} catch (error) {
|
||||
error.message = `Could not parse version number: ${version}: ${error.message}`;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const updateVersion = () => {
|
||||
const packageJson = getPackageJson();
|
||||
packageJson.version = increaseVersion(packageJson.version);
|
||||
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8');
|
||||
|
||||
const manifest = readManifest(manifestPath);
|
||||
manifest.version = increaseVersion(manifest.version);
|
||||
writeManifest(manifestPath, manifest);
|
||||
|
||||
if (packageJson.version !== manifest.version) {
|
||||
console.warn(chalk.yellow(`Version numbers have been updated but they do not match: package.json (${packageJson.version}), manifest.json (${manifest.version}). Set them to the required values to get them in sync.`));
|
||||
}
|
||||
};
|
||||
|
||||
function main(environ) {
|
||||
const configName = environ['joplin-plugin-config'];
|
||||
if (!configName) throw new Error('A config file must be specified via the --joplin-plugin-config flag');
|
||||
@@ -298,6 +331,11 @@ function main(environ) {
|
||||
fs.mkdirpSync(publishDir);
|
||||
}
|
||||
|
||||
if (configName === 'updateVersion') {
|
||||
updateVersion();
|
||||
return [];
|
||||
}
|
||||
|
||||
return configs[configName];
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "generator-joplin",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.1",
|
||||
"description": "Scaffolds out a new Joplin plugin",
|
||||
"homepage": "https://github.com/laurent22/joplin/tree/dev/packages/generator-joplin",
|
||||
"author": {
|
||||
@@ -34,4 +34,4 @@
|
||||
"repository": "https://github.com/laurent22/generator-joplin",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"private": true
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/htmlpack",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "Pack an HTML file and all its linked resources into a single HTML file",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
@@ -14,7 +14,7 @@
|
||||
"author": "Laurent Cozic",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@joplin/fork-htmlparser2": "^4.1.43",
|
||||
"@joplin/fork-htmlparser2": "^4.1.44",
|
||||
"css": "3.0.0",
|
||||
"datauri": "4.1.0",
|
||||
"fs-extra": "11.1.1",
|
||||
|
@@ -3,13 +3,14 @@ import * as callbackUrlUtils from './callbackUrlUtils';
|
||||
describe('callbackUrlUtils', () => {
|
||||
|
||||
it('should identify valid callback urls', () => {
|
||||
const url = 'joplin://x-callback-url/123?a=b';
|
||||
const url = 'joplin://x-callback-url/openFolder?a=b';
|
||||
expect(callbackUrlUtils.isCallbackUrl(url)).toBe(true);
|
||||
});
|
||||
|
||||
it('should identify invalid callback urls', () => {
|
||||
expect(callbackUrlUtils.isCallbackUrl('not-joplin://x-callback-url/123?a=b')).toBe(false);
|
||||
expect(callbackUrlUtils.isCallbackUrl('joplin://xcallbackurl/123?a=b')).toBe(false);
|
||||
expect(callbackUrlUtils.isCallbackUrl('joplin://x-callback-url/invalidCommand?a=b')).toBe(false);
|
||||
});
|
||||
|
||||
it('should build valid note callback urls', () => {
|
||||
|
@@ -1,7 +1,9 @@
|
||||
const URL = require('url-parse');
|
||||
|
||||
export function isCallbackUrl(s: string) {
|
||||
return s.startsWith('joplin://x-callback-url/');
|
||||
return s.startsWith('joplin://x-callback-url/openNote?') ||
|
||||
s.startsWith('joplin://x-callback-url/openFolder?') ||
|
||||
s.startsWith('joplin://x-callback-url/openTag?');
|
||||
}
|
||||
|
||||
export function getNoteCallbackUrl(noteId: string) {
|
||||
|
@@ -508,7 +508,8 @@ function languageNameInEnglish(languageCode: string) {
|
||||
return codeToLanguageE_[languageCode] ? codeToLanguageE_[languageCode] : '';
|
||||
}
|
||||
|
||||
function languageName(languageCode: string, defaultToEnglish: boolean = true) {
|
||||
function languageName(canonicalName: string, defaultToEnglish: boolean = true) {
|
||||
const languageCode = languageCodeOnly(canonicalName);
|
||||
if (codeToLanguage_[languageCode]) return codeToLanguage_[languageCode];
|
||||
if (defaultToEnglish) return languageNameInEnglish(languageCode);
|
||||
return '';
|
||||
@@ -603,4 +604,4 @@ const stringByLocale = (locale: string, s: string, ...args: any[]): string => {
|
||||
}
|
||||
};
|
||||
|
||||
export { _, _n, supportedLocales, currentLocale, localesFromLanguageCode, languageCodeOnly, countryDisplayName, localeStrings, setLocale, supportedLocalesToLanguages, defaultLocale, closestSupportedLocale, languageCode, countryCodeOnly };
|
||||
export { _, _n, supportedLocales, languageName, currentLocale, localesFromLanguageCode, languageCodeOnly, countryDisplayName, localeStrings, setLocale, supportedLocalesToLanguages, defaultLocale, closestSupportedLocale, languageCode, countryCodeOnly };
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/lib",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "Joplin Core library",
|
||||
"author": "Laurent Cozic",
|
||||
"homepage": "",
|
||||
@@ -31,14 +31,14 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.296.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.296.0",
|
||||
"@joplin/fork-htmlparser2": "^4.1.43",
|
||||
"@joplin/fork-sax": "^1.2.47",
|
||||
"@joplin/fork-uslug": "^1.0.8",
|
||||
"@joplin/htmlpack": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@joplin/turndown": "^4.0.65",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.47",
|
||||
"@joplin/utils": "~2.11",
|
||||
"@joplin/fork-htmlparser2": "^4.1.44",
|
||||
"@joplin/fork-sax": "^1.2.48",
|
||||
"@joplin/fork-uslug": "^1.0.9",
|
||||
"@joplin/htmlpack": "~2.12",
|
||||
"@joplin/renderer": "~2.12",
|
||||
"@joplin/turndown": "^4.0.66",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.48",
|
||||
"@joplin/utils": "~2.12",
|
||||
"@types/nanoid": "3.0.0",
|
||||
"async-mutex": "0.4.0",
|
||||
"base-64": "1.0.0",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/pdf-viewer",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "Provides embedded PDF viewers for Joplin",
|
||||
"main": "dist/main.js",
|
||||
"types": "src/main.ts",
|
||||
@@ -30,7 +30,7 @@
|
||||
"jest-environment-jsdom": "29.5.0",
|
||||
"style-loader": "3.3.3",
|
||||
"ts-jest": "29.1.0",
|
||||
"ts-loader": "9.4.2",
|
||||
"ts-loader": "9.4.3",
|
||||
"typescript": "5.0.2",
|
||||
"webpack": "5.74.0",
|
||||
"webpack-cli": "4.10.0"
|
||||
@@ -39,11 +39,11 @@
|
||||
"@fortawesome/fontawesome-svg-core": "6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "6.1.2",
|
||||
"@fortawesome/react-fontawesome": "0.2.0",
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/lib": "~2.12",
|
||||
"async-mutex": "0.4.0",
|
||||
"pdfjs-dist": "2.16.105",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"styled-components": "5.3.10"
|
||||
"styled-components": "5.3.11"
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/plugin-repo-cli",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"bin": "./dist/index.js",
|
||||
@@ -18,9 +18,9 @@
|
||||
"author": "",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/tools": "~2.11",
|
||||
"@joplin/utils": "~2.11",
|
||||
"@joplin/lib": "~2.12",
|
||||
"@joplin/tools": "~2.12",
|
||||
"@joplin/utils": "~2.12",
|
||||
"fs-extra": "11.1.1",
|
||||
"gh-release-assets": "2.0.1",
|
||||
"node-fetch": "2.6.7",
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@joplin/react-native-alarm-notification",
|
||||
"title": "React Native Alarm Notification for Joplin. Forked from https://github.com/emekalites/react-native-alarm-notification",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "schedule alarm with notification in react-native",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/react-native-saf-x",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "a module to help work with scoped storages on android easily",
|
||||
"main": "src/index",
|
||||
"react-native": "src/index",
|
||||
|
@@ -5,7 +5,7 @@ describe('linkReplacement', () => {
|
||||
|
||||
test('should handle non-resource links', () => {
|
||||
const r = linkReplacement('https://example.com/test').html;
|
||||
expect(r).toBe('<a data-from-md href=\'https://example.com/test\' onclick=\'postMessage("https://example.com/test", { resourceId: "" }); return false;\'>');
|
||||
expect(r).toBe('<a data-from-md href=\'https://example.com/test\' onclick=\'postMessage("https://example.com/test", { resourceId: "" }); return false;\'>');
|
||||
});
|
||||
|
||||
test('should handle non-resource links - simple rendering', () => {
|
||||
@@ -17,7 +17,7 @@ describe('linkReplacement', () => {
|
||||
// Handles a link such as:
|
||||
// [Google](https://www.goo'onclick=javascript:alert(/1/);f=')
|
||||
const r = linkReplacement('https://www.goo\'onclick=javascript:alert(/1/);f=\'', { linkRenderingType: 1 }).html;
|
||||
expect(r).toBe('<a data-from-md href=\'https://www.goo'onclick=javascript:alert(/1/);f='\' onclick=\'postMessage("https://www.goo%27onclick=javascript:alert(/1/);f=%27", { resourceId: "" }); return false;\'>');
|
||||
expect(r).toBe('<a data-from-md href=\'https://www.goo'onclick=javascript:alert(/1/);f='\' onclick=\'postMessage("https://www.goo%27onclick=javascript:alert(/1/);f=%27", { resourceId: "" }); return false;\'>');
|
||||
});
|
||||
|
||||
test('should handle resource links - downloaded status', () => {
|
||||
@@ -35,7 +35,7 @@ describe('linkReplacement', () => {
|
||||
},
|
||||
}).html;
|
||||
|
||||
expect(r).toBe(`<a data-from-md data-resource-id='${resourceId}' href='#' onclick='postMessage("joplin://${resourceId}", { resourceId: "${resourceId}" }); return false;'><span class="resource-icon fa-joplin"></span>`);
|
||||
expect(r).toBe(`<a data-from-md data-resource-id='${resourceId}' href='#' onclick='postMessage("joplin://${resourceId}", { resourceId: "${resourceId}" }); return false;'><span class="resource-icon fa-joplin"></span>`);
|
||||
});
|
||||
|
||||
test('should handle resource links - idle status', () => {
|
||||
|
@@ -99,7 +99,7 @@ export default function(href: string, options: Options = null): LinkReplacementR
|
||||
postMessageSyntax: options.postMessageSyntax ?? 'void',
|
||||
}, onClick);
|
||||
} else {
|
||||
js = `onclick='${js}'`;
|
||||
js = `onclick='${htmlentities(js)}'`;
|
||||
}
|
||||
|
||||
if (hrefAttr.indexOf('#') === 0 && href.indexOf('#') === 0) js = ''; // If it's an internal anchor, don't add any JS since the webview is going to handle navigating to the right place
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/renderer",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"description": "The Joplin note renderer, used the mobile and desktop application",
|
||||
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/renderer",
|
||||
"main": "index.js",
|
||||
@@ -26,8 +26,8 @@
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/fork-htmlparser2": "^4.1.43",
|
||||
"@joplin/fork-uslug": "^1.0.8",
|
||||
"@joplin/fork-htmlparser2": "^4.1.44",
|
||||
"@joplin/fork-uslug": "^1.0.9",
|
||||
"font-awesome-filetypes": "2.1.0",
|
||||
"fs-extra": "11.1.1",
|
||||
"highlight.js": "11.8.0",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/server",
|
||||
"version": "2.11.1",
|
||||
"version": "2.12.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start-dev": "yarn run build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
|
||||
@@ -23,19 +23,19 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.296.0",
|
||||
"@fortawesome/fontawesome-free": "5.15.4",
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@koa/cors": "3.1.0",
|
||||
"@joplin/lib": "~2.12",
|
||||
"@joplin/renderer": "~2.12",
|
||||
"@koa/cors": "3.4.3",
|
||||
"@types/uuid": "9.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bulma": "0.9.4",
|
||||
"bulma-prefers-dark": "0.1.0-beta.1",
|
||||
"compare-versions": "3.6.0",
|
||||
"dayjs": "1.11.7",
|
||||
"formidable": "2.1.1",
|
||||
"dayjs": "1.11.8",
|
||||
"formidable": "2.1.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"html-entities": "1.4.0",
|
||||
"jquery": "3.6.4",
|
||||
"jquery": "3.7.0",
|
||||
"knex": "2.4.2",
|
||||
"koa": "2.14.2",
|
||||
"markdown-it": "13.0.1",
|
||||
@@ -43,9 +43,9 @@
|
||||
"nanoid": "2.1.11",
|
||||
"node-cron": "3.0.2",
|
||||
"node-env-file": "0.1.8",
|
||||
"nodemailer": "6.9.2",
|
||||
"nodemailer": "6.9.3",
|
||||
"nodemon": "2.0.22",
|
||||
"pg": "8.10.0",
|
||||
"pg": "8.11.0",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"prettycron": "0.10.0",
|
||||
"query-string": "7.1.3",
|
||||
@@ -58,7 +58,7 @@
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@joplin/tools": "~2.11",
|
||||
"@joplin/tools": "~2.12",
|
||||
"@rmp135/sql-ts": "1.16.0",
|
||||
"@types/formidable": "2.0.6",
|
||||
"@types/fs-extra": "11.0.1",
|
||||
|
@@ -3,7 +3,7 @@ import { DbConnection, defaultAdminEmail, defaultAdminPassword } from '../db';
|
||||
import { hashPassword } from '../utils/auth';
|
||||
import uuidgen from '../utils/uuidgen';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.text('email', 'mediumtext').unique().notNullable();
|
||||
@@ -123,13 +123,13 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
updated_time: now,
|
||||
created_time: now,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('users');
|
||||
await db.schema.dropTable('sessions');
|
||||
await db.schema.dropTable('permissions');
|
||||
await db.schema.dropTable('files');
|
||||
await db.schema.dropTable('api_clients');
|
||||
await db.schema.dropTable('changes');
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('notifications', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('owner_id', 32).notNullable();
|
||||
@@ -17,8 +17,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('notifications', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['owner_id', 'key']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('notifications');
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('owner_id', 32).notNullable();
|
||||
@@ -10,8 +10,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('shares');
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('share_users', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('share_id', 32).notNullable();
|
||||
@@ -38,8 +38,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('share_users');
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('joplin_file_contents', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('owner_id', 32).notNullable();
|
||||
@@ -18,8 +18,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
table.integer('content_type', 2).defaultTo(1).notNullable();
|
||||
table.string('content_id', 32).defaultTo('').notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('joplin_file_contents');
|
||||
}
|
||||
};
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('folder_id', 32).defaultTo('').notNullable();
|
||||
table.integer('is_auto', 1).defaultTo(0).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('joplin_items');
|
||||
}
|
||||
};
|
||||
|
@@ -25,7 +25,7 @@ import { DbConnection } from '../db';
|
||||
// is_shared: 1
|
||||
// type_: 1`;
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.text('name').notNullable();
|
||||
@@ -109,8 +109,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
|
||||
await db.schema.dropTable('permissions');
|
||||
await db.schema.dropTable('joplin_file_contents');
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('items');
|
||||
}
|
||||
};
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('max_item_size').defaultTo(0).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('can_share').defaultTo(1).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('email_confirmed').defaultTo(0).notNullable();
|
||||
table.integer('must_set_password').defaultTo(0).notNullable();
|
||||
@@ -40,8 +40,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('tokens', (table: Knex.CreateTableBuilder) => {
|
||||
table.index(['value', 'user_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('account_type').defaultTo(0).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('can_upload').defaultTo(1).notNullable();
|
||||
});
|
||||
|
||||
await db('users').update({ can_upload: 1 });
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('subscriptions', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.string('user_id', 32).notNullable();
|
||||
@@ -12,8 +12,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.bigInteger('jop_updated_time').defaultTo(0).notNullable();
|
||||
});
|
||||
@@ -22,8 +22,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.renameColumn('can_share', 'can_share_folder');
|
||||
table.integer('can_share_note').defaultTo(1).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -5,14 +5,14 @@ import { DbConnection } from '../db';
|
||||
// recreate it in the same migration. So this is split into two migrations.
|
||||
// https://github.com/knex/knex/issues/2581
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('max_item_size');
|
||||
table.dropColumn('can_share_folder');
|
||||
table.dropColumn('can_share_note');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('max_item_size').defaultTo(null).nullable();
|
||||
table.specificType('can_share_folder', 'smallint').defaultTo(null).nullable();
|
||||
@@ -12,8 +12,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('total_item_size').defaultTo(0).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db('users').update({ email: db.raw('LOWER(email)') });
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('total_item_size');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.bigInteger('total_item_size').defaultTo(0).notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.specificType('enabled', 'smallint').defaultTo(1).nullable();
|
||||
});
|
||||
@@ -9,8 +9,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('subscriptions', (table: Knex.CreateTableBuilder) => {
|
||||
table.specificType('is_deleted', 'smallint').defaultTo(0).nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
try {
|
||||
await db.schema.alterTable('emails', (table: Knex.CreateTableBuilder) => {
|
||||
table.text('key', 'mediumtext').defaultTo('').notNullable();
|
||||
@@ -13,8 +13,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
// await db.schema.alterTable('emails', function(table: Knex.CreateTableBuilder) {
|
||||
// table.unique(['recipient_email', 'key']);
|
||||
// });
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(_db: DbConnection): Promise<any> {
|
||||
export const up = async (_db: DbConnection) => {
|
||||
// try {
|
||||
// await db.schema.alterTable('emails', function(table: Knex.CreateTableBuilder) {
|
||||
// table.dropUnique(['recipient_email', 'key']);
|
||||
@@ -9,8 +9,8 @@ export async function up(_db: DbConnection): Promise<any> {
|
||||
// } catch (error) {
|
||||
// // console.warn('Could not drop unique constraint - this is not an error.', error);
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
export const down = async (_db: DbConnection) => {
|
||||
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('user_flags', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.string('user_id', 32).notNullable();
|
||||
@@ -13,8 +13,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('user_flags', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['user_id', 'type']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('user_flags');
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('share_users', (table: Knex.CreateTableBuilder) => {
|
||||
table.text('master_key', 'mediumtext').defaultTo('').notNullable();
|
||||
});
|
||||
@@ -9,9 +9,9 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('master_key_id', 32).defaultTo('').notNullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('share_users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('master_key');
|
||||
});
|
||||
@@ -19,4 +19,4 @@ export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('master_key_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('events', (table: Knex.CreateTableBuilder) => {
|
||||
table.uuid('id').unique().notNullable();
|
||||
table.increments('counter').unique().primary().notNullable();
|
||||
@@ -14,8 +14,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
table.index('type');
|
||||
table.index('name');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('events');
|
||||
}
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@ import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
import { msleep } from '../utils/time';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
if (!(await db.schema.hasColumn('items', 'owner_id'))) {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('owner_id', 32).defaultTo('').notNullable();
|
||||
@@ -58,10 +58,10 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('owner_id', 32).notNullable().alter();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('owner_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['name', 'owner_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropUnique(['name', 'owner_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('storages', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.text('connection_string').notNullable();
|
||||
@@ -31,12 +31,12 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('storages', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['connection_string']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('storages');
|
||||
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('content_storage_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.index('content_storage_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropIndex('content_storage_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.createTable('user_deletions', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.string('user_id', 32).notNullable();
|
||||
@@ -19,8 +19,8 @@ export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('user_deletions', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['user_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.dropTable('user_deletions');
|
||||
}
|
||||
};
|
||||
|
@@ -5,16 +5,16 @@ import { DbConnection } from '../db';
|
||||
// it to an empty string by default, and update all rows that have "0" as
|
||||
// recipient_id.
|
||||
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('emails', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('recipient_id', 32).defaultTo('').notNullable().alter();
|
||||
});
|
||||
|
||||
await db('emails').update({ recipient_id: '' }).where('recipient_id', '=', '0');
|
||||
}
|
||||
};
|
||||
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
export const down = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('emails', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('recipient_id', 32).defaultTo(0).notNullable().alter();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user