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 17dcc99a7..62e6b3ed1 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 000000000..9ea4dbe61 --- /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 66356164d..854ccfd23 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 854ccfd23..3a17b7d20 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 e5ca32c45..ace30105f 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 690dcac6f..220fd2cca 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 3a17b7d20..988c537b1 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 55a5da24c..6e15f3458 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 ace30105f..53c3ccbbd 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 9ea4dbe61..632651ca5 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 988c537b1..0188add6d 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 6e15f3458..9081ed9e1 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 98d4e8460..a7b2b1467 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 e0ef2d767..bf468c578 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 454c73f1d..afa051168 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 28459da5d..3b7756cf7 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 6886e0845..fb8b2ad99 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 974acbdfe..7c41693d1 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