mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-23 18:53:36 +02:00
Merge branch 'release-2.2' into dev
This commit is contained in:
commit
3a22674c03
5245
packages/app-cli/package-lock.json
generated
5245
packages/app-cli/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "2.2.1",
|
||||
"version": "2.2.2",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
@ -42,6 +42,7 @@
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.2",
|
||||
"@joplin/renderer": "~2.2",
|
||||
"aws-sdk": "^2.588.0",
|
||||
"chalk": "^4.1.0",
|
||||
"compare-version": "^0.1.2",
|
||||
"fs-extra": "^5.0.0",
|
||||
|
@ -40,23 +40,7 @@ joplin.plugins.register({
|
||||
`);
|
||||
|
||||
const result3 = await dialogs.open(handle3);
|
||||
console.info('Got result: ' + JSON.stringify(result3));
|
||||
|
||||
|
||||
const handle4 = await dialogs.create('myDialog4');
|
||||
await dialogs.setHtml(handle4, `
|
||||
<h1>This dialog tests dynamic sizing</h1>
|
||||
<h3>Resize the window and the dialog should resize accordingly</h3>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
|
||||
</p>
|
||||
`);
|
||||
await (dialogs as any).setFitToContent(handle4, false);
|
||||
await dialogs.open(handle4);
|
||||
|
||||
console.info('Got result: ' + JSON.stringify(result3));
|
||||
},
|
||||
|
||||
});
|
||||
|
@ -782,7 +782,6 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
scripts={view.scripts}
|
||||
pluginId={plugin.id}
|
||||
buttons={view.buttons}
|
||||
fitToContent={view.fitToContent}
|
||||
/>);
|
||||
}
|
||||
|
||||
|
2
packages/app-desktop/package-lock.json
generated
2
packages/app-desktop/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.2.6",
|
||||
"version": "2.2.7",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.2.6",
|
||||
"version": "2.2.7",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
|
@ -31,8 +31,8 @@ export interface Props {
|
||||
const StyledFrame = styled.iframe`
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: ${(props: any) => props.fitToContent ? `${props.width}px` : '90vw'};
|
||||
height: ${(props: any) => props.fitToContent ? `${props.height}px` : '80vh'};
|
||||
width: ${(props: any) => props.fitToContent ? `${props.width}px` : '100%'};
|
||||
height: ${(props: any) => props.fitToContent ? `${props.height}px` : '100%'};
|
||||
border: none;
|
||||
border-bottom: ${(props: Props) => props.borderBottom ? `1px solid ${props.theme.dividerColor}` : 'none'};
|
||||
`;
|
||||
|
@ -9,7 +9,6 @@ const styled = require('styled-components').default;
|
||||
|
||||
interface Props extends UserWebviewProps {
|
||||
buttons: ButtonSpec[];
|
||||
fitToContent: boolean;
|
||||
}
|
||||
|
||||
const StyledRoot = styled.div`
|
||||
@ -114,7 +113,7 @@ export default function UserWebviewDialog(props: Props) {
|
||||
viewId={props.viewId}
|
||||
themeId={props.themeId}
|
||||
borderBottom={false}
|
||||
fitToContent={props.fitToContent}
|
||||
fitToContent={true}
|
||||
onSubmit={onSubmit}
|
||||
onDismiss={onDismiss}
|
||||
onReady={onReady}
|
||||
|
@ -141,10 +141,10 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097642
|
||||
versionName "2.2.3"
|
||||
versionCode 2097644
|
||||
versionName "2.2.5"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
||||
// https://github.com/react-native-community/react-native-camera/issues/2138
|
||||
@ -158,7 +158,7 @@ android {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
include "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
@ -6,10 +6,6 @@
|
||||
|
||||
// So there's basically still a one way flux: React => SQLite => Redux => React
|
||||
|
||||
// For aws-sdk-js-v3
|
||||
import 'react-native-get-random-values';
|
||||
import 'react-native-url-polyfill/auto';
|
||||
|
||||
import { LogBox, AppRegistry } from 'react-native';
|
||||
const Root = require('./root').default;
|
||||
|
||||
|
@ -221,8 +221,6 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-geolocation (2.0.2):
|
||||
- React
|
||||
- react-native-get-random-values (1.7.0):
|
||||
- React-Core
|
||||
- react-native-image-picker (2.3.4):
|
||||
- React-Core
|
||||
- react-native-image-resizer (1.3.0):
|
||||
@ -347,7 +345,6 @@ DEPENDENCIES:
|
||||
- react-native-camera (from `../node_modules/react-native-camera`)
|
||||
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
|
||||
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
|
||||
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
|
||||
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
|
||||
- react-native-image-resizer (from `../node_modules/react-native-image-resizer`)
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
@ -426,8 +423,6 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-document-picker"
|
||||
react-native-geolocation:
|
||||
:path: "../node_modules/@react-native-community/geolocation"
|
||||
react-native-get-random-values:
|
||||
:path: "../node_modules/react-native-get-random-values"
|
||||
react-native-image-picker:
|
||||
:path: "../node_modules/react-native-image-picker"
|
||||
react-native-image-resizer:
|
||||
@ -512,7 +507,6 @@ SPEC CHECKSUMS:
|
||||
react-native-camera: 5c1fbfecf63b802b8ca4a71c60d30a71550fb348
|
||||
react-native-document-picker: b3e78a8f7fef98b5cb069f20fc35797d55e68e28
|
||||
react-native-geolocation: cbd9d6bd06bac411eed2671810f454d4908484a8
|
||||
react-native-get-random-values: 237bffb1c7e05fb142092681531810a29ba53015
|
||||
react-native-image-picker: 32d1ad2c0024ca36161ae0d5c2117e2d6c441f11
|
||||
react-native-image-resizer: b53bf95ad880100e20262687e41f76fdbc9df255
|
||||
react-native-netinfo: 34f4d7a42f49157f3b45c14217d256bce7dc9682
|
||||
|
57
packages/app-mobile/package-lock.json
generated
57
packages/app-mobile/package-lock.json
generated
@ -3636,11 +3636,6 @@
|
||||
"time-stamp": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"fast-base64-decode": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
|
||||
"integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="
|
||||
},
|
||||
"fb-watchman": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
|
||||
@ -7073,11 +7068,6 @@
|
||||
"escape-goat": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@ -7352,14 +7342,6 @@
|
||||
"utf8": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-native-get-random-values": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.7.0.tgz",
|
||||
"integrity": "sha512-zDhmpWUekGRFb9I+MQkxllHcqXN9HBSsgPwBQfrZ1KZYpzDspWLZ6/yLMMZrtq4pVqNR7C7N96L3SuLpXv1nhQ==",
|
||||
"requires": {
|
||||
"fast-base64-decode": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"react-native-image-picker": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-2.3.4.tgz",
|
||||
@ -7423,14 +7405,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-native-sqlite-storage/-/react-native-sqlite-storage-5.0.0.tgz",
|
||||
"integrity": "sha512-c1Joq3/tO1nmIcP8SkRZNolPSbfvY8uZg5lXse0TmjIPC0qHVbk96IMvWGyly1TmYCIpxpuDRc0/xCffDbYIvg=="
|
||||
},
|
||||
"react-native-url-polyfill": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.3.0.tgz",
|
||||
"integrity": "sha512-w9JfSkvpqqlix9UjDvJjm1EjSt652zVQ6iwCIj1cVVkwXf4jQhQgTNXY6EVTwuAmUjg6BC6k9RHCBynoLFo3IQ==",
|
||||
"requires": {
|
||||
"whatwg-url-without-unicode": "8.0.0-3"
|
||||
}
|
||||
},
|
||||
"react-native-vector-icons": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-7.1.0.tgz",
|
||||
@ -9092,22 +9066,6 @@
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
|
||||
},
|
||||
"url": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
|
||||
"integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
|
||||
"requires": {
|
||||
"punycode": "1.3.2",
|
||||
"querystring": "0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"url-parse-lax": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||
@ -9274,26 +9232,11 @@
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
|
||||
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz",
|
||||
"integrity": "sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ=="
|
||||
},
|
||||
"whatwg-url-without-unicode": {
|
||||
"version": "8.0.0-3",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
|
||||
"integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==",
|
||||
"requires": {
|
||||
"buffer": "^5.4.3",
|
||||
"punycode": "^2.1.1",
|
||||
"webidl-conversions": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
|
@ -39,7 +39,6 @@
|
||||
"react-native-dropdownalert": "^3.1.2",
|
||||
"react-native-file-viewer": "^2.1.4",
|
||||
"react-native-fs": "^2.16.6",
|
||||
"react-native-get-random-values": "^1.7.0",
|
||||
"react-native-image-picker": "^2.3.4",
|
||||
"react-native-image-resizer": "^1.3.0",
|
||||
"react-native-modal-datetime-picker": "^9.0.0",
|
||||
@ -50,7 +49,6 @@
|
||||
"react-native-share": "^5.1.5",
|
||||
"react-native-side-menu": "^1.1.3",
|
||||
"react-native-sqlite-storage": "^5.0.0",
|
||||
"react-native-url-polyfill": "^1.3.0",
|
||||
"react-native-vector-icons": "^7.1.0",
|
||||
"react-native-version-info": "^1.1.0",
|
||||
"react-native-webview": "^10.9.2",
|
||||
@ -61,7 +59,6 @@
|
||||
"stream-browserify": "^3.0.0",
|
||||
"string-natural-compare": "^2.0.2",
|
||||
"timers": "^0.1.1",
|
||||
"url": "^0.11.0",
|
||||
"valid-url": "^1.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import FsDriverBase from '@joplin/lib/fs-driver-base';
|
||||
const RNFetchBlob = require('rn-fetch-blob').default;
|
||||
const RNFS = require('react-native-fs');
|
||||
const { Writable } = require('stream-browserify');
|
||||
const { Buffer } = require('buffer');
|
||||
|
||||
export default class FsDriverRN extends FsDriverBase {
|
||||
public appendFileSync() {
|
||||
@ -24,6 +26,27 @@ export default class FsDriverRN extends FsDriverBase {
|
||||
return await this.unlink(path);
|
||||
}
|
||||
|
||||
public writeBinaryFile(path: string, content: any) {
|
||||
const buffer = Buffer.from(content);
|
||||
return RNFetchBlob.fs.writeStream(path, 'base64').then((stream: any) => {
|
||||
const fileStream = new Writable({
|
||||
write(chunk: any, _encoding: any, callback: Function) {
|
||||
this.stream.write(chunk.toString('base64'));
|
||||
callback();
|
||||
},
|
||||
final(callback: Function) {
|
||||
this.stream.close();
|
||||
callback();
|
||||
},
|
||||
});
|
||||
// using options.construct is not implemented in readable-stream so lets
|
||||
// pass the stream from RNFetchBlob to the Writable instance here
|
||||
fileStream.stream = stream;
|
||||
fileStream.write(buffer);
|
||||
fileStream.end();
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a format compatible with Node.js format
|
||||
private rnfsStatToStd_(stat: any, path: string) {
|
||||
return {
|
||||
|
2
packages/fork-htmlparser2/package-lock.json
generated
2
packages/fork-htmlparser2/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"version": "4.1.31",
|
||||
"version": "4.1.32",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@joplin/fork-htmlparser2",
|
||||
"description": "Fast & forgiving HTML/XML/RSS parser",
|
||||
"version": "4.1.31",
|
||||
"version": "4.1.32",
|
||||
"author": "Felix Boehm <me@feedic.com>",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
2
packages/fork-sax/package-lock.json
generated
2
packages/fork-sax/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/fork-sax",
|
||||
"version": "1.2.35",
|
||||
"version": "1.2.36",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -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.35",
|
||||
"version": "1.2.36",
|
||||
"main": "lib/sax.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -4,7 +4,7 @@ const Setting = require('./models/Setting').default;
|
||||
const { FileApi } = require('./file-api.js');
|
||||
const Synchronizer = require('./Synchronizer').default;
|
||||
const { FileApiDriverAmazonS3 } = require('./file-api-driver-amazon-s3.js');
|
||||
const { S3Client, HeadBucketCommand } = require('@aws-sdk/client-s3');
|
||||
const S3 = require('aws-sdk/clients/s3');
|
||||
|
||||
class SyncTargetAmazonS3 extends BaseSyncTarget {
|
||||
static id() {
|
||||
@ -38,14 +38,10 @@ class SyncTargetAmazonS3 extends BaseSyncTarget {
|
||||
|
||||
s3AuthParameters() {
|
||||
return {
|
||||
// We need to set a region. See https://github.com/aws/aws-sdk-js-v3/issues/1845#issuecomment-754832210
|
||||
region: 'us-east-1',
|
||||
credentials: {
|
||||
accessKeyId: Setting.value('sync.8.username'),
|
||||
secretAccessKey: Setting.value('sync.8.password'),
|
||||
},
|
||||
UseArnRegion: true, // override the request region with the region inferred from requested resource's ARN
|
||||
forcePathStyle: true,
|
||||
accessKeyId: Setting.value('sync.8.username'),
|
||||
secretAccessKey: Setting.value('sync.8.password'),
|
||||
s3UseArnRegion: true, // override the request region with the region inferred from requested resource's ARN
|
||||
s3ForcePathStyle: true,
|
||||
endpoint: Setting.value('sync.8.url'),
|
||||
};
|
||||
}
|
||||
@ -53,31 +49,20 @@ class SyncTargetAmazonS3 extends BaseSyncTarget {
|
||||
api() {
|
||||
if (this.api_) return this.api_;
|
||||
|
||||
this.api_ = new S3Client(this.s3AuthParameters());
|
||||
|
||||
// There is a bug with auto skew correction in aws-sdk-js-v3
|
||||
// and this attempts to remove the skew correction for all calls.
|
||||
// There are some additional spots in the app where we reset this
|
||||
// to zero as well as it appears the skew logic gets triggered
|
||||
// which makes "RequestTimeTooSkewed" errors...
|
||||
// See https://github.com/aws/aws-sdk-js-v3/issues/2208
|
||||
this.api_.config.systemClockOffset = 0;
|
||||
this.api_ = new S3(this.s3AuthParameters());
|
||||
return this.api_;
|
||||
}
|
||||
|
||||
static async newFileApi_(syncTargetId, options) {
|
||||
const apiOptions = {
|
||||
region: 'us-east-1',
|
||||
credentials: {
|
||||
accessKeyId: options.username(),
|
||||
secretAccessKey: options.password(),
|
||||
},
|
||||
UseArnRegion: true, // override the request region with the region inferred from requested resource's ARN
|
||||
forcePathStyle: true,
|
||||
accessKeyId: options.username(),
|
||||
secretAccessKey: options.password(),
|
||||
s3UseArnRegion: true,
|
||||
s3ForcePathStyle: true,
|
||||
endpoint: options.url(),
|
||||
};
|
||||
|
||||
const api = new S3Client(apiOptions);
|
||||
const api = new S3(apiOptions);
|
||||
const driver = new FileApiDriverAmazonS3(api, SyncTargetAmazonS3.s3BucketName());
|
||||
const fileApi = new FileApi('', driver);
|
||||
fileApi.setSyncTargetId(syncTargetId);
|
||||
@ -95,14 +80,12 @@ class SyncTargetAmazonS3 extends BaseSyncTarget {
|
||||
|
||||
try {
|
||||
const headBucketReq = new Promise((resolve, reject) => {
|
||||
fileApi.driver().api().send(
|
||||
|
||||
new HeadBucketCommand({
|
||||
Bucket: options.path(),
|
||||
}),(err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
fileApi.driver().api().headBucket({
|
||||
Bucket: options.path(),
|
||||
},(err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
});
|
||||
const result = await headBucketReq;
|
||||
if (!result) throw new Error(`AWS S3 bucket not found: ${SyncTargetAmazonS3.s3BucketName()}`);
|
||||
|
@ -85,6 +85,7 @@ shared.saveSettings = function(comp) {
|
||||
for (const key in comp.state.settings) {
|
||||
if (!comp.state.settings.hasOwnProperty(key)) continue;
|
||||
if (comp.state.changedSettingKeys.indexOf(key) < 0) continue;
|
||||
console.info('Saving', key, comp.state.settings[key]);
|
||||
Setting.setValue(key, comp.state.settings[key]);
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,6 @@ const { basename } = require('./path-utils');
|
||||
const shim = require('./shim').default;
|
||||
const JoplinError = require('./JoplinError').default;
|
||||
const { Buffer } = require('buffer');
|
||||
const { GetObjectCommand, ListObjectsV2Command, HeadObjectCommand, PutObjectCommand, DeleteObjectCommand, DeleteObjectsCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
||||
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
|
||||
|
||||
const S3_MAX_DELETES = 1000;
|
||||
|
||||
@ -28,33 +26,31 @@ class FileApiDriverAmazonS3 {
|
||||
}
|
||||
|
||||
hasErrorCode_(error, errorCode) {
|
||||
if (!error || typeof error.name !== 'string') return false;
|
||||
return error.name.indexOf(errorCode) >= 0;
|
||||
if (!error || typeof error.code !== 'string') return false;
|
||||
return error.code.indexOf(errorCode) >= 0;
|
||||
}
|
||||
|
||||
// Because of the way AWS-SDK-v3 works for getting data from a bucket we will
|
||||
// use a pre-signed URL to avoid https://github.com/aws/aws-sdk-js-v3/issues/1877
|
||||
async s3GenerateGetURL(key) {
|
||||
const signedUrl = await getSignedUrl(this.api(), new GetObjectCommand({
|
||||
Bucket: this.s3_bucket_,
|
||||
Key: key,
|
||||
}), {
|
||||
expiresIn: 3600,
|
||||
});
|
||||
return signedUrl;
|
||||
}
|
||||
|
||||
// We've now moved to aws-sdk-v3 and this note is outdated, but explains the promise structure.
|
||||
// Need to make a custom promise, built-in promise is broken: https://github.com/aws/aws-sdk-js/issues/1436
|
||||
// TODO: Re-factor to https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3#asyncawait
|
||||
async s3GetObject(key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().getObject({
|
||||
Bucket: this.s3_bucket_,
|
||||
Key: key,
|
||||
}, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async s3ListObjects(key, cursor) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().send(new ListObjectsV2Command({
|
||||
this.api().listObjectsV2({
|
||||
Bucket: this.s3_bucket_,
|
||||
Prefix: key,
|
||||
Delimiter: '/',
|
||||
ContinuationToken: cursor,
|
||||
}), (err, response) => {
|
||||
}, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
@ -63,10 +59,10 @@ class FileApiDriverAmazonS3 {
|
||||
|
||||
async s3HeadObject(key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().send(new HeadObjectCommand({
|
||||
this.api().headObject({
|
||||
Bucket: this.s3_bucket_,
|
||||
Key: key,
|
||||
}), (err, response) => {
|
||||
}, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
@ -75,11 +71,11 @@ class FileApiDriverAmazonS3 {
|
||||
|
||||
async s3PutObject(key, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().send(new PutObjectCommand({
|
||||
this.api().putObject({
|
||||
Bucket: this.s3_bucket_,
|
||||
Key: key,
|
||||
Body: body,
|
||||
}), (err, response) => {
|
||||
}, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
@ -91,12 +87,12 @@ class FileApiDriverAmazonS3 {
|
||||
const body = await shim.fsDriver().readFile(path, 'base64');
|
||||
const fileStat = await shim.fsDriver().stat(path);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().send(new PutObjectCommand({
|
||||
this.api().putObject({
|
||||
Bucket: this.s3_bucket_,
|
||||
Key: key,
|
||||
Body: Buffer.from(body, 'base64'),
|
||||
ContentLength: `${fileStat.size}`,
|
||||
}), (err, response) => {
|
||||
}, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
@ -105,10 +101,10 @@ class FileApiDriverAmazonS3 {
|
||||
|
||||
async s3DeleteObject(key) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().send(new DeleteObjectCommand({
|
||||
this.api().deleteObject({
|
||||
Bucket: this.s3_bucket_,
|
||||
Key: key,
|
||||
}),
|
||||
},
|
||||
(err, response) => {
|
||||
if (err) {
|
||||
console.log(err.code);
|
||||
@ -122,10 +118,10 @@ class FileApiDriverAmazonS3 {
|
||||
// Assumes key is formatted, like `{Key: 's3 path'}`
|
||||
async s3DeleteObjects(keys) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api().send(new DeleteObjectsCommand({
|
||||
this.api().deleteObjects({
|
||||
Bucket: this.s3_bucket_,
|
||||
Delete: { Objects: keys },
|
||||
}),
|
||||
},
|
||||
(err, response) => {
|
||||
if (err) {
|
||||
console.log(err.code);
|
||||
@ -192,20 +188,8 @@ class FileApiDriverAmazonS3 {
|
||||
prefixPath = `${prefixPath}/`;
|
||||
}
|
||||
|
||||
// There is a bug/quirk of aws-sdk-js-v3 which causes the
|
||||
// S3Client systemClockOffset to be wildly inaccurate. This
|
||||
// effectively removes the offset and sets it to system time.
|
||||
// See https://github.com/aws/aws-sdk-js-v3/issues/2208 for more.
|
||||
// If the user's time actaully off, then this should correctly
|
||||
// result in a RequestTimeTooSkewed error from s3ListObjects.
|
||||
this.api().config.systemClockOffset = 0;
|
||||
|
||||
let response = await this.s3ListObjects(prefixPath);
|
||||
|
||||
// In aws-sdk-js-v3 if there are no contents it no longer returns
|
||||
// an empty array. This creates an Empty array to pass onward.
|
||||
if (response.Contents === undefined) response.Contents = [];
|
||||
|
||||
let output = this.metadataToStats_(response.Contents, prefixPath);
|
||||
|
||||
while (response.IsTruncated) {
|
||||
@ -228,17 +212,31 @@ class FileApiDriverAmazonS3 {
|
||||
|
||||
try {
|
||||
let output = null;
|
||||
let response = null;
|
||||
|
||||
const s3Url = await this.s3GenerateGetURL(remotePath);
|
||||
const response = await this.s3GetObject(remotePath);
|
||||
output = response.Body;
|
||||
|
||||
if (options.target === 'file') {
|
||||
output = await shim.fetchBlob(s3Url, options);
|
||||
const filePath = options.path;
|
||||
if (!filePath) throw new Error('get: target options.path is missing');
|
||||
|
||||
// TODO: check if this ever hits on RN
|
||||
await shim.fsDriver().writeBinaryFile(filePath, output);
|
||||
return {
|
||||
ok: true,
|
||||
path: filePath,
|
||||
text: () => {
|
||||
return response.statusMessage;
|
||||
},
|
||||
json: () => {
|
||||
return { message: `${response.statusCode}: ${response.statusMessage}` };
|
||||
},
|
||||
status: response.statusCode,
|
||||
headers: response.headers,
|
||||
};
|
||||
}
|
||||
|
||||
if (responseFormat === 'text') {
|
||||
response = await shim.fetch(s3Url, options);
|
||||
output = await response.text();
|
||||
output = output.toString();
|
||||
}
|
||||
|
||||
return output;
|
||||
@ -312,11 +310,11 @@ class FileApiDriverAmazonS3 {
|
||||
|
||||
async move(oldPath, newPath) {
|
||||
const req = new Promise((resolve, reject) => {
|
||||
this.api().send(new CopyObjectCommand({
|
||||
this.api().copyObject({
|
||||
Bucket: this.s3_bucket_,
|
||||
CopySource: this.makePath_(oldPath),
|
||||
Key: newPath,
|
||||
}),(err, response) => {
|
||||
},(err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
@ -342,10 +340,10 @@ class FileApiDriverAmazonS3 {
|
||||
async clearRoot() {
|
||||
const listRecursive = async (cursor) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.api().send(new ListObjectsV2Command({
|
||||
return this.api().listObjectsV2({
|
||||
Bucket: this.s3_bucket_,
|
||||
ContinuationToken: cursor,
|
||||
}), (err, response) => {
|
||||
}, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response);
|
||||
});
|
||||
@ -353,9 +351,6 @@ class FileApiDriverAmazonS3 {
|
||||
};
|
||||
|
||||
let response = await listRecursive();
|
||||
// In aws-sdk-js-v3 if there are no contents it no longer returns
|
||||
// an empty array. This creates an Empty array to pass onward.
|
||||
if (response.Contents === undefined) response.Contents = [];
|
||||
let keys = response.Contents.map((content) => content.Key);
|
||||
|
||||
while (response.IsTruncated) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
class FsDriverDummy {
|
||||
constructor() {}
|
||||
appendFileSync() {}
|
||||
writeBinaryFile() {}
|
||||
readFile() {}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,16 @@ export default class FsDriverNode extends FsDriverBase {
|
||||
}
|
||||
}
|
||||
|
||||
public async writeBinaryFile(path: string, content: any) {
|
||||
try {
|
||||
// let buffer = new Buffer(content);
|
||||
const buffer = Buffer.from(content);
|
||||
return await fs.writeFile(path, buffer);
|
||||
} catch (error) {
|
||||
throw this.fsErrorToJsError_(error, path);
|
||||
}
|
||||
}
|
||||
|
||||
public async writeFile(path: string, string: string, encoding: string = 'base64') {
|
||||
try {
|
||||
if (encoding === 'buffer') {
|
||||
|
@ -245,6 +245,10 @@ export default class Resource extends BaseItem {
|
||||
return this.fsDriver().readFile(this.fullPath(resource), 'Buffer');
|
||||
}
|
||||
|
||||
static setContent(resource: ResourceEntity, content: any) {
|
||||
return this.fsDriver().writeBinaryFile(this.fullPath(resource), content);
|
||||
}
|
||||
|
||||
static isResourceUrl(url: string) {
|
||||
return url && url.length === 34 && url[0] === ':' && url[1] === '/';
|
||||
}
|
||||
|
1150
packages/lib/package-lock.json
generated
1150
packages/lib/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/lib",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"description": "Joplin Core library",
|
||||
"author": "Laurent Cozic",
|
||||
"homepage": "",
|
||||
@ -25,14 +25,13 @@
|
||||
"typescript": "^4.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.22.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.23.0",
|
||||
"@joplin/fork-htmlparser2": "^4.1.31",
|
||||
"@joplin/fork-sax": "^1.2.35",
|
||||
"@joplin/renderer": "^2.2.3",
|
||||
"@joplin/turndown": "^4.0.53",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.35",
|
||||
"@joplin/fork-htmlparser2": "^4.1.32",
|
||||
"@joplin/fork-sax": "^1.2.36",
|
||||
"@joplin/renderer": "^2.2.4",
|
||||
"@joplin/turndown": "^4.0.54",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.36",
|
||||
"async-mutex": "^0.1.3",
|
||||
"aws-sdk": "^2.588.0",
|
||||
"base-64": "^0.1.0",
|
||||
"base64-stream": "^1.0.0",
|
||||
"builtin-modules": "^3.1.0",
|
||||
|
@ -58,7 +58,6 @@ export default class WebviewController extends ViewController {
|
||||
scripts: [],
|
||||
opened: false,
|
||||
buttons: null,
|
||||
fitToContent: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -174,11 +173,4 @@ export default class WebviewController extends ViewController {
|
||||
this.setStoreProp('buttons', buttons);
|
||||
}
|
||||
|
||||
public get fitToContent(): boolean {
|
||||
return this.storeView.fitToContent;
|
||||
}
|
||||
|
||||
public set fitToContent(fitToContent: boolean) {
|
||||
this.setStoreProp('fitToContent', fitToContent);
|
||||
}
|
||||
}
|
||||
|
@ -98,13 +98,4 @@ export default class JoplinViewsDialogs {
|
||||
return this.controller(handle).open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle on whether to fit the dialog size to the content or not.
|
||||
* When set to false, the dialog stretches to fill the application
|
||||
* window.
|
||||
* @default true
|
||||
*/
|
||||
public async setFitToContent(handle: ViewHandle, status: boolean) {
|
||||
return this.controller(handle).fitToContent = status;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ import SyncTargetJoplinCloud from '../SyncTargetJoplinCloud';
|
||||
import KeychainService from '../services/keychain/KeychainService';
|
||||
import { loadKeychainServiceAndSettings } from '../services/SettingUtils';
|
||||
const md5 = require('md5');
|
||||
const { S3Client } = require('@aws-sdk/client-s3');
|
||||
const S3 = require('aws-sdk/clients/s3');
|
||||
const { Dirnames } = require('../services/synchronizer/utils/types');
|
||||
|
||||
// Each suite has its own separate data and temp directory so that multiple
|
||||
@ -569,16 +569,10 @@ async function initFileApi() {
|
||||
const appDir = await api.appDirectory();
|
||||
fileApi = new FileApi(appDir, new FileApiDriverOneDrive(api));
|
||||
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('amazon_s3')) {
|
||||
|
||||
// We make sure for S3 tests run in band because tests
|
||||
// share the same directory which will cause locking errors.
|
||||
|
||||
mustRunInBand();
|
||||
|
||||
const amazonS3CredsPath = `${oldTestDir}/support/amazon-s3-auth.json`;
|
||||
const amazonS3Creds = require(amazonS3CredsPath);
|
||||
if (!amazonS3Creds || !amazonS3Creds.accessKeyId) throw new Error(`AWS auth JSON missing in ${amazonS3CredsPath} format should be: { "accessKeyId": "", "secretAccessKey": "", "bucket": "mybucket"}`);
|
||||
const api = new S3Client({ region: 'us-east-1', accessKeyId: amazonS3Creds.accessKeyId, secretAccessKey: amazonS3Creds.secretAccessKey, s3UseArnRegion: true });
|
||||
const api = new S3({ accessKeyId: amazonS3Creds.accessKeyId, secretAccessKey: amazonS3Creds.secretAccessKey, s3UseArnRegion: true });
|
||||
fileApi = new FileApi('', new FileApiDriverAmazonS3(api, amazonS3Creds.bucket));
|
||||
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('joplinServer')) {
|
||||
mustRunInBand();
|
||||
|
2
packages/plugin-repo-cli/package-lock.json
generated
2
packages/plugin-repo-cli/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/plugin-repo-cli",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/plugin-repo-cli",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"bin": {
|
||||
@ -18,8 +18,8 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@joplin/lib": "^2.2.3",
|
||||
"@joplin/tools": "^2.2.3",
|
||||
"@joplin/lib": "^2.2.4",
|
||||
"@joplin/tools": "^2.2.4",
|
||||
"fs-extra": "^9.0.1",
|
||||
"gh-release-assets": "^2.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
|
2
packages/renderer/package-lock.json
generated
2
packages/renderer/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/renderer",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/renderer",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"description": "The Joplin note renderer, used the mobile and desktop application",
|
||||
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/renderer",
|
||||
"main": "index.js",
|
||||
@ -24,7 +24,7 @@
|
||||
"typescript": "^4.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/fork-htmlparser2": "^4.1.31",
|
||||
"@joplin/fork-htmlparser2": "^4.1.32",
|
||||
"font-awesome-filetypes": "^2.1.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"highlight.js": "^10.2.1",
|
||||
|
2
packages/tools/package-lock.json
generated
2
packages/tools/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/tools",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/tools",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.4",
|
||||
"description": "Various tools for Joplin",
|
||||
"main": "index.js",
|
||||
"author": "Laurent Cozic",
|
||||
@ -18,7 +18,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@joplin/lib": "^2.2.3",
|
||||
"@joplin/lib": "^2.2.4",
|
||||
"execa": "^4.1.0",
|
||||
"fs-extra": "^4.0.3",
|
||||
"gettext-parser": "^1.3.0",
|
||||
|
2
packages/turndown-plugin-gfm/package-lock.json
generated
2
packages/turndown-plugin-gfm/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/turndown-plugin-gfm",
|
||||
"version": "1.0.35",
|
||||
"version": "1.0.36",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -4,7 +4,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"version": "1.0.35",
|
||||
"version": "1.0.36",
|
||||
"author": "Dom Christie",
|
||||
"main": "lib/turndown-plugin-gfm.cjs.js",
|
||||
"devDependencies": {
|
||||
|
2
packages/turndown/package-lock.json
generated
2
packages/turndown/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/turndown",
|
||||
"version": "4.0.53",
|
||||
"version": "4.0.54",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@joplin/turndown",
|
||||
"description": "A library that converts HTML to Markdown",
|
||||
"version": "4.0.53",
|
||||
"version": "4.0.54",
|
||||
"author": "Dom Christie",
|
||||
"main": "lib/turndown.cjs.js",
|
||||
"publishConfig": {
|
||||
|
@ -1,5 +1,11 @@
|
||||
# Joplin Android app changelog
|
||||
|
||||
## [android-v2.2.5](https://github.com/laurent22/joplin/releases/tag/android-v2.2.5) (Pre-release) - 2021-08-11T10:54:38Z
|
||||
|
||||
- Revert "Plugins: Add ability to make dialogs fit the application window (#5219)" as it breaks several plugin webviews.
|
||||
- Revert "Resolves #4810, Resolves #4610: Fix AWS S3 sync error and upgrade framework to v3 (#5212)" due to incompatibility with some AWS providers.
|
||||
- Improved: Upgraded React Native to v0.64 (afb7e1a)
|
||||
|
||||
## [android-v2.2.3](https://github.com/laurent22/joplin/releases/tag/android-v2.2.3) (Pre-release) - 2021-08-09T18:48:29Z
|
||||
|
||||
- Improved: Ensure that timestamps are not changed when sharing or unsharing a note (cafaa9c)
|
||||
|
@ -1,5 +1,9 @@
|
||||
# Joplin terminal app changelog
|
||||
|
||||
## [cli-v2.2.2](https://github.com/laurent22/joplin/releases/tag/cli-v2.2.2) - 2021-08-11T15:34:56Z
|
||||
|
||||
- Fixed: Fixed version command so that it does not require the keychain (15766d1)
|
||||
|
||||
## [cli-v2.2.1](https://github.com/laurent22/joplin/releases/tag/cli-v2.2.1) - 2021-08-10T10:21:09Z
|
||||
|
||||
- Improved: Ensure that timestamps are not changed when sharing or unsharing a note (cafaa9c)
|
||||
|
Loading…
x
Reference in New Issue
Block a user