You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-23 23:33:01 +02:00
Compare commits
35 Commits
cli-v2.12.
...
issue-7808
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ab14c4ab0 | ||
|
|
74d407de6f | ||
|
|
9740dd9bbe | ||
|
|
98b3432105 | ||
|
|
cdba5cfa8c | ||
|
|
0cfe4f1e33 | ||
|
|
56fb48d78b | ||
|
|
87e51aa8e6 | ||
|
|
41fdc0d44d | ||
|
|
a754a8d772 | ||
|
|
41d0363fd0 | ||
|
|
2a4c7a334e | ||
|
|
df1b0a96f4 | ||
|
|
0030681cb4 | ||
|
|
e7014492c5 | ||
|
|
4804c1c0c3 | ||
|
|
270d96ad07 | ||
|
|
5ed3d94faa | ||
|
|
d0e943630d | ||
|
|
406e933407 | ||
|
|
7108a4243d | ||
|
|
135e2e4a21 | ||
|
|
5ff963704b | ||
|
|
bea40d0997 | ||
|
|
c68c0bf501 | ||
|
|
cf3d86698d | ||
|
|
3251c4c40e | ||
|
|
bd5e0fd42a | ||
|
|
7d0b7122f0 | ||
|
|
85eddbfe22 | ||
|
|
5d87b4ca3e | ||
|
|
3dea9ab6e7 | ||
|
|
89f550ca48 | ||
|
|
dd869c43bb | ||
|
|
7f5acdea5e |
@@ -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
2
.gitignore
vendored
@@ -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
BIN
Assets/Aide.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface NoteEditorProps {
|
||||
isProvisional: boolean;
|
||||
editorNoteStatuses: any;
|
||||
syncStarted: boolean;
|
||||
decryptionStarted: boolean;
|
||||
bodyEditor: string;
|
||||
notesParentType: string;
|
||||
selectedNoteTags: any[];
|
||||
|
||||
@@ -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!',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
@@ -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: '',
|
||||
};
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -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'),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ export enum ErrorCode {
|
||||
NoSub = 'no_sub',
|
||||
NoStripeSub = 'no_stripe_sub',
|
||||
InvalidOrigin = 'invalidOrigin',
|
||||
TaskAlreadyRunning = 'taskAlreadyRunning',
|
||||
}
|
||||
|
||||
export interface ErrorOptions {
|
||||
|
||||
@@ -104,5 +104,7 @@ export default async function(env: Env, models: Models, config: Config, services
|
||||
|
||||
await taskService.registerTasks(tasks);
|
||||
|
||||
await taskService.resetInterruptedTasks();
|
||||
|
||||
return taskService;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
135
yarn.lock
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user