1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-23 23:33:01 +02:00

Compare commits

...

35 Commits

Author SHA1 Message Date
Hubert
3ab14c4ab0 Merge remote-tracking branch 'origin/issue-7808' into issue-7808
# Conflicts:
#	packages/server/src/views/index/user.mustache
2023-08-18 09:02:58 -03:00
Hubert
74d407de6f Removing the spaces. 2023-08-18 09:01:37 -03:00
Hubert
9740dd9bbe Merge remote-tracking branch 'origin/dev' into issue-7808 2023-08-18 08:49:04 -03:00
Hubert
98b3432105 Removing the spaces. 2023-08-18 08:48:35 -03:00
Hubert
cdba5cfa8c Removing the spaces. 2023-08-18 08:45:30 -03:00
Hubert
0cfe4f1e33 Removing the spaces. 2023-08-18 08:44:59 -03:00
Hubert
56fb48d78b Fixes from review. 2023-08-18 08:40:40 -03:00
Laurent Cozic
87e51aa8e6 Doc: Remove support email 2023-08-18 11:50:44 +01:00
Henry Heino
41fdc0d44d Mobile: Fixes #8687: Hide markdown toolbar completely when low on vertical space (#8688) 2023-08-18 09:45:04 +01:00
renovate[bot]
a754a8d772 Update dependency knex to v2.5.0 (#8686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-18 09:44:48 +01:00
Hubert
41d0363fd0 Android: Fixes #8510: The voice typing box covers the texts in the editor (#8685) 2023-08-18 09:42:03 +01:00
Hubert
2a4c7a334e Server: Fixes #8307: Searching for user should be case insensitive (#8682) 2023-08-18 09:39:57 +01:00
Hubert
df1b0a96f4 Server: Fixes #8308: Sorting users by "total size" leads to a crash (#8680) 2023-08-18 09:36:41 +01:00
Henry Heino
0030681cb4 Mobile: Fixes #8310: Preserve image rotation (and other metadata) when resizing (#8669) 2023-08-18 09:34:31 +01:00
Henry Heino
e7014492c5 Desktop: Fixes #8661: Fix note editor blank after syncing an encrypted note with remote changes (#8666) 2023-08-18 09:31:45 +01:00
Joplin Bot
4804c1c0c3 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-08-18 06:19:25 +00:00
Joplin Bot
270d96ad07 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-08-18 00:35:18 +00:00
Laurent Cozic
5ed3d94faa Server: Ensure that server does not crash when trying to start a task that is already running 2023-08-16 15:03:20 +01:00
renovate[bot]
d0e943630d Update dependency rate-limiter-flexible to v2.4.2 (#8678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-16 13:06:33 +00:00
Henry Heino
406e933407 Chore: Mobile: Remove unused dependency (#8676) 2023-08-16 12:00:14 +01:00
Xavi Ivars
7108a4243d Update Catalan localization (#8675) 2023-08-16 10:41:26 +01:00
github-actions[bot]
135e2e4a21 @xavivars has signed the CLA in laurent22/joplin#8675 2023-08-15 23:52:14 +00:00
Hubert
5ff963704b Merge remote-tracking branch 'origin/dev' into issue-7808 2023-08-15 16:15:19 -03:00
Hubert
bea40d0997 Fixes appointed in the review. 2023-08-15 16:14:10 -03:00
renovate[bot]
c68c0bf501 Update dependency @react-native-community/datetimepicker to v7.4.1 (#8672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-15 19:08:56 +00:00
renovate[bot]
cf3d86698d Update dependency @react-native-community/datetimepicker to v7.4.0 (#8671)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-15 17:35:53 +01:00
Mr-Kanister
3251c4c40e Update de_DE.po (#8668) 2023-08-15 17:00:15 +01:00
Laurent Cozic
bd5e0fd42a Merge branch 'release-2.12' into dev 2023-08-14 18:39:56 +01:00
Laurent Cozic
7d0b7122f0 Revert "Desktop: Fixes #8661: Fix note editor blank after syncing an encrypted note with remote changes (#8665)"
This reverts commit 85eddbfe22.

Due to useForm conflicts with https://github.com/laurent22/joplin/pull/8654
2023-08-14 18:38:31 +01:00
Henry Heino
85eddbfe22 Desktop: Fixes #8661: Fix note editor blank after syncing an encrypted note with remote changes (#8665) 2023-08-14 18:21:41 +01:00
renovate[bot]
5d87b4ca3e Update dependency word-wrap to v1.2.5 (#8651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-11 19:23:30 +00:00
Hubert
3dea9ab6e7 A shortcut to user resent the account confirmation email. 2023-08-11 15:59:53 -03:00
renovate[bot]
89f550ca48 Update dependency sharp to v0.32.4 (#8648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-10 21:41:09 +00:00
Hubert
dd869c43bb Added a condition to only show send account confirmation email when the user didn't confirm the email yet. 2023-08-10 17:00:03 -03:00
Hubert
7f5acdea5e Added the possibility to user send account confirmation email from their profile. 2023-08-10 15:25:24 -03:00
37 changed files with 632 additions and 448 deletions

View File

@@ -260,6 +260,7 @@ packages/app-desktop/gui/NoteEditor/utils/types.js
packages/app-desktop/gui/NoteEditor/utils/useDropHandler.js
packages/app-desktop/gui/NoteEditor/utils/useEffectiveNoteId.js
packages/app-desktop/gui/NoteEditor/utils/useFolder.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.test.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.js
packages/app-desktop/gui/NoteEditor/utils/useMarkupToHtml.js
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
@@ -410,6 +411,7 @@ packages/app-mobile/components/NoteEditor/MarkdownToolbar/Toolbar.js
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarButton.js
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarOverflowRows.js
packages/app-mobile/components/NoteEditor/MarkdownToolbar/types.js
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
packages/app-mobile/components/NoteEditor/NoteEditor.js
packages/app-mobile/components/NoteEditor/SearchPanel.js
packages/app-mobile/components/NoteEditor/SelectionFormatting.js

2
.gitignore vendored
View File

@@ -246,6 +246,7 @@ packages/app-desktop/gui/NoteEditor/utils/types.js
packages/app-desktop/gui/NoteEditor/utils/useDropHandler.js
packages/app-desktop/gui/NoteEditor/utils/useEffectiveNoteId.js
packages/app-desktop/gui/NoteEditor/utils/useFolder.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.test.js
packages/app-desktop/gui/NoteEditor/utils/useFormNote.js
packages/app-desktop/gui/NoteEditor/utils/useMarkupToHtml.js
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
@@ -396,6 +397,7 @@ packages/app-mobile/components/NoteEditor/MarkdownToolbar/Toolbar.js
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarButton.js
packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToolbarOverflowRows.js
packages/app-mobile/components/NoteEditor/MarkdownToolbar/types.js
packages/app-mobile/components/NoteEditor/NoteEditor.test.js
packages/app-mobile/components/NoteEditor/NoteEditor.js
packages/app-mobile/components/NoteEditor/SearchPanel.js
packages/app-mobile/components/NoteEditor/SelectionFormatting.js

BIN
Assets/Aide.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -112,7 +112,7 @@
}).then(async function(result) {
if (!result.ok) {
console.error('Could not create Stripe checkout session', await result.text());
alert('The checkout session could not be created. Please contact support@joplincloud.com for support.');
alert('The checkout session could not be created. Please contact us on the forum for support.');
} else {
return result.json();
}

View File

@@ -57,7 +57,7 @@
"proper-lockfile": "4.1.2",
"read-chunk": "2.1.0",
"server-destroy": "1.0.1",
"sharp": "0.32.3",
"sharp": "0.32.4",
"sprintf-js": "1.1.2",
"sqlite3": "5.1.6",
"string-padding": "1.0.2",
@@ -66,7 +66,7 @@
"terminal-kit": "3.0.0",
"tkwidgets": "0.5.27",
"url-parse": "1.5.10",
"word-wrap": "1.2.4",
"word-wrap": "1.2.5",
"yargs-parser": "21.1.1"
},
"devDependencies": {

View File

@@ -78,6 +78,7 @@ function NoteEditor(props: NoteEditorProps) {
const { formNote, setFormNote, isNewNote, resourceInfos } = useFormNote({
syncStarted: props.syncStarted,
decryptionStarted: props.decryptionStarted,
noteId: effectiveNoteId,
isProvisional: props.isProvisional,
titleInputRef: titleInputRef,
@@ -633,6 +634,7 @@ const mapStateToProps = (state: AppState) => {
isProvisional: state.provisionalNoteIds.includes(noteId),
editorNoteStatuses: state.editorNoteStatuses,
syncStarted: state.syncStarted,
decryptionStarted: state.decryptionWorker?.state !== 'idle',
themeId: state.settings.theme,
richTextBannerDismissed: state.settings.richTextBannerDismissed,
watchedNoteFiles: state.watchedNoteFiles,

View File

@@ -27,6 +27,7 @@ export interface NoteEditorProps {
isProvisional: boolean;
editorNoteStatuses: any;
syncStarted: boolean;
decryptionStarted: boolean;
bodyEditor: string;
notesParentType: string;
selectedNoteTags: any[];

View File

@@ -0,0 +1,73 @@
import Note from '@joplin/lib/models/Note';
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
import { renderHook } from '@testing-library/react-hooks';
import useFormNote, { HookDependencies } from './useFormNote';
describe('useFormNote', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
});
it('should update note when decryption completes', async () => {
const testNote = await Note.save({ title: 'Test Note!' });
const makeFormNoteProps = (syncStarted: boolean, decryptionStarted: boolean): HookDependencies => {
return {
syncStarted,
decryptionStarted,
noteId: testNote.id,
isProvisional: false,
titleInputRef: null,
editorRef: null,
onBeforeLoad: ()=>{},
onAfterLoad: ()=>{},
};
};
const formNote = renderHook(props => useFormNote(props), {
initialProps: makeFormNoteProps(true, false),
});
await formNote.waitFor(() => {
expect(formNote.result.current.formNote).toMatchObject({
encryption_applied: 0,
title: testNote.title,
});
});
await Note.save({
id: testNote.id,
encryption_cipher_text: 'cipher_text',
encryption_applied: 1,
});
// Sync starting should cause a re-render
formNote.rerender(makeFormNoteProps(false, false));
await formNote.waitFor(() => {
expect(formNote.result.current.formNote).toMatchObject({
encryption_applied: 1,
});
});
formNote.rerender(makeFormNoteProps(false, true));
await Note.save({
id: testNote.id,
encryption_applied: 0,
title: 'Test Note!',
});
// Ending decryption should also cause a re-render
formNote.rerender(makeFormNoteProps(false, false));
await formNote.waitFor(() => {
expect(formNote.result.current.formNote).toMatchObject({
encryption_applied: 0,
title: 'Test Note!',
});
});
});
});

View File

@@ -18,8 +18,9 @@ export interface OnLoadEvent {
formNote: FormNote;
}
interface HookDependencies {
export interface HookDependencies {
syncStarted: boolean;
decryptionStarted: boolean;
noteId: string;
isProvisional: boolean;
titleInputRef: any;
@@ -61,15 +62,21 @@ function resourceInfosChanged(a: ResourceInfos, b: ResourceInfos): boolean {
}
export default function useFormNote(dependencies: HookDependencies) {
const { syncStarted, noteId, isProvisional, titleInputRef, editorRef, onBeforeLoad, onAfterLoad } = dependencies;
const {
syncStarted, decryptionStarted, noteId, isProvisional, titleInputRef, editorRef, onBeforeLoad, onAfterLoad,
} = dependencies;
const [formNote, setFormNote] = useState<FormNote>(defaultFormNote());
const [formNoteRefeshScheduled, setFormNoteRefreshScheduled] = useState<boolean>(false);
const [isNewNote, setIsNewNote] = useState(false);
const prevSyncStarted = usePrevious(syncStarted);
const prevDecryptionStarted = usePrevious(decryptionStarted);
const previousNoteId = usePrevious(formNote.id);
const [resourceInfos, setResourceInfos] = useState<ResourceInfos>({});
// Increasing the value of this counter cancels any ongoing note refreshes and starts
// a new refresh.
const [formNoteRefeshScheduled, setFormNoteRefreshScheduled] = useState<number>(0);
async function initNoteState(n: any) {
let originalCss = '';
@@ -107,7 +114,7 @@ export default function useFormNote(dependencies: HookDependencies) {
}
useEffect(() => {
if (!formNoteRefeshScheduled) return () => {};
if (formNoteRefeshScheduled <= 0) return () => {};
reg.logger().info('Sync has finished and note has never been changed - reloading it');
@@ -126,7 +133,7 @@ export default function useFormNote(dependencies: HookDependencies) {
}
await initNoteState(n);
setFormNoteRefreshScheduled(false);
setFormNoteRefreshScheduled(0);
};
void loadNote();
@@ -136,21 +143,32 @@ export default function useFormNote(dependencies: HookDependencies) {
};
}, [formNoteRefeshScheduled, noteId]);
const refreshFormNote = useCallback(() => {
// Increase the counter to cancel any ongoing refresh attempts
// and start a new one.
setFormNoteRefreshScheduled(formNoteRefeshScheduled + 1);
}, [formNoteRefeshScheduled]);
useEffect(() => {
// Check that synchronisation has just finished - and
// if the note has never been changed, we reload it.
// If the note has already been changed, it's a conflict
// that's already been handled by the synchronizer.
const decryptionJustEnded = prevDecryptionStarted && !decryptionStarted;
const syncJustEnded = prevSyncStarted && !syncStarted;
if (!prevSyncStarted) return;
if (syncStarted) return;
if (!decryptionJustEnded && !syncJustEnded) return;
if (formNote.hasChanged) return;
// Refresh the form note.
// This is kept separate from the above logic so that when prevSyncStarted is changed
// from true to false, it doesn't cancel the note from loading.
setFormNoteRefreshScheduled(true);
}, [prevSyncStarted, syncStarted, formNote.hasChanged]);
refreshFormNote();
}, [
prevSyncStarted, syncStarted,
prevDecryptionStarted, decryptionStarted,
formNote.hasChanged, refreshFormNote,
]);
useEffect(() => {
if (!noteId) {

View File

@@ -1,19 +1,14 @@
/* eslint-disable jest/require-top-level-describe */
const { default: Logger, TargetType } = require('@joplin/utils/Logger');
const initLib = require('@joplin/lib/initLib').default;
// TODO: Some libraries required by test-utils.js seem to fail to import with the
// jsdom environment.
//
// Thus, require('@joplin/lib/testing/test-utils.js') fails and some setup must be
// copied.
const logger = new Logger();
logger.addTarget(TargetType.Console);
logger.setLevel(Logger.LEVEL_WARN);
Logger.initializeGlobalLogger(logger);
initLib(logger);
const { shimInit } = require('@joplin/lib/shim-init-node');
const sqlite3 = require('sqlite3');
const SyncTargetNone = require('@joplin/lib/SyncTargetNone').default;
// Mock the S3 sync target -- the @aws-s3 libraries depend on an old version
// of uuid that doesn't work with jest without additional configuration.
jest.doMock('@joplin/lib/SyncTargetAmazonS3', () => {
return SyncTargetNone;
});
// @electron/remote requires electron to be running. Mock it.
jest.mock('@electron/remote', () => {
@@ -25,3 +20,18 @@ jest.mock('@electron/remote', () => {
},
};
});
// Import after mocking problematic libraries
const { afterEachCleanUp, afterAllCleanUp } = require('@joplin/lib/testing/test-utils.js');
shimInit({ nodeSqlite: sqlite3 });
afterEach(async () => {
await afterEachCleanUp();
});
afterAll(async () => {
await afterAllCleanUp();
});

View File

@@ -1,6 +1,6 @@
const React = require('react');
import { ReactElement, useCallback, useState } from 'react';
import { ReactElement, useCallback, useMemo, useState } from 'react';
import { LayoutChangeEvent, ScrollView, View, ViewStyle } from 'react-native';
import ToggleOverflowButton from './ToggleOverflowButton';
import ToolbarButton, { buttonSize } from './ToolbarButton';
@@ -18,19 +18,22 @@ const Toolbar = (props: ToolbarProps) => {
const [overflowButtonsVisible, setOverflowPopupVisible] = useState(false);
const [maxButtonsEachSide, setMaxButtonsEachSide] = useState(0);
const allButtonSpecs = props.buttons.reduce((accumulator: ButtonSpec[], current: ButtonGroup) => {
const newItems: ButtonSpec[] = [];
for (const item of current.items) {
if (item.visible ?? true) {
newItems.push(item);
const allButtonSpecs = useMemo(() => {
const buttons = props.buttons.reduce((accumulator: ButtonSpec[], current: ButtonGroup) => {
const newItems: ButtonSpec[] = [];
for (const item of current.items) {
if (item.visible ?? true) {
newItems.push(item);
}
}
}
return accumulator.concat(...newItems);
}, []);
return accumulator.concat(...newItems);
}, []);
// Sort from highest priority to lowest
allButtonSpecs.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
// Sort from highest priority to lowest
buttons.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
return buttons;
}, [props.buttons]);
const allButtonComponents: ReactElement[] = [];
let key = 0;
@@ -67,7 +70,9 @@ const Toolbar = (props: ToolbarProps) => {
);
const mainButtons: ReactElement[] = [];
if (maxButtonsEachSide < allButtonComponents.length) {
if (maxButtonsEachSide >= allButtonComponents.length) {
mainButtons.push(...allButtonComponents);
} else if (maxButtonsEachSide > 0) {
// We want the menu to look something like this:
// B I (…) 🔍 ⌨
// where (…) shows/hides overflow.
@@ -77,7 +82,7 @@ const Toolbar = (props: ToolbarProps) => {
mainButtons.push(toggleOverflowButton);
mainButtons.push(...allButtonComponents.slice(-maxButtonsEachSide));
} else {
mainButtons.push(...allButtonComponents);
mainButtons.push(toggleOverflowButton);
}
const styles = props.styleSheet.styles;

View File

@@ -0,0 +1,72 @@
import * as React from 'react';
import { describe, it, expect, beforeEach } from '@jest/globals';
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react-native';
import '@testing-library/jest-native';
import NoteEditor from './NoteEditor';
import Setting from '@joplin/lib/models/Setting';
import { _ } from '@joplin/lib/locale';
import { MenuProvider } from 'react-native-popup-menu';
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
describe('NoteEditor', () => {
beforeEach(async () => {
// Required to use ExtendedWebView
await setupDatabaseAndSynchronizer(0);
await switchClient(0);
});
it('should hide the markdown toolbar when the window is small', async () => {
const wrappedNoteEditor = render(
<MenuProvider>
<NoteEditor
themeId={Setting.THEME_ARITIM_DARK}
initialText='Testing...'
style={{}}
toolbarEnabled={true}
readOnly={false}
onChange={()=>{}}
onSelectionChange={()=>{}}
onUndoRedoDepthChange={()=>{}}
onAttach={()=>{}}
/>
</MenuProvider>
);
// Maps from screen height to whether the markdown toolbar should be visible.
const testCases: [number, boolean][] = [
[10, false],
[1000, true],
[100, false],
[80, false],
[600, true],
];
const noteEditorRoot = await wrappedNoteEditor.findByTestId('note-editor-root');
const setRootHeight = (height: number) => {
act(() => {
// See https://stackoverflow.com/a/61774123
fireEvent(noteEditorRoot, 'layout', {
nativeEvent: {
layout: { height },
},
});
});
};
for (const [height, visible] of testCases) {
setRootHeight(height);
await waitFor(async () => {
const showMoreButton = await screen.queryByLabelText(_('Show more actions'));
if (visible) {
expect(showMoreButton).not.toBeNull();
} else {
expect(showMoreButton).toBeNull();
}
});
}
});
});

View File

@@ -8,7 +8,7 @@ import ExtendedWebView from '../ExtendedWebView';
const React = require('react');
import { forwardRef, RefObject, useImperativeHandle } from 'react';
import { useEffect, useMemo, useState, useCallback, useRef } from 'react';
import { View, ViewStyle } from 'react-native';
import { LayoutChangeEvent, View, ViewStyle } from 'react-native';
const { editorFont } = require('../global-style');
import SelectionFormatting from './SelectionFormatting';
@@ -368,6 +368,19 @@ function NoteEditor(props: Props, ref: any) {
console.error('NoteEditor: webview error');
}, []);
const [hasSpaceForToolbar, setHasSpaceForToolbar] = useState(true);
const toolbarEnabled = props.toolbarEnabled && hasSpaceForToolbar;
const onContainerLayout = useCallback((event: LayoutChangeEvent) => {
const containerHeight = event.nativeEvent.layout.height;
if (containerHeight < 140) {
setHasSpaceForToolbar(false);
} else {
setHasSpaceForToolbar(true);
}
}, []);
const toolbar = <MarkdownToolbar
style={{
// Don't show the markdown toolbar if there isn't enough space
@@ -385,10 +398,14 @@ function NoteEditor(props: Props, ref: any) {
// - `scrollEnabled` prevents iOS from scrolling the document (has no effect on Android)
// when an editable region (e.g. a the full-screen NoteEditor) is focused.
return (
<View style={{
...props.style,
flexDirection: 'column',
}}>
<View
testID='note-editor-root'
onLayout={onContainerLayout}
style={{
...props.style,
flexDirection: 'column',
}}
>
<EditLinkDialog
visible={linkDialogVisible}
themeId={props.themeId}
@@ -419,7 +436,7 @@ function NoteEditor(props: Props, ref: any) {
searchState={searchState}
/>
{props.toolbarEnabled ? toolbar : null}
{toolbarEnabled ? toolbar : null}
</View>
);
}

View File

@@ -36,7 +36,7 @@ const { BaseScreenComponent } = require('../base-screen.js');
const { themeStyle, editorFont } = require('../global-style.js');
const { dialogs } = require('../../utils/dialogs.js');
const DialogBox = require('react-native-dialogbox').default;
const ImageResizer = require('react-native-image-resizer').default;
import ImageResizer from '@bam.tech/react-native-image-resizer';
import shared from '@joplin/lib/components/shared/note-screen-shared';
import { ImagePickerResponse, launchImageLibrary } from 'react-native-image-picker';
import SelectDateTimeDialog from '../SelectDateTimeDialog';
@@ -586,7 +586,16 @@ class NoteScreenComponent extends BaseScreenComponent {
const format = mimeType === 'image/png' ? 'PNG' : 'JPEG';
reg.logger().info(`Resizing image ${localFilePath}`);
const resizedImage = await ImageResizer.createResizedImage(localFilePath, dimensions.width, dimensions.height, format, 85); // , 0, targetPath);
const resizedImage = await ImageResizer.createResizedImage(
localFilePath,
dimensions.width,
dimensions.height,
format,
85, // quality
undefined, // rotation
undefined, // outputPath
true // keep metadata
);
const resizedImagePath = resizedImage.uri;
reg.logger().info('Resized image ', resizedImagePath);

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { useState, useEffect, useCallback } from 'react';
import { Banner, ActivityIndicator, Modal } from 'react-native-paper';
import { Banner, ActivityIndicator } 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';
@@ -107,18 +107,16 @@ export default (props: Props) => {
};
return (
<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>
<Banner
visible={true}
icon={renderIcon()}
actions={[
{
label: _('Done'),
onPress: onDismiss,
},
]}>
{`${_('Voice typing...')}\n${renderContent()}`}
</Banner>
);
};

View File

@@ -353,7 +353,7 @@ PODS:
- React-Core
- react-native-image-picker (5.6.0):
- React-Core
- react-native-image-resizer (1.4.5):
- react-native-image-resizer (3.0.5):
- React-Core
- react-native-netinfo (9.4.1):
- React-Core
@@ -584,7 +584,7 @@ DEPENDENCIES:
- "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-image-resizer (from `../node_modules/@bam.tech/react-native-image-resizer`)"
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-rsa-native (from `../node_modules/react-native-rsa-native`)
- "react-native-saf-x (from `../node_modules/@joplin/react-native-saf-x`)"
@@ -703,7 +703,7 @@ EXTERNAL SOURCES:
react-native-image-picker:
:path: "../node_modules/react-native-image-picker"
react-native-image-resizer:
:path: "../node_modules/react-native-image-resizer"
:path: "../node_modules/@bam.tech/react-native-image-resizer"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-rsa-native:
@@ -824,7 +824,7 @@ SPEC CHECKSUMS:
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
react-native-image-picker: db60857e03d63721f19b6f4027de20429ddd9cba
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
react-native-image-resizer: 00ceb0e05586c7aadf061eea676957a6c2ec60fa
react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
react-native-saf-x: 129cd2ddf120a1f6164c724b2846d172666b33de

View File

@@ -33,6 +33,21 @@ document.createRange = () => {
shimInit({ nodeSqlite: sqlite3 });
// This library has the following error when running within Jest:
// Invariant Violation: `new NativeEventEmitter()` requires a non-null argument.
jest.mock('react-native-device-info', () => {
return {
hasNotch: () => false,
};
});
// react-native-webview expects native iOS/Android code so needs to be mocked.
jest.mock('react-native-webview', () => {
const { View } = require('react-native');
return {
WebView: View,
};
});
// react-native-fs's CachesDirectoryPath export doesn't work in a testing environment.
// Use a temporary folder instead.

View File

@@ -18,13 +18,14 @@
"postinstall": "jetify && yarn run build"
},
"dependencies": {
"@bam.tech/react-native-image-resizer": "3.0.5",
"@joplin/lib": "~2.12",
"@joplin/react-native-alarm-notification": "~2.12",
"@joplin/react-native-saf-x": "~2.12",
"@joplin/renderer": "~2.12",
"@joplin/utils": "~2.12",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/datetimepicker": "7.3.0",
"@react-native-community/datetimepicker": "7.4.1",
"@react-native-community/geolocation": "3.0.6",
"@react-native-community/netinfo": "9.4.1",
"@react-native-community/push-notification-ios": "1.11.0",
@@ -43,7 +44,6 @@
"punycode": "2.3.0",
"react": "18.2.0",
"react-native": "0.71.10",
"react-native-action-button": "2.8.5",
"react-native-camera": "4.2.1",
"react-native-device-info": "10.7.0",
"react-native-dialogbox": "0.6.10",
@@ -57,7 +57,6 @@
"react-native-gesture-handler": "2.12.0",
"react-native-get-random-values": "1.9.0",
"react-native-image-picker": "5.6.0",
"react-native-image-resizer": "1.4.5",
"react-native-localize": "3.0.2",
"react-native-modal-datetime-picker": "15.0.1",
"react-native-paper": "5.9.1",

View File

@@ -25,7 +25,7 @@
"@types/uuid": "9.0.2",
"clean-html": "1.5.0",
"jest": "29.5.0",
"sharp": "0.32.3",
"sharp": "0.32.4",
"typescript": "5.1.3"
},
"dependencies": {
@@ -91,7 +91,7 @@
"uglifycss": "0.0.29",
"url-parse": "1.5.10",
"uuid": "9.0.0",
"word-wrap": "1.2.4",
"word-wrap": "1.2.5",
"xml2js": "0.4.23"
},
"gitHead": "eb4b0e64eab40a51b0895d3a40a9d8c3cb7b1b14"

View File

@@ -34,7 +34,6 @@ const { FileApiDriverLocal } = require('../file-api-driver-local');
const { FileApiDriverWebDav } = require('../file-api-driver-webdav.js');
const { FileApiDriverDropbox } = require('../file-api-driver-dropbox.js');
const { FileApiDriverOneDrive } = require('../file-api-driver-onedrive.js');
const { FileApiDriverAmazonS3 } = require('../file-api-driver-amazon-s3.js');
import SyncTargetRegistry from '../SyncTargetRegistry';
const SyncTargetMemory = require('../SyncTargetMemory.js');
const SyncTargetFilesystem = require('../SyncTargetFilesystem.js');
@@ -60,7 +59,6 @@ import Synchronizer from '../Synchronizer';
import SyncTargetNone from '../SyncTargetNone';
import { setRSA } from '../services/e2ee/ppk';
const md5 = require('md5');
const { S3Client } = require('@aws-sdk/client-s3');
const { Dirnames } = require('../services/synchronizer/utils/types');
import RSA from '../services/e2ee/RSA.node';
import { State as ShareState } from '../services/share/reducer';
@@ -627,6 +625,13 @@ async function initFileApi() {
const appDir = await api.appDirectory();
fileApi = new FileApi(appDir, new FileApiDriverOneDrive(api));
} else if (syncTargetId_ === SyncTargetRegistry.nameToId('amazon_s3')) {
// (Most of?) the @aws-sdk libraries depend on an old version of uuid
// that doesn't work with jest (without converting ES6 exports to CommonJS).
//
// Require it dynamically so that this doesn't break test environments that
// aren't configured to do this conversion.
const { FileApiDriverAmazonS3 } = require('../file-api-driver-amazon-s3.js');
const { S3Client } = require('@aws-sdk/client-s3');
// We make sure for S3 tests run in band because tests
// share the same directory which will cause locking errors.

View File

@@ -37,7 +37,7 @@
"fs-extra": "11.1.1",
"html-entities": "1.4.0",
"jquery": "3.7.0",
"knex": "2.4.2",
"knex": "2.5.0",
"koa": "2.14.2",
"markdown-it": "13.0.1",
"mustache": "4.2.0",
@@ -49,7 +49,7 @@
"pretty-bytes": "5.6.0",
"prettycron": "0.10.0",
"query-string": "7.1.3",
"rate-limiter-flexible": "2.4.1",
"rate-limiter-flexible": "2.4.2",
"raw-body": "2.5.2",
"sqlite3": "5.1.6",
"stripe": "8.222.0",

View File

@@ -1,43 +0,0 @@
// function stripeConfig() {
// if (!joplin || !joplin.stripeConfig) throw new Error('Stripe config is not set');
// return joplin.stripeConfig;
// }
// function newStripe() {
// return Stripe(stripeConfig().publishableKey);
// }
// async function createStripeCheckoutSession(priceId) {
// const urlQuery = new URLSearchParams(location.search);
// const coupon = urlQuery.get('coupon') || '';
// console.info('Creating Stripe session for price:', priceId, 'Coupon:', coupon);
// const result = await fetch(`${stripeConfig().webhookBaseUrl}/stripe/createCheckoutSession`, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({
// priceId: priceId,
// coupon: coupon,
// }),
// });
// if (!result.ok) {
// console.error('Could not create Stripe checkout session', await result.text());
// alert('The checkout session could not be created. Please contact support@joplincloud.com for support.');
// } else {
// return result.json();
// }
// }
// async function startStripeCheckout(priceId) {
// const data = await createStripeCheckoutSession(stripeId);
// const result = await stripe.redirectToCheckout({
// sessionId: data.sessionId,
// });
// console.info('Redirected to checkout', result);
// }

View File

@@ -63,7 +63,7 @@ async function handleConfirmEmailNotification(ctx: AppContext): Promise<Notifica
if (!ctx.joplin.owner.email_confirmed) {
return {
id: 'confirmEmail',
messageHtml: renderMarkdown('An email has been sent to you containing an activation link to complete your registration.\n\nMake sure you click it to secure your account and keep access to it.'),
messageHtml: renderMarkdown(`An email has been sent to you containing an activation link to complete your registration. If you did not receive it, you may send it again from [your profile page](${profileUrl()}).\n\nMake sure you click it to secure your account and keep access to it.`),
levelClassName: levelClassName(NotificationLevel.Important),
closeUrl: '',
};

View File

@@ -1,4 +1,5 @@
import { TaskId, TaskState } from '../services/database/types';
import { ErrorBadRequest, ErrorCode } from '../utils/errors';
import BaseModel from './BaseModel';
export default class TaskStateModel extends BaseModel<TaskState> {
@@ -32,13 +33,13 @@ export default class TaskStateModel extends BaseModel<TaskState> {
public async start(taskId: TaskId) {
const state = await this.loadByTaskId(taskId);
if (state.running) throw new Error(`Task is already running: ${taskId}`);
if (state.running) throw new ErrorBadRequest(`Task is already running: ${taskId}`, { code: ErrorCode.TaskAlreadyRunning });
await this.save({ id: state.id, running: 1 });
}
public async stop(taskId: TaskId) {
const state = await this.loadByTaskId(taskId);
if (!state.running) throw new Error(`Task is not running: ${taskId}`);
if (!state.running) throw new ErrorBadRequest(`Task is not running: ${taskId}`, { code: ErrorCode.TaskAlreadyRunning });
await this.save({ id: state.id, running: 0 });
}

View File

@@ -100,7 +100,7 @@ router.get('admin/users', async (_path: SubPath, ctx: AppContext) => {
await userModel.checkIfAllowed(ctx.joplin.owner, AclAction.List);
const showDisabled = ctx.query.show_disabled === '1';
const searchQuery = ctx.query.query || '';
const searchQuery = (ctx.query.query && ctx.query.query.toString().toLowerCase()) || '';
const pagination = makeTablePagination(ctx.query, 'full_name', PaginationOrderDir.ASC);
pagination.limit = 1000;
@@ -112,7 +112,9 @@ router.get('admin/users', async (_path: SubPath, ctx: AppContext) => {
if (searchQuery) {
void query.where(qb => {
void qb.whereRaw('full_name like ?', [`%${searchQuery}%`]).orWhereRaw('email like ?', [`%${searchQuery}%`]);
void qb
.whereRaw('lower(full_name) like ?', [`%${searchQuery}%`])
.orWhereRaw('lower(email) like ?', [`%${searchQuery}%`]);
});
}
@@ -135,7 +137,7 @@ router.get('admin/users', async (_path: SubPath, ctx: AppContext) => {
label: _('Email'),
},
{
name: 'account',
name: 'account_type',
label: _('Account'),
},
{
@@ -143,15 +145,15 @@ router.get('admin/users', async (_path: SubPath, ctx: AppContext) => {
label: _('Max Item Size'),
},
{
name: 'total_size',
name: 'total_item_size',
label: _('Total Size'),
},
{
name: 'max_total_size',
name: 'max_total_item_size',
label: _('Max Total Size'),
},
{
name: 'can_share',
name: 'can_share_folder',
label: _('Can Share'),
},
],

View File

@@ -90,6 +90,7 @@ router.get('users/:id', async (path: SubPath, ctx: AppContext, formUser: User =
view.content.error = error;
view.content.postUrl = postUrl;
view.content.csrfTag = await createCsrfTag(ctx);
view.content.showSendAccountConfirmationEmailButton = !user.email_confirmed;
if (subscription) {
const lastPaymentAttempt = models.subscription().lastPaymentAttempt(subscription);
@@ -213,6 +214,7 @@ interface FormFields {
update_subscription_basic_button: string;
update_subscription_pro_button: string;
stop_impersonate_button: string;
send_account_confirmation_email: string;
}
router.post('users', async (path: SubPath, ctx: AppContext) => {
@@ -246,6 +248,8 @@ router.post('users', async (path: SubPath, ctx: AppContext) => {
// that user, except the current one (otherwise they would be
// logged out).
if (userToSave.password) await models.session().deleteByUserId(userToSave.id, contextSessionId(ctx));
} else if (fields.send_account_confirmation_email) {
await models.user().sendAccountConfirmationEmail(user);
} else if (fields.stop_impersonate_button) {
await stopImpersonating(ctx);
return redirect(ctx, config().baseUrl);

View File

@@ -1,5 +1,6 @@
import config from '../config';
import { Models } from '../models/factory';
import { ErrorCode } from '../utils/errors';
import { afterAllTests, beforeAllDb, beforeEachDb, expectThrow, models } from '../utils/testing/testUtils';
import { Env } from '../utils/types';
import { TaskId } from './database/types';
@@ -14,6 +15,23 @@ const newService = () => {
});
};
const createDemoTasks = (): Task[] => {
return [
{
id: TaskId.DeleteExpiredTokens,
description: '',
run: (_models: Models) => {},
schedule: '',
},
{
id: TaskId.CompressOldChanges,
description: '',
run: (_models: Models) => {},
schedule: '',
},
];
};
describe('TaskService', () => {
beforeAll(async () => {
@@ -31,98 +49,66 @@ describe('TaskService', () => {
test('should register a task', async () => {
const service = newService();
const task: Task = {
id: TaskId.DeleteExpiredTokens,
description: '',
run: (_models: Models) => {},
schedule: '',
};
await service.registerTask(task);
const tasks = createDemoTasks();
await service.registerTasks(tasks);
expect(service.tasks[TaskId.DeleteExpiredTokens]).toBeTruthy();
await expectThrow(async () => service.registerTask(task));
expect(service.tasks[TaskId.CompressOldChanges]).toBeTruthy();
await expectThrow(async () => service.registerTask(tasks[0]));
});
// test('should run a task', async function() {
// const service = newService();
// let taskStarted = false;
// let waitToFinish = true;
// let finishTask = false;
// let taskHasRan = false;
// const taskId = TaskId.DeleteExpiredTokens;
// const task: Task = {
// id: taskId,
// description: '',
// run: async (_models: Models) => {
// taskStarted = true;
// const iid = setInterval(() => {
// if (waitToFinish) return;
// if (finishTask) {
// clearInterval(iid);
// taskHasRan = true;
// }
// }, 1);
// },
// schedule: '',
// };
// await service.registerTask(task);
// expect((await service.taskState(taskId)).running).toBe(0);
// const startTime = new Date();
// void service.runTask(taskId, RunType.Manual);
// while (!taskStarted) {
// await msleep(1);
// }
// expect((await service.taskState(taskId)).running).toBe(1);
// waitToFinish = false;
// while (!taskHasRan) {
// await msleep(1);
// finishTask = true;
// }
// expect((await service.taskState(taskId)).running).toBe(0);
// const events = await service.taskLastEvents(taskId);
// expect(events.taskStarted.created_time).toBeGreaterThanOrEqual(startTime.getTime());
// expect(events.taskCompleted.created_time).toBeGreaterThan(startTime.getTime());
// });
test('should not run if task is disabled', async () => {
const service = newService();
let taskHasRan = false;
const taskId = TaskId.DeleteExpiredTokens;
const task: Task = {
id: taskId,
description: '',
run: async (_models: Models) => {
taskHasRan = true;
},
schedule: '',
};
await service.registerTask(task);
const tasks = createDemoTasks();
tasks[0].run = async (_models: Models) => {
taskHasRan = true;
},
await service.registerTasks(tasks);
const taskId = tasks[0].id;
await service.runTask(taskId, RunType.Manual);
expect(taskHasRan).toBe(true);
taskHasRan = false;
await models().taskState().disable(task.id);
await models().taskState().disable(taskId);
await service.runTask(taskId, RunType.Manual);
expect(taskHasRan).toBe(false);
});
test('should not run if task is already running', async () => {
const service = newService();
const tasks = createDemoTasks();
await service.registerTasks(tasks);
const task = tasks[0];
const state = await models().taskState().loadByTaskId(task.id);
await models().taskState().save({ id: state.id, running: 1 });
await expectThrow(async () => service.runTask(task.id, RunType.Manual), ErrorCode.TaskAlreadyRunning);
});
test('should reset interrupted tasks', async () => {
const service = newService();
const tasks = createDemoTasks();
await service.registerTasks(tasks);
const task = tasks[0];
const state = await models().taskState().loadByTaskId(task.id);
await models().taskState().save({ id: state.id, running: 1 });
const stateBefore = await models().taskState().loadByTaskId(task.id);
await service.resetInterruptedTasks();
const stateAfter = await models().taskState().loadByTaskId(task.id);
expect(stateBefore.running).toBe(1);
expect(stateAfter.running).toBe(0);
});
});

View File

@@ -5,7 +5,7 @@ import BaseService from './BaseService';
import { Event, EventType, TaskId, TaskState } from './database/types';
import { Services } from './types';
import { _ } from '@joplin/lib/locale';
import { ErrorNotFound } from '../utils/errors';
import { ErrorCode, ErrorNotFound } from '../utils/errors';
import { durationToMilliseconds } from '../utils/time';
const cron = require('node-cron');
@@ -104,6 +104,16 @@ export default class TaskService extends BaseService {
};
}
public async resetInterruptedTasks() {
const taskStates = await this.models.taskState().all();
for (const taskState of taskStates) {
if (taskState.running) {
logger.warn(`Found a task that was in running state: ${this.taskDisplayString(taskState.task_id)} - resetting it.`);
await this.models.taskState().stop(taskState.task_id);
}
}
}
private taskById(id: TaskId): Task {
if (!this.tasks_[id]) throw new Error(`No such task: ${id}`);
return this.tasks_[id];
@@ -159,13 +169,28 @@ export default class TaskService extends BaseService {
interval = null;
}
const runTaskWithErrorChecking = async (taskId: TaskId) => {
try {
await this.runTask(taskId, RunType.Scheduled);
} catch (error) {
if (error.code === ErrorCode.TaskAlreadyRunning) {
// This is not critical but we should log a warning
// because it may mean that the interval is too tight,
// or the task is taking too long.
logger.warn(`Tried to start ${this.taskDisplayString(taskId)} but it was already running`);
} else {
logger.error(`Failed running task ${this.taskDisplayString(taskId)}`, error);
}
}
};
if (interval !== null) {
setInterval(async () => {
await this.runTask(Number(taskId), RunType.Scheduled);
await runTaskWithErrorChecking(Number(taskId));
}, interval);
} else {
cron.schedule(task.schedule, async () => {
await this.runTask(Number(taskId), RunType.Scheduled);
await runTaskWithErrorChecking(Number(taskId));
});
}
}

View File

@@ -6,6 +6,7 @@ export enum ErrorCode {
NoSub = 'no_sub',
NoStripeSub = 'no_stripe_sub',
InvalidOrigin = 'invalidOrigin',
TaskAlreadyRunning = 'taskAlreadyRunning',
}
export interface ErrorOptions {

View File

@@ -104,5 +104,7 @@ export default async function(env: Env, models: Models, config: Config, services
await taskService.registerTasks(tasks);
await taskService.resetInterruptedTasks();
return taskService;
}

View File

@@ -27,7 +27,7 @@
</div>
<p id="password_strength" class="help"></p>
</div>
<div class="field">
<label class="label">Repeat password</label>
<div class="control">
@@ -37,6 +37,9 @@
<div class="control block">
<input type="submit" name="post_button" class="button is-primary" value="{{buttonTitle}}" />
{{#showSendAccountConfirmationEmailButton}}
<input type="submit" name="send_account_confirmation_email" class="button is-link" value="Send account confirmation email" />
{{/showSendAccountConfirmationEmailButton}}
</div>
</div>
@@ -50,7 +53,7 @@
<p class="help">Click for more info about the Pro plan and to upgrade your account.</p>
</div>
{{/showUpdateSubscriptionPro}}
<div class="control block">
<p><a class="button is-link" target="_blank" href="{{stripePortalUrl}}">Manage subscription</a></p>
<p class="help">Click to update your payment details, switch to a different billing cycle or plan, or to cancel your subscription.</p>

View File

@@ -48,7 +48,7 @@ msgstr "(%s)"
#: packages/lib/services/plugins/api/JoplinViewsDialogs.ts:73
msgid "(In plugin: %s)"
msgstr ""
msgstr "(A l'extensió: %s)"
#: packages/lib/SyncTargetNone.ts:16
msgid "(None)"
@@ -96,12 +96,12 @@ msgstr "%d dies"
#: packages/lib/utils/joplinCloud.ts:136 packages/lib/utils/joplinCloud.ts:137
#: packages/lib/utils/joplinCloud.ts:138
msgid "%d GB"
msgstr ""
msgstr "%d GB"
#: packages/lib/utils/joplinCloud.ts:133 packages/lib/utils/joplinCloud.ts:134
#: packages/lib/utils/joplinCloud.ts:135
msgid "%d GB storage space"
msgstr ""
msgstr "%d GB d'espai d'emmagatzematge"
#: packages/lib/models/Setting.ts:1367
msgid "%d hour"
@@ -114,13 +114,12 @@ msgstr "%d hores"
#: packages/lib/utils/joplinCloud.ts:124 packages/lib/utils/joplinCloud.ts:125
#: packages/lib/utils/joplinCloud.ts:126
msgid "%d MB"
msgstr ""
msgstr "%d MB"
#: packages/lib/utils/joplinCloud.ts:121 packages/lib/utils/joplinCloud.ts:122
#: packages/lib/utils/joplinCloud.ts:123
#, fuzzy
msgid "%d MB per note or attachment"
msgstr "Adjunts de la nota"
msgstr "%d MB per nota o adjunt"
#: packages/lib/models/Setting.ts:1364 packages/lib/models/Setting.ts:1365
#: packages/lib/models/Setting.ts:1366
@@ -133,9 +132,8 @@ msgstr "%d notes coincideixen amb aquest patró. Voleu suprimir-les?"
#: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:257
#: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:267
#, fuzzy
msgid "%s"
msgstr "(%s)"
msgstr "%s"
#: packages/app-desktop/gui/MainScreen/commands/duplicateNote.ts:18
msgid "%s - Copy"
@@ -263,15 +261,15 @@ msgstr "Accepta"
#: packages/lib/WebDavApi.js:451
msgid "Access denied: Please check your username and password"
msgstr ""
msgstr "S'ha denegat l'accés: comproveu el nom d'usuari i la contrasenya"
#: packages/lib/WebDavApi.js:449
msgid "Access denied: Please re-enter your password and/or username"
msgstr ""
msgstr "S'ha denegat l'accés: torneu a introduir el nom d'usuari i/o la contrasenya"
#: packages/server/src/routes/admin/users.ts:138
msgid "Account"
msgstr ""
msgstr "Compte"
#: packages/app-desktop/gui/ResourceScreen.tsx:96
msgid "Action"
@@ -296,9 +294,8 @@ msgid "Add body"
msgstr "Afegeix contingut"
#: packages/app-mobile/components/ActionButton.tsx:59
#, fuzzy
msgid "Add new"
msgstr "Afegeix títol"
msgstr "Afegeix-ne un"
#: packages/app-desktop/gui/MainScreen/commands/setTags.ts:38
msgid "Add or remove tags:"
@@ -336,7 +333,7 @@ msgstr "Opcions avançades"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:99
msgid ""
"All data, including notes, notebooks and tags will be permanently deleted."
msgstr ""
msgstr "Totes les dades, incloent notes, blocs de notes i etiquetes se suprimiran de manera permanent."
#: packages/app-desktop/gui/Sidebar/Sidebar.tsx:497
#: packages/app-mobile/components/screens/Notes.tsx:178
@@ -417,9 +414,8 @@ msgid "Aritim Dark"
msgstr "Aritim fosc"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:220
#, fuzzy
msgid "Attach"
msgstr "Adjunta..."
msgstr "Adjunta"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:59
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:615
@@ -540,13 +536,12 @@ msgid "Bulleted List"
msgstr "Llista de pics"
#: packages/server/src/routes/admin/users.ts:154
#, fuzzy
msgid "Can Share"
msgstr "Comparteix"
msgstr "Pot compartir"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:114
msgid "Can view"
msgstr ""
msgstr "Pot veure"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:115
msgid "Can view and edit"
@@ -604,9 +599,8 @@ msgid "Cannot copy note to \"%s\" notebook"
msgstr "No es pot copiar la nota al bloc de notes «%s»"
#: packages/app-mobile/components/screens/Notes.tsx:165
#, fuzzy
msgid "Cannot create a new note: %s"
msgstr "Crea una nota nova."
msgstr "No pot crear una nova nota: %s"
#: packages/app-cli/app/command-attach.js:21
#: packages/app-cli/app/command-cat.js:25 packages/app-cli/app/command-cp.js:24
@@ -637,7 +631,6 @@ msgid "Cannot find \"%s\"."
msgstr "No es pot trobar «%s»."
#: packages/app-cli/app/command-mkbook.ts:28
#, fuzzy
msgid "Cannot find: \"%s\""
msgstr "No es pot trobar «%s»."
@@ -780,9 +773,8 @@ msgid "Close"
msgstr "Tanca"
#: packages/app-mobile/components/Dropdown.tsx:156
#, fuzzy
msgid "Close dropdown"
msgstr "Tanca la finestra"
msgstr "Tanca el desplegable"
#: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:24
#: packages/app-desktop/gui/MenuBar.tsx:598
@@ -912,9 +904,8 @@ msgid "Convert to todo"
msgstr "Converteix a llistat de tasques pendents"
#: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:89
#, fuzzy
msgid "Converting speech to text..."
msgstr "Converteix a nota"
msgstr "Converteix text a veu..."
#: packages/app-desktop/gui/MenuBar.tsx:497
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:19
@@ -958,9 +949,8 @@ msgstr[1] "Copia els enllaços compartibles"
#: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:21
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:370
#, fuzzy
msgid "Copy to clipboard"
msgstr "Copia el camí al porta-retalls"
msgstr "Copia al porta-retalls"
#: packages/app-desktop/gui/ClipperConfigScreen.tsx:140
msgid "Copy token"
@@ -1015,9 +1005,8 @@ msgstr ""
"L'error és \"%s\""
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:56
#, fuzzy
msgid "Could not switch profile: %s"
msgstr "No s'ha pogut instal·lar l'extensió: %s"
msgstr "No s'ha pogut canviar el perfil: %s"
#: packages/lib/components/EncryptionConfigScreen/utils.ts:219
msgid "Could not upgrade master key: %s"
@@ -1032,18 +1021,16 @@ msgstr ""
"s'està avortant. Torneu a provar quan tingueu connexió a Internet."
#: packages/app-mobile/components/biometrics/biometricAuthenticate.ts:20
#, fuzzy
msgid "Could not verify your identify: %s"
msgstr "No s'han pogut exportar les notes: %s"
msgstr "No s'ha pogut verificar la identitat: %s"
#: packages/app-desktop/gui/PromptDialog.tsx:277
msgid "Create"
msgstr "Crea"
#: packages/app-cli/app/command-mkbook.ts:19
#, fuzzy
msgid "Create a new notebook under a parent notebook."
msgstr "Crea un bloc de notes nou."
msgstr "Crea un bloc de notes nou sota un bloc de notes pare."
#: packages/app-mobile/components/NoteList.tsx:98
msgid "Create a notebook"
@@ -1231,9 +1218,8 @@ msgstr ""
"sincronització"
#: packages/app-desktop/gui/MainScreen/commands/deleteNote.ts:8
#, fuzzy
msgid "Delete note"
msgstr "Voleu suprimir la nota?"
msgstr "Suprimeix la nota"
#: packages/lib/models/Note.ts:778
msgid "Delete note \"%s\"?"
@@ -1245,9 +1231,8 @@ msgid "Delete note?"
msgstr "Voleu suprimir la nota?"
#: packages/app-desktop/gui/MainScreen/commands/deleteFolder.ts:9
#, fuzzy
msgid "Delete notebook"
msgstr "Voleu suprimir la nota?"
msgstr "Suprimeix el bloc de notes"
#: packages/app-desktop/gui/MainScreen/commands/deleteFolder.ts:20
#: packages/app-mobile/components/side-menu-content.tsx:162
@@ -1273,14 +1258,12 @@ msgid "Delete plugin \"%s\"?"
msgstr "Voleu suprimir l'extensió \"%s\"?"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:102
#, fuzzy
msgid "Delete profile \"%s\""
msgstr "Voleu suprimir la nota \"%s\"?"
msgstr "Suprimeix el perfil \"%s\"?"
#: packages/app-mobile/components/ScreenHeader.tsx:438
#, fuzzy
msgid "Delete selected notes"
msgstr "Voleu suprimir aquestes notes?"
msgstr "Suprimeix les notes seleccionades"
#: packages/app-desktop/gui/MainScreen/commands/deleteFolder.ts:22
#: packages/app-mobile/components/side-menu-content.tsx:159
@@ -1304,9 +1287,8 @@ msgstr ""
"quadern compartit."
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:98
#, fuzzy
msgid "Delete this profile?"
msgstr "Voleu suprimir aquestes %d notes?"
msgstr "Voleu suprimir aquestes perfil?"
#: packages/lib/Synchronizer.ts:192
msgid "Deleted local items: %d."
@@ -1485,9 +1467,8 @@ msgid "Downloading"
msgstr "Descarregant"
#: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:90
#, fuzzy
msgid "Downloading %s language files..."
msgstr "Descarregant recursos..."
msgstr "S'estan baixant %s fitxers de llengua..."
#: packages/app-cli/app/command-sync.ts:219
msgid "Downloading resources..."
@@ -1520,9 +1501,8 @@ msgid "Duplicate line"
msgstr "Duplica la línia"
#: packages/app-mobile/components/ScreenHeader.tsx:456
#, fuzzy
msgid "Duplicate selected notes"
msgstr "Duplica la línia"
msgstr "Duplica les notes seleccionades"
#: packages/app-cli/app/command-cp.js:13
msgid ""
@@ -1545,9 +1525,8 @@ msgid "Edit in external editor"
msgstr "Edita en un editor extern"
#: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:141
#, fuzzy
msgid "Edit link"
msgstr "Edita el bloc de notes"
msgstr "Edita l'enllaç"
#: packages/app-cli/app/command-edit.js:17
msgid "Edit note."
@@ -1559,9 +1538,8 @@ msgid "Edit notebook"
msgstr "Edita el bloc de notes"
#: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:88
#, fuzzy
msgid "Edit profile"
msgstr "Exporta el perfil"
msgstr "Edita el perfil"
#: packages/app-desktop/commands/editProfileConfig.ts:9
msgid "Edit profile configuration..."
@@ -1614,13 +1592,12 @@ msgstr "Correu electrònic"
#: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:18
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:364
#, fuzzy
msgid "Email to note"
msgstr "Edita la nota."
msgstr "De correu electrònic a nota"
#: packages/lib/utils/joplinCloud.ts:165
msgid "Email to Note"
msgstr ""
msgstr "De correu electrònic a nota"
#: packages/server/src/routes/admin/emails.ts:111
#: packages/server/src/services/MustacheService.ts:128
@@ -1723,9 +1700,8 @@ msgid "Enable table of contents extension"
msgstr "Activar l'extensió de l'índex"
#: packages/lib/models/Setting.ts:1070
#, fuzzy
msgid "Enable the Markdown toolbar"
msgstr "Activa els emoticons Markdown"
msgstr "Activa la barra d'eines Markdown"
#: packages/lib/models/Setting.ts:1153
msgid "Enable typographer support"
@@ -1864,9 +1840,8 @@ msgid "Export all"
msgstr "Exporta-ho tot"
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:87
#, fuzzy
msgid "Export all notes as JEX"
msgstr "Exporta-ho tot"
msgstr "Exporta totes les notes com a JEX"
#: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:177
msgid "Export debug report"
@@ -1893,9 +1868,8 @@ msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "S'està exportant a «%s» com a format «%s». Espereu..."
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:87
#, fuzzy
msgid "Exporting..."
msgstr "Exportant el perfil..."
msgstr "S'està exportant..."
#: packages/app-cli/app/command-export.js:13
msgid ""
@@ -1960,9 +1934,8 @@ msgid "Find and replace"
msgstr ""
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:250
#, fuzzy
msgid "Find: "
msgstr "Trobades: %d."
msgstr "S'ha trobat: "
#: packages/app-desktop/gui/ExtensionBadge.tsx:63
msgid "Firefox Extension"
@@ -2031,9 +2004,8 @@ msgid "Force path style"
msgstr "Força l'estil del camí"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:292
#, fuzzy
msgid "Formatting"
msgstr "Informació"
msgstr "S'està aplicant el format"
#: packages/lib/commands/historyForward.ts:6
msgid "Forward"
@@ -2053,9 +2025,8 @@ msgid "Full changelog"
msgstr "Registre complet de canvis"
#: packages/server/src/routes/admin/users.ts:130
#, fuzzy
msgid "Full name"
msgstr "Registre complet de canvis"
msgstr "Nom complet"
#: packages/lib/models/Setting.ts:2525
#: packages/server/src/services/MustacheService.ts:109
@@ -2120,23 +2091,20 @@ msgid "Help"
msgstr "Ajuda"
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:690
#, fuzzy
msgid "Hermes enabled: %d"
msgstr "FTS activat: %d"
msgstr "Hermes activat: %d"
#: packages/app-desktop/gui/MenuBar.tsx:569
msgid "Hide %s"
msgstr "Amaga %s"
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:218
#, fuzzy
msgid "Hide advanced"
msgstr "Amaga les metadades"
msgstr "Amaga la cerca avançada"
#: packages/server/src/routes/admin/users.ts:200
#, fuzzy
msgid "Hide disabled"
msgstr "Amaga les claus deshabilitades"
msgstr "Amaga allò deshabilitat"
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:172
msgid "Hide disabled keys"
@@ -2147,14 +2115,12 @@ msgid "Hide Joplin"
msgstr "Amaga el Joplin"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:269
#, fuzzy
msgid "Hide keyboard"
msgstr "Amaga les metadades"
msgstr "Amaga el teclat"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToggleOverflowButton.tsx:22
#, fuzzy
msgid "Hide more actions"
msgstr "Amaga les metadades"
msgstr "Amaga més accions"
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:14
msgid "Highlight"
@@ -2344,9 +2310,8 @@ msgstr "Introdueix un enllaç"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:89
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:649
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:201
#, fuzzy
msgid "Insert time"
msgstr "Insereix la data i hora"
msgstr "Insereix el temps"
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:191
msgid "Install"
@@ -2572,14 +2537,12 @@ msgid "Lines"
msgstr "Línies"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:186
#, fuzzy
msgid "Link"
msgstr "text destacat"
msgstr "Enllaç"
#: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:95
#, fuzzy
msgid "Link description"
msgstr "Xifratge"
msgstr "Descripció de l'enllaç"
#: packages/app-desktop/gui/ShareNoteDialog.tsx:184
msgid "Link has been copied to clipboard!"
@@ -2588,9 +2551,8 @@ msgstr[0] "L'enllaç s'ha copiat al porta-retalls!"
msgstr[1] "Els enllaços s'han copiat al porta-retalls!"
#: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:92
#, fuzzy
msgid "Link text"
msgstr "text destacat"
msgstr "Text de l'enllaç"
#: packages/app-mobile/components/screens/Note.tsx:206
msgid "Links with protocol \"%s\" are not supported"
@@ -2611,9 +2573,8 @@ msgid "Loaded"
msgstr "S'ha carregat"
#: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:87
#, fuzzy
msgid "Loading..."
msgstr "S'està actualitzant..."
msgstr "S'està carregant..."
#: packages/app-desktop/gui/NotePropertiesDialog.tsx:54
msgid "Location"
@@ -2673,14 +2634,12 @@ msgid "Manage master password..."
msgstr "Gestiona la contrasenya mestra..."
#: packages/lib/utils/joplinCloud.ts:171
#, fuzzy
msgid "Manage multiple users"
msgstr "Gestiona la contrasenya mestra"
msgstr "Gestiona múltiples usuaris"
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:571
#, fuzzy
msgid "Manage profiles"
msgstr "Actualitza el perfil"
msgstr "Gestiona els perfils"
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:325
msgid "Manage your plugins"
@@ -2746,14 +2705,12 @@ msgid "Max Item Size"
msgstr ""
#: packages/lib/utils/joplinCloud.ts:117
#, fuzzy
msgid "Max note or attachment size"
msgstr "Adjunts de la nota"
msgstr "Mida màxima de nota o adjunt"
#: packages/server/src/routes/admin/users.ts:150
#, fuzzy
msgid "Max Total Size"
msgstr "Mida real"
msgstr "Mida màxima total"
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:324
msgid "Missing keys"
@@ -2768,7 +2725,6 @@ msgid "Missing required argument: %s"
msgstr "Manca un argument requerit: %s"
#: packages/app-cli/app/cli-utils.js:135
#, fuzzy
msgid "Missing required flag value: %s"
msgstr "Manca un argument requerit: %s"
@@ -2806,9 +2762,8 @@ msgid "Move to notebook..."
msgstr "Mou al bloc de notes..."
#: packages/app-cli/app/command-mv.js:14
#, fuzzy
msgid "Moves the given <item> to [notebook]"
msgstr "Mou les notes que coincideixen amb <note> a [notebook]."
msgstr "Mou els elements marcats a [notebook]."
#: packages/app-cli/app/cli-utils.js:177
#: packages/app-cli/app/setupCommand.ts:21
@@ -2950,9 +2905,8 @@ msgid "Not generated"
msgstr "No s'ha generat"
#: packages/app-mobile/components/biometrics/BiometricPopup.tsx:91
#, fuzzy
msgid "Not now"
msgstr "Fes-ho ara"
msgstr "No ara"
#: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:112
#: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:122
@@ -2987,9 +2941,8 @@ msgid "Note does not exist: \"%s\". Create it?"
msgstr "La nota «%s» no existeix. Voleu crear-la?"
#: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:84
#, fuzzy
msgid "Note editor"
msgstr "Historial de la nota"
msgstr "Editor de la nota"
#: packages/app-cli/app/command-edit.js:97
msgid "Note has been saved."
@@ -3137,9 +3090,8 @@ msgid "Open %s"
msgstr "Obre %s"
#: packages/app-desktop/gui/MainScreen/commands/openPdfViewer.ts:7
#, fuzzy
msgid "Open PDF viewer"
msgstr "Habilita el visor de PDF"
msgstr "Obre el visor de PDF"
#: packages/app-desktop/commands/openProfileDirectory.ts:8
msgid "Open profile directory"
@@ -3170,9 +3122,8 @@ msgid "Or create an account."
msgstr "O creeu un compte."
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:86
#, fuzzy
msgid "Ordered list"
msgstr "Crea un usuari"
msgstr "Llista ordenada"
#: packages/app-desktop/gui/MenuBar.tsx:412
msgid "Other applications..."
@@ -3403,9 +3354,8 @@ msgid "Privacy Policy"
msgstr "Política de privacitat"
#: packages/lib/utils/joplinCloud.ts:322
#, fuzzy
msgid "Pro"
msgstr "Perfil"
msgstr "Pro"
#: packages/server/src/services/TaskService.ts:26
msgid "Process failed payment subscriptions"
@@ -3424,9 +3374,8 @@ msgid "Profile"
msgstr "Perfil"
#: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:96
#, fuzzy
msgid "Profile name"
msgstr "Nom del perfil:"
msgstr "Nom del perfil"
#: packages/app-desktop/gui/MainScreen/commands/addProfile.ts:17
msgid "Profile name:"
@@ -3437,18 +3386,16 @@ msgid "Profile Version: %s"
msgstr "Versió del perfil: %s"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:156
#, fuzzy
msgid "Profiles"
msgstr "Perfil"
msgstr "Perfils"
#: packages/app-mobile/components/screens/Note.tsx:1043
msgid "Properties"
msgstr "Propietats"
#: packages/lib/models/Setting.ts:1495
#, fuzzy
msgid "Proxy enabled"
msgstr "Activat"
msgstr "Intermediari activat"
#: packages/lib/models/Setting.ts:1517
msgid "Proxy timeout (seconds)"
@@ -3530,9 +3477,8 @@ msgid "Refresh"
msgstr "Actualitza"
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:313
#, fuzzy
msgid "Regular expression"
msgstr "Activa les expressions matemàtiques"
msgstr "Expressió regular"
#: packages/app-desktop/gui/MainScreen/MainScreen.tsx:633
#: packages/app-desktop/gui/Root.tsx:181
@@ -3577,9 +3523,8 @@ msgid "Replace"
msgstr ""
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:298
#, fuzzy
msgid "Replace all"
msgstr "Seleccioneu tot"
msgstr "Reemplaça-ho tot"
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:236
msgid "Replace with..."
@@ -3590,9 +3535,8 @@ msgid "Replace: "
msgstr ""
#: packages/app-desktop/gui/MainScreen/commands/resetLayout.ts:7
#, fuzzy
msgid "Reset application layout"
msgstr "Canvia la disposició de l'aplicació"
msgstr "Reinicialitza la disposició de l'aplicació"
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:220
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:221
@@ -3730,9 +3674,8 @@ msgid "Search for plugins..."
msgstr "Cerca connectors..."
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:223
#, fuzzy
msgid "Search for..."
msgstr "Cerca..."
msgstr "Cerca per..."
#: packages/app-desktop/gui/NoteListControls/commands/focusSearch.ts:6
msgid "Search in all the notes"
@@ -3778,9 +3721,8 @@ msgid "Select file..."
msgstr "Selecciona un fitxer..."
#: packages/app-mobile/components/screens/folder.js:109
#, fuzzy
msgid "Select parent notebook"
msgstr "Suprimeix el bloc de notes"
msgstr "Selecciona el bloc de notes pare"
#: packages/app-cli/app/command-server.js:38
msgid "Server is already running on port %d"
@@ -3842,9 +3784,8 @@ msgid ""
msgstr ""
#: packages/lib/utils/joplinCloud.ts:159
#, fuzzy
msgid "Share and collaborate on a notebook"
msgstr "Només podeu crear notes en un bloc de notes."
msgstr "Compartiu i col·laboreu en un bloc de notes"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:383
msgid "Share Notebook"
@@ -3867,13 +3808,12 @@ msgid "Shortcuts are not available in CLI mode."
msgstr "Les dreceres no són disponibles en el mode de línia d'ordres."
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:208
#, fuzzy
msgid "Show advanced"
msgstr "Mostra opcions avançades"
msgstr "Mostra les opcions avançades"
#: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:219
msgid "Show Advanced Settings"
msgstr "Mostra opcions avançades"
msgstr "Mostra les opcions avançades"
#: packages/app-mobile/components/screens/log.js:117
msgid "Show all"
@@ -3884,18 +3824,16 @@ msgid "Show completed to-dos"
msgstr "Mostra els llistats de tasques pendents finalitzats"
#: packages/server/src/routes/admin/users.ts:200
#, fuzzy
msgid "Show disabled"
msgstr "Mostra les claus deshabilitades"
msgstr "Mostra les deshabilitades"
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:172
msgid "Show disabled keys"
msgstr "Mostra les claus deshabilitades"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToggleOverflowButton.tsx:22
#, fuzzy
msgid "Show more actions"
msgstr "Mostra el nombre de notes"
msgstr "Mostra més accions"
#: packages/lib/models/Setting.ts:894
msgid "Show note counts"
@@ -4258,9 +4196,8 @@ msgid "Take photo"
msgstr "Fes una foto"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:100
#, fuzzy
msgid "Task list"
msgstr "Tasques"
msgstr "Llista de tasques"
#: packages/server/src/services/MustacheService.ts:124
#: packages/server/src/services/MustacheService.ts:277
@@ -4612,25 +4549,22 @@ msgstr ""
"poden restaurar."
#: packages/app-mobile/components/ScreenHeader.tsx:278
#, fuzzy
msgid "This note could not be deleted: %s"
msgid_plural "These notes could not be deleted: %s"
msgstr[0] "Aquest fitxer no s'ha pogut obrir: %s"
msgstr[1] "Aquest fitxer no s'ha pogut obrir: %s"
msgstr[0] "Aquesta nota no s'ha pogut suprimir: %s"
msgstr[1] "Aquestes notes no s'han pogut suprimir: %s"
#: packages/app-mobile/components/ScreenHeader.tsx:258
#, fuzzy
msgid "This note could not be duplicated: %s"
msgid_plural "These notes could not be duplicated: %s"
msgstr[0] "No s'ha pogut desar el bloc de notes: %s"
msgstr[1] "No s'ha pogut desar el bloc de notes: %s"
msgstr[0] "Aquesta nota no s'ha pogut duplicar: %s"
msgstr[1] "Aquestes notes no s'han pogut duplicar: %s"
#: packages/app-mobile/components/ScreenHeader.tsx:549
#, fuzzy
msgid "This note could not be moved: %s"
msgid_plural "These notes could not be moved: %s"
msgstr[0] "No s'ha pogut desar el bloc de notes: %s"
msgstr[1] "No s'ha pogut desar el bloc de notes: %s"
msgstr[0] "Aquesta nota no s'ha pogut moure: %s"
msgstr[1] "Aquestes notes no s'han pogut moure: %s"
#: packages/lib/models/Note.ts:103
msgid "This note does not have geolocation information."
@@ -4779,9 +4713,8 @@ msgid "to-do"
msgstr "tasques pendents"
#: packages/app-mobile/components/note-item.js:143
#, fuzzy
msgid "to-do: %s"
msgstr "tasques pendents"
msgstr "tasques pendents: %s"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:118
msgid "Toggle comment"
@@ -4832,9 +4765,8 @@ msgid "Tools"
msgstr "Eines"
#: packages/server/src/routes/admin/users.ts:146
#, fuzzy
msgid "Total Size"
msgstr "Mida real"
msgstr "Mida total"
#: packages/lib/services/ReportService.ts:285
msgid "Total: %d/%d"
@@ -4847,9 +4779,8 @@ msgstr "Intenta-ho de nou"
#: packages/lib/utils/joplinCloud.ts:315 packages/lib/utils/joplinCloud.ts:337
#: packages/lib/utils/joplinCloud.ts:359
#, fuzzy
msgid "Try it now"
msgstr "Fes-ho ara"
msgstr "Proveu-ho ara"
#: packages/app-cli/app/command-help.js:71
msgid ""
@@ -4907,9 +4838,8 @@ msgstr ""
"darrera versió"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:72
#, fuzzy
msgid "Unordered list"
msgstr "Crea un usuari"
msgstr "Llista no ordenada"
#: packages/app-desktop/gui/ShareNoteDialog.tsx:163
msgid "Unpublish note"
@@ -5132,11 +5062,12 @@ msgstr ""
"Avís: no es mostren tots els recursos per motius de rendiment (límit:% s)."
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:100
#, fuzzy
msgid ""
"Warnings:\n"
"%s"
msgstr "Avís"
msgstr ""
"Avisos:\n"
"%s"
#: packages/lib/models/Setting.ts:2535 packages/lib/utils/joplinCloud.ts:153
msgid "Web Clipper"
@@ -5181,9 +5112,8 @@ msgstr ""
"premeu «mn»."
#: packages/lib/WelcomeUtils.ts:63
#, fuzzy
msgid "Welcome!"
msgstr "Benvingut"
msgstr "Benvinguts!"
#: packages/lib/models/Setting.ts:1114
msgid "When creating a new note:"

View File

@@ -7,6 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Mr-Kanister <viger_gtrc@simplelogin.com>\n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -258,11 +260,12 @@ msgstr "Akzeptieren"
#: packages/lib/WebDavApi.js:451
msgid "Access denied: Please check your username and password"
msgstr ""
msgstr "Zugriff verweigert: Bitte überprüfe Nutzername und Passwort"
#: packages/lib/WebDavApi.js:449
msgid "Access denied: Please re-enter your password and/or username"
msgstr ""
"Zugriff verweigert: Bitte trage dein Passwort und/oder Nutzername erneut ein"
#: packages/server/src/routes/admin/users.ts:138
msgid "Account"
@@ -387,6 +390,8 @@ msgid ""
"Any email sent to this address will be converted into a note and added to "
"your collection. The note will be saved into the Inbox notebook"
msgstr ""
"Jede an diese Adresse gerichtete E-Mail wird zu einer Notiz konvertiert und "
"deiner Kollektion hinzugefügt. Die Notiz wird im Inbox-Notizbuch gespeichert"
#: packages/lib/models/Setting.ts:2527
msgid "Appearance"
@@ -559,15 +564,15 @@ msgstr "Aufzählung"
#: packages/server/src/routes/admin/users.ts:154
msgid "Can Share"
msgstr "Teilen"
msgstr "Teilen möglich"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:114
msgid "Can view"
msgstr "Sehen"
msgstr "Lesen möglich"
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:115
msgid "Can view and edit"
msgstr "Sehen und bearbeiten"
msgstr "Lesen und bearbeiten möglich"
#: packages/app-desktop/bridge.ts:197 packages/app-desktop/bridge.ts:215
#: packages/app-desktop/checkForUpdates.ts:107
@@ -621,9 +626,8 @@ msgid "Cannot copy note to \"%s\" notebook"
msgstr "Kann Notiz nicht in das Notizbuch „%s“ kopieren"
#: packages/app-mobile/components/screens/Notes.tsx:165
#, fuzzy
msgid "Cannot create a new note: %s"
msgstr "Erstellt eine neue Notiz."
msgstr "Konnte neue Notiz nicht erstellen: %s"
#: packages/app-cli/app/command-attach.js:21
#: packages/app-cli/app/command-cat.js:25 packages/app-cli/app/command-cp.js:24
@@ -978,9 +982,8 @@ msgstr[1] "Teilbare Links kopieren"
#: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:21
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:370
#, fuzzy
msgid "Copy to clipboard"
msgstr "Pfad in Zwischenablage kopieren"
msgstr "In Zwischenablage kopieren"
#: packages/app-desktop/gui/ClipperConfigScreen.tsx:140
msgid "Copy token"
@@ -1251,9 +1254,8 @@ msgid "Delete local data and re-download from sync target"
msgstr "Lösche lokale Daten und lade Daten erneut vom Synchronisierungsziel"
#: packages/app-desktop/gui/MainScreen/commands/deleteNote.ts:8
#, fuzzy
msgid "Delete note"
msgstr "Notiz löschen?"
msgstr "Notiz löschen"
#: packages/lib/models/Note.ts:778
msgid "Delete note \"%s\"?"
@@ -1265,9 +1267,8 @@ msgid "Delete note?"
msgstr "Notiz löschen?"
#: packages/app-desktop/gui/MainScreen/commands/deleteFolder.ts:9
#, fuzzy
msgid "Delete notebook"
msgstr "Notizbuch löschen?"
msgstr "Notizbuch löschen"
#: packages/app-desktop/gui/MainScreen/commands/deleteFolder.ts:20
#: packages/app-mobile/components/side-menu-content.tsx:162
@@ -1309,6 +1310,10 @@ msgid ""
"If you delete the inbox notebook, any email that's recently been sent to it "
"may be lost."
msgstr ""
"Das Inbox-Notizbuch löschen?\n"
"\n"
"Wenn du das Inbox-Notizbuch löschst, gehen in ihm gespeicherte E-Mails "
"möglicherweise verloren."
#: packages/lib/models/Note.ts:780
msgid "Delete these %d notes?"
@@ -1633,13 +1638,12 @@ msgstr "E-Mail"
#: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:18
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:364
#, fuzzy
msgid "Email to note"
msgstr "Notiz bearbeiten."
msgstr "E-Mail zu Notiz"
#: packages/lib/utils/joplinCloud.ts:165
msgid "Email to Note"
msgstr ""
msgstr "E-Mail zu Notiz"
#: packages/server/src/routes/admin/emails.ts:111
#: packages/server/src/services/MustacheService.ts:128
@@ -1881,9 +1885,8 @@ msgid "Export all"
msgstr "Alles exportieren"
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:87
#, fuzzy
msgid "Export all notes as JEX"
msgstr "Alles exportieren"
msgstr "Alle Notizen als JEX exportieren"
#: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:177
msgid "Export debug report"
@@ -1899,7 +1902,7 @@ msgstr "Profil exportieren"
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:106
msgid "Exported successfully!"
msgstr ""
msgstr "Exportieren erfolgreich!"
#: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:581
msgid "Exporting profile..."
@@ -1910,9 +1913,8 @@ msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
msgstr "Es wird nach „%s“ im Format „%s“ exportiert. Bitte warten ..."
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:87
#, fuzzy
msgid "Exporting..."
msgstr "Profil wird exportiert ..."
msgstr "Exportiere..."
#: packages/app-cli/app/command-export.js:13
msgid ""
@@ -2559,7 +2561,7 @@ msgstr "Layout-Reihenfolge"
#: packages/lib/models/Setting.ts:1719
msgid "Leave it blank to download the language files from the default website"
msgstr ""
"Lasse es leer, um die Sprachdateien von der Standardseite herunterzuladen."
"Lasse es leer, um die Sprachdateien von der Standardseite herunterzuladen"
#: packages/app-desktop/gui/MainScreen/commands/leaveSharedFolder.ts:10
msgid "Leave notebook..."
@@ -3851,6 +3853,8 @@ msgid ""
"Share a copy of all notes in a file format that can be imported by Joplin on "
"a computer."
msgstr ""
"Teile eine Kopie aller Notizen in einem Dateiformat, welches von Joplin auf "
"einem anderen Computer importiert werden kann."
# Plural klingt subjektiv besser als Singular.
#: packages/lib/utils/joplinCloud.ts:159
@@ -4642,25 +4646,22 @@ msgstr ""
"löschst, da sie danach nicht wiederhergestellt werden können."
#: packages/app-mobile/components/ScreenHeader.tsx:278
#, fuzzy
msgid "This note could not be deleted: %s"
msgid_plural "These notes could not be deleted: %s"
msgstr[0] "Dieses Notizbuch konnte nicht geöffnet werden: %s"
msgstr[1] "Dieses Notizbuch konnte nicht geöffnet werden: %s"
msgstr[0] "Diese Notiz konnte nicht gelöscht werden: %s"
msgstr[1] "Diese Notizen konnten nicht gelöscht werden: %s"
#: packages/app-mobile/components/ScreenHeader.tsx:258
#, fuzzy
msgid "This note could not be duplicated: %s"
msgid_plural "These notes could not be duplicated: %s"
msgstr[0] "Dieses Notizbuch konnte nicht gespeichert werden: %s"
msgstr[1] "Dieses Notizbuch konnte nicht gespeichert werden: %s"
msgstr[0] "Diese Notiz konnte nicht dupliziert werden: %s"
msgstr[1] "Diese Notizen konnten nicht dupliziert werden: %s"
#: packages/app-mobile/components/ScreenHeader.tsx:549
#, fuzzy
msgid "This note could not be moved: %s"
msgid_plural "These notes could not be moved: %s"
msgstr[0] "Dieses Notizbuch konnte nicht gespeichert werden: %s"
msgstr[1] "Dieses Notizbuch konnte nicht gespeichert werden: %s"
msgstr[0] "Diese Notiz konnte nicht verschoben werden: %s"
msgstr[1] "Diese Notizen konnten nicht verschoben werden: %s"
#: packages/lib/models/Note.ts:103
msgid "This note does not have geolocation information."
@@ -4918,7 +4919,7 @@ msgstr "Typ: %s."
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:69
msgid "Unable to export or share data. Reason: %s"
msgstr ""
msgstr "Exportieren oder Teilen der Daten nicht möglich. Grund: %s"
#: packages/lib/models/Setting.ts:911
msgid "Uncompleted to-dos on top"
@@ -5168,11 +5169,12 @@ msgstr ""
"(Obergrenze: %s)."
#: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:100
#, fuzzy
msgid ""
"Warnings:\n"
"%s"
msgstr "Warnung"
msgstr ""
"Warnungen: \n"
"%s"
#: packages/lib/models/Setting.ts:2535 packages/lib/utils/joplinCloud.ts:153
msgid "Web Clipper"

View File

@@ -36,7 +36,7 @@
"node-fetch": "2.6.7",
"relative": "3.0.2",
"request": "2.88.2",
"sharp": "0.32.3",
"sharp": "0.32.4",
"source-map-support": "0.5.21",
"uri-template": "2.0.0",
"yargs": "17.7.2"

View File

@@ -671,6 +671,14 @@
"created_at": "2023-08-07T22:03:21Z",
"repoId": 79162682,
"pullRequestNo": 8635
},
{
"name": "xavivars",
"id": 134083,
"comment_id": 1679771834,
"created_at": "2023-08-15T23:51:35Z",
"repoId": 79162682,
"pullRequestNo": 8675
}
]
}

View File

@@ -18,7 +18,7 @@ Moreover, by getting a subscription you are supporting the development of the pr
We offer a 50% Education Discount for students and teachers. To claim it, please contact us from your university or school email address. You will then receive a URL you can use to subscribe to Joplin Cloud while benefiting from the 50% discount. This is valid for a whole year and can be renewed for as long as you are in education by contacting us again.
We may also offer bulk discounts for companies, associations and nonprofit organisations. Please [contact us](mailto:support@joplincloud.com) for more details.
We may also offer bulk discounts for companies, associations and nonprofit organisations. Please [contact us](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/Aide.png) for more details.
## Where is Joplin Cloud data located?

135
yarn.lock
View File

@@ -2840,6 +2840,16 @@ __metadata:
languageName: node
linkType: hard
"@bam.tech/react-native-image-resizer@npm:3.0.5":
version: 3.0.5
resolution: "@bam.tech/react-native-image-resizer@npm:3.0.5"
peerDependencies:
react: "*"
react-native: "*"
checksum: f555bd10aafab1a797b6f5142e59b1bb11f229b61d35c3e6c9d734bbd4999f97bcc86853f69965d758ca872aad024add7a852041da498b177eee923ef82e506d
languageName: node
linkType: hard
"@bcoe/v8-coverage@npm:^0.2.3":
version: 0.2.3
resolution: "@bcoe/v8-coverage@npm:0.2.3"
@@ -4502,6 +4512,7 @@ __metadata:
"@babel/core": 7.20.2
"@babel/preset-env": 7.20.2
"@babel/runtime": 7.20.0
"@bam.tech/react-native-image-resizer": 3.0.5
"@codemirror/commands": 6.2.2
"@codemirror/lang-cpp": 6.0.2
"@codemirror/lang-html": 6.4.3
@@ -4523,7 +4534,7 @@ __metadata:
"@joplin/utils": ~2.12
"@lezer/highlight": 1.1.4
"@react-native-community/clipboard": 1.5.1
"@react-native-community/datetimepicker": 7.3.0
"@react-native-community/datetimepicker": 7.4.1
"@react-native-community/geolocation": 3.0.6
"@react-native-community/netinfo": 9.4.1
"@react-native-community/push-notification-ios": 1.11.0
@@ -4563,7 +4574,6 @@ __metadata:
punycode: 2.3.0
react: 18.2.0
react-native: 0.71.10
react-native-action-button: 2.8.5
react-native-camera: 4.2.1
react-native-device-info: 10.7.0
react-native-dialogbox: 0.6.10
@@ -4577,7 +4587,6 @@ __metadata:
react-native-gesture-handler: 2.12.0
react-native-get-random-values: 1.9.0
react-native-image-picker: 5.6.0
react-native-image-resizer: 1.4.5
react-native-localize: 3.0.2
react-native-modal-datetime-picker: 15.0.1
react-native-paper: 5.9.1
@@ -4734,7 +4743,7 @@ __metadata:
relative: 3.0.2
reselect: 4.1.8
server-destroy: 1.0.1
sharp: 0.32.3
sharp: 0.32.4
sprintf-js: 1.1.2
sqlite3: 5.1.6
string-padding: 1.0.2
@@ -4745,7 +4754,7 @@ __metadata:
uglifycss: 0.0.29
url-parse: 1.5.10
uuid: 9.0.0
word-wrap: 1.2.4
word-wrap: 1.2.5
xml2js: 0.4.23
languageName: unknown
linkType: soft
@@ -4909,7 +4918,7 @@ __metadata:
jest-expect-message: 1.1.3
jquery: 3.7.0
jsdom: 22.1.0
knex: 2.4.2
knex: 2.5.0
koa: 2.14.2
markdown-it: 13.0.1
mustache: 4.2.0
@@ -4922,7 +4931,7 @@ __metadata:
pretty-bytes: 5.6.0
prettycron: 0.10.0
query-string: 7.1.3
rate-limiter-flexible: 2.4.1
rate-limiter-flexible: 2.4.2
raw-body: 2.5.2
source-map-support: 0.5.21
sqlite3: 5.1.6
@@ -4968,7 +4977,7 @@ __metadata:
request: 2.88.2
rss: 1.2.2
sass: 1.63.6
sharp: 0.32.3
sharp: 0.32.4
source-map-support: 0.5.21
sqlite3: 5.1.6
typescript: 5.1.3
@@ -6855,12 +6864,12 @@ __metadata:
languageName: node
linkType: hard
"@react-native-community/datetimepicker@npm:7.3.0":
version: 7.3.0
resolution: "@react-native-community/datetimepicker@npm:7.3.0"
"@react-native-community/datetimepicker@npm:7.4.1":
version: 7.4.1
resolution: "@react-native-community/datetimepicker@npm:7.4.1"
dependencies:
invariant: ^2.2.4
checksum: e522f01d0068b9a20f3f8883b814f4cfd84717165c43ff36edd242ae4b64d90202a3750209ca1f47b4b77edbf17358446011aeefacb3df67b96ce53574ba4144
checksum: bf1b2591ca4413a6ca1e074150940578b8d6d6c6063a740895e359088fe31cbf0cefb65f829a3d29e2f861b72d9d8fdf4f835942566f8953e7410068dfe37ea1
languageName: node
linkType: hard
@@ -14244,6 +14253,13 @@ __metadata:
languageName: node
linkType: hard
"detect-libc@npm:^2.0.2":
version: 2.0.2
resolution: "detect-libc@npm:2.0.2"
checksum: 2b2cd3649b83d576f4be7cc37eb3b1815c79969c8b1a03a40a4d55d83bc74d010753485753448eacb98784abf22f7dbd3911fd3b60e29fda28fed2d1a997944d
languageName: node
linkType: hard
"detect-newline@npm:^3.0.0":
version: 3.1.0
resolution: "detect-newline@npm:3.1.0"
@@ -21042,7 +21058,7 @@ __metadata:
proper-lockfile: 4.1.2
read-chunk: 2.1.0
server-destroy: 1.0.1
sharp: 0.32.3
sharp: 0.32.4
sprintf-js: 1.1.2
sqlite3: 5.1.6
string-padding: 1.0.2
@@ -21053,7 +21069,7 @@ __metadata:
tkwidgets: 0.5.27
typescript: 5.1.3
url-parse: 1.5.10
word-wrap: 1.2.4
word-wrap: 1.2.5
yargs-parser: 21.1.1
bin:
joplin: ./main.js
@@ -21657,7 +21673,46 @@ __metadata:
languageName: node
linkType: hard
"knex@npm:2.4.2, knex@npm:^2.4.2":
"knex@npm:2.5.0":
version: 2.5.0
resolution: "knex@npm:2.5.0"
dependencies:
colorette: 2.0.19
commander: ^10.0.0
debug: 4.3.4
escalade: ^3.1.1
esm: ^3.2.25
get-package-type: ^0.1.0
getopts: 2.3.0
interpret: ^2.2.0
lodash: ^4.17.21
pg-connection-string: 2.6.1
rechoir: ^0.8.0
resolve-from: ^5.0.0
tarn: ^3.0.2
tildify: 2.0.0
peerDependenciesMeta:
better-sqlite3:
optional: true
mysql:
optional: true
mysql2:
optional: true
pg:
optional: true
pg-native:
optional: true
sqlite3:
optional: true
tedious:
optional: true
bin:
knex: bin/cli.js
checksum: 83c9fa20423546cbfcfedd28095645ad22c4a3529c02a94cbfe970800c0542c0dde502245237666f52da7edfe4b404b4acd3d5179fc37008ddaa6025b1fcfb9d
languageName: node
linkType: hard
"knex@npm:^2.4.2":
version: 2.4.2
resolution: "knex@npm:2.4.2"
dependencies:
@@ -26478,7 +26533,7 @@ __metadata:
languageName: node
linkType: hard
"pg-connection-string@npm:^2.6.1":
"pg-connection-string@npm:2.6.1, pg-connection-string@npm:^2.6.1":
version: 2.6.1
resolution: "pg-connection-string@npm:2.6.1"
checksum: 882344a47e1ecf3a91383e0809bf2ac48facea97fcec0358d6e060e1cbcb8737acde419b4c86f05da4ce4a16634ee50fff1d2bb787d73b52ccbfde697243ad8a
@@ -27232,7 +27287,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.5.10, prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
"prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
version: 15.7.2
resolution: "prop-types@npm:15.7.2"
dependencies:
@@ -27561,10 +27616,10 @@ __metadata:
languageName: node
linkType: hard
"rate-limiter-flexible@npm:2.4.1":
version: 2.4.1
resolution: "rate-limiter-flexible@npm:2.4.1"
checksum: 5eea3ffbb6a11f634edd8b9575815c2bf239a8becdfdc82c4183cad92025e853913972a2b2f2d45c16e81aea1a3451fbad8da76dee1ba0e4549c22a0ba58c50f
"rate-limiter-flexible@npm:2.4.2":
version: 2.4.2
resolution: "rate-limiter-flexible@npm:2.4.2"
checksum: 039e58b664991963ba2668a83d0406a72e5822683103acbe416854deb92ed834b840ce6e0acfea35917d9b49685bd53946ae47435a9f5916c2e7550395dec9dc
languageName: node
linkType: hard
@@ -27712,17 +27767,6 @@ __metadata:
languageName: node
linkType: hard
"react-native-action-button@npm:2.8.5":
version: 2.8.5
resolution: "react-native-action-button@npm:2.8.5"
dependencies:
prop-types: ^15.5.10
peerDependencies:
react-native: ">=0.11"
checksum: e5f8236c9980e491daff3707648ab3a0f4c79c3c4c102ec340d376e204a740b87486f8d4b5e2336e2ab29e5dcd4990693778513cb76e7cc5ddd00ac1c2166977
languageName: node
linkType: hard
"react-native-camera@npm:4.2.1":
version: 4.2.1
resolution: "react-native-camera@npm:4.2.1"
@@ -27917,15 +27961,6 @@ __metadata:
languageName: node
linkType: hard
"react-native-image-resizer@npm:1.4.5":
version: 1.4.5
resolution: "react-native-image-resizer@npm:1.4.5"
peerDependencies:
react-native: ">=v0.40.0"
checksum: c530b119f25c27b669148461554440acd05fb37f0a24a1afc3d58c861e426551c70c679983c0399034fd54ca3575c89d0863778c49295721cb33b65bbf3f0f37
languageName: node
linkType: hard
"react-native-localize@npm:3.0.2":
version: 3.0.2
resolution: "react-native-localize@npm:3.0.2"
@@ -30020,12 +30055,12 @@ __metadata:
languageName: node
linkType: hard
"sharp@npm:0.32.3":
version: 0.32.3
resolution: "sharp@npm:0.32.3"
"sharp@npm:0.32.4":
version: 0.32.4
resolution: "sharp@npm:0.32.4"
dependencies:
color: ^4.2.3
detect-libc: ^2.0.1
detect-libc: ^2.0.2
node-addon-api: ^6.1.0
node-gyp: latest
prebuild-install: ^7.1.1
@@ -30033,7 +30068,7 @@ __metadata:
simple-get: ^4.0.1
tar-fs: ^3.0.4
tunnel-agent: ^0.6.0
checksum: 8a6ed0d00bd4d3d6ba92c392fe1f00a4a207f138257a4d903ce5afe5c6d7f684b5218c5b4e8df1097aac960ac10e0114c823f6a8a7e18255bf4a8ec364087051
checksum: 52e3cfe8fbba2623a9b935be8a3d00d6993a2c56c775ac5cc89b273826db95f029f68a0029a37f96dcb6790aa2e3c05a02599035535b319f50ab31f5d86a13f0
languageName: node
linkType: hard
@@ -34330,10 +34365,10 @@ __metadata:
languageName: node
linkType: hard
"word-wrap@npm:1.2.4":
version: 1.2.4
resolution: "word-wrap@npm:1.2.4"
checksum: 8f1f2e0a397c0e074ca225ba9f67baa23f99293bc064e31355d426ae91b8b3f6b5f6c1fc9ae5e9141178bb362d563f55e62fd8d5c31f2a77e3ade56cb3e35bd1
"word-wrap@npm:1.2.5":
version: 1.2.5
resolution: "word-wrap@npm:1.2.5"
checksum: f93ba3586fc181f94afdaff3a6fef27920b4b6d9eaefed0f428f8e07adea2a7f54a5f2830ce59406c8416f033f86902b91eb824072354645eea687dff3691ccb
languageName: node
linkType: hard