diff --git a/src/common_functions.js b/src/common_functions.js index 736202f6..e580ef7d 100644 --- a/src/common_functions.js +++ b/src/common_functions.js @@ -29,6 +29,11 @@ export function b64ToUni(bytes) { return new TextDecoder().decode(base64ToBytes(bytes)) } +export function areStringsEqual(str1, str2) { + const retVal = str1.localeCompare(str2) + return retVal === 0 +} + //////////////// expand, collapse and show or hide the children of the node //////////// export function showNode(node) { if (node) { @@ -185,4 +190,4 @@ export function isValidEmail(email) { return re.test(email) } -export default { uniTob64, b64ToUni, expandNode, collapseNode, showNode, hideNode, addToArray, createId, createLoadEventText, dedup, getLocationInfo, getSprintById, getSprintNameById, localTimeAndMilis, removeFromArray, isValidEmail } +export default { uniTob64, b64ToUni, areStringsEqual, expandNode, collapseNode, showNode, hideNode, addToArray, createId, createLoadEventText, dedup, getLocationInfo, getSprintById, getSprintNameById, localTimeAndMilis, removeFromArray, isValidEmail } diff --git a/src/components/admin/admin.js b/src/components/admin/admin.js index 16bd8498..894317b3 100644 --- a/src/components/admin/admin.js +++ b/src/components/admin/admin.js @@ -1,5 +1,5 @@ import { STATE, LEVEL } from '../../constants.js' -import { createId } from '../../common_functions.js' +import { uniTob64, createId } from '../../common_functions.js' import common_admin from './common_admin' import store from '../../store/store.js' @@ -81,8 +81,8 @@ const methods = { reqarea: null, title: this.productTitle, followers: [], - description: window.btoa(''), - acceptanceCriteria: window.btoa('
Please do not neglect
'), + description: uniTob64('Please do not neglect
'), priority, comments: [{ ignoreEvent: 'comments initiated', diff --git a/src/components/views/coarse_product/c_product_view.js b/src/components/views/coarse_product/c_product_view.js index 78d2c0f1..be6a952a 100644 --- a/src/components/views/coarse_product/c_product_view.js +++ b/src/components/views/coarse_product/c_product_view.js @@ -103,25 +103,24 @@ const methods = { /* Event handling */ onNodesSelected(fromContextMenu) { - // update explicitly as the tree is not receiving focus due to the "user-select: none" css setting causing that @blur on the editor is not emitted - if (this.isDescriptionEdited) this.updateDescription(this.getPreviousNodeSelected) - if (this.isAcceptanceEdited) this.updateAcceptance(this.getPreviousNodeSelected) - // load the document - store.dispatch('loadDoc', { - id: this.getLastSelectedNode._id, - onSuccessCallback: () => { - // preset the req area color if available - this.selReqAreaColor = this.getLastSelectedNode.data.reqAreaItemColor - // if the user clicked on a node of another product (not root) - if (this.getLastSelectedNode._id !== 'root' && store.state.currentProductId !== this.getLastSelectedNode.productId) { - // update current productId and title - store.commit('switchCurrentProduct', this.getLastSelectedNode.productId) - } - if (this.getLastSelectedNode._id !== 'requirement-areas') { - if (!fromContextMenu) this.showSelectionEvent(store.state.selectedNodes) - } else this.showLastEvent('Create / maintain Requirement Areas here', SEV.INFO) + const onSuccessCallback = () => { + // preset the req area color if available + this.selReqAreaColor = this.getLastSelectedNode.data.reqAreaItemColor + // if the user clicked on a node of another product (not root) + if (this.getLastSelectedNode._id !== 'root' && store.state.currentProductId !== this.getLastSelectedNode.productId) { + // update current productId and title + store.commit('switchCurrentProduct', this.getLastSelectedNode.productId) } - }) + if (this.getLastSelectedNode._id !== 'requirement-areas') { + if (!fromContextMenu) this.showSelectionEvent(store.state.selectedNodes) + } else this.showLastEvent('Create / maintain Requirement Areas here', SEV.INFO) + } + + // update explicitly as the tree is not receiving focus due to the "user-select: none" css setting causing that @blur on the editor is not emitted + if (this.isDescriptionEdited) { this.updateDescription({ node: this.getPreviousNodeSelected, cb: onSuccessCallback }) } else + if (this.isAcceptanceEdited) { this.updateAcceptance({ node: this.getPreviousNodeSelected, cb: onSuccessCallback }) } else + // load the selected document + store.dispatch('loadDoc', { id: this.getLastSelectedNode._id, onSuccessCallback }) }, /* Use this event to check if the drag is allowed. If not, issue a warning */ diff --git a/src/components/views/coarse_product/c_product_view.vue b/src/components/views/coarse_product/c_product_view.vue index 2d77817d..5f9c31ee 100644 --- a/src/components/views/coarse_product/c_product_view.vue +++ b/src/components/views/coarse_product/c_product_view.vue @@ -60,7 +60,7 @@Please do not neglect
') : uniTob64('See the acceptance criteria of the story/spike/defect.
'), priority: newNode.data.priority, comments: [{ diff --git a/src/components/views/common_listings.vue b/src/components/views/common_listings.vue index 57e36b7f..5d002880 100644 --- a/src/components/views/common_listings.vue +++ b/src/components/views/common_listings.vue @@ -91,8 +91,8 @@ function data() { editMyComment: false, editMyHistComment: false, commentObjToBeReplaced: {}, - myLastCommentText: "", - myLastHistCommentText: "" + myLastCommentText: "Database root document
'), - acceptanceCriteria: window.btoa('not applicable
'), + description: uniTob64('Database root document
'), + acceptanceCriteria: uniTob64('not applicable
'), priority: 0, comments: [{ ignoreEvent: 'comments initiated', @@ -579,8 +579,8 @@ const actions = { spikepersonhours: 0, title: 'REQUIREMENT AREAS', followers: [], - description: window.btoa('To insert one or more requirement areas inside this node right-click on this nodes title in the tree view.
'), - acceptanceCriteria: window.btoa('n/a
'), + description: uniTob64('To insert one or more requirement areas inside this node right-click on this nodes title in the tree view.
'), + acceptanceCriteria: uniTob64('n/a
'), // do not set a priority, must be null comments: [{ ignoreEvent: 'comments initiated', @@ -625,8 +625,8 @@ const actions = { reqarea: null, title, followers: [], - description: window.btoa(''), - acceptanceCriteria: window.btoa('Please do not neglect
'), + description: uniTob64('Please do not neglect
'), priority: 0, comments: [{ ignoreEvent: 'comments initiated', diff --git a/src/store/modules/planningboard.js b/src/store/modules/planningboard.js index 4df6a77b..e0235d0a 100644 --- a/src/store/modules/planningboard.js +++ b/src/store/modules/planningboard.js @@ -1,5 +1,5 @@ import { SEV, LEVEL, STATE } from '../../constants.js' -import { expandNode, getSprintNameById } from '../../common_functions.js' +import { expandNode, getSprintNameById, uniTob64 } from '../../common_functions.js' import globalAxios from 'axios' // IMPORTANT: all updates on the backlogitem documents must add history in order for the changes feed to work properly (if omitted the previous event will be processed again) // Save the history, to trigger the distribution to other online users, when all other database updates are done. @@ -1011,8 +1011,8 @@ const actions = { conditionalFor: [], title: payload.taskTitle, followers: storyDoc.followers || [], - description: window.btoa(''), - acceptanceCriteria: window.btoa('See the acceptance criteria of the story/spike/defect.
'), + description: uniTob64('See the acceptance criteria of the story/spike/defect.
'), priority: taskPriority, comments: [{ ignoreEvent: 'comments initiated', diff --git a/src/store/modules/update.js b/src/store/modules/update.js index 9e526cd7..a89f77d7 100644 --- a/src/store/modules/update.js +++ b/src/store/modules/update.js @@ -735,32 +735,37 @@ const actions = { const prevLastContentChange = tmpDoc.lastContentChange || 0 tmpDoc.lastContentChange = payload.timestamp tmpDoc.lastChange = payload.timestamp - tmpDoc.description = newEncodedDescription + + const onSuccessCallback = () => { + rootState.isDescriptionEdited = false + commit('updateNodesAndCurrentDoc', { node, description: payload.newDescription, lastContentChange: payload.timestamp, newHist }) + if (!payload.isUndoAction || payload.isUndoAction === undefined) { + commit('addToEventList', { txt: `The description of item with short id ${id.slice(-5)} is changed`, severity: SEV.INFO }) + // create an entry for undoing the change in a last-in first-out sequence + const entry = { + node, + type: 'undoDescriptionChange', + oldDescription, + prevLastContentChange + } + rootState.changeHistory.unshift(entry) + } else { + commit('addToEventList', { txt: 'Change of the item description is undone', severity: SEV.INFO }) + rootState.busyWithLastUndo = false + } + } + + const onFailureCallback = () => { + if (payload.isUndoAction) rootState.busyWithLastUndo = false + } + dispatch('updateDoc', { dbName: rootState.userData.currentDb, updatedDoc: tmpDoc, caller: 'saveDescription', - onSuccessCallback: () => { - commit('updateNodesAndCurrentDoc', { node, description: payload.newDescription, lastContentChange: payload.timestamp, newHist }) - if (!payload.isUndoAction || payload.isUndoAction === undefined) { - commit('addToEventList', { txt: `The description of item with short id ${id.slice(-5)} is changed`, severity: SEV.INFO }) - // create an entry for undoing the change in a last-in first-out sequence - const entry = { - node, - type: 'undoDescriptionChange', - oldDescription, - prevLastContentChange - } - rootState.changeHistory.unshift(entry) - } else { - commit('addToEventList', { txt: 'Change of the item description is undone', severity: SEV.INFO }) - rootState.busyWithLastUndo = false - } - }, - onFailureCallback: () => { - if (payload.isUndoAction) rootState.busyWithLastUndo = false - }, + onSuccessCallback, + onFailureCallback, toDispatch: payload.toDispatch }) }).catch(error => { @@ -799,32 +804,37 @@ const actions = { const prevLastContentChange = tmpDoc.lastContentChange || 0 tmpDoc.lastContentChange = payload.timestamp tmpDoc.lastChange = payload.timestamp - tmpDoc.acceptanceCriteria = newEncodedAcceptance + + const onSuccessCallback = () => { + rootState.isAcceptanceEdited = false + commit('updateNodesAndCurrentDoc', { node, acceptanceCriteria: payload.newAcceptance, lastContentChange: payload.timestamp, newHist }) + if (!payload.isUndoAction || payload.isUndoAction === undefined) { + commit('addToEventList', { txt: `The acceptance criteria of item with short id ${id.slice(-5)} are changed`, severity: SEV.INFO }) + // create an entry for undoing the change in a last-in first-out sequence + const entry = { + node, + type: 'undoAcceptanceChange', + oldAcceptance, + prevLastContentChange + } + rootState.changeHistory.unshift(entry) + } else { + commit('addToEventList', { txt: 'Change of the item acceptance criteria is undone', severity: SEV.INFO }) + rootState.busyWithLastUndo = false + } + } + + const onFailureCallback = () => { + if (payload.isUndoAction) rootState.busyWithLastUndo = false + } + dispatch('updateDoc', { dbName: rootState.userData.currentDb, updatedDoc: tmpDoc, caller: 'saveAcceptance', - onSuccessCallback: () => { - commit('updateNodesAndCurrentDoc', { node, acceptanceCriteria: payload.newAcceptance, lastContentChange: payload.timestamp, newHist }) - if (!payload.isUndoAction || payload.isUndoAction === undefined) { - commit('addToEventList', { txt: `The acceptance criteria of item with short id ${id.slice(-5)} are changed`, severity: SEV.INFO }) - // create an entry for undoing the change in a last-in first-out sequence - const entry = { - node, - type: 'undoAcceptanceChange', - oldAcceptance, - prevLastContentChange - } - rootState.changeHistory.unshift(entry) - } else { - commit('addToEventList', { txt: 'Change of the item acceptance criteria is undone', severity: SEV.INFO }) - rootState.busyWithLastUndo = false - } - }, - onFailureCallback: () => { - if (payload.isUndoAction) rootState.busyWithLastUndo = false - }, + onSuccessCallback, + onFailureCallback, toDispatch: payload.toDispatch }) }).catch(error => { @@ -1076,6 +1086,7 @@ const actions = { /* * Create or update an existing document by creating a new revision. + * Must call loadDoc on success to update the current doc visable to the user. * Executes a onSuccessCallback and onFailureCallback if provided in the payload. */ updateDoc({