Merge branch '004-server-history-support' into develop

This commit is contained in:
Baptiste Grob
2020-08-14 17:55:25 +02:00
8 changed files with 263 additions and 181 deletions

View File

@@ -45,7 +45,7 @@ import {
PrivilegesAuthModal,
PrivilegesManagementModal,
RevisionPreviewModal,
SessionHistoryMenu,
HistoryMenu,
SyncResolutionMenu
} from './directives/views';
@@ -110,7 +110,7 @@ function startApplication(platform: Platform) {
.directive('privilegesAuthModal', () => new PrivilegesAuthModal())
.directive('privilegesManagementModal', () => new PrivilegesManagementModal())
.directive('revisionPreviewModal', () => new RevisionPreviewModal())
.directive('sessionHistoryMenu', () => new SessionHistoryMenu())
.directive('historyMenu', () => new HistoryMenu())
.directive('syncResolutionMenu', () => new SyncResolutionMenu());
// Filters

View File

@@ -0,0 +1,191 @@
import { WebDirective } from '../../types';
import { WebApplication } from '@/ui_models/application';
import template from '%/directives/history-menu.pug';
import { SNItem, ItemHistoryEntry } from '@node_modules/snjs/dist/@types';
import { PureViewCtrl } from '@/views';
import { ItemSessionHistory } from 'snjs/dist/@types/services/history/session/item_session_history';
import { RemoteHistoryList, RemoteHistoryListEntry } from 'snjs/dist/@types/services/history/history_manager';
import { confirmDialog } from '@/services/alertService';
type HistoryState = {
fetchingRemoteHistory: boolean
}
interface HistoryScope {
application: WebApplication
item: SNItem
}
class HistoryMenuCtrl extends PureViewCtrl<{}, HistoryState> implements HistoryScope {
diskEnabled = false
autoOptimize = false
application!: WebApplication
item!: SNItem
sessionHistory?: ItemSessionHistory
remoteHistory?: RemoteHistoryList
/* @ngInject */
constructor(
$timeout: ng.ITimeoutService
) {
super($timeout);
this.state = {
fetchingRemoteHistory: false
};
}
$onInit() {
super.$onInit();
this.reloadSessionHistory();
this.fetchRemoteHistory();
this.diskEnabled = this.application.historyManager!.isDiskEnabled();
this.autoOptimize = this.application.historyManager!.isAutoOptimizeEnabled();
}
reloadSessionHistory() {
this.sessionHistory = this.application.historyManager!.sessionHistoryForItem(this.item);
}
get isfetchingRemoteHistory() {
return this.state.fetchingRemoteHistory;
}
set fetchingRemoteHistory(value: boolean) {
this.setState({
fetchingRemoteHistory: value
});
}
async fetchRemoteHistory() {
this.fetchingRemoteHistory = true;
this.remoteHistory = await this.application.historyManager!.remoteHistoryForItem(this.item)
.finally(() => {
this.fetchingRemoteHistory = false;
});
}
async openSessionRevision(revision: ItemHistoryEntry) {
this.application.presentRevisionPreviewModal(
revision.payload.uuid,
revision.payload.content
);
}
async openRemoteRevision(revision: RemoteHistoryListEntry) {
this.fetchingRemoteHistory = true;
const remoteRevision = await this.application.historyManager!.fetchRemoteRevision(this.item.uuid, revision);
this.fetchingRemoteHistory = false;
if (!remoteRevision) {
this.application.alertService!.alert("The remote revision could not be loaded. Please try again later.");
return;
}
this.application.presentRevisionPreviewModal(
remoteRevision.payload.uuid,
remoteRevision.payload.content
);
}
classForSessionRevision(revision: ItemHistoryEntry) {
const vector = revision.operationVector();
if (vector === 0) {
return 'default';
} else if (vector === 1) {
return 'success';
} else if (vector === -1) {
return 'danger';
}
}
clearItemSessionHistory() {
confirmDialog({
text: "Are you sure you want to delete the local session history for this note?",
confirmButtonStyle: "danger"
}).then((confirmed) => {
if (!confirmed) {
return;
}
this.application.historyManager!.clearHistoryForItem(this.item).then(() => {
this.$timeout(() => {
this.reloadSessionHistory();
});
});
});
}
clearAllSessionHistory() {
confirmDialog({
text: "Are you sure you want to delete the local session history for all notes?",
confirmButtonStyle: "danger"
}).then((confirmed) => {
if (!confirmed) {
return;
}
this.application.historyManager!.clearAllHistory().then(() => {
this.$timeout(() => {
this.reloadSessionHistory();
});
});
});
}
get sessionHistoryEntries() {
return this.sessionHistory?.entries;
}
get remoteHistoryEntries() {
return this.remoteHistory;
}
toggleSessionHistoryDiskSaving() {
const run = () => {
this.application.historyManager!.toggleDiskSaving().then(() => {
this.$timeout(() => {
this.diskEnabled = this.application.historyManager!.isDiskEnabled();
});
});
};
if (!this.application.historyManager!.isDiskEnabled()) {
confirmDialog({
text: "Are you sure you want to save history to disk? This will decrease general " +
"performance, especially as you type. You are advised to disable this feature " +
"if you experience any lagging.",
confirmButtonStyle: "danger"
}).then((confirmed) => {
if (confirmed) {
run();
}
});
} else {
run();
}
}
toggleSessionHistoryAutoOptimize() {
this.application.historyManager!.toggleAutoOptimize().then(() => {
this.$timeout(() => {
this.autoOptimize = this.application.historyManager!.autoOptimize;
});
});
}
previewRemoteHistoryTitle(revision: RemoteHistoryListEntry) {
const createdAt = revision.created_at!;
return new Date(createdAt).toLocaleString();
}
}
export class HistoryMenu extends WebDirective {
constructor() {
super();
this.restrict = 'E';
this.template = template;
this.controller = HistoryMenuCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
this.scope = {
item: '=',
application: '='
};
}
}

View File

@@ -11,5 +11,5 @@ export { PermissionsModal } from './permissionsModal';
export { PrivilegesAuthModal } from './privilegesAuthModal';
export { PrivilegesManagementModal } from './privilegesManagementModal';
export { RevisionPreviewModal } from './revisionPreviewModal';
export { SessionHistoryMenu } from './sessionHistoryMenu';
export { HistoryMenu } from './historyMenu';
export { SyncResolutionMenu } from './syncResolutionMenu';

View File

@@ -89,7 +89,7 @@ class RevisionPreviewModalCtrl implements RevisionPreviewScope {
}
}
async restore(asCopy: boolean) {
restore(asCopy: boolean) {
const run = async () => {
if (asCopy) {
const contentCopy = Object.assign({}, this.content);
@@ -110,12 +110,14 @@ class RevisionPreviewModalCtrl implements RevisionPreviewScope {
};
if (!asCopy) {
if (await confirmDialog({
confirmDialog({
text: "Are you sure you want to replace the current note's contents with what you see in this preview?",
confirmButtonStyle: 'danger',
})) {
run();
}
confirmButtonStyle: "danger"
}).then((confirmed) => {
if (confirmed) {
run();
}
});
} else {
run();
}

View File

@@ -1,131 +0,0 @@
import { WebDirective } from './../../types';
import { WebApplication } from '@/ui_models/application';
import template from '%/directives/session-history-menu.pug';
import { SNItem, ItemHistoryEntry, ItemHistory } from '@node_modules/snjs/dist/@types';
import { confirmDialog } from '@/services/alertService';
interface SessionHistoryScope {
application: WebApplication
item: SNItem
}
class SessionHistoryMenuCtrl implements SessionHistoryScope {
$timeout: ng.ITimeoutService
diskEnabled = false
autoOptimize = false
application!: WebApplication
item!: SNItem
entries!: ItemHistoryEntry[]
history!: ItemHistory
/* @ngInject */
constructor(
$timeout: ng.ITimeoutService
) {
this.$timeout = $timeout;
}
$onInit() {
this.reloadHistory();
this.diskEnabled = this.application.historyManager!.isDiskEnabled();
this.autoOptimize = this.application.historyManager!.isAutoOptimizeEnabled();
}
reloadHistory() {
const history = this.application.historyManager!.historyForItem(this.item);
this.entries = history.entries.slice(0).sort((a, b) => {
return a.payload.updated_at! < b.payload.updated_at! ? 1 : -1;
});
this.history = history;
}
openRevision(revision: ItemHistoryEntry) {
this.application.presentRevisionPreviewModal(
revision.payload.uuid,
revision.payload.content
);
}
classForRevision(revision: ItemHistoryEntry) {
const vector = revision.operationVector();
if (vector === 0) {
return 'default';
} else if (vector === 1) {
return 'success';
} else if (vector === -1) {
return 'danger';
}
}
async clearItemHistory() {
if (await confirmDialog({
text: "Are you sure you want to delete the local session history for this note?",
confirmButtonStyle: 'danger',
})) {
this.application.historyManager!.clearHistoryForItem(this.item).then(() => {
this.$timeout(() => {
this.reloadHistory();
});
});
}
}
clearAllHistory() {
if (confirmDialog({
text: "Are you sure you want to delete the local session history for all notes?",
confirmButtonStyle: 'danger'
})) {
this.application.historyManager!.clearAllHistory().then(() => {
this.$timeout(() => {
this.reloadHistory();
});
});
}
}
async toggleDiskSaving() {
const run = () => {
this.application.historyManager!.toggleDiskSaving().then(() => {
this.$timeout(() => {
this.diskEnabled = this.application.historyManager!.isDiskEnabled();
});
});
};
if (!this.application.historyManager!.isDiskEnabled()) {
if (await confirmDialog({
text: `Are you sure you want to save history to disk? This will decrease general
performance, especially as you type. You are advised to disable this feature
if you experience any lagging.`,
confirmButtonStyle: 'danger',
})) {
run();
}
} else {
run();
}
}
toggleAutoOptimize() {
this.application.historyManager!.toggleAutoOptimize().then(() => {
this.$timeout(() => {
this.autoOptimize = this.application.historyManager!.autoOptimize;
});
});
}
}
export class SessionHistoryMenu extends WebDirective {
constructor() {
super();
this.restrict = 'E';
this.template = template;
this.controller = SessionHistoryMenuCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
this.scope = {
item: '=',
application: '='
};
}
}

View File

@@ -183,14 +183,14 @@
application='self.application'
)
.sk-app-bar-item(
click-outside=`self.setMenuState('showSessionHistory', false)`,
is-open='self.state.showSessionHistory',
ng-click="self.toggleMenu('showSessionHistory')"
click-outside=`self.setMenuState('showHistory', false)`,
is-open='self.state.showHistory',
ng-click="self.toggleMenu('showHistory')"
)
.sk-label Session History
session-history-menu(
.sk-label History
history-menu(
item='self.note',
ng-if='self.state.showSessionHistory',
ng-if='self.state.showHistory',
application='self.application'
)
#editor-content.editor-content(ng-if='!self.note.errorDecrypting')

View File

@@ -0,0 +1,55 @@
#history-menu.sn-component
.sk-menu-panel.dropdown-menu
.sk-menu-panel-header
.sk-menu-panel-header-title Session
.sk-menu-panel-header-subtitle {{ctrl.sessionHistoryEntries.length || 'No'}} revisions
a.sk-a.info.sk-h5(
ng-click='ctrl.showSessionOptions = !ctrl.showSessionOptions; $event.stopPropagation();'
) Options
div(ng-if='ctrl.showSessionOptions')
menu-row(
action='ctrl.clearItemSessionHistory()'
label="'Clear note local history'"
)
menu-row(
action='ctrl.clearAllSessionHistory()'
label="'Clear all local history'"
)
menu-row(
action='ctrl.toggleSessionHistoryAutoOptimize()'
label="(ctrl.autoOptimize ? 'Disable' : 'Enable') + ' auto cleanup'")
.sk-sublabel
| Automatically cleans up small revisions to conserve space.
menu-row(
action='ctrl.toggleSessionHistoryDiskSaving()'
label="(ctrl.diskEnabled ? 'Disable' : 'Enable') + ' saving history to disk'"
)
.sk-sublabel
| Saving to disk is not recommended. Decreases performance and increases app
| loading time and memory footprint.
menu-row(
ng-repeat='revision in ctrl.sessionHistoryEntries track by $index'
action='ctrl.openSessionRevision(revision);'
label='revision.previewTitle()'
)
.sk-sublabel.opaque(ng-class='ctrl.classForSessionRevision(revision)')
| {{revision.previewSubTitle()}}
.sk-menu-panel-header
.sk-menu-panel-header-title Remote
.sk-menu-panel-header-subtitle {{ctrl.remoteHistoryEntries.length || 'No'}} revisions
a.sk-a.info.sk-h5(
ng-click='ctrl.showRemoteOptions = !ctrl.showRemoteOptions; $event.stopPropagation();'
) Options
div(ng-if='ctrl.showRemoteOptions')
menu-row(
action='ctrl.fetchRemoteHistory()'
label="'Refresh'"
disabled="ctrl.isfetchingRemoteHistory"
spinner-class="ctrl.isfetchingRemoteHistory ? 'info' : null")
.sk-sublabel
| Fetch history from server.
menu-row(
ng-repeat='revision in ctrl.remoteHistoryEntries track by $index'
action='ctrl.openRemoteRevision(revision);'
label='ctrl.previewRemoteHistoryTitle(revision);'
)

View File

@@ -1,35 +0,0 @@
#session-history-menu.sn-component
.sk-menu-panel.dropdown-menu
.sk-menu-panel-header
.sk-menu-panel-header-title {{ctrl.history.entries.length || 'No'}} revisions
a.sk-a.info.sk-h5(
ng-click='ctrl.showOptions = !ctrl.showOptions; $event.stopPropagation();'
) Options
div(ng-if='ctrl.showOptions')
menu-row(
action='ctrl.clearItemHistory()'
label="'Clear note local history'"
)
menu-row(
action='ctrl.clearAllHistory()'
label="'Clear all local history'"
)
menu-row(
action='ctrl.toggleAutoOptimize()'
label="(ctrl.autoOptimize ? 'Disable' : 'Enable') + ' auto cleanup'")
.sk-sublabel
| Automatically cleans up small revisions to conserve space.
menu-row(
action='ctrl.toggleDiskSaving()'
label="(ctrl.diskEnabled ? 'Disable' : 'Enable') + ' saving history to disk'"
)
.sk-sublabel
| Saving to disk is not recommended. Decreases performance and increases app
| loading time and memory footprint.
menu-row(
ng-repeat='revision in ctrl.entries'
action='ctrl.openRevision(revision);'
label='revision.previewTitle()'
)
.sk-sublabel.opaque(ng-class='ctrl.classForRevision(revision)')
| {{revision.previewSubTitle()}}