opened file change detection now useable on all note types

This commit is contained in:
zadam 2021-04-24 21:56:44 +02:00
parent dcd35b1ea2
commit ccac46527c
13 changed files with 100 additions and 49 deletions

View File

@ -36,6 +36,7 @@ import SearchResultWidget from "../widgets/search_result.js";
import SyncStatusWidget from "../widgets/sync_status.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import RootContainer from "../widgets/containers/root_container.js";
import NoteUpdateStatusWidget from "../widgets/note_update_status.js";
const RIGHT_PANE_CSS = `
<style>
@ -177,6 +178,7 @@ export default class DesktopLayout {
.child(new InheritedAttributesWidget())
)
)
.child(new NoteUpdateStatusWidget())
.child(
new TabCachingWidget(() => new ScrollingContainer()
.child(new SqlTableSchemasWidget())

View File

@ -11,6 +11,10 @@ function fileModificationUploaded(noteId) {
delete fileModificationStatus[noteId];
}
function ignoreModification(noteId) {
delete fileModificationStatus[noteId];
}
ws.subscribeToMessages(async message => {
if (message.type !== 'openedFileUpdated') {
return;
@ -27,5 +31,6 @@ ws.subscribeToMessages(async message => {
export default {
getFileModificationStatus,
fileModificationUploaded
fileModificationUploaded,
ignoreModification
}

View File

@ -44,7 +44,7 @@ async function getRenderedContent(note, options = {}) {
const $openButton = $('<button class="file-open btn btn-primary" type="button">Open</button>');
$downloadButton.on('click', () => openService.downloadFileNote(note.noteId));
$openButton.on('click', () => openService.openFileNote(note.noteId));
$openButton.on('click', () => openService.openNoteExternally(note.noteId));
// open doesn't work for protected notes since it works through browser which isn't in protected session
$openButton.toggle(!note.isProtected);

View File

@ -21,9 +21,9 @@ function downloadFileNote(noteId) {
download(url);
}
async function openFileNote(noteId) {
async function openNoteExternally(noteId) {
if (utils.isElectron()) {
const resp = await server.post("notes/" + noteId + "/saveToTmpDir");
const resp = await server.post("notes/" + noteId + "/save-to-tmp-dir");
const electron = utils.dynamicRequire('electron');
const res = await electron.shell.openPath(resp.tmpFilePath);
@ -66,7 +66,7 @@ function getHost() {
export default {
download,
downloadFileNote,
openFileNote,
openNoteExternally,
downloadNoteRevision,
getUrlForDownload
}

View File

@ -1,11 +1,12 @@
import TabAwareWidget from "./tab_aware_widget.js";
import protectedSessionService from "../services/protected_session.js";
import openService from "../services/open.js";
const TPL = `
<div class="dropdown note-actions">
<style>
.note-actions .dropdown-menu {
width: 15em;
width: 20em;
}
.note-actions .dropdown-item[disabled], .note-actions .dropdown-item[disabled]:hover {
@ -84,6 +85,7 @@ const TPL = `
<a data-trigger-command="showNoteRevisions" class="dropdown-item show-note-revisions-button">Revisions</a>
<a data-trigger-command="showLinkMap" class="dropdown-item show-link-map-button"><kbd data-command="showLinkMap"></kbd> Link map</a>
<a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a>
<a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a>
<a class="dropdown-item import-files-button">Import files</a>
<a class="dropdown-item export-note-button">Export note</a>
<a data-trigger-command="printActiveNote" class="dropdown-item print-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a>
@ -119,6 +121,9 @@ export default class NoteActionsWidget extends TabAwareWidget {
this.$widget.on('click', '.dropdown-item',
() => this.$widget.find('.dropdown-toggle').dropdown('toggle'));
this.$openNoteExternallyButton = this.$widget.find(".open-note-externally-button");
this.$openNoteExternallyButton.on('click', () => openService.openNoteExternally(this.noteId));
}
refreshWithNote(note) {

View File

@ -0,0 +1,64 @@
import TabAwareWidget from "./tab_aware_widget.js";
import server from "../services/server.js";
import fileWatcher from "../services/file_watcher.js";
const TPL = `
<div class="dropdown note-update-status-widget alert alert-warning">
<style>
.note-update-status-widget {
margin: 10px;
}
</style>
<p>File <code class="file-path"></code> has been last modified on <span class="file-last-modified"></span>.</p>
<div style="display: flex; flex-direction: row; justify-content: space-evenly;">
<button class="btn btn-sm file-upload-button">Upload modified file</button>
<button class="btn btn-sm ignore-this-change-button">Ignore this change</button>
</div>
</div>`;
export default class NoteUpdateStatusWidget extends TabAwareWidget {
isEnabled() {
return super.isEnabled()
&& !!fileWatcher.getFileModificationStatus(this.noteId);
}
doRender() {
this.$widget = $(TPL);
this.overflowing();
this.$filePath = this.$widget.find(".file-path");
this.$fileLastModified = this.$widget.find(".file-last-modified");
this.$fileUploadButton = this.$widget.find(".file-upload-button");
this.$fileUploadButton.on("click", async () => {
await server.post(`notes/${this.noteId}/upload-modified-file`, {
filePath: this.$filePath.text()
});
fileWatcher.fileModificationUploaded(this.noteId);
this.refresh();
});
this.$ignoreThisChangeButton = this.$widget.find(".ignore-this-change-button");
this.$ignoreThisChangeButton.on('click', () => {
fileWatcher.ignoreModification(this.noteId);
this.refresh();
});
}
refreshWithNote(note) {
const status = fileWatcher.getFileModificationStatus(note.noteId);
this.$filePath.text(status.filePath);
this.$fileLastModified.text(dayjs.unix(status.lastModifiedMs / 1000).format("HH:mm:ss"));
}
openedFileUpdatedEvent(data) {
if (data.noteId === this.noteId) {
this.refresh();
}
}
}

View File

@ -82,7 +82,7 @@ export default class FilePropertiesWidget extends TabAwareWidget {
this.$uploadNewRevisionInput = this.$widget.find(".file-upload-new-revision-input");
this.$downloadButton.on('click', () => openService.downloadFileNote(this.noteId));
this.$openButton.on('click', () => openService.openFileNote(this.noteId));
this.$openButton.on('click', () => openService.openNoteExternally(this.noteId));
this.$uploadNewRevisionButton.on("click", () => {
this.$uploadNewRevisionInput.trigger("click");

View File

@ -26,6 +26,8 @@ const TPL = `
<div class="no-print" style="display: flex; justify-content: space-evenly; margin: 10px;">
<button class="image-download btn btn-sm btn-primary" type="button">Download</button>
<button class="image-open btn btn-sm btn-primary" type="button">Open</button>
<button class="image-copy-to-clipboard btn btn-sm btn-primary" type="button">Copy to clipboard</button>
<button class="image-upload-new-revision btn btn-sm btn-primary" type="button">Upload new revision</button>
@ -59,6 +61,9 @@ export default class ImagePropertiesWidget extends TabAwareWidget {
this.$fileType = this.$widget.find(".image-filetype");
this.$fileSize = this.$widget.find(".image-filesize");
this.$openButton = this.$widget.find(".image-open");
this.$openButton.on('click', () => openService.openNoteExternally(this.noteId));
this.$imageDownloadButton = this.$widget.find(".image-download");
this.$imageDownloadButton.on('click', () => openService.downloadFileNote(this.noteId));

View File

@ -24,12 +24,6 @@ const TPL = `
}
</style>
<div class="file-watcher-wrapper alert alert-warning">
<p>File <code class="file-watcher-path"></code> has been last modified on <span class="file-watcher-last-modified"></span>.</p>
<button class="btn btn-sm file-watcher-upload-button">Upload modified file</button>
</div>
<pre class="file-preview-content"></pre>
<div class="file-preview-not-available alert alert-info">
@ -54,22 +48,6 @@ export default class FileTypeWidget extends TypeWidget {
this.$pdfPreview = this.$widget.find(".pdf-preview");
this.$videoPreview = this.$widget.find(".video-preview");
this.$audioPreview = this.$widget.find(".audio-preview");
this.$fileWatcherWrapper = this.$widget.find(".file-watcher-wrapper");
this.$fileWatcherWrapper.hide();
this.$fileWatcherPath = this.$widget.find(".file-watcher-path");
this.$fileWatcherLastModified = this.$widget.find(".file-watcher-last-modified");
this.$fileWatcherUploadButton = this.$widget.find(".file-watcher-upload-button");
this.$fileWatcherUploadButton.on("click", async () => {
await server.post(`notes/${this.noteId}/upload-modified-file`, {
filePath: this.$fileWatcherPath.text()
});
fileWatcher.fileModificationUploaded(this.noteId);
this.refreshFileWatchingStatus();
});
}
async doRefresh(note) {
@ -107,22 +85,5 @@ export default class FileTypeWidget extends TypeWidget {
else {
this.$previewNotAvailable.show();
}
this.refreshFileWatchingStatus();
}
refreshFileWatchingStatus() {
const status = fileWatcher.getFileModificationStatus(this.noteId);
this.$fileWatcherWrapper.toggle(!!status);
if (status) {
this.$fileWatcherPath.text(status.filePath);
this.$fileWatcherLastModified.text(dayjs.unix(status.lastModifiedMs / 1000).format("HH:mm:ss"));
}
}
openedFileUpdatedEvent(data) {
this.refreshFileWatchingStatus();
}
}

View File

@ -3,6 +3,7 @@
const protectedSessionService = require('../../services/protected_session');
const repository = require('../../services/repository');
const utils = require('../../services/utils');
const log = require('../../services/log');
const noteRevisionService = require('../../services/note_revisions');
const tmp = require('tmp');
const fs = require('fs');
@ -122,6 +123,8 @@ function saveToTmpDir(req) {
fs.writeSync(tmpObj.fd, note.getContent());
fs.closeSync(tmpObj.fd);
log.info(`Saved temporary file for note ${noteId} into ${tmpObj.name}`);
if (utils.isElectron()) {
chokidar.watch(tmpObj.name).on('change', (path, stats) => {
ws.sendMessageToAllClients({
@ -130,8 +133,6 @@ function saveToTmpDir(req) {
lastModifiedMs: stats.atimeMs,
filePath: tmpObj.name
});
console.log(stats, path);
});
}

View File

@ -285,6 +285,8 @@ function uploadModifiedFile(req) {
return [404, `Note ${noteId} has not been found`];
}
log.info(`Updating note ${noteId} with content from ${filePath}`);
noteRevisionService.createNoteRevision(note);
const fileContent = fs.readFileSync(filePath);

View File

@ -186,7 +186,7 @@ function register(app) {
route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile);
// this "hacky" path is used for easier referencing of CSS resources
route(GET, '/api/notes/download/:noteId', [auth.checkApiAuthOrElectron], filesRoute.downloadFile);
apiRoute(POST, '/api/notes/:noteId/saveToTmpDir', filesRoute.saveToTmpDir);
apiRoute(POST, '/api/notes/:noteId/save-to-tmp-dir', filesRoute.saveToTmpDir);
apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes);
apiRoute(POST, '/api/notes/:noteId/attributes', attributesRoute.addNoteAttribute);

View File

@ -352,6 +352,12 @@ const DEFAULT_KEYBOARD_ACTIONS = [
defaultShortcuts: [],
scope: "window"
},
{
actionName: "openNoteExternally",
defaultShortcuts: [],
description: "Open note as a file with default application",
scope: "window"
},
{
actionName: "renderActiveNote",
defaultShortcuts: [],