diff --git a/client/components/editor.vue b/client/components/editor.vue index 7cd577b1..48b7f563 100644 --- a/client/components/editor.vue +++ b/client/components/editor.vue @@ -86,7 +86,8 @@ export default { editorModalMedia: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-media.vue'), editorModalBlocks: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-blocks.vue'), editorModalConflict: () => import(/* webpackChunkName: "editor-conflict", webpackMode: "lazy" */ './editor/editor-modal-conflict.vue'), - editorModalDrawio: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-drawio.vue') + editorModalDrawio: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-drawio.vue'), + editorModalMaturityMatrix: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-maturitymatrix.vue') }, props: { locale: { diff --git a/client/components/editor/editor-markdown.vue b/client/components/editor/editor-markdown.vue index 80a21284..fad1cda6 100644 --- a/client/components/editor/editor-markdown.vue +++ b/client/components/editor/editor-markdown.vue @@ -127,6 +127,11 @@ v-btn.mt-3.animated.fadeInLeft.wait-p2s(icon, tile, v-on='on', dark, @click='toggleModal(`editorModalDrawio`)').mx-0 v-icon mdi-chart-multiline span {{$t('editor:markup.insertDiagram')}} + v-tooltip(right, color='teal') + template(v-slot:activator='{ on }') + v-btn.mt-3.animated.fadeInLeft.wait-p3s(icon, tile, v-on='on', dark, @click='openMaturityMatrix').mx-0 + v-icon mdi-table-check + span Insert Maturity Matrix template(v-if='$vuetify.breakpoint.mdAndUp') v-spacer v-tooltip(right, color='teal') @@ -459,7 +464,7 @@ export default { processContent (newContent) { linesMap = [] // this.$store.set('editor/content', newContent) - this.processMarkers(this.cm.firstLine(), this.cm.lastLine()) + this.processMarkers(this.cm.firstLine(), this.cm.lastLine() + 1) this.previewHTML = DOMPurify.sanitize(md.render(newContent), { ADD_TAGS: ['foreignObject'], HTML_INTEGRATION_POINTS: { foreignobject: true } @@ -663,6 +668,10 @@ export default { insertLink () { this.insertLinkDialog = true }, + openMaturityMatrix () { + this.$store.set('editor/activeModalData', null) + this.toggleModal(`editorModalMaturityMatrix`) + }, insertLinkHandler ({ locale, path }) { const lastPart = _.last(path.split('/')) this.insertAtCursor({ @@ -682,7 +691,33 @@ export default { if (ln.text.startsWith('```diagram')) { found = 'diagram' foundStart = line - } else if (ln.text === '```' && found) { + } else if (ln.text === '') { + found = 'maturity-matrix' + foundStart = line + } else if (ln.text === '' && found === 'maturity-matrix') { + const startLine = foundStart + const endLine = line + const startLineLen = this.cm.doc.getLine(startLine).length + this.addMarker({ + kind: 'maturity-matrix', + from: { line: startLine, ch: 0 }, + to: { line: startLine, ch: startLineLen }, + text: 'Edit Maturity Matrix', + action: ((start, end) => { + return (ev) => { + const endLen = this.cm.doc.getLine(end).length + this.cm.doc.setSelection({ line: start, ch: 0 }, { line: end, ch: endLen }) + const innerLines = [] + for (let i = start + 1; i < end; i++) { + innerLines.push(this.cm.doc.getLine(i)) + } + this.$store.set('editor/activeModalData', innerLines.join('\n')) + this.toggleModal(`editorModalMaturityMatrix`) + } + })(startLine, endLine) + }) + found = null + } else if (ln.text === '```' && found === 'diagram') { switch (found) { // ------------------------------ // -> DIAGRAM @@ -851,6 +886,15 @@ export default { this.cm.doc.replaceSelection('```diagram\n' + opts.text + '\n```\n', 'start') this.processMarkers(selStartLine, selEndLine) break + case 'MATURITY_MATRIX': { + const mmStart = this.cm.getCursor('from').line + const wrapped = '\n' + opts.markdown + '\n\n' + const wrappedLineCount = wrapped.split('\n').length + this.cm.doc.replaceSelection(wrapped, 'start') + // replaceSelection(_, 'start') leaves cursor at start; compute end from inserted line count + this.processMarkers(mmStart, mmStart + wrappedLineCount + 1) + break + } } }) diff --git a/client/components/editor/editor-modal-maturitymatrix.vue b/client/components/editor/editor-modal-maturitymatrix.vue new file mode 100644 index 00000000..620c015e --- /dev/null +++ b/client/components/editor/editor-modal-maturitymatrix.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/client/static/maturity-matrix/index.html b/client/static/maturity-matrix/index.html new file mode 100644 index 00000000..887ffd6c --- /dev/null +++ b/client/static/maturity-matrix/index.html @@ -0,0 +1,1393 @@ + + + + + +Use Case Maturity Assessment Matrix + + + + + +
+
+ +
Use Case Maturity Assessment Matrix
+
+
+ + +
+
+ +
+ +
+
+ + +
+
+ + +
+
+ +
+
+
Performance
+
—%
+
+
0 / 0 pts
+
+
+
Availability
+
—%
+
+
0 / 0 pts
+
+
+
Excellence
+
—%
+
+
0 / 0 pts
+
+
+
Overall Maturity
+
—%
+
+
All sections combined
+
+
+ +
+
+ +
+ +
+ + + +
+ + + + + \ No newline at end of file diff --git a/server/middlewares/security.js b/server/middlewares/security.js index 4f2e4e8f..33eff409 100644 --- a/server/middlewares/security.js +++ b/server/middlewares/security.js @@ -14,7 +14,13 @@ module.exports = function (req, res, next) { // -> Disable Frame Embedding if (WIKI.config.security.securityIframe) { - res.set('X-Frame-Options', 'deny') + // Allow same-origin embedding for the Maturity Matrix editor asset + // (loaded inside the editor as an iframe). Everything else stays denied. + if (req.path.startsWith('/_assets/maturity-matrix/')) { + res.set('X-Frame-Options', 'sameorigin') + } else { + res.set('X-Frame-Options', 'deny') + } } // -> Re-enable XSS Fitler if disabled