From e1b67e20ec66b0d295fe567d21baeb68ad23c72a Mon Sep 17 00:00:00 2001 From: dymani Date: Tue, 30 May 2023 02:24:56 +0800 Subject: [PATCH 1/7] Add buttons to move split panes --- src/public/app/layouts/desktop_layout.js | 3 + .../app/widgets/buttons/move_pane_button.js | 55 +++++++++++++++++++ .../containers/split_note_container.js | 38 +++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/public/app/widgets/buttons/move_pane_button.js diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js index 17dcc99a79..62e6b3ed1f 100644 --- a/src/public/app/layouts/desktop_layout.js +++ b/src/public/app/layouts/desktop_layout.js @@ -75,6 +75,7 @@ import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js"; import ApiLogWidget from "../widgets/api_log.js"; import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js"; import ScriptExecutorWidget from "../widgets/ribbon_widgets/script_executor.js"; +import MovePaneButton from "../widgets/buttons/move_pane_button.js"; export default class DesktopLayout { constructor(customWidgets) { @@ -123,6 +124,8 @@ export default class DesktopLayout { .child(new NoteIconWidget()) .child(new NoteTitleWidget()) .child(new SpacerWidget(0, 1)) + .child(new MovePaneButton(true)) + .child(new MovePaneButton(false)) .child(new ClosePaneButton()) .child(new CreatePaneButton()) ) diff --git a/src/public/app/widgets/buttons/move_pane_button.js b/src/public/app/widgets/buttons/move_pane_button.js new file mode 100644 index 0000000000..9ea4dbe61b --- /dev/null +++ b/src/public/app/widgets/buttons/move_pane_button.js @@ -0,0 +1,55 @@ +import OnClickButtonWidget from "./onclick_button.js"; +import appContext from "../../components/app_context.js"; + +export default class MovePaneButton extends OnClickButtonWidget { + isEnabled() { + if (!super.isEnabled()) + return false; + + if (this.isMovingLeft) { + // movable if the current context is not a main context, i.e. non-null mainNtxId + return !!this.noteContext?.mainNtxId; + } else { + const currentIndex = appContext.tabManager.noteContexts.findIndex(c => c.ntxId === this.ntxId); + const nextContext = appContext.tabManager.noteContexts[currentIndex + 1]; + // movable if the next context is not null and not a main context, i.e. non-null mainNtxId + return !!nextContext?.mainNtxId; + } + } + + initialRenderCompleteEvent() { + this.refresh(); + super.initialRenderCompleteEvent(); + } + + async noteContextRemovedEvent({ntxIds}) { + this.refresh(); + } + + async newNoteContextCreatedEvent({noteContext}) { + this.refresh(); + } + + async noteContextSwitchEvent() { + this.refresh(); + } + + async noteContextReorderEvent({ntxIdsInOrder}) { + this.refresh(); + } + + constructor(isMovingLeft) { + super(); + + this.isMovingLeft = isMovingLeft; + + this.icon(isMovingLeft ? "bx-chevron-left" : "bx-chevron-right") + .title(isMovingLeft ? "Move left" : "Move right") + .titlePlacement("bottom") + .onClick(async (widget, e) => { + e.stopPropagation(); + widget.triggerCommand("moveThisNoteSplit", {ntxId: widget.getClosestNtxId(), isMovingLeft: this.isMovingLeft}); + }) + .class("icon-action"); + } +} diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 66356164d2..854ccfd23c 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -1,5 +1,6 @@ import FlexContainer from "./flex_container.js"; import appContext from "../../components/app_context.js"; +import NoteContext from "../../components/note_context.js"; export default class SplitNoteContainer extends FlexContainer { constructor(widgetFactory) { @@ -74,6 +75,43 @@ export default class SplitNoteContainer extends FlexContainer { appContext.tabManager.removeNoteContext(ntxId); } + async moveThisNoteSplitCommand({ntxId, isMovingLeft}) { + if (!ntxId) { + logError("empty ntxId!"); + return; + } + + const contexts = appContext.tabManager.noteContexts; + + const currentIndex = contexts.findIndex(c => c.ntxId === ntxId); + const otherIndex = currentIndex + (isMovingLeft ? -1 : 1); + + if (currentIndex === -1 || otherIndex < 0 || otherIndex >= contexts.length) { + logError("invalid context!"); + return; + } + + if (contexts[currentIndex].isEmpty() && contexts[otherIndex].isEmpty()) + // no op + return; + + const currentId = contexts[currentIndex].ntxId; + const currentPath = contexts[currentIndex].notePath; + + const otherId = contexts[otherIndex].ntxId; + const otherPath = contexts[otherIndex].notePath; + + if (!!currentPath) + await appContext.tabManager.switchToNoteContext(otherId, currentPath); + if (!!otherPath) + await appContext.tabManager.switchToNoteContext(currentId, otherPath); + + // activate context that now contains the original note + await appContext.tabManager.activateNoteContext(otherId); + + this.triggerEvent('noteContextSwitch'); + } + activeContextChangedEvent() { this.refresh(); } From 2a399069936bb3e0c094ca52ebbad493ed529122 Mon Sep 17 00:00:00 2001 From: dymani Date: Tue, 30 May 2023 04:22:51 +0800 Subject: [PATCH 2/7] Cleanup --- src/public/app/widgets/containers/split_note_container.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 854ccfd23c..3a17b7d20f 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -1,6 +1,5 @@ import FlexContainer from "./flex_container.js"; import appContext from "../../components/app_context.js"; -import NoteContext from "../../components/note_context.js"; export default class SplitNoteContainer extends FlexContainer { constructor(widgetFactory) { From 735852b3c1dc9d642bfc01f603b1f84aec9e9e1b Mon Sep 17 00:00:00 2001 From: dymani Date: Wed, 31 May 2023 01:53:55 +0800 Subject: [PATCH 3/7] Use noteContextReorder event instead --- src/public/app/components/tab_manager.js | 13 ++++--- .../app/widgets/buttons/close_pane_button.js | 4 +++ .../containers/split_note_container.js | 36 ++++++++++--------- src/public/app/widgets/tab_row.js | 16 +++++++++ 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js index e5ca32c452..ace30105f3 100644 --- a/src/public/app/components/tab_manager.js +++ b/src/public/app/components/tab_manager.js @@ -451,16 +451,15 @@ export default class TabManager extends Component { this.tabsUpdate.scheduleUpdate(); } - noteContextReorderEvent({ntxIdsInOrder}) { - const order = {}; - let i = 0; - - for (const ntxId of ntxIdsInOrder) { - order[ntxId] = i++; - } + noteContextReorderEvent({ntxIdsInOrder, mainNtxIdsInOrder}) { + const order = Object.fromEntries(ntxIdsInOrder.map((v, i) => [v, i])); this.children.sort((a, b) => order[a.ntxId] < order[b.ntxId] ? -1 : 1); + if (!!mainNtxIdsInOrder && mainNtxIdsInOrder.length === this.children.length) { + this.children.forEach((c, i) => c.mainNtxId = mainNtxIdsInOrder[i]); + } + this.tabsUpdate.scheduleUpdate(); } diff --git a/src/public/app/widgets/buttons/close_pane_button.js b/src/public/app/widgets/buttons/close_pane_button.js index 690dcac6f9..220fd2cca2 100644 --- a/src/public/app/widgets/buttons/close_pane_button.js +++ b/src/public/app/widgets/buttons/close_pane_button.js @@ -7,6 +7,10 @@ export default class ClosePaneButton extends OnClickButtonWidget { && this.noteContext && !!this.noteContext.mainNtxId; } + async noteContextReorderEvent({ntxIdsInOrder}) { + this.refresh(); + } + constructor() { super(); diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 3a17b7d20f..988c537b19 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -83,32 +83,36 @@ export default class SplitNoteContainer extends FlexContainer { const contexts = appContext.tabManager.noteContexts; const currentIndex = contexts.findIndex(c => c.ntxId === ntxId); - const otherIndex = currentIndex + (isMovingLeft ? -1 : 1); + const leftIndex = isMovingLeft ? currentIndex - 1 : currentIndex; - if (currentIndex === -1 || otherIndex < 0 || otherIndex >= contexts.length) { + if (currentIndex === -1 || leftIndex < 0 || leftIndex + 1 >= contexts.length) { logError("invalid context!"); return; } - if (contexts[currentIndex].isEmpty() && contexts[otherIndex].isEmpty()) + if (contexts[leftIndex].isEmpty() && contexts[leftIndex + 1].isEmpty()) // no op return; - const currentId = contexts[currentIndex].ntxId; - const currentPath = contexts[currentIndex].notePath; - - const otherId = contexts[otherIndex].ntxId; - const otherPath = contexts[otherIndex].notePath; - - if (!!currentPath) - await appContext.tabManager.switchToNoteContext(otherId, currentPath); - if (!!otherPath) - await appContext.tabManager.switchToNoteContext(currentId, otherPath); + const ntxIds = contexts.map(c => c.ntxId); + const mainNtxIds = contexts.map(c => c.mainNtxId); + + this.triggerCommand("noteContextReorder", { + ntxIdsInOrder: [ + ...ntxIds.slice(0, leftIndex), + ntxIds[leftIndex + 1], + ntxIds[leftIndex], + ...ntxIds.slice(leftIndex + 2), + ], + oldNtxIdsInOrder: ntxIds, + mainNtxIdsInOrder: mainNtxIds.map(id => id === ntxIds[leftIndex] ? ntxIds[leftIndex + 1] : id) + }); + + this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex]}"]`) + .insertAfter(this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex + 1]}"]`)); // activate context that now contains the original note - await appContext.tabManager.activateNoteContext(otherId); - - this.triggerEvent('noteContextSwitch'); + await appContext.tabManager.activateNoteContext(isMovingLeft ? ntxIds[leftIndex + 1] : ntxIds[leftIndex]); } activeContextChangedEvent() { diff --git a/src/public/app/widgets/tab_row.js b/src/public/app/widgets/tab_row.js index 55a5da24ca..6e15f3458f 100644 --- a/src/public/app/widgets/tab_row.js +++ b/src/public/app/widgets/tab_row.js @@ -609,6 +609,22 @@ export default class TabRowWidget extends BasicWidget { this.updateTabById(noteContext.mainNtxId || noteContext.ntxId); } + noteContextReorderEvent({ntxIdsInOrder, oldNtxIdsInOrder, mainNtxIdsInOrder}) { + if (!oldNtxIdsInOrder || !mainNtxIdsInOrder + || ntxIdsInOrder.length !== oldNtxIdsInOrder.length + || ntxIdsInOrder.length !== mainNtxIdsInOrder.length + ) + return; + + ntxIdsInOrder.forEach((id, i) => { + // update main context that is not a tab + if (!mainNtxIdsInOrder[i] && this.getTabById(id).length === 0) { + this.getTabById(oldNtxIdsInOrder[i]).attr("data-ntx-id", id); + this.updateTabById(id); + } + }); + } + updateTabById(ntxId) { const $tab = this.getTabById(ntxId); From 58253567cd55a72a86252cd6237d8b1a46ebc996 Mon Sep 17 00:00:00 2001 From: dymani Date: Thu, 1 Jun 2023 00:48:37 +0800 Subject: [PATCH 4/7] Simplify noteContextReorder event call --- src/public/app/components/tab_manager.js | 14 +++- .../app/widgets/buttons/move_pane_button.js | 64 ++++++++----------- .../containers/split_note_container.js | 25 ++++---- src/public/app/widgets/tab_row.js | 19 ++---- 4 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js index ace30105f3..53c3ccbbd2 100644 --- a/src/public/app/components/tab_manager.js +++ b/src/public/app/components/tab_manager.js @@ -451,13 +451,21 @@ export default class TabManager extends Component { this.tabsUpdate.scheduleUpdate(); } - noteContextReorderEvent({ntxIdsInOrder, mainNtxIdsInOrder}) { + noteContextReorderEvent({ntxIdsInOrder, oldMainNtxId, newMainNtxId}) { const order = Object.fromEntries(ntxIdsInOrder.map((v, i) => [v, i])); this.children.sort((a, b) => order[a.ntxId] < order[b.ntxId] ? -1 : 1); - if (!!mainNtxIdsInOrder && mainNtxIdsInOrder.length === this.children.length) { - this.children.forEach((c, i) => c.mainNtxId = mainNtxIdsInOrder[i]); + if (oldMainNtxId && newMainNtxId) { + this.children.forEach(c => { + if (c.ntxId === newMainNtxId) { + // new main context has null mainNtxId + c.mainNtxId = null; + } else if (c.ntxId === oldMainNtxId || c.mainNtxId === oldMainNtxId) { + // old main context or subcontexts all have the new mainNtxId + c.mainNtxId = newMainNtxId; + } + }); } this.tabsUpdate.scheduleUpdate(); diff --git a/src/public/app/widgets/buttons/move_pane_button.js b/src/public/app/widgets/buttons/move_pane_button.js index 9ea4dbe61b..632651ca5f 100644 --- a/src/public/app/widgets/buttons/move_pane_button.js +++ b/src/public/app/widgets/buttons/move_pane_button.js @@ -2,42 +2,6 @@ import OnClickButtonWidget from "./onclick_button.js"; import appContext from "../../components/app_context.js"; export default class MovePaneButton extends OnClickButtonWidget { - isEnabled() { - if (!super.isEnabled()) - return false; - - if (this.isMovingLeft) { - // movable if the current context is not a main context, i.e. non-null mainNtxId - return !!this.noteContext?.mainNtxId; - } else { - const currentIndex = appContext.tabManager.noteContexts.findIndex(c => c.ntxId === this.ntxId); - const nextContext = appContext.tabManager.noteContexts[currentIndex + 1]; - // movable if the next context is not null and not a main context, i.e. non-null mainNtxId - return !!nextContext?.mainNtxId; - } - } - - initialRenderCompleteEvent() { - this.refresh(); - super.initialRenderCompleteEvent(); - } - - async noteContextRemovedEvent({ntxIds}) { - this.refresh(); - } - - async newNoteContextCreatedEvent({noteContext}) { - this.refresh(); - } - - async noteContextSwitchEvent() { - this.refresh(); - } - - async noteContextReorderEvent({ntxIdsInOrder}) { - this.refresh(); - } - constructor(isMovingLeft) { super(); @@ -52,4 +16,32 @@ export default class MovePaneButton extends OnClickButtonWidget { }) .class("icon-action"); } + + isEnabled() { + if (!super.isEnabled()) { + return false; + } + + if (this.isMovingLeft) { + // movable if the current context is not a main context, i.e. non-null mainNtxId + return !!this.noteContext?.mainNtxId; + } else { + const currentIndex = appContext.tabManager.noteContexts.findIndex(c => c.ntxId === this.ntxId); + const nextContext = appContext.tabManager.noteContexts[currentIndex + 1]; + // movable if the next context is not null and not a main context, i.e. non-null mainNtxId + return !!nextContext?.mainNtxId; + } + } + + async noteContextRemovedEvent() { + this.refresh(); + } + + async newNoteContextCreatedEvent() { + this.refresh(); + } + + async noteContextReorderEvent() { + this.refresh(); + } } diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 988c537b19..0188add6d7 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -86,28 +86,31 @@ export default class SplitNoteContainer extends FlexContainer { const leftIndex = isMovingLeft ? currentIndex - 1 : currentIndex; if (currentIndex === -1 || leftIndex < 0 || leftIndex + 1 >= contexts.length) { - logError("invalid context!"); + logError(`invalid context! currentIndex: ${currentIndex}, leftIndex: ${leftIndex}, contexts.length: ${contexts.length}`); return; } - if (contexts[leftIndex].isEmpty() && contexts[leftIndex + 1].isEmpty()) + if (contexts[leftIndex].isEmpty() && contexts[leftIndex + 1].isEmpty()) { // no op return; + } const ntxIds = contexts.map(c => c.ntxId); - const mainNtxIds = contexts.map(c => c.mainNtxId); + const newNtxIds = [ + ...ntxIds.slice(0, leftIndex), + ntxIds[leftIndex + 1], + ntxIds[leftIndex], + ...ntxIds.slice(leftIndex + 2), + ]; + const isChangingMainContext = !contexts[leftIndex].mainNtxId; this.triggerCommand("noteContextReorder", { - ntxIdsInOrder: [ - ...ntxIds.slice(0, leftIndex), - ntxIds[leftIndex + 1], - ntxIds[leftIndex], - ...ntxIds.slice(leftIndex + 2), - ], - oldNtxIdsInOrder: ntxIds, - mainNtxIdsInOrder: mainNtxIds.map(id => id === ntxIds[leftIndex] ? ntxIds[leftIndex + 1] : id) + ntxIdsInOrder: newNtxIds, + oldMainNtxId: isChangingMainContext ? ntxIds[leftIndex] : null, + newMainNtxId: isChangingMainContext ? ntxIds[leftIndex + 1]: null, }); + // reorder the note context widgets this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex]}"]`) .insertAfter(this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex + 1]}"]`)); diff --git a/src/public/app/widgets/tab_row.js b/src/public/app/widgets/tab_row.js index 6e15f3458f..9081ed9e1d 100644 --- a/src/public/app/widgets/tab_row.js +++ b/src/public/app/widgets/tab_row.js @@ -609,20 +609,15 @@ export default class TabRowWidget extends BasicWidget { this.updateTabById(noteContext.mainNtxId || noteContext.ntxId); } - noteContextReorderEvent({ntxIdsInOrder, oldNtxIdsInOrder, mainNtxIdsInOrder}) { - if (!oldNtxIdsInOrder || !mainNtxIdsInOrder - || ntxIdsInOrder.length !== oldNtxIdsInOrder.length - || ntxIdsInOrder.length !== mainNtxIdsInOrder.length - ) + noteContextReorderEvent({oldMainNtxId, newMainNtxId}) { + if (!oldMainNtxId || !newMainNtxId) { + // no need to update tab row return; + } - ntxIdsInOrder.forEach((id, i) => { - // update main context that is not a tab - if (!mainNtxIdsInOrder[i] && this.getTabById(id).length === 0) { - this.getTabById(oldNtxIdsInOrder[i]).attr("data-ntx-id", id); - this.updateTabById(id); - } - }); + // update tab id for the new main context + this.getTabById(oldMainNtxId).attr("data-ntx-id", newMainNtxId); + this.updateTabById(newMainNtxId); } updateTabById(ntxId) { From 7e71029d1ccde2a16a3ab9ed073c2e9872f73999 Mon Sep 17 00:00:00 2001 From: zadam Date: Fri, 2 Jun 2023 16:05:02 +0200 Subject: [PATCH 5/7] use note size format also in file properties --- src/public/app/services/frontend_script_api.js | 7 +++++++ src/public/app/services/utils.js | 14 +++++++++++++- .../widgets/ribbon_widgets/file_properties.js | 2 +- .../widgets/ribbon_widgets/note_info_widget.js | 18 ++++-------------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/public/app/services/frontend_script_api.js b/src/public/app/services/frontend_script_api.js index 98d4e84601..a7b2b14676 100644 --- a/src/public/app/services/frontend_script_api.js +++ b/src/public/app/services/frontend_script_api.js @@ -483,6 +483,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain */ this.randomString = utils.randomString; + /** + * @method + * @param {int} size in bytes + * @return {string} formatted string + */ + this.formatNoteSize = utils.formatNoteSize; + this.logMessages = {}; this.logSpacedUpdates = {}; diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js index e0ef2d767c..bf468c5788 100644 --- a/src/public/app/services/utils.js +++ b/src/public/app/services/utils.js @@ -354,6 +354,17 @@ function escapeRegExp(str) { return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); } +function formatNoteSize(size) { + size = Math.max(Math.round(size / 1024), 1); + + if (size < 1024) { + return `${size} KiB`; + } + else { + return `${Math.round(size / 102.4) / 10} MiB`; + } +} + export default { reloadFrontendApp, parseDate, @@ -396,5 +407,6 @@ export default { filterAttributeName, isValidAttributeName, sleep, - escapeRegExp + escapeRegExp, + formatNoteSize }; diff --git a/src/public/app/widgets/ribbon_widgets/file_properties.js b/src/public/app/widgets/ribbon_widgets/file_properties.js index 454c73f1d8..afa0511684 100644 --- a/src/public/app/widgets/ribbon_widgets/file_properties.js +++ b/src/public/app/widgets/ribbon_widgets/file_properties.js @@ -136,7 +136,7 @@ export default class FilePropertiesWidget extends NoteContextAwareWidget { const noteComplement = await this.noteContext.getNoteComplement(); - this.$fileSize.text(`${noteComplement.contentLength} bytes`); + this.$fileSize.text(utils.formatNoteSize(noteComplement.contentLength)); // open doesn't work for protected notes since it works through browser which isn't in protected session this.$openButton.toggle(!note.isProtected); diff --git a/src/public/app/widgets/ribbon_widgets/note_info_widget.js b/src/public/app/widgets/ribbon_widgets/note_info_widget.js index 28459da5db..3b7756cf79 100644 --- a/src/public/app/widgets/ribbon_widgets/note_info_widget.js +++ b/src/public/app/widgets/ribbon_widgets/note_info_widget.js @@ -1,5 +1,6 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js"; import server from "../../services/server.js"; +import utils from "../../services/utils.js"; const TPL = `
@@ -105,12 +106,12 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { this.$subTreeSize.empty().append($('')); const noteSizeResp = await server.get(`stats/note-size/${this.noteId}`); - this.$noteSize.text(this.formatSize(noteSizeResp.noteSize)); + this.$noteSize.text(utils.formatNoteSize(noteSizeResp.noteSize)); const subTreeResp = await server.get(`stats/subtree-size/${this.noteId}`); if (subTreeResp.subTreeNoteCount > 1) { - this.$subTreeSize.text(`(subtree size: ${this.formatSize(subTreeResp.subTreeSize)} in ${subTreeResp.subTreeNoteCount} notes)`); + this.$subTreeSize.text(`(subtree size: ${utils.formatNoteSize(subTreeResp.subTreeSize)} in ${subTreeResp.subTreeNoteCount} notes)`); } else { this.$subTreeSize.text(""); @@ -142,18 +143,7 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { this.$calculateButton.show(); this.$noteSizesWrapper.hide(); } - - formatSize(size) { - size = Math.max(Math.round(size / 1024), 1); - - if (size < 1024) { - return `${size} KiB`; - } - else { - return `${Math.round(size / 102.4) / 10} MiB`; - } - } - + entitiesReloadedEvent({loadResults}) { if (loadResults.isNoteReloaded(this.noteId) || loadResults.isNoteContentReloaded(this.noteId)) { this.refresh(); From c4f69fd9cbcc9dff08aa7cb2b38a1fc151d30e34 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 3 Jun 2023 00:21:46 +0200 Subject: [PATCH 6/7] don't allow patching relation's value in ETAPI #3998 --- src/etapi/attributes.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/etapi/attributes.js b/src/etapi/attributes.js index 6886e08454..fb8b2ad999 100644 --- a/src/etapi/attributes.js +++ b/src/etapi/attributes.js @@ -40,19 +40,25 @@ function register(router) { } }); - const ALLOWED_PROPERTIES_FOR_PATCH = { + const ALLOWED_PROPERTIES_FOR_PATCH_LABEL = { 'value': [v.notNull, v.isString], 'position': [v.notNull, v.isInteger] }; + const ALLOWED_PROPERTIES_FOR_PATCH_RELATION = { + 'position': [v.notNull, v.isInteger] + }; + eu.route(router, 'patch' ,'/etapi/attributes/:attributeId', (req, res, next) => { const attribute = eu.getAndCheckAttribute(req.params.attributeId); - if (attribute.type === 'relation') { + if (attribute.type === 'label') { + eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH_LABEL); + } else if (attribute.type === 'relation') { eu.getAndCheckNote(req.body.value); - } - eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH); + eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH_RELATION); + } attribute.save(); From d3bf325f19f9a45bf4a0559fdc11f6b8959b1d0c Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 3 Jun 2023 00:32:16 +0200 Subject: [PATCH 7/7] added some comments to openapi spec --- src/etapi/etapi.openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etapi/etapi.openapi.yaml b/src/etapi/etapi.openapi.yaml index 974acbdfe3..7c41693d1e 100644 --- a/src/etapi/etapi.openapi.yaml +++ b/src/etapi/etapi.openapi.yaml @@ -374,7 +374,7 @@ paths: schema: $ref: '#/components/schemas/Error' patch: - description: patch a branch identified by the branchId with changes in the body + description: patch a branch identified by the branchId with changes in the body. Only prefix and notePosition can be updated. If you want to update other properties, you need to delete the old branch and create a new one. operationId: patchBranchById requestBody: required: true @@ -456,7 +456,7 @@ paths: schema: $ref: '#/components/schemas/Error' patch: - description: patch a attribute identified by the attributeId with changes in the body + description: patch a attribute identified by the attributeId with changes in the body. For labels, only value and position can be updated. For relations, only position can be updated. If you want to modify other properties, you need to delete the old attribute and create a new one. operationId: patchAttributeById requestBody: required: true