You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-03-03 09:27:01 +02:00
Compare commits
31 Commits
transcribe
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36b25a9517 | ||
|
|
b3e0575361 | ||
|
|
f9f40b3c9b | ||
|
|
b59721f4b3 | ||
|
|
891ab3e317 | ||
|
|
0e156796bc | ||
|
|
f2b558cb75 | ||
|
|
322657ef72 | ||
|
|
c1e99afd2e | ||
|
|
b3822e2700 | ||
|
|
a43f46fc01 | ||
|
|
50a26b63c8 | ||
|
|
02c1c75587 | ||
|
|
345632324d | ||
|
|
8073e03daf | ||
|
|
7feb953c70 | ||
|
|
8e895fb2c0 | ||
|
|
ee97c41309 | ||
|
|
c9a55563b5 | ||
|
|
39f5dc8c95 | ||
|
|
9256ab197a | ||
|
|
ee2869da86 | ||
|
|
e11441cfbc | ||
|
|
2b5be639ce | ||
|
|
cf3d7f5b88 | ||
|
|
595452f30e | ||
|
|
33c4029547 | ||
|
|
eb238efc7b | ||
|
|
513341f103 | ||
|
|
65b7c4be26 | ||
|
|
344a3c2605 |
@@ -85,6 +85,22 @@ reviews:
|
||||
instructions: "Apply when the PR modifies files under packages/app-web/. Or when the PR modifies files under packages/app-mobile and the change is specific to the web app only"
|
||||
- label: "windows"
|
||||
instructions: "Apply when the PR is mainly about changes specific to Windows"
|
||||
|
||||
pre_merge_checks:
|
||||
description:
|
||||
mode: "warning"
|
||||
custom_checks:
|
||||
- name: "PR Description Must Follow Guidelines"
|
||||
mode: "error"
|
||||
instructions: |
|
||||
Fail if the pull request description does not include clear sections for:
|
||||
- Problem or user-impact description
|
||||
- A high-level Solution explanation
|
||||
- Any Test Plan or verification steps
|
||||
|
||||
The description should align with our PR guidelines
|
||||
at https://github.com/joplin/gsoc/blob/master/pull_request_guidelines.md
|
||||
and should not just restate the diff or implementation details.
|
||||
knowledge_base:
|
||||
code_guidelines:
|
||||
enabled: true
|
||||
|
||||
@@ -695,8 +695,6 @@ packages/app-mobile/components/ExtendedWebView/index.js
|
||||
packages/app-mobile/components/ExtendedWebView/index.web.js
|
||||
packages/app-mobile/components/ExtendedWebView/types.js
|
||||
packages/app-mobile/components/ExtendedWebView/utils/useCss.js
|
||||
packages/app-mobile/components/FeedbackBanner.test.js
|
||||
packages/app-mobile/components/FeedbackBanner.js
|
||||
packages/app-mobile/components/FolderPicker.js
|
||||
packages/app-mobile/components/Icon.js
|
||||
packages/app-mobile/components/IconButton.js
|
||||
@@ -741,7 +739,6 @@ packages/app-mobile/components/ScreenHeader/Menu.js
|
||||
packages/app-mobile/components/ScreenHeader/WarningBanner.test.js
|
||||
packages/app-mobile/components/ScreenHeader/WarningBanner.js
|
||||
packages/app-mobile/components/ScreenHeader/WarningBox.js
|
||||
packages/app-mobile/components/ScreenHeader/WebBetaButton.js
|
||||
packages/app-mobile/components/ScreenHeader/index.js
|
||||
packages/app-mobile/components/SearchInput.js
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
@@ -1434,6 +1431,7 @@ packages/lib/services/AlarmServiceDriverNode.js
|
||||
packages/lib/services/BaseService.js
|
||||
packages/lib/services/CommandService.test.js
|
||||
packages/lib/services/CommandService.js
|
||||
packages/lib/services/DecryptionWorker.test.js
|
||||
packages/lib/services/DecryptionWorker.js
|
||||
packages/lib/services/ExternalEditWatcher.js
|
||||
packages/lib/services/ExternalEditWatcher/utils.js
|
||||
|
||||
10
.github/PULL_REQUEST_TEMPLATE
vendored
10
.github/PULL_REQUEST_TEMPLATE
vendored
@@ -1,6 +1,12 @@
|
||||
<!--
|
||||
|
||||
Please prefix the title with the platform you are targetting:
|
||||
Before contributing, please read the contribution guidelines: https://github.com/laurent22/joplin/blob/dev/readme/dev/index.md
|
||||
|
||||
If this is a Google Summer of Code pull request, please read the [GSoC pull request guidelines](https://github.com/joplin/gsoc/blob/master/pull_request_guidelines.md).
|
||||
|
||||
---
|
||||
|
||||
**Pull request title**: Please prefix the title with the platform you are targetting.
|
||||
|
||||
Here are some examples of good titles:
|
||||
|
||||
@@ -20,6 +26,4 @@ If it's not related to any platform (such as a translation, change to the docume
|
||||
|
||||
Then please append the issue that you've addressed or fixed. Use "Resolves #123" for new features or improvements and "Fixes #123" for bug fixes.
|
||||
|
||||
AND PLEASE READ THE GUIDE: https://github.com/laurent22/joplin/blob/dev/readme/dev/index.md
|
||||
|
||||
-->
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -668,8 +668,6 @@ packages/app-mobile/components/ExtendedWebView/index.js
|
||||
packages/app-mobile/components/ExtendedWebView/index.web.js
|
||||
packages/app-mobile/components/ExtendedWebView/types.js
|
||||
packages/app-mobile/components/ExtendedWebView/utils/useCss.js
|
||||
packages/app-mobile/components/FeedbackBanner.test.js
|
||||
packages/app-mobile/components/FeedbackBanner.js
|
||||
packages/app-mobile/components/FolderPicker.js
|
||||
packages/app-mobile/components/Icon.js
|
||||
packages/app-mobile/components/IconButton.js
|
||||
@@ -714,7 +712,6 @@ packages/app-mobile/components/ScreenHeader/Menu.js
|
||||
packages/app-mobile/components/ScreenHeader/WarningBanner.test.js
|
||||
packages/app-mobile/components/ScreenHeader/WarningBanner.js
|
||||
packages/app-mobile/components/ScreenHeader/WarningBox.js
|
||||
packages/app-mobile/components/ScreenHeader/WebBetaButton.js
|
||||
packages/app-mobile/components/ScreenHeader/index.js
|
||||
packages/app-mobile/components/SearchInput.js
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
@@ -1407,6 +1404,7 @@ packages/lib/services/AlarmServiceDriverNode.js
|
||||
packages/lib/services/BaseService.js
|
||||
packages/lib/services/CommandService.test.js
|
||||
packages/lib/services/CommandService.js
|
||||
packages/lib/services/DecryptionWorker.test.js
|
||||
packages/lib/services/DecryptionWorker.js
|
||||
packages/lib/services/ExternalEditWatcher.js
|
||||
packages/lib/services/ExternalEditWatcher/utils.js
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:24-bullseye
|
||||
FROM node:24-bookworm
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
|
||||
@@ -31,7 +31,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
|
||||
# Sponsors
|
||||
|
||||
<!-- SPONSORS-ORG -->
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp"><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com"><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a> <a href="https://bestkru.com"><img title="BestKru" width="256" src="https://joplinapp.org/images/sponsors/BestKru.png"/></a> <a href="https://www.socialfollowers.uk/buy-tiktok-followers/"><img title="Social Followers" width="256" src="https://joplinapp.org/images/sponsors/SocialFollowers.png"/></a> <a href="https://stormlikes.com/"><img title="Stormlikes" width="256" src="https://joplinapp.org/images/sponsors/Stormlikes.png"/></a> <a href="https://route4me.com"><img title="Route4Me" width="256" src="https://joplinapp.org/images/sponsors/Route4Me.png"/></a> <a href="https://topagency.webflow.io"><img title="WebDesignAgency" width="256" src="https://joplinapp.org/images/sponsors/WebDesignAgency.png" alt="topagency"/></a> <a href="https://essayshark.com"><img title="EssayShark - essay writers for hire" width="256" src="https://joplinapp.org/images/sponsors/EssayShark.png" alt="EssayShark - essay writers for hire"/></a> <a href="https://pokieslab1.com/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/PokiesLab.png" alt="Australian Real Money Pokies"/></a> <a href="https://pokiesman1.net/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/Pokiesman.png" alt="Australian Real Money Pokies"/></a> <a href="https://socialkings.online"><img title="Boost your reach and buy real followers" width="256" src="https://joplinapp.org/images/sponsors/SocialKings.png" alt="Boost your reach and buy real followers"/></a> <a href="https://essayservice.com/"><img title="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines" width="256" src="https://joplinapp.org/images/sponsors/EssayService.png" alt="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines"/></a> <a href=" https://thenationonlineng.net/casino-en-ligne/casino-en-ligne-payant-au-canada/"><img title="casino en ligne le plus payant" width="256" src="https://joplinapp.org/images/sponsors/TheNationOnline.jpg" alt="casino en ligne le plus payant"/></a>
|
||||
<a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/></a> <a href="https://citricsheep.com"><img title="Citric Sheep" width="256" src="https://joplinapp.org/images/sponsors/CitricSheep.png"/></a> <a href="https://sorted.travel/?utm_source=joplinapp"><img title="Sorted Travel" width="256" src="https://joplinapp.org/images/sponsors/SortedTravel.png"/></a> <a href="https://celebian.com"><img title="Celebian" width="256" src="https://joplinapp.org/images/sponsors/Celebian.png"/></a> <a href="https://bestkru.com"><img title="BestKru" width="256" src="https://joplinapp.org/images/sponsors/BestKru.png"/></a> <a href="https://www.socialfollowers.uk/buy-tiktok-followers/"><img title="Social Followers" width="256" src="https://joplinapp.org/images/sponsors/SocialFollowers.png"/></a> <a href="https://stormlikes.com/"><img title="Stormlikes" width="256" src="https://joplinapp.org/images/sponsors/Stormlikes.png"/></a> <a href="https://route4me.com"><img title="Route4Me" width="256" src="https://joplinapp.org/images/sponsors/Route4Me.png"/></a> <a href="https://topagency.webflow.io"><img title="WebDesignAgency" width="256" src="https://joplinapp.org/images/sponsors/WebDesignAgency.png" alt="topagency"/></a> <a href="https://essayshark.com"><img title="EssayShark - essay writers for hire" width="256" src="https://joplinapp.org/images/sponsors/EssayShark.png" alt="EssayShark - essay writers for hire"/></a> <a href="https://pokieslab1.com/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/PokiesLab.png" alt="Australian Real Money Pokies"/></a> <a href="https://pokiesman1.net/real-money-pokies/"><img title="Australian Real Money Pokies" width="256" src="https://joplinapp.org/images/sponsors/Pokiesman.png" alt="Australian Real Money Pokies"/></a> <a href="https://socialkings.online"><img title="Boost your reach and buy real followers" width="256" src="https://joplinapp.org/images/sponsors/SocialKings.png" alt="Boost your reach and buy real followers"/></a> <a href="https://essayservice.com/"><img title="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines" width="256" src="https://joplinapp.org/images/sponsors/EssayService.png" alt="For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines"/></a> <a href="https://thenationonlineng.net/casino-en-ligne/casino-en-ligne-payant-au-canada/"><img title="casino en ligne le plus payant" width="256" src="https://joplinapp.org/images/sponsors/TheNationOnline.jpg" alt="casino en ligne le plus payant"/></a>
|
||||
<!-- SPONSORS-ORG -->
|
||||
|
||||
* * *
|
||||
|
||||
@@ -646,6 +646,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
|
||||
useCustomPdfViewer: props.useCustomPdfViewer,
|
||||
noteId: props.noteId,
|
||||
vendorDir: bridge().vendorDir(),
|
||||
showNoteLinkIcon: props.showNoteLinkIcon,
|
||||
}));
|
||||
|
||||
if (cancelled) return;
|
||||
@@ -666,7 +667,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
|
||||
shim.clearTimeout(timeoutId);
|
||||
};
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [props.content, props.contentKey, renderedBodyContentKey, props.contentMarkupLanguage, props.visiblePanes, props.resourceInfos, props.markupToHtml]);
|
||||
}, [props.content, props.contentKey, renderedBodyContentKey, props.contentMarkupLanguage, props.visiblePanes, props.resourceInfos, props.markupToHtml, props.showNoteLinkIcon]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!webviewReady) return;
|
||||
|
||||
@@ -222,6 +222,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
|
||||
noteId: props.noteId,
|
||||
vendorDir: bridge().vendorDir(),
|
||||
globalSettings: getGlobalSettings(Setting),
|
||||
showNoteLinkIcon: props.showNoteLinkIcon,
|
||||
}));
|
||||
|
||||
if (cancelled) return;
|
||||
@@ -244,7 +245,7 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
|
||||
}, [
|
||||
props.content, props.contentKey, renderedBodyContentKey, props.contentMarkupLanguage,
|
||||
props.visiblePanes, props.resourceInfos, props.markupToHtml, props.contentMaxWidth,
|
||||
props.noteId, props.useCustomPdfViewer,
|
||||
props.noteId, props.useCustomPdfViewer, props.showNoteLinkIcon,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -474,6 +474,7 @@ function NoteEditorContent(props: NoteEditorProps) {
|
||||
noteId: props.noteId,
|
||||
watchedNoteFiles: props.watchedNoteFiles,
|
||||
enableHtmlToMarkdownBanner: props.enableHtmlToMarkdownBanner,
|
||||
showNoteLinkIcon: props.showNoteLinkIcon,
|
||||
};
|
||||
|
||||
let editor = null;
|
||||
@@ -767,6 +768,7 @@ const mapStateToProps = (state: AppState, ownProps: ConnectProps) => {
|
||||
searchResults: state.searchResults,
|
||||
enableHtmlToMarkdownBanner: state.settings['editor.enableHtmlToMarkdownBanner'],
|
||||
enableInEditorRendering: state.settings['editor.inlineRendering'],
|
||||
showNoteLinkIcon: state.settings['notes.showNoteLinkIcon'],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ export interface NoteEditorProps {
|
||||
bodyEditor: NoteBodyEditorType;
|
||||
startupPluginsLoaded: boolean;
|
||||
enableHtmlToMarkdownBanner: boolean;
|
||||
showNoteLinkIcon: boolean;
|
||||
}
|
||||
|
||||
export interface NoteBodyEditorRef {
|
||||
@@ -156,6 +157,7 @@ export interface NoteBodyEditorProps {
|
||||
useCustomPdfViewer: boolean;
|
||||
watchedNoteFiles: string[];
|
||||
enableHtmlToMarkdownBanner: boolean;
|
||||
showNoteLinkIcon: boolean;
|
||||
}
|
||||
|
||||
export interface NoteBodyEditorPropsAndRef extends NoteBodyEditorProps {
|
||||
|
||||
@@ -95,12 +95,18 @@ const useConnectToEditorPlugin = ({
|
||||
}, [activeEditorView, editorPluginHandler]);
|
||||
|
||||
const formNoteBody = formNote.body;
|
||||
const formNoteId = formNote.id;
|
||||
useEffect(() => {
|
||||
// Don't emit updates when formNote hasn't loaded the current note yet.
|
||||
// This can happen during note navigation when effectiveNoteId updates
|
||||
// immediately but formNote still contains the previous note's data.
|
||||
if (formNoteId !== effectiveNoteId) return;
|
||||
|
||||
editorPluginHandler.emitUpdate({
|
||||
noteId: effectiveNoteId,
|
||||
newBody: formNoteBody,
|
||||
}, shownEditorViewIds);
|
||||
}, [effectiveNoteId, formNoteBody, editorPluginHandler, shownEditorViewIds]);
|
||||
}, [effectiveNoteId, formNoteId, formNoteBody, editorPluginHandler, shownEditorViewIds]);
|
||||
};
|
||||
|
||||
export default useConnectToEditorPlugin;
|
||||
|
||||
@@ -35,6 +35,7 @@ interface Props {
|
||||
customCss: string;
|
||||
scrollbarSize: ScrollbarSize;
|
||||
fontFamily: string;
|
||||
showNoteLinkIcon: boolean;
|
||||
}
|
||||
|
||||
const useNoteContent = (
|
||||
@@ -45,6 +46,7 @@ const useNoteContent = (
|
||||
customCss: string,
|
||||
scrollbarSize: ScrollbarSize,
|
||||
fontFamily: string,
|
||||
showNoteLinkIcon: boolean,
|
||||
) => {
|
||||
const [note, setNote] = useState<NoteEntity>(null);
|
||||
|
||||
@@ -75,17 +77,18 @@ const useNoteContent = (
|
||||
resources: await shared.attachedResources(noteBody),
|
||||
whiteBackgroundNoteRendering: markupLanguage === MarkupLanguage.Html,
|
||||
globalSettings: getGlobalSettings(Setting),
|
||||
showNoteLinkIcon,
|
||||
});
|
||||
|
||||
viewerRef.current.setHtml(result.html, {
|
||||
pluginAssets: result.pluginAssets,
|
||||
});
|
||||
}, [note, viewerRef]);
|
||||
}, [note, viewerRef, markupToHtml, showNoteLinkIcon]);
|
||||
|
||||
return note;
|
||||
};
|
||||
|
||||
const NoteRevisionViewerComponent: React.FC<Props> = ({ themeId, noteId, onBack, customCss, scrollbarSize, fontFamily }) => {
|
||||
const NoteRevisionViewerComponent: React.FC<Props> = ({ themeId, noteId, onBack, customCss, scrollbarSize, fontFamily, showNoteLinkIcon }) => {
|
||||
const helpButton_onClick = useCallback(() => {}, []);
|
||||
const viewerRef = useRef<NoteViewerControl|null>(null);
|
||||
const revisionListRef = useRef<HTMLSelectElement|null>(null);
|
||||
@@ -96,7 +99,7 @@ const NoteRevisionViewerComponent: React.FC<Props> = ({ themeId, noteId, onBack,
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
|
||||
const note = useNoteContent(
|
||||
viewerRef, currentRevId, revisions, themeId, customCss, scrollbarSize, fontFamily,
|
||||
viewerRef, currentRevId, revisions, themeId, customCss, scrollbarSize, fontFamily, showNoteLinkIcon,
|
||||
);
|
||||
|
||||
const viewer_domReady = useCallback(async () => {
|
||||
@@ -229,6 +232,7 @@ const mapStateToProps = (state: AppState) => {
|
||||
themeId: state.settings.theme,
|
||||
scrollbarSize: state.settings['style.scrollbarSize'],
|
||||
fontFamily: state.settings['style.viewer.fontFamily'],
|
||||
showNoteLinkIcon: state.settings['notes.showNoteLinkIcon'],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -28,12 +28,19 @@ const useScrollToSelectionHandler = (
|
||||
return lastSelectedItemKey.current;
|
||||
}
|
||||
}, [listItems, selectedIndex]);
|
||||
lastSelectedItemKey.current = selectedItemKey;
|
||||
|
||||
const selectedIndexRef = useRef(selectedIndex);
|
||||
selectedIndexRef.current = selectedIndex;
|
||||
|
||||
useEffect(() => {
|
||||
// Skip scrolling if the selected item hasn't actually changed. When a folder is
|
||||
// expanded or collapsed the selected item's index may shift, but its key stays
|
||||
// the same — in that case we don't want to scroll the view.
|
||||
if (selectedItemKey === lastSelectedItemKey.current) {
|
||||
return;
|
||||
}
|
||||
lastSelectedItemKey.current = selectedItemKey;
|
||||
|
||||
if (!itemListRef.current || !selectedItemKey) return;
|
||||
|
||||
const hasFocus = !!itemListRef.current.container.contains(document.activeElement);
|
||||
|
||||
@@ -54,12 +54,42 @@ type ItemContextMenuListener = MouseEventHandler<HTMLElement>;
|
||||
|
||||
const menuUtils = new MenuUtils(CommandService.instance());
|
||||
|
||||
// Checks whether an element is at least partially visible within a scrollable
|
||||
// container by comparing their bounding rectangles.
|
||||
const isElementVisibleInContainer = (element: HTMLElement, container: HTMLElement) => {
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
|
||||
return elementRect.bottom > containerRect.top && elementRect.top < containerRect.bottom;
|
||||
};
|
||||
|
||||
const focusListItem = (item: HTMLElement|null) => {
|
||||
if (item) {
|
||||
// Avoid scrolling to the selected item when refocusing the note list. Such a refocus
|
||||
// can happen if the note list rerenders and the selection is scrolled out of view and
|
||||
// can cause scroll to change unexpectedly.
|
||||
focus('useOnRenderItem', item, { preventScroll: true });
|
||||
const activeElement = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
||||
const itemList = item.closest('.item-list');
|
||||
const activeTreeItem = activeElement?.closest('[role="treeitem"]');
|
||||
const focusWasLost = activeElement === document.body;
|
||||
|
||||
// If the currently focused element is a tree item inside the same list,
|
||||
// the user is navigating with the keyboard — always allow focus to move
|
||||
// to the newly selected item so arrow-key scrolling is not interrupted.
|
||||
const isKeyboardNavigating = !!activeTreeItem && itemList?.contains(activeTreeItem);
|
||||
|
||||
// Avoid disturbing scroll while user is manually scrolling through the list.
|
||||
// However, if focus was lost (activeElement -> <body>), or the user is
|
||||
// navigating with the keyboard, allow re-focusing even when the selected
|
||||
// item is currently out of view.
|
||||
if (itemList instanceof HTMLElement && !isElementVisibleInContainer(item, itemList) && !focusWasLost && !isKeyboardNavigating) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Move focus only if needed: either focus was lost, or selection changed
|
||||
// to a different tree item.
|
||||
if (focusWasLost || activeTreeItem !== item) {
|
||||
// preventScroll: true avoids a secondary scroll caused by the focus() call
|
||||
// itself when the item is near the edge of the visible area.
|
||||
focus('useOnRenderItem', item, { preventScroll: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -363,7 +393,12 @@ const useOnRenderItem = (props: Props) => {
|
||||
multipleItemsSelected: props.selectedIndexes.length > 1,
|
||||
};
|
||||
|
||||
const focusInList = document.hasFocus() && props.containerRef.current?.contains(document.activeElement);
|
||||
const sidebarContainsFocus = props.containerRef.current?.contains(document.activeElement);
|
||||
// Focus moves to <body> when the previously-focused element is removed
|
||||
// from the DOM (e.g. scrolled out of the virtualized list). We still
|
||||
// want to restore focus to the newly-selected item in that case.
|
||||
const focusLostFromDom = document.activeElement === document.body;
|
||||
const focusInList = document.hasFocus() && (sidebarContainsFocus || focusLostFromDom);
|
||||
const anchorRef = (focusInList && primarySelected) ? focusListItem : noFocusListItem;
|
||||
|
||||
if (item.kind === ListItemType.Tag) {
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
ul ul, ul ol, ol ul, ol ol {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
::highlight(search-results) {
|
||||
background-color: #f7d26e;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -503,7 +507,7 @@
|
||||
if (!options) options = {};
|
||||
|
||||
// TODO: Add support for scriptType on mobile and CLI
|
||||
|
||||
CSS.highlights.clear();
|
||||
if (!mark_) {
|
||||
mark_ = new Mark(document.getElementById('joplin-container-content'), {
|
||||
exclude: ['img'],
|
||||
@@ -519,7 +523,8 @@
|
||||
|
||||
let selectedElement = null;
|
||||
let elementIndex = 0;
|
||||
|
||||
|
||||
const allRanges = [];
|
||||
const markKeywordOptions = {};
|
||||
|
||||
if ('separateWordSearch' in options) markKeywordOptions.separateWordSearch = options.separateWordSearch;
|
||||
@@ -527,9 +532,17 @@
|
||||
try {
|
||||
for (const keyword of keywords) {
|
||||
markJsUtils.markKeyword(mark_, keyword, {
|
||||
pregQuote: pregQuote,
|
||||
replaceRegexDiacritics: replaceRegexDiacritics,
|
||||
}, markKeywordOptions);
|
||||
pregQuote: pregQuote,
|
||||
replaceRegexDiacritics: replaceRegexDiacritics,
|
||||
}, {
|
||||
...markKeywordOptions,
|
||||
element: 'mark-ghost',
|
||||
each: (node) => {
|
||||
const range = new Range();
|
||||
range.selectNodeContents(node);
|
||||
allRanges.push(range);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.name !== 'SyntaxError') {
|
||||
@@ -540,6 +553,10 @@
|
||||
// https://github.com/laurent22/joplin/issues/7634
|
||||
console.error('Error while trying to highlight words from search: ', error);
|
||||
}
|
||||
if (allRanges.length > 0) {
|
||||
const searchResultsHighlight = new Highlight(...allRanges);
|
||||
CSS.highlights.set("search-results", searchResultsHighlight);
|
||||
}
|
||||
}
|
||||
|
||||
let markLoader_ = { state: 'idle', whenDone: null };
|
||||
@@ -809,6 +826,37 @@
|
||||
);
|
||||
}));
|
||||
|
||||
// By default, Chromium inlines body styles (e.g. theme background color) into the clipboard HTML.
|
||||
// Intercept the copy event and write only the selected content to bypass this behaviour.
|
||||
document.addEventListener('copy', webviewLib.logEnabledEventHandler(e => {
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.isCollapsed) return;
|
||||
if (selection.rangeCount === 0 || !e.clipboardData) return;
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.appendChild(range.cloneContents());
|
||||
|
||||
wrapper.querySelectorAll('style').forEach(s => s.remove());
|
||||
|
||||
const inlineTags = new Set(['STRONG', 'EM', 'CODE', 'S', 'DEL', 'INS', 'MARK', 'SUP', 'SUB', 'U', 'SPAN', 'A']);
|
||||
let node = range.commonAncestorContainer;
|
||||
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
||||
|
||||
while (node && node !== document.body && node.id !== 'rendered-md' && node.id !== 'joplin-container-content') {
|
||||
if (inlineTags.has(node.tagName)) {
|
||||
const el = node.cloneNode(false);
|
||||
while (wrapper.firstChild) el.appendChild(wrapper.firstChild);
|
||||
wrapper.appendChild(el);
|
||||
}
|
||||
node = node.parentElement;
|
||||
}
|
||||
|
||||
e.clipboardData.setData('text/html', wrapper.innerHTML);
|
||||
e.clipboardData.setData('text/plain', selection.toString());
|
||||
e.preventDefault();
|
||||
}));
|
||||
|
||||
let lastClientWidth_ = NaN, lastClientHeight_ = NaN, lastScrollTop_ = NaN;
|
||||
|
||||
window.addEventListener('resize', webviewLib.logEnabledEventHandler(() => {
|
||||
|
||||
@@ -161,7 +161,7 @@ test.describe('markdownEditor', () => {
|
||||
const viewer = noteEditor.getNoteViewerFrameLocator();
|
||||
await expect(viewer.locator('h1')).toHaveText('Testing');
|
||||
|
||||
const matches = viewer.locator('mark');
|
||||
const matches = viewer.locator('mark-ghost');
|
||||
await expect(matches).toHaveCount(0);
|
||||
|
||||
await mainWindow.keyboard.press(process.platform === 'darwin' ? 'Meta+f' : 'Control+f');
|
||||
@@ -404,5 +404,35 @@ test.describe('markdownEditor', () => {
|
||||
await activateMainMenuItem(electronApp, 'Redo');
|
||||
await noteEditor.expectToHaveText('A');
|
||||
});
|
||||
});
|
||||
|
||||
test('copying from the preview pane should not include theme background color and should preserve bold formatting', async ({ mainWindow, electronApp }) => {
|
||||
// Set dark theme so background-color would be present in clipboard without the fix
|
||||
await setSettingValue(electronApp, mainWindow, 'theme', 2);
|
||||
|
||||
const mainScreen = await new MainScreen(mainWindow).setup();
|
||||
await mainScreen.waitFor();
|
||||
|
||||
await mainScreen.createNewNote('Test copy formatting');
|
||||
const noteEditor = mainScreen.noteEditor;
|
||||
await noteEditor.focusCodeMirrorEditor();
|
||||
await mainWindow.keyboard.type('**hello**');
|
||||
|
||||
const viewerFrame = noteEditor.getNoteViewerFrameLocator();
|
||||
await expect(viewerFrame.locator('strong')).toHaveText('hello');
|
||||
|
||||
// Double-click selects the text node inside <strong>, not <strong> itself.
|
||||
// Without the ancestor re-wrapping fix, <strong> would be dropped.
|
||||
await viewerFrame.locator('strong').dblclick();
|
||||
const modifier = process.platform === 'darwin' ? 'Meta' : 'Control';
|
||||
await mainWindow.keyboard.press(`${modifier}+c`);
|
||||
|
||||
const clipboardHtml = await mainWindow.evaluate(() => {
|
||||
const { clipboard } = require('electron');
|
||||
return clipboard.readHTML();
|
||||
});
|
||||
|
||||
expect(clipboardHtml).toContain('hello');
|
||||
expect(clipboardHtml).not.toMatch(/background-color\s*:/i);
|
||||
expect(clipboardHtml).toContain('<strong>');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { test, expect } from './util/test';
|
||||
import MainScreen from './models/MainScreen';
|
||||
import { msleep, Second } from '@joplin/utils/time';
|
||||
import setSettingValue from './util/setSettingValue';
|
||||
|
||||
test.describe('pluginApi', () => {
|
||||
test('the editor.setText command should update the current note (use RTE: false)', async ({ startAppWithPlugins }) => {
|
||||
@@ -80,6 +81,30 @@ test.describe('pluginApi', () => {
|
||||
await expectVisible(false);
|
||||
});
|
||||
|
||||
// Regression tests for #13718
|
||||
for (const method of ['Cancel button', 'Escape key'] as const) {
|
||||
test(`should dismiss a plugin dialog via ${method} with isolated iframes`, async ({ startAppWithPlugins }) => {
|
||||
const { app, mainWindow } = await startAppWithPlugins(['resources/test-plugins/dialogs.js']);
|
||||
const mainScreen = await new MainScreen(mainWindow).setup();
|
||||
await mainScreen.createNewNote('Test note');
|
||||
|
||||
// WebView isolation is currently behind a feature flag:
|
||||
await setSettingValue(app, mainWindow, 'featureFlag.plugins.isolatePluginWebViews', true);
|
||||
|
||||
await mainScreen.goToAnything.runCommand(app, 'showTestDialogWithDismiss');
|
||||
const dialogContent = mainScreen.dialog.locator('iframe').contentFrame();
|
||||
await dialogContent.locator('p').waitFor();
|
||||
|
||||
if (method === 'Cancel button') {
|
||||
await mainScreen.dialog.getByRole('button', { name: 'Cancel' }).click();
|
||||
} else {
|
||||
await mainWindow.keyboard.press('Escape');
|
||||
}
|
||||
|
||||
await expect(mainScreen.dialog).toBeHidden();
|
||||
});
|
||||
}
|
||||
|
||||
test('should be possible to create multiple toasts with the same text from a plugin', async ({ startAppWithPlugins }) => {
|
||||
const { app, mainWindow } = await startAppWithPlugins(['resources/test-plugins/showToast.js']);
|
||||
const mainScreen = await new MainScreen(mainWindow).setup();
|
||||
|
||||
@@ -48,6 +48,21 @@ joplin.plugins.register({
|
||||
},
|
||||
});
|
||||
|
||||
const dismissDialogHandle = await dialogs.create('test-dialog-with-dismiss');
|
||||
await dialogs.setHtml(dismissDialogHandle, '<p>Press Escape to dismiss</p>');
|
||||
await dialogs.setButtons(dismissDialogHandle, [
|
||||
{ id: 'ok', title: 'Okay' },
|
||||
{ id: 'cancel', title: 'Cancel' },
|
||||
]);
|
||||
await joplin.commands.register({
|
||||
name: 'showTestDialogWithDismiss',
|
||||
label: 'showTestDialogWithDismiss',
|
||||
execute: async () => {
|
||||
const result = await joplin.views.dialogs.open(dismissDialogHandle);
|
||||
await joplin.commands.execute('editor.setText', result.id);
|
||||
},
|
||||
});
|
||||
|
||||
await joplin.commands.register({
|
||||
name: 'getTestDialogVisibility',
|
||||
label: 'Returns the dialog visibility state',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "3.6.2",
|
||||
"version": "3.6.3",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.bundle.js",
|
||||
"private": true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { useRef, useCallback } from 'react';
|
||||
import { useRef, useCallback, useMemo } from 'react';
|
||||
import { ButtonSpec, DialogResult } from '@joplin/lib/services/plugins/api/types';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import WebviewController from '@joplin/lib/services/plugins/WebviewController';
|
||||
@@ -76,8 +76,16 @@ export default function UserWebviewDialog(props: Props) {
|
||||
if (webviewRef.current) focus('UserWebviewDialog', webviewRef.current);
|
||||
}, []);
|
||||
|
||||
// When the iframe is isolated (security setting enabled), keyboard events
|
||||
// like Escape don't reach the iframe content. We let the native <dialog>
|
||||
// handle Escape by passing onCancel, but only when there's a dismiss button.
|
||||
// https://github.com/laurent22/joplin/issues/13718
|
||||
const onCancel = useMemo(() => {
|
||||
return findDismissButton(buttons) ? onDismiss : undefined;
|
||||
}, [buttons, onDismiss]);
|
||||
|
||||
return (
|
||||
<Dialog className={`user-webview-dialog ${props.fitToContent ? '-fit' : ''}`}>
|
||||
<Dialog className={`user-webview-dialog ${props.fitToContent ? '-fit' : ''}`} onCancel={onCancel}>
|
||||
<div className='user-dialog-wrapper'>
|
||||
<UserWebview
|
||||
ref={webviewRef}
|
||||
|
||||
@@ -83,8 +83,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097800
|
||||
versionName "3.6.12"
|
||||
versionCode 2097801
|
||||
versionName "3.6.13"
|
||||
|
||||
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ const useStyles = (themeId: number, containerStyle: ViewStyle, size: DialogVaria
|
||||
},
|
||||
closeButton: {
|
||||
margin: 0,
|
||||
marginRight: -8,
|
||||
},
|
||||
// Ensure that the close button is aligned with the center of the header:
|
||||
// Make its container smaller and center it.
|
||||
@@ -91,8 +92,8 @@ const useStyles = (themeId: number, containerStyle: ViewStyle, size: DialogVaria
|
||||
dialogSurface: {
|
||||
borderRadius: 24,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 24,
|
||||
paddingHorizontal: theme.margin,
|
||||
paddingVertical: theme.margin,
|
||||
...dialogSizing,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Store } from 'redux';
|
||||
import { AppState } from '../utils/types';
|
||||
import TestProviderStack from './testing/TestProviderStack';
|
||||
import { switchClient, setupDatabase, mockMobilePlatform, mockFetch } from '@joplin/lib/testing/test-utils';
|
||||
import waitFor from '@joplin/lib/testing/waitFor';
|
||||
import createMockReduxStore from '../utils/testing/createMockReduxStore';
|
||||
import setupGlobalStore from '../utils/testing/setupGlobalStore';
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react-native';
|
||||
import FeedbackBanner from './FeedbackBanner';
|
||||
import { MobilePlatform } from '@joplin/lib/shim';
|
||||
|
||||
interface WrapperProps { }
|
||||
|
||||
let store: Store<AppState>;
|
||||
const WrappedFeedbackBanner: React.FC<WrapperProps> = () => {
|
||||
return <TestProviderStack store={store}>
|
||||
<FeedbackBanner/>
|
||||
</TestProviderStack>;
|
||||
};
|
||||
|
||||
const getFeedbackButton = (positive: boolean) => {
|
||||
return screen.getByRole('button', { name: positive ? 'Useful' : 'Not useful' });
|
||||
};
|
||||
|
||||
const getSurveyLink = () => {
|
||||
return screen.getByRole('button', { name: 'Take survey' });
|
||||
};
|
||||
|
||||
const mockFeedbackServer = (surveyName = 'web-app-test') => {
|
||||
let helpfulCount = 0;
|
||||
let unhelpfulCount = 0;
|
||||
|
||||
const { reset } = mockFetch((request) => {
|
||||
const surveyBaseUrls = [
|
||||
'https://objects.joplinusercontent.com/',
|
||||
'http://localhost:3430/',
|
||||
];
|
||||
const isSurveyRequest = surveyBaseUrls.some(url => request.url.startsWith(url));
|
||||
if (!isSurveyRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (url.pathname === `/r/survey--${surveyName}--helpful`) {
|
||||
helpfulCount ++;
|
||||
} else if (url.pathname === `/r/survey--${surveyName}--unhelpful`) {
|
||||
unhelpfulCount ++;
|
||||
} else {
|
||||
return new Response('Not found', { status: 404 });
|
||||
}
|
||||
|
||||
// The feedback server always redirects to another URL after a
|
||||
// successful request. Mock this by always redirecting to the
|
||||
// same URL.
|
||||
return new Response('', {
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302
|
||||
status: 302,
|
||||
statusText: 'Found',
|
||||
headers: [
|
||||
['location', 'https://joplinapp.org'],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
reset,
|
||||
get helpfulCount() {
|
||||
return helpfulCount;
|
||||
},
|
||||
get unhelpfulCount() {
|
||||
return unhelpfulCount;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
describe('FeedbackBanner', () => {
|
||||
const resetMobilePlatform = ()=>{};
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabase(0);
|
||||
await switchClient(0);
|
||||
|
||||
store = createMockReduxStore();
|
||||
setupGlobalStore(store);
|
||||
|
||||
jest.useFakeTimers({ advanceTimers: true });
|
||||
mockMobilePlatform(MobilePlatform.Web);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
screen.unmount();
|
||||
resetMobilePlatform();
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ platform: MobilePlatform.Android, shouldShow: false },
|
||||
{ platform: MobilePlatform.Web, shouldShow: true },
|
||||
{ platform: MobilePlatform.Ios, shouldShow: false },
|
||||
])('should correctly show/hide the feedback banner on %s', ({ platform, shouldShow }) => {
|
||||
mockMobilePlatform(platform);
|
||||
|
||||
render(<WrappedFeedbackBanner />);
|
||||
|
||||
const header = screen.queryByRole('header', { name: 'Feedback' });
|
||||
if (shouldShow) {
|
||||
expect(header).toBeVisible();
|
||||
} else {
|
||||
expect(header).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
test('clicking the "Useful" button should submit the response and show the "take survey" link', async () => {
|
||||
const feedbackServerMock = mockFeedbackServer();
|
||||
render(<WrappedFeedbackBanner />);
|
||||
|
||||
try {
|
||||
const usefulButton = getFeedbackButton(true);
|
||||
fireEvent.press(usefulButton);
|
||||
|
||||
await act(() => waitFor(async () => {
|
||||
expect(getSurveyLink()).toBeVisible();
|
||||
}));
|
||||
|
||||
expect(feedbackServerMock).toMatchObject({
|
||||
helpfulCount: 1,
|
||||
unhelpfulCount: 0,
|
||||
});
|
||||
} finally {
|
||||
feedbackServerMock.reset();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,216 +0,0 @@
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import * as React from 'react';
|
||||
import { View, StyleSheet, useWindowDimensions, TextStyle, Linking } from 'react-native';
|
||||
import { Portal, Text } from 'react-native-paper';
|
||||
import IconButton from './IconButton';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import { Dispatch } from 'redux';
|
||||
import { themeStyle } from './global-style';
|
||||
import { AppState } from '../utils/types';
|
||||
import { connect } from 'react-redux';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { LinkButton } from './buttons';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { SurveyProgress } from '@joplin/lib/models/settings/builtInMetadata';
|
||||
|
||||
const logger = Logger.create('FeedbackBanner');
|
||||
|
||||
interface Props {
|
||||
dispatch: Dispatch;
|
||||
progress: SurveyProgress;
|
||||
surveyKey: string;
|
||||
themeId: number;
|
||||
}
|
||||
|
||||
const useStyles = (themeId: number, sentFeedback: boolean) => {
|
||||
const { width: windowWidth } = useWindowDimensions();
|
||||
return useMemo(() => {
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
const iconBaseStyle: TextStyle = {
|
||||
fontSize: 24,
|
||||
color: theme.color3,
|
||||
};
|
||||
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: theme.backgroundColor3,
|
||||
borderTopRightRadius: 16,
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'row',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
maxWidth: windowWidth - 50,
|
||||
gap: 18,
|
||||
padding: 12,
|
||||
},
|
||||
contentRight: {
|
||||
display: sentFeedback ? 'none' : 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 16,
|
||||
},
|
||||
header: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
iconUseful: {
|
||||
...iconBaseStyle,
|
||||
color: theme.colorCorrect,
|
||||
},
|
||||
iconNotUseful: {
|
||||
...iconBaseStyle,
|
||||
color: theme.colorWarn,
|
||||
},
|
||||
dismissButtonIcon: {
|
||||
fontSize: 16,
|
||||
color: theme.color2,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
dismissButton: {
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
borderColor: theme.backgroundColor,
|
||||
borderWidth: 2,
|
||||
width: 29,
|
||||
height: 29,
|
||||
borderRadius: 14,
|
||||
position: 'absolute',
|
||||
top: -16,
|
||||
right: -16,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
dismissButtonContent: {
|
||||
flexShrink: 1,
|
||||
},
|
||||
});
|
||||
}, [themeId, windowWidth, sentFeedback]);
|
||||
};
|
||||
|
||||
const useSurveyUrl = (surveyKey: string) => {
|
||||
return useMemo(() => {
|
||||
let baseUrl = 'https://objects.joplinusercontent.com/';
|
||||
|
||||
// For testing with a locally-hosted server:
|
||||
const useLocalServer = false;
|
||||
if (Setting.value('env') === 'dev' && useLocalServer) {
|
||||
baseUrl = 'http://localhost:3430/';
|
||||
}
|
||||
|
||||
return `${baseUrl}r/survey--${encodeURIComponent(surveyKey)}`;
|
||||
}, [surveyKey]);
|
||||
};
|
||||
|
||||
const setProgress = (progress: SurveyProgress) => {
|
||||
Setting.setValue('survey.webClientEval2025.progress', progress);
|
||||
};
|
||||
|
||||
const onDismiss = () => {
|
||||
setProgress(SurveyProgress.Dismissed);
|
||||
};
|
||||
|
||||
const FeedbackBanner: React.FC<Props> = props => {
|
||||
const surveyUrl = useSurveyUrl(props.surveyKey);
|
||||
const sentFeedback = props.progress === SurveyProgress.Started;
|
||||
|
||||
const sendSurveyResponse = useCallback(async (surveyResponse: string) => {
|
||||
const fetchUrl = `${surveyUrl}--${encodeURIComponent(surveyResponse)}`;
|
||||
logger.debug('sending response to', fetchUrl);
|
||||
const showError = (message: string) => {
|
||||
logger.error('Error', message);
|
||||
void shim.showErrorDialog(
|
||||
_('An error occurred while sending the response. This can happen if the app is offline or cannot connect to the server.\nError: %s', message),
|
||||
);
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await shim.fetch(fetchUrl);
|
||||
// The server currently redirects (status 302) in response
|
||||
// to many survey-related requests. This may be returned by
|
||||
// the web app service worker as a 200 OK response, however. Support both:
|
||||
if (response.ok || response.status === 302) {
|
||||
setProgress(SurveyProgress.Started);
|
||||
} else {
|
||||
const body = await response.text();
|
||||
showError(`Server error: ${response.status} ${body}`);
|
||||
}
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
}
|
||||
}, [surveyUrl]);
|
||||
|
||||
const onSurveyLinkClick = useCallback(() => {
|
||||
void Linking.openURL(surveyUrl);
|
||||
onDismiss();
|
||||
}, [surveyUrl]);
|
||||
|
||||
const onNotUsefulClick = useCallback(() => {
|
||||
void sendSurveyResponse('unhelpful');
|
||||
}, [sendSurveyResponse]);
|
||||
|
||||
const onUsefulClick = useCallback(() => {
|
||||
void sendSurveyResponse('helpful');
|
||||
}, [sendSurveyResponse]);
|
||||
|
||||
const styles = useStyles(props.themeId, sentFeedback);
|
||||
|
||||
const renderStatusMessage = () => {
|
||||
if (sentFeedback) {
|
||||
return <View>
|
||||
<Text>{_('Thank you for the feedback!\nDo you have time to complete a short survey?')}</Text>
|
||||
<LinkButton onPress={onSurveyLinkClick}>{_('Take survey')}</LinkButton>
|
||||
</View>;
|
||||
} else {
|
||||
return <Text>{_('Do you find the Joplin web app useful?')}</Text>;
|
||||
}
|
||||
};
|
||||
|
||||
if (shim.mobilePlatform() !== 'web' || props.progress === SurveyProgress.Dismissed) return null;
|
||||
|
||||
return <Portal>
|
||||
<View style={styles.container} role='complementary'>
|
||||
<View>
|
||||
<Text
|
||||
accessibilityRole='header'
|
||||
variant='titleMedium'
|
||||
style={styles.header}
|
||||
>{_('Feedback')}</Text>
|
||||
<Text>{renderStatusMessage()}</Text>
|
||||
</View>
|
||||
<View style={styles.contentRight}>
|
||||
<IconButton
|
||||
iconName='fas times'
|
||||
themeId={props.themeId}
|
||||
onPress={onNotUsefulClick}
|
||||
description={_('Not useful')}
|
||||
iconStyle={styles.iconNotUseful}
|
||||
/>
|
||||
<IconButton
|
||||
iconName='fas check'
|
||||
themeId={props.themeId}
|
||||
onPress={onUsefulClick}
|
||||
description={_('Useful')}
|
||||
iconStyle={styles.iconUseful}
|
||||
/>
|
||||
</View>
|
||||
<IconButton
|
||||
iconName='fas times'
|
||||
themeId={props.themeId}
|
||||
onPress={onDismiss}
|
||||
description={_('Dismiss')}
|
||||
iconStyle={styles.dismissButtonIcon}
|
||||
contentWrapperStyle={styles.dismissButtonContent}
|
||||
containerStyle={styles.dismissButton}
|
||||
/>
|
||||
</View>
|
||||
</Portal>;
|
||||
};
|
||||
|
||||
export default connect((state: AppState) => ({
|
||||
themeId: state.settings.theme,
|
||||
surveyKey: 'web-app-test',
|
||||
progress: state.settings['survey.webClientEval2025.progress'],
|
||||
}))(FeedbackBanner);
|
||||
@@ -34,6 +34,7 @@ interface Props {
|
||||
onScroll: OnScrollCallback;
|
||||
onLoadEnd?: ()=> void;
|
||||
pluginStates: PluginStates;
|
||||
showNoteLinkIcon: boolean;
|
||||
}
|
||||
|
||||
const onJoplinLinkClick = async (message: string) => {
|
||||
@@ -84,6 +85,7 @@ function NoteBodyViewer(props: Props) {
|
||||
initialScrollPercent: props.initialScrollPercent,
|
||||
|
||||
paddingBottom: props.paddingBottom,
|
||||
showNoteLinkIcon: props.showNoteLinkIcon,
|
||||
});
|
||||
|
||||
const onLoadEnd = useCallback(() => {
|
||||
@@ -115,4 +117,5 @@ export default connect((state: AppState) => ({
|
||||
themeId: state.settings.theme,
|
||||
fontSize: state.settings['style.viewer.fontSize'],
|
||||
pluginStates: state.pluginService.plugins,
|
||||
showNoteLinkIcon: state.settings['notes.showNoteLinkIcon'],
|
||||
}))(NoteBodyViewer);
|
||||
|
||||
@@ -27,6 +27,7 @@ interface Props {
|
||||
initialScrollPercent: number|undefined;
|
||||
|
||||
paddingBottom: number;
|
||||
showNoteLinkIcon: boolean;
|
||||
}
|
||||
|
||||
const onlyCheckboxHasChangedHack = (previousBody: string, newBody: string) => {
|
||||
@@ -100,7 +101,7 @@ const useRerenderHandler = (props: Props) => {
|
||||
const effectDependencies = [
|
||||
props.noteBody, props.noteMarkupLanguage, props.renderer, props.highlightedKeywords,
|
||||
props.noteHash, props.noteResources, props.themeId, props.paddingBottom, resourceDownloadRerenderCounter,
|
||||
props.fontSize,
|
||||
props.fontSize, props.showNoteLinkIcon,
|
||||
];
|
||||
const previousDeps = usePrevious(effectDependencies, []);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
@@ -138,6 +139,7 @@ const useRerenderHandler = (props: Props) => {
|
||||
// instead.
|
||||
initialScrollPercent: (previousHash && hashChanged) ? undefined : props.initialScrollPercent,
|
||||
noteHash: props.noteHash,
|
||||
showNoteLinkIcon: props.showNoteLinkIcon,
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Linking, StyleSheet, TextStyle, View, ViewStyle } from 'react-native';
|
||||
import { Text } from 'react-native-paper';
|
||||
import IconButton from '../IconButton';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { useCallback, useState } from 'react';
|
||||
import DismissibleDialog, { DialogVariant } from '../DismissibleDialog';
|
||||
import { LinkButton, PrimaryButton } from '../buttons';
|
||||
import makeDiscourseDebugUrl from '@joplin/lib/makeDiscourseDebugUrl';
|
||||
import getPackageInfo from '../../utils/getPackageInfo';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
|
||||
interface Props {
|
||||
wrapperStyle: ViewStyle;
|
||||
iconStyle: TextStyle;
|
||||
themeId: number;
|
||||
}
|
||||
|
||||
const onLeaveFeedback = () => {
|
||||
void Linking.openURL('https://forms.gle/B5YGDNzsUYBnoPx19');
|
||||
};
|
||||
|
||||
const onReportBug = () => {
|
||||
void Linking.openURL(
|
||||
makeDiscourseDebugUrl('', '', [], getPackageInfo(), PluginService.instance(), Setting.value('plugins.states')),
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
feedbackContainer: {
|
||||
flexGrow: 1,
|
||||
flexDirection: 'row',
|
||||
gap: 16,
|
||||
justifyContent: 'flex-end',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
paragraph: {
|
||||
paddingBottom: 7,
|
||||
},
|
||||
});
|
||||
|
||||
const WebBetaButton: React.FC<Props> = props => {
|
||||
const [dialogVisible, setDialogVisible] = useState(false);
|
||||
|
||||
const onShowDialog = useCallback(() => {
|
||||
setDialogVisible(true);
|
||||
}, []);
|
||||
|
||||
const onHideDialog = useCallback(() => {
|
||||
setDialogVisible(false);
|
||||
}, []);
|
||||
|
||||
const renderParagraph = (content: string) => {
|
||||
return <Text variant='bodyLarge' style={styles.paragraph}>{content}</Text>;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
onPress={onShowDialog}
|
||||
description={_('Beta')}
|
||||
themeId={props.themeId}
|
||||
contentWrapperStyle={props.wrapperStyle}
|
||||
|
||||
iconName="material beta"
|
||||
iconStyle={props.iconStyle}
|
||||
/>
|
||||
<DismissibleDialog
|
||||
heading={_('Beta')}
|
||||
size={DialogVariant.SmallResize}
|
||||
themeId={props.themeId}
|
||||
visible={dialogVisible}
|
||||
onDismiss={onHideDialog}
|
||||
>
|
||||
{renderParagraph('Welcome to the beta version of the Joplin Web App!')}
|
||||
{renderParagraph('Thank you for participating in the beta version of the Joplin Web App.')}
|
||||
{renderParagraph('The Joplin Web App is available for a limited time in open beta and may later join the Joplin Cloud plans.')}
|
||||
{renderParagraph('Feel free to use it and let us know if have any questions or notice any issues!')}
|
||||
<View style={styles.feedbackContainer}>
|
||||
<LinkButton onPress={onReportBug}>{'Report bug'}</LinkButton>
|
||||
<PrimaryButton onPress={onLeaveFeedback}>{'Give feedback'}</PrimaryButton>
|
||||
</View>
|
||||
</DismissibleDialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WebBetaButton;
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { PureComponent, ReactElement } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, ViewStyle, Platform } from 'react-native';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, ViewStyle } from 'react-native';
|
||||
import BackButtonService from '../../services/BackButtonService';
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
import { _, _n } from '@joplin/lib/locale';
|
||||
@@ -20,7 +20,6 @@ import { PluginStates } from '@joplin/lib/services/plugins/reducer';
|
||||
import { ContainerType } from '@joplin/lib/services/plugins/WebviewController';
|
||||
import { Dispatch } from 'redux';
|
||||
import WarningBanner from './WarningBanner';
|
||||
import WebBetaButton from './WebBetaButton';
|
||||
|
||||
import Menu, { MenuOptionType } from './Menu';
|
||||
import shim from '@joplin/lib/shim';
|
||||
@@ -456,18 +455,6 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
);
|
||||
};
|
||||
|
||||
const betaIconButton = () => {
|
||||
if (Platform.OS !== 'web') return null;
|
||||
|
||||
return (
|
||||
<WebBetaButton
|
||||
themeId={themeId}
|
||||
wrapperStyle={this.styles().iconButton}
|
||||
iconStyle={this.styles().topIcon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const renderTogglePluginEditorButton = (styles: any, onPress: OnPressCallback, disabled: boolean) => {
|
||||
if (!this.props.showPluginEditorButton) return null;
|
||||
@@ -666,7 +653,6 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
const sideMenuComp = !showSideMenuButton ? null : sideMenuButton(this.styles(), () => this.sideMenuButton_press());
|
||||
const backButtonComp = !showBackButton ? null : backButton(this.styles(), () => this.backButton_press(), backButtonDisabled);
|
||||
const pluginPanelsComp = pluginPanelToggleButton(this.styles(), () => this.pluginPanelToggleButton_press());
|
||||
const betaIconComp = !showSideMenuButton ? null : betaIconButton();
|
||||
const selectAllButtonComp = !showSelectAllButton ? null : selectAllButton(this.styles(), () => this.selectAllButton_press());
|
||||
const searchButtonComp = !showSearchButton ? null : searchButton(this.styles(), () => this.searchButton_press());
|
||||
const customDeleteButtonComp = this.props.onDeleteButtonPress ? customDeleteButton(this.styles(), this.props.onDeleteButtonPress) : null;
|
||||
@@ -680,7 +666,6 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
// space while in use, we allow certain buttons to be hidden.
|
||||
const hideableRightComponents = <>
|
||||
{pluginPanelsComp}
|
||||
{betaIconComp}
|
||||
{togglePluginEditorButton}
|
||||
{selectAllButtonComp}
|
||||
{searchButtonComp}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Icon, Text } from 'react-native-paper';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import JoplinCloudIcon from './JoplinCloudIcon';
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
import CardButton from '../buttons/CardButton';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
|
||||
@@ -47,6 +47,14 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
const useShouldShowOtherButton = () => {
|
||||
// Always show "other" on non-web platforms
|
||||
if (Platform.OS !== 'web') return true;
|
||||
// Don't show "other" when hosted on Joplin Cloud (other sync
|
||||
// targets can still be selected from settings).
|
||||
return location.origin !== 'https://app.joplincloud.com';
|
||||
};
|
||||
|
||||
interface SyncProviderProps {
|
||||
title: string;
|
||||
icon: ()=> React.ReactNode;
|
||||
@@ -102,6 +110,8 @@ const SyncWizard: React.FC<Props> = ({ themeId, visible, dispatch }) => {
|
||||
await NavService.go('Config', { sectionName: 'sync' });
|
||||
}, [onDismiss]);
|
||||
|
||||
const showOther = useShouldShowOtherButton();
|
||||
|
||||
return <DismissibleDialog
|
||||
themeId={themeId}
|
||||
visible={visible}
|
||||
@@ -126,14 +136,14 @@ const SyncWizard: React.FC<Props> = ({ themeId, visible, dispatch }) => {
|
||||
onPress={onSelectJoplinCloud}
|
||||
disabled={false}
|
||||
/>
|
||||
<SyncProvider
|
||||
{showOther && <SyncProvider
|
||||
title={_('Other')}
|
||||
description={_('Select one of the other supported sync targets.')}
|
||||
icon={() => <Icon size={iconSize} source='dots-horizontal-circle'/>}
|
||||
featuresList={[]}
|
||||
onPress={onSelectOtherTarget}
|
||||
disabled={false}
|
||||
/>
|
||||
/>}
|
||||
</View>
|
||||
</DismissibleDialog>;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ import { themeStyle } from './global-style';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import useKeyboardState from '../utils/hooks/useKeyboardState';
|
||||
import usePrevious from '@joplin/lib/hooks/usePrevious';
|
||||
import FeedbackBanner from './FeedbackBanner';
|
||||
import { Theme } from '@joplin/lib/themes/type';
|
||||
import { useMemo } from 'react';
|
||||
import KeyboardAvoidingView from './KeyboardAvoidingView';
|
||||
@@ -78,7 +77,6 @@ const AppNavComponent: React.FC<Props> = (props) => {
|
||||
<NotesScreen visible={notesScreenVisible} />
|
||||
{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} />}
|
||||
{!notesScreenVisible && !searchScreenVisible && <Screen navigation={{ state: route }} themeId={props.themeId} dispatch={props.dispatch} />}
|
||||
{notesScreenVisible ? <FeedbackBanner/> : null}
|
||||
<View style={{ height: autocompletionBarPadding }} />
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
|
||||
@@ -39,8 +39,6 @@ const styles = (() => {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 20,
|
||||
marginLeft: 10,
|
||||
marginRight: 10,
|
||||
};
|
||||
return StyleSheet.create({
|
||||
descriptionText: {
|
||||
@@ -64,7 +62,7 @@ const styles = (() => {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: 10,
|
||||
paddingVertical: 10,
|
||||
marginTop: 12,
|
||||
marginBottom: 14,
|
||||
},
|
||||
@@ -123,7 +121,7 @@ const PluginInfoModalContent: React.FC<Props> = props => {
|
||||
});
|
||||
|
||||
const aboutPlugin = (
|
||||
<Card mode='outlined' style={{ margin: 8 }} testID='plugin-card'>
|
||||
<Card mode='outlined' style={{ marginVertical: 8 }} testID='plugin-card'>
|
||||
<Card.Content>
|
||||
<PluginTitle manifest={manifest}/>
|
||||
<Text variant='bodyMedium'>{_('by %s', manifest.author)}</Text>
|
||||
|
||||
@@ -718,8 +718,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
const explicitReloadRequired = !editorPlugin && this.props.editorNoteReloadTimeRequest > this.state.noteLastLoadTime;
|
||||
|
||||
if (explicitReloadRequired) {
|
||||
void shared.reloadNote(this);
|
||||
this.refreshKey = this.props.editorNoteReloadTimeRequest;
|
||||
void this.reloadNoteAndUpdateRefreshKey();
|
||||
}
|
||||
|
||||
if (explicitReloadRequired || (editorPlugin && editorPluginIdsChanged)) {
|
||||
@@ -774,6 +773,11 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
});
|
||||
}
|
||||
|
||||
private async reloadNoteAndUpdateRefreshKey() {
|
||||
await shared.reloadNote(this);
|
||||
this.refreshKey = this.props.editorNoteReloadTimeRequest;
|
||||
}
|
||||
|
||||
private title_changeText(text: string) {
|
||||
let newText = text;
|
||||
newText = text.replace(/(\r\n|\n|\r)/gm, ' ');
|
||||
|
||||
@@ -21,6 +21,7 @@ const defaultRendererSettings: RenderSettings = {
|
||||
|
||||
pluginSettings: {},
|
||||
requestPluginSetting: () => { },
|
||||
showNoteLinkIcon: true,
|
||||
};
|
||||
|
||||
const makeRenderer = (options: Partial<RendererSetupOptions>) => {
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface RenderSettings {
|
||||
|
||||
splitted?: boolean; // Move CSS into a separate output
|
||||
mapsToLine?: boolean; // Sourcemaps
|
||||
showNoteLinkIcon?: boolean;
|
||||
|
||||
createEditPopupSyntax: string;
|
||||
destroyEditPopupSyntax: string;
|
||||
@@ -136,6 +137,7 @@ export default class Renderer {
|
||||
splitted: settings.splitted,
|
||||
mapsToLine: settings.mapsToLine,
|
||||
whiteBackgroundNoteRendering: markup.language === MarkupLanguage.Html,
|
||||
showNoteLinkIcon: settings.showNoteLinkIcon,
|
||||
globalSettings: settings.globalSettings,
|
||||
};
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ export interface RenderOptions {
|
||||
// Forwarded renderer settings
|
||||
splitted?: boolean;
|
||||
mapsToLine?: boolean;
|
||||
showNoteLinkIcon?: boolean;
|
||||
}
|
||||
|
||||
type CancelEvent = { cancelled: boolean };
|
||||
|
||||
@@ -240,6 +240,7 @@ const useWebViewSetup = (props: Props): Result => {
|
||||
}
|
||||
},
|
||||
removeUnusedPluginAssets: options.removeUnusedPluginAssets,
|
||||
showNoteLinkIcon: options.showNoteLinkIcon,
|
||||
globalSettings: {
|
||||
'markdown.plugin.abc.options': Setting.value('markdown.plugin.abc.options'),
|
||||
},
|
||||
|
||||
@@ -520,7 +520,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 150;
|
||||
CURRENT_PROJECT_VERSION = 151;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
@@ -529,7 +529,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 13.6.1;
|
||||
MARKETING_VERSION = 13.6.2;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -555,7 +555,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 150;
|
||||
CURRENT_PROJECT_VERSION = 151;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
@@ -563,7 +563,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 13.6.1;
|
||||
MARKETING_VERSION = 13.6.2;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -758,7 +758,7 @@
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 150;
|
||||
CURRENT_PROJECT_VERSION = 151;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -769,7 +769,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 13.6.1;
|
||||
MARKETING_VERSION = 13.6.2;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
@@ -801,7 +801,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 150;
|
||||
CURRENT_PROJECT_VERSION = 151;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
@@ -812,7 +812,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 13.6.1;
|
||||
MARKETING_VERSION = 13.6.2;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
|
||||
@@ -2015,7 +2015,7 @@ PODS:
|
||||
- Yoga
|
||||
- RNCPushNotificationIOS (1.11.0):
|
||||
- React-Core
|
||||
- RNDateTimePicker (8.4.7):
|
||||
- RNDateTimePicker (8.5.1):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
@@ -2041,7 +2041,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNFileViewer (2.1.5):
|
||||
- React-Core
|
||||
- RNLocalize (3.5.4):
|
||||
- RNLocalize (3.6.0):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
@@ -2627,10 +2627,10 @@ SPEC CHECKSUMS:
|
||||
rn-fetch-blob: 25612b6d6f6e980c6f17ed98ba2f58f5696a51ca
|
||||
RNCClipboard: 88d7eeb555d1183915f0885bdbc5c97eb6f7f3ba
|
||||
RNCPushNotificationIOS: 6c4ca3388c7434e4a662b92e4dfeeee858e6f440
|
||||
RNDateTimePicker: f11373a05d806e849ab984e2806c531278b47cdd
|
||||
RNDateTimePicker: 19ffa303c4524ec0a2dfdee2658198451c16b7f1
|
||||
RNDeviceInfo: bcce8752b5043a623fe3c26789679b473f705d3c
|
||||
RNFileViewer: 4b5d83358214347e4ab2d4ca8d5c1c90d869e251
|
||||
RNLocalize: da3c00bf1044a67e72cf8b450289e263fd5baab3
|
||||
RNLocalize: 83a242b38886bf7e84073410c101e9ea39a1c1a5
|
||||
RNQuickAction: c2c8f379e614428be0babe4d53a575739667744d
|
||||
RNSecureRandom: b64d263529492a6897e236a22a2c4249aa1b53dc
|
||||
RNShare: 0e600372fb35783fe30d413efd28d11de2bf6cf0
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"react-native-file-viewer": "2.1.5",
|
||||
"react-native-get-random-values": "1.11.0",
|
||||
"react-native-image-picker": "8.2.1",
|
||||
"react-native-localize": "3.5.4",
|
||||
"react-native-localize": "3.6.0",
|
||||
"react-native-modal-datetime-picker": "18.0.0",
|
||||
"react-native-nitro-modules": "0.33.2",
|
||||
"react-native-paper": "5.14.5",
|
||||
|
||||
@@ -531,6 +531,13 @@ export default class Synchronizer {
|
||||
|
||||
// console.info('NEW', newInfo);
|
||||
|
||||
if (newInfo.revisionServiceEnabled !== localInfo.revisionServiceEnabled) {
|
||||
Setting.setValue('revisionService.enabled', newInfo.revisionServiceEnabled);
|
||||
}
|
||||
if (newInfo.revisionServiceTtlDays !== localInfo.revisionServiceTtlDays) {
|
||||
Setting.setValue('revisionService.ttlDays', newInfo.revisionServiceTtlDays);
|
||||
}
|
||||
|
||||
if (newInfo.e2ee !== previousE2EE) {
|
||||
if (newInfo.e2ee) {
|
||||
const mk = getActiveMasterKey(newInfo);
|
||||
|
||||
@@ -10,6 +10,7 @@ import BaseItem from '../../models/BaseItem';
|
||||
import shim from '../../shim';
|
||||
import { Dispatch } from 'redux';
|
||||
import { State } from '../../reducer';
|
||||
import { onRevisionServiceSettingsChanged } from '../../services/synchronizer/syncInfoUtils';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
let sortNoteListTimeout: any = null;
|
||||
@@ -31,6 +32,10 @@ export default async (store: any, _next: any, action: any, dispatch: Dispatch) =
|
||||
reg.resetSyncTarget();
|
||||
}
|
||||
|
||||
if (action.type === 'SETTING_UPDATE_ONE') {
|
||||
onRevisionServiceSettingsChanged(action.key, action.value);
|
||||
}
|
||||
|
||||
let mustAutoAddResources = false;
|
||||
|
||||
if (action.type === 'SETTING_UPDATE_ONE' && action.key === 'sync.resourceDownloadMode') {
|
||||
|
||||
@@ -1967,7 +1967,8 @@ const builtInMetadata = (Setting: typeof SettingType) => {
|
||||
},
|
||||
|
||||
'survey.webClientEval2025.progress': {
|
||||
value: SurveyProgress.NotStarted,
|
||||
// Ended in February 2026. See https://github.com/laurent22/joplin/pull/14497.
|
||||
value: SurveyProgress.Dismissed,
|
||||
type: SettingItemType.Int,
|
||||
public: false,
|
||||
isEnum: true,
|
||||
@@ -2077,6 +2078,17 @@ const builtInMetadata = (Setting: typeof SettingType) => {
|
||||
storage: SettingStorage.File,
|
||||
isGlobal: false,
|
||||
},
|
||||
|
||||
'notes.showNoteLinkIcon': {
|
||||
value: true,
|
||||
type: SettingItemType.Bool,
|
||||
storage: SettingStorage.File,
|
||||
section: 'note',
|
||||
public: true,
|
||||
isGlobal: true,
|
||||
label: () => _('Show Joplin icon for note links'),
|
||||
appTypes: [AppType.Desktop, AppType.Mobile],
|
||||
},
|
||||
} satisfies Record<string, SettingItem>;
|
||||
|
||||
for (const [key, md] of Object.entries(output)) {
|
||||
|
||||
26
packages/lib/services/DecryptionWorker.test.ts
Normal file
26
packages/lib/services/DecryptionWorker.test.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { setupDatabaseAndSynchronizer, switchClient, decryptionWorker } from '../testing/test-utils';
|
||||
|
||||
describe('services/DecryptionWorker', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
});
|
||||
|
||||
it('should not return null when a call to .start is cancelled', async () => {
|
||||
const worker = decryptionWorker();
|
||||
|
||||
// Both calls should return a valid DecryptionResult, even if the
|
||||
// queue skips one task due to concurrency.
|
||||
const results = await Promise.all([
|
||||
worker.start(),
|
||||
worker.start(),
|
||||
]);
|
||||
|
||||
for (const result of results) {
|
||||
expect(result === null).toBe(false);
|
||||
expect(result === undefined).toBe(false);
|
||||
expect(result).toHaveProperty('error');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -349,6 +349,15 @@ export default class DecryptionWorker {
|
||||
if (lastError) {
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
// If this task was skipped due to a concurrent start() call, return an empty
|
||||
// DecryptionResult instead of null. AsyncActionQueue drops earlier tasks when
|
||||
// multiple are queued, but start() guarantees Promise<DecryptionResult> and
|
||||
// must not resolve null.
|
||||
if (!output) {
|
||||
return { error: null, decryptedItemCount: 0, skippedItemCount: 0 };
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { synchronizerStart, revisionService, setupDatabaseAndSynchronizer, synch
|
||||
import Note from '../../models/Note';
|
||||
import Revision from '../../models/Revision';
|
||||
import { loadMasterKeysFromSettings, setupAndEnableEncryption } from '../e2ee/utils';
|
||||
import { onRevisionServiceSettingsChanged } from './syncInfoUtils';
|
||||
|
||||
describe('Synchronizer.revisions', () => {
|
||||
|
||||
@@ -301,4 +302,27 @@ describe('Synchronizer.revisions', () => {
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should sync revision service settings across clients', (async () => {
|
||||
const changeSetting = (key: string, value: unknown) => {
|
||||
Setting.setValue(key, value);
|
||||
onRevisionServiceSettingsChanged(key, value);
|
||||
};
|
||||
|
||||
changeSetting('revisionService.enabled', false);
|
||||
await synchronizerStart();
|
||||
await switchClient(2);
|
||||
|
||||
expect(Setting.value('revisionService.enabled')).toBe(true);
|
||||
await synchronizerStart();
|
||||
expect(Setting.value('revisionService.enabled')).toBe(false);
|
||||
|
||||
changeSetting('revisionService.enabled', true);
|
||||
await synchronizerStart();
|
||||
await switchClient(1);
|
||||
|
||||
expect(Setting.value('revisionService.enabled')).toBe(false);
|
||||
await synchronizerStart();
|
||||
expect(Setting.value('revisionService.enabled')).toBe(true);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterAllCleanUp, setupDatabaseAndSynchronizer, logger, switchClient, encryptionService, msleep, fileApi } from '../../testing/test-utils';
|
||||
import MasterKey from '../../models/MasterKey';
|
||||
import { checkIfCanSync, localSyncInfo, masterKeyEnabled, mergeSyncInfos, saveLocalSyncInfo, setMasterKeyEnabled, SyncInfo, syncInfoEquals, checkSyncTargetIsValid, fetchSyncInfo } from './syncInfoUtils';
|
||||
import { checkIfCanSync, localSyncInfo, masterKeyEnabled, mergeSyncInfos, saveLocalSyncInfo, setMasterKeyEnabled, SyncInfo, syncInfoEquals, checkSyncTargetIsValid, fetchSyncInfo, onRevisionServiceSettingsChanged } from './syncInfoUtils';
|
||||
import Setting from '../../models/Setting';
|
||||
import BaseItem from '../../models/BaseItem';
|
||||
import BaseModel from '../../models/BaseItem';
|
||||
@@ -283,6 +283,14 @@ describe('syncInfoUtils', () => {
|
||||
'publicKey': '-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCA...',
|
||||
},
|
||||
},
|
||||
'revisionServiceEnabled': {
|
||||
'updatedTime': 0,
|
||||
'value': true,
|
||||
},
|
||||
'revisionServiceTtlDays': {
|
||||
'updatedTime': 0,
|
||||
'value': 90,
|
||||
},
|
||||
'version': 3,
|
||||
});
|
||||
});
|
||||
@@ -392,4 +400,66 @@ describe('syncInfoUtils', () => {
|
||||
Setting.setValue('sync.wipeOutFailSafe', true);
|
||||
expect(fetchSyncInfo(fileApi())).resolves.not.toThrow();
|
||||
}));
|
||||
|
||||
it('should merge revision service settings based on timestamps', () => {
|
||||
const s1 = new SyncInfo();
|
||||
s1.revisionServiceEnabled = false;
|
||||
s1.revisionServiceTtlDays = 30;
|
||||
|
||||
const s2 = new SyncInfo();
|
||||
s2.revisionServiceEnabled = true;
|
||||
s2.revisionServiceTtlDays = 90;
|
||||
|
||||
s1.setKeyTimestamp('revisionServiceEnabled', 200);
|
||||
s1.setKeyTimestamp('revisionServiceTtlDays', 100);
|
||||
s2.setKeyTimestamp('revisionServiceEnabled', 100);
|
||||
s2.setKeyTimestamp('revisionServiceTtlDays', 200);
|
||||
|
||||
const merged = mergeSyncInfos(s1, s2);
|
||||
expect(merged.revisionServiceEnabled).toBe(false);
|
||||
expect(merged.revisionServiceTtlDays).toBe(90);
|
||||
});
|
||||
|
||||
it('should use default revision service settings when not present in sync info', () => {
|
||||
const s = new SyncInfo(JSON.stringify({ version: 3 }));
|
||||
expect(s.revisionServiceEnabled).toBe(true);
|
||||
expect(s.revisionServiceTtlDays).toBe(90);
|
||||
});
|
||||
|
||||
it('should update syncInfo when revision service setting changes', async () => {
|
||||
const s = new SyncInfo();
|
||||
s.revisionServiceTtlDays = 90;
|
||||
s.setKeyTimestamp('revisionServiceTtlDays', 0);
|
||||
saveLocalSyncInfo(s);
|
||||
|
||||
onRevisionServiceSettingsChanged('revisionService.ttlDays', 30);
|
||||
|
||||
const updated = localSyncInfo();
|
||||
expect(updated.revisionServiceTtlDays).toBe(30);
|
||||
expect(updated.keyTimestamp('revisionServiceTtlDays')).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should not update syncInfo when revision service setting value is unchanged', async () => {
|
||||
const s = new SyncInfo();
|
||||
s.revisionServiceTtlDays = 90;
|
||||
s.setKeyTimestamp('revisionServiceTtlDays', 0);
|
||||
saveLocalSyncInfo(s);
|
||||
|
||||
onRevisionServiceSettingsChanged('revisionService.ttlDays', 90);
|
||||
|
||||
const updated = localSyncInfo();
|
||||
expect(updated.keyTimestamp('revisionServiceTtlDays')).toBe(0);
|
||||
});
|
||||
|
||||
it('should ignore unrelated keys in onRevisionServiceSettingsChanged', async () => {
|
||||
const s = new SyncInfo();
|
||||
s.revisionServiceTtlDays = 90;
|
||||
s.setKeyTimestamp('revisionServiceTtlDays', 0);
|
||||
saveLocalSyncInfo(s);
|
||||
|
||||
onRevisionServiceSettingsChanged('sync.target', 1);
|
||||
|
||||
const updated = localSyncInfo();
|
||||
expect(updated.keyTimestamp('revisionServiceTtlDays')).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,6 +24,11 @@ export interface SyncInfoValueString {
|
||||
updatedTime: number;
|
||||
}
|
||||
|
||||
export interface SyncInfoValueInt {
|
||||
value: number;
|
||||
updatedTime: number;
|
||||
}
|
||||
|
||||
export interface SyncInfoValuePublicPrivateKeyPair {
|
||||
value: PublicPrivateKeyPair;
|
||||
updatedTime: number;
|
||||
@@ -44,6 +49,23 @@ export const setAppMinVersion = (v: string) => {
|
||||
appMinVersion_ = v;
|
||||
};
|
||||
|
||||
export function onRevisionServiceSettingsChanged(key: string, value: unknown) {
|
||||
if (key !== 'revisionService.enabled' && key !== 'revisionService.ttlDays') return;
|
||||
const s = localSyncInfo();
|
||||
let changed = false;
|
||||
if (key === 'revisionService.enabled' && s.revisionServiceEnabled !== value) {
|
||||
if (typeof value !== 'boolean') return;
|
||||
s.revisionServiceEnabled = value;
|
||||
changed = true;
|
||||
}
|
||||
if (key === 'revisionService.ttlDays' && s.revisionServiceTtlDays !== value) {
|
||||
if (typeof value !== 'number') return;
|
||||
s.revisionServiceTtlDays = value;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) saveLocalSyncInfo(s);
|
||||
}
|
||||
|
||||
export async function migrateLocalSyncInfo(db: JoplinDatabase) {
|
||||
if (Setting.value('syncInfoCache')) return; // Already initialized
|
||||
|
||||
@@ -75,6 +97,10 @@ export async function migrateLocalSyncInfo(db: JoplinDatabase) {
|
||||
// most likely not what the user wants.
|
||||
syncInfo.setKeyTimestamp('e2ee', 0);
|
||||
syncInfo.setKeyTimestamp('activeMasterKeyId', 0);
|
||||
syncInfo.revisionServiceEnabled = Setting.value('revisionService.enabled');
|
||||
syncInfo.revisionServiceTtlDays = Setting.value('revisionService.ttlDays');
|
||||
syncInfo.setKeyTimestamp('revisionServiceEnabled', 0);
|
||||
syncInfo.setKeyTimestamp('revisionServiceTtlDays', 0);
|
||||
|
||||
await saveLocalSyncInfo(syncInfo);
|
||||
}
|
||||
@@ -219,6 +245,8 @@ export function mergeSyncInfos(s1: SyncInfo, s2: SyncInfo): SyncInfo {
|
||||
|
||||
output.setWithTimestamp(s1.keyTimestamp('e2ee') > s2.keyTimestamp('e2ee') ? s1 : s2, 'e2ee');
|
||||
output.setWithTimestamp(s1.keyTimestamp('ppk') > s2.keyTimestamp('ppk') ? s1 : s2, 'ppk');
|
||||
output.setWithTimestamp(s1.keyTimestamp('revisionServiceEnabled') > s2.keyTimestamp('revisionServiceEnabled') ? s1 : s2, 'revisionServiceEnabled');
|
||||
output.setWithTimestamp(s1.keyTimestamp('revisionServiceTtlDays') > s2.keyTimestamp('revisionServiceTtlDays') ? s1 : s2, 'revisionServiceTtlDays');
|
||||
output.version = s1.version > s2.version ? s1.version : s2.version;
|
||||
|
||||
mergeActiveMasterKeys(s1, s2, output);
|
||||
@@ -255,11 +283,15 @@ export class SyncInfo {
|
||||
private masterKeys_: MasterKeyEntity[] = [];
|
||||
private ppk_: SyncInfoValuePublicPrivateKeyPair;
|
||||
private appMinVersion_: string = appMinVersion_;
|
||||
private revisionServiceEnabled_: SyncInfoValueBoolean;
|
||||
private revisionServiceTtlDays_: SyncInfoValueInt;
|
||||
|
||||
public constructor(serialized: string = null) {
|
||||
this.e2ee_ = { value: false, updatedTime: 0 };
|
||||
this.activeMasterKeyId_ = { value: '', updatedTime: 0 };
|
||||
this.ppk_ = { value: null, updatedTime: 0 };
|
||||
this.revisionServiceEnabled_ = { value: true, updatedTime: 0 };
|
||||
this.revisionServiceTtlDays_ = { value: 90, updatedTime: 0 };
|
||||
|
||||
if (serialized) this.load(serialized);
|
||||
}
|
||||
@@ -273,6 +305,8 @@ export class SyncInfo {
|
||||
masterKeys: this.masterKeys,
|
||||
ppk: this.ppk_,
|
||||
appMinVersion: this.appMinVersion,
|
||||
revisionServiceEnabled: this.revisionServiceEnabled_,
|
||||
revisionServiceTtlDays: this.revisionServiceTtlDays_,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -315,6 +349,8 @@ export class SyncInfo {
|
||||
this.masterKeys_ = 'masterKeys' in s ? s.masterKeys : [];
|
||||
this.ppk_ = 'ppk' in s ? s.ppk : { value: null, updatedTime: 0 };
|
||||
this.appMinVersion_ = s.appMinVersion ? s.appMinVersion : '0.0.0';
|
||||
this.revisionServiceEnabled_ = 'revisionServiceEnabled' in s ? s.revisionServiceEnabled : { value: true, updatedTime: 0 };
|
||||
this.revisionServiceTtlDays_ = 'revisionServiceTtlDays' in s ? s.revisionServiceTtlDays : { value: 90, updatedTime: 0 };
|
||||
|
||||
// Migration for master keys that didn't have "hasBeenUsed" property -
|
||||
// in that case we assume they've been used at least once.
|
||||
@@ -382,6 +418,26 @@ export class SyncInfo {
|
||||
this.activeMasterKeyId_ = { value: v, updatedTime: Date.now() };
|
||||
}
|
||||
|
||||
public get revisionServiceEnabled(): boolean {
|
||||
return this.revisionServiceEnabled_.value;
|
||||
}
|
||||
|
||||
public set revisionServiceEnabled(v: boolean) {
|
||||
if (v === this.revisionServiceEnabled) return;
|
||||
|
||||
this.revisionServiceEnabled_ = { value: v, updatedTime: Date.now() };
|
||||
}
|
||||
|
||||
public get revisionServiceTtlDays(): number {
|
||||
return this.revisionServiceTtlDays_.value;
|
||||
}
|
||||
|
||||
public set revisionServiceTtlDays(v: number) {
|
||||
if (v === this.revisionServiceTtlDays) return;
|
||||
|
||||
this.revisionServiceTtlDays_ = { value: v, updatedTime: Date.now() };
|
||||
}
|
||||
|
||||
public get masterKeys(): MasterKeyEntity[] {
|
||||
return this.masterKeys_;
|
||||
}
|
||||
|
||||
@@ -210,6 +210,8 @@ export interface RuleOptions {
|
||||
allowedFilePrefixes?: string[];
|
||||
|
||||
platformName?: string;
|
||||
|
||||
showNoteLinkIcon?: boolean;
|
||||
}
|
||||
|
||||
export default class MdToHtml implements MarkupRenderer {
|
||||
|
||||
@@ -79,4 +79,24 @@ describe('linkReplacement', () => {
|
||||
expect(linkHtml).toContain('ontouchend');
|
||||
expect(linkHtml).toContain('ontouchcancel');
|
||||
});
|
||||
|
||||
test('should show Joplin Icon for internal link by default', () => {
|
||||
const resourceId = 'e6afba55bdf74568ac94f8d1e3578d2c';
|
||||
const linkHtml = linkReplacement(`:/${resourceId}`, {
|
||||
ResourceModel: defaultResourceModel,
|
||||
resources: {},
|
||||
showNoteLinkIcon: true,
|
||||
}).html;
|
||||
expect(linkHtml).toContain('<span class="resource-icon fa-joplin"></span>');
|
||||
});
|
||||
|
||||
test('should not include Joplin Icon for internal link if configuration is not enabled', () => {
|
||||
const resourceId = 'e6afba55bdf74568ac94f8d1e3578d2c';
|
||||
const linkHtml = linkReplacement(`:/${resourceId}`, {
|
||||
ResourceModel: defaultResourceModel,
|
||||
resources: {},
|
||||
showNoteLinkIcon: false,
|
||||
}).html;
|
||||
expect(linkHtml).not.toContain('<span class="resource-icon fa-joplin"></span>');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface Options {
|
||||
postMessageSyntax?: string;
|
||||
enableLongPress?: boolean;
|
||||
itemIdToUrl?: ItemIdToUrlHandler;
|
||||
showNoteLinkIcon?: boolean;
|
||||
}
|
||||
|
||||
export interface LinkReplacementResult {
|
||||
@@ -35,6 +36,7 @@ export default function(href: string, options: Options = null): LinkReplacementR
|
||||
options.plainResourceRendering ??= false;
|
||||
options.postMessageSyntax ??= 'postMessage';
|
||||
options.enableLongPress ??= false;
|
||||
options.showNoteLinkIcon ??= true;
|
||||
|
||||
const resourceHrefInfo = urlUtils.parseResourceUrl(href);
|
||||
const isResourceUrl = options.resources && !!resourceHrefInfo;
|
||||
@@ -74,12 +76,16 @@ export default function(href: string, options: Options = null): LinkReplacementR
|
||||
if (resourceHrefInfo.hash) href += `#${resourceHrefInfo.hash}`;
|
||||
resourceIdAttr = `data-resource-id='${resourceId}'`;
|
||||
|
||||
const iconType = mime ? getClassNameForMimeType(mime) : 'fa-joplin';
|
||||
|
||||
let iconType;
|
||||
if (mime) {
|
||||
iconType = getClassNameForMimeType(mime);
|
||||
} else {
|
||||
iconType = options.showNoteLinkIcon ? 'fa-joplin' : '';
|
||||
}
|
||||
// Icons are defined in lib/renderers/noteStyle using inline svg
|
||||
// The icons are taken from fork-awesome but use the font-awesome naming scheme in order
|
||||
// to be more compatible with the getClass library
|
||||
icon = `<span class="resource-icon ${iconType}"></span>`;
|
||||
icon = iconType ? `<span class="resource-icon ${iconType}"></span>` : '';
|
||||
}
|
||||
} else {
|
||||
// If the link is a plain URL (as opposed to a resource link), set the href to the actual
|
||||
|
||||
@@ -23,6 +23,7 @@ function plugin(markdownIt: any, ruleOptions: RuleOptions) {
|
||||
postMessageSyntax: ruleOptions.postMessageSyntax,
|
||||
enableLongPress: ruleOptions.enableLongPress,
|
||||
itemIdToUrl: ruleOptions.itemIdToUrl,
|
||||
showNoteLinkIcon: ruleOptions.showNoteLinkIcon,
|
||||
});
|
||||
|
||||
ruleOptions.context.currentLinks.push({
|
||||
|
||||
@@ -92,6 +92,8 @@ export interface RenderOptions {
|
||||
|
||||
platformName?: string;
|
||||
|
||||
showNoteLinkIcon?: boolean;
|
||||
|
||||
// HtmlToHtml only
|
||||
whiteBackgroundNoteRendering?: boolean;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"query-string": "7.1.3",
|
||||
"rate-limiter-flexible": "7.4.0",
|
||||
"raw-body": "3.0.2",
|
||||
"samlify": "2.10.1",
|
||||
"samlify": "2.10.2",
|
||||
"sqlite3": "5.1.6",
|
||||
"stripe": "13.9.0",
|
||||
"uuid": "11.1.0",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ItemType, databaseSchema, Uuid, Item, ShareType, Share, ChangeType, Use
|
||||
import { defaultPagination, paginateDbQuery, PaginatedResults, Pagination } from './utils/pagination';
|
||||
import { isJoplinItemName, isJoplinResourceBlobPath, linkedResourceIds, serializeJoplinItem, unserializeJoplinItem } from '../utils/joplinUtils';
|
||||
import { ModelType } from '@joplin/lib/BaseModel';
|
||||
import { ApiError, CustomErrorCode, ErrorConflict, ErrorForbidden, ErrorPayloadTooLarge, ErrorUnprocessableEntity, ErrorCode } from '../utils/errors';
|
||||
import { ApiError, CustomErrorCode, ErrorConflict, ErrorForbidden, ErrorPayloadTooLarge, ErrorUnprocessableEntity, ErrorCode, ErrorBadRequest } from '../utils/errors';
|
||||
import { Knex } from 'knex';
|
||||
import { ChangePreviousItem } from './ChangeModel';
|
||||
import { unique } from '../utils/array';
|
||||
@@ -1065,6 +1065,8 @@ export default class ItemModel extends BaseModel<Item> {
|
||||
if (!item.owner_id) item.owner_id = userId;
|
||||
} else {
|
||||
const beforeSaveItem = await this.load(item.id, { fields: ['name', 'jop_share_id'] });
|
||||
if (!beforeSaveItem) throw new ErrorBadRequest('Item does not exist');
|
||||
|
||||
previousName = beforeSaveItem.name;
|
||||
previousItem = {
|
||||
jop_share_id: beforeSaveItem.jop_share_id,
|
||||
|
||||
@@ -4,6 +4,51 @@ import { ShareType } from '../services/database/types';
|
||||
import { inviteUserToShare, shareFolderWithUser, shareWithUserAndAccept, updateItemShareId } from '../utils/testing/shareApiUtils';
|
||||
import { withWarningSilenced } from '@joplin/lib/testing/test-utils';
|
||||
|
||||
// Goes through the process of:
|
||||
// 1. Creating two users/sessions
|
||||
// 2. Creating a share and accepting it
|
||||
// 3. Moving a note created by the share recipient in to the share
|
||||
//
|
||||
// This creates a note owned by the share recipient, but within the
|
||||
// share.
|
||||
const createShareWithNoteOwnedByRecipient = async () => {
|
||||
const { session: session1 } = await createUserAndSession(1);
|
||||
const { session: session2, user: user2 } = await createUserAndSession(2);
|
||||
|
||||
await createItemTree(session1.user_id, '', {
|
||||
'000000000000000000000000000000F1': {
|
||||
},
|
||||
});
|
||||
await createItemTree(session2.user_id, '', {
|
||||
'000000000000000000000000000000F2': {
|
||||
'00000000000000000000000000000001': null,
|
||||
},
|
||||
});
|
||||
|
||||
const shareRoot = await models().item().loadByJopId(session1.user_id, '000000000000000000000000000000F1');
|
||||
|
||||
// Note should initially be owned by user 2
|
||||
let note = await models().item().loadByJopId(session2.user_id, '00000000000000000000000000000001');
|
||||
expect(note.owner_id).toBe(session2.user_id);
|
||||
|
||||
const { share, shareUser } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.Folder, shareRoot);
|
||||
|
||||
await updateItemShareId(session1, shareRoot.id, share.id);
|
||||
await models().share().updateSharedItems3();
|
||||
|
||||
// Changing the note's share ID and parent should not change the owner ID
|
||||
note = await updateItemShareId(session2, note.id, share.id);
|
||||
note = await models().item().saveForUser(session1.user_id, {
|
||||
...note,
|
||||
jop_parent_id: '000000000000000000000000000000F1',
|
||||
});
|
||||
|
||||
await models().share().updateSharedItems3();
|
||||
expect(note.owner_id).toBe(session2.user_id);
|
||||
|
||||
return { share, shareUser, note, session1, session2 };
|
||||
};
|
||||
|
||||
describe('ShareModel', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
@@ -258,4 +303,42 @@ describe('ShareModel', () => {
|
||||
});
|
||||
expect(await getUser2UserItems()).toHaveLength(0);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ deleteShare: false, label: '' },
|
||||
// Deleting the share means that the maintenance task can't use share.owner_id to
|
||||
// determine the new owner for the item.
|
||||
{ deleteShare: true, label: 'and the share is deleted' },
|
||||
])('should update owner_id when the original owner no longer has access $label', async ({ deleteShare }) => {
|
||||
const { share, shareUser, note, session1, session2 } = await createShareWithNoteOwnedByRecipient();
|
||||
expect(note.owner_id).toBe(session2.user_id);
|
||||
|
||||
// Remove session2.user_id from the share either by deleting the entire share or
|
||||
// by removing the shareUser.
|
||||
if (deleteShare) {
|
||||
await models().share().delete(share.id);
|
||||
} else {
|
||||
await models().shareUser().delete(shareUser.id);
|
||||
}
|
||||
await models().share().updateSharedItems3();
|
||||
|
||||
const updatedNote = await models().item().load(note.id);
|
||||
// The owner_id should be updated
|
||||
expect(updatedNote.owner_id).toBe(session1.user_id);
|
||||
// ...but it should still be part of the share.
|
||||
expect(updatedNote.jop_share_id).toBe(share.id);
|
||||
});
|
||||
|
||||
test('should not update owner_id after unsharing if an item has been moved out of a share by the item\'s owner', async () => {
|
||||
const { shareUser, note, session2 } = await createShareWithNoteOwnedByRecipient();
|
||||
|
||||
await updateItemShareId(session2, note.id, '');
|
||||
|
||||
// Removing session2 from the share should keep the item's owner the same
|
||||
await models().shareUser().delete(shareUser.id);
|
||||
await models().share().updateSharedItems3();
|
||||
|
||||
const updatedNote = await models().item().load(note.id);
|
||||
expect(updatedNote.owner_id).toBe(session2.user_id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -208,7 +208,11 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreated = async (change: Change, item: Item, share: Share) => {
|
||||
// For performance, handleCreated acts on all changes for a particular item at once.
|
||||
//
|
||||
// This function must behave correctly regardless of whether it is called before or after
|
||||
// other events are processed.
|
||||
const handleCreated = async (item: Item, changes: Change[], share: Share) => {
|
||||
if (!item.jop_share_id) return;
|
||||
|
||||
// When a folder is unshared, the share object is deleted, then all
|
||||
@@ -229,7 +233,9 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
|
||||
const shareUserIds = await this.allShareUserIds(share);
|
||||
for (const shareUserId of shareUserIds) {
|
||||
if (shareUserId === change.user_id) continue;
|
||||
const hasCreationEvent = changes.some(change => change.user_id === shareUserId);
|
||||
if (hasCreationEvent) continue;
|
||||
|
||||
await addUserItem(shareUserId, item.id);
|
||||
}
|
||||
|
||||
@@ -275,18 +281,22 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
};
|
||||
|
||||
const handleDeleted = async (change: Change, item: Item|null, share: Share|null) => {
|
||||
// On deletion, we check for extra user_items entries for items that still exist.
|
||||
// These user_items can be created by race conditions between updateSharedItems3
|
||||
// and logic for removing users from a share.
|
||||
// On deletion, we check for extra user_items entries and incorrect ownership for
|
||||
// items that still exist:
|
||||
// - Unexpected user_items can be created by race conditions between updateSharedItems3
|
||||
// and logic for removing users from a share.
|
||||
// - Outdated owner_id information can be caused by moving an item into a share,
|
||||
// then removing the item's original owner from the share.
|
||||
//
|
||||
// For now, only check the case where the item exists, and thus the user_items
|
||||
// entry could allow access to the item.
|
||||
// For now, only check the case where the item exists, and thus the user_items entry
|
||||
// could allow access to the item.
|
||||
if (!item) return;
|
||||
|
||||
perfTimer.push('handleDeleted');
|
||||
|
||||
// If the userItem exists, the user still has access to the item, despite the deletion change:
|
||||
const userItem = await this.models().userItem().byUserAndItemId(change.user_id, change.item_id);
|
||||
let userItem = await this.models().userItem().byUserAndItemId(change.user_id, change.item_id);
|
||||
if (userItem) {
|
||||
perfTimer.push('handleDeleted');
|
||||
|
||||
const isShareMember = async () => {
|
||||
if (!share) return false;
|
||||
@@ -302,10 +312,56 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
// Delete by the UserItem's ID to avoid race conditions. If a new user item is created for the same
|
||||
// (user, item) pair (perhaps after removing the original), it should not be deleted by this task:
|
||||
await this.models().userItem().deleteByUserItemIds([userItem.id]);
|
||||
userItem = null;
|
||||
}
|
||||
|
||||
perfTimer.pop();
|
||||
}
|
||||
|
||||
// If an item was deleted for the owner, and the owner no longer has access, the item should now be owned by
|
||||
// a different user:
|
||||
const deletedForOwner = item.owner_id === change.user_id;
|
||||
if (deletedForOwner && !userItem) {
|
||||
const userItems = await this.models().userItem().byItemIds([item.id]);
|
||||
const usersWithAccess = userItems.map(item => item.user_id);
|
||||
|
||||
let newOwnerId;
|
||||
// Check that the share owner still has access: Handle the case where the item's parent share
|
||||
// is changed after the item and share have been loaded.
|
||||
if (share && usersWithAccess.includes(share.owner_id)) {
|
||||
// Case where the item was moved to a different share or the original owner was removed from the
|
||||
// share:
|
||||
newOwnerId = share.owner_id;
|
||||
} else if (usersWithAccess.length === 1) {
|
||||
// Case where the item was moved out of a share by a user that didn't previously own the item,
|
||||
// or the item's share was deleted:
|
||||
newOwnerId = usersWithAccess[0];
|
||||
} else {
|
||||
// May happen due to a race condition related to moving an item between shares
|
||||
// while processing the item's shares/deletions.
|
||||
logger.warn('handleDeleted: Unable to accurately fix owner_id for item', item.id, 'in share', share?.id, 'and users with access', usersWithAccess);
|
||||
}
|
||||
|
||||
if (!newOwnerId) {
|
||||
logger.warn('handleDeleted: Item', item.id, 'deleted for owner', item.owner_id, 'and still exists, but no new owner ID was assigned.');
|
||||
} else {
|
||||
try {
|
||||
await this.models().item().saveForUser(newOwnerId, {
|
||||
id: item.id,
|
||||
owner_id: newOwnerId,
|
||||
}, { isNew: false });
|
||||
} catch (error) {
|
||||
// Guard against a potential race condition: Handle the case where the item was deleted for all users
|
||||
// during the share update process:
|
||||
if (error instanceof ErrorBadRequest) {
|
||||
logger.warn('handleDeleted: Unable to update owner_id on item', item.id, error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
perfTimer.pop();
|
||||
};
|
||||
|
||||
// This function add any missing item to a user's collection. Normally
|
||||
@@ -354,6 +410,21 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
perfTimer.pop();
|
||||
};
|
||||
|
||||
const buildItemToChangeTypeMap = (changeType: ChangeType, changes: Change[]) => {
|
||||
const itemToChanges = new Map<Uuid, Change[]>();
|
||||
for (const change of changes) {
|
||||
if (change.type !== changeType) continue;
|
||||
|
||||
const itemChanges = itemToChanges.get(change.item_id);
|
||||
if (itemChanges) {
|
||||
itemChanges.push(change);
|
||||
} else {
|
||||
itemToChanges.set(change.item_id, [change]);
|
||||
}
|
||||
}
|
||||
return itemToChanges;
|
||||
};
|
||||
|
||||
// This loop essentially applies the change made by one user to all the
|
||||
// other users in the share.
|
||||
//
|
||||
@@ -399,18 +470,17 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
await this.withTransaction(async () => {
|
||||
perfTimer.push(`Processing ${changes.length} changes`);
|
||||
|
||||
const itemToUpdates = new Map<Uuid, Change[]>();
|
||||
for (const change of changes) {
|
||||
if (change.type === ChangeType.Update) {
|
||||
const updates = itemToUpdates.get(change.item_id);
|
||||
if (updates) {
|
||||
updates.push(change);
|
||||
} else {
|
||||
itemToUpdates.set(change.item_id, [change]);
|
||||
}
|
||||
}
|
||||
// Performance: Group creation events per-item
|
||||
const itemToCreations = buildItemToChangeTypeMap(ChangeType.Create, changes);
|
||||
for (const [itemId, itemChanges] of itemToCreations.entries()) {
|
||||
const item = items.find(i => i.id === itemId);
|
||||
if (!item) continue;
|
||||
|
||||
const itemShare = shares.find(s => s.id === item.jop_share_id);
|
||||
await handleCreated(item, itemChanges, itemShare);
|
||||
}
|
||||
|
||||
const itemToUpdates = buildItemToChangeTypeMap(ChangeType.Update, changes);
|
||||
for (const change of changes) {
|
||||
const item = items.find(i => i.id === change.item_id);
|
||||
|
||||
@@ -419,10 +489,6 @@ export default class ShareModel extends BaseModel<Share> {
|
||||
if (item) {
|
||||
const itemShare = shares.find(s => s.id === item.jop_share_id);
|
||||
|
||||
if (change.type === ChangeType.Create) {
|
||||
await handleCreated(change, item, itemShare);
|
||||
}
|
||||
|
||||
if (change.type === ChangeType.Update) {
|
||||
const allUpdates = itemToUpdates.get(item.id);
|
||||
const changeIndex = allUpdates.indexOf(change);
|
||||
|
||||
@@ -83,7 +83,7 @@ export const updateItemShareId = async (session: Session, itemId: Uuid, shareId:
|
||||
const item = await models().item().load(itemId);
|
||||
const joplinItem = await models().item().loadAsJoplinItem<FolderEntity|NoteEntity>(itemId);
|
||||
|
||||
await updateItem(session.id, `root:/${item.name}:`, await serializeJoplinItem({
|
||||
return await updateItem(session.id, `root:/${item.name}:`, await serializeJoplinItem({
|
||||
...joplinItem,
|
||||
share_id: shareId,
|
||||
}));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@
|
||||
"@types/node": "18.19.130",
|
||||
"@types/node-fetch": "2.6.13",
|
||||
"@types/yargs": "17.0.35",
|
||||
"gettext-extractor": "4.0.1",
|
||||
"gettext-extractor": "4.0.3",
|
||||
"gulp": "4.0.2",
|
||||
"html-entities": "1.4.0",
|
||||
"jest": "29.7.0",
|
||||
|
||||
@@ -204,6 +204,9 @@
|
||||
"android-v3.5.9": true,
|
||||
"android-v3.6.12": true,
|
||||
"ios-v13.6.1": true,
|
||||
"v3.5.13": true
|
||||
"v3.5.13": true,
|
||||
"v3.6.3": true,
|
||||
"android-v3.6.13": true,
|
||||
"ios-v13.6.2": true
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@
|
||||
"alt": "For those in need of immediate academic assistance, EssayService offers a fast and reliable service to write my essay for me now, ensuring high-quality results within tight deadlines"
|
||||
},
|
||||
{
|
||||
"url": " https://thenationonlineng.net/casino-en-ligne/casino-en-ligne-payant-au-canada/",
|
||||
"url": "https://thenationonlineng.net/casino-en-ligne/casino-en-ligne-payant-au-canada/",
|
||||
"title": "casino en ligne le plus payant",
|
||||
"imageName": "TheNationOnline.jpg",
|
||||
"alt": "casino en ligne le plus payant"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/transcribe",
|
||||
"version": "3.6.5",
|
||||
"version": "3.6.6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"rebuild": "yarn clean && yarn build && yarn tsc",
|
||||
|
||||
@@ -1,5 +1,43 @@
|
||||
# Joplin Android Changelog
|
||||
|
||||
## [android-v3.6.13](https://github.com/laurent22/joplin/releases/tag/android-v3.6.13) - 2026-03-02T17:36:26Z
|
||||
|
||||
- New: Add an import txt function (#13742 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Add new option to disable the Joplin icon for internal note links (#14503) (#12220 by [@Harsh16gupta](https://github.com/Harsh16gupta))
|
||||
- Improved: Add waving hand emoji to welcome notebook (#14398) (#13755 by Ashutosh Singh)
|
||||
- Improved: Markdown editor: Enable in-editor rendering by default (#13878) (#13215 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Move editor settings to dedicated editor section (#14403) (#13216 by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Improved: Prevent race condition when refreshing note contents on mobile (#14486 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Refresh note when updated via the API when in edit mode (#14378 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Remember the viewing / editing mode (updated) (#14363) (#11521 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Remove redundant navigation history for notes or folders which were deleted (#13428 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Store note history settings in sync info (#14449) (#14336 by [@yugalkaushik](https://github.com/yugalkaushik))
|
||||
- Improved: Trigger a note refresh when viewing or editing a note and the contents are updated via the API (#13671 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Updated packages @react-native-community/datetimepicker (v8.5.1), form-data (v4.0.5), react (v19.1.5), react-native-localize (v3.6.0), react-native-share (v12.2.1), react-native-svg (v15.14.0), react-native-webview (v13.16.0), sharp (v0.34.5), style-to-js (v1.1.21)
|
||||
- Improved: Upgrade React Native to v0.81.6 (#14330 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Add a reveal in notebook option for notes (#14338) (#14255 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Defer starting revision service maintenance until the initial sync has completed (#14394) (#13660 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Fix additional space included above keyboard (#14272) (#14268 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix biometric 'try again' button is off-screen on certain devices (#14373) (#14195 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix heading links (#14201 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix import/export buttons have wrong background after task completes (#14282) (#14266 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix missing conflict scenario (#13624) (#13611 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Fix profile data not deleted when removing profiles (#14369) (#13871 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix status 400 error on Tomcat WebDAV servers (#14332 by [@horvatkm](https://github.com/horvatkm))
|
||||
- Fixed: Fix title bar underline missing on some Android devices (#14273) (#14267 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix unexpected conflicts created during sync (#14453 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix unexpected conflicts sometimes created after a full sync (#14388) (#14383 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Handle missing script assets in HTML export (#14442) (#12545 by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Fixed: Hide the expand / collapse title button when the title is too long (#14203) (#14194 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Improve dropdown menu positioning (#14288) (#14275 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Make the view / edit note button hidden when an editor plugin is visible (#14458) (#14452 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Opt out of Android 16 predictive back behavior (#14281) (#14265 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Reset undo/redo button state when toggling an editor plugin (#14444) (#14387 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Support include_deleted parameter for GET /folders endpoint (#14421) (#14335 by Sriram Varun Kumar)
|
||||
- Fixed: Uses consistent padding in plugin info dialog (#14466) (#11793 by [@Nagmani001](https://github.com/Nagmani001))
|
||||
- Fixed: When cleaning old revisions, ensure revisions are merged for all revision branches (#13795) (#13782 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: YouTube videos are displayed inline too (#14370) (#14352)
|
||||
|
||||
## [android-v3.6.12](https://github.com/laurent22/joplin/releases/tag/android-v3.6.12) - 2026-02-04T14:08:14Z
|
||||
|
||||
- New: Add more error information when the profile is corrupted (f075b56)
|
||||
|
||||
@@ -1,5 +1,63 @@
|
||||
# Joplin Desktop Changelog
|
||||
|
||||
## [v3.6.3](https://github.com/laurent22/joplin/releases/tag/v3.6.3) (Pre-release) - 2026-03-02T18:21:09Z
|
||||
|
||||
- New: Add context menu to non-image resources in Markdown editor ([#14402](https://github.com/laurent22/joplin/issues/14402))
|
||||
- New: Add support for FrontMatter block rendering in notes ([#14256](https://github.com/laurent22/joplin/issues/14256))
|
||||
- New: Api: Add a delete revisions for note API ([#13882](https://github.com/laurent22/joplin/issues/13882) by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Add Close Window shortcut and menu item on Windows/Linux ([#14317](https://github.com/laurent22/joplin/issues/14317)) ([#13794](https://github.com/laurent22/joplin/issues/13794) by Ronald Eddy Jr)
|
||||
- Improved: Add a text layer over OCR-ed PDF files to make them accessible ([#14390](https://github.com/laurent22/joplin/issues/14390)) ([#12400](https://github.com/laurent22/joplin/issues/12400))
|
||||
- Improved: Add editor and sync target to about dialog ([#14443](https://github.com/laurent22/joplin/issues/14443)) ([#9336](https://github.com/laurent22/joplin/issues/9336) by Ashutosh Singh)
|
||||
- Improved: Add new option to disable the Joplin icon for internal note links ([#14503](https://github.com/laurent22/joplin/issues/14503)) ([#12220](https://github.com/laurent22/joplin/issues/12220) by [@Harsh16gupta](https://github.com/Harsh16gupta))
|
||||
- Improved: Add waving hand emoji to welcome notebook ([#14398](https://github.com/laurent22/joplin/issues/14398)) ([#13755](https://github.com/laurent22/joplin/issues/13755) by Ashutosh Singh)
|
||||
- Improved: Display context menu when right-clicking an image in Markdown editor ([#14209](https://github.com/laurent22/joplin/issues/14209))
|
||||
- Improved: Display percentage completion of checkbox lists in note list ([#14312](https://github.com/laurent22/joplin/issues/14312)) ([#14292](https://github.com/laurent22/joplin/issues/14292))
|
||||
- Improved: Exclude trashed notebooks from the list of notebooks on the move to notebook dialog ([#13572](https://github.com/laurent22/joplin/issues/13572) by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Fix Escape key not closing PromptDialog ([#14325](https://github.com/laurent22/joplin/issues/14325)) ([#14301](https://github.com/laurent22/joplin/issues/14301) by Ronald Eddy Jr)
|
||||
- Improved: Importing from OneNote: Enable stricter path sanitization on Windows ([#14321](https://github.com/laurent22/joplin/issues/14321) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Importing from OneNote: Improve handwriting import ([#14305](https://github.com/laurent22/joplin/issues/14305) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Importing from OneNote: Make "module not found" message more useful ([#14324](https://github.com/laurent22/joplin/issues/14324) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Markdown Editor: Make code block highlighting closer to the viewer ([#14168](https://github.com/laurent22/joplin/issues/14168)) ([#14158](https://github.com/laurent22/joplin/issues/14158) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Markdown editor: Enable in-editor rendering by default ([#13878](https://github.com/laurent22/joplin/issues/13878)) ([#13215](https://github.com/laurent22/joplin/issues/13215) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Markdown: Allow specifying the start/end of audio, videos, and PDFs ([#14257](https://github.com/laurent22/joplin/issues/14257)) ([#9745](https://github.com/laurent22/joplin/issues/9745) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Move editor settings to dedicated editor section ([#14403](https://github.com/laurent22/joplin/issues/14403)) ([#13216](https://github.com/laurent22/joplin/issues/13216) by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Improved: OneNote import: Import invalid attachments as empty attachments ([#14177](https://github.com/laurent22/joplin/issues/14177) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Store note history settings in sync info ([#14449](https://github.com/laurent22/joplin/issues/14449)) ([#14336](https://github.com/laurent22/joplin/issues/14336) by [@yugalkaushik](https://github.com/yugalkaushik))
|
||||
- Improved: Sync: Make resource processing in read-only shares more reliable ([#14204](https://github.com/laurent22/joplin/issues/14204) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Synchronise pending changes when closing the app ([#13845](https://github.com/laurent22/joplin/issues/13845) by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Updated packages @axe-core/playwright (v4.11.0), @playwright/test (v1.56.1), @rollup/plugin-commonjs (v28.0.9), @rollup/plugin-replace (v6.0.3), dayjs (v1.11.19), electron-updater (v6.6.8), form-data (v4.0.5), nan (v2.23.1), react (v19.1.5), sass (v1.93.3), sharp (v0.34.5), style-to-js (v1.1.21), turndown (v7.2.2)
|
||||
- Improved: Upgrade tar to v7.5.8 ([#14464](https://github.com/laurent22/joplin/issues/14464) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: "Copy dev mode command to clipboard" does not work when path contains spaces ([#14432](https://github.com/laurent22/joplin/issues/14432)) ([#14328](https://github.com/laurent22/joplin/issues/14328) by Sriram Varun Kumar)
|
||||
- Fixed: Copy and paste from markdown preview includes search highlight effect ([#14493](https://github.com/laurent22/joplin/issues/14493)) ([#12385](https://github.com/laurent22/joplin/issues/12385) by [@yentropysack](https://github.com/yentropysack))
|
||||
- Fixed: Copying from markdown preview including theme background colour ([#14474](https://github.com/laurent22/joplin/issues/14474)) ([#12401](https://github.com/laurent22/joplin/issues/12401) by [@Harsh16gupta](https://github.com/Harsh16gupta))
|
||||
- Fixed: Dark mode not respected in emoji window ([#14303](https://github.com/laurent22/joplin/issues/14303)) ([#14080](https://github.com/laurent22/joplin/issues/14080) by Lakshay Manchanda)
|
||||
- Fixed: Defer starting revision service maintenance until the initial sync has completed ([#14394](https://github.com/laurent22/joplin/issues/14394)) ([#13660](https://github.com/laurent22/joplin/issues/13660) by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Fix UI freeze when closing plugin dialog with Escape key ([#14477](https://github.com/laurent22/joplin/issues/14477) by Sriram Varun Kumar)
|
||||
- Fixed: Fix editor plugins receiving stale note body during navigation ([#14513](https://github.com/laurent22/joplin/issues/14513))
|
||||
- Fixed: Fix missing conflict scenario ([#13624](https://github.com/laurent22/joplin/issues/13624)) ([#13611](https://github.com/laurent22/joplin/issues/13611) by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Fix sidebar scroll jump when expanding/collapsing folders ([#14467](https://github.com/laurent22/joplin/issues/14467)) ([#13679](https://github.com/laurent22/joplin/issues/13679) by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Fixed: Fix status 400 error on Tomcat WebDAV servers ([#14332](https://github.com/laurent22/joplin/issues/14332) by [@horvatkm](https://github.com/horvatkm))
|
||||
- Fixed: Fix undo/redo menu items in the Rich Text and Markdown editors ([#14218](https://github.com/laurent22/joplin/issues/14218)) ([#14216](https://github.com/laurent22/joplin/issues/14216) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix unexpected conflicts created during sync ([#14453](https://github.com/laurent22/joplin/issues/14453) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix unexpected conflicts sometimes created after a full sync ([#14388](https://github.com/laurent22/joplin/issues/14388)) ([#14383](https://github.com/laurent22/joplin/issues/14383) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Handle missing script assets in HTML export ([#14442](https://github.com/laurent22/joplin/issues/14442)) ([#12545](https://github.com/laurent22/joplin/issues/12545) by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Fixed: Improve context menu handling in secondary windows ([#14262](https://github.com/laurent22/joplin/issues/14262)) ([#13540](https://github.com/laurent22/joplin/issues/13540) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Make conflicts caused by resource duplication less likely ([#14188](https://github.com/laurent22/joplin/issues/14188)) ([#13793](https://github.com/laurent22/joplin/issues/13793) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Make notebook search accent-insensitive in GotoAnything ([#14360](https://github.com/laurent22/joplin/issues/14360)) ([#14350](https://github.com/laurent22/joplin/issues/14350) by [@yousef-genedy](https://github.com/yousef-genedy))
|
||||
- Fixed: Markdown editor: Fix error logged in "hide markdown" mode for certain markup ([#14179](https://github.com/laurent22/joplin/issues/14179) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Markdown editor: Scroll jumps in notes with many inline images ([#13955](https://github.com/laurent22/joplin/issues/13955)) ([#13933](https://github.com/laurent22/joplin/issues/13933) by [@bwat47](https://github.com/bwat47))
|
||||
- Fixed: Markdown editor: Upgrade most CodeMirror dependencies ([#14186](https://github.com/laurent22/joplin/issues/14186)) ([#14009](https://github.com/laurent22/joplin/issues/14009) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: OneNote import: Fix onepkg import stops after the first section fails to import ([#14246](https://github.com/laurent22/joplin/issues/14246) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: OneNote importer: Skip importing ink when ID lookup fails ([#14230](https://github.com/laurent22/joplin/issues/14230)) ([#14210](https://github.com/laurent22/joplin/issues/14210) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Prevent 4th backtick when closing fenced code block ([#14423](https://github.com/laurent22/joplin/issues/14423)) ([#12569](https://github.com/laurent22/joplin/issues/12569) by [@Harsh16gupta](https://github.com/Harsh16gupta))
|
||||
- Fixed: Remove empty hidden divs from ENEX imports ([#14411](https://github.com/laurent22/joplin/issues/14411)) ([#14139](https://github.com/laurent22/joplin/issues/14139) by [@yugalkaushik](https://github.com/yugalkaushik))
|
||||
- Fixed: Support include_deleted parameter for GET /folders endpoint ([#14421](https://github.com/laurent22/joplin/issues/14421)) ([#14335](https://github.com/laurent22/joplin/issues/14335) by Sriram Varun Kumar)
|
||||
- Fixed: Unlinked resource deletion: Fix resources attached only via reference links are auto-deleted ([#14178](https://github.com/laurent22/joplin/issues/14178) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: When cleaning old revisions, ensure revisions are merged for all revision branches ([#13795](https://github.com/laurent22/joplin/issues/13795)) ([#13782](https://github.com/laurent22/joplin/issues/13782) by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: YouTube videos are displayed inline too ([#14370](https://github.com/laurent22/joplin/issues/14370)) ([#14352](https://github.com/laurent22/joplin/issues/14352))
|
||||
- Fixed: `.onepkg` file import: Fix import failure when notebook titles contain certain Unicode characters ([#14090](https://github.com/laurent22/joplin/issues/14090)) ([#14084](https://github.com/laurent22/joplin/issues/14084) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Security: Strengthen Content-Security-Policy ([#14316](https://github.com/laurent22/joplin/issues/14316) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
|
||||
## [v3.5.13](https://github.com/laurent22/joplin/releases/tag/v3.5.13) - 2026-02-25T21:19:11Z
|
||||
|
||||
- Improved: Importing from OneNote: Enable stricter path sanitization on Windows ([#14321](https://github.com/laurent22/joplin/issues/14321) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
# Joplin iOS Changelog
|
||||
|
||||
## [ios-v13.6.2](https://github.com/laurent22/joplin/releases/tag/ios-v13.6.2) - 2026-03-02T17:51:24Z
|
||||
|
||||
- New: Add an import txt function (#13742 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Add new option to disable the Joplin icon for internal note links (#14503) (#12220 by [@Harsh16gupta](https://github.com/Harsh16gupta))
|
||||
- Improved: Add waving hand emoji to welcome notebook (#14398) (#13755 by Ashutosh Singh)
|
||||
- Improved: Markdown editor: Enable in-editor rendering by default (#13878) (#13215 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Improved: Move editor settings to dedicated editor section (#14403) (#13216 by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Improved: Prevent race condition when refreshing note contents on mobile (#14486 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Refresh note when updated via the API when in edit mode (#14378 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Remember the viewing / editing mode (updated) (#14363) (#11521 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Remove redundant navigation history for notes or folders which were deleted (#13428 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Store note history settings in sync info (#14449) (#14336 by [@yugalkaushik](https://github.com/yugalkaushik))
|
||||
- Improved: Trigger a note refresh when viewing or editing a note and the contents are updated via the API (#13671 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Improved: Updated packages @react-native-community/datetimepicker (v8.5.1), form-data (v4.0.5), react (v19.1.5), react-native-localize (v3.6.0), react-native-share (v12.2.1), react-native-svg (v15.14.0), react-native-webview (v13.16.0), sharp (v0.34.5), style-to-js (v1.1.21)
|
||||
- Improved: Upgrade React Native to v0.81.6 (#14330 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Add a reveal in notebook option for notes (#14338) (#14255 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Defer starting revision service maintenance until the initial sync has completed (#14394) (#13660 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Fix biometric 'try again' button is off-screen on certain devices (#14373) (#14195 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix heading links (#14201 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix missing conflict scenario (#13624) (#13611 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Fix profile data not deleted when removing profiles (#14369) (#13871 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix status 400 error on Tomcat WebDAV servers (#14332 by [@horvatkm](https://github.com/horvatkm))
|
||||
- Fixed: Fix unexpected conflicts created during sync (#14453 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Fix unexpected conflicts sometimes created after a full sync (#14388) (#14383 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Handle missing script assets in HTML export (#14442) (#12545 by [@kanishka0411](https://github.com/kanishka0411))
|
||||
- Fixed: Hide the expand / collapse title button when the title is too long (#14203) (#14194 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Improve dropdown menu positioning (#14288) (#14275 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
|
||||
- Fixed: Make the view / edit note button hidden when an editor plugin is visible (#14458) (#14452 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Reset undo/redo button state when toggling an editor plugin (#14444) (#14387 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: Support include_deleted parameter for GET /folders endpoint (#14421) (#14335 by Sriram Varun Kumar)
|
||||
- Fixed: Uses consistent padding in plugin info dialog (#14466) (#11793 by [@Nagmani001](https://github.com/Nagmani001))
|
||||
- Fixed: When cleaning old revisions, ensure revisions are merged for all revision branches (#13795) (#13782 by [@mrjo118](https://github.com/mrjo118))
|
||||
- Fixed: YouTube videos are displayed inline too (#14370) (#14352)
|
||||
|
||||
## [ios-v13.6.1](https://github.com/laurent22/joplin/releases/tag/ios-v13.6.1) - 2026-02-04T14:45:26Z
|
||||
|
||||
- New: Add more error information when the profile is corrupted (f075b56)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Transcribe Changelog
|
||||
|
||||
## [transcribe-v3.6.6](https://github.com/laurent22/joplin/releases/tag/transcribe-v3.6.6) - 2026-02-26T21:08:33Z
|
||||
|
||||
- Improved: Upgraded image to node: 24-bookworm to fix build issue (513341f)
|
||||
|
||||
## [transcribe-v3.6.5](https://github.com/laurent22/joplin/releases/tag/transcribe-v3.6.5) - 2026-02-26T15:06:49Z
|
||||
|
||||
- Fixed: Fixed location of llamacpp library (df10bbd)
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
updated: 2026-02-01T02:35:07Z
|
||||
updated: 2026-03-01T02:32:04Z
|
||||
---
|
||||
|
||||
# Joplin statistics
|
||||
|
||||
| Name | Value |
|
||||
| ----- | ----- |
|
||||
| Total Windows downloads | 7,693,776 |
|
||||
| Total macOs downloads | 2,092,639 |
|
||||
| Total Linux downloads | 1,732,101 |
|
||||
| Total Windows downloads | 7,836,256 |
|
||||
| Total macOs downloads | 2,103,860 |
|
||||
| Total Linux downloads | 1,758,947 |
|
||||
| Windows % | 67% |
|
||||
| macOS % | 18% |
|
||||
| Linux % | 15% |
|
||||
@@ -17,278 +17,279 @@ updated: 2026-02-01T02:35:07Z
|
||||
|
||||
| Version | Date | Windows | macOS | Linux | Total |
|
||||
| ----- | ----- | ----- | ----- | ----- | ----- |
|
||||
| [v3.6.2](https://github.com/laurent22/joplin/releases/tag/v3.6.2) (p) | 2026-01-18T20:10:43Z | 2,014 | 375 | 652 | 3,041 |
|
||||
| [v3.6.1](https://github.com/laurent22/joplin/releases/tag/v3.6.1) (p) | 2026-01-17T14:17:29Z | 451 | 86 | 90 | 627 |
|
||||
| [v3.5.12](https://github.com/laurent22/joplin/releases/tag/v3.5.12) | 2026-01-17T14:20:33Z | 109,044 | 8,240 | 15,151 | 132,435 |
|
||||
| [v3.5.11](https://github.com/laurent22/joplin/releases/tag/v3.5.11) | 2026-01-12T15:17:25Z | 74,153 | 6,083 | 5,681 | 85,917 |
|
||||
| [v3.5.10](https://github.com/laurent22/joplin/releases/tag/v3.5.10) (p) | 2026-01-08T20:18:15Z | 999 | 167 | 256 | 1,422 |
|
||||
| [v3.5.9](https://github.com/laurent22/joplin/releases/tag/v3.5.9) (p) | 2025-11-30T19:11:11Z | 5,307 | 948 | 2,084 | 8,339 |
|
||||
| [v3.5.7](https://github.com/laurent22/joplin/releases/tag/v3.5.7) (p) | 2025-11-22T08:35:36Z | 1,835 | 329 | 1,116 | 3,280 |
|
||||
| [v3.5.6](https://github.com/laurent22/joplin/releases/tag/v3.5.6) (p) | 2025-10-29T14:48:46Z | 4,250 | 675 | 1,462 | 6,387 |
|
||||
| [v3.5.5](https://github.com/laurent22/joplin/releases/tag/v3.5.5) (p) | 2025-10-18T10:31:09Z | 2,436 | 374 | 587 | 3,397 |
|
||||
| [v3.5.4](https://github.com/laurent22/joplin/releases/tag/v3.5.4) (p) | 2025-10-10T17:19:58Z | 2,521 | 264 | 336 | 3,121 |
|
||||
| [v3.4.12](https://github.com/laurent22/joplin/releases/tag/v3.4.12) | 2025-09-09T21:35:47Z | 367,244 | 34,261 | 100,031 | 501,536 |
|
||||
| [v3.4.10](https://github.com/laurent22/joplin/releases/tag/v3.4.10) | 2025-09-01T12:25:22Z | 77,546 | 7,864 | 10,380 | 95,790 |
|
||||
| [v3.4.7](https://github.com/laurent22/joplin/releases/tag/v3.4.7) (p) | 2025-08-23T10:49:54Z | 8,074 | 385 | 603 | 9,062 |
|
||||
| [v3.4.6](https://github.com/laurent22/joplin/releases/tag/v3.4.6) (p) | 2025-08-20T20:30:35Z | 42,918 | 5,175 | 2,645 | 50,738 |
|
||||
| [v3.5.13](https://github.com/laurent22/joplin/releases/tag/v3.5.13) | 2026-02-25T21:19:11Z | 41,765 | 3,352 | 2,932 | 48,049 |
|
||||
| [v3.6.2](https://github.com/laurent22/joplin/releases/tag/v3.6.2) (p) | 2026-01-18T20:10:43Z | 3,758 | 947 | 2,053 | 6,758 |
|
||||
| [v3.6.1](https://github.com/laurent22/joplin/releases/tag/v3.6.1) (p) | 2026-01-17T14:17:29Z | 479 | 92 | 101 | 672 |
|
||||
| [v3.5.12](https://github.com/laurent22/joplin/releases/tag/v3.5.12) | 2026-01-17T14:20:33Z | 196,916 | 14,452 | 36,257 | 247,625 |
|
||||
| [v3.5.11](https://github.com/laurent22/joplin/releases/tag/v3.5.11) | 2026-01-12T15:17:25Z | 74,487 | 6,148 | 5,714 | 86,349 |
|
||||
| [v3.5.10](https://github.com/laurent22/joplin/releases/tag/v3.5.10) (p) | 2026-01-08T20:18:15Z | 1,002 | 171 | 258 | 1,431 |
|
||||
| [v3.5.9](https://github.com/laurent22/joplin/releases/tag/v3.5.9) (p) | 2025-11-30T19:11:11Z | 5,378 | 949 | 2,090 | 8,417 |
|
||||
| [v3.5.7](https://github.com/laurent22/joplin/releases/tag/v3.5.7) (p) | 2025-11-22T08:35:36Z | 1,837 | 330 | 1,123 | 3,290 |
|
||||
| [v3.5.6](https://github.com/laurent22/joplin/releases/tag/v3.5.6) (p) | 2025-10-29T14:48:46Z | 4,254 | 684 | 1,464 | 6,402 |
|
||||
| [v3.5.5](https://github.com/laurent22/joplin/releases/tag/v3.5.5) (p) | 2025-10-18T10:31:09Z | 2,437 | 374 | 588 | 3,399 |
|
||||
| [v3.5.4](https://github.com/laurent22/joplin/releases/tag/v3.5.4) (p) | 2025-10-10T17:19:58Z | 2,525 | 264 | 339 | 3,128 |
|
||||
| [v3.4.12](https://github.com/laurent22/joplin/releases/tag/v3.4.12) | 2025-09-09T21:35:47Z | 367,639 | 34,318 | 100,212 | 502,169 |
|
||||
| [v3.4.10](https://github.com/laurent22/joplin/releases/tag/v3.4.10) | 2025-09-01T12:25:22Z | 77,785 | 7,907 | 10,416 | 96,108 |
|
||||
| [v3.4.7](https://github.com/laurent22/joplin/releases/tag/v3.4.7) (p) | 2025-08-23T10:49:54Z | 8,098 | 385 | 606 | 9,089 |
|
||||
| [v3.4.6](https://github.com/laurent22/joplin/releases/tag/v3.4.6) (p) | 2025-08-20T20:30:35Z | 43,079 | 5,201 | 2,666 | 50,946 |
|
||||
| [v3.4.5](https://github.com/laurent22/joplin/releases/tag/v3.4.5) (p) | 2025-08-10T12:49:30Z | 1,788 | 399 | 450 | 2,637 |
|
||||
| [v3.4.4](https://github.com/laurent22/joplin/releases/tag/v3.4.4) (p) | 2025-08-13T16:46:39Z | 113 | 60 | 42 | 215 |
|
||||
| [v3.4.3](https://github.com/laurent22/joplin/releases/tag/v3.4.3) (p) | 2025-07-25T19:49:44Z | 2,005 | 505 | 569 | 3,079 |
|
||||
| [v3.4.3](https://github.com/laurent22/joplin/releases/tag/v3.4.3) (p) | 2025-07-25T19:49:44Z | 2,005 | 505 | 571 | 3,081 |
|
||||
| [v3.4.2](https://github.com/laurent22/joplin/releases/tag/v3.4.2) (p) | 2025-07-24T10:43:55Z | 645 | 161 | 130 | 936 |
|
||||
| [v3.3.13](https://github.com/laurent22/joplin/releases/tag/v3.3.13) | 2025-06-09T20:13:30Z | 266,081 | 27,230 | 61,031 | 354,342 |
|
||||
| [v3.4.1](https://github.com/laurent22/joplin/releases/tag/v3.4.1) (p) | 2025-05-20T09:59:39Z | 3,967 | 1,163 | 1,332 | 6,462 |
|
||||
| [v3.3.12](https://github.com/laurent22/joplin/releases/tag/v3.3.12) | 2025-05-04T18:12:23Z | 165,618 | 21,592 | 28,244 | 215,454 |
|
||||
| [v3.3.10](https://github.com/laurent22/joplin/releases/tag/v3.3.10) | 2025-05-02T19:46:15Z | 32,250 | 5,165 | 1,847 | 39,262 |
|
||||
| [v3.3.9](https://github.com/laurent22/joplin/releases/tag/v3.3.9) | 2025-05-01T21:02:12Z | 31,181 | 6,157 | 1,203 | 38,541 |
|
||||
| [v3.3.7](https://github.com/laurent22/joplin/releases/tag/v3.3.7) (p) | 2025-04-29T13:47:19Z | 771 | 0 | 182 | 953 |
|
||||
| [v3.3.13](https://github.com/laurent22/joplin/releases/tag/v3.3.13) | 2025-06-09T20:13:30Z | 266,817 | 27,292 | 61,368 | 355,477 |
|
||||
| [v3.4.1](https://github.com/laurent22/joplin/releases/tag/v3.4.1) (p) | 2025-05-20T09:59:39Z | 3,968 | 1,163 | 1,332 | 6,463 |
|
||||
| [v3.3.12](https://github.com/laurent22/joplin/releases/tag/v3.3.12) | 2025-05-04T18:12:23Z | 166,534 | 21,595 | 28,246 | 216,375 |
|
||||
| [v3.3.10](https://github.com/laurent22/joplin/releases/tag/v3.3.10) | 2025-05-02T19:46:15Z | 32,967 | 5,165 | 1,848 | 39,980 |
|
||||
| [v3.3.9](https://github.com/laurent22/joplin/releases/tag/v3.3.9) | 2025-05-01T21:02:12Z | 31,912 | 6,158 | 1,204 | 39,274 |
|
||||
| [v3.3.7](https://github.com/laurent22/joplin/releases/tag/v3.3.7) (p) | 2025-04-29T13:47:19Z | 772 | 0 | 182 | 954 |
|
||||
| [v3.3.6](https://github.com/laurent22/joplin/releases/tag/v3.3.6) (p) | 2025-04-24T12:27:20Z | 1,071 | 303 | 262 | 1,636 |
|
||||
| [v3.3.5](https://github.com/laurent22/joplin/releases/tag/v3.3.5) (p) | 2025-04-17T13:40:31Z | 1,402 | 319 | 316 | 2,037 |
|
||||
| [v3.3.4](https://github.com/laurent22/joplin/releases/tag/v3.3.4) (p) | 2025-04-07T20:23:35Z | 1,644 | 427 | 382 | 2,453 |
|
||||
| [v3.3.3](https://github.com/laurent22/joplin/releases/tag/v3.3.3) (p) | 2025-03-16T11:52:33Z | 2,717 | 844 | 991 | 4,552 |
|
||||
| [v3.2.13](https://github.com/laurent22/joplin/releases/tag/v3.2.13) | 2025-02-28T14:38:21Z | 224,897 | 33,047 | 44,720 | 302,664 |
|
||||
| [v3.3.4](https://github.com/laurent22/joplin/releases/tag/v3.3.4) (p) | 2025-04-07T20:23:35Z | 1,644 | 427 | 383 | 2,454 |
|
||||
| [v3.3.3](https://github.com/laurent22/joplin/releases/tag/v3.3.3) (p) | 2025-03-16T11:52:33Z | 2,718 | 844 | 992 | 4,554 |
|
||||
| [v3.2.13](https://github.com/laurent22/joplin/releases/tag/v3.2.13) | 2025-02-28T14:38:21Z | 225,138 | 33,084 | 44,791 | 303,013 |
|
||||
| [v3.3.2](https://github.com/laurent22/joplin/releases/tag/v3.3.2) (p) | 2025-02-19T17:34:26Z | 2,375 | 595 | 665 | 3,635 |
|
||||
| [v3.3.1](https://github.com/laurent22/joplin/releases/tag/v3.3.1) (p) | 2025-02-16T17:06:26Z | 871 | 217 | 186 | 1,274 |
|
||||
| [v3.2.12](https://github.com/laurent22/joplin/releases/tag/v3.2.12) | 2025-01-23T23:52:04Z | 153,757 | 25,408 | 28,064 | 207,229 |
|
||||
| [v3.2.11](https://github.com/laurent22/joplin/releases/tag/v3.2.11) | 2025-01-13T17:48:21Z | 67,721 | 14,884 | 6,903 | 89,508 |
|
||||
| [v3.2.10](https://github.com/laurent22/joplin/releases/tag/v3.2.10) (p) | 2025-01-10T10:17:28Z | 2,987 | 195 | 205 | 3,387 |
|
||||
| [v3.2.9](https://github.com/laurent22/joplin/releases/tag/v3.2.9) (p) | 2025-01-09T22:58:42Z | 394 | 120 | 70 | 584 |
|
||||
| [v3.2.7](https://github.com/laurent22/joplin/releases/tag/v3.2.7) (p) | 2025-01-06T16:35:41Z | 909 | 185 | 907 | 2,001 |
|
||||
| [v3.2.6](https://github.com/laurent22/joplin/releases/tag/v3.2.6) (p) | 2024-12-23T21:54:40Z | 1,789 | 364 | 494 | 2,647 |
|
||||
| [v3.3.1](https://github.com/laurent22/joplin/releases/tag/v3.3.1) (p) | 2025-02-16T17:06:26Z | 872 | 220 | 187 | 1,279 |
|
||||
| [v3.2.12](https://github.com/laurent22/joplin/releases/tag/v3.2.12) | 2025-01-23T23:52:04Z | 153,893 | 25,453 | 28,112 | 207,458 |
|
||||
| [v3.2.11](https://github.com/laurent22/joplin/releases/tag/v3.2.11) | 2025-01-13T17:48:21Z | 67,898 | 14,909 | 6,928 | 89,735 |
|
||||
| [v3.2.10](https://github.com/laurent22/joplin/releases/tag/v3.2.10) (p) | 2025-01-10T10:17:28Z | 3,032 | 195 | 205 | 3,432 |
|
||||
| [v3.2.9](https://github.com/laurent22/joplin/releases/tag/v3.2.9) (p) | 2025-01-09T22:58:42Z | 394 | 123 | 70 | 587 |
|
||||
| [v3.2.7](https://github.com/laurent22/joplin/releases/tag/v3.2.7) (p) | 2025-01-06T16:35:41Z | 909 | 185 | 912 | 2,006 |
|
||||
| [v3.2.6](https://github.com/laurent22/joplin/releases/tag/v3.2.6) (p) | 2024-12-23T21:54:40Z | 1,791 | 364 | 496 | 2,651 |
|
||||
| [v3.2.5](https://github.com/laurent22/joplin/releases/tag/v3.2.5) (p) | 2024-12-18T10:41:13Z | 1,030 | 229 | 238 | 1,497 |
|
||||
| [v3.2.4](https://github.com/laurent22/joplin/releases/tag/v3.2.4) (p) | 2024-12-12T17:59:52Z | 1,042 | 182 | 253 | 1,477 |
|
||||
| [v3.2.3](https://github.com/laurent22/joplin/releases/tag/v3.2.3) (p) | 2024-11-18T00:09:05Z | 2,736 | 585 | 912 | 4,233 |
|
||||
| [v3.2.1](https://github.com/laurent22/joplin/releases/tag/v3.2.1) (p) | 2024-11-10T16:16:27Z | 1,285 | 268 | 366 | 1,919 |
|
||||
| [v3.1.24](https://github.com/laurent22/joplin/releases/tag/v3.1.24) | 2024-11-09T15:08:29Z | 210,156 | 33,577 | 43,939 | 287,672 |
|
||||
| [v3.1.23](https://github.com/laurent22/joplin/releases/tag/v3.1.23) | 2024-11-07T10:56:45Z | 28,642 | 6,768 | 1,563 | 36,973 |
|
||||
| [v3.1.22](https://github.com/laurent22/joplin/releases/tag/v3.1.22) | 2024-11-05T08:59:32Z | 30,552 | 8,732 | 1,240 | 40,524 |
|
||||
| [v3.1.20](https://github.com/laurent22/joplin/releases/tag/v3.1.20) | 2024-10-22T12:21:32Z | 96,993 | 19,413 | 13,951 | 130,357 |
|
||||
| [v3.2.3](https://github.com/laurent22/joplin/releases/tag/v3.2.3) (p) | 2024-11-18T00:09:05Z | 2,738 | 586 | 914 | 4,238 |
|
||||
| [v3.2.1](https://github.com/laurent22/joplin/releases/tag/v3.2.1) (p) | 2024-11-10T16:16:27Z | 1,287 | 269 | 366 | 1,922 |
|
||||
| [v3.1.24](https://github.com/laurent22/joplin/releases/tag/v3.1.24) | 2024-11-09T15:08:29Z | 210,337 | 33,591 | 43,977 | 287,905 |
|
||||
| [v3.1.23](https://github.com/laurent22/joplin/releases/tag/v3.1.23) | 2024-11-07T10:56:45Z | 28,730 | 6,768 | 1,563 | 37,061 |
|
||||
| [v3.1.22](https://github.com/laurent22/joplin/releases/tag/v3.1.22) | 2024-11-05T08:59:32Z | 30,666 | 8,732 | 1,241 | 40,639 |
|
||||
| [v3.1.20](https://github.com/laurent22/joplin/releases/tag/v3.1.20) | 2024-10-22T12:21:32Z | 97,191 | 19,414 | 13,951 | 130,556 |
|
||||
| [v3.1.18](https://github.com/laurent22/joplin/releases/tag/v3.1.18) (p) | 2024-10-11T23:27:10Z | 1,541 | 311 | 605 | 2,457 |
|
||||
| [v3.1.17](https://github.com/laurent22/joplin/releases/tag/v3.1.17) (p) | 2024-09-26T11:57:54Z | 1,732 | 384 | 548 | 2,664 |
|
||||
| [v3.1.15](https://github.com/laurent22/joplin/releases/tag/v3.1.15) (p) | 2024-09-17T09:15:10Z | 1,216 | 255 | 513 | 1,984 |
|
||||
| [v3.1.8](https://github.com/laurent22/joplin/releases/tag/v3.1.8) (p) | 2024-09-08T20:32:44Z | 1,256 | 288 | 351 | 1,895 |
|
||||
| [v3.1.6](https://github.com/laurent22/joplin/releases/tag/v3.1.6) (p) | 2024-09-02T13:19:40Z | 996 | 260 | 442 | 1,698 |
|
||||
| [v3.1.4](https://github.com/laurent22/joplin/releases/tag/v3.1.4) (p) | 2024-08-27T17:46:38Z | 979 | 207 | 266 | 1,452 |
|
||||
| [v3.0.15](https://github.com/laurent22/joplin/releases/tag/v3.0.15) | 2024-08-21T09:19:58Z | 205,455 | 37,888 | 45,228 | 288,571 |
|
||||
| [v3.1.4](https://github.com/laurent22/joplin/releases/tag/v3.1.4) (p) | 2024-08-27T17:46:38Z | 979 | 208 | 266 | 1,453 |
|
||||
| [v3.0.15](https://github.com/laurent22/joplin/releases/tag/v3.0.15) | 2024-08-21T09:19:58Z | 205,634 | 37,890 | 45,233 | 288,757 |
|
||||
| [v3.1.3](https://github.com/laurent22/joplin/releases/tag/v3.1.3) (p) | 2024-08-17T13:08:21Z | 1,272 | 317 | 504 | 2,093 |
|
||||
| [v3.1.2](https://github.com/laurent22/joplin/releases/tag/v3.1.2) (p) | 2024-08-16T09:00:59Z | 484 | 147 | 107 | 738 |
|
||||
| [v3.1.1](https://github.com/laurent22/joplin/releases/tag/v3.1.1) (p) | 2024-08-10T11:36:02Z | 1,116 | 229 | 282 | 1,627 |
|
||||
| [v2.14.23](https://github.com/laurent22/joplin/releases/tag/v2.14.23) | 2024-08-07T11:15:25Z | 10,883 | 2,794 | 656 | 14,333 |
|
||||
| [v3.0.14](https://github.com/laurent22/joplin/releases/tag/v3.0.14) | 2024-07-28T13:55:50Z | 91,293 | 18,600 | 18,874 | 128,767 |
|
||||
| [v3.0.12](https://github.com/laurent22/joplin/releases/tag/v3.0.12) | 2024-07-02T17:11:14Z | 46,275 | 12,907 | 7,403 | 66,585 |
|
||||
| [v3.1.2](https://github.com/laurent22/joplin/releases/tag/v3.1.2) (p) | 2024-08-16T09:00:59Z | 484 | 148 | 109 | 741 |
|
||||
| [v3.1.1](https://github.com/laurent22/joplin/releases/tag/v3.1.1) (p) | 2024-08-10T11:36:02Z | 1,116 | 231 | 282 | 1,629 |
|
||||
| [v2.14.23](https://github.com/laurent22/joplin/releases/tag/v2.14.23) | 2024-08-07T11:15:25Z | 10,895 | 2,815 | 657 | 14,367 |
|
||||
| [v3.0.14](https://github.com/laurent22/joplin/releases/tag/v3.0.14) | 2024-07-28T13:55:50Z | 91,488 | 18,601 | 18,874 | 128,963 |
|
||||
| [v3.0.12](https://github.com/laurent22/joplin/releases/tag/v3.0.12) | 2024-07-02T17:11:14Z | 46,465 | 12,915 | 7,409 | 66,789 |
|
||||
| [v3.0.11](https://github.com/laurent22/joplin/releases/tag/v3.0.11) (p) | 2024-06-29T10:20:02Z | 875 | 181 | 284 | 1,340 |
|
||||
| [v3.0.10](https://github.com/laurent22/joplin/releases/tag/v3.0.10) (p) | 2024-06-19T15:24:07Z | 1,651 | 307 | 577 | 2,535 |
|
||||
| [v3.0.10](https://github.com/laurent22/joplin/releases/tag/v3.0.10) (p) | 2024-06-19T15:24:07Z | 1,651 | 308 | 578 | 2,537 |
|
||||
| [v3.0.9](https://github.com/laurent22/joplin/releases/tag/v3.0.9) (p) | 2024-06-12T19:07:50Z | 1,303 | 277 | 395 | 1,975 |
|
||||
| [v3.0.8](https://github.com/laurent22/joplin/releases/tag/v3.0.8) (p) | 2024-05-22T14:20:45Z | 2,696 | 0 | 955 | 3,651 |
|
||||
| [v2.14.22](https://github.com/laurent22/joplin/releases/tag/v2.14.22) | 2024-05-22T19:19:02Z | 144,593 | 30,950 | 25,579 | 201,122 |
|
||||
| [v3.0.6](https://github.com/laurent22/joplin/releases/tag/v3.0.6) (p) | 2024-04-27T13:16:04Z | 3,040 | 705 | 879 | 4,624 |
|
||||
| [v3.0.3](https://github.com/laurent22/joplin/releases/tag/v3.0.3) (p) | 2024-04-18T15:41:38Z | 1,518 | 339 | 348 | 2,205 |
|
||||
| [v3.0.2](https://github.com/laurent22/joplin/releases/tag/v3.0.2) (p) | 2024-03-21T18:18:49Z | 2,909 | 762 | 1,125 | 4,796 |
|
||||
| [v2.14.20](https://github.com/laurent22/joplin/releases/tag/v2.14.20) | 2024-03-18T17:05:17Z | 194,812 | 39,645 | 38,415 | 272,872 |
|
||||
| [v2.14.19](https://github.com/laurent22/joplin/releases/tag/v2.14.19) | 2024-03-08T10:45:16Z | 66,070 | 18,495 | 8,581 | 93,146 |
|
||||
| [v2.14.17](https://github.com/laurent22/joplin/releases/tag/v2.14.17) | 2024-03-01T18:10:26Z | 64,523 | 18,659 | 7,646 | 90,828 |
|
||||
| [v2.14.16](https://github.com/laurent22/joplin/releases/tag/v2.14.16) (p) | 2024-02-22T22:49:10Z | 1,383 | 302 | 394 | 2,079 |
|
||||
| [v2.14.15](https://github.com/laurent22/joplin/releases/tag/v2.14.15) (p) | 2024-02-19T11:24:57Z | 886 | 197 | 208 | 1,291 |
|
||||
| [v3.0.8](https://github.com/laurent22/joplin/releases/tag/v3.0.8) (p) | 2024-05-22T14:20:45Z | 2,697 | 0 | 955 | 3,652 |
|
||||
| [v2.14.22](https://github.com/laurent22/joplin/releases/tag/v2.14.22) | 2024-05-22T19:19:02Z | 144,684 | 30,993 | 25,604 | 201,281 |
|
||||
| [v3.0.6](https://github.com/laurent22/joplin/releases/tag/v3.0.6) (p) | 2024-04-27T13:16:04Z | 3,041 | 705 | 879 | 4,625 |
|
||||
| [v3.0.3](https://github.com/laurent22/joplin/releases/tag/v3.0.3) (p) | 2024-04-18T15:41:38Z | 1,518 | 341 | 348 | 2,207 |
|
||||
| [v3.0.2](https://github.com/laurent22/joplin/releases/tag/v3.0.2) (p) | 2024-03-21T18:18:49Z | 2,913 | 764 | 1,125 | 4,802 |
|
||||
| [v2.14.20](https://github.com/laurent22/joplin/releases/tag/v2.14.20) | 2024-03-18T17:05:17Z | 194,938 | 39,701 | 38,483 | 273,122 |
|
||||
| [v2.14.19](https://github.com/laurent22/joplin/releases/tag/v2.14.19) | 2024-03-08T10:45:16Z | 66,124 | 18,505 | 8,594 | 93,223 |
|
||||
| [v2.14.17](https://github.com/laurent22/joplin/releases/tag/v2.14.17) | 2024-03-01T18:10:26Z | 64,551 | 18,660 | 7,648 | 90,859 |
|
||||
| [v2.14.16](https://github.com/laurent22/joplin/releases/tag/v2.14.16) (p) | 2024-02-22T22:49:10Z | 1,386 | 304 | 394 | 2,084 |
|
||||
| [v2.14.15](https://github.com/laurent22/joplin/releases/tag/v2.14.15) (p) | 2024-02-19T11:24:57Z | 886 | 198 | 208 | 1,292 |
|
||||
| [v2.14.14](https://github.com/laurent22/joplin/releases/tag/v2.14.14) (p) | 2024-02-10T16:03:08Z | 1,305 | 259 | 399 | 1,963 |
|
||||
| [v2.14.13](https://github.com/laurent22/joplin/releases/tag/v2.14.13) (p) | 2024-02-09T16:31:54Z | 457 | 135 | 106 | 698 |
|
||||
| [v2.14.12](https://github.com/laurent22/joplin/releases/tag/v2.14.12) (p) | 2024-02-03T12:11:47Z | 1,014 | 233 | 268 | 1,515 |
|
||||
| [v2.14.11](https://github.com/laurent22/joplin/releases/tag/v2.14.11) (p) | 2024-01-26T11:53:05Z | 1,307 | 275 | 493 | 2,075 |
|
||||
| [v2.14.10](https://github.com/laurent22/joplin/releases/tag/v2.14.10) (p) | 2024-01-18T22:45:04Z | 2,130 | 286 | 390 | 2,806 |
|
||||
| [v2.13.15](https://github.com/laurent22/joplin/releases/tag/v2.13.15) | 2024-01-15T13:01:19Z | 151,241 | 34,191 | 29,307 | 214,739 |
|
||||
| [v2.13.14](https://github.com/laurent22/joplin/releases/tag/v2.13.14) | 2024-01-13T19:11:04Z | 20,878 | 7,846 | 2,383 | 31,107 |
|
||||
| [v2.14.9](https://github.com/laurent22/joplin/releases/tag/v2.14.9) (p) | 2024-01-11T22:17:59Z | 1,092 | 0 | 261 | 1,353 |
|
||||
| [v2.14.8](https://github.com/laurent22/joplin/releases/tag/v2.14.8) (p) | 2024-01-09T22:57:07Z | 791 | 253 | 199 | 1,243 |
|
||||
| [v2.14.7](https://github.com/laurent22/joplin/releases/tag/v2.14.7) (p) | 2024-01-08T11:51:49Z | 653 | 144 | 194 | 991 |
|
||||
| [v2.14.6](https://github.com/laurent22/joplin/releases/tag/v2.14.6) (p) | 2024-01-06T16:38:32Z | 761 | 166 | 168 | 1,095 |
|
||||
| [v2.13.13](https://github.com/laurent22/joplin/releases/tag/v2.13.13) | 2024-01-06T13:33:11Z | 55,100 | 15,954 | 6,368 | 77,422 |
|
||||
| [v2.13.12](https://github.com/laurent22/joplin/releases/tag/v2.13.12) | 2023-12-31T16:08:02Z | 46,242 | 14,316 | 5,111 | 65,669 |
|
||||
| [v2.13.11](https://github.com/laurent22/joplin/releases/tag/v2.13.11) | 2023-12-24T12:58:53Z | 47,035 | 13,283 | 6,023 | 66,341 |
|
||||
| [v2.13.10](https://github.com/laurent22/joplin/releases/tag/v2.13.10) | 2023-12-22T10:11:08Z | 20,446 | 8,784 | 1,612 | 30,842 |
|
||||
| [v2.13.9](https://github.com/laurent22/joplin/releases/tag/v2.13.9) | 2023-12-09T17:18:58Z | 69,242 | 21,942 | 8,654 | 99,838 |
|
||||
| [v2.13.8](https://github.com/laurent22/joplin/releases/tag/v2.13.8) | 2023-12-03T12:07:08Z | 51,644 | 17,923 | 5,238 | 74,805 |
|
||||
| [v2.14.13](https://github.com/laurent22/joplin/releases/tag/v2.14.13) (p) | 2024-02-09T16:31:54Z | 457 | 135 | 110 | 702 |
|
||||
| [v2.14.12](https://github.com/laurent22/joplin/releases/tag/v2.14.12) (p) | 2024-02-03T12:11:47Z | 1,016 | 233 | 269 | 1,518 |
|
||||
| [v2.14.11](https://github.com/laurent22/joplin/releases/tag/v2.14.11) (p) | 2024-01-26T11:53:05Z | 1,309 | 275 | 497 | 2,081 |
|
||||
| [v2.14.10](https://github.com/laurent22/joplin/releases/tag/v2.14.10) (p) | 2024-01-18T22:45:04Z | 2,130 | 288 | 391 | 2,809 |
|
||||
| [v2.13.15](https://github.com/laurent22/joplin/releases/tag/v2.13.15) | 2024-01-15T13:01:19Z | 151,320 | 34,201 | 29,330 | 214,851 |
|
||||
| [v2.13.14](https://github.com/laurent22/joplin/releases/tag/v2.13.14) | 2024-01-13T19:11:04Z | 20,914 | 7,847 | 2,393 | 31,154 |
|
||||
| [v2.14.9](https://github.com/laurent22/joplin/releases/tag/v2.14.9) (p) | 2024-01-11T22:17:59Z | 1,093 | 0 | 263 | 1,356 |
|
||||
| [v2.14.8](https://github.com/laurent22/joplin/releases/tag/v2.14.8) (p) | 2024-01-09T22:57:07Z | 797 | 254 | 201 | 1,252 |
|
||||
| [v2.14.7](https://github.com/laurent22/joplin/releases/tag/v2.14.7) (p) | 2024-01-08T11:51:49Z | 663 | 148 | 195 | 1,006 |
|
||||
| [v2.14.6](https://github.com/laurent22/joplin/releases/tag/v2.14.6) (p) | 2024-01-06T16:38:32Z | 761 | 167 | 168 | 1,096 |
|
||||
| [v2.13.13](https://github.com/laurent22/joplin/releases/tag/v2.13.13) | 2024-01-06T13:33:11Z | 55,139 | 15,955 | 6,368 | 77,462 |
|
||||
| [v2.13.12](https://github.com/laurent22/joplin/releases/tag/v2.13.12) | 2023-12-31T16:08:02Z | 46,278 | 14,326 | 5,111 | 65,715 |
|
||||
| [v2.13.11](https://github.com/laurent22/joplin/releases/tag/v2.13.11) | 2023-12-24T12:58:53Z | 47,062 | 13,283 | 6,024 | 66,369 |
|
||||
| [v2.13.10](https://github.com/laurent22/joplin/releases/tag/v2.13.10) | 2023-12-22T10:11:08Z | 20,495 | 8,818 | 1,636 | 30,949 |
|
||||
| [v2.13.9](https://github.com/laurent22/joplin/releases/tag/v2.13.9) | 2023-12-09T17:18:58Z | 69,311 | 21,942 | 8,657 | 99,910 |
|
||||
| [v2.13.8](https://github.com/laurent22/joplin/releases/tag/v2.13.8) | 2023-12-03T12:07:08Z | 51,673 | 17,923 | 5,238 | 74,834 |
|
||||
| [v2.13.6](https://github.com/laurent22/joplin/releases/tag/v2.13.6) (p) | 2023-11-17T19:24:03Z | 2,192 | 463 | 598 | 3,253 |
|
||||
| [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (p) | 2023-11-09T20:24:09Z | 1,504 | 356 | 459 | 2,319 |
|
||||
| [v2.13.4](https://github.com/laurent22/joplin/releases/tag/v2.13.4) (p) | 2023-10-31T00:01:00Z | 1,581 | 388 | 505 | 2,474 |
|
||||
| [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (p) | 2023-11-09T20:24:09Z | 1,506 | 357 | 459 | 2,322 |
|
||||
| [v2.13.4](https://github.com/laurent22/joplin/releases/tag/v2.13.4) (p) | 2023-10-31T00:01:00Z | 1,584 | 389 | 505 | 2,478 |
|
||||
| [v2.13.3](https://github.com/laurent22/joplin/releases/tag/v2.13.3) (p) | 2023-10-24T09:25:33Z | 1,315 | 285 | 305 | 1,905 |
|
||||
| [v2.12.19](https://github.com/laurent22/joplin/releases/tag/v2.12.19) | 2023-10-21T09:39:18Z | 168,293 | 43,680 | 27,916 | 239,889 |
|
||||
| [v2.12.19](https://github.com/laurent22/joplin/releases/tag/v2.12.19) | 2023-10-21T09:39:18Z | 168,335 | 43,710 | 27,945 | 239,990 |
|
||||
| [v2.13.2](https://github.com/laurent22/joplin/releases/tag/v2.13.2) (p) | 2023-10-06T17:00:07Z | 2,052 | 505 | 709 | 3,266 |
|
||||
| [v2.12.18](https://github.com/laurent22/joplin/releases/tag/v2.12.18) | 2023-09-22T14:37:24Z | 110,388 | 36,535 | 18,735 | 165,658 |
|
||||
| [v2.12.17](https://github.com/laurent22/joplin/releases/tag/v2.12.17) | 2023-09-14T21:54:52Z | 48,185 | 21,045 | 6,654 | 75,884 |
|
||||
| [v2.13.1](https://github.com/laurent22/joplin/releases/tag/v2.13.1) (p) | 2023-09-13T09:31:50Z | 1,396 | 431 | 690 | 2,517 |
|
||||
| [v2.12.16](https://github.com/laurent22/joplin/releases/tag/v2.12.16) | 2023-09-11T22:33:37Z | 28,829 | 14,678 | 2,472 | 45,979 |
|
||||
| [v2.12.15](https://github.com/laurent22/joplin/releases/tag/v2.12.15) | 2023-08-27T11:35:39Z | 65,826 | 28,205 | 8,501 | 102,532 |
|
||||
| [v2.12.12](https://github.com/laurent22/joplin/releases/tag/v2.12.12) (p) | 2023-08-19T22:44:56Z | 3,449 | 400 | 431 | 4,280 |
|
||||
| [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (p) | 2023-07-30T18:25:58Z | 8,097 | 3,821 | 918 | 12,836 |
|
||||
| [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (p) | 2023-07-25T16:06:08Z | 2,897 | 375 | 324 | 3,596 |
|
||||
| [v2.12.7](https://github.com/laurent22/joplin/releases/tag/v2.12.7) (p) | 2023-07-13T12:55:31Z | 2,209 | 669 | 596 | 3,474 |
|
||||
| [v2.12.5](https://github.com/laurent22/joplin/releases/tag/v2.12.5) (p) | 2023-07-12T15:03:46Z | 2,170 | 174 | 165 | 2,509 |
|
||||
| [v2.12.4](https://github.com/laurent22/joplin/releases/tag/v2.12.4) (p) | 2023-07-07T22:36:53Z | 2,820 | 2,136 | 226 | 5,182 |
|
||||
| [v2.12.3](https://github.com/laurent22/joplin/releases/tag/v2.12.3) (p) | 2023-07-07T10:16:55Z | 429 | 213 | 104 | 746 |
|
||||
| [v2.11.11](https://github.com/laurent22/joplin/releases/tag/v2.11.11) | 2023-06-23T15:16:37Z | 190,946 | 67,271 | 38,964 | 297,181 |
|
||||
| [v2.11.9](https://github.com/laurent22/joplin/releases/tag/v2.11.9) (p) | 2023-06-06T16:23:27Z | 2,321 | 583 | 754 | 3,658 |
|
||||
| [v2.12.18](https://github.com/laurent22/joplin/releases/tag/v2.12.18) | 2023-09-22T14:37:24Z | 110,428 | 36,558 | 18,758 | 165,744 |
|
||||
| [v2.12.17](https://github.com/laurent22/joplin/releases/tag/v2.12.17) | 2023-09-14T21:54:52Z | 48,187 | 21,069 | 6,677 | 75,933 |
|
||||
| [v2.13.1](https://github.com/laurent22/joplin/releases/tag/v2.13.1) (p) | 2023-09-13T09:31:50Z | 1,399 | 431 | 690 | 2,520 |
|
||||
| [v2.12.16](https://github.com/laurent22/joplin/releases/tag/v2.12.16) | 2023-09-11T22:33:37Z | 28,829 | 14,703 | 2,495 | 46,027 |
|
||||
| [v2.12.15](https://github.com/laurent22/joplin/releases/tag/v2.12.15) | 2023-08-27T11:35:39Z | 65,876 | 28,270 | 8,561 | 102,707 |
|
||||
| [v2.12.12](https://github.com/laurent22/joplin/releases/tag/v2.12.12) (p) | 2023-08-19T22:44:56Z | 3,493 | 402 | 431 | 4,326 |
|
||||
| [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (p) | 2023-07-30T18:25:58Z | 8,131 | 3,822 | 920 | 12,873 |
|
||||
| [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (p) | 2023-07-25T16:06:08Z | 2,935 | 375 | 324 | 3,634 |
|
||||
| [v2.12.7](https://github.com/laurent22/joplin/releases/tag/v2.12.7) (p) | 2023-07-13T12:55:31Z | 2,210 | 669 | 596 | 3,475 |
|
||||
| [v2.12.5](https://github.com/laurent22/joplin/releases/tag/v2.12.5) (p) | 2023-07-12T15:03:46Z | 2,219 | 177 | 166 | 2,562 |
|
||||
| [v2.12.4](https://github.com/laurent22/joplin/releases/tag/v2.12.4) (p) | 2023-07-07T22:36:53Z | 2,893 | 2,205 | 226 | 5,324 |
|
||||
| [v2.12.3](https://github.com/laurent22/joplin/releases/tag/v2.12.3) (p) | 2023-07-07T10:16:55Z | 430 | 213 | 104 | 747 |
|
||||
| [v2.11.11](https://github.com/laurent22/joplin/releases/tag/v2.11.11) | 2023-06-23T15:16:37Z | 191,074 | 67,298 | 38,995 | 297,367 |
|
||||
| [v2.11.9](https://github.com/laurent22/joplin/releases/tag/v2.11.9) (p) | 2023-06-06T16:23:27Z | 2,322 | 583 | 754 | 3,659 |
|
||||
| [v2.11.6](https://github.com/laurent22/joplin/releases/tag/v2.11.6) (p) | 2023-05-31T20:13:08Z | 1,184 | 443 | 353 | 1,980 |
|
||||
| [v2.11.5](https://github.com/laurent22/joplin/releases/tag/v2.11.5) (p) | 2023-05-28T00:41:40Z | 1,045 | 315 | 291 | 1,651 |
|
||||
| [v2.10.19](https://github.com/laurent22/joplin/releases/tag/v2.10.19) | 2023-05-17T12:25:41Z | 125,850 | 48,358 | 22,505 | 196,713 |
|
||||
| [v2.11.4](https://github.com/laurent22/joplin/releases/tag/v2.11.4) (p) | 2023-05-16T10:02:21Z | 1,098 | 477 | 424 | 1,999 |
|
||||
| [v2.10.19](https://github.com/laurent22/joplin/releases/tag/v2.10.19) | 2023-05-17T12:25:41Z | 125,945 | 48,384 | 22,534 | 196,863 |
|
||||
| [v2.11.4](https://github.com/laurent22/joplin/releases/tag/v2.11.4) (p) | 2023-05-16T10:02:21Z | 1,104 | 479 | 425 | 2,008 |
|
||||
| [v2.11.3](https://github.com/laurent22/joplin/releases/tag/v2.11.3) (p) | 2023-05-16T09:09:57Z | 158 | 49 | 46 | 253 |
|
||||
| [v2.10.18](https://github.com/laurent22/joplin/releases/tag/v2.10.18) | 2023-05-09T13:27:43Z | 57,557 | 24,272 | 6,818 | 88,647 |
|
||||
| [v2.10.17](https://github.com/laurent22/joplin/releases/tag/v2.10.17) | 2023-05-08T17:27:28Z | 19,888 | 11,518 | 900 | 32,306 |
|
||||
| [v2.10.16](https://github.com/laurent22/joplin/releases/tag/v2.10.16) | 2023-04-27T09:27:45Z | 10,497 | 4,265 | 792 | 15,554 |
|
||||
| [v2.10.18](https://github.com/laurent22/joplin/releases/tag/v2.10.18) | 2023-05-09T13:27:43Z | 57,628 | 24,297 | 6,842 | 88,767 |
|
||||
| [v2.10.17](https://github.com/laurent22/joplin/releases/tag/v2.10.17) | 2023-05-08T17:27:28Z | 19,928 | 11,519 | 900 | 32,347 |
|
||||
| [v2.10.16](https://github.com/laurent22/joplin/releases/tag/v2.10.16) | 2023-04-27T09:27:45Z | 10,563 | 4,266 | 792 | 15,621 |
|
||||
| [v2.10.15](https://github.com/laurent22/joplin/releases/tag/v2.10.15) (p) | 2023-04-26T22:02:16Z | 392 | 149 | 65 | 606 |
|
||||
| [v2.10.13](https://github.com/laurent22/joplin/releases/tag/v2.10.13) (p) | 2023-04-03T16:53:46Z | 5,207 | 831 | 1,081 | 7,119 |
|
||||
| [v2.10.12](https://github.com/laurent22/joplin/releases/tag/v2.10.12) (p) | 2023-03-23T12:17:13Z | 4,177 | 521 | 607 | 5,305 |
|
||||
| [v2.10.11](https://github.com/laurent22/joplin/releases/tag/v2.10.11) (p) | 2023-03-17T10:54:02Z | 3,548 | 386 | 409 | 4,343 |
|
||||
| [v2.10.10](https://github.com/laurent22/joplin/releases/tag/v2.10.10) (p) | 2023-03-13T23:16:37Z | 3,039 | 286 | 258 | 3,583 |
|
||||
| [v2.10.9](https://github.com/laurent22/joplin/releases/tag/v2.10.9) (p) | 2023-03-12T16:16:45Z | 2,590 | 216 | 299 | 3,105 |
|
||||
| [v2.10.8](https://github.com/laurent22/joplin/releases/tag/v2.10.8) (p) | 2023-02-26T12:53:55Z | 5,070 | 574 | 875 | 6,519 |
|
||||
| [v2.10.7](https://github.com/laurent22/joplin/releases/tag/v2.10.7) (p) | 2023-02-24T10:56:20Z | 2,745 | 193 | 282 | 3,220 |
|
||||
| [v2.10.6](https://github.com/laurent22/joplin/releases/tag/v2.10.6) (p) | 2023-02-20T14:00:05Z | 3,531 | 344 | 292 | 4,167 |
|
||||
| [v2.10.5](https://github.com/laurent22/joplin/releases/tag/v2.10.5) | 2023-01-16T15:00:53Z | 388 | 108 | 330 | 826 |
|
||||
| [v2.10.4](https://github.com/laurent22/joplin/releases/tag/v2.10.4) (p) | 2023-01-05T13:09:20Z | 8,754 | 1,308 | 1,815 | 11,877 |
|
||||
| [v2.10.3](https://github.com/laurent22/joplin/releases/tag/v2.10.3) (p) | 2022-12-31T15:53:23Z | 3,323 | 316 | 421 | 4,060 |
|
||||
| [v2.10.2](https://github.com/laurent22/joplin/releases/tag/v2.10.2) (p) | 2022-12-18T18:05:08Z | 4,747 | 594 | 643 | 5,984 |
|
||||
| [v2.9.17](https://github.com/laurent22/joplin/releases/tag/v2.9.17) | 2022-11-15T10:28:37Z | 336,728 | 108,813 | 83,415 | 528,956 |
|
||||
| [v2.9.12](https://github.com/laurent22/joplin/releases/tag/v2.9.12) (p) | 2022-11-01T17:06:05Z | 11,926 | 614 | 548 | 13,088 |
|
||||
| [v2.9.11](https://github.com/laurent22/joplin/releases/tag/v2.9.11) (p) | 2022-10-23T16:09:58Z | 4,071 | 533 | 764 | 5,368 |
|
||||
| [v2.9.4](https://github.com/laurent22/joplin/releases/tag/v2.9.4) (p) | 2022-08-18T16:52:26Z | 9,112 | 1,871 | 2,203 | 13,186 |
|
||||
| [v2.10.13](https://github.com/laurent22/joplin/releases/tag/v2.10.13) (p) | 2023-04-03T16:53:46Z | 5,243 | 832 | 1,081 | 7,156 |
|
||||
| [v2.10.12](https://github.com/laurent22/joplin/releases/tag/v2.10.12) (p) | 2023-03-23T12:17:13Z | 4,208 | 521 | 607 | 5,336 |
|
||||
| [v2.10.11](https://github.com/laurent22/joplin/releases/tag/v2.10.11) (p) | 2023-03-17T10:54:02Z | 3,586 | 388 | 413 | 4,387 |
|
||||
| [v2.10.10](https://github.com/laurent22/joplin/releases/tag/v2.10.10) (p) | 2023-03-13T23:16:37Z | 3,077 | 287 | 259 | 3,623 |
|
||||
| [v2.10.9](https://github.com/laurent22/joplin/releases/tag/v2.10.9) (p) | 2023-03-12T16:16:45Z | 2,620 | 216 | 299 | 3,135 |
|
||||
| [v2.10.8](https://github.com/laurent22/joplin/releases/tag/v2.10.8) (p) | 2023-02-26T12:53:55Z | 5,108 | 574 | 875 | 6,557 |
|
||||
| [v2.10.7](https://github.com/laurent22/joplin/releases/tag/v2.10.7) (p) | 2023-02-24T10:56:20Z | 2,781 | 194 | 283 | 3,258 |
|
||||
| [v2.10.6](https://github.com/laurent22/joplin/releases/tag/v2.10.6) (p) | 2023-02-20T14:00:05Z | 3,570 | 344 | 292 | 4,206 |
|
||||
| [v2.10.5](https://github.com/laurent22/joplin/releases/tag/v2.10.5) | 2023-01-16T15:00:53Z | 388 | 108 | 332 | 828 |
|
||||
| [v2.10.4](https://github.com/laurent22/joplin/releases/tag/v2.10.4) (p) | 2023-01-05T13:09:20Z | 8,791 | 1,308 | 1,816 | 11,915 |
|
||||
| [v2.10.3](https://github.com/laurent22/joplin/releases/tag/v2.10.3) (p) | 2022-12-31T15:53:23Z | 3,360 | 316 | 421 | 4,097 |
|
||||
| [v2.10.2](https://github.com/laurent22/joplin/releases/tag/v2.10.2) (p) | 2022-12-18T18:05:08Z | 4,786 | 596 | 643 | 6,025 |
|
||||
| [v2.9.17](https://github.com/laurent22/joplin/releases/tag/v2.9.17) | 2022-11-15T10:28:37Z | 336,822 | 108,817 | 83,418 | 529,057 |
|
||||
| [v2.9.12](https://github.com/laurent22/joplin/releases/tag/v2.9.12) (p) | 2022-11-01T17:06:05Z | 11,960 | 614 | 548 | 13,122 |
|
||||
| [v2.9.11](https://github.com/laurent22/joplin/releases/tag/v2.9.11) (p) | 2022-10-23T16:09:58Z | 4,104 | 534 | 765 | 5,403 |
|
||||
| [v2.9.4](https://github.com/laurent22/joplin/releases/tag/v2.9.4) (p) | 2022-08-18T16:52:26Z | 9,142 | 1,871 | 2,203 | 13,216 |
|
||||
| [v2.9.3](https://github.com/laurent22/joplin/releases/tag/v2.9.3) (p) | 2022-08-18T13:11:09Z | 368 | 95 | 279 | 742 |
|
||||
| [v2.9.2](https://github.com/laurent22/joplin/releases/tag/v2.9.2) (p) | 2022-08-12T18:12:12Z | 1,539 | 450 | 0 | 1,989 |
|
||||
| [v2.9.1](https://github.com/laurent22/joplin/releases/tag/v2.9.1) (p) | 2022-07-11T09:59:32Z | 8,557 | 1,345 | 1,415 | 11,317 |
|
||||
| [v2.8.8](https://github.com/laurent22/joplin/releases/tag/v2.8.8) | 2022-05-17T14:48:06Z | 352,778 | 114,442 | 113,633 | 580,853 |
|
||||
| [v2.8.7](https://github.com/laurent22/joplin/releases/tag/v2.8.7) (p) | 2022-05-06T11:34:27Z | 5,070 | 368 | 432 | 5,870 |
|
||||
| [v2.8.6](https://github.com/laurent22/joplin/releases/tag/v2.8.6) (p) | 2022-05-03T10:08:25Z | 4,686 | 405 | 336 | 5,427 |
|
||||
| [v2.8.5](https://github.com/laurent22/joplin/releases/tag/v2.8.5) (p) | 2022-04-27T13:51:50Z | 4,794 | 373 | 360 | 5,527 |
|
||||
| [v2.8.4](https://github.com/laurent22/joplin/releases/tag/v2.8.4) (p) | 2022-04-19T18:00:09Z | 5,263 | 592 | 336 | 6,191 |
|
||||
| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 4,688 | 282 | 284 | 5,254 |
|
||||
| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 157,038 | 56,788 | 51,302 | 265,128 |
|
||||
| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 35,278 | 16,787 | 4,817 | 56,882 |
|
||||
| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 55,718 | 25,731 | 11,732 | 93,181 |
|
||||
| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 5,452 | 467 | 507 | 6,426 |
|
||||
| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 4,606 | 198 | 177 | 4,981 |
|
||||
| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 4,108 | 129 | 98 | 4,335 |
|
||||
| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 6,348 | 773 | 832 | 7,953 |
|
||||
| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 4,439 | 159 | 146 | 4,744 |
|
||||
| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 4,366 | 186 | 123 | 4,675 |
|
||||
| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 137,262 | 51,219 | 49,338 | 237,819 |
|
||||
| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 20,109 | 9,505 | 3,200 | 32,814 |
|
||||
| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 4,579 | 182 | 115 | 4,876 |
|
||||
| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 4,584 | 259 | 177 | 5,020 |
|
||||
| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 3,897 | 54 | 39 | 3,990 |
|
||||
| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 4,658 | 293 | 209 | 5,160 |
|
||||
| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 6,428 | 795 | 704 | 7,927 |
|
||||
| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 83,917 | 32,512 | 25,245 | 141,674 |
|
||||
| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 47,957 | 19,054 | 10,103 | 77,114 |
|
||||
| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 16,658 | 6,584 | 2,337 | 25,579 |
|
||||
| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 4,160 | 206 | 170 | 4,536 |
|
||||
| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 4,217 | 180 | 110 | 4,507 |
|
||||
| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 5,710 | 570 | 591 | 6,871 |
|
||||
| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 48,525 | 19,992 | 9,793 | 78,310 |
|
||||
| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 6,804 | 909 | 949 | 8,662 |
|
||||
| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 60,201 | 23,269 | 15,944 | 99,414 |
|
||||
| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 10,571 | 1,776 | 537 | 12,884 |
|
||||
| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 4,725 | 261 | 213 | 5,199 |
|
||||
| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 5,481 | 463 | 522 | 6,466 |
|
||||
| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 4,720 | 279 | 227 | 5,226 |
|
||||
| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 4,941 | 382 | 377 | 5,700 |
|
||||
| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 4,426 | 209 | 184 | 4,819 |
|
||||
| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 4,208 | 153 | 94 | 4,455 |
|
||||
| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 5,014 | 374 | 339 | 5,727 |
|
||||
| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 86,356 | 31,472 | 33,172 | 151,000 |
|
||||
| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 19,419 | 6,889 | 4,065 | 30,373 |
|
||||
| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 19,302 | 7,527 | 2,610 | 29,439 |
|
||||
| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 11,445 | 4,621 | 960 | 17,026 |
|
||||
| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 4,759 | 280 | 210 | 5,249 |
|
||||
| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 4,419 | 210 | 135 | 4,764 |
|
||||
| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 6,366 | 739 | 650 | 7,755 |
|
||||
| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 50,975 | 18,974 | 16,829 | 86,778 |
|
||||
| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 5,977 | 419 | 397 | 6,793 |
|
||||
| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 34,252 | 12,211 | 12,742 | 59,205 |
|
||||
| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 17,534 | 6,414 | 3,644 | 27,592 |
|
||||
| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 4,853 | 256 | 204 | 5,313 |
|
||||
| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 4,933 | 314 | 219 | 5,466 |
|
||||
| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 27,362 | 9,285 | 9,917 | 46,564 |
|
||||
| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 6,482 | 950 | 402 | 7,834 |
|
||||
| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 4,956 | 312 | 904 | 6,172 |
|
||||
| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 4,360 | 250 | 604 | 5,214 |
|
||||
| [v2.9.2](https://github.com/laurent22/joplin/releases/tag/v2.9.2) (p) | 2022-08-12T18:12:12Z | 1,540 | 450 | 0 | 1,990 |
|
||||
| [v2.9.1](https://github.com/laurent22/joplin/releases/tag/v2.9.1) (p) | 2022-07-11T09:59:32Z | 8,593 | 1,345 | 1,415 | 11,353 |
|
||||
| [v2.8.8](https://github.com/laurent22/joplin/releases/tag/v2.8.8) | 2022-05-17T14:48:06Z | 352,877 | 114,454 | 113,638 | 580,969 |
|
||||
| [v2.8.7](https://github.com/laurent22/joplin/releases/tag/v2.8.7) (p) | 2022-05-06T11:34:27Z | 5,100 | 368 | 432 | 5,900 |
|
||||
| [v2.8.6](https://github.com/laurent22/joplin/releases/tag/v2.8.6) (p) | 2022-05-03T10:08:25Z | 4,718 | 405 | 336 | 5,459 |
|
||||
| [v2.8.5](https://github.com/laurent22/joplin/releases/tag/v2.8.5) (p) | 2022-04-27T13:51:50Z | 4,828 | 374 | 360 | 5,562 |
|
||||
| [v2.8.4](https://github.com/laurent22/joplin/releases/tag/v2.8.4) (p) | 2022-04-19T18:00:09Z | 5,288 | 592 | 336 | 6,216 |
|
||||
| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 4,722 | 283 | 284 | 5,289 |
|
||||
| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 157,076 | 56,788 | 51,302 | 265,166 |
|
||||
| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 35,311 | 16,787 | 4,818 | 56,916 |
|
||||
| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 55,755 | 25,731 | 11,732 | 93,218 |
|
||||
| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 5,479 | 467 | 508 | 6,454 |
|
||||
| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 4,634 | 198 | 177 | 5,009 |
|
||||
| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 4,144 | 131 | 98 | 4,373 |
|
||||
| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 6,377 | 773 | 832 | 7,982 |
|
||||
| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 4,471 | 159 | 146 | 4,776 |
|
||||
| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 4,402 | 186 | 123 | 4,711 |
|
||||
| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 137,296 | 51,219 | 49,338 | 237,853 |
|
||||
| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 20,139 | 9,505 | 3,200 | 32,844 |
|
||||
| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 4,612 | 182 | 115 | 4,909 |
|
||||
| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 4,617 | 259 | 177 | 5,053 |
|
||||
| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 3,926 | 54 | 39 | 4,019 |
|
||||
| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 4,688 | 293 | 209 | 5,190 |
|
||||
| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 6,459 | 795 | 704 | 7,958 |
|
||||
| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 83,952 | 32,512 | 25,246 | 141,710 |
|
||||
| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 47,998 | 19,055 | 10,103 | 77,156 |
|
||||
| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 16,691 | 6,585 | 2,337 | 25,613 |
|
||||
| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 4,185 | 206 | 170 | 4,561 |
|
||||
| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 4,250 | 180 | 110 | 4,540 |
|
||||
| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 5,746 | 570 | 592 | 6,908 |
|
||||
| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 48,572 | 19,992 | 9,793 | 78,357 |
|
||||
| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 6,843 | 909 | 949 | 8,701 |
|
||||
| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 60,241 | 23,270 | 15,949 | 99,460 |
|
||||
| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 10,605 | 1,776 | 537 | 12,918 |
|
||||
| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 4,764 | 261 | 213 | 5,238 |
|
||||
| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 5,518 | 463 | 522 | 6,503 |
|
||||
| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 4,761 | 279 | 227 | 5,267 |
|
||||
| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 4,980 | 382 | 378 | 5,740 |
|
||||
| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 4,467 | 209 | 184 | 4,860 |
|
||||
| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 4,245 | 153 | 94 | 4,492 |
|
||||
| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 5,048 | 374 | 339 | 5,761 |
|
||||
| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 86,404 | 31,480 | 33,177 | 151,061 |
|
||||
| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 19,462 | 6,889 | 4,065 | 30,416 |
|
||||
| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 19,336 | 7,527 | 2,610 | 29,473 |
|
||||
| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 11,489 | 4,622 | 960 | 17,071 |
|
||||
| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 4,786 | 281 | 210 | 5,277 |
|
||||
| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 4,449 | 211 | 136 | 4,796 |
|
||||
| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 6,404 | 739 | 650 | 7,793 |
|
||||
| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 51,032 | 18,974 | 16,829 | 86,835 |
|
||||
| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 6,020 | 419 | 397 | 6,836 |
|
||||
| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 34,282 | 12,211 | 12,743 | 59,236 |
|
||||
| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 17,572 | 6,414 | 3,645 | 27,631 |
|
||||
| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 4,889 | 256 | 204 | 5,349 |
|
||||
| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 4,967 | 314 | 219 | 5,500 |
|
||||
| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 27,405 | 9,285 | 9,918 | 46,608 |
|
||||
| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 6,519 | 950 | 402 | 7,871 |
|
||||
| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 4,996 | 313 | 904 | 6,213 |
|
||||
| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 4,390 | 250 | 604 | 5,244 |
|
||||
| [v2.0.4](https://github.com/laurent22/joplin/releases/tag/v2.0.4) (p) | 2021-06-02T12:54:17Z | 1,647 | 406 | 395 | 2,448 |
|
||||
| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 6,441 | 505 | 1,683 | 8,629 |
|
||||
| [v2.0.1](https://github.com/laurent22/joplin/releases/tag/v2.0.1) (p) | 2021-05-15T13:22:58Z | 959 | 290 | 1,042 | 2,291 |
|
||||
| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 42,589 | 16,321 | 19,451 | 78,361 |
|
||||
| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 4,306 | 154 | 475 | 4,935 |
|
||||
| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 5,315 | 322 | 953 | 6,590 |
|
||||
| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 5,594 | 453 | 1,304 | 7,351 |
|
||||
| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 6,603 | 842 | 2,468 | 9,913 |
|
||||
| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 121,812 | 43,035 | 64,480 | 229,327 |
|
||||
| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,646 | 4,889 | 4,537 | 24,072 |
|
||||
| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 6,468 | 505 | 1,683 | 8,656 |
|
||||
| [v2.0.1](https://github.com/laurent22/joplin/releases/tag/v2.0.1) (p) | 2021-05-15T13:22:58Z | 961 | 292 | 1,042 | 2,295 |
|
||||
| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 42,632 | 16,323 | 19,453 | 78,408 |
|
||||
| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 4,336 | 154 | 476 | 4,966 |
|
||||
| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 5,348 | 322 | 953 | 6,623 |
|
||||
| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 5,634 | 454 | 1,304 | 7,392 |
|
||||
| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 6,638 | 842 | 2,468 | 9,948 |
|
||||
| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 121,854 | 43,046 | 64,483 | 229,383 |
|
||||
| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,647 | 4,892 | 4,539 | 24,078 |
|
||||
| [v1.7.9](https://github.com/laurent22/joplin/releases/tag/v1.7.9) (p) | 2021-01-28T09:50:21Z | 536 | 150 | 516 | 1,202 |
|
||||
| [v1.7.6](https://github.com/laurent22/joplin/releases/tag/v1.7.6) (p) | 2021-01-27T10:36:05Z | 351 | 110 | 306 | 767 |
|
||||
| [v1.7.5](https://github.com/laurent22/joplin/releases/tag/v1.7.5) (p) | 2021-01-26T09:53:05Z | 444 | 221 | 470 | 1,135 |
|
||||
| [v1.7.4](https://github.com/laurent22/joplin/releases/tag/v1.7.4) (p) | 2021-01-22T17:58:38Z | 734 | 221 | 643 | 1,598 |
|
||||
| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 24,257 | 7,735 | 7,640 | 39,632 |
|
||||
| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 24,324 | 7,736 | 7,640 | 39,700 |
|
||||
| [v1.7.3](https://github.com/laurent22/joplin/releases/tag/v1.7.3) (p) | 2021-01-20T11:23:50Z | 388 | 97 | 461 | 946 |
|
||||
| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 15,628 | 4,672 | 4,576 | 24,876 |
|
||||
| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 15,672 | 4,672 | 4,576 | 24,920 |
|
||||
| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,872 | 3,445 | 4,825 | 21,142 |
|
||||
| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 4,548 | 93 | 326 | 4,967 |
|
||||
| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 4,579 | 93 | 326 | 4,998 |
|
||||
| [v1.6.4](https://github.com/laurent22/joplin/releases/tag/v1.6.4) (p) | 2021-01-07T19:11:32Z | 428 | 95 | 222 | 745 |
|
||||
| [v1.6.2](https://github.com/laurent22/joplin/releases/tag/v1.6.2) (p) | 2021-01-04T22:34:55Z | 710 | 244 | 608 | 1,562 |
|
||||
| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 16,115 | 5,236 | 5,554 | 26,905 |
|
||||
| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 16,157 | 5,237 | 5,554 | 26,948 |
|
||||
| [v1.6.1](https://github.com/laurent22/joplin/releases/tag/v1.6.1) (p) | 2020-12-29T19:37:45Z | 207 | 55 | 188 | 450 |
|
||||
| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 793 | 245 | 232 | 1,270 |
|
||||
| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 793 | 246 | 232 | 1,271 |
|
||||
| [v1.5.12](https://github.com/laurent22/joplin/releases/tag/v1.5.12) | 2020-12-28T15:14:08Z | 2,576 | 1,800 | 946 | 5,322 |
|
||||
| [v1.5.11](https://github.com/laurent22/joplin/releases/tag/v1.5.11) | 2020-12-27T19:54:07Z | 14,428 | 4,665 | 4,321 | 23,414 |
|
||||
| [v1.5.11](https://github.com/laurent22/joplin/releases/tag/v1.5.11) | 2020-12-27T19:54:07Z | 14,428 | 4,665 | 4,322 | 23,415 |
|
||||
| [v1.5.10](https://github.com/laurent22/joplin/releases/tag/v1.5.10) (p) | 2020-12-26T12:35:36Z | 329 | 126 | 288 | 743 |
|
||||
| [v1.5.9](https://github.com/laurent22/joplin/releases/tag/v1.5.9) (p) | 2020-12-23T18:01:08Z | 363 | 388 | 429 | 1,180 |
|
||||
| [v1.5.8](https://github.com/laurent22/joplin/releases/tag/v1.5.8) (p) | 2020-12-20T09:45:19Z | 599 | 181 | 662 | 1,442 |
|
||||
| [v1.5.7](https://github.com/laurent22/joplin/releases/tag/v1.5.7) (p) | 2020-12-10T12:58:33Z | 925 | 271 | 1,012 | 2,208 |
|
||||
| [v1.5.4](https://github.com/laurent22/joplin/releases/tag/v1.5.4) (p) | 2020-12-05T12:07:49Z | 737 | 184 | 654 | 1,575 |
|
||||
| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 30,477 | 13,641 | 11,719 | 55,837 |
|
||||
| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 30,512 | 13,643 | 11,720 | 55,875 |
|
||||
| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,766 | 3,913 | 3,166 | 18,845 |
|
||||
| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,655 | 864 | 624 | 3,143 |
|
||||
| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 1,045 | 516 | 299 | 1,860 |
|
||||
| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,226 | 1,381 | 1,331 | 5,938 |
|
||||
| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 5,352 | 195 | 613 | 6,160 |
|
||||
| [v1.4.10](https://github.com/laurent22/joplin/releases/tag/v1.4.10) (p) | 2020-11-14T09:53:15Z | 701 | 235 | 705 | 1,641 |
|
||||
| [v1.4.9](https://github.com/laurent22/joplin/releases/tag/v1.4.9) (p) | 2020-11-11T14:23:17Z | 878 | 180 | 422 | 1,480 |
|
||||
| [v1.4.7](https://github.com/laurent22/joplin/releases/tag/v1.4.7) (p) | 2020-11-07T18:23:29Z | 564 | 211 | 536 | 1,311 |
|
||||
| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 36,082 | 11,393 | 10,551 | 58,026 |
|
||||
| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 1,047 | 516 | 299 | 1,862 |
|
||||
| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,226 | 1,382 | 1,332 | 5,940 |
|
||||
| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 5,384 | 195 | 613 | 6,192 |
|
||||
| [v1.4.10](https://github.com/laurent22/joplin/releases/tag/v1.4.10) (p) | 2020-11-14T09:53:15Z | 702 | 235 | 705 | 1,642 |
|
||||
| [v1.4.9](https://github.com/laurent22/joplin/releases/tag/v1.4.9) (p) | 2020-11-11T14:23:17Z | 878 | 181 | 423 | 1,482 |
|
||||
| [v1.4.7](https://github.com/laurent22/joplin/releases/tag/v1.4.7) (p) | 2020-11-07T18:23:29Z | 564 | 212 | 536 | 1,312 |
|
||||
| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 36,124 | 11,394 | 10,555 | 58,073 |
|
||||
| [v1.3.17](https://github.com/laurent22/joplin/releases/tag/v1.3.17) (p) | 2020-11-06T11:35:15Z | 91 | 67 | 45 | 203 |
|
||||
| [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 783 | 131 | 72 | 986 |
|
||||
| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,839 | 1,349 | 874 | 5,062 |
|
||||
| [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 787 | 131 | 72 | 990 |
|
||||
| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,845 | 1,349 | 874 | 5,068 |
|
||||
| [v1.3.11](https://github.com/laurent22/joplin/releases/tag/v1.3.11) (p) | 2020-10-31T13:22:20Z | 745 | 223 | 501 | 1,469 |
|
||||
| [v1.3.10](https://github.com/laurent22/joplin/releases/tag/v1.3.10) (p) | 2020-10-29T13:27:14Z | 418 | 155 | 336 | 909 |
|
||||
| [v1.3.9](https://github.com/laurent22/joplin/releases/tag/v1.3.9) (p) | 2020-10-23T16:04:26Z | 934 | 281 | 654 | 1,869 |
|
||||
| [v1.3.9](https://github.com/laurent22/joplin/releases/tag/v1.3.9) (p) | 2020-10-23T16:04:26Z | 938 | 281 | 654 | 1,873 |
|
||||
| [v1.3.8](https://github.com/laurent22/joplin/releases/tag/v1.3.8) (p) | 2020-10-21T18:46:29Z | 564 | 156 | 352 | 1,072 |
|
||||
| [v1.3.7](https://github.com/laurent22/joplin/releases/tag/v1.3.7) (p) | 2020-10-20T11:35:55Z | 338 | 124 | 364 | 826 |
|
||||
| [v1.3.5](https://github.com/laurent22/joplin/releases/tag/v1.3.5) (p) | 2020-10-17T14:26:35Z | 516 | 175 | 429 | 1,120 |
|
||||
| [v1.3.3](https://github.com/laurent22/joplin/releases/tag/v1.3.3) (p) | 2020-10-17T10:56:57Z | 161 | 84 | 54 | 299 |
|
||||
| [v1.3.2](https://github.com/laurent22/joplin/releases/tag/v1.3.2) (p) | 2020-10-11T20:39:49Z | 716 | 220 | 589 | 1,525 |
|
||||
| [v1.3.1](https://github.com/laurent22/joplin/releases/tag/v1.3.1) (p) | 2020-10-11T15:10:18Z | 126 | 90 | 65 | 281 |
|
||||
| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 50,092 | 17,797 | 14,097 | 81,986 |
|
||||
| [v1.2.4](https://github.com/laurent22/joplin/releases/tag/v1.2.4) (p) | 2020-09-30T07:34:29Z | 866 | 292 | 823 | 1,981 |
|
||||
| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 50,147 | 17,797 | 14,097 | 82,041 |
|
||||
| [v1.2.4](https://github.com/laurent22/joplin/releases/tag/v1.2.4) (p) | 2020-09-30T07:34:29Z | 866 | 292 | 824 | 1,982 |
|
||||
| [v1.2.3](https://github.com/laurent22/joplin/releases/tag/v1.2.3) (p) | 2020-09-29T15:13:02Z | 263 | 103 | 105 | 471 |
|
||||
| [v1.2.2](https://github.com/laurent22/joplin/releases/tag/v1.2.2) (p) | 2020-09-22T20:31:55Z | 1,161 | 246 | 660 | 2,067 |
|
||||
| [v1.2.2](https://github.com/laurent22/joplin/releases/tag/v1.2.2) (p) | 2020-09-22T20:31:55Z | 1,161 | 247 | 661 | 2,069 |
|
||||
| [v1.1.4](https://github.com/laurent22/joplin/releases/tag/v1.1.4) | 2020-09-21T11:20:09Z | 28,241 | 13,561 | 7,791 | 49,593 |
|
||||
| [v1.1.3](https://github.com/laurent22/joplin/releases/tag/v1.1.3) (p) | 2020-09-17T10:30:37Z | 631 | 192 | 486 | 1,309 |
|
||||
| [v1.1.3](https://github.com/laurent22/joplin/releases/tag/v1.1.3) (p) | 2020-09-17T10:30:37Z | 631 | 193 | 487 | 1,311 |
|
||||
| [v1.1.2](https://github.com/laurent22/joplin/releases/tag/v1.1.2) (p) | 2020-09-15T12:58:38Z | 425 | 155 | 273 | 853 |
|
||||
| [v1.1.1](https://github.com/laurent22/joplin/releases/tag/v1.1.1) (p) | 2020-09-11T23:32:47Z | 602 | 235 | 373 | 1,210 |
|
||||
| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 23,079 | 10,070 | 5,678 | 38,827 |
|
||||
| [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,912 | 6,467 | 3,049 | 22,428 |
|
||||
| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 26,696 | 5,994 | 5,157 | 37,847 |
|
||||
| [v1.0.239](https://github.com/laurent22/joplin/releases/tag/v1.0.239) (p) | 2020-09-01T21:56:36Z | 1,016 | 270 | 426 | 1,712 |
|
||||
| [v1.0.237](https://github.com/laurent22/joplin/releases/tag/v1.0.237) (p) | 2020-08-29T15:38:04Z | 639 | 965 | 361 | 1,965 |
|
||||
| [v1.0.236](https://github.com/laurent22/joplin/releases/tag/v1.0.236) (p) | 2020-08-28T09:16:54Z | 364 | 153 | 127 | 644 |
|
||||
| [v1.0.235](https://github.com/laurent22/joplin/releases/tag/v1.0.235) (p) | 2020-08-18T22:08:01Z | 2,089 | 530 | 945 | 3,564 |
|
||||
| [v1.0.234](https://github.com/laurent22/joplin/releases/tag/v1.0.234) (p) | 2020-08-17T23:13:02Z | 722 | 166 | 124 | 1,012 |
|
||||
| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 48,711 | 18,253 | 12,392 | 79,356 |
|
||||
| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 23,079 | 10,071 | 5,679 | 38,829 |
|
||||
| [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,912 | 6,468 | 3,050 | 22,430 |
|
||||
| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 26,699 | 5,995 | 5,161 | 37,855 |
|
||||
| [v1.0.239](https://github.com/laurent22/joplin/releases/tag/v1.0.239) (p) | 2020-09-01T21:56:36Z | 1,020 | 271 | 427 | 1,718 |
|
||||
| [v1.0.237](https://github.com/laurent22/joplin/releases/tag/v1.0.237) (p) | 2020-08-29T15:38:04Z | 639 | 966 | 362 | 1,967 |
|
||||
| [v1.0.236](https://github.com/laurent22/joplin/releases/tag/v1.0.236) (p) | 2020-08-28T09:16:54Z | 364 | 154 | 127 | 645 |
|
||||
| [v1.0.235](https://github.com/laurent22/joplin/releases/tag/v1.0.235) (p) | 2020-08-18T22:08:01Z | 2,093 | 531 | 945 | 3,569 |
|
||||
| [v1.0.234](https://github.com/laurent22/joplin/releases/tag/v1.0.234) (p) | 2020-08-17T23:13:02Z | 726 | 167 | 125 | 1,018 |
|
||||
| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 48,765 | 18,253 | 12,394 | 79,412 |
|
||||
| [v1.0.232](https://github.com/laurent22/joplin/releases/tag/v1.0.232) (p) | 2020-07-28T22:34:40Z | 705 | 265 | 202 | 1,172 |
|
||||
| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 42,024 | 15,328 | 9,680 | 67,032 |
|
||||
| [v1.0.226](https://github.com/laurent22/joplin/releases/tag/v1.0.226) (p) | 2020-07-04T10:21:26Z | 4,980 | 2,295 | 711 | 7,986 |
|
||||
| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 25,301 | 11,053 | 6,035 | 42,389 |
|
||||
| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 42,030 | 15,329 | 9,681 | 67,040 |
|
||||
| [v1.0.226](https://github.com/laurent22/joplin/releases/tag/v1.0.226) (p) | 2020-07-04T10:21:26Z | 4,981 | 2,296 | 711 | 7,988 |
|
||||
| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 25,301 | 11,054 | 6,036 | 42,391 |
|
||||
| [v1.0.223](https://github.com/laurent22/joplin/releases/tag/v1.0.223) (p) | 2020-06-20T11:51:27Z | 233 | 154 | 102 | 489 |
|
||||
| [v1.0.221](https://github.com/laurent22/joplin/releases/tag/v1.0.221) (p) | 2020-06-20T01:44:20Z | 903 | 249 | 236 | 1,388 |
|
||||
| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,840 | 9,975 | 6,452 | 49,267 |
|
||||
| [v1.0.218](https://github.com/laurent22/joplin/releases/tag/v1.0.218) | 2020-06-07T10:43:34Z | 14,646 | 7,022 | 3,156 | 24,824 |
|
||||
| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,841 | 9,975 | 6,452 | 49,268 |
|
||||
| [v1.0.218](https://github.com/laurent22/joplin/releases/tag/v1.0.218) | 2020-06-07T10:43:34Z | 14,646 | 7,023 | 3,156 | 24,825 |
|
||||
| [v1.0.217](https://github.com/laurent22/joplin/releases/tag/v1.0.217) (p) | 2020-06-06T15:17:27Z | 283 | 141 | 87 | 511 |
|
||||
| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 42,470 | 14,365 | 10,230 | 67,065 |
|
||||
| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 42,516 | 14,365 | 10,231 | 67,112 |
|
||||
| [v1.0.214](https://github.com/laurent22/joplin/releases/tag/v1.0.214) (p) | 2020-05-21T17:15:15Z | 7,109 | 3,516 | 791 | 11,416 |
|
||||
| [v1.0.212](https://github.com/laurent22/joplin/releases/tag/v1.0.212) (p) | 2020-05-21T07:48:39Z | 257 | 114 | 73 | 444 |
|
||||
| [v1.0.211](https://github.com/laurent22/joplin/releases/tag/v1.0.211) (p) | 2020-05-20T08:59:16Z | 356 | 178 | 115 | 649 |
|
||||
@@ -296,116 +297,116 @@ updated: 2026-02-01T02:35:07Z
|
||||
| [v1.0.207](https://github.com/laurent22/joplin/releases/tag/v1.0.207) (p) | 2020-05-10T16:37:35Z | 1,254 | 308 | 1,047 | 2,609 |
|
||||
| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,431 | 20,112 | 18,229 | 92,772 |
|
||||
| [v1.0.200](https://github.com/laurent22/joplin/releases/tag/v1.0.200) | 2020-04-12T12:17:46Z | 9,641 | 4,943 | 1,935 | 16,519 |
|
||||
| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,973 | 5,938 | 3,847 | 29,758 |
|
||||
| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 23,529 | 9,877 | 6,725 | 40,131 |
|
||||
| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,974 | 5,938 | 3,847 | 29,759 |
|
||||
| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 23,530 | 9,877 | 6,734 | 40,141 |
|
||||
| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,185 | 8,010 | 4,541 | 31,736 |
|
||||
| [v1.0.194](https://github.com/laurent22/joplin/releases/tag/v1.0.194) (p) | 2020-03-14T00:00:32Z | 1,344 | 1,435 | 545 | 3,324 |
|
||||
| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,852 | 10,986 | 7,466 | 47,304 |
|
||||
| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 596 | 168 | 117 | 881 |
|
||||
| [v1.0.190](https://github.com/laurent22/joplin/releases/tag/v1.0.190) (p) | 2020-03-06T01:22:22Z | 471 | 136 | 111 | 718 |
|
||||
| [v1.0.189](https://github.com/laurent22/joplin/releases/tag/v1.0.189) (p) | 2020-03-04T17:27:15Z | 464 | 140 | 125 | 729 |
|
||||
| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,854 | 10,986 | 7,466 | 47,306 |
|
||||
| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 600 | 168 | 117 | 885 |
|
||||
| [v1.0.190](https://github.com/laurent22/joplin/releases/tag/v1.0.190) (p) | 2020-03-06T01:22:22Z | 476 | 136 | 111 | 723 |
|
||||
| [v1.0.189](https://github.com/laurent22/joplin/releases/tag/v1.0.189) (p) | 2020-03-04T17:27:15Z | 468 | 140 | 125 | 733 |
|
||||
| [v1.0.187](https://github.com/laurent22/joplin/releases/tag/v1.0.187) (p) | 2020-03-01T12:31:06Z | 985 | 282 | 300 | 1,567 |
|
||||
| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,852 | 29,156 | 22,619 | 123,627 |
|
||||
| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,858 | 29,165 | 22,620 | 123,643 |
|
||||
| [v1.0.178](https://github.com/laurent22/joplin/releases/tag/v1.0.178) | 2020-01-20T19:06:45Z | 17,682 | 6,015 | 2,625 | 26,322 |
|
||||
| [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 2,015 | 482 | 761 | 3,258 |
|
||||
| [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 2,015 | 482 | 763 | 3,260 |
|
||||
| [v1.0.176](https://github.com/laurent22/joplin/releases/tag/v1.0.176) (p) | 2019-12-14T10:36:44Z | 3,179 | 2,582 | 498 | 6,259 |
|
||||
| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,815 | 17,030 | 16,635 | 107,480 |
|
||||
| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,786 | 11,813 | 8,259 | 50,858 |
|
||||
| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,786 | 11,815 | 8,261 | 50,862 |
|
||||
| [v1.0.173](https://github.com/laurent22/joplin/releases/tag/v1.0.173) | 2019-11-11T08:33:35Z | 5,160 | 2,128 | 776 | 8,064 |
|
||||
| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,924 | 8,839 | 7,722 | 44,485 |
|
||||
| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,300 | 5,979 | 3,789 | 27,068 |
|
||||
| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,924 | 8,839 | 7,723 | 44,486 |
|
||||
| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,302 | 5,979 | 3,789 | 27,070 |
|
||||
| [v1.0.168](https://github.com/laurent22/joplin/releases/tag/v1.0.168) | 2019-09-25T21:21:38Z | 5,400 | 2,321 | 750 | 8,471 |
|
||||
| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 17,030 | 5,754 | 3,747 | 26,531 |
|
||||
| [v1.0.166](https://github.com/laurent22/joplin/releases/tag/v1.0.166) | 2019-09-09T17:35:54Z | 2,010 | 607 | 263 | 2,880 |
|
||||
| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 17,032 | 5,754 | 3,747 | 26,533 |
|
||||
| [v1.0.166](https://github.com/laurent22/joplin/releases/tag/v1.0.166) | 2019-09-09T17:35:54Z | 2,010 | 608 | 264 | 2,882 |
|
||||
| [v1.0.165](https://github.com/laurent22/joplin/releases/tag/v1.0.165) | 2019-08-14T21:46:29Z | 19,129 | 7,028 | 5,495 | 31,652 |
|
||||
| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,463 | 6,396 | 4,164 | 30,023 |
|
||||
| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,895 | 7,802 | 8,140 | 46,837 |
|
||||
| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,299 | 2,225 | 1,324 | 8,848 |
|
||||
| [v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,895 | 3,596 | 1,965 | 15,456 |
|
||||
| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,465 | 6,396 | 4,164 | 30,025 |
|
||||
| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,898 | 7,802 | 8,140 | 46,840 |
|
||||
| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,305 | 2,225 | 1,324 | 8,854 |
|
||||
| [v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,896 | 3,596 | 1,965 | 15,457 |
|
||||
| [v1.0.157](https://github.com/laurent22/joplin/releases/tag/v1.0.157) | 2019-05-26T17:55:53Z | 2,254 | 886 | 317 | 3,457 |
|
||||
| [v1.0.153](https://github.com/laurent22/joplin/releases/tag/v1.0.153) (p) | 2019-05-15T06:27:29Z | 918 | 146 | 134 | 1,198 |
|
||||
| [v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,954 | 4,482 | 4,096 | 22,532 |
|
||||
| [v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,954 | 4,483 | 4,097 | 22,534 |
|
||||
| [v1.0.151](https://github.com/laurent22/joplin/releases/tag/v1.0.151) | 2019-05-12T15:14:32Z | 2,007 | 579 | 987 | 3,573 |
|
||||
| [v1.0.150](https://github.com/laurent22/joplin/releases/tag/v1.0.150) | 2019-05-12T11:27:48Z | 500 | 180 | 99 | 779 |
|
||||
| [v1.0.148](https://github.com/laurent22/joplin/releases/tag/v1.0.148) (p) | 2019-05-08T19:12:24Z | 191 | 98 | 123 | 412 |
|
||||
| [v1.0.145](https://github.com/laurent22/joplin/releases/tag/v1.0.145) | 2019-05-03T09:16:53Z | 7,087 | 2,906 | 1,469 | 11,462 |
|
||||
| [v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,998 | 3,598 | 2,814 | 18,410 |
|
||||
| [v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,998 | 3,599 | 2,814 | 18,411 |
|
||||
| [v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,873 | 4,613 | 4,764 | 24,250 |
|
||||
| [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,757 | 4,225 | 3,411 | 21,393 |
|
||||
| [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,761 | 4,225 | 3,411 | 21,397 |
|
||||
| [v1.0.139](https://github.com/laurent22/joplin/releases/tag/v1.0.139) (p) | 2019-03-09T10:06:48Z | 190 | 107 | 71 | 368 |
|
||||
| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 262 | 132 | 110 | 504 |
|
||||
| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 266 | 132 | 110 | 508 |
|
||||
| [v1.0.137](https://github.com/laurent22/joplin/releases/tag/v1.0.137) (p) | 2019-03-03T01:12:51Z | 652 | 99 | 110 | 861 |
|
||||
| [v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,709 | 4,005 | 4,113 | 20,827 |
|
||||
| [v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,711 | 4,006 | 4,114 | 20,831 |
|
||||
| [v1.0.134](https://github.com/laurent22/joplin/releases/tag/v1.0.134) | 2019-02-27T10:21:44Z | 1,516 | 615 | 247 | 2,378 |
|
||||
| [v1.0.132](https://github.com/laurent22/joplin/releases/tag/v1.0.132) | 2019-02-26T23:02:05Z | 1,154 | 497 | 122 | 1,773 |
|
||||
| [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 10,044 | 3,220 | 2,965 | 16,229 |
|
||||
| [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 10,047 | 3,220 | 2,965 | 16,232 |
|
||||
| [v1.0.126](https://github.com/laurent22/joplin/releases/tag/v1.0.126) (p) | 2019-02-09T19:46:16Z | 1,003 | 119 | 140 | 1,262 |
|
||||
| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,452 | 3,605 | 1,729 | 15,786 |
|
||||
| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,454 | 3,605 | 1,729 | 15,788 |
|
||||
| [v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,710 | 5,260 | 6,553 | 27,523 |
|
||||
| [v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 9,044 | 3,307 | 2,046 | 14,397 |
|
||||
| [v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 9,049 | 3,307 | 2,046 | 14,402 |
|
||||
| [v1.0.118](https://github.com/laurent22/joplin/releases/tag/v1.0.118) | 2019-01-11T08:34:13Z | 769 | 292 | 118 | 1,179 |
|
||||
| [v1.0.117](https://github.com/laurent22/joplin/releases/tag/v1.0.117) | 2018-11-24T12:05:24Z | 16,352 | 4,946 | 6,415 | 27,713 |
|
||||
| [v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 4,073 | 1,174 | 746 | 5,993 |
|
||||
| [v1.0.115](https://github.com/laurent22/joplin/releases/tag/v1.0.115) | 2018-11-16T16:52:02Z | 3,727 | 1,346 | 830 | 5,903 |
|
||||
| [v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | 11,475 | 3,547 | 3,860 | 18,882 |
|
||||
| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,587 | 3,576 | 3,711 | 19,874 |
|
||||
| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,587 | 3,576 | 3,712 | 19,875 |
|
||||
| [v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 1,018 | 453 | 145 | 1,616 |
|
||||
| [v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 2,152 | 747 | 360 | 3,259 |
|
||||
| [v1.0.108](https://github.com/laurent22/joplin/releases/tag/v1.0.108) (p) | 2018-09-29T18:49:29Z | 68 | 63 | 39 | 170 |
|
||||
| [v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 7,213 | 2,180 | 1,740 | 11,133 |
|
||||
| [v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 7,213 | 2,181 | 1,741 | 11,135 |
|
||||
| [v1.0.106](https://github.com/laurent22/joplin/releases/tag/v1.0.106) | 2018-09-08T15:23:40Z | 4,605 | 1,499 | 343 | 6,447 |
|
||||
| [v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4,706 | 1,638 | 1,487 | 7,831 |
|
||||
| [v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 15,214 | 4,749 | 7,423 | 27,386 |
|
||||
| [v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2,134 | 930 | 707 | 3,771 |
|
||||
| [v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1,379 | 652 | 438 | 2,469 |
|
||||
| [v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 965 | 481 | 276 | 1,722 |
|
||||
| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,336 | 646 | 411 | 2,393 |
|
||||
| [v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 15,214 | 4,749 | 7,424 | 27,387 |
|
||||
| [v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2,134 | 931 | 708 | 3,773 |
|
||||
| [v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1,379 | 653 | 438 | 2,470 |
|
||||
| [v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 965 | 482 | 277 | 1,724 |
|
||||
| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,336 | 647 | 412 | 2,395 |
|
||||
| [v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 362 | 197 | 89 | 648 |
|
||||
| [v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,806 | 1,271 | 1,756 | 5,833 |
|
||||
| [v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,808 | 1,272 | 1,758 | 5,838 |
|
||||
| [v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 473 | 262 | 168 | 903 |
|
||||
| [v1.0.94](https://github.com/laurent22/joplin/releases/tag/v1.0.94) | 2018-05-21T20:52:59Z | 1,221 | 633 | 451 | 2,305 |
|
||||
| [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,886 | 1,391 | 808 | 4,085 |
|
||||
| [v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 875 | 598 | 368 | 1,841 |
|
||||
| [v1.0.94](https://github.com/laurent22/joplin/releases/tag/v1.0.94) | 2018-05-21T20:52:59Z | 1,221 | 635 | 452 | 2,308 |
|
||||
| [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,886 | 1,398 | 809 | 4,093 |
|
||||
| [v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 875 | 599 | 369 | 1,843 |
|
||||
| [v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) | 2018-05-09T13:05:05Z | 552 | 291 | 161 | 1,004 |
|
||||
| [v1.0.85](https://github.com/laurent22/joplin/releases/tag/v1.0.85) | 2018-05-01T21:08:24Z | 1,702 | 997 | 681 | 3,380 |
|
||||
| [v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 5,649 | 2,581 | 2,708 | 10,938 |
|
||||
| [v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 754 | 454 | 171 | 1,379 |
|
||||
| [v1.0.81](https://github.com/laurent22/joplin/releases/tag/v1.0.81) | 2018-03-28T08:13:58Z | 1,042 | 641 | 831 | 2,514 |
|
||||
| [v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 974 | 584 | 433 | 1,991 |
|
||||
| [v1.0.78](https://github.com/laurent22/joplin/releases/tag/v1.0.78) | 2018-03-17T15:27:18Z | 1,357 | 947 | 920 | 3,224 |
|
||||
| [v1.0.85](https://github.com/laurent22/joplin/releases/tag/v1.0.85) | 2018-05-01T21:08:24Z | 1,702 | 998 | 683 | 3,383 |
|
||||
| [v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 5,649 | 2,582 | 2,708 | 10,939 |
|
||||
| [v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 754 | 454 | 173 | 1,381 |
|
||||
| [v1.0.81](https://github.com/laurent22/joplin/releases/tag/v1.0.81) | 2018-03-28T08:13:58Z | 1,042 | 642 | 832 | 2,516 |
|
||||
| [v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 974 | 585 | 434 | 1,993 |
|
||||
| [v1.0.78](https://github.com/laurent22/joplin/releases/tag/v1.0.78) | 2018-03-17T15:27:18Z | 1,357 | 948 | 921 | 3,226 |
|
||||
| [v1.0.77](https://github.com/laurent22/joplin/releases/tag/v1.0.77) | 2018-03-16T15:12:35Z | 206 | 148 | 92 | 446 |
|
||||
| [v1.0.72](https://github.com/laurent22/joplin/releases/tag/v1.0.72) | 2018-03-14T09:44:35Z | 456 | 300 | 102 | 858 |
|
||||
| [v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 2,009 | 1,099 | 1,301 | 4,409 |
|
||||
| [v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,950 | 649 | 0 | 2,599 |
|
||||
| [v1.0.72](https://github.com/laurent22/joplin/releases/tag/v1.0.72) | 2018-03-14T09:44:35Z | 456 | 301 | 104 | 861 |
|
||||
| [v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 2,009 | 1,101 | 1,304 | 4,414 |
|
||||
| [v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,950 | 650 | 0 | 2,600 |
|
||||
| [v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) | 2018-02-18T23:09:09Z | 454 | 178 | 111 | 743 |
|
||||
| [v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 352 | 176 | 158 | 686 |
|
||||
| [v1.0.64](https://github.com/laurent22/joplin/releases/tag/v1.0.64) | 2018-02-16T00:58:20Z | 1,201 | 587 | 1,151 | 2,939 |
|
||||
| [v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 352 | 177 | 158 | 687 |
|
||||
| [v1.0.64](https://github.com/laurent22/joplin/releases/tag/v1.0.64) | 2018-02-16T00:58:20Z | 1,201 | 588 | 1,151 | 2,940 |
|
||||
| [v1.0.63](https://github.com/laurent22/joplin/releases/tag/v1.0.63) | 2018-02-14T19:40:36Z | 416 | 204 | 119 | 739 |
|
||||
| [v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 717 | 351 | 403 | 1,471 |
|
||||
| [v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 1,130 | 684 | 990 | 2,804 |
|
||||
| [v0.10.60](https://github.com/laurent22/joplin/releases/tag/v0.10.60) | 2018-02-06T13:09:56Z | 775 | 569 | 579 | 1,923 |
|
||||
| [v0.10.54](https://github.com/laurent22/joplin/releases/tag/v0.10.54) | 2018-01-31T20:21:30Z | 1,966 | 1,508 | 350 | 3,824 |
|
||||
| [v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 717 | 351 | 404 | 1,472 |
|
||||
| [v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 1,130 | 685 | 990 | 2,805 |
|
||||
| [v0.10.60](https://github.com/laurent22/joplin/releases/tag/v0.10.60) | 2018-02-06T13:09:56Z | 775 | 569 | 580 | 1,924 |
|
||||
| [v0.10.54](https://github.com/laurent22/joplin/releases/tag/v0.10.54) | 2018-01-31T20:21:30Z | 1,966 | 1,509 | 350 | 3,825 |
|
||||
| [v0.10.52](https://github.com/laurent22/joplin/releases/tag/v0.10.52) | 2018-01-31T19:25:18Z | 167 | 682 | 45 | 894 |
|
||||
| [v0.10.51](https://github.com/laurent22/joplin/releases/tag/v0.10.51) | 2018-01-28T18:47:02Z | 1,436 | 1,648 | 355 | 3,439 |
|
||||
| [v0.10.48](https://github.com/laurent22/joplin/releases/tag/v0.10.48) | 2018-01-23T11:19:51Z | 2,115 | 1,800 | 59 | 3,974 |
|
||||
| [v0.10.48](https://github.com/laurent22/joplin/releases/tag/v0.10.48) | 2018-01-23T11:19:51Z | 2,115 | 1,800 | 60 | 3,975 |
|
||||
| [v0.10.47](https://github.com/laurent22/joplin/releases/tag/v0.10.47) | 2018-01-16T17:27:17Z | 1,338 | 1,321 | 94 | 2,753 |
|
||||
| [v0.10.43](https://github.com/laurent22/joplin/releases/tag/v0.10.43) | 2018-01-08T10:12:10Z | 3,496 | 2,411 | 1,248 | 7,155 |
|
||||
| [v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,249 | 1,605 | 271 | 3,125 |
|
||||
| [v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,643 | 1,836 | 366 | 3,845 |
|
||||
| [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 6,004 | 4,451 | 3,337 | 13,792 |
|
||||
| [v0.10.38](https://github.com/laurent22/joplin/releases/tag/v0.10.38) | 2017-12-08T10:12:06Z | 1,094 | 1,279 | 332 | 2,705 |
|
||||
| [v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,249 | 1,606 | 272 | 3,127 |
|
||||
| [v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,643 | 1,836 | 367 | 3,846 |
|
||||
| [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 6,004 | 4,452 | 3,337 | 13,793 |
|
||||
| [v0.10.38](https://github.com/laurent22/joplin/releases/tag/v0.10.38) | 2017-12-08T10:12:06Z | 1,095 | 1,279 | 332 | 2,706 |
|
||||
| [v0.10.37](https://github.com/laurent22/joplin/releases/tag/v0.10.37) | 2017-12-07T19:38:05Z | 294 | 897 | 113 | 1,304 |
|
||||
| [v0.10.36](https://github.com/laurent22/joplin/releases/tag/v0.10.36) | 2017-12-05T09:34:40Z | 1,057 | 1,409 | 468 | 2,934 |
|
||||
| [v0.10.35](https://github.com/laurent22/joplin/releases/tag/v0.10.35) | 2017-12-02T15:56:08Z | 1,615 | 1,599 | 772 | 3,986 |
|
||||
| [v0.10.34](https://github.com/laurent22/joplin/releases/tag/v0.10.34) | 2017-12-02T14:50:28Z | 120 | 723 | 87 | 930 |
|
||||
| [v0.10.33](https://github.com/laurent22/joplin/releases/tag/v0.10.33) | 2017-12-02T13:20:39Z | 100 | 718 | 54 | 872 |
|
||||
| [v0.10.31](https://github.com/laurent22/joplin/releases/tag/v0.10.31) | 2017-12-01T09:56:44Z | 922 | 1,505 | 442 | 2,869 |
|
||||
| [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 849 | 1,434 | 454 | 2,737 |
|
||||
| [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 850 | 1,435 | 455 | 2,740 |
|
||||
| [v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,500 | 1,768 | 910 | 4,178 |
|
||||
| [v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 311 | 763 | 294 | 1,368 |
|
||||
| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 265 | 758 | 6,820 | 7,843 |
|
||||
| [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 254 | 720 | 70 | 1,044 |
|
||||
| [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 254 | 721 | 71 | 1,046 |
|
||||
| [v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 198 | 707 | 52 | 957 |
|
||||
| [v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 174 | 699 | 47 | 920 |
|
||||
| [v0.10.20](https://github.com/laurent22/joplin/releases/tag/v0.10.20) | 2017-11-17T17:18:25Z | 167 | 712 | 60 | 939 |
|
||||
| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 194 | 716 | 59 | 969 |
|
||||
| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 195 | 716 | 59 | 970 |
|
||||
70
yarn.lock
70
yarn.lock
@@ -10671,7 +10671,7 @@ __metadata:
|
||||
react-native-file-viewer: "npm:2.1.5"
|
||||
react-native-get-random-values: "npm:1.11.0"
|
||||
react-native-image-picker: "npm:8.2.1"
|
||||
react-native-localize: "npm:3.5.4"
|
||||
react-native-localize: "npm:3.6.0"
|
||||
react-native-modal-datetime-picker: "npm:18.0.0"
|
||||
react-native-nitro-modules: "npm:0.33.2"
|
||||
react-native-paper: "npm:5.14.5"
|
||||
@@ -11148,7 +11148,7 @@ __metadata:
|
||||
query-string: "npm:7.1.3"
|
||||
rate-limiter-flexible: "npm:7.4.0"
|
||||
raw-body: "npm:3.0.2"
|
||||
samlify: "npm:2.10.1"
|
||||
samlify: "npm:2.10.2"
|
||||
short-uuid: "npm:5.2.0"
|
||||
source-map-support: "npm:0.5.21"
|
||||
sqlite3: "npm:5.1.6"
|
||||
@@ -11182,7 +11182,7 @@ __metadata:
|
||||
dayjs: "npm:1.11.19"
|
||||
execa: "npm:4.1.0"
|
||||
fs-extra: "npm:11.3.2"
|
||||
gettext-extractor: "npm:4.0.1"
|
||||
gettext-extractor: "npm:4.0.3"
|
||||
gettext-parser: "npm:7.0.1"
|
||||
glob: "npm:11.0.3"
|
||||
gulp: "npm:4.0.2"
|
||||
@@ -30552,17 +30552,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"gettext-extractor@npm:4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "gettext-extractor@npm:4.0.1"
|
||||
"gettext-extractor@npm:4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "gettext-extractor@npm:4.0.3"
|
||||
dependencies:
|
||||
"@types/parse5": "npm:^5"
|
||||
css-selector-parser: "npm:^1.3"
|
||||
glob: "npm:11.0.1"
|
||||
glob: "npm:11.1.0"
|
||||
parse5: "npm:5 - 6"
|
||||
pofile: "npm:1.0.x"
|
||||
typescript: "npm:^5.4.0"
|
||||
checksum: 10/768a63bb07336d4364381feba14d4463dc5fc9c81e8c74746f0d6e0745663f6549b343a02f54139f9e8f91a953f5b477823c6e6ae3005c369f72306c62e9c13c
|
||||
checksum: 10/ae8848b7b31e921510b750906df0afe819abfc1da955a19bae68f27ca2fc951e43b028b9f8ccdf4910ee822dedc6c3b03b5b8faf731ad7eceab0ef511732d30f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -30770,22 +30770,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:11.0.1":
|
||||
version: 11.0.1
|
||||
resolution: "glob@npm:11.0.1"
|
||||
dependencies:
|
||||
foreground-child: "npm:^3.1.0"
|
||||
jackspeak: "npm:^4.0.1"
|
||||
minimatch: "npm:^10.0.0"
|
||||
minipass: "npm:^7.1.2"
|
||||
package-json-from-dist: "npm:^1.0.0"
|
||||
path-scurry: "npm:^2.0.0"
|
||||
bin:
|
||||
glob: dist/esm/bin.mjs
|
||||
checksum: 10/57b12a05cc25f1c38f3b24cf6ea7a8bacef11e782c4b9a8c5b0bef3e6c5bcb8c4548cb31eb4115592e0490a024c1bde7359c470565608dd061d3b21179740457
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:11.0.3":
|
||||
version: 11.0.3
|
||||
resolution: "glob@npm:11.0.3"
|
||||
@@ -30802,6 +30786,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:11.1.0":
|
||||
version: 11.1.0
|
||||
resolution: "glob@npm:11.1.0"
|
||||
dependencies:
|
||||
foreground-child: "npm:^3.3.1"
|
||||
jackspeak: "npm:^4.1.1"
|
||||
minimatch: "npm:^10.1.1"
|
||||
minipass: "npm:^7.1.2"
|
||||
package-json-from-dist: "npm:^1.0.0"
|
||||
path-scurry: "npm:^2.0.0"
|
||||
bin:
|
||||
glob: dist/esm/bin.mjs
|
||||
checksum: 10/da4501819633daff8822c007bb3f93d5c4d2cbc7b15a8e886660f4497dd251a1fb4f53a85fba1e760b31704eff7164aeb2c7a82db10f9f2c362d12c02fe52cf3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:7.0.6":
|
||||
version: 7.0.6
|
||||
resolution: "glob@npm:7.0.6"
|
||||
@@ -34489,7 +34489,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jackspeak@npm:^4.0.1, jackspeak@npm:^4.1.1":
|
||||
"jackspeak@npm:^4.1.1":
|
||||
version: 4.1.1
|
||||
resolution: "jackspeak@npm:4.1.1"
|
||||
dependencies:
|
||||
@@ -38645,7 +38645,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^10.0.0, minimatch@npm:^10.0.1, minimatch@npm:^10.1.1":
|
||||
"minimatch@npm:^10.0.1, minimatch@npm:^10.1.1":
|
||||
version: 10.1.1
|
||||
resolution: "minimatch@npm:10.1.1"
|
||||
dependencies:
|
||||
@@ -44258,11 +44258,11 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-localize@npm:3.5.4":
|
||||
version: 3.5.4
|
||||
resolution: "react-native-localize@npm:3.5.4"
|
||||
"react-native-localize@npm:3.6.0":
|
||||
version: 3.6.0
|
||||
resolution: "react-native-localize@npm:3.6.0"
|
||||
peerDependencies:
|
||||
"@expo/config-plugins": ^9.0.0 || ^10.0.0
|
||||
"@expo/config-plugins": "*"
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
react-native-macos: "*"
|
||||
@@ -44271,7 +44271,7 @@ __metadata:
|
||||
optional: true
|
||||
react-native-macos:
|
||||
optional: true
|
||||
checksum: 10/afcd00e12561d147ad50b5d2f240a7b7853c5bd8226386e0afab61c7acd7b8a2b40651552272dbb293f5ed68800e0e3e48bd939d98888be81a0f9687c70cdb6b
|
||||
checksum: 10/1a443a77f3431ad638c577c1fc1b2f0b6234c61fd66dcf1ca095303b23dea47fb8bd0d40b18abc2917b874c9df75fe638c40bec6745fce995ad01ccef69d250e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -46582,9 +46582,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"samlify@npm:2.10.1":
|
||||
version: 2.10.1
|
||||
resolution: "samlify@npm:2.10.1"
|
||||
"samlify@npm:2.10.2":
|
||||
version: 2.10.2
|
||||
resolution: "samlify@npm:2.10.2"
|
||||
dependencies:
|
||||
"@authenio/xml-encryption": "npm:^2.0.2"
|
||||
"@xmldom/xmldom": "npm:^0.8.6"
|
||||
@@ -46597,7 +46597,7 @@ __metadata:
|
||||
xml-crypto: "npm:^6.1.2"
|
||||
xml-escape: "npm:^1.1.0"
|
||||
xpath: "npm:^0.0.32"
|
||||
checksum: 10/f44259ec1f03faacedbd9b3098b07893dd69204492d1f4c63dca0bd8b979ed9ea76e3911f7e953baa4e11787acdb9f33e5449e21b0199f7ff627f449a9ce3897
|
||||
checksum: 10/2f46e2b172fd43c3c63ad18e9a715e6cbfaf4a781ef8f6b2f7f42c3a3998ae7e07fc41a3d24a5f54f88e716535b3a8e0c2953a3788fef0430762b29e8f8b9ffe
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user