1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

All: Handling of unsyncable items

This commit is contained in:
Laurent Cozic 2017-12-05 18:56:39 +00:00
parent 4d5c4b1743
commit c703521b6c
10 changed files with 189 additions and 53 deletions

View File

@ -259,6 +259,14 @@ class Application extends BaseApplication {
}, { }, {
label: _('Tools'), label: _('Tools'),
submenu: [{ submenu: [{
label: _('Synchronisation status'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'Status',
});
}
},{
label: _('Options'), label: _('Options'),
click: () => { click: () => {
this.dispatch({ this.dispatch({

View File

@ -338,17 +338,17 @@ class MainScreenComponent extends React.Component {
const onViewDisabledItemsClick = () => { const onViewDisabledItemsClick = () => {
this.props.dispatch({ this.props.dispatch({
type: 'NAV_GO', type: 'NAV_GO',
routeName: 'SyncDisabledItems', routeName: 'Status',
}); });
} }
const messageComp = ( const messageComp = this.props.hasDisabledSyncItems ? (
<div style={styles.messageBox}> <div style={styles.messageBox}>
<span style={theme.textStyle}> <span style={theme.textStyle}>
{_('Some items cannot be synchronised.')} <a href="#" onClick={() => { onViewDisabledItemsClick() }}>{_('View them now')}</a> {_('Some items cannot be synchronised.')} <a href="#" onClick={() => { onViewDisabledItemsClick() }}>{_('View them now')}</a>
</span> </span>
</div> </div>
); ) : null;
return ( return (
<div style={style}> <div style={style}>
@ -381,6 +381,7 @@ const mapStateToProps = (state) => {
noteVisiblePanes: state.noteVisiblePanes, noteVisiblePanes: state.noteVisiblePanes,
folders: state.folders, folders: state.folders,
notes: state.notes, notes: state.notes,
hasDisabledSyncItems: state.hasDisabledSyncItems,
}; };
}; };

View File

@ -8,7 +8,7 @@ const { Setting } = require('lib/models/setting.js');
const { MainScreen } = require('./MainScreen.min.js'); const { MainScreen } = require('./MainScreen.min.js');
const { OneDriveLoginScreen } = require('./OneDriveLoginScreen.min.js'); const { OneDriveLoginScreen } = require('./OneDriveLoginScreen.min.js');
const { SyncDisabledItemsScreen } = require('./SyncDisabledItemsScreen.min.js'); const { StatusScreen } = require('./StatusScreen.min.js');
const { ImportScreen } = require('./ImportScreen.min.js'); const { ImportScreen } = require('./ImportScreen.min.js');
const { ConfigScreen } = require('./ConfigScreen.min.js'); const { ConfigScreen } = require('./ConfigScreen.min.js');
const { Navigator } = require('./Navigator.min.js'); const { Navigator } = require('./Navigator.min.js');
@ -76,7 +76,7 @@ class RootComponent extends React.Component {
OneDriveLogin: { screen: OneDriveLoginScreen, title: () => _('OneDrive Login') }, OneDriveLogin: { screen: OneDriveLoginScreen, title: () => _('OneDrive Login') },
Import: { screen: ImportScreen, title: () => _('Import') }, Import: { screen: ImportScreen, title: () => _('Import') },
Config: { screen: ConfigScreen, title: () => _('Options') }, Config: { screen: ConfigScreen, title: () => _('Options') },
SyncDisabledItems: { screen: SyncDisabledItemsScreen, title: () => _('Items that cannot be synchronised') }, Status: { screen: StatusScreen, title: () => _('Synchronisation Status') },
}; };
return ( return (

View File

@ -0,0 +1,147 @@
const React = require('react');
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
const { Setting } = require('lib/models/setting.js');
const { bridge } = require('electron').remote.require('./bridge');
const { Header } = require('./Header.min.js');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
const { ReportService } = require('lib/services/report.js');
const { BaseItem } = require('lib/models/base-item.js');
class StatusScreenComponent extends React.Component {
constructor() {
super();
this.state = {
report: [],
disabledItems: [],
};
}
componentWillMount() {
this.resfreshScreen();
}
async resfreshScreen() {
const service = new ReportService();
const report = await service.status(Setting.value('sync.target'));
const disabledItems = await BaseItem.syncDisabledItems();
this.setState({
report: report,
disabledItems: disabledItems,
});
}
render() {
const theme = themeStyle(this.props.theme);
const style = this.props.style;
const headerStyle = {
width: style.width,
};
const containerPadding = 10;
const containerStyle = {
padding: containerPadding,
overflowY: 'auto',
height: style.height - theme.headerHeight - containerPadding * 2,
};
function renderSectionTitleHtml(key, title) {
return <h2 key={'section_' + key} style={theme.h2Style}>{title}</h2>
}
function renderSectionHtml(key, section) {
let itemsHtml = [];
itemsHtml.push(renderSectionTitleHtml(section.title, section.title));
for (let n in section.body) {
if (!section.body.hasOwnProperty(n)) continue;
itemsHtml.push(<div style={theme.textStyle} key={'item_' + n}>{section.body[n]}</div>);
}
return (
<div key={key}>
{itemsHtml}
</div>
);
}
function renderBodyHtml(report, disabledItems) {
let output = [];
let baseStyle = {
paddingLeft: 6,
paddingRight: 6,
paddingTop: 2,
paddingBottom: 2,
flex: 0,
color: theme.color,
fontSize: theme.fontSize,
};
let sectionsHtml = [];
if (disabledItems.length) {
const titleHtml = [renderSectionTitleHtml('disabled_sync_items', _('Items that cannot be synchronised'))];
const trsHtml = [];
for (let i = 0; i < disabledItems.length; i++) {
const row = disabledItems[i];
trsHtml.push(<tr key={'item_' + i}><td style={theme.textStyle}>{row.item.title}</td><td style={theme.textStyle}>{row.syncInfo.sync_disabled_reason}</td></tr>);
}
sectionsHtml.push(
<div key={'disabled_sync_items'}>
{titleHtml}
<table>
<tbody>
<tr><th style={theme.textStyle}>{_('Name')}</th><th style={theme.textStyle}>{_('Reason')}</th></tr>
{trsHtml}
</tbody>
</table>
</div>
);
}
for (let i = 0; i < report.length; i++) {
let section = report[i];
if (!section.body.length) continue;
sectionsHtml.push(renderSectionHtml(i, section));
}
return (
<div>
{sectionsHtml}
</div>
);
}
console.info(this.state.disabledItems);
let body = renderBodyHtml(this.state.report, this.state.disabledItems);
return (
<div style={style}>
<Header style={headerStyle} />
<div style={containerStyle}>
{body}
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
theme: state.settings.theme,
settings: state.settings,
locale: state.settings.locale,
};
};
const StatusScreen = connect(mapStateToProps)(StatusScreenComponent);
module.exports = { StatusScreen };

View File

@ -1,45 +0,0 @@
const React = require('react');
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
const { Setting } = require('lib/models/setting.js');
const { bridge } = require('electron').remote.require('./bridge');
const { Header } = require('./Header.min.js');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
class SyncDisabledItemsScreenComponent extends React.Component {
render() {
const theme = themeStyle(this.props.theme);
const style = this.props.style;
const headerStyle = {
width: style.width,
};
const containerStyle = {
padding: 10,
};
return (
<div style={style}>
<Header style={headerStyle} />
<div style={containerStyle}>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
theme: state.settings.theme,
settings: state.settings,
locale: state.settings.locale,
};
};
const SyncDisabledItemsScreen = connect(mapStateToProps)(SyncDisabledItemsScreenComponent);
module.exports = { SyncDisabledItemsScreen };

View File

@ -9,6 +9,19 @@ body, textarea {
overflow: hidden; overflow: hidden;
} }
table {
border-collapse: collapse;
}
table th {
text-align: left;
}
table td, table th {
padding: .5em;
border: 1px solid #ccc;
}
/* By default, the Ice Editor displays invalid characters, such as non-breaking spaces /* By default, the Ice Editor displays invalid characters, such as non-breaking spaces
as red boxes, but since those are actually valid characters and common in imported as red boxes, but since those are actually valid characters and common in imported
Evernote data, we hide them here. */ Evernote data, we hide them here. */

View File

@ -71,6 +71,9 @@ globalStyle.textStyle2 = Object.assign({}, globalStyle.textStyle, {
color: globalStyle.color2, color: globalStyle.color2,
}); });
globalStyle.h2Style = Object.assign({}, globalStyle.textStyle);
globalStyle.h2Style.fontSize *= 1.3;
let themeCache_ = {}; let themeCache_ = {};
function themeStyle(theme) { function themeStyle(theme) {

View File

@ -387,7 +387,8 @@ class BaseItem extends BaseModel {
const rows = await this.db().selectAll('SELECT * FROM sync_items WHERE sync_disabled = 1'); const rows = await this.db().selectAll('SELECT * FROM sync_items WHERE sync_disabled = 1');
let output = []; let output = [];
for (let i = 0; i < rows.length; i++) { for (let i = 0; i < rows.length; i++) {
const item = await this.loadItem(rows[i].item_type, rows[i].id); const item = await this.loadItem(rows[i].item_type, rows[i].item_id);
if (!item) continue; // The referenced item no longer exist
output.push({ output.push({
syncInfo: rows[i], syncInfo: rows[i],
item: item, item: item,

View File

@ -25,7 +25,8 @@ const defaultState = {
searchQuery: '', searchQuery: '',
settings: {}, settings: {},
appState: 'starting', appState: 'starting',
windowContentSize: { width: 0, height: 0 }, //windowContentSize: { width: 0, height: 0 },
hasDisabledSyncItems: false,
}; };
// When deleting a note, tag or folder // When deleting a note, tag or folder
@ -395,6 +396,12 @@ const reducer = (state = defaultState, action) => {
newState.appState = action.state; newState.appState = action.state;
break; break;
case 'SYNC_HAS_DISABLED_SYNC_ITEMS':
newState = Object.assign({}, state);
newState.hasDisabledSyncItems = true;
break;
} }
} catch (error) { } catch (error) {
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action); error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);

View File

@ -253,8 +253,9 @@ class Synchronizer {
this.logSyncOperation(action, local, remote, reason); this.logSyncOperation(action, local, remote, reason);
async function handleCannotSyncItem(syncTargetId, item, cannotSyncReason) { const handleCannotSyncItem = async (syncTargetId, item, cannotSyncReason) => {
await ItemClass.saveSyncDisabled(syncTargetId, item, cannotSyncReason); await ItemClass.saveSyncDisabled(syncTargetId, item, cannotSyncReason);
this.dispatch({ type: 'SYNC_HAS_DISABLED_SYNC_ITEMS' });
} }
if (local.type_ == BaseModel.TYPE_RESOURCE && (action == 'createRemote' || (action == 'itemConflict' && remote))) { if (local.type_ == BaseModel.TYPE_RESOURCE && (action == 'createRemote' || (action == 'itemConflict' && remote))) {