diff --git a/client/web/workflow/public/icons/dark/text.svg b/client/web/workflow/public/icons/dark/text.svg new file mode 100644 index 0000000000..232c6b731c --- /dev/null +++ b/client/web/workflow/public/icons/dark/text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/web/workflow/public/icons/text.svg b/client/web/workflow/public/icons/text.svg new file mode 100644 index 0000000000..1d722d83cb --- /dev/null +++ b/client/web/workflow/public/icons/text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/web/workflow/src/components/Configurator/Text.vue b/client/web/workflow/src/components/Configurator/Text.vue new file mode 100644 index 0000000000..28f471d2f3 --- /dev/null +++ b/client/web/workflow/src/components/Configurator/Text.vue @@ -0,0 +1,38 @@ + + + diff --git a/client/web/workflow/src/components/Configurator/index.vue b/client/web/workflow/src/components/Configurator/index.vue index 75e2c6a9e3..0002924ee5 100644 --- a/client/web/workflow/src/components/Configurator/index.vue +++ b/client/web/workflow/src/components/Configurator/index.vue @@ -3,6 +3,7 @@ class="d-flex flex-column" > @@ -64,7 +66,7 @@ export default { }, kind () { - const { kind } = this.item.config + const { kind, ref } = this.item.config if (kind === 'exec-workflow') { return 'ExecWorkflow' @@ -74,6 +76,10 @@ export default { return 'ErrorHandler' } + if (kind === 'visual' && ref === 'text') { + return 'Text' + } + if (kind) { return kind.charAt(0).toUpperCase() + kind.slice(1) } diff --git a/client/web/workflow/src/components/Configurator/loader.js b/client/web/workflow/src/components/Configurator/loader.js index 17cf992eb1..c117d2e7d5 100644 --- a/client/web/workflow/src/components/Configurator/loader.js +++ b/client/web/workflow/src/components/Configurator/loader.js @@ -10,3 +10,4 @@ export { default as Prompt } from './Prompt' export { default as Delay } from './Delay' export { default as ExecWorkflow } from './ExecWorkflow' export { default as ErrorHandler } from './ErrorHandler' +export { default as Text } from './Text' diff --git a/client/web/workflow/src/components/WorkflowEditor.vue b/client/web/workflow/src/components/WorkflowEditor.vue index da1037e117..4bd1e19e15 100644 --- a/client/web/workflow/src/components/WorkflowEditor.vue +++ b/client/web/workflow/src/components/WorkflowEditor.vue @@ -848,6 +848,7 @@ export default { this.graph.setConnectable(true) this.graph.setAllowDanglingEdges(false) this.graph.setTooltips(true) + /* eslint-disable no-new */ new mxRubberband(this.graph) // Enables multiple selection this.graph.edgeLabelsMovable = false @@ -906,6 +907,7 @@ export default { const vertex = this.vertices[cell.id] const { kind } = vertex.config const { style } = vertex.node + if (vertex && kind !== 'visual') { const icon = this.getIcon(getStyleFromKind(vertex.config).icon, this.currentTheme) const type = this.$t(`steps:${style}.short`) @@ -1057,7 +1059,7 @@ export default { values + '' } else { - label = `
${encodeHTML(cell.value || '')}
` + label = cell.value } } @@ -1115,6 +1117,8 @@ export default { value = style.split('gateway')[1] } else if (style === 'expressions') { value = 'Define and mutate scope variables' + } else if (style === 'text') { + value = 'Text here' } const cell = new mxCell( @@ -1584,15 +1588,22 @@ export default { this.graph.addListener(mxEvent.CELLS_ADDED, (sender, evt) => { if (!this.rendering) { const cells = evt.getProperty('cells') + let lastVertexID = null cells.forEach(cell => { if (cell && cell.vertex) { if (!this.rendering) { cell.defaultName = true this.addCellToVertices(cell) this.graph.setSelectionCells([cell]) + lastVertexID = cell.id } } }) + + if (lastVertexID) { + const vertex = this.vertices[lastVertexID] + this.sidebarReopen(vertex, vertex.config.kind) + } } }) @@ -1636,21 +1647,6 @@ export default { }) }) - this.graph.addListener(mxEvent.DOUBLE_CLICK, (sender, evt) => { - const event = evt.getProperty('event') - const cell = evt.getProperty('cell') - if (event && cell) { - const isVisual = ((this.vertices[cell.id] || {}).config || {}).kind === 'visual' - if (cell.edge || isVisual) { - const item = cell.edge ? this.edges[cell.id] : this.vertices[cell.id] - const itemType = cell.edge ? 'edge' : item.config.kind - this.sidebarReopen(item, itemType) - } - } - - evt.consume() - }) - // Zoom event mxEvent.addMouseWheelListener((event, up) => { if (mxEvent.isConsumed(event)) { @@ -1706,9 +1702,10 @@ export default { // Prevent sidebar opening/closing when CTRL(CMD) is pressed while clicking } else if (cell) { // If clicked on Cog icon - if (event.target.id === 'openSidebar') { - const item = cell.edge ? this.edges[cell.id] : this.vertices[cell.id] - const itemType = cell.edge ? 'edge' : item.config.kind + const item = cell.edge ? this.edges[cell.id] : this.vertices[cell.id] + const itemType = cell.edge ? 'edge' : item.config.kind + + if (event.target.id === 'openSidebar' || item.config.kind === 'visual') { this.sidebarReopen(item, itemType) } else if (event.target.id === 'openIssues') { this.issuesModal.issues = this.issues[cell.id] @@ -1758,6 +1755,8 @@ export default { mxConstants.GUIDE_STROKEWIDTH = 1 // Creates the default style for vertices + const defaultStyle = this.graph.getStylesheet().getDefaultVertexStyle() + let style = this.graph.getStylesheet().getDefaultVertexStyle() style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter @@ -1801,6 +1800,21 @@ export default { style[mxConstants.STYLE_STROKEWIDTH] = 0 style[mxConstants.STYLE_STROKEWIDTH] = 2 this.graph.getStylesheet().putCellStyle('swimlane', style) + + // Text + style = {} + style[mxConstants.STYLE_RESIZABLE] = true + style[mxConstants.STYLE_CONNECTABLE] = false + style[mxConstants.STYLE_FILLCOLOR] = 'var(--white)' + style[mxConstants.STYLE_STROKECOLOR] = 'var(--extra-light)' + style[mxConstants.STYLE_STROKEWIDTH] = 1 + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT + style[mxConstants.STYLE_SPACING_TOP] = 10 + style[mxConstants.STYLE_SPACING_LEFT] = 10 + style[mxConstants.STYLE_WHITE_SPACE] = 'wrap' + style[mxConstants.STYLE_OVERFLOW] = 'hidden' + this.graph.getStylesheet().putCellStyle('text', style) }, translateCell (style) { @@ -1835,7 +1849,7 @@ export default { } const { cell } = terminal - let isConnectable = this.model.isVertex(cell) && !cell.style.includes('swimlane') + let isConnectable = this.model.isVertex(cell) && !['swimlane', 'text'].includes(cell.style) // Only one outbound connection per trigger if (cell.style.includes('trigger') && cell.edges) { diff --git a/client/web/workflow/src/components/faIcons.js b/client/web/workflow/src/components/faIcons.js index 8be5704799..81f95bd5da 100644 --- a/client/web/workflow/src/components/faIcons.js +++ b/client/web/workflow/src/components/faIcons.js @@ -29,6 +29,24 @@ import { faFileExport, faToggleOn, faToggleOff, + faBold, + faItalic, + faUnderline, + faStrikethrough, + faQuoteRight, + faCode, + faListUl, + faListOl, + faOutdent, + faIndent, + faAlignLeft, + faAlignCenter, + faAlignRight, + faAlignJustify, + faLink, + faRemoveFormat, + faParagraph, + faTasks, } from '@fortawesome/free-solid-svg-icons' import { @@ -72,4 +90,22 @@ library.add( faToggleOff, faAngleUp, faAngleDown, + faBold, + faItalic, + faUnderline, + faStrikethrough, + faQuoteRight, + faCode, + faListUl, + faListOl, + faOutdent, + faIndent, + faAlignLeft, + faAlignCenter, + faAlignRight, + faAlignJustify, + faLink, + faRemoveFormat, + faParagraph, + faTasks, ) diff --git a/client/web/workflow/src/lib/style.js b/client/web/workflow/src/lib/style.js index 8727983255..14e9220067 100644 --- a/client/web/workflow/src/lib/style.js +++ b/client/web/workflow/src/lib/style.js @@ -135,6 +135,13 @@ const kindToStyle = { icon: 'debug', style: 'debug', }, + + visualText: { + width: 400, + height: 250, + icon: 'text', + style: 'text', + }, } // When adding & or copy/pasting a new cell, this is used to determine the kind & ref @@ -167,6 +174,8 @@ export function getKindFromStyle (vertex) { } } else if (kind === 'swimlane') { return { kind: 'visual', ref: 'swimlane' } + } else if (kind === 'text') { + return { kind: 'visual', ref: 'text' } } else { return { kind } } diff --git a/client/web/workflow/src/lib/toolbar.js b/client/web/workflow/src/lib/toolbar.js index 7d7d3eeba8..cef3cf8548 100644 --- a/client/web/workflow/src/lib/toolbar.js +++ b/client/web/workflow/src/lib/toolbar.js @@ -3,6 +3,10 @@ export default [ kind: 'visual', ref: 'swimlane', }, + { + kind: 'visual', + ref: 'text', + }, { kind: 'hr', }, diff --git a/lib/vue/src/components/input/CRichTextInput/index.vue b/lib/vue/src/components/input/CRichTextInput/index.vue index 4448d96a89..51b186c1ed 100644 --- a/lib/vue/src/components/input/CRichTextInput/index.vue +++ b/lib/vue/src/components/input/CRichTextInput/index.vue @@ -106,14 +106,6 @@ export default { }, onUpdate: this.onUpdate, }) - - /** - * Since we migrated to TipTap, the new content should be emitted - * after tiptap is done parsing it. - */ - this.$nextTick(() => { - this.onUpdate() - }) }, /** diff --git a/locale/en/corteza-webapp-workflow/steps.yaml b/locale/en/corteza-webapp-workflow/steps.yaml index 8d68db12ec..296527b694 100644 --- a/locale/en/corteza-webapp-workflow/steps.yaml +++ b/locale/en/corteza-webapp-workflow/steps.yaml @@ -108,4 +108,8 @@ trigger: short: Trigger tooltip: Trigger the workflow execution based on configuration tooltip: - configure-step: Configure step \ No newline at end of file + configure-step: Configure step +text: + label: Text + short: Text + tooltip: Text block used for annotations \ No newline at end of file