mirror of https://github.com/laurent22/joplin.git
Merge branch 'dev' into release-2.8
commit
89a498b886
|
@ -562,6 +562,9 @@ packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js.map
|
|||
packages/app-desktop/gui/NoteList/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteList/commands/index.js
|
||||
packages/app-desktop/gui/NoteList/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteList/types.d.ts
|
||||
packages/app-desktop/gui/NoteList/types.js
|
||||
packages/app-desktop/gui/NoteList/types.js.map
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js.map
|
||||
|
|
|
@ -552,6 +552,9 @@ packages/app-desktop/gui/NoteList/commands/focusElementNoteList.js.map
|
|||
packages/app-desktop/gui/NoteList/commands/index.d.ts
|
||||
packages/app-desktop/gui/NoteList/commands/index.js
|
||||
packages/app-desktop/gui/NoteList/commands/index.js.map
|
||||
packages/app-desktop/gui/NoteList/types.d.ts
|
||||
packages/app-desktop/gui/NoteList/types.js
|
||||
packages/app-desktop/gui/NoteList/types.js.map
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.d.ts
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js
|
||||
packages/app-desktop/gui/NoteListControls/NoteListControls.js.map
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
|
@ -70,7 +70,7 @@ A community maintained list of these distributions can be found here: [Unofficia
|
|||
# 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://usrigging.com/"><img title="U.S. Ringing Supply" width="256" src="https://joplinapp.org/images/sponsors/RingingSupply.svg"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-github&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></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://usrigging.com/"><img title="U.S. Ringing Supply" width="256" src="https://joplinapp.org/images/sponsors/RingingSupply.svg"/></a> <a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-github&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a> <a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a>
|
||||
<!-- SPONSORS-ORG -->
|
||||
|
||||
* * *
|
||||
|
|
|
@ -354,8 +354,7 @@ class Application extends BaseApplication {
|
|||
}
|
||||
|
||||
// Loads app-wide styles. (Markdown preview-specific styles loaded in app.js)
|
||||
const filename = Setting.custom_css_files.JOPLIN_APP;
|
||||
await injectCustomStyles('appStyles', `${dir}/${filename}`);
|
||||
await injectCustomStyles('appStyles', Setting.customCssFilePath(Setting.customCssFilenames.JOPLIN_APP));
|
||||
|
||||
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
||||
AlarmService.setLogger(reg.logger());
|
||||
|
@ -433,7 +432,7 @@ class Application extends BaseApplication {
|
|||
});
|
||||
|
||||
// Loads custom Markdown preview styles
|
||||
const cssString = await loadCustomCss(`${Setting.value('profileDir')}/userstyle.css`);
|
||||
const cssString = await loadCustomCss(Setting.customCssFilePath(Setting.customCssFilenames.RENDERED_MARKDOWN));
|
||||
this.store().dispatch({
|
||||
type: 'CUSTOM_CSS_APPEND',
|
||||
css: cssString,
|
||||
|
@ -522,6 +521,7 @@ class Application extends BaseApplication {
|
|||
migrationService: MigrationService.instance(),
|
||||
decryptionWorker: DecryptionWorker.instance(),
|
||||
commandService: CommandService.instance(),
|
||||
pluginService: PluginService.instance(),
|
||||
bridge: bridge(),
|
||||
debug: new DebugService(reg.db()),
|
||||
};
|
||||
|
|
|
@ -265,7 +265,7 @@ export class Bridge {
|
|||
}
|
||||
}
|
||||
|
||||
restart() {
|
||||
restart(linuxSafeRestart = true) {
|
||||
// Note that in this case we are not sending the "appClose" event
|
||||
// to notify services and component that the app is about to close
|
||||
// but for the current use-case it's not really needed.
|
||||
|
@ -276,7 +276,7 @@ export class Bridge {
|
|||
execPath: process.env.PORTABLE_EXECUTABLE_FILE,
|
||||
};
|
||||
app.relaunch(options);
|
||||
} else if (shim.isLinux()) {
|
||||
} else if (shim.isLinux() && linuxSafeRestart) {
|
||||
this.showInfoMessageBox(_('The app is now going to close. Please relaunch it to complete the process.'));
|
||||
} else {
|
||||
app.relaunch();
|
||||
|
|
|
@ -10,17 +10,17 @@ export const declaration: CommandDeclaration = {
|
|||
|
||||
export const runtime = (): CommandRuntime => {
|
||||
return {
|
||||
execute: async (context: CommandContext, profileIndex: number) => {
|
||||
execute: async (context: CommandContext, profileId: string) => {
|
||||
const currentConfig = context.state.profileConfig;
|
||||
if (currentConfig.currentProfile === profileIndex) return;
|
||||
if (currentConfig.currentProfileId === profileId) return;
|
||||
|
||||
const newConfig: ProfileConfig = {
|
||||
...currentConfig,
|
||||
currentProfile: profileIndex,
|
||||
currentProfileId: profileId,
|
||||
};
|
||||
|
||||
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
||||
bridge().restart();
|
||||
bridge().restart(false);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import CommandService, { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { profileIdByIndex } from '../../lib/services/profileConfig';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'switchProfile1',
|
||||
|
@ -8,8 +9,8 @@ export const declaration: CommandDeclaration = {
|
|||
|
||||
export const runtime = (): CommandRuntime => {
|
||||
return {
|
||||
execute: async (_context: CommandContext) => {
|
||||
await CommandService.instance().execute('switchProfile', 0);
|
||||
execute: async (context: CommandContext) => {
|
||||
await CommandService.instance().execute('switchProfile', profileIdByIndex(context.state.profileConfig, 0));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import CommandService, { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { profileIdByIndex } from '../../lib/services/profileConfig';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'switchProfile2',
|
||||
|
@ -8,8 +9,8 @@ export const declaration: CommandDeclaration = {
|
|||
|
||||
export const runtime = (): CommandRuntime => {
|
||||
return {
|
||||
execute: async (_context: CommandContext) => {
|
||||
await CommandService.instance().execute('switchProfile', 1);
|
||||
execute: async (context: CommandContext) => {
|
||||
await CommandService.instance().execute('switchProfile', profileIdByIndex(context.state.profileConfig, 1));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import CommandService, { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { profileIdByIndex } from '../../lib/services/profileConfig';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'switchProfile3',
|
||||
|
@ -8,8 +9,8 @@ export const declaration: CommandDeclaration = {
|
|||
|
||||
export const runtime = (): CommandRuntime => {
|
||||
return {
|
||||
execute: async (_context: CommandContext) => {
|
||||
await CommandService.instance().execute('switchProfile', 2);
|
||||
execute: async (context: CommandContext) => {
|
||||
await CommandService.instance().execute('switchProfile', profileIdByIndex(context.state.profileConfig, 2));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ import NoteEditor from '../NoteEditor/NoteEditor';
|
|||
import NoteContentPropertiesDialog from '../NoteContentPropertiesDialog';
|
||||
import ShareNoteDialog from '../ShareNoteDialog';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
import { PluginStates, utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';
|
||||
import { PluginHtmlContents, PluginStates, utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';
|
||||
import Sidebar from '../Sidebar/Sidebar';
|
||||
import UserWebview from '../../services/plugins/UserWebview';
|
||||
import UserWebviewDialog from '../../services/plugins/UserWebviewDialog';
|
||||
|
@ -53,6 +53,7 @@ interface LayerModalState {
|
|||
|
||||
interface Props {
|
||||
plugins: PluginStates;
|
||||
pluginHtmlContents: PluginHtmlContents;
|
||||
pluginsLoaded: boolean;
|
||||
hasNotesBeingSaved: boolean;
|
||||
dispatch: Function;
|
||||
|
@ -723,12 +724,13 @@ class MainScreenComponent extends React.Component<Props, State> {
|
|||
}
|
||||
} else {
|
||||
const { view, plugin } = viewInfo;
|
||||
const html = this.props.pluginHtmlContents[plugin.id]?.[view.id] ?? '';
|
||||
|
||||
return <UserWebview
|
||||
key={view.id}
|
||||
viewId={view.id}
|
||||
themeId={this.props.themeId}
|
||||
html={view.html}
|
||||
html={html}
|
||||
scripts={view.scripts}
|
||||
pluginId={plugin.id}
|
||||
borderBottom={true}
|
||||
|
@ -762,12 +764,13 @@ class MainScreenComponent extends React.Component<Props, State> {
|
|||
const { plugin, view } = info;
|
||||
if (view.containerType !== ContainerType.Dialog) continue;
|
||||
if (!view.opened) continue;
|
||||
const html = this.props.pluginHtmlContents[plugin.id]?.[view.id] ?? '';
|
||||
|
||||
output.push(<UserWebviewDialog
|
||||
key={view.id}
|
||||
viewId={view.id}
|
||||
themeId={this.props.themeId}
|
||||
html={view.html}
|
||||
html={html}
|
||||
scripts={view.scripts}
|
||||
pluginId={plugin.id}
|
||||
buttons={view.buttons}
|
||||
|
@ -865,6 +868,7 @@ const mapStateToProps = (state: AppState) => {
|
|||
selectedNoteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
|
||||
pluginsLegacy: state.pluginsLegacy,
|
||||
plugins: state.pluginService.plugins,
|
||||
pluginHtmlContents: state.pluginService.pluginHtmlContents,
|
||||
customCss: state.customCss,
|
||||
editorNoteStatuses: state.editorNoteStatuses,
|
||||
hasNotesBeingSaved: stateUtils.hasNotesBeingSaved(state),
|
||||
|
|
|
@ -19,10 +19,10 @@ export const runtime = (comp: any): CommandRuntime => {
|
|||
value: '',
|
||||
onClose: async (answer: string) => {
|
||||
if (answer) {
|
||||
const newConfig = await createNewProfile(context.state.profileConfig, answer);
|
||||
newConfig.currentProfile = newConfig.profiles.length - 1;
|
||||
const { newConfig, newProfile } = createNewProfile(context.state.profileConfig, answer);
|
||||
newConfig.currentProfileId = newProfile.id;
|
||||
await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newConfig);
|
||||
bridge().restart();
|
||||
bridge().restart(false);
|
||||
}
|
||||
|
||||
comp.setState({ promptOptions: null });
|
||||
|
|
|
@ -86,14 +86,14 @@ const useSwitchProfileMenuItems = (profileConfig: ProfileConfig, menuItemDic: an
|
|||
menuItem = {
|
||||
label: profile.name,
|
||||
click: () => {
|
||||
void CommandService.instance().execute('switchProfile', i);
|
||||
void CommandService.instance().execute('switchProfile', profile.id);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
menuItem.label = profile.name;
|
||||
menuItem.type = 'checkbox';
|
||||
menuItem.checked = profileConfig.currentProfile === i;
|
||||
menuItem.checked = profileConfig.currentProfileId === profile.id;
|
||||
|
||||
switchProfileMenuItems.push(menuItem);
|
||||
}
|
||||
|
@ -211,6 +211,12 @@ function useMenu(props: Props) {
|
|||
const [keymapLastChangeTime, setKeymapLastChangeTime] = useState(Date.now());
|
||||
const [modulesLastChangeTime, setModulesLastChangeTime] = useState(Date.now());
|
||||
|
||||
// We use a ref here because the plugin state can change frequently when
|
||||
// switching note since any plugin view might be rendered again. However we
|
||||
// need this plugin state only in a click handler when exporting notes, and
|
||||
// for that a ref is sufficient.
|
||||
const pluginsRef = useRef(props.plugins);
|
||||
|
||||
const onMenuItemClick = useCallback((commandName: string) => {
|
||||
void CommandService.instance().execute(commandName);
|
||||
}, []);
|
||||
|
@ -371,7 +377,7 @@ function useMenu(props: Props) {
|
|||
(action: any) => props.dispatch(action),
|
||||
module,
|
||||
{
|
||||
plugins: props.plugins,
|
||||
plugins: pluginsRef.current,
|
||||
customCss: props.customCss,
|
||||
}
|
||||
);
|
||||
|
@ -905,7 +911,6 @@ function useMenu(props: Props) {
|
|||
modulesLastChangeTime,
|
||||
props['spellChecker.language'],
|
||||
props['spellChecker.enabled'],
|
||||
props.plugins,
|
||||
props.customCss,
|
||||
props.locale,
|
||||
props.profileConfig,
|
||||
|
|
|
@ -39,7 +39,7 @@ class NavigatorComponent extends Component {
|
|||
};
|
||||
|
||||
return (
|
||||
<div style={this.props.style}>
|
||||
<div style={this.props.style} className={this.props.className}>
|
||||
<Screen style={screenStyle} {...screenProps} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,11 +30,11 @@ export interface ContextMenuItems {
|
|||
[key: string]: ContextMenuItem;
|
||||
}
|
||||
|
||||
export async function resourceInfo(options: ContextMenuOptions): Promise<any> {
|
||||
export async function resourceInfo(options: ContextMenuOptions) {
|
||||
const resource = options.resourceId ? await Resource.load(options.resourceId) : null;
|
||||
const filePath = resource ? Resource.fullPath(resource) : null;
|
||||
const resourcePath = resource ? Resource.fullPath(resource) : null;
|
||||
const filename = resource ? (resource.filename ? resource.filename : resource.title) : options.filename ? options.filename : '';
|
||||
return { resource, filePath, filename };
|
||||
return { resource, resourcePath, filename };
|
||||
}
|
||||
|
||||
export function textToDataUri(text: string, mime: string): string {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { useMemo, useEffect, useState, useRef, useCallback } from 'react';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import NoteListUtils from '../utils/NoteListUtils';
|
||||
|
@ -11,12 +13,12 @@ import CommandService from '@joplin/lib/services/CommandService';
|
|||
import shim from '@joplin/lib/shim';
|
||||
import styled from 'styled-components';
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
const React = require('react');
|
||||
|
||||
const { ItemList } = require('../ItemList.min.js');
|
||||
const { connect } = require('react-redux');
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import { Props } from './types';
|
||||
import usePrevious from '../hooks/usePrevious';
|
||||
|
||||
const commands = [
|
||||
require('./commands/focusElementNoteList'),
|
||||
|
@ -29,50 +31,48 @@ const StyledRoot = styled.div`
|
|||
border-right: 1px solid ${(props: any) => props.theme.dividerColor};
|
||||
`;
|
||||
|
||||
class NoteListComponent extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
const itemAnchorRefs_: any = {
|
||||
current: {},
|
||||
};
|
||||
|
||||
CommandService.instance().componentRegisterCommands(this, commands);
|
||||
export const itemAnchorRef = (itemId: string) => {
|
||||
if (itemAnchorRefs_.current[itemId] && itemAnchorRefs_.current[itemId].current) return itemAnchorRefs_.current[itemId].current;
|
||||
return null;
|
||||
};
|
||||
|
||||
this.itemHeight = 34;
|
||||
const NoteListComponent = (props: Props) => {
|
||||
const [dragOverTargetNoteIndex, setDragOverTargetNoteIndex] = useState(null);
|
||||
const [width, setWidth] = useState(0);
|
||||
const [, setHeight] = useState(0);
|
||||
|
||||
this.state = {
|
||||
dragOverTargetNoteIndex: null,
|
||||
width: 0,
|
||||
height: 0,
|
||||
useEffect(() => {
|
||||
itemAnchorRefs_.current = {};
|
||||
CommandService.instance().registerCommands(commands);
|
||||
|
||||
return () => {
|
||||
itemAnchorRefs_.current = {};
|
||||
CommandService.instance().unregisterCommands(commands);
|
||||
};
|
||||
}, []);
|
||||
|
||||
this.noteListRef = React.createRef();
|
||||
this.itemListRef = React.createRef();
|
||||
this.itemAnchorRefs_ = {};
|
||||
const itemHeight = 34;
|
||||
|
||||
this.renderItem = this.renderItem.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.noteItem_titleClick = this.noteItem_titleClick.bind(this);
|
||||
this.noteItem_noteDragOver = this.noteItem_noteDragOver.bind(this);
|
||||
this.noteItem_noteDrop = this.noteItem_noteDrop.bind(this);
|
||||
this.noteItem_checkboxClick = this.noteItem_checkboxClick.bind(this);
|
||||
this.noteItem_dragStart = this.noteItem_dragStart.bind(this);
|
||||
this.onGlobalDrop_ = this.onGlobalDrop_.bind(this);
|
||||
this.registerGlobalDragEndEvent_ = this.registerGlobalDragEndEvent_.bind(this);
|
||||
this.unregisterGlobalDragEndEvent_ = this.unregisterGlobalDragEndEvent_.bind(this);
|
||||
this.itemContextMenu = this.itemContextMenu.bind(this);
|
||||
this.resizableLayout_resize = this.resizableLayout_resize.bind(this);
|
||||
}
|
||||
const focusItemIID_ = useRef<any>(null);
|
||||
const noteListRef = useRef(null);
|
||||
const itemListRef = useRef(null);
|
||||
|
||||
style() {
|
||||
if (this.styleCache_ && this.styleCache_[this.props.themeId]) return this.styleCache_[this.props.themeId];
|
||||
let globalDragEndEventRegistered_ = false;
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const style = useMemo(() => {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
const style = {
|
||||
return {
|
||||
root: {
|
||||
backgroundColor: theme.backgroundColor,
|
||||
},
|
||||
listItem: {
|
||||
maxWidth: '100%',
|
||||
height: this.itemHeight,
|
||||
height: itemHeight,
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
alignItems: 'stretch',
|
||||
|
@ -99,76 +99,71 @@ class NoteListComponent extends React.Component {
|
|||
textDecoration: 'line-through',
|
||||
},
|
||||
};
|
||||
}, [props.themeId, itemHeight]);
|
||||
|
||||
this.styleCache_ = {};
|
||||
this.styleCache_[this.props.themeId] = style;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
itemContextMenu(event: any) {
|
||||
const itemContextMenu = useCallback((event: any) => {
|
||||
const currentItemId = event.currentTarget.getAttribute('data-id');
|
||||
if (!currentItemId) return;
|
||||
|
||||
let noteIds = [];
|
||||
if (this.props.selectedNoteIds.indexOf(currentItemId) < 0) {
|
||||
if (props.selectedNoteIds.indexOf(currentItemId) < 0) {
|
||||
noteIds = [currentItemId];
|
||||
} else {
|
||||
noteIds = this.props.selectedNoteIds;
|
||||
noteIds = props.selectedNoteIds;
|
||||
}
|
||||
|
||||
if (!noteIds.length) return;
|
||||
|
||||
const menu = NoteListUtils.makeContextMenu(noteIds, {
|
||||
notes: this.props.notes,
|
||||
dispatch: this.props.dispatch,
|
||||
watchedNoteFiles: this.props.watchedNoteFiles,
|
||||
plugins: this.props.plugins,
|
||||
inConflictFolder: this.props.selectedFolderId === Folder.conflictFolderId(),
|
||||
customCss: this.props.customCss,
|
||||
notes: props.notes,
|
||||
dispatch: props.dispatch,
|
||||
watchedNoteFiles: props.watchedNoteFiles,
|
||||
plugins: props.plugins,
|
||||
inConflictFolder: props.selectedFolderId === Folder.conflictFolderId(),
|
||||
customCss: props.customCss,
|
||||
});
|
||||
|
||||
menu.popup(bridge().window());
|
||||
}
|
||||
}, [props.selectedNoteIds, props.notes, props.dispatch, props.watchedNoteFiles,props.plugins, props.selectedFolderId, props.customCss]);
|
||||
|
||||
onGlobalDrop_() {
|
||||
this.unregisterGlobalDragEndEvent_();
|
||||
this.setState({ dragOverTargetNoteIndex: null });
|
||||
}
|
||||
const onGlobalDrop_ = () => {
|
||||
unregisterGlobalDragEndEvent_();
|
||||
setDragOverTargetNoteIndex(null);
|
||||
};
|
||||
|
||||
registerGlobalDragEndEvent_() {
|
||||
if (this.globalDragEndEventRegistered_) return;
|
||||
this.globalDragEndEventRegistered_ = true;
|
||||
document.addEventListener('dragend', this.onGlobalDrop_);
|
||||
}
|
||||
const registerGlobalDragEndEvent_ = () => {
|
||||
if (globalDragEndEventRegistered_) return;
|
||||
globalDragEndEventRegistered_ = true;
|
||||
document.addEventListener('dragend', onGlobalDrop_);
|
||||
};
|
||||
|
||||
unregisterGlobalDragEndEvent_() {
|
||||
this.globalDragEndEventRegistered_ = false;
|
||||
document.removeEventListener('dragend', this.onGlobalDrop_);
|
||||
}
|
||||
const unregisterGlobalDragEndEvent_ = () => {
|
||||
globalDragEndEventRegistered_ = false;
|
||||
document.removeEventListener('dragend', onGlobalDrop_);
|
||||
};
|
||||
|
||||
dragTargetNoteIndex_(event: any) {
|
||||
return Math.abs(Math.round((event.clientY - this.itemListRef.current.offsetTop() + this.itemListRef.current.offsetScroll()) / this.itemHeight));
|
||||
}
|
||||
const dragTargetNoteIndex_ = (event: any) => {
|
||||
return Math.abs(Math.round((event.clientY - itemListRef.current.offsetTop() + itemListRef.current.offsetScroll()) / itemHeight));
|
||||
};
|
||||
|
||||
noteItem_noteDragOver(event: any) {
|
||||
if (this.props.notesParentType !== 'Folder') return;
|
||||
const noteItem_noteDragOver = (event: any) => {
|
||||
if (props.notesParentType !== 'Folder') return;
|
||||
|
||||
const dt = event.dataTransfer;
|
||||
|
||||
if (dt.types.indexOf('text/x-jop-note-ids') >= 0) {
|
||||
event.preventDefault();
|
||||
const newIndex = this.dragTargetNoteIndex_(event);
|
||||
if (this.state.dragOverTargetNoteIndex === newIndex) return;
|
||||
this.registerGlobalDragEndEvent_();
|
||||
this.setState({ dragOverTargetNoteIndex: newIndex });
|
||||
const newIndex = dragTargetNoteIndex_(event);
|
||||
if (dragOverTargetNoteIndex === newIndex) return;
|
||||
registerGlobalDragEndEvent_();
|
||||
setDragOverTargetNoteIndex(newIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async noteItem_noteDrop(event: any) {
|
||||
if (this.props.notesParentType !== 'Folder') return;
|
||||
const noteItem_noteDrop = async (event: any) => {
|
||||
if (props.notesParentType !== 'Folder') return;
|
||||
|
||||
if (this.props.noteSortOrder !== 'order') {
|
||||
if (props.noteSortOrder !== 'order') {
|
||||
const doIt = await bridge().showConfirmMessageBox(_('To manually sort the notes, the sort order must be changed to "%s" in the menu "%s" > "%s"', _('Custom order'), _('View'), _('Sort notes by')), {
|
||||
buttons: [_('Do it now'), _('Cancel')],
|
||||
});
|
||||
|
@ -181,17 +176,17 @@ class NoteListComponent extends React.Component {
|
|||
// TODO: check that parent type is folder
|
||||
|
||||
const dt = event.dataTransfer;
|
||||
this.unregisterGlobalDragEndEvent_();
|
||||
this.setState({ dragOverTargetNoteIndex: null });
|
||||
unregisterGlobalDragEndEvent_();
|
||||
setDragOverTargetNoteIndex(null);
|
||||
|
||||
const targetNoteIndex = this.dragTargetNoteIndex_(event);
|
||||
const targetNoteIndex = dragTargetNoteIndex_(event);
|
||||
const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids'));
|
||||
|
||||
void Note.insertNotesAt(this.props.selectedFolderId, noteIds, targetNoteIndex);
|
||||
}
|
||||
void Note.insertNotesAt(props.selectedFolderId, noteIds, targetNoteIndex);
|
||||
};
|
||||
|
||||
|
||||
async noteItem_checkboxClick(event: any, item: any) {
|
||||
const noteItem_checkboxClick = async (event: any, item: any) => {
|
||||
const checked = event.target.checked;
|
||||
const newNote = {
|
||||
id: item.id,
|
||||
|
@ -199,37 +194,37 @@ class NoteListComponent extends React.Component {
|
|||
};
|
||||
await Note.save(newNote, { userSideValidation: true });
|
||||
eventManager.emit('todoToggle', { noteId: item.id, note: newNote });
|
||||
}
|
||||
};
|
||||
|
||||
async noteItem_titleClick(event: any, item: any) {
|
||||
const noteItem_titleClick = async (event: any, item: any) => {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
event.preventDefault();
|
||||
this.props.dispatch({
|
||||
props.dispatch({
|
||||
type: 'NOTE_SELECT_TOGGLE',
|
||||
id: item.id,
|
||||
});
|
||||
} else if (event.shiftKey) {
|
||||
event.preventDefault();
|
||||
this.props.dispatch({
|
||||
props.dispatch({
|
||||
type: 'NOTE_SELECT_EXTEND',
|
||||
id: item.id,
|
||||
});
|
||||
} else {
|
||||
this.props.dispatch({
|
||||
props.dispatch({
|
||||
type: 'NOTE_SELECT',
|
||||
id: item.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
noteItem_dragStart(event: any) {
|
||||
const noteItem_dragStart = (event: any) => {
|
||||
let noteIds = [];
|
||||
|
||||
// Here there is two cases:
|
||||
// - If multiple notes are selected, we drag the group
|
||||
// - If only one note is selected, we drag the note that was clicked on (which might be different from the currently selected note)
|
||||
if (this.props.selectedNoteIds.length >= 2) {
|
||||
noteIds = this.props.selectedNoteIds;
|
||||
if (props.selectedNoteIds.length >= 2) {
|
||||
noteIds = props.selectedNoteIds;
|
||||
} else {
|
||||
const clickedNoteId = event.currentTarget.getAttribute('data-id');
|
||||
if (clickedNoteId) noteIds.push(clickedNoteId);
|
||||
|
@ -240,61 +235,66 @@ class NoteListComponent extends React.Component {
|
|||
event.dataTransfer.setDragImage(new Image(), 1, 1);
|
||||
event.dataTransfer.clearData();
|
||||
event.dataTransfer.setData('text/x-jop-note-ids', JSON.stringify(noteIds));
|
||||
}
|
||||
};
|
||||
|
||||
renderItem(item: any, index: number) {
|
||||
const renderItem = useCallback((item: any, index: number) => {
|
||||
const highlightedWords = () => {
|
||||
if (this.props.notesParentType === 'Search') {
|
||||
const query = BaseModel.byId(this.props.searches, this.props.selectedSearchId);
|
||||
if (props.notesParentType === 'Search') {
|
||||
const query = BaseModel.byId(props.searches, props.selectedSearchId);
|
||||
if (query) {
|
||||
return this.props.highlightedWords;
|
||||
return props.highlightedWords;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
if (!this.itemAnchorRefs_[item.id]) this.itemAnchorRefs_[item.id] = React.createRef();
|
||||
const ref = this.itemAnchorRefs_[item.id];
|
||||
if (!itemAnchorRefs_.current[item.id]) itemAnchorRefs_.current[item.id] = React.createRef();
|
||||
const ref = itemAnchorRefs_.current[item.id];
|
||||
|
||||
return <NoteListItem
|
||||
ref={ref}
|
||||
key={item.id}
|
||||
style={this.style()}
|
||||
style={style}
|
||||
item={item}
|
||||
index={index}
|
||||
themeId={this.props.themeId}
|
||||
width={this.state.width}
|
||||
height={this.itemHeight}
|
||||
dragItemIndex={this.state.dragOverTargetNoteIndex}
|
||||
themeId={props.themeId}
|
||||
width={width}
|
||||
height={itemHeight}
|
||||
dragItemIndex={dragOverTargetNoteIndex}
|
||||
highlightedWords={highlightedWords()}
|
||||
isProvisional={this.props.provisionalNoteIds.includes(item.id)}
|
||||
isSelected={this.props.selectedNoteIds.indexOf(item.id) >= 0}
|
||||
isWatched={this.props.watchedNoteFiles.indexOf(item.id) < 0}
|
||||
itemCount={this.props.notes.length}
|
||||
onCheckboxClick={this.noteItem_checkboxClick}
|
||||
onDragStart={this.noteItem_dragStart}
|
||||
onNoteDragOver={this.noteItem_noteDragOver}
|
||||
onNoteDrop={this.noteItem_noteDrop}
|
||||
onTitleClick={this.noteItem_titleClick}
|
||||
onContextMenu={this.itemContextMenu}
|
||||
isProvisional={props.provisionalNoteIds.includes(item.id)}
|
||||
isSelected={props.selectedNoteIds.indexOf(item.id) >= 0}
|
||||
isWatched={props.watchedNoteFiles.indexOf(item.id) < 0}
|
||||
itemCount={props.notes.length}
|
||||
onCheckboxClick={noteItem_checkboxClick}
|
||||
onDragStart={noteItem_dragStart}
|
||||
onNoteDragOver={noteItem_noteDragOver}
|
||||
onNoteDrop={noteItem_noteDrop}
|
||||
onTitleClick={noteItem_titleClick}
|
||||
onContextMenu={itemContextMenu}
|
||||
/>;
|
||||
}
|
||||
}, [style, props.themeId, width, itemHeight, dragOverTargetNoteIndex, props.provisionalNoteIds, props.selectedNoteIds, props.watchedNoteFiles,
|
||||
props.notes,
|
||||
props.notesParentType,
|
||||
props.searches,
|
||||
props.selectedSearchId,
|
||||
props.highlightedWords,
|
||||
]);
|
||||
|
||||
itemAnchorRef(itemId: string) {
|
||||
if (this.itemAnchorRefs_[itemId] && this.itemAnchorRefs_[itemId].current) return this.itemAnchorRefs_[itemId].current;
|
||||
return null;
|
||||
}
|
||||
const previousSelectedNoteIds = usePrevious(props.selectedNoteIds, []);
|
||||
const previousNotes = usePrevious(props.notes, []);
|
||||
const previousVisible = usePrevious(props.visible, false);
|
||||
|
||||
componentDidUpdate(prevProps: any) {
|
||||
if (prevProps.selectedNoteIds !== this.props.selectedNoteIds && this.props.selectedNoteIds.length === 1) {
|
||||
const id = this.props.selectedNoteIds[0];
|
||||
const doRefocus = this.props.notes.length < prevProps.notes.length;
|
||||
useEffect(() => {
|
||||
if (previousSelectedNoteIds !== props.selectedNoteIds && props.selectedNoteIds.length === 1) {
|
||||
const id = props.selectedNoteIds[0];
|
||||
const doRefocus = props.notes.length < previousNotes.length;
|
||||
|
||||
for (let i = 0; i < this.props.notes.length; i++) {
|
||||
if (this.props.notes[i].id === id) {
|
||||
this.itemListRef.current.makeItemIndexVisible(i);
|
||||
for (let i = 0; i < props.notes.length; i++) {
|
||||
if (props.notes[i].id === id) {
|
||||
itemListRef.current.makeItemIndexVisible(i);
|
||||
if (doRefocus) {
|
||||
const ref = this.itemAnchorRef(id);
|
||||
const ref = itemAnchorRef(id);
|
||||
if (ref) ref.focus();
|
||||
}
|
||||
break;
|
||||
|
@ -302,24 +302,24 @@ class NoteListComponent extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
if (prevProps.visible !== this.props.visible) {
|
||||
this.updateSizeState();
|
||||
if (previousVisible !== props.visible) {
|
||||
updateSizeState();
|
||||
}
|
||||
}
|
||||
}, [previousSelectedNoteIds,previousNotes, previousVisible, props.selectedNoteIds, props.notes]);
|
||||
|
||||
scrollNoteIndex_(keyCode: any, ctrlKey: any, metaKey: any, noteIndex: any) {
|
||||
const scrollNoteIndex_ = (keyCode: any, ctrlKey: any, metaKey: any, noteIndex: any) => {
|
||||
|
||||
if (keyCode === 33) {
|
||||
// Page Up
|
||||
noteIndex -= (this.itemListRef.current.visibleItemCount() - 1);
|
||||
noteIndex -= (itemListRef.current.visibleItemCount() - 1);
|
||||
|
||||
} else if (keyCode === 34) {
|
||||
// Page Down
|
||||
noteIndex += (this.itemListRef.current.visibleItemCount() - 1);
|
||||
noteIndex += (itemListRef.current.visibleItemCount() - 1);
|
||||
|
||||
} else if ((keyCode === 35 && ctrlKey) || (keyCode === 40 && metaKey)) {
|
||||
// CTRL+End, CMD+Down
|
||||
noteIndex = this.props.notes.length - 1;
|
||||
noteIndex = props.notes.length - 1;
|
||||
|
||||
} else if ((keyCode === 36 && ctrlKey) || (keyCode === 38 && metaKey)) {
|
||||
// CTRL+Home, CMD+Up
|
||||
|
@ -334,31 +334,31 @@ class NoteListComponent extends React.Component {
|
|||
noteIndex += 1;
|
||||
}
|
||||
if (noteIndex < 0) noteIndex = 0;
|
||||
if (noteIndex > this.props.notes.length - 1) noteIndex = this.props.notes.length - 1;
|
||||
if (noteIndex > props.notes.length - 1) noteIndex = props.notes.length - 1;
|
||||
return noteIndex;
|
||||
}
|
||||
};
|
||||
|
||||
async onKeyDown(event: any) {
|
||||
const onKeyDown = async (event: any) => {
|
||||
const keyCode = event.keyCode;
|
||||
const noteIds = this.props.selectedNoteIds;
|
||||
const noteIds = props.selectedNoteIds;
|
||||
|
||||
if (noteIds.length > 0 && (keyCode === 40 || keyCode === 38 || keyCode === 33 || keyCode === 34 || keyCode === 35 || keyCode == 36)) {
|
||||
// DOWN / UP / PAGEDOWN / PAGEUP / END / HOME
|
||||
const noteId = noteIds[0];
|
||||
let noteIndex = BaseModel.modelIndexById(this.props.notes, noteId);
|
||||
let noteIndex = BaseModel.modelIndexById(props.notes, noteId);
|
||||
|
||||
noteIndex = this.scrollNoteIndex_(keyCode, event.ctrlKey, event.metaKey, noteIndex);
|
||||
noteIndex = scrollNoteIndex_(keyCode, event.ctrlKey, event.metaKey, noteIndex);
|
||||
|
||||
const newSelectedNote = this.props.notes[noteIndex];
|
||||
const newSelectedNote = props.notes[noteIndex];
|
||||
|
||||
this.props.dispatch({
|
||||
props.dispatch({
|
||||
type: 'NOTE_SELECT',
|
||||
id: newSelectedNote.id,
|
||||
});
|
||||
|
||||
this.itemListRef.current.makeItemIndexVisible(noteIndex);
|
||||
itemListRef.current.makeItemIndexVisible(noteIndex);
|
||||
|
||||
this.focusNoteId_(newSelectedNote.id);
|
||||
focusNoteId_(newSelectedNote.id);
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ class NoteListComponent extends React.Component {
|
|||
// SPACE
|
||||
event.preventDefault();
|
||||
|
||||
const notes = BaseModel.modelsByIds(this.props.notes, noteIds);
|
||||
const notes = BaseModel.modelsByIds(props.notes, noteIds);
|
||||
const todos = notes.filter((n: any) => !!n.is_todo);
|
||||
if (!todos.length) return;
|
||||
|
||||
|
@ -382,7 +382,7 @@ class NoteListComponent extends React.Component {
|
|||
await Note.save(toggledTodo);
|
||||
}
|
||||
|
||||
this.focusNoteId_(todos[0].id);
|
||||
focusNoteId_(todos[0].id);
|
||||
}
|
||||
|
||||
if (keyCode === 9) {
|
||||
|
@ -400,62 +400,63 @@ class NoteListComponent extends React.Component {
|
|||
// Ctrl+A key
|
||||
event.preventDefault();
|
||||
|
||||
this.props.dispatch({
|
||||
props.dispatch({
|
||||
type: 'NOTE_SELECT_ALL',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
focusNoteId_(noteId: string) {
|
||||
const focusNoteId_ = (noteId: string) => {
|
||||
// - We need to focus the item manually otherwise focus might be lost when the
|
||||
// list is scrolled and items within it are being rebuilt.
|
||||
// - We need to use an interval because when leaving the arrow pressed, the rendering
|
||||
// of items might lag behind and so the ref is not yet available at this point.
|
||||
if (!this.itemAnchorRef(noteId)) {
|
||||
if (this.focusItemIID_) shim.clearInterval(this.focusItemIID_);
|
||||
this.focusItemIID_ = shim.setInterval(() => {
|
||||
if (this.itemAnchorRef(noteId)) {
|
||||
this.itemAnchorRef(noteId).focus();
|
||||
shim.clearInterval(this.focusItemIID_);
|
||||
this.focusItemIID_ = null;
|
||||
if (!itemAnchorRef(noteId)) {
|
||||
if (focusItemIID_.current) shim.clearInterval(focusItemIID_.current);
|
||||
focusItemIID_.current = shim.setInterval(() => {
|
||||
if (itemAnchorRef(noteId)) {
|
||||
itemAnchorRef(noteId).focus();
|
||||
shim.clearInterval(focusItemIID_.current);
|
||||
focusItemIID_.current = null;
|
||||
}
|
||||
}, 10);
|
||||
} else {
|
||||
this.itemAnchorRef(noteId).focus();
|
||||
itemAnchorRef(noteId).focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateSizeState() {
|
||||
this.setState({
|
||||
width: this.noteListRef.current.clientWidth,
|
||||
height: this.noteListRef.current.clientHeight,
|
||||
});
|
||||
}
|
||||
const updateSizeState = () => {
|
||||
setWidth(noteListRef.current.clientWidth);
|
||||
setHeight(noteListRef.current.clientHeight);
|
||||
};
|
||||
|
||||
resizableLayout_resize() {
|
||||
this.updateSizeState();
|
||||
}
|
||||
const resizableLayout_resize = () => {
|
||||
updateSizeState();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.resizableLayoutEventEmitter.on('resize', this.resizableLayout_resize);
|
||||
this.updateSizeState();
|
||||
}
|
||||
useEffect(() => {
|
||||
props.resizableLayoutEventEmitter.on('resize', resizableLayout_resize);
|
||||
return () => {
|
||||
props.resizableLayoutEventEmitter.off('resize', resizableLayout_resize);
|
||||
};
|
||||
}, [props.resizableLayoutEventEmitter]);
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.focusItemIID_) {
|
||||
shim.clearInterval(this.focusItemIID_);
|
||||
this.focusItemIID_ = null;
|
||||
}
|
||||
useEffect(() => {
|
||||
updateSizeState();
|
||||
|
||||
this.props.resizableLayoutEventEmitter.off('resize', this.resizableLayout_resize);
|
||||
return () => {
|
||||
if (focusItemIID_.current) {
|
||||
shim.clearInterval(focusItemIID_.current);
|
||||
focusItemIID_.current = null;
|
||||
}
|
||||
CommandService.instance().componentUnregisterCommands(commands);
|
||||
};
|
||||
}, []);
|
||||
|
||||
CommandService.instance().componentUnregisterCommands(commands);
|
||||
}
|
||||
const renderEmptyList = () => {
|
||||
if (props.notes.length) return null;
|
||||
|
||||
renderEmptyList() {
|
||||
if (this.props.notes.length) return null;
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const theme = themeStyle(props.themeId);
|
||||
const padding = 10;
|
||||
const emptyDivStyle = {
|
||||
padding: `${padding}px`,
|
||||
|
@ -464,39 +465,35 @@ class NoteListComponent extends React.Component {
|
|||
backgroundColor: theme.backgroundColor,
|
||||
fontFamily: theme.fontFamily,
|
||||
};
|
||||
// emptyDivStyle.width = emptyDivStyle.width - padding * 2;
|
||||
// emptyDivStyle.height = emptyDivStyle.height - padding * 2;
|
||||
return <div style={emptyDivStyle}>{this.props.folders.length ? _('No notes in here. Create one by clicking on "New note".') : _('There is currently no notebook. Create one by clicking on "New notebook".')}</div>;
|
||||
}
|
||||
return <div style={emptyDivStyle}>{props.folders.length ? _('No notes in here. Create one by clicking on "New note".') : _('There is currently no notebook. Create one by clicking on "New notebook".')}</div>;
|
||||
};
|
||||
|
||||
renderItemList(style: any) {
|
||||
if (!this.props.notes.length) return null;
|
||||
const renderItemList = () => {
|
||||
if (!props.notes.length) return null;
|
||||
|
||||
return (
|
||||
<ItemList
|
||||
ref={this.itemListRef}
|
||||
disabled={this.props.isInsertingNotes}
|
||||
itemHeight={this.style().listItem.height}
|
||||
ref={itemListRef}
|
||||
disabled={props.isInsertingNotes}
|
||||
itemHeight={style.listItem.height}
|
||||
className={'note-list'}
|
||||
items={this.props.notes}
|
||||
style={style}
|
||||
itemRenderer={this.renderItem}
|
||||
onKeyDown={this.onKeyDown}
|
||||
items={props.notes}
|
||||
style={props.size}
|
||||
itemRenderer={renderItem}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
if (!this.props.size) throw new Error('props.size is required');
|
||||
if (!props.size) throw new Error('props.size is required');
|
||||
|
||||
return (
|
||||
<StyledRoot ref={this.noteListRef}>
|
||||
{this.renderEmptyList()}
|
||||
{this.renderItemList(this.props.size)}
|
||||
</StyledRoot>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<StyledRoot ref={noteListRef}>
|
||||
{renderEmptyList()}
|
||||
{renderItemList()}
|
||||
</StyledRoot>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { stateUtils } from '@joplin/lib/reducer';
|
||||
import { itemAnchorRef } from '../NoteList';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'focusElementNoteList',
|
||||
|
@ -8,13 +9,13 @@ export const declaration: CommandDeclaration = {
|
|||
parentLabel: () => _('Focus'),
|
||||
};
|
||||
|
||||
export const runtime = (comp: any): CommandRuntime => {
|
||||
export const runtime = (): CommandRuntime => {
|
||||
return {
|
||||
execute: async (context: CommandContext, noteId: string = null) => {
|
||||
noteId = noteId || stateUtils.selectedNoteId(context.state);
|
||||
|
||||
if (noteId) {
|
||||
const ref = comp.itemAnchorRef(noteId);
|
||||
const ref = itemAnchorRef(noteId);
|
||||
if (ref) ref.focus();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { FolderEntity, NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
|
||||
|
||||
export interface Props {
|
||||
themeId: any;
|
||||
selectedNoteIds: string[];
|
||||
notes: NoteEntity[];
|
||||
dispatch: Function;
|
||||
watchedNoteFiles: any[];
|
||||
plugins: PluginStates;
|
||||
selectedFolderId: string;
|
||||
customCss: string;
|
||||
notesParentType: string;
|
||||
noteSortOrder: string;
|
||||
resizableLayoutEventEmitter: any;
|
||||
isInsertingNotes: boolean;
|
||||
folders: FolderEntity[];
|
||||
size: any;
|
||||
searches: any[];
|
||||
selectedSearchId: string;
|
||||
highlightedWords: string[];
|
||||
provisionalNoteIds: string[];
|
||||
visible: boolean;
|
||||
}
|
|
@ -228,7 +228,7 @@ class RootComponent extends React.Component<Props, any> {
|
|||
<StyleSheetContainer themeId={this.props.themeId}></StyleSheetContainer>
|
||||
<MenuBar/>
|
||||
<GlobalStyle/>
|
||||
<Navigator style={navigatorStyle} screens={screens} />
|
||||
<Navigator style={navigatorStyle} screens={screens} className={`profile-${this.props.profileConfigCurrentProfileId}`} />
|
||||
{this.renderModalMessage(this.modalDialogProps())}
|
||||
{this.renderDialogs()}
|
||||
</ThemeProvider>
|
||||
|
@ -245,6 +245,7 @@ const mapStateToProps = (state: AppState) => {
|
|||
themeId: state.settings.theme,
|
||||
needApiAuth: state.needApiAuth,
|
||||
dialogs: state.dialogs,
|
||||
profileConfigCurrentProfileId: state.profileConfig.currentProfileId,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Logger from '@joplin/lib/Logger';
|
||||
import time from '@joplin/lib/time';
|
||||
|
||||
const logger = Logger.create('BackOffHandler');
|
||||
|
||||
|
@ -9,23 +10,39 @@ const logger = Logger.create('BackOffHandler');
|
|||
// When a plugin needs to be throttled that way a warning is displayed so
|
||||
// that the author gets an opportunity to fix it.
|
||||
//
|
||||
// 2. If the plugin makes many simultaneous calls (over 100), the handler throws
|
||||
// an exception to stop the plugin. In that case the plugin will be broken,
|
||||
// but most plugins will not get this error anyway because call are usually
|
||||
// made in sequence. It might reveal a bug though - for example if the plugin
|
||||
// 2. If the plugin makes many simultaneous calls, the handler throws an
|
||||
// exception to stop the plugin. In that case the plugin will be broken, but
|
||||
// most plugins will not get this error anyway because call are usually made
|
||||
// in sequence. It might reveal a bug though - for example if the plugin
|
||||
// makes a call every 1 second, but does not wait for the response (or assume
|
||||
// the response will come in less than one second). In that case, the back
|
||||
// off intervals combined with the incorrect code will make the plugin fail.
|
||||
|
||||
export default class BackOffHandler {
|
||||
|
||||
private backOffIntervals_ = Array(100).fill(0).concat([0, 1, 1, 2, 3, 5, 8]);
|
||||
// The current logic is:
|
||||
//
|
||||
// - Up to 200 calls per 10 seconds without restrictions
|
||||
// - For calls 200 to 300, a 1 second wait time is applied
|
||||
// - Over 300 calls, a 2 seconds wait time is applied
|
||||
// - After 10 seconds without making any call, the limits are reset (back to
|
||||
// 0 second between calls).
|
||||
//
|
||||
// If more than 50 simultaneous calls are being throttled, it's a bug in the
|
||||
// plugin (not waiting for API responses), so we stop responding and throw
|
||||
// an error.
|
||||
|
||||
private backOffIntervals_ =
|
||||
Array(200).fill(0).concat(
|
||||
Array(100).fill(1)).concat(
|
||||
[2]);
|
||||
|
||||
private lastRequestTime_ = 0;
|
||||
private pluginId_: string;
|
||||
private resetBackOffInterval_ = (this.backOffIntervals_[this.backOffIntervals_.length - 1] + 1) * 1000;
|
||||
private resetBackOffInterval_ = 10 * 1000; // (this.backOffIntervals_[this.backOffIntervals_.length - 1] + 1) * 1000;
|
||||
private backOffIndex_ = 0;
|
||||
private waitCount_ = 0;
|
||||
private maxWaitCount_ = 100;
|
||||
private maxWaitCount_ = 50;
|
||||
|
||||
public constructor(pluginId: string) {
|
||||
this.pluginId_ = pluginId;
|
||||
|
@ -51,21 +68,13 @@ export default class BackOffHandler {
|
|||
|
||||
this.waitCount_++;
|
||||
|
||||
// For now don't actually apply a backoff and don't abort.
|
||||
|
||||
logger.warn(`Plugin ${this.pluginId_}: Applying a backoff of ${interval} seconds due to frequent plugin API calls. Consider reducing the number of calls, caching the data, or requesting more data per call. API call was: `, path, args, `[Wait count: ${this.waitCount_}]`);
|
||||
|
||||
if (this.waitCount_ > this.maxWaitCount_) logger.error(`Plugin ${this.pluginId_}: More than ${this.maxWaitCount_} API alls are waiting - aborting. Please consider queuing the API calls in your plugins to reduce the load on the application.`);
|
||||
if (this.waitCount_ > this.maxWaitCount_) throw new Error(`Plugin ${this.pluginId_}: More than ${this.maxWaitCount_} API calls are waiting - aborting. Please consider queuing the API calls in your plugins to reduce the load on the application.`);
|
||||
|
||||
await time.sleep(interval);
|
||||
|
||||
this.waitCount_--;
|
||||
|
||||
|
||||
|
||||
// if (this.waitCount_ > this.maxWaitCount_) throw new Error(`Plugin ${this.pluginId_}: More than ${this.maxWaitCount_} API alls are waiting - aborting. Please consider queuing the API calls in your plugins to reduce the load on the application.`);
|
||||
|
||||
// await time.sleep(interval);
|
||||
|
||||
// this.waitCount_--;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,6 +157,8 @@ export default class PluginRunner extends BasePluginRunner {
|
|||
const debugMappedArgs = fullPath.includes('setHtml') ? '<hidden>' : mappedArgs;
|
||||
logger.debug(`Got message (3): ${fullPath}`, debugMappedArgs);
|
||||
|
||||
this.recordCallStat(plugin.id);
|
||||
|
||||
try {
|
||||
await this.backOffHandler(plugin.id).wait(fullPath, debugMappedArgs);
|
||||
} catch (error) {
|
||||
|
|
|
@ -86,7 +86,7 @@ class Dropdown extends React.Component {
|
|||
if (this.props.labelTransform && this.props.labelTransform === 'trim') headerLabel = headerLabel.trim();
|
||||
|
||||
const closeList = () => {
|
||||
if (this.props.onClose()) this.props.onClose();
|
||||
if (this.props.onClose) this.props.onClose();
|
||||
this.setState({ listVisible: false });
|
||||
};
|
||||
|
||||
|
@ -116,7 +116,7 @@ class Dropdown extends React.Component {
|
|||
onPress={() => {
|
||||
this.updateHeaderCoordinates();
|
||||
this.setState({ listVisible: true });
|
||||
if (this.props.onOpen()) this.props.onOpen();
|
||||
if (this.props.onOpen) this.props.onOpen();
|
||||
}}
|
||||
>
|
||||
<Text ellipsizeMode="tail" numberOfLines={1} style={headerStyle}>
|
||||
|
|
|
@ -492,7 +492,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 80;
|
||||
CURRENT_PROJECT_VERSION = 81;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
|
@ -521,7 +521,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 80;
|
||||
CURRENT_PROJECT_VERSION = 81;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
INFOPLIST_FILE = Joplin/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
|
@ -667,7 +667,7 @@
|
|||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 80;
|
||||
CURRENT_PROJECT_VERSION = 81;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
@ -698,7 +698,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 80;
|
||||
CURRENT_PROJECT_VERSION = 81;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = A9BXAFS6CT;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "@joplin/app-mobile",
|
||||
"description": "Joplin for Mobile",
|
||||
"license": "MIT",
|
||||
"version": "0.8.9",
|
||||
"version": "2.8.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "react-native start --reset-cache",
|
||||
|
@ -15,8 +15,8 @@
|
|||
"postinstall": "jetify && yarn run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "~2.6",
|
||||
"@joplin/renderer": "~2.6",
|
||||
"@joplin/lib": "~2.8",
|
||||
"@joplin/renderer": "~2.8",
|
||||
"@react-native-community/clipboard": "^1.5.0",
|
||||
"@react-native-community/datetimepicker": "^3.0.3",
|
||||
"@react-native-community/geolocation": "^2.0.2",
|
||||
|
@ -75,7 +75,7 @@
|
|||
"@codemirror/lang-markdown": "^0.18.4",
|
||||
"@codemirror/state": "^0.18.7",
|
||||
"@codemirror/view": "^0.18.19",
|
||||
"@joplin/tools": "~2.6",
|
||||
"@joplin/tools": "~2.8",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@types/node": "^14.14.6",
|
||||
|
|
|
@ -36,6 +36,50 @@ function shimInit() {
|
|||
return temp;
|
||||
};
|
||||
|
||||
// This function can be used to debug "Network Request Failed" errors. It
|
||||
// uses the native XMLHttpRequest which is more likely to get the proper
|
||||
// response and error message.
|
||||
|
||||
shim.debugFetch = async (url, options = null) => {
|
||||
options = {
|
||||
method: 'GET',
|
||||
headers: {},
|
||||
...options,
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(options.method, url, true);
|
||||
|
||||
for (const [key, value] of Object.entries(options.headers)) {
|
||||
xhr.setRequestHeader(key, value);
|
||||
}
|
||||
|
||||
xhr.onload = function() {
|
||||
console.info('======================== XHR RESPONSE');
|
||||
console.info(xhr.getAllResponseHeaders());
|
||||
console.info('-------------------------------------');
|
||||
// console.info(xhr.responseText);
|
||||
console.info('======================== XHR RESPONSE');
|
||||
|
||||
resolve(xhr.responseText);
|
||||
};
|
||||
|
||||
xhr.onerror = function() {
|
||||
console.info('======================== XHR ERROR');
|
||||
console.info(xhr.getAllResponseHeaders());
|
||||
console.info('-------------------------------------');
|
||||
console.info(xhr.responseText);
|
||||
console.info('======================== XHR ERROR');
|
||||
|
||||
reject(new Error(xhr.responseText));
|
||||
};
|
||||
|
||||
// TODO: Send POST data here if needed
|
||||
xhr.send();
|
||||
});
|
||||
};
|
||||
|
||||
shim.fetch = async function(url, options = null) {
|
||||
// The native fetch() throws an uncatchable error that crashes the
|
||||
// app if calling it with an invalid URL such as '//.resource' or
|
||||
|
|
|
@ -738,7 +738,7 @@ export default class BaseApplication {
|
|||
Setting.setConstant('tempDir', tempDir);
|
||||
Setting.setConstant('pluginDataDir', `${profileDir}/plugin-data`);
|
||||
Setting.setConstant('cacheDir', cacheDir);
|
||||
Setting.setConstant('pluginDir', `${profileDir}/plugins`);
|
||||
Setting.setConstant('pluginDir', `${rootProfileDir}/plugins`);
|
||||
|
||||
SyncTargetRegistry.addClass(SyncTargetNone);
|
||||
SyncTargetRegistry.addClass(SyncTargetFilesystem);
|
||||
|
@ -811,8 +811,12 @@ export default class BaseApplication {
|
|||
appLogger.info(`Client ID: ${Setting.value('clientId')}`);
|
||||
|
||||
if (Setting.value('firstStart')) {
|
||||
const locale = shim.detectAndSetLocale(Setting);
|
||||
reg.logger().info(`First start: detected locale as ${locale}`);
|
||||
// If it's a sub-profile, the locale must come from the root
|
||||
// profile.
|
||||
if (!Setting.value('isSubProfile')) {
|
||||
const locale = shim.detectAndSetLocale(Setting);
|
||||
reg.logger().info(`First start: detected locale as ${locale}`);
|
||||
}
|
||||
|
||||
Setting.skipDefaultMigrations();
|
||||
|
||||
|
@ -825,9 +829,10 @@ export default class BaseApplication {
|
|||
Setting.setValue('firstStart', 0);
|
||||
} else {
|
||||
Setting.applyDefaultMigrations();
|
||||
setLocale(Setting.value('locale'));
|
||||
}
|
||||
|
||||
setLocale(Setting.value('locale'));
|
||||
|
||||
if (Setting.value('env') === Env.Dev) {
|
||||
// Setting.setValue('sync.10.path', 'https://api.joplincloud.com');
|
||||
// Setting.setValue('sync.10.userContentPath', 'https://joplinusercontent.com');
|
||||
|
|
|
@ -124,8 +124,15 @@ class FileApiDriverDropbox {
|
|||
if (!options.responseFormat) options.responseFormat = 'text';
|
||||
|
||||
try {
|
||||
// IMPORTANT:
|
||||
//
|
||||
// We cannot use POST here, because iOS (as of version 14?) doesn't
|
||||
// support POST requests with an empty body:
|
||||
//
|
||||
// https://www.dropboxforum.com/t5/Dropbox-API-Support-Feedback/Error-1017-quot-cannot-parse-response-quot/td-p/589595
|
||||
|
||||
const response = await this.api().exec(
|
||||
'POST',
|
||||
'GET',
|
||||
'files/download',
|
||||
null,
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ import Tag from './Tag';
|
|||
import ItemChange from './ItemChange';
|
||||
import Resource from './Resource';
|
||||
import { ResourceEntity } from '../services/database/types';
|
||||
import { toForwardSlashes } from '../path-utils';
|
||||
const ArrayUtils = require('../ArrayUtils.js');
|
||||
|
||||
async function allItems() {
|
||||
|
@ -259,7 +260,8 @@ describe('models/Note', function() {
|
|||
const t1 = r1.updated_time;
|
||||
const t2 = r2.updated_time;
|
||||
|
||||
const resourceDirE = markdownUtils.escapeLinkUrl(resourceDir);
|
||||
const resourceDirE = markdownUtils.escapeLinkUrl(toForwardSlashes(resourceDir));
|
||||
const fileProtocol = `file://${process.platform === 'win32' ? '/' : ''}`;
|
||||
|
||||
const testCases = [
|
||||
[
|
||||
|
@ -285,17 +287,17 @@ describe('models/Note', function() {
|
|||
[
|
||||
true,
|
||||
`![](:/${r1.id})`,
|
||||
`![](file://${resourceDirE}/${r1.id}.jpg?t=${t1})`,
|
||||
`![](${fileProtocol}${resourceDirE}/${r1.id}.jpg?t=${t1})`,
|
||||
],
|
||||
[
|
||||
true,
|
||||
`![](:/${r1.id}) ![](:/${r1.id}) ![](:/${r2.id})`,
|
||||
`![](file://${resourceDirE}/${r1.id}.jpg?t=${t1}) ![](file://${resourceDirE}/${r1.id}.jpg?t=${t1}) ![](file://${resourceDirE}/${r2.id}.jpg?t=${t2})`,
|
||||
`![](${fileProtocol}${resourceDirE}/${r1.id}.jpg?t=${t1}) ![](${fileProtocol}${resourceDirE}/${r1.id}.jpg?t=${t1}) ![](${fileProtocol}${resourceDirE}/${r2.id}.jpg?t=${t2})`,
|
||||
],
|
||||
[
|
||||
true,
|
||||
`![](:/${r3.id})`,
|
||||
`![](file://${resourceDirE}/${r3.id}.pdf)`,
|
||||
`![](${fileProtocol}${resourceDirE}/${r3.id}.pdf)`,
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import Tag from './Tag';
|
|||
const { sprintf } = require('sprintf-js');
|
||||
import Resource from './Resource';
|
||||
import syncDebugLog from '../services/synchronizer/syncDebugLog';
|
||||
import { toFileProtocolPath, toForwardSlashes } from '../path-utils';
|
||||
const { pregQuote, substrWithEllipsis } = require('../string-utils.js');
|
||||
const { _ } = require('../locale');
|
||||
const ArrayUtils = require('../ArrayUtils.js');
|
||||
|
@ -167,7 +168,7 @@ export default class Note extends BaseItem {
|
|||
// change, the preview is updated inside the note. This is not
|
||||
// needed for other resources since they are simple links.
|
||||
const timestampParam = isImage ? `?t=${resource.updated_time}` : '';
|
||||
const resourcePath = options.useAbsolutePaths ? `file://${Resource.fullPath(resource)}${timestampParam}` : Resource.relativePath(resource);
|
||||
const resourcePath = options.useAbsolutePaths ? toFileProtocolPath(Resource.fullPath(resource)) + timestampParam : Resource.relativePath(resource);
|
||||
body = body.replace(new RegExp(`:/${id}`, 'gi'), markdownUtils.escapeLinkUrl(resourcePath));
|
||||
}
|
||||
|
||||
|
@ -181,10 +182,14 @@ export default class Note extends BaseItem {
|
|||
useAbsolutePaths: false,
|
||||
}, options);
|
||||
|
||||
const resourceDir = toForwardSlashes(Setting.value('resourceDir'));
|
||||
|
||||
let pathsToTry = [];
|
||||
if (options.useAbsolutePaths) {
|
||||
pathsToTry.push(`file://${Setting.value('resourceDir')}`);
|
||||
pathsToTry.push(`file://${shim.pathRelativeToCwd(Setting.value('resourceDir'))}`);
|
||||
pathsToTry.push(`file://${resourceDir}`);
|
||||
pathsToTry.push(`file:///${resourceDir}`);
|
||||
pathsToTry.push(`file://${shim.pathRelativeToCwd(resourceDir)}`);
|
||||
pathsToTry.push(`file:///${shim.pathRelativeToCwd(resourceDir)}`);
|
||||
} else {
|
||||
pathsToTry.push(Resource.baseRelativeDirectoryPath());
|
||||
}
|
||||
|
|
|
@ -15,8 +15,9 @@ const switchToSubProfileSettings = async () => {
|
|||
const rootProfileDir = Setting.value('profileDir');
|
||||
const profileConfigPath = `${rootProfileDir}/profiles.json`;
|
||||
let profileConfig = defaultProfileConfig();
|
||||
profileConfig = createNewProfile(profileConfig, 'Sub-profile');
|
||||
profileConfig.currentProfile = 1;
|
||||
const { newConfig, newProfile } = createNewProfile(profileConfig, 'Sub-profile');
|
||||
profileConfig = newConfig;
|
||||
profileConfig.currentProfileId = newProfile.id;
|
||||
await saveProfileConfig(profileConfigPath, profileConfig);
|
||||
const { profileDir } = await initProfile(rootProfileDir);
|
||||
await mkdirp(profileDir);
|
||||
|
@ -272,7 +273,7 @@ describe('models/Setting', function() {
|
|||
expect(Setting.value('style.editor.contentMaxWidth')).toBe(600); // Changed
|
||||
}));
|
||||
|
||||
it('should load sub-profile settings', async () => {
|
||||
it('should load sub-profile settings - 1', async () => {
|
||||
await Setting.reset();
|
||||
|
||||
Setting.setValue('locale', 'fr_FR'); // Global setting
|
||||
|
@ -293,7 +294,7 @@ describe('models/Setting', function() {
|
|||
expect((await Setting.loadOne('sync.target')).value).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should save sub-profile settings', async () => {
|
||||
it('should save sub-profile settings - 2', async () => {
|
||||
await Setting.reset();
|
||||
Setting.setValue('locale', 'fr_FR'); // Global setting
|
||||
Setting.setValue('theme', Setting.THEME_DARK); // Global setting
|
||||
|
|
|
@ -243,7 +243,7 @@ class Setting extends BaseModel {
|
|||
public static SYNC_UPGRADE_STATE_SHOULD_DO = 1; // Should be upgraded, but waiting for user to confirm
|
||||
public static SYNC_UPGRADE_STATE_MUST_DO = 2; // Must be upgraded - on next restart, the upgrade will start
|
||||
|
||||
public static custom_css_files = {
|
||||
public static customCssFilenames = {
|
||||
JOPLIN_APP: 'userchrome.css',
|
||||
RENDERED_MARKDOWN: 'userstyle.css',
|
||||
};
|
||||
|
@ -1177,7 +1177,7 @@ class Setting extends BaseModel {
|
|||
|
||||
'style.editor.contentMaxWidth': { value: 0, type: SettingItemType.Int, public: true, storage: SettingStorage.File, isGlobal: true,appTypes: [AppType.Desktop], section: 'appearance', label: () => _('Editor maximum width'), description: () => _('Set it to 0 to make it take the complete available space. Recommended width is 600.') },
|
||||
|
||||
'ui.layout': { value: {}, type: SettingItemType.Object, storage: SettingStorage.File, public: false, appTypes: [AppType.Desktop] },
|
||||
'ui.layout': { value: {}, type: SettingItemType.Object, storage: SettingStorage.File, isGlobal: true, public: false, appTypes: [AppType.Desktop] },
|
||||
|
||||
// TODO: Is there a better way to do this? The goal here is to simply have
|
||||
// a way to display a link to the customizable stylesheets, not for it to
|
||||
|
@ -1187,12 +1187,10 @@ class Setting extends BaseModel {
|
|||
'style.customCss.renderedMarkdown': {
|
||||
value: null,
|
||||
onClick: () => {
|
||||
const dir = Setting.value('profileDir');
|
||||
const filename = Setting.custom_css_files.RENDERED_MARKDOWN;
|
||||
const filepath = `${dir}/${filename}`;
|
||||
const defaultContents = '/* For styling the rendered Markdown */';
|
||||
|
||||
shim.openOrCreateFile(filepath, defaultContents);
|
||||
shim.openOrCreateFile(
|
||||
this.customCssFilePath(Setting.customCssFilenames.RENDERED_MARKDOWN),
|
||||
'/* For styling the rendered Markdown */'
|
||||
);
|
||||
},
|
||||
type: SettingItemType.Button,
|
||||
public: true,
|
||||
|
@ -1206,12 +1204,10 @@ class Setting extends BaseModel {
|
|||
'style.customCss.joplinApp': {
|
||||
value: null,
|
||||
onClick: () => {
|
||||
const dir = Setting.value('profileDir');
|
||||
const filename = Setting.custom_css_files.JOPLIN_APP;
|
||||
const filepath = `${dir}/${filename}`;
|
||||
const defaultContents = `/* For styling the entire Joplin app (except the rendered Markdown, which is defined in \`${Setting.custom_css_files.RENDERED_MARKDOWN}\`) */`;
|
||||
|
||||
shim.openOrCreateFile(filepath, defaultContents);
|
||||
shim.openOrCreateFile(
|
||||
this.customCssFilePath(Setting.customCssFilenames.JOPLIN_APP),
|
||||
`/* For styling the entire Joplin app (except the rendered Markdown, which is defined in \`${Setting.customCssFilenames.RENDERED_MARKDOWN}\`) */`
|
||||
);
|
||||
},
|
||||
type: SettingItemType.Button,
|
||||
public: true,
|
||||
|
@ -1527,6 +1523,10 @@ class Setting extends BaseModel {
|
|||
}
|
||||
}
|
||||
|
||||
public static customCssFilePath(filename: string): string {
|
||||
return `${this.value('rootProfileDir')}/${filename}`;
|
||||
}
|
||||
|
||||
public static skipDefaultMigrations() {
|
||||
logger.info('Skipping all default migrations...');
|
||||
|
||||
|
|
|
@ -146,6 +146,10 @@ export function toSystemSlashes(path: string, os: string = null) {
|
|||
return path.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
export function toForwardSlashes(path: string) {
|
||||
return toSystemSlashes(path, 'linux');
|
||||
}
|
||||
|
||||
export function rtrimSlashes(path: string) {
|
||||
return path.replace(/[\/\\]+$/, '');
|
||||
}
|
||||
|
|
|
@ -199,6 +199,18 @@ export default class CommandService extends BaseService {
|
|||
command.runtime = runtime;
|
||||
}
|
||||
|
||||
public registerCommands(commands: any[]) {
|
||||
for (const command of commands) {
|
||||
CommandService.instance().registerRuntime(command.declaration.name, command.runtime());
|
||||
}
|
||||
}
|
||||
|
||||
public unregisterCommands(commands: any[]) {
|
||||
for (const command of commands) {
|
||||
CommandService.instance().unregisterRuntime(command.declaration.name);
|
||||
}
|
||||
}
|
||||
|
||||
public componentRegisterCommands(component: any, commands: any[]) {
|
||||
for (const command of commands) {
|
||||
CommandService.instance().registerRuntime(command.declaration.name, command.runtime(component));
|
||||
|
|
|
@ -4,7 +4,21 @@ import Global from './api/Global';
|
|||
|
||||
export default abstract class BasePluginRunner extends BaseService {
|
||||
|
||||
async run(plugin: Plugin, sandbox: Global): Promise<void> {
|
||||
// A dictionary with the plugin ID as key. Then each entry has a list
|
||||
// of timestamp/call counts.
|
||||
//
|
||||
// 'org.joplinapp.plugins.ExamplePlugin': {
|
||||
// 1650375620: 5, // 5 calls at second 1650375620
|
||||
// 1650375621: 19, // 19 calls at second 1650375621
|
||||
// 1650375623: 12,
|
||||
// },
|
||||
// 'org.joplinapp.plugins.AnotherOne': {
|
||||
// 1650375620: 1,
|
||||
// 1650375623: 4,
|
||||
// };
|
||||
private callStats_: Record<string, Record<number, number>> = {};
|
||||
|
||||
public async run(plugin: Plugin, sandbox: Global): Promise<void> {
|
||||
throw new Error(`Not implemented: ${plugin} / ${sandbox}`);
|
||||
}
|
||||
|
||||
|
@ -12,4 +26,26 @@ export default abstract class BasePluginRunner extends BaseService {
|
|||
throw new Error('Not implemented: waitForSandboxCalls');
|
||||
}
|
||||
|
||||
protected recordCallStat(pluginId: string) {
|
||||
const timeSeconds = Math.floor(Date.now() / 1000);
|
||||
if (!this.callStats_[pluginId]) this.callStats_[pluginId] = {};
|
||||
if (!this.callStats_[pluginId][timeSeconds]) this.callStats_[pluginId][timeSeconds] = 0;
|
||||
this.callStats_[pluginId][timeSeconds]++;
|
||||
}
|
||||
|
||||
// Duration in seconds
|
||||
public callStatsSummary(pluginId: string, duration: number): number[] {
|
||||
const output: number[] = [];
|
||||
|
||||
const startTime = Math.floor(Date.now() / 1000 - duration);
|
||||
const endTime = startTime + duration;
|
||||
|
||||
for (let t = startTime; t <= endTime; t++) {
|
||||
const callCount = this.callStats_[pluginId][t];
|
||||
output.push(callCount ? callCount : 0);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -315,6 +315,10 @@ export default class PluginService extends BaseService {
|
|||
return settings[pluginId].enabled !== false;
|
||||
}
|
||||
|
||||
public callStatsSummary(pluginId: string, duration: number) {
|
||||
return this.runner_.callStatsSummary(pluginId, duration);
|
||||
}
|
||||
|
||||
public async loadAndRunPlugins(pluginDirOrPaths: string | string[], settings: PluginSettings, devMode: boolean = false) {
|
||||
let pluginPaths = [];
|
||||
|
||||
|
|
|
@ -33,14 +33,24 @@ export interface PluginStates {
|
|||
[key: string]: PluginState;
|
||||
}
|
||||
|
||||
export interface PluginHtmlContent {
|
||||
[viewId: string]: string;
|
||||
}
|
||||
|
||||
export interface PluginHtmlContents {
|
||||
[pluginId: string]: PluginHtmlContent;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
plugins: PluginStates;
|
||||
pluginHtmlContents: PluginHtmlContents;
|
||||
}
|
||||
|
||||
export const stateRootKey = 'pluginService';
|
||||
|
||||
export const defaultState: State = {
|
||||
plugins: {},
|
||||
pluginHtmlContents: {},
|
||||
};
|
||||
|
||||
export const utils = {
|
||||
|
@ -139,7 +149,12 @@ const reducer = (draftRoot: Draft<any>, action: any) => {
|
|||
|
||||
case 'PLUGIN_VIEW_PROP_SET':
|
||||
|
||||
(draft.plugins[action.pluginId].views[action.id] as any)[action.name] = action.value;
|
||||
if (action.name !== 'html') {
|
||||
(draft.plugins[action.pluginId].views[action.id] as any)[action.name] = action.value;
|
||||
} else {
|
||||
draft.pluginHtmlContents[action.pluginId] ??= {};
|
||||
draft.pluginHtmlContents[action.pluginId][action.id] = action.value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PLUGIN_VIEW_PROP_PUSH':
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { writeFile } from 'fs-extra';
|
||||
import { createNewProfile, getProfileFullPath, loadProfileConfig, saveProfileConfig } from '.';
|
||||
import { createNewProfile, getProfileFullPath, loadProfileConfig, migrateProfileConfig, saveProfileConfig } from '.';
|
||||
import { tempFilePath } from '../../testing/test-utils';
|
||||
import { defaultProfile, defaultProfileConfig, ProfileConfig } from './types';
|
||||
import { CurrentProfileVersion, defaultProfile, defaultProfileConfig, DefaultProfileId, Profile, ProfileConfig } from './types';
|
||||
|
||||
describe('profileConfig/index', () => {
|
||||
|
||||
|
@ -17,7 +17,7 @@ describe('profileConfig/index', () => {
|
|||
profiles: [
|
||||
{
|
||||
name: 'Testing',
|
||||
path: '.',
|
||||
id: DefaultProfileId,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -26,12 +26,12 @@ describe('profileConfig/index', () => {
|
|||
const loadedConfig = await loadProfileConfig(filePath);
|
||||
|
||||
const expected: ProfileConfig = {
|
||||
version: 1,
|
||||
currentProfile: 0,
|
||||
version: CurrentProfileVersion,
|
||||
currentProfileId: DefaultProfileId,
|
||||
profiles: [
|
||||
{
|
||||
name: 'Testing',
|
||||
path: '.',
|
||||
id: DefaultProfileId,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -50,36 +50,71 @@ describe('profileConfig/index', () => {
|
|||
});
|
||||
|
||||
it('should get a profile full path', async () => {
|
||||
const profile1 = {
|
||||
const profile1: Profile = {
|
||||
...defaultProfile(),
|
||||
path: 'profile-abcd',
|
||||
id: 'abcd',
|
||||
};
|
||||
|
||||
const profile2 = {
|
||||
const profile2: Profile = {
|
||||
...defaultProfile(),
|
||||
path: '.',
|
||||
};
|
||||
|
||||
const profile3 = {
|
||||
...defaultProfile(),
|
||||
path: 'profiles/pro/',
|
||||
id: DefaultProfileId,
|
||||
};
|
||||
|
||||
expect(getProfileFullPath(profile1, '/test/root')).toBe('/test/root/profile-abcd');
|
||||
expect(getProfileFullPath(profile2, '/test/root')).toBe('/test/root');
|
||||
expect(getProfileFullPath(profile3, '/test/root')).toBe('/test/root/profiles/pro');
|
||||
});
|
||||
|
||||
it('should create a new profile', async () => {
|
||||
let config = defaultProfileConfig();
|
||||
config = createNewProfile(config, 'new profile 1');
|
||||
config = createNewProfile(config, 'new profile 2');
|
||||
const r1 = createNewProfile(config, 'new profile 1');
|
||||
const r2 = createNewProfile(r1.newConfig, 'new profile 2');
|
||||
config = r2.newConfig;
|
||||
|
||||
expect(config.profiles.length).toBe(3);
|
||||
expect(config.profiles[1].name).toBe('new profile 1');
|
||||
expect(config.profiles[2].name).toBe('new profile 2');
|
||||
|
||||
expect(config.profiles[1].path).not.toBe(config.profiles[2].path);
|
||||
expect(config.profiles[1].id).not.toBe(config.profiles[2].id);
|
||||
});
|
||||
|
||||
it('should migrate profile config - version 1 to 2', async () => {
|
||||
const migrated1 = migrateProfileConfig({
|
||||
'version': 1,
|
||||
'currentProfile': 2,
|
||||
'profiles': [
|
||||
{
|
||||
'name': 'Default',
|
||||
'path': '.',
|
||||
},
|
||||
{
|
||||
'name': 'sub1',
|
||||
'path': 'profile-sjn25kuh',
|
||||
},
|
||||
{
|
||||
'name': 'sub2',
|
||||
'path': 'profile-yufzkns3',
|
||||
},
|
||||
],
|
||||
}, 2);
|
||||
|
||||
expect(migrated1).toEqual({
|
||||
'version': 2,
|
||||
'currentProfileId': 'yufzkns3',
|
||||
'profiles': [
|
||||
{
|
||||
'name': 'Default',
|
||||
'id': 'default',
|
||||
},
|
||||
{
|
||||
'name': 'sub1',
|
||||
'id': 'sjn25kuh',
|
||||
},
|
||||
{
|
||||
'name': 'sub2',
|
||||
'id': 'yufzkns3',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,8 +1,34 @@
|
|||
import { rtrimSlashes, trimSlashes } from '../../path-utils';
|
||||
import { rtrimSlashes } from '../../path-utils';
|
||||
import shim from '../../shim';
|
||||
import { defaultProfile, defaultProfileConfig, Profile, ProfileConfig } from './types';
|
||||
import { CurrentProfileVersion, defaultProfile, defaultProfileConfig, DefaultProfileId, Profile, ProfileConfig } from './types';
|
||||
import { customAlphabet } from 'nanoid/non-secure';
|
||||
|
||||
export const migrateProfileConfig = (profileConfig: any, toVersion: number): ProfileConfig => {
|
||||
let version = 2;
|
||||
|
||||
while (profileConfig.version < toVersion) {
|
||||
if (profileConfig.version === 1) {
|
||||
for (const profile of profileConfig.profiles) {
|
||||
if (profile.path === '.') {
|
||||
profile.id = DefaultProfileId;
|
||||
} else {
|
||||
profile.id = profile.path.split('-').pop();
|
||||
}
|
||||
delete profile.path;
|
||||
}
|
||||
|
||||
const currentProfile = profileConfig.profiles[profileConfig.currentProfile];
|
||||
profileConfig.currentProfileId = currentProfile.id;
|
||||
delete profileConfig.currentProfile;
|
||||
}
|
||||
|
||||
profileConfig.version = version;
|
||||
version++;
|
||||
}
|
||||
|
||||
return profileConfig;
|
||||
};
|
||||
|
||||
export const loadProfileConfig = async (profileConfigPath: string): Promise<ProfileConfig> => {
|
||||
if (!(await shim.fsDriver().exists(profileConfigPath))) {
|
||||
return defaultProfileConfig();
|
||||
|
@ -10,9 +36,11 @@ export const loadProfileConfig = async (profileConfigPath: string): Promise<Prof
|
|||
|
||||
try {
|
||||
const configContent = await shim.fsDriver().readFile(profileConfigPath, 'utf8');
|
||||
const parsed = JSON.parse(configContent) as ProfileConfig;
|
||||
let parsed = JSON.parse(configContent) as ProfileConfig;
|
||||
if (!parsed.profiles || !parsed.profiles.length) throw new Error(`Profile config should contain at least one profile: ${profileConfigPath}`);
|
||||
|
||||
parsed = migrateProfileConfig(parsed, CurrentProfileVersion);
|
||||
|
||||
const output: ProfileConfig = {
|
||||
...defaultProfileConfig(),
|
||||
...parsed,
|
||||
|
@ -25,7 +53,7 @@ export const loadProfileConfig = async (profileConfigPath: string): Promise<Prof
|
|||
};
|
||||
}
|
||||
|
||||
if (output.currentProfile < 0 || output.currentProfile >= output.profiles.length) throw new Error(`Profile index out of range: ${output.currentProfile}`);
|
||||
if (!output.profiles.find(p => p.id === output.currentProfileId)) throw new Error(`Current profile ID is invalid: ${output.currentProfileId}`);
|
||||
return output;
|
||||
} catch (error) {
|
||||
error.message = `Could not parse profile configuration: ${profileConfigPath}: ${error.message}`;
|
||||
|
@ -38,27 +66,39 @@ export const saveProfileConfig = async (profileConfigPath: string, config: Profi
|
|||
};
|
||||
|
||||
export const getCurrentProfile = (config: ProfileConfig): Profile => {
|
||||
return { ...config.profiles[config.currentProfile] };
|
||||
return config.profiles.find(p => p.id === config.currentProfileId);
|
||||
};
|
||||
|
||||
export const getProfileFullPath = (profile: Profile, rootProfilePath: string): string => {
|
||||
let p = trimSlashes(profile.path);
|
||||
if (p === '.') p = '';
|
||||
return rtrimSlashes(`${rtrimSlashes(rootProfilePath)}/${p}`);
|
||||
const folderName = profile.id === DefaultProfileId ? '' : `/profile-${profile.id}`;
|
||||
return `${rtrimSlashes(rootProfilePath)}${folderName}`;
|
||||
};
|
||||
|
||||
export const isSubProfile = (profile: Profile): boolean => {
|
||||
return profile.id !== DefaultProfileId;
|
||||
};
|
||||
|
||||
const profileIdGenerator = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8);
|
||||
|
||||
export const createNewProfile = (config: ProfileConfig, profileName: string) => {
|
||||
const newConfig = {
|
||||
const newConfig: ProfileConfig = {
|
||||
...config,
|
||||
profiles: config.profiles.slice(),
|
||||
};
|
||||
|
||||
newConfig.profiles.push({
|
||||
const newProfile: Profile = {
|
||||
name: profileName,
|
||||
path: `profile-${profileIdGenerator()}`,
|
||||
});
|
||||
id: profileIdGenerator(),
|
||||
};
|
||||
|
||||
return newConfig;
|
||||
newConfig.profiles.push(newProfile);
|
||||
|
||||
return {
|
||||
newConfig: newConfig,
|
||||
newProfile: newProfile,
|
||||
};
|
||||
};
|
||||
|
||||
export const profileIdByIndex = (config: ProfileConfig, index: number): string => {
|
||||
return config.profiles[index].id;
|
||||
};
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { getCurrentProfile, getProfileFullPath, loadProfileConfig } from '.';
|
||||
import { getCurrentProfile, getProfileFullPath, isSubProfile, loadProfileConfig } from '.';
|
||||
import Setting from '../../models/Setting';
|
||||
|
||||
export default async (rootProfileDir: string) => {
|
||||
const profileConfig = await loadProfileConfig(`${rootProfileDir}/profiles.json`);
|
||||
const profileDir = getProfileFullPath(getCurrentProfile(profileConfig), rootProfileDir);
|
||||
const isSubProfile = profileConfig.currentProfile !== 0;
|
||||
Setting.setConstant('isSubProfile', isSubProfile);
|
||||
const isSub = isSubProfile(getCurrentProfile(profileConfig));
|
||||
Setting.setConstant('isSubProfile', isSub);
|
||||
Setting.setConstant('rootProfileDir', rootProfileDir);
|
||||
Setting.setConstant('profileDir', profileDir);
|
||||
return {
|
||||
profileConfig,
|
||||
profileDir,
|
||||
isSubProfile,
|
||||
isSubProfile: isSub,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
export const DefaultProfileId = 'default';
|
||||
export const CurrentProfileVersion = 2;
|
||||
|
||||
export interface Profile {
|
||||
name: string;
|
||||
path: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProfileConfig {
|
||||
version: number;
|
||||
currentProfile: number;
|
||||
currentProfileId: string;
|
||||
profiles: Profile[];
|
||||
}
|
||||
|
||||
export const defaultProfile = (): Profile => {
|
||||
return {
|
||||
name: 'Default',
|
||||
path: '.',
|
||||
id: DefaultProfileId,
|
||||
};
|
||||
};
|
||||
|
||||
export const defaultProfileConfig = (): ProfileConfig => {
|
||||
return {
|
||||
version: 1,
|
||||
currentProfile: 0,
|
||||
version: CurrentProfileVersion,
|
||||
currentProfileId: DefaultProfileId,
|
||||
profiles: [defaultProfile()],
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,7 +7,9 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: Joplin-CLI 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: MrKanister <pthrp_bnsrv@aleeas.com>\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: MrKanister <pueblos_spatulas@aleeas.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -402,7 +404,6 @@ msgid "Auto"
|
|||
msgstr "Automatisch"
|
||||
|
||||
#: packages/server/src/services/TaskService.ts:39
|
||||
#, fuzzy
|
||||
msgid "Auto-add disabled accounts for deletion"
|
||||
msgstr "Automatisches Hinzufügen deaktivierter Accounts zur Löschliste"
|
||||
|
||||
|
@ -1867,7 +1868,7 @@ msgstr "TLS-Zertifikatfehler ignorieren"
|
|||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:102
|
||||
msgid "Images"
|
||||
msgstr ""
|
||||
msgstr "Bilder"
|
||||
|
||||
#: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:170
|
||||
#: packages/app-desktop/gui/MenuBar.tsx:484
|
||||
|
@ -2745,9 +2746,8 @@ msgid "Or create an account."
|
|||
msgstr "Oder erstelle ein Konto."
|
||||
|
||||
#: packages/app-desktop/gui/MenuBar.tsx:352
|
||||
#, fuzzy
|
||||
msgid "Other applications..."
|
||||
msgstr "Beendet die Anwendung."
|
||||
msgstr "Andere Anwendungen..."
|
||||
|
||||
#: packages/app-cli/app/command-import.js:27
|
||||
msgid "Output format: %s"
|
||||
|
@ -3254,14 +3254,12 @@ msgid "Select all"
|
|||
msgstr "Alles auswählen"
|
||||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:140
|
||||
#, fuzzy
|
||||
msgid "Select emoji..."
|
||||
msgstr "Datum auswählen"
|
||||
msgstr "Emoji auswählen..."
|
||||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:144
|
||||
#, fuzzy
|
||||
msgid "Select file..."
|
||||
msgstr "Alles auswählen"
|
||||
msgstr "Datei auswählen..."
|
||||
|
||||
#: packages/app-cli/app/command-server.js:38
|
||||
msgid "Server is already running on port %d"
|
||||
|
|
|
@ -24,6 +24,8 @@ msgstr ""
|
|||
"X-Generator: Poedit 2.4.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.tsx:565
|
||||
msgid "- Camera: to allow taking a picture and attaching it to a note."
|
||||
|
@ -275,11 +277,11 @@ msgstr "Agregar al diccionario"
|
|||
#: packages/server/src/services/MustacheService.ts:183
|
||||
#: packages/server/src/services/MustacheService.ts:307
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
msgstr "Administrador"
|
||||
|
||||
#: packages/server/src/routes/admin/dashboard.ts:10
|
||||
msgid "Admin dashboard"
|
||||
msgstr ""
|
||||
msgstr "Tablero de Mandos de Administrador"
|
||||
|
||||
#: packages/app-desktop/gui/ClipperConfigScreen.min.js:189
|
||||
#: packages/app-desktop/gui/ClipperConfigScreen.tsx:147
|
||||
|
@ -406,16 +408,15 @@ msgstr "Automático"
|
|||
|
||||
#: packages/server/src/services/TaskService.ts:39
|
||||
msgid "Auto-add disabled accounts for deletion"
|
||||
msgstr ""
|
||||
msgstr "Añadir automáticamente las cuentas deshabilitadas para su eliminación"
|
||||
|
||||
#: packages/lib/models/Setting.ts:855
|
||||
msgid "Auto-pair braces, parenthesis, quotations, etc."
|
||||
msgstr "Autoemparejar llaves, paréntesis, comillas, etc."
|
||||
|
||||
#: packages/lib/models/Setting.ts:1195
|
||||
#, fuzzy
|
||||
msgid "Automatically check for updates"
|
||||
msgstr "Comprobar actualizaciones..."
|
||||
msgstr "Comprobar actualizaciones"
|
||||
|
||||
#: packages/lib/models/Setting.ts:772
|
||||
msgid "Automatically switch theme to match system theme"
|
||||
|
@ -725,7 +726,7 @@ msgstr "Completado: %s (%s)"
|
|||
|
||||
#: packages/server/src/services/TaskService.ts:37
|
||||
msgid "Compress old changes"
|
||||
msgstr ""
|
||||
msgstr "Comprimir cambios antiguos"
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.tsx:637
|
||||
#: packages/app-mobile/components/side-menu-content.js:332
|
||||
|
@ -787,9 +788,8 @@ msgid "Copy external link"
|
|||
msgstr "Copiar enlace externo"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:134
|
||||
#, fuzzy
|
||||
msgid "Copy image"
|
||||
msgstr "Copiar token"
|
||||
msgstr "Copiar imagen"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:172
|
||||
msgid "Copy Link Address"
|
||||
|
@ -882,14 +882,12 @@ msgid "Create a notebook"
|
|||
msgstr "Crea una libreta"
|
||||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:161
|
||||
#, fuzzy
|
||||
msgid "Create notebook"
|
||||
msgstr "Crea una libreta"
|
||||
msgstr "Crea libreta"
|
||||
|
||||
#: packages/server/src/routes/admin/users.ts:171
|
||||
#, fuzzy
|
||||
msgid "Create user"
|
||||
msgstr "Creado: %s"
|
||||
msgstr "Crear usuario"
|
||||
|
||||
#: packages/app-desktop/gui/NotePropertiesDialog.min.js:29
|
||||
msgid "Created"
|
||||
|
@ -981,7 +979,7 @@ msgstr "Oscuro"
|
|||
|
||||
#: packages/server/src/services/MustacheService.ts:136
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
msgstr "Tablero de Mandos"
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.tsx:625
|
||||
msgid "Database v%s"
|
||||
|
@ -1038,14 +1036,12 @@ msgid "Delete attachment \"%s\"?"
|
|||
msgstr "¿Borrar adjunto «%s»?"
|
||||
|
||||
#: packages/server/src/services/TaskService.ts:36
|
||||
#, fuzzy
|
||||
msgid "Delete expired sessions"
|
||||
msgstr "Activar expresiones matemáticas"
|
||||
msgstr "Borrar sesiones expiradas"
|
||||
|
||||
#: packages/server/src/services/TaskService.ts:31
|
||||
#, fuzzy
|
||||
msgid "Delete expired tokens"
|
||||
msgstr "¿Borrar estas %d notas?"
|
||||
msgstr "Borrar tokens expirados"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:88
|
||||
msgid "Delete line"
|
||||
|
@ -1366,12 +1362,12 @@ msgstr "Emacs"
|
|||
#: packages/app-desktop/gui/SyncWizard/Dialog.tsx:236
|
||||
#: packages/server/src/routes/admin/emails.ts:128
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
msgstr "Email"
|
||||
|
||||
#: packages/server/src/routes/admin/emails.ts:112
|
||||
#: packages/server/src/services/MustacheService.ts:152
|
||||
msgid "Emails"
|
||||
msgstr ""
|
||||
msgstr "Emails"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx:194
|
||||
msgid "emphasised text"
|
||||
|
@ -1859,7 +1855,7 @@ msgstr "Ignorar errores en certificados TLS"
|
|||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:102
|
||||
msgid "Images"
|
||||
msgstr ""
|
||||
msgstr "Imágenes"
|
||||
|
||||
#: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:170
|
||||
#: packages/app-desktop/gui/MenuBar.tsx:484
|
||||
|
@ -2270,7 +2266,7 @@ msgstr "Cerrar sesión"
|
|||
|
||||
#: packages/server/src/services/MustacheService.ts:179
|
||||
msgid "Logs"
|
||||
msgstr ""
|
||||
msgstr "Registros"
|
||||
|
||||
#: packages/app-desktop/gui/MenuBar.tsx:716
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.tsx:583
|
||||
|
@ -2729,9 +2725,8 @@ msgid "Or create an account."
|
|||
msgstr "Crea una nueva nota.O crea una cuenta."
|
||||
|
||||
#: packages/app-desktop/gui/MenuBar.tsx:352
|
||||
#, fuzzy
|
||||
msgid "Other applications..."
|
||||
msgstr "Sale de la aplicación."
|
||||
msgstr "Otras aplicaciones..."
|
||||
|
||||
#: packages/app-cli/app/command-import.js:27
|
||||
msgid "Output format: %s"
|
||||
|
@ -2935,19 +2930,19 @@ msgstr "Política de Privacidad"
|
|||
|
||||
#: packages/server/src/services/TaskService.ts:35
|
||||
msgid "Process failed payment subscriptions"
|
||||
msgstr ""
|
||||
msgstr "Procesar las suscripciones de pago fallidas"
|
||||
|
||||
#: packages/server/src/services/TaskService.ts:33
|
||||
msgid "Process oversized accounts"
|
||||
msgstr ""
|
||||
msgstr "Procesar cuentas de gran tamaño"
|
||||
|
||||
#: packages/server/src/services/TaskService.ts:38
|
||||
msgid "Process user deletions"
|
||||
msgstr ""
|
||||
msgstr "Procesar eliminaciones de usuarios"
|
||||
|
||||
#: packages/server/src/routes/admin/users.ts:168
|
||||
msgid "Profile"
|
||||
msgstr ""
|
||||
msgstr "Perfil"
|
||||
|
||||
#: packages/lib/versionInfo.ts:26
|
||||
msgid "Profile Version: %s"
|
||||
|
@ -3133,29 +3128,24 @@ msgid "S3"
|
|||
msgstr "S3"
|
||||
|
||||
#: packages/lib/models/Setting.ts:547
|
||||
#, fuzzy
|
||||
msgid "S3 access key"
|
||||
msgstr "Clave de acceso de AWS"
|
||||
msgstr "Clave de acceso de S3"
|
||||
|
||||
#: packages/lib/models/Setting.ts:507
|
||||
#, fuzzy
|
||||
msgid "S3 bucket"
|
||||
msgstr "AWS S3 bucket"
|
||||
msgstr "S3 bucket"
|
||||
|
||||
#: packages/lib/models/Setting.ts:536
|
||||
#, fuzzy
|
||||
msgid "S3 region"
|
||||
msgstr "Región de AWS"
|
||||
msgstr "Región de S3"
|
||||
|
||||
#: packages/lib/models/Setting.ts:558
|
||||
#, fuzzy
|
||||
msgid "S3 secret key"
|
||||
msgstr "Clave secreta de AWS"
|
||||
msgstr "Clave secreta de S3"
|
||||
|
||||
#: packages/lib/models/Setting.ts:522
|
||||
#, fuzzy
|
||||
msgid "S3 URL"
|
||||
msgstr "URL de AWS S3"
|
||||
msgstr "URL de S3"
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.tsx:579
|
||||
msgid ""
|
||||
|
@ -3232,14 +3222,12 @@ msgid "Select all"
|
|||
msgstr "Seleccionar todo"
|
||||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:140
|
||||
#, fuzzy
|
||||
msgid "Select emoji..."
|
||||
msgstr "Seleccione fecha"
|
||||
msgstr "Seleccionar emoji..."
|
||||
|
||||
#: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:144
|
||||
#, fuzzy
|
||||
msgid "Select file..."
|
||||
msgstr "Seleccionar todo"
|
||||
msgstr "Seleccionar archivo..."
|
||||
|
||||
#: packages/app-cli/app/command-server.js:38
|
||||
msgid "Server is already running on port %d"
|
||||
|
@ -4272,14 +4260,12 @@ msgstr "Actualizar"
|
|||
|
||||
#: packages/server/src/routes/admin/users.ts:171
|
||||
#: packages/server/src/routes/index/users.ts:89
|
||||
#, fuzzy
|
||||
msgid "Update profile"
|
||||
msgstr "Exportar perfil"
|
||||
msgstr "Actualizar perfil"
|
||||
|
||||
#: packages/server/src/services/TaskService.ts:32
|
||||
#, fuzzy
|
||||
msgid "Update total sizes"
|
||||
msgstr "Elementos locales actualizados: %d."
|
||||
msgstr "Actualizar tamaños totales"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:208
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:209
|
||||
|
@ -4388,7 +4374,7 @@ msgstr ""
|
|||
|
||||
#: packages/server/src/services/MustacheService.ts:144
|
||||
msgid "User deletions"
|
||||
msgstr ""
|
||||
msgstr "Eliminaciones de usuarios"
|
||||
|
||||
#: packages/server/src/routes/admin/users.ts:107
|
||||
#: packages/server/src/services/MustacheService.ts:140
|
||||
|
|
|
@ -7,8 +7,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: Joplin-CLI 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2022-03-26\n"
|
||||
"Last-Translator: mrkaato\n"
|
||||
"PO-Revision-Date: 2022-04-15\n"
|
||||
"Last-Translator: mrkaato0\n"
|
||||
"Language-Team: \n"
|
||||
"Language: fi_FI\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
|
|
@ -122,6 +122,7 @@ async function main() {
|
|||
|
||||
await updatePackageVersion(`${rootDir}/packages/app-cli/package.json`, majorMinorVersion, options);
|
||||
await updatePackageVersion(`${rootDir}/packages/app-desktop/package.json`, majorMinorVersion, options);
|
||||
await updatePackageVersion(`${rootDir}/packages/app-mobile/package.json`, majorMinorVersion, options);
|
||||
await updatePackageVersion(`${rootDir}/packages/generator-joplin/package.json`, majorMinorVersion, options);
|
||||
await updatePackageVersion(`${rootDir}/packages/htmlpack/package.json`, majorMinorVersion, options);
|
||||
await updatePackageVersion(`${rootDir}/packages/lib/package.json`, majorMinorVersion, options);
|
||||
|
|
|
@ -117,6 +117,11 @@
|
|||
"urlWebsite": "https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner",
|
||||
"title": "Hosting.de",
|
||||
"imageName": "HostingDe.png"
|
||||
},
|
||||
{
|
||||
"url": "https://residence-greece.com/",
|
||||
"title": "Greece Golden Visa",
|
||||
"imageName": "ResidenceGreece.jpg"
|
||||
}
|
||||
],
|
||||
"orgsOld": []
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
# Joplin changelog
|
||||
|
||||
## [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (Pre-release) - 2022-04-14T11:35:45Z
|
||||
|
||||
- New: Add support for multiple profiles ([#6385](https://github.com/laurent22/joplin/issues/6385)) ([#591](https://github.com/laurent22/joplin/issues/591))
|
||||
- New: Allow saving a Mermaid graph as a PNG or SVG via context menu ([#6126](https://github.com/laurent22/joplin/issues/6126)) ([#6100](https://github.com/laurent22/joplin/issues/6100) by [@asrient](https://github.com/asrient))
|
||||
- New: Support for Joplin Cloud recursive linked notes (9d9420a)
|
||||
- Improved: Don’t unpin app from taskbar on update ([#6271](https://github.com/laurent22/joplin/issues/6271)) ([#4155](https://github.com/laurent22/joplin/issues/4155) by Daniel Aleksandersen)
|
||||
- Improved: Make search engine filter keywords case insensitive ([#6267](https://github.com/laurent22/joplin/issues/6267)) ([#6266](https://github.com/laurent22/joplin/issues/6266) by [@JackGruber](https://github.com/JackGruber))
|
||||
- Improved: Plugins: Add support for "categories" manifest field ([#6109](https://github.com/laurent22/joplin/issues/6109)) ([#5867](https://github.com/laurent22/joplin/issues/5867) by Mayank Bondre)
|
||||
- Improved: Plugins: Allow updating a resource via the data API (74273cd)
|
||||
- Improved: Automatically start sync after setting the sync parameters (ff066ba)
|
||||
- Improved: Improve E2EE usability when accidentally creating multiple keys ([#6399](https://github.com/laurent22/joplin/issues/6399)) ([#6338](https://github.com/laurent22/joplin/issues/6338))
|
||||
- Improved: Improved handling of ENTER and ESCAPE keys in dialogs ([#6194](https://github.com/laurent22/joplin/issues/6194))
|
||||
- Fixed: Fixed color of published note on Light theme (21706fa)
|
||||
- Fixed: Fixed creation of empty notebooks when importing directory of files ([#6274](https://github.com/laurent22/joplin/issues/6274)) ([#6197](https://github.com/laurent22/joplin/issues/6197) by [@Retrove](https://github.com/Retrove))
|
||||
- Fixed: Fixes right click menu on Markdown Editor ([#6132](https://github.com/laurent22/joplin/issues/6132) by [@bishoy-magdy](https://github.com/bishoy-magdy))
|
||||
- Fixed: Scroll jumps when typing if heavy scripts or many large elements are used ([#6383](https://github.com/laurent22/joplin/issues/6383)) ([#6074](https://github.com/laurent22/joplin/issues/6074) by Kenichi Kobayashi)
|
||||
|
||||
## [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) - 2022-03-17T13:03:23Z
|
||||
|
||||
- Improved: Handle invalid revision patches ([#6209](https://github.com/laurent22/joplin/issues/6209))
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
# Joplin iOS app changelog
|
||||
|
||||
## [ios-v12.7.2](https://github.com/laurent22/joplin/releases/tag/ios-v12.7.2) - 2022-04-15T11:07:27Z
|
||||
|
||||
- Improved: Allow filtering tags in tag dialog (#6221 by [@shinglyu](https://github.com/shinglyu))
|
||||
- Improved: Handle invalid revision patches (#6209)
|
||||
- Improved: Improve error message when revision metadata cannot be decoded, to improve debugging (a325bf6)
|
||||
- Fixed: Ensure that note revision markup type is set correctly (#6261)
|
||||
- Fixed: IOS and Dropbox synchronisation not working on iOS 15 (#6375)
|
||||
- Fixed: The camera button remains clickable after taking a photo bug (#6222 by [@shinglyu](https://github.com/shinglyu))
|
||||
|
||||
## [ios-v12.7.1](https://github.com/laurent22/joplin/releases/tag/ios-v12.7.1) - 2022-02-14T14:10:49Z
|
||||
|
||||
- New: Add additional time format HH.mm (#6086 by [@vincentjocodes](https://github.com/vincentjocodes))
|
||||
|
|
275
readme/stats.md
275
readme/stats.md
|
@ -1,14 +1,14 @@
|
|||
---
|
||||
updated: 2022-03-20T00:37:32Z
|
||||
updated: 2022-04-19T06:17:11Z
|
||||
---
|
||||
|
||||
# Joplin statistics
|
||||
|
||||
| Name | Value |
|
||||
| ----- | ----- |
|
||||
| Total Windows downloads | 2,244,597 |
|
||||
| Total macOs downloads | 889,023 |
|
||||
| Total Linux downloads | 708,023 |
|
||||
| Total Windows downloads | 2,315,940 |
|
||||
| Total macOs downloads | 914,149 |
|
||||
| Total Linux downloads | 728,950 |
|
||||
| Windows % | 58% |
|
||||
| macOS % | 23% |
|
||||
| Linux % | 18% |
|
||||
|
@ -17,78 +17,79 @@ updated: 2022-03-20T00:37:32Z
|
|||
|
||||
| Version | Date | Windows | macOS | Linux | Total |
|
||||
| ----- | ----- | ----- | ----- | ----- | ----- |
|
||||
| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 15,145 | 8,985 | 2,642 | 26,772 |
|
||||
| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 30,487 | 16,564 | 4,679 | 51,730 |
|
||||
| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 51,313 | 25,612 | 11,643 | 88,568 |
|
||||
| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 1,715 | 435 | 428 | 2,578 |
|
||||
| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 921 | 174 | 135 | 1,230 |
|
||||
| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 586 | 99 | 55 | 740 |
|
||||
| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 2,888 | 745 | 794 | 4,427 |
|
||||
| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 845 | 133 | 108 | 1,086 |
|
||||
| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 952 | 158 | 88 | 1,198 |
|
||||
| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 130,779 | 51,059 | 48,240 | 230,078 |
|
||||
| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 15,986 | 9,448 | 3,135 | 28,569 |
|
||||
| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 1,156 | 141 | 77 | 1,374 |
|
||||
| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 1,215 | 231 | 143 | 1,589 |
|
||||
| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 507 | 26 | 12 | 545 |
|
||||
| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 1,287 | 264 | 171 | 1,722 |
|
||||
| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 2,953 | 771 | 669 | 4,393 |
|
||||
| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 78,682 | 32,403 | 25,149 | 136,234 |
|
||||
| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 43,828 | 18,959 | 10,013 | 72,800 |
|
||||
| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 12,910 | 6,529 | 2,279 | 21,718 |
|
||||
| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 879 | 185 | 133 | 1,197 |
|
||||
| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 835 | 153 | 85 | 1,073 |
|
||||
| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 2,103 | 549 | 548 | 3,200 |
|
||||
| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 43,377 | 19,923 | 9,738 | 73,038 |
|
||||
| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 3,241 | 878 | 919 | 5,038 |
|
||||
| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 55,862 | 23,175 | 15,794 | 94,831 |
|
||||
| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 7,169 | 1,750 | 506 | 9,425 |
|
||||
| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 1,227 | 232 | 182 | 1,641 |
|
||||
| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 1,880 | 439 | 495 | 2,814 |
|
||||
| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 1,294 | 248 | 204 | 1,746 |
|
||||
| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 1,571 | 357 | 338 | 2,266 |
|
||||
| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 1,085 | 183 | 150 | 1,418 |
|
||||
| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 791 | 128 | 72 | 991 |
|
||||
| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 1,681 | 352 | 315 | 2,348 |
|
||||
| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 81,073 | 31,347 | 33,050 | 145,470 |
|
||||
| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 14,544 | 6,851 | 4,031 | 25,426 |
|
||||
| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 14,958 | 7,485 | 2,565 | 25,008 |
|
||||
| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 7,740 | 4,600 | 937 | 13,277 |
|
||||
| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 1,390 | 256 | 186 | 1,832 |
|
||||
| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 1,104 | 186 | 112 | 1,402 |
|
||||
| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 3,006 | 716 | 626 | 4,348 |
|
||||
| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 46,031 | 18,760 | 16,679 | 81,470 |
|
||||
| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 2,419 | 396 | 372 | 3,187 |
|
||||
| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 29,921 | 12,159 | 12,699 | 54,779 |
|
||||
| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 13,817 | 6,376 | 3,602 | 23,795 |
|
||||
| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 1,426 | 226 | 176 | 1,828 |
|
||||
| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 1,574 | 288 | 194 | 2,056 |
|
||||
| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 23,088 | 9,218 | 9,797 | 42,103 |
|
||||
| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 2,395 | 911 | 364 | 3,670 |
|
||||
| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 1,475 | 286 | 872 | 2,633 |
|
||||
| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 1,080 | 222 | 569 | 1,871 |
|
||||
| [v2.0.4](https://github.com/laurent22/joplin/releases/tag/v2.0.4) (p) | 2021-06-02T12:54:17Z | 1,437 | 384 | 371 | 2,192 |
|
||||
| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 2,612 | 485 | 1,661 | 4,758 |
|
||||
| [v2.0.1](https://github.com/laurent22/joplin/releases/tag/v2.0.1) (p) | 2021-05-15T13:22:58Z | 854 | 266 | 1,017 | 2,137 |
|
||||
| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 37,788 | 16,250 | 19,384 | 73,422 |
|
||||
| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 1,128 | 132 | 452 | 1,712 |
|
||||
| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 1,865 | 303 | 934 | 3,102 |
|
||||
| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 2,199 | 433 | 1,282 | 3,914 |
|
||||
| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 3,429 | 823 | 2,447 | 6,699 |
|
||||
| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 116,023 | 42,754 | 64,261 | 223,038 |
|
||||
| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,026 | 4,853 | 4,471 | 23,350 |
|
||||
| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 765 | 215 | 211 | 1,191 |
|
||||
| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 80,140 | 33,355 | 22,481 | 135,976 |
|
||||
| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 30,805 | 16,708 | 4,728 | 52,241 |
|
||||
| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 51,508 | 25,658 | 11,657 | 88,823 |
|
||||
| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 1,837 | 439 | 432 | 2,708 |
|
||||
| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 1,043 | 176 | 137 | 1,356 |
|
||||
| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 711 | 101 | 58 | 870 |
|
||||
| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 3,005 | 747 | 796 | 4,548 |
|
||||
| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 962 | 135 | 110 | 1,207 |
|
||||
| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 1,064 | 160 | 90 | 1,314 |
|
||||
| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 131,057 | 51,082 | 48,789 | 230,928 |
|
||||
| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 16,038 | 9,452 | 3,138 | 28,628 |
|
||||
| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 1,189 | 141 | 77 | 1,407 |
|
||||
| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 1,250 | 231 | 143 | 1,624 |
|
||||
| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 551 | 31 | 12 | 594 |
|
||||
| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 1,326 | 266 | 174 | 1,766 |
|
||||
| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 2,993 | 773 | 671 | 4,437 |
|
||||
| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 78,786 | 32,413 | 25,155 | 136,354 |
|
||||
| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 43,910 | 18,971 | 10,022 | 72,903 |
|
||||
| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 12,961 | 6,533 | 2,283 | 21,777 |
|
||||
| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 918 | 187 | 135 | 1,240 |
|
||||
| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 874 | 155 | 87 | 1,116 |
|
||||
| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 2,159 | 551 | 550 | 3,260 |
|
||||
| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 43,471 | 19,928 | 9,744 | 73,143 |
|
||||
| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 3,289 | 880 | 921 | 5,090 |
|
||||
| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 55,933 | 23,185 | 15,803 | 94,921 |
|
||||
| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 7,212 | 1,752 | 510 | 9,474 |
|
||||
| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 1,266 | 234 | 184 | 1,684 |
|
||||
| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 1,932 | 441 | 497 | 2,870 |
|
||||
| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 1,333 | 250 | 206 | 1,789 |
|
||||
| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 1,608 | 359 | 340 | 2,307 |
|
||||
| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 1,125 | 185 | 152 | 1,462 |
|
||||
| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 830 | 130 | 74 | 1,034 |
|
||||
| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 1,718 | 354 | 317 | 2,389 |
|
||||
| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 81,160 | 31,353 | 33,057 | 145,570 |
|
||||
| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 14,616 | 6,854 | 4,034 | 25,504 |
|
||||
| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 15,029 | 7,488 | 2,569 | 25,086 |
|
||||
| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 7,792 | 4,602 | 939 | 13,333 |
|
||||
| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 1,429 | 258 | 188 | 1,875 |
|
||||
| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 1,144 | 188 | 114 | 1,446 |
|
||||
| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 3,046 | 718 | 628 | 4,392 |
|
||||
| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 46,099 | 18,764 | 16,683 | 81,546 |
|
||||
| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 2,468 | 398 | 374 | 3,240 |
|
||||
| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 30,011 | 12,164 | 12,701 | 54,876 |
|
||||
| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 13,863 | 6,380 | 3,605 | 23,848 |
|
||||
| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 1,465 | 228 | 178 | 1,871 |
|
||||
| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 1,614 | 290 | 196 | 2,100 |
|
||||
| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 23,162 | 9,226 | 9,799 | 42,187 |
|
||||
| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 2,443 | 913 | 367 | 3,723 |
|
||||
| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 1,519 | 288 | 874 | 2,681 |
|
||||
| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 1,119 | 224 | 571 | 1,914 |
|
||||
| [v2.0.4](https://github.com/laurent22/joplin/releases/tag/v2.0.4) (p) | 2021-06-02T12:54:17Z | 1,458 | 384 | 371 | 2,213 |
|
||||
| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 2,648 | 485 | 1,662 | 4,795 |
|
||||
| [v2.0.1](https://github.com/laurent22/joplin/releases/tag/v2.0.1) (p) | 2021-05-15T13:22:58Z | 855 | 266 | 1,017 | 2,138 |
|
||||
| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 37,857 | 16,250 | 19,385 | 73,492 |
|
||||
| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 1,161 | 132 | 452 | 1,745 |
|
||||
| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 1,914 | 303 | 934 | 3,151 |
|
||||
| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 2,244 | 433 | 1,282 | 3,959 |
|
||||
| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 3,464 | 823 | 2,447 | 6,734 |
|
||||
| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 116,163 | 42,763 | 64,267 | 223,193 |
|
||||
| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,057 | 4,853 | 4,475 | 23,385 |
|
||||
| [v1.7.9](https://github.com/laurent22/joplin/releases/tag/v1.7.9) (p) | 2021-01-28T09:50:21Z | 502 | 133 | 498 | 1,133 |
|
||||
| [v1.7.6](https://github.com/laurent22/joplin/releases/tag/v1.7.6) (p) | 2021-01-27T10:36:05Z | 310 | 93 | 287 | 690 |
|
||||
| [v1.7.5](https://github.com/laurent22/joplin/releases/tag/v1.7.5) (p) | 2021-01-26T09:53:05Z | 386 | 204 | 454 | 1,044 |
|
||||
| [v1.7.5](https://github.com/laurent22/joplin/releases/tag/v1.7.5) (p) | 2021-01-26T09:53:05Z | 388 | 204 | 454 | 1,046 |
|
||||
| [v1.7.4](https://github.com/laurent22/joplin/releases/tag/v1.7.4) (p) | 2021-01-22T17:58:38Z | 693 | 204 | 625 | 1,522 |
|
||||
| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 19,358 | 7,690 | 7,598 | 34,646 |
|
||||
| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 19,454 | 7,690 | 7,598 | 34,742 |
|
||||
| [v1.7.3](https://github.com/laurent22/joplin/releases/tag/v1.7.3) (p) | 2021-01-20T11:23:50Z | 345 | 76 | 442 | 863 |
|
||||
| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 11,307 | 4,634 | 4,542 | 20,483 |
|
||||
| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,538 | 3,417 | 4,793 | 20,748 |
|
||||
| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 1,267 | 72 | 308 | 1,647 |
|
||||
| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 11,369 | 4,634 | 4,542 | 20,545 |
|
||||
| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,555 | 3,417 | 4,793 | 20,765 |
|
||||
| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 1,312 | 72 | 308 | 1,692 |
|
||||
| [v1.6.4](https://github.com/laurent22/joplin/releases/tag/v1.6.4) (p) | 2021-01-07T19:11:32Z | 391 | 78 | 203 | 672 |
|
||||
| [v1.6.2](https://github.com/laurent22/joplin/releases/tag/v1.6.2) (p) | 2021-01-04T22:34:55Z | 673 | 228 | 590 | 1,491 |
|
||||
| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 11,771 | 5,203 | 5,526 | 22,500 |
|
||||
| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 11,834 | 5,203 | 5,526 | 22,563 |
|
||||
| [v1.6.1](https://github.com/laurent22/joplin/releases/tag/v1.6.1) (p) | 2020-12-29T19:37:45Z | 171 | 36 | 168 | 375 |
|
||||
| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 629 | 218 | 200 | 1,047 |
|
||||
| [v1.5.12](https://github.com/laurent22/joplin/releases/tag/v1.5.12) | 2020-12-28T15:14:08Z | 2,409 | 1,769 | 923 | 5,101 |
|
||||
|
@ -98,19 +99,19 @@ updated: 2022-03-20T00:37:32Z
|
|||
| [v1.5.8](https://github.com/laurent22/joplin/releases/tag/v1.5.8) (p) | 2020-12-20T09:45:19Z | 566 | 165 | 642 | 1,373 |
|
||||
| [v1.5.7](https://github.com/laurent22/joplin/releases/tag/v1.5.7) (p) | 2020-12-10T12:58:33Z | 889 | 254 | 993 | 2,136 |
|
||||
| [v1.5.4](https://github.com/laurent22/joplin/releases/tag/v1.5.4) (p) | 2020-12-05T12:07:49Z | 692 | 166 | 634 | 1,492 |
|
||||
| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 26,523 | 13,446 | 11,679 | 51,648 |
|
||||
| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,346 | 3,879 | 3,138 | 18,363 |
|
||||
| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,479 | 828 | 596 | 2,903 |
|
||||
| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 26,597 | 13,456 | 11,679 | 51,732 |
|
||||
| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,377 | 3,879 | 3,138 | 18,394 |
|
||||
| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,481 | 829 | 597 | 2,907 |
|
||||
| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 897 | 486 | 274 | 1,657 |
|
||||
| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,027 | 1,327 | 1,303 | 5,657 |
|
||||
| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 1,798 | 159 | 593 | 2,550 |
|
||||
| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,029 | 1,327 | 1,303 | 5,659 |
|
||||
| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 1,857 | 159 | 593 | 2,609 |
|
||||
| [v1.4.10](https://github.com/laurent22/joplin/releases/tag/v1.4.10) (p) | 2020-11-14T09:53:15Z | 631 | 198 | 686 | 1,515 |
|
||||
| [v1.4.9](https://github.com/laurent22/joplin/releases/tag/v1.4.9) (p) | 2020-11-11T14:23:17Z | 696 | 143 | 404 | 1,243 |
|
||||
| [v1.4.9](https://github.com/laurent22/joplin/releases/tag/v1.4.9) (p) | 2020-11-11T14:23:17Z | 707 | 143 | 404 | 1,254 |
|
||||
| [v1.4.7](https://github.com/laurent22/joplin/releases/tag/v1.4.7) (p) | 2020-11-07T18:23:29Z | 520 | 175 | 516 | 1,211 |
|
||||
| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 31,799 | 11,337 | 10,515 | 53,651 |
|
||||
| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 31,861 | 11,337 | 10,515 | 53,713 |
|
||||
| [v1.3.17](https://github.com/laurent22/joplin/releases/tag/v1.3.17) (p) | 2020-11-06T11:35:15Z | 50 | 27 | 25 | 102 |
|
||||
| [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 515 | 95 | 55 | 665 |
|
||||
| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,430 | 1,301 | 848 | 4,579 |
|
||||
| [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 532 | 95 | 55 | 682 |
|
||||
| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,438 | 1,301 | 848 | 4,587 |
|
||||
| [v1.3.11](https://github.com/laurent22/joplin/releases/tag/v1.3.11) (p) | 2020-10-31T13:22:20Z | 699 | 189 | 484 | 1,372 |
|
||||
| [v1.3.10](https://github.com/laurent22/joplin/releases/tag/v1.3.10) (p) | 2020-10-29T13:27:14Z | 378 | 118 | 319 | 815 |
|
||||
| [v1.3.9](https://github.com/laurent22/joplin/releases/tag/v1.3.9) (p) | 2020-10-23T16:04:26Z | 839 | 245 | 636 | 1,720 |
|
||||
|
@ -120,65 +121,65 @@ updated: 2022-03-20T00:37:32Z
|
|||
| [v1.3.3](https://github.com/laurent22/joplin/releases/tag/v1.3.3) (p) | 2020-10-17T10:56:57Z | 121 | 49 | 36 | 206 |
|
||||
| [v1.3.2](https://github.com/laurent22/joplin/releases/tag/v1.3.2) (p) | 2020-10-11T20:39:49Z | 667 | 184 | 568 | 1,419 |
|
||||
| [v1.3.1](https://github.com/laurent22/joplin/releases/tag/v1.3.1) (p) | 2020-10-11T15:10:18Z | 85 | 54 | 46 | 185 |
|
||||
| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 45,407 | 17,739 | 14,047 | 77,193 |
|
||||
| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 45,498 | 17,740 | 14,047 | 77,285 |
|
||||
| [v1.2.4](https://github.com/laurent22/joplin/releases/tag/v1.2.4) (p) | 2020-09-30T07:34:29Z | 816 | 250 | 800 | 1,866 |
|
||||
| [v1.2.3](https://github.com/laurent22/joplin/releases/tag/v1.2.3) (p) | 2020-09-29T15:13:02Z | 220 | 68 | 82 | 370 |
|
||||
| [v1.2.2](https://github.com/laurent22/joplin/releases/tag/v1.2.2) (p) | 2020-09-22T20:31:55Z | 961 | 210 | 642 | 1,813 |
|
||||
| [v1.1.4](https://github.com/laurent22/joplin/releases/tag/v1.1.4) | 2020-09-21T11:20:09Z | 27,825 | 13,510 | 7,756 | 49,091 |
|
||||
| [v1.2.2](https://github.com/laurent22/joplin/releases/tag/v1.2.2) (p) | 2020-09-22T20:31:55Z | 979 | 210 | 642 | 1,831 |
|
||||
| [v1.1.4](https://github.com/laurent22/joplin/releases/tag/v1.1.4) | 2020-09-21T11:20:09Z | 27,839 | 13,510 | 7,756 | 49,105 |
|
||||
| [v1.1.3](https://github.com/laurent22/joplin/releases/tag/v1.1.3) (p) | 2020-09-17T10:30:37Z | 568 | 155 | 467 | 1,190 |
|
||||
| [v1.1.2](https://github.com/laurent22/joplin/releases/tag/v1.1.2) (p) | 2020-09-15T12:58:38Z | 380 | 121 | 254 | 755 |
|
||||
| [v1.1.1](https://github.com/laurent22/joplin/releases/tag/v1.1.1) (p) | 2020-09-11T23:32:47Z | 535 | 202 | 353 | 1,090 |
|
||||
| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 21,756 | 10,012 | 5,645 | 37,413 |
|
||||
| [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,658 | 6,426 | 3,021 | 22,105 |
|
||||
| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 25,133 | 5,841 | 5,074 | 36,048 |
|
||||
| [v1.0.239](https://github.com/laurent22/joplin/releases/tag/v1.0.239) (p) | 2020-09-01T21:56:36Z | 775 | 234 | 407 | 1,416 |
|
||||
| [v1.1.1](https://github.com/laurent22/joplin/releases/tag/v1.1.1) (p) | 2020-09-11T23:32:47Z | 536 | 202 | 353 | 1,091 |
|
||||
| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 21,807 | 10,012 | 5,645 | 37,464 |
|
||||
| [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,672 | 6,426 | 3,021 | 22,119 |
|
||||
| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 25,262 | 5,861 | 5,081 | 36,204 |
|
||||
| [v1.0.239](https://github.com/laurent22/joplin/releases/tag/v1.0.239) (p) | 2020-09-01T21:56:36Z | 790 | 234 | 407 | 1,431 |
|
||||
| [v1.0.237](https://github.com/laurent22/joplin/releases/tag/v1.0.237) (p) | 2020-08-29T15:38:04Z | 596 | 932 | 344 | 1,872 |
|
||||
| [v1.0.236](https://github.com/laurent22/joplin/releases/tag/v1.0.236) (p) | 2020-08-28T09:16:54Z | 321 | 119 | 110 | 550 |
|
||||
| [v1.0.235](https://github.com/laurent22/joplin/releases/tag/v1.0.235) (p) | 2020-08-18T22:08:01Z | 1,854 | 498 | 928 | 3,280 |
|
||||
| [v1.0.234](https://github.com/laurent22/joplin/releases/tag/v1.0.234) (p) | 2020-08-17T23:13:02Z | 578 | 133 | 107 | 818 |
|
||||
| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 44,303 | 18,202 | 12,367 | 74,872 |
|
||||
| [v1.0.235](https://github.com/laurent22/joplin/releases/tag/v1.0.235) (p) | 2020-08-18T22:08:01Z | 1,869 | 498 | 928 | 3,295 |
|
||||
| [v1.0.234](https://github.com/laurent22/joplin/releases/tag/v1.0.234) (p) | 2020-08-17T23:13:02Z | 579 | 133 | 107 | 819 |
|
||||
| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 44,384 | 18,202 | 12,367 | 74,953 |
|
||||
| [v1.0.232](https://github.com/laurent22/joplin/releases/tag/v1.0.232) (p) | 2020-07-28T22:34:40Z | 660 | 231 | 186 | 1,077 |
|
||||
| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 40,898 | 15,288 | 9,641 | 65,827 |
|
||||
| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 40,936 | 15,288 | 9,641 | 65,865 |
|
||||
| [v1.0.226](https://github.com/laurent22/joplin/releases/tag/v1.0.226) (p) | 2020-07-04T10:21:26Z | 4,922 | 2,261 | 694 | 7,877 |
|
||||
| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 24,817 | 11,015 | 6,013 | 41,845 |
|
||||
| [v1.0.223](https://github.com/laurent22/joplin/releases/tag/v1.0.223) (p) | 2020-06-20T11:51:27Z | 194 | 120 | 84 | 398 |
|
||||
| [v1.0.221](https://github.com/laurent22/joplin/releases/tag/v1.0.221) (p) | 2020-06-20T01:44:20Z | 862 | 214 | 216 | 1,292 |
|
||||
| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,175 | 9,929 | 6,421 | 48,525 |
|
||||
| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,206 | 9,929 | 6,421 | 48,556 |
|
||||
| [v1.0.218](https://github.com/laurent22/joplin/releases/tag/v1.0.218) | 2020-06-07T10:43:34Z | 14,552 | 6,977 | 2,962 | 24,491 |
|
||||
| [v1.0.217](https://github.com/laurent22/joplin/releases/tag/v1.0.217) (p) | 2020-06-06T15:17:27Z | 232 | 101 | 60 | 393 |
|
||||
| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 38,147 | 14,298 | 10,188 | 62,633 |
|
||||
| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 38,204 | 14,299 | 10,188 | 62,691 |
|
||||
| [v1.0.214](https://github.com/laurent22/joplin/releases/tag/v1.0.214) (p) | 2020-05-21T17:15:15Z | 6,573 | 3,476 | 768 | 10,817 |
|
||||
| [v1.0.212](https://github.com/laurent22/joplin/releases/tag/v1.0.212) (p) | 2020-05-21T07:48:39Z | 218 | 76 | 53 | 347 |
|
||||
| [v1.0.211](https://github.com/laurent22/joplin/releases/tag/v1.0.211) (p) | 2020-05-20T08:59:16Z | 307 | 140 | 93 | 540 |
|
||||
| [v1.0.209](https://github.com/laurent22/joplin/releases/tag/v1.0.209) (p) | 2020-05-17T18:32:51Z | 1,399 | 860 | 153 | 2,412 |
|
||||
| [v1.0.207](https://github.com/laurent22/joplin/releases/tag/v1.0.207) (p) | 2020-05-10T16:37:35Z | 1,201 | 271 | 1,022 | 2,494 |
|
||||
| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,117 | 20,055 | 18,184 | 92,356 |
|
||||
| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,178 | 20,056 | 18,184 | 92,418 |
|
||||
| [v1.0.200](https://github.com/laurent22/joplin/releases/tag/v1.0.200) | 2020-04-12T12:17:46Z | 9,566 | 4,897 | 1,908 | 16,371 |
|
||||
| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,511 | 5,894 | 3,794 | 29,199 |
|
||||
| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 22,590 | 9,597 | 5,947 | 38,134 |
|
||||
| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,086 | 7,954 | 4,510 | 31,550 |
|
||||
| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,517 | 5,894 | 3,794 | 29,205 |
|
||||
| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 22,630 | 9,608 | 5,979 | 38,217 |
|
||||
| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,087 | 7,954 | 4,510 | 31,551 |
|
||||
| [v1.0.194](https://github.com/laurent22/joplin/releases/tag/v1.0.194) (p) | 2020-03-14T00:00:32Z | 1,290 | 1,389 | 522 | 3,201 |
|
||||
| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,695 | 10,915 | 7,403 | 47,013 |
|
||||
| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,697 | 10,916 | 7,403 | 47,016 |
|
||||
| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 484 | 127 | 93 | 704 |
|
||||
| [v1.0.190](https://github.com/laurent22/joplin/releases/tag/v1.0.190) (p) | 2020-03-06T01:22:22Z | 383 | 96 | 89 | 568 |
|
||||
| [v1.0.189](https://github.com/laurent22/joplin/releases/tag/v1.0.189) (p) | 2020-03-04T17:27:15Z | 356 | 101 | 99 | 556 |
|
||||
| [v1.0.187](https://github.com/laurent22/joplin/releases/tag/v1.0.187) (p) | 2020-03-01T12:31:06Z | 926 | 235 | 272 | 1,433 |
|
||||
| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,327 | 28,657 | 22,559 | 122,543 |
|
||||
| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,337 | 28,668 | 22,560 | 122,565 |
|
||||
| [v1.0.178](https://github.com/laurent22/joplin/releases/tag/v1.0.178) | 2020-01-20T19:06:45Z | 17,595 | 5,968 | 2,592 | 26,155 |
|
||||
| [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 1,953 | 443 | 707 | 3,103 |
|
||||
| [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 1,954 | 443 | 707 | 3,104 |
|
||||
| [v1.0.176](https://github.com/laurent22/joplin/releases/tag/v1.0.176) (p) | 2019-12-14T10:36:44Z | 3,128 | 2,539 | 471 | 6,138 |
|
||||
| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,205 | 16,957 | 16,555 | 106,717 |
|
||||
| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,506 | 11,739 | 8,225 | 50,470 |
|
||||
| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,312 | 16,963 | 16,558 | 106,833 |
|
||||
| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,514 | 11,741 | 8,226 | 50,481 |
|
||||
| [v1.0.173](https://github.com/laurent22/joplin/releases/tag/v1.0.173) | 2019-11-11T08:33:35Z | 5,103 | 2,084 | 750 | 7,937 |
|
||||
| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,605 | 8,765 | 7,681 | 44,051 |
|
||||
| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,164 | 5,926 | 3,758 | 26,848 |
|
||||
| [v1.0.168](https://github.com/laurent22/joplin/releases/tag/v1.0.168) | 2019-09-25T21:21:38Z | 5,336 | 2,278 | 721 | 8,335 |
|
||||
| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 16,820 | 5,709 | 3,707 | 26,236 |
|
||||
| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,613 | 8,771 | 7,681 | 44,065 |
|
||||
| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,167 | 5,926 | 3,758 | 26,851 |
|
||||
| [v1.0.168](https://github.com/laurent22/joplin/releases/tag/v1.0.168) | 2019-09-25T21:21:38Z | 5,336 | 2,278 | 722 | 8,336 |
|
||||
| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 16,824 | 5,709 | 3,707 | 26,240 |
|
||||
| [v1.0.166](https://github.com/laurent22/joplin/releases/tag/v1.0.166) | 2019-09-09T17:35:54Z | 1,961 | 566 | 240 | 2,767 |
|
||||
| [v1.0.165](https://github.com/laurent22/joplin/releases/tag/v1.0.165) | 2019-08-14T21:46:29Z | 18,999 | 6,980 | 5,468 | 31,447 |
|
||||
| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,304 | 6,357 | 4,140 | 29,801 |
|
||||
| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,625 | 7,753 | 8,107 | 46,485 |
|
||||
| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,200 | 2,183 | 1,119 | 8,502 |
|
||||
| [v1.0.165](https://github.com/laurent22/joplin/releases/tag/v1.0.165) | 2019-08-14T21:46:29Z | 19,005 | 6,980 | 5,468 | 31,453 |
|
||||
| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,306 | 6,357 | 4,140 | 29,803 |
|
||||
| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,632 | 7,753 | 8,108 | 46,493 |
|
||||
| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,200 | 2,183 | 1,120 | 8,503 |
|
||||
| [v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,820 | 3,548 | 1,940 | 15,308 |
|
||||
| [v1.0.157](https://github.com/laurent22/joplin/releases/tag/v1.0.157) | 2019-05-26T17:55:53Z | 2,183 | 849 | 295 | 3,327 |
|
||||
| [v1.0.153](https://github.com/laurent22/joplin/releases/tag/v1.0.153) (p) | 2019-05-15T06:27:29Z | 854 | 107 | 110 | 1,071 |
|
||||
|
@ -188,25 +189,25 @@ updated: 2022-03-20T00:37:32Z
|
|||
| [v1.0.148](https://github.com/laurent22/joplin/releases/tag/v1.0.148) (p) | 2019-05-08T19:12:24Z | 135 | 61 | 99 | 295 |
|
||||
| [v1.0.145](https://github.com/laurent22/joplin/releases/tag/v1.0.145) | 2019-05-03T09:16:53Z | 7,012 | 2,866 | 1,441 | 11,319 |
|
||||
| [v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,923 | 3,555 | 2,784 | 18,262 |
|
||||
| [v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,716 | 4,570 | 4,731 | 24,017 |
|
||||
| [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,635 | 4,176 | 3,321 | 21,132 |
|
||||
| [v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,722 | 4,570 | 4,731 | 24,023 |
|
||||
| [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,636 | 4,176 | 3,327 | 21,139 |
|
||||
| [v1.0.139](https://github.com/laurent22/joplin/releases/tag/v1.0.139) (p) | 2019-03-09T10:06:48Z | 128 | 68 | 50 | 246 |
|
||||
| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 156 | 94 | 88 | 338 |
|
||||
| [v1.0.137](https://github.com/laurent22/joplin/releases/tag/v1.0.137) (p) | 2019-03-03T01:12:51Z | 596 | 63 | 87 | 746 |
|
||||
| [v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,570 | 3,964 | 4,082 | 20,616 |
|
||||
| [v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,577 | 3,964 | 4,082 | 20,623 |
|
||||
| [v1.0.134](https://github.com/laurent22/joplin/releases/tag/v1.0.134) | 2019-02-27T10:21:44Z | 1,472 | 574 | 223 | 2,269 |
|
||||
| [v1.0.132](https://github.com/laurent22/joplin/releases/tag/v1.0.132) | 2019-02-26T23:02:05Z | 1,092 | 457 | 100 | 1,649 |
|
||||
| [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 9,835 | 3,177 | 2,934 | 15,946 |
|
||||
| [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 9,841 | 3,177 | 2,934 | 15,952 |
|
||||
| [v1.0.126](https://github.com/laurent22/joplin/releases/tag/v1.0.126) (p) | 2019-02-09T19:46:16Z | 938 | 79 | 121 | 1,138 |
|
||||
| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,274 | 3,564 | 1,707 | 15,545 |
|
||||
| [v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,610 | 5,208 | 6,522 | 27,340 |
|
||||
| [v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 8,911 | 3,267 | 2,018 | 14,196 |
|
||||
| [v1.0.118](https://github.com/laurent22/joplin/releases/tag/v1.0.118) | 2019-01-11T08:34:13Z | 722 | 253 | 93 | 1,068 |
|
||||
| [v1.0.117](https://github.com/laurent22/joplin/releases/tag/v1.0.117) | 2018-11-24T12:05:24Z | 16,266 | 4,902 | 6,385 | 27,553 |
|
||||
| [v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 3,504 | 1,128 | 718 | 5,350 |
|
||||
| [v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 3,543 | 1,128 | 718 | 5,389 |
|
||||
| [v1.0.115](https://github.com/laurent22/joplin/releases/tag/v1.0.115) | 2018-11-16T16:52:02Z | 3,662 | 1,308 | 805 | 5,775 |
|
||||
| [v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | 11,401 | 3,507 | 3,834 | 18,742 |
|
||||
| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,093 | 3,316 | 3,686 | 19,095 |
|
||||
| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,102 | 3,318 | 3,687 | 19,107 |
|
||||
| [v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 966 | 414 | 122 | 1,502 |
|
||||
| [v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 2,107 | 710 | 332 | 3,149 |
|
||||
| [v1.0.108](https://github.com/laurent22/joplin/releases/tag/v1.0.108) (p) | 2018-09-29T18:49:29Z | 35 | 27 | 18 | 80 |
|
||||
|
@ -220,13 +221,13 @@ updated: 2022-03-20T00:37:32Z
|
|||
| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,260 | 603 | 385 | 2,248 |
|
||||
| [v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 317 | 162 | 65 | 544 |
|
||||
| [v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,726 | 1,230 | 1,707 | 5,663 |
|
||||
| [v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 424 | 225 | 128 | 777 |
|
||||
| [v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 424 | 225 | 129 | 778 |
|
||||
| [v1.0.94](https://github.com/laurent22/joplin/releases/tag/v1.0.94) | 2018-05-21T20:52:59Z | 1,138 | 591 | 404 | 2,133 |
|
||||
| [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,796 | 1,208 | 766 | 3,770 |
|
||||
| [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,796 | 1,214 | 766 | 3,776 |
|
||||
| [v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 832 | 558 | 317 | 1,707 |
|
||||
| [v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) | 2018-05-09T13:05:05Z | 500 | 238 | 118 | 856 |
|
||||
| [v1.0.85](https://github.com/laurent22/joplin/releases/tag/v1.0.85) | 2018-05-01T21:08:24Z | 1,657 | 957 | 641 | 3,255 |
|
||||
| [v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 5,198 | 2,538 | 2,665 | 10,401 |
|
||||
| [v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 5,230 | 2,538 | 2,665 | 10,433 |
|
||||
| [v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 696 | 412 | 129 | 1,237 |
|
||||
| [v1.0.81](https://github.com/laurent22/joplin/releases/tag/v1.0.81) | 2018-03-28T08:13:58Z | 1,003 | 603 | 790 | 2,396 |
|
||||
| [v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 934 | 545 | 388 | 1,867 |
|
||||
|
@ -249,21 +250,21 @@ updated: 2022-03-20T00:37:32Z
|
|||
| [v0.10.47](https://github.com/laurent22/joplin/releases/tag/v0.10.47) | 2018-01-16T17:27:17Z | 1,233 | 1,277 | 72 | 2,582 |
|
||||
| [v0.10.43](https://github.com/laurent22/joplin/releases/tag/v0.10.43) | 2018-01-08T10:12:10Z | 3,445 | 2,362 | 1,213 | 7,020 |
|
||||
| [v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,040 | 1,555 | 247 | 2,842 |
|
||||
| [v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,598 | 1,795 | 344 | 3,737 |
|
||||
| [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,828 | 4,300 | 3,200 | 13,328 |
|
||||
| [v0.10.38](https://github.com/laurent22/joplin/releases/tag/v0.10.38) | 2017-12-08T10:12:06Z | 1,052 | 1,236 | 311 | 2,599 |
|
||||
| [v0.10.37](https://github.com/laurent22/joplin/releases/tag/v0.10.37) | 2017-12-07T19:38:05Z | 268 | 851 | 88 | 1,207 |
|
||||
| [v0.10.36](https://github.com/laurent22/joplin/releases/tag/v0.10.36) | 2017-12-05T09:34:40Z | 1,018 | 1,363 | 444 | 2,825 |
|
||||
| [v0.10.35](https://github.com/laurent22/joplin/releases/tag/v0.10.35) | 2017-12-02T15:56:08Z | 1,581 | 1,554 | 750 | 3,885 |
|
||||
| [v0.10.34](https://github.com/laurent22/joplin/releases/tag/v0.10.34) | 2017-12-02T14:50:28Z | 93 | 677 | 65 | 835 |
|
||||
| [v0.10.33](https://github.com/laurent22/joplin/releases/tag/v0.10.33) | 2017-12-02T13:20:39Z | 65 | 665 | 28 | 758 |
|
||||
| [v0.10.31](https://github.com/laurent22/joplin/releases/tag/v0.10.31) | 2017-12-01T09:56:44Z | 896 | 1,457 | 412 | 2,765 |
|
||||
| [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 726 | 1,375 | 425 | 2,526 |
|
||||
| [v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,352 | 1,708 | 881 | 3,941 |
|
||||
| [v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 191 | 707 | 266 | 1,164 |
|
||||
| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 152 | 703 | 6,551 | 7,406 |
|
||||
| [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 136 | 654 | 33 | 823 |
|
||||
| [v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 89 | 651 | 26 | 766 |
|
||||
| [v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 56 | 644 | 19 | 719 |
|
||||
| [v0.10.20](https://github.com/laurent22/joplin/releases/tag/v0.10.20) | 2017-11-17T17:18:25Z | 38 | 655 | 28 | 721 |
|
||||
| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 28 | 653 | 22 | 703 |
|
||||
| [v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,599 | 1,795 | 344 | 3,738 |
|
||||
| [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,837 | 4,309 | 3,208 | 13,354 |
|
||||
| [v0.10.38](https://github.com/laurent22/joplin/releases/tag/v0.10.38) | 2017-12-08T10:12:06Z | 1,054 | 1,240 | 313 | 2,607 |
|
||||
| [v0.10.37](https://github.com/laurent22/joplin/releases/tag/v0.10.37) | 2017-12-07T19:38:05Z | 270 | 855 | 90 | 1,215 |
|
||||
| [v0.10.36](https://github.com/laurent22/joplin/releases/tag/v0.10.36) | 2017-12-05T09:34:40Z | 1,020 | 1,367 | 446 | 2,833 |
|
||||
| [v0.10.35](https://github.com/laurent22/joplin/releases/tag/v0.10.35) | 2017-12-02T15:56:08Z | 1,583 | 1,558 | 752 | 3,893 |
|
||||
| [v0.10.34](https://github.com/laurent22/joplin/releases/tag/v0.10.34) | 2017-12-02T14:50:28Z | 95 | 681 | 67 | 843 |
|
||||
| [v0.10.33](https://github.com/laurent22/joplin/releases/tag/v0.10.33) | 2017-12-02T13:20:39Z | 67 | 669 | 30 | 766 |
|
||||
| [v0.10.31](https://github.com/laurent22/joplin/releases/tag/v0.10.31) | 2017-12-01T09:56:44Z | 898 | 1,461 | 414 | 2,773 |
|
||||
| [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 728 | 1,379 | 427 | 2,534 |
|
||||
| [v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,354 | 1,712 | 883 | 3,949 |
|
||||
| [v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 195 | 711 | 268 | 1,174 |
|
||||
| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 154 | 707 | 6,565 | 7,426 |
|
||||
| [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 142 | 671 | 43 | 856 |
|
||||
| [v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 92 | 657 | 29 | 778 |
|
||||
| [v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 59 | 650 | 23 | 732 |
|
||||
| [v0.10.20](https://github.com/laurent22/joplin/releases/tag/v0.10.20) | 2017-11-17T17:18:25Z | 42 | 661 | 31 | 734 |
|
||||
| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 31 | 660 | 28 | 719 |
|
198
yarn.lock
198
yarn.lock
|
@ -2978,9 +2978,9 @@ __metadata:
|
|||
"@codemirror/lang-markdown": ^0.18.4
|
||||
"@codemirror/state": ^0.18.7
|
||||
"@codemirror/view": ^0.18.19
|
||||
"@joplin/lib": ~2.6
|
||||
"@joplin/renderer": ~2.6
|
||||
"@joplin/tools": ~2.6
|
||||
"@joplin/lib": ~2.8
|
||||
"@joplin/renderer": ~2.8
|
||||
"@joplin/tools": ~2.8
|
||||
"@react-native-community/clipboard": ^1.5.0
|
||||
"@react-native-community/datetimepicker": ^3.0.3
|
||||
"@react-native-community/geolocation": ^2.0.2
|
||||
|
@ -3089,7 +3089,7 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@joplin/htmlpack@^2.6.1, @joplin/htmlpack@workspace:packages/htmlpack, @joplin/htmlpack@~2.8":
|
||||
"@joplin/htmlpack@workspace:packages/htmlpack, @joplin/htmlpack@~2.8":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@joplin/htmlpack@workspace:packages/htmlpack"
|
||||
dependencies:
|
||||
|
@ -3102,7 +3102,7 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@joplin/lib@^2.6.3, @joplin/lib@workspace:packages/lib, @joplin/lib@~2.8":
|
||||
"@joplin/lib@workspace:packages/lib, @joplin/lib@~2.8":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@joplin/lib@workspace:packages/lib"
|
||||
dependencies:
|
||||
|
@ -3183,76 +3183,6 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@joplin/lib@npm:~2.6":
|
||||
version: 2.6.3
|
||||
resolution: "@joplin/lib@npm:2.6.3"
|
||||
dependencies:
|
||||
"@aws-sdk/client-s3": ^3.34.0
|
||||
"@aws-sdk/s3-request-presigner": ^3.34.0
|
||||
"@joplin/fork-htmlparser2": ^4.1.39
|
||||
"@joplin/fork-sax": ^1.2.43
|
||||
"@joplin/htmlpack": ^2.6.1
|
||||
"@joplin/renderer": ^2.6.3
|
||||
"@joplin/turndown": ^4.0.61
|
||||
"@joplin/turndown-plugin-gfm": ^1.0.43
|
||||
async-mutex: ^0.1.3
|
||||
base-64: ^0.1.0
|
||||
base64-stream: ^1.0.0
|
||||
builtin-modules: ^3.1.0
|
||||
chokidar: ^3.4.3
|
||||
color: 3.1.2
|
||||
compare-versions: ^3.6.0
|
||||
css: ^3.0.0
|
||||
diff-match-patch: ^1.0.4
|
||||
es6-promise-pool: ^2.5.0
|
||||
fast-deep-equal: ^3.1.3
|
||||
follow-redirects: ^1.2.4
|
||||
form-data: ^2.1.4
|
||||
fs-extra: ^5.0.0
|
||||
html-entities: ^1.2.1
|
||||
html-minifier: ^3.5.15
|
||||
image-data-uri: ^2.0.0
|
||||
image-type: ^3.0.0
|
||||
immer: ^7.0.14
|
||||
js-yaml: ^4.1.0
|
||||
levenshtein: ^1.0.5
|
||||
lodash: ^4.17.20
|
||||
markdown-it: ^10.0.0
|
||||
md5: ^2.2.1
|
||||
md5-file: ^4.0.0
|
||||
moment: ^2.29.1
|
||||
multiparty: ^4.2.1
|
||||
mustache: ^4.0.1
|
||||
nanoid: ^3.1.12
|
||||
node-fetch: ^1.7.1
|
||||
node-notifier: ^8.0.0
|
||||
node-persist: ^2.1.0
|
||||
node-rsa: ^1.1.1
|
||||
promise: ^7.1.1
|
||||
query-string: 4.3.4
|
||||
re-reselect: ^4.0.0
|
||||
read-chunk: ^2.1.0
|
||||
redux: ^3.7.2
|
||||
relative: ^3.0.2
|
||||
reselect: ^4.0.0
|
||||
server-destroy: ^1.0.1
|
||||
sprintf-js: ^1.1.2
|
||||
sqlite3: ^5.0.2
|
||||
string-padding: ^1.0.2
|
||||
string-to-stream: ^1.1.0
|
||||
tar: ^4.4.10
|
||||
tcp-port-used: ^0.1.2
|
||||
uglifycss: 0.0.29
|
||||
url-parse: ^1.4.7
|
||||
uslug: "git+https://github.com/laurent22/uslug.git#emoji-support"
|
||||
uuid: ^3.0.1
|
||||
valid-url: ^1.0.9
|
||||
word-wrap: ^1.2.3
|
||||
xml2js: ^0.4.19
|
||||
checksum: d0208121688057f179fe52a61a3442ce63fe82f3ef65d1fa27a7d21e2912048f7009daa464d44ec00f5fa980d3cf33ae0ec869598357ed96225aed20dcc1dcd0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@joplin/plugin-repo-cli@workspace:packages/plugin-repo-cli":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@joplin/plugin-repo-cli@workspace:packages/plugin-repo-cli"
|
||||
|
@ -3283,7 +3213,7 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@joplin/renderer@^2.6.3, @joplin/renderer@workspace:packages/renderer, @joplin/renderer@~2.8":
|
||||
"@joplin/renderer@workspace:packages/renderer, @joplin/renderer@~2.8":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@joplin/renderer@workspace:packages/renderer"
|
||||
dependencies:
|
||||
|
@ -3317,37 +3247,6 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@joplin/renderer@npm:~2.6":
|
||||
version: 2.6.3
|
||||
resolution: "@joplin/renderer@npm:2.6.3"
|
||||
dependencies:
|
||||
"@joplin/fork-htmlparser2": ^4.1.39
|
||||
font-awesome-filetypes: ^2.1.0
|
||||
fs-extra: ^8.1.0
|
||||
highlight.js: ^11.2.0
|
||||
html-entities: ^1.2.1
|
||||
json-stringify-safe: ^5.0.1
|
||||
katex: ^0.13.3
|
||||
markdown-it: ^10.0.0
|
||||
markdown-it-abbr: ^1.0.4
|
||||
markdown-it-anchor: ^5.2.5
|
||||
markdown-it-deflist: ^2.0.3
|
||||
markdown-it-emoji: ^1.4.0
|
||||
markdown-it-expand-tabs: ^1.0.13
|
||||
markdown-it-footnote: ^3.0.2
|
||||
markdown-it-ins: ^3.0.0
|
||||
markdown-it-mark: ^3.0.0
|
||||
markdown-it-multimd-table: ^4.0.1
|
||||
markdown-it-sub: ^1.0.0
|
||||
markdown-it-sup: ^1.0.0
|
||||
markdown-it-toc-done-right: ^4.1.0
|
||||
md5: ^2.2.1
|
||||
mermaid: ^8.13.5
|
||||
uslug: "git+https://github.com/laurent22/uslug.git#emoji-support"
|
||||
checksum: d72adc250939c425175d61956e7060dc2fca77a00b49cfcd41cc3ff5a44de1c891c0c3be3232ba761efc67129726df155fb8626398feedc5eebdbce9094bc5c5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@joplin/server@workspace:packages/server":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@joplin/server@workspace:packages/server"
|
||||
|
@ -3409,31 +3308,6 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@joplin/tools@npm:~2.6":
|
||||
version: 2.6.3
|
||||
resolution: "@joplin/tools@npm:2.6.3"
|
||||
dependencies:
|
||||
"@joplin/lib": ^2.6.3
|
||||
"@joplin/renderer": ^2.6.3
|
||||
execa: ^4.1.0
|
||||
fs-extra: ^4.0.3
|
||||
gettext-parser: ^1.3.0
|
||||
glob: ^7.1.6
|
||||
markdown-it: ^8.4.1
|
||||
md5-file: ^4.0.0
|
||||
moment: ^2.24.0
|
||||
mustache: ^2.3.0
|
||||
node-fetch: ^1.7.3
|
||||
relative: ^3.0.2
|
||||
request: ^2.88.0
|
||||
sharp: ^0.25.2
|
||||
source-map-support: ^0.5.19
|
||||
uri-template: ^1.0.1
|
||||
yargs: ^16.0.3
|
||||
checksum: d9320b87b43336b8fdc446e144e9dd913fa4de13704c14cdfac0a885f11a8e84824e5e73eb5f20380bdc68e010d738a0cf3203ade445f7765c51d143f2bb4d35
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@joplin/tools@workspace:packages/tools, @joplin/tools@~2.8":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@joplin/tools@workspace:packages/tools"
|
||||
|
@ -16135,13 +16009,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"highlight.js@npm:^11.2.0":
|
||||
version: 11.3.1
|
||||
resolution: "highlight.js@npm:11.3.1"
|
||||
checksum: 9adaaa1fe5aaae0ca522f9355bc2a7387f76ab362f88c32c86879b99f606619a9aa33c32ffc94cd893987e71ba5d2de6f3e325ed9e8eac65e5872d251e8cba3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"highlight.js@npm:~9.12.0":
|
||||
version: 9.12.0
|
||||
resolution: "highlight.js@npm:9.12.0"
|
||||
|
@ -20480,15 +20347,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-it-multimd-table@npm:^4.0.1":
|
||||
version: 4.1.1
|
||||
resolution: "markdown-it-multimd-table@npm:4.1.1"
|
||||
dependencies:
|
||||
markdown-it: ^11.0.0
|
||||
checksum: a92c9d43f87f26f0f9d1271612ba94bb27affe0408c6bcd34641e9b4c361bf561cf9a1276ce6cf2f8df77fc5a9bb598826dc50e6411905b46aeb481a524e2974
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-it-multimd-table@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "markdown-it-multimd-table@npm:4.1.2"
|
||||
|
@ -20534,21 +20392,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-it@npm:^11.0.0":
|
||||
version: 11.0.1
|
||||
resolution: "markdown-it@npm:11.0.1"
|
||||
dependencies:
|
||||
argparse: ^1.0.7
|
||||
entities: ~2.0.0
|
||||
linkify-it: ^3.0.1
|
||||
mdurl: ^1.0.1
|
||||
uc.micro: ^1.0.5
|
||||
bin:
|
||||
markdown-it: bin/markdown-it.js
|
||||
checksum: 05e953045479fb0e47ef45fbae1ba544e9539cd26bc4cd56a9662ac08dd716a61f78a1fa64aea618c20eb80805aef8214b02e5aa7280e47cd6c3517d31591dad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-it@npm:^12.0.4":
|
||||
version: 12.2.0
|
||||
resolution: "markdown-it@npm:12.2.0"
|
||||
|
@ -20860,23 +20703,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mermaid@npm:^8.13.5":
|
||||
version: 8.13.6
|
||||
resolution: "mermaid@npm:8.13.6"
|
||||
dependencies:
|
||||
"@braintree/sanitize-url": ^3.1.0
|
||||
d3: ^7.0.0
|
||||
dagre: ^0.8.5
|
||||
dagre-d3: ^0.6.4
|
||||
dompurify: 2.3.4
|
||||
graphlib: ^2.1.8
|
||||
khroma: ^1.4.1
|
||||
moment-mini: ^2.24.0
|
||||
stylis: ^4.0.10
|
||||
checksum: 70c75c236b04d8e430de58129bd9afa5305f0879c7a60c1d4e44f636181adcc2dcdf6a2fc467ac9e76a008958a8701480dd4cb211729b0be785b650bdd55a408
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mermaid@npm:^8.13.9":
|
||||
version: 8.13.9
|
||||
resolution: "mermaid@npm:8.13.9"
|
||||
|
@ -22051,7 +21877,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-emoji@npm:1.11.0, node-emoji@npm:^1.11.0":
|
||||
"node-emoji@npm:1.11.0":
|
||||
version: 1.11.0
|
||||
resolution: "node-emoji@npm:1.11.0"
|
||||
dependencies:
|
||||
|
@ -30337,16 +30163,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"uslug@git+https://github.com/laurent22/uslug.git#emoji-support":
|
||||
version: 1.0.4
|
||||
resolution: "uslug@https://github.com/laurent22/uslug.git#commit=8c12bc7678eaefa752e673ea9cfbc0b1a14d7237"
|
||||
dependencies:
|
||||
node-emoji: ^1.11.0
|
||||
unorm: ">= 1.0.0"
|
||||
checksum: 9ed2a3b18f25090aec7468d60b8fa0b2172029d6bb8e917079971758cb67a68c9a591f2a42aa447124849dae8aaea2fa9873d38c9e792cc2e9c3c05329f59fb3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"utf8-byte-length@npm:^1.0.1":
|
||||
version: 1.0.4
|
||||
resolution: "utf8-byte-length@npm:1.0.4"
|
||||
|
|
Loading…
Reference in New Issue