You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-01-05 00:12:33 +02:00
Compare commits
17 Commits
v1.3.6
...
command_en
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3b708ff64 | ||
|
|
fea85b39a0 | ||
|
|
a53955a03d | ||
|
|
8d61514f64 | ||
|
|
c8f496b733 | ||
|
|
c4414e3bee | ||
|
|
89e7a3a65e | ||
|
|
b3bce34e9a | ||
|
|
d059aeebab | ||
|
|
910a5ad09d | ||
|
|
259dadb650 | ||
|
|
4ce2bf492b | ||
|
|
e635ee967a | ||
|
|
6a43f3be66 | ||
|
|
a4562a0a75 | ||
|
|
410a0f5d14 | ||
|
|
f8f46db910 |
@@ -180,7 +180,6 @@ ElectronClient/gui/SideBar/styles/index.js
|
||||
ElectronClient/gui/StatusScreen/StatusScreen.js
|
||||
ElectronClient/gui/style/StyledInput.js
|
||||
ElectronClient/gui/style/StyledTextInput.js
|
||||
ElectronClient/gui/TagList.js
|
||||
ElectronClient/gui/ToggleEditorsButton/styles/index.js
|
||||
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
|
||||
ElectronClient/gui/ToolbarBase.js
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -174,7 +174,6 @@ ElectronClient/gui/SideBar/styles/index.js
|
||||
ElectronClient/gui/StatusScreen/StatusScreen.js
|
||||
ElectronClient/gui/style/StyledInput.js
|
||||
ElectronClient/gui/style/StyledTextInput.js
|
||||
ElectronClient/gui/TagList.js
|
||||
ElectronClient/gui/ToggleEditorsButton/styles/index.js
|
||||
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
|
||||
ElectronClient/gui/ToolbarBase.js
|
||||
|
||||
1
.ignore
1
.ignore
@@ -123,7 +123,6 @@ ElectronClient/gui/SideBar/styles/index.js
|
||||
ElectronClient/gui/StatusScreen/StatusScreen.js
|
||||
ElectronClient/gui/style/StyledInput.js
|
||||
ElectronClient/gui/style/StyledTextInput.js
|
||||
ElectronClient/gui/TagList.js
|
||||
ElectronClient/gui/ToggleEditorsButton/styles/index.js
|
||||
ElectronClient/gui/ToggleEditorsButton/ToggleEditorsButton.js
|
||||
ElectronClient/gui/ToolbarBase.js
|
||||
|
||||
@@ -26,7 +26,6 @@ import { AppState } from '../../app';
|
||||
import ToolbarButtonUtils from 'lib/services/commands/ToolbarButtonUtils';
|
||||
import { _ } from 'lib/locale';
|
||||
import stateToWhenClauseContext from 'lib/services/commands/stateToWhenClauseContext';
|
||||
import TagList from '../TagList';
|
||||
|
||||
const { themeStyle } = require('lib/theme');
|
||||
const { substrWithEllipsis } = require('lib/string-utils');
|
||||
@@ -40,6 +39,7 @@ const Note = require('lib/models/Note.js');
|
||||
const bridge = require('electron').remote.require('./bridge').default;
|
||||
const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
|
||||
const NoteRevisionViewer = require('../NoteRevisionViewer.min');
|
||||
const TagList = require('../TagList.min.js');
|
||||
|
||||
const commands = [
|
||||
require('./commands/showRevisions'),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import app from '../app';
|
||||
import MainScreen from './MainScreen/MainScreen';
|
||||
import ConfigScreen from './ConfigScreen/ConfigScreen';
|
||||
@@ -9,7 +10,6 @@ import { themeStyle } from 'lib/theme';
|
||||
import { Size } from './ResizableLayout/ResizableLayout';
|
||||
import MenuBar from './MenuBar';
|
||||
import { _ } from 'lib/locale';
|
||||
const React = require('react');
|
||||
|
||||
const { render } = require('react-dom');
|
||||
const { connect, Provider } = require('react-redux');
|
||||
|
||||
@@ -569,20 +569,6 @@ class SideBarComponent extends React.Component<Props, State> {
|
||||
CommandService.instance().execute('newFolder');
|
||||
}
|
||||
|
||||
// componentDidUpdate(prevProps:any, prevState:any) {
|
||||
// for (const n in prevProps) {
|
||||
// if (prevProps[n] !== (this.props as any)[n]) {
|
||||
// console.info('CHANGED PROPS', n);
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (const n in prevState) {
|
||||
// if (prevState[n] !== (this.state as any)[n]) {
|
||||
// console.info('CHANGED STATE', n);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
render() {
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
|
||||
52
ElectronClient/gui/TagList.jsx
Normal file
52
ElectronClient/gui/TagList.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
const React = require('react');
|
||||
const { connect } = require('react-redux');
|
||||
const { themeStyle } = require('lib/theme');
|
||||
const TagItem = require('./TagItem.min.js');
|
||||
|
||||
class TagListComponent extends React.Component {
|
||||
render() {
|
||||
const style = Object.assign({}, this.props.style);
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const tags = this.props.items;
|
||||
|
||||
style.display = 'flex';
|
||||
style.flexDirection = 'row';
|
||||
// style.borderBottom = `1px solid ${theme.dividerColor}`;
|
||||
style.boxSizing = 'border-box';
|
||||
style.fontSize = theme.fontSize;
|
||||
style.whiteSpace = 'nowrap';
|
||||
// style.height = 40;
|
||||
style.paddingTop = 8;
|
||||
style.paddingBottom = 8;
|
||||
|
||||
const tagItems = [];
|
||||
if (tags && tags.length > 0) {
|
||||
|
||||
tags.sort((a, b) => {
|
||||
return a.title < b.title ? -1 : +1;
|
||||
});
|
||||
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
const props = {
|
||||
title: tags[i].title,
|
||||
key: tags[i].id,
|
||||
};
|
||||
tagItems.push(<TagItem {...props} />);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tag-list" style={style}>
|
||||
{tagItems}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return { themeId: state.settings.theme };
|
||||
};
|
||||
|
||||
const TagList = connect(mapStateToProps)(TagListComponent);
|
||||
|
||||
module.exports = TagList;
|
||||
@@ -1,63 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { AppState } from '../app';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { themeStyle } = require('lib/theme');
|
||||
const TagItem = require('./TagItem.min.js');
|
||||
|
||||
interface Props {
|
||||
themeId: number,
|
||||
style: any,
|
||||
items: any[],
|
||||
}
|
||||
|
||||
function TagList(props:Props) {
|
||||
const style = useMemo(() => {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
const output = { ...props.style };
|
||||
output.display = 'flex';
|
||||
output.flexDirection = 'row';
|
||||
output.boxSizing = 'border-box';
|
||||
output.fontSize = theme.fontSize;
|
||||
output.whiteSpace = 'nowrap';
|
||||
output.paddingTop = 8;
|
||||
output.paddingBottom = 8;
|
||||
return output;
|
||||
}, [props.style, props.themeId]);
|
||||
|
||||
const tags = useMemo(() => {
|
||||
const output = props.items.slice();
|
||||
|
||||
output.sort((a:any, b:any) => {
|
||||
return a.title < b.title ? -1 : +1;
|
||||
});
|
||||
|
||||
return output;
|
||||
}, [props.items]);
|
||||
|
||||
const tagItems = useMemo(() => {
|
||||
const output = [];
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
const props = {
|
||||
title: tags[i].title,
|
||||
key: tags[i].id,
|
||||
};
|
||||
output.push(<TagItem {...props} />);
|
||||
}
|
||||
return output;
|
||||
}, [tags]);
|
||||
|
||||
return (
|
||||
<div className="tag-list" style={style}>
|
||||
{tagItems}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state:AppState) => {
|
||||
return { themeId: state.settings.theme };
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(TagList);
|
||||
2
ElectronClient/package-lock.json
generated
2
ElectronClient/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "1.3.6",
|
||||
"version": "1.3.5",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "1.3.6",
|
||||
"version": "1.3.5",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -546,13 +546,7 @@ export default class BaseApplication {
|
||||
await this.refreshNotes(newState, refreshNotesUseSelectedNoteId, refreshNotesHash);
|
||||
}
|
||||
|
||||
if (action.type === 'NOTE_UPDATE_ONE') {
|
||||
if (!action.changedFields.length || action.changedFields.includes('parent_id') || action.changedFields.includes('encryption_applied')) {
|
||||
refreshFolders = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === 'NOTE_DELETE') {
|
||||
if (action.type === 'NOTE_UPDATE_ONE' || action.type === 'NOTE_DELETE') {
|
||||
refreshFolders = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { View, Button, Text } from 'react-native';
|
||||
import { themeStyle } from 'lib/theme';
|
||||
import { _ } from 'lib/locale';
|
||||
const { View, Button, Text } = require('react-native');
|
||||
|
||||
const PopupDialog = require('react-native-popup-dialog').default;
|
||||
const { DialogTitle, DialogButton } = require('react-native-popup-dialog');
|
||||
|
||||
@@ -43,11 +43,8 @@ const reduxSharedMiddleware = async function(store, next, action) {
|
||||
DecryptionWorker.instance().scheduleStart();
|
||||
}
|
||||
|
||||
// 2020-10-19: Removed "NOTE_UPDATE_ONE" because there's no property in a note that
|
||||
// should trigger a refreshing of the tags.
|
||||
// Trying to fix this: https://github.com/laurent22/joplin/issues/3893
|
||||
if (action.type == 'NOTE_DELETE' ||
|
||||
// action.type == 'NOTE_UPDATE_ONE' ||
|
||||
action.type == 'NOTE_UPDATE_ONE' ||
|
||||
action.type == 'NOTE_UPDATE_ALL' ||
|
||||
action.type == 'NOTE_TAG_REMOVE' ||
|
||||
action.type == 'TAG_UPDATE_ONE') {
|
||||
|
||||
@@ -587,29 +587,10 @@ class Note extends BaseItem {
|
||||
// decide what to keep and what to ignore, but in practice keeping the previous content is a bit
|
||||
// heavy - the note needs to be reloaded here, the JSON blob needs to be saved, etc.
|
||||
// So the check for old note here is basically an optimisation.
|
||||
|
||||
// 2020-10-19: It's not ideal to reload the previous version of the note before saving it again
|
||||
// but it should be relatively fast anyway. This is so that code that listens to the NOTE_UPDATE_ONE
|
||||
// action can decide what to do based on the fields that have been modified.
|
||||
// This is necessary for example so that the folder list is not refreshed every time a note is changed.
|
||||
// Now it can look at the properties and refresh only if the "parent_id" property is changed.
|
||||
// Trying to fix: https://github.com/laurent22/joplin/issues/3893
|
||||
const oldNote = await Note.load(o.id);
|
||||
|
||||
let beforeNoteJson = null;
|
||||
if (!isNew && this.revisionService().isOldNote(o.id)) {
|
||||
if (oldNote) beforeNoteJson = JSON.stringify(oldNote);
|
||||
}
|
||||
|
||||
const changedFields = [];
|
||||
|
||||
if (oldNote) {
|
||||
for (const field in o) {
|
||||
if (!o.hasOwnProperty(field)) continue;
|
||||
if (o[field] !== oldNote[field]) {
|
||||
changedFields.push(field);
|
||||
}
|
||||
}
|
||||
beforeNoteJson = await Note.load(o.id);
|
||||
if (beforeNoteJson) beforeNoteJson = JSON.stringify(beforeNoteJson);
|
||||
}
|
||||
|
||||
const note = await super.save(o, options);
|
||||
@@ -622,7 +603,6 @@ class Note extends BaseItem {
|
||||
type: 'NOTE_UPDATE_ONE',
|
||||
note: note,
|
||||
provisional: isProvisional,
|
||||
changedFields: changedFields,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -176,12 +176,7 @@ class Tag extends BaseItem {
|
||||
}
|
||||
|
||||
static async save(o, options = null) {
|
||||
options = Object.assign({}, {
|
||||
dispatchUpdateAction: true,
|
||||
userSideValidation: false,
|
||||
}, options);
|
||||
|
||||
if (options.userSideValidation) {
|
||||
if (options && options.userSideValidation) {
|
||||
if ('title' in o) {
|
||||
o.title = o.title.trim().toLowerCase();
|
||||
|
||||
@@ -191,13 +186,10 @@ class Tag extends BaseItem {
|
||||
}
|
||||
|
||||
return super.save(o, options).then(tag => {
|
||||
if (options.dispatchUpdateAction) {
|
||||
this.dispatch({
|
||||
type: 'TAG_UPDATE_ONE',
|
||||
item: tag,
|
||||
});
|
||||
}
|
||||
|
||||
this.dispatch({
|
||||
type: 'TAG_UPDATE_ONE',
|
||||
item: tag,
|
||||
});
|
||||
return tag;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,42 +1,18 @@
|
||||
const Folder = require('lib/models/Folder');
|
||||
const Note = require('lib/models/Note');
|
||||
const Tag = require('lib/models/Tag');
|
||||
|
||||
function randomIndex(array:any[]):number {
|
||||
return Math.round(Math.random() * (array.length - 1));
|
||||
}
|
||||
|
||||
function randomIndexes(arrayLength:number, count:number):number[] {
|
||||
const arr = [];
|
||||
while (arr.length < count) {
|
||||
const r = Math.floor(Math.random() * arrayLength);
|
||||
if (arr.indexOf(r) === -1) arr.push(r);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function randomElements(array:any[], count:number):any[] {
|
||||
const indexes = randomIndexes(array.length, count);
|
||||
const output = [];
|
||||
for (const index of indexes) {
|
||||
output.push(array[index]);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Use the constants below to define how many folders, notes and tags
|
||||
// should be created.
|
||||
export default async function populateDatabase(db:any) {
|
||||
await db.clearForTesting();
|
||||
|
||||
const folderCount = 200;
|
||||
const noteCount = 1000;
|
||||
const tagCount = 5000;
|
||||
const tagsPerNote = 10;
|
||||
const folderCount = 2000;
|
||||
const noteCount = 20000;
|
||||
|
||||
const createdFolderIds:string[] = [];
|
||||
const createdNoteIds:string[] = [];
|
||||
const createdTagIds:string[] = [];
|
||||
|
||||
for (let i = 0; i < folderCount; i++) {
|
||||
const folder:any = {
|
||||
@@ -56,24 +32,6 @@ export default async function populateDatabase(db:any) {
|
||||
console.info(`Folders: ${i} / ${folderCount}`);
|
||||
}
|
||||
|
||||
let tagBatch = [];
|
||||
for (let i = 0; i < tagCount; i++) {
|
||||
tagBatch.push(Tag.save({ title: `tag${i}` }, { dispatchUpdateAction: false }).then((savedTag:any) => {
|
||||
createdTagIds.push(savedTag.id);
|
||||
console.info(`Tags: ${i} / ${tagCount}`);
|
||||
}));
|
||||
|
||||
if (tagBatch.length > 1000) {
|
||||
await Promise.all(tagBatch);
|
||||
tagBatch = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (tagBatch.length) {
|
||||
await Promise.all(tagBatch);
|
||||
tagBatch = [];
|
||||
}
|
||||
|
||||
let noteBatch = [];
|
||||
for (let i = 0; i < noteCount; i++) {
|
||||
const note:any = { title: `note${i}`, body: `This is note num. ${i}` };
|
||||
@@ -95,20 +53,4 @@ export default async function populateDatabase(db:any) {
|
||||
await Promise.all(noteBatch);
|
||||
noteBatch = [];
|
||||
}
|
||||
|
||||
let noteTagBatch = [];
|
||||
for (const noteId of createdNoteIds) {
|
||||
const tagIds = randomElements(createdTagIds, tagsPerNote);
|
||||
noteTagBatch.push(Tag.setNoteTagsByIds(noteId, tagIds));
|
||||
|
||||
if (noteTagBatch.length > 1000) {
|
||||
await Promise.all(noteTagBatch);
|
||||
noteTagBatch = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (noteTagBatch.length) {
|
||||
await Promise.all(noteTagBatch);
|
||||
noteTagBatch = [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user