mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
* N8N-3029 Add Node Type for Wokrflow Stickies/Notes * N8N-3029 Update Content, Update Aliasses * N8N-3030 Created N8N Sticky Component in Design System * N8N-3030 Fixed Code spaccing Sticky Component * N8N-3030 Fixed Code spaccing StickyStories Component * N8N-3030 Fixed Code spaccing Markdown Component * N8N-3030 Added Sticky Colors Pallete into Storybook, Update Color Variables for Sticky Component * N8N-3030 Added Unfocus Event * N8N-3030 Update Default Placeholder, Markdown Styles, Fixed Edit State, Added Text to EditState, Fixed Height of Area, Turned off Resize of textarea * N8N-3030 Update Sticky Overflow, Update Hover States, Updated Markdown Overflow * N8N-3030, N8N-3031 - Add Resize to Sticky, Created N8n-Resize component * N8N-3031 Fixed Importing Components in Editor-ui * N8N-3031 Fixed Resize Component, Fixed Gradient * N8N-3030, N8N-3031 Update Note Description * N8N-3032 Hotfix Building Storybook * N8N-3032 - Select Behaviour, Changes in Resize Component, Emit on Width/Height/Top/Left Change * N8N-3032 Update Resize Component to emmit left/top, Update Dynamic Resize on Selected Background * N8N-3032 Updated / Dragging vs Resizing, prevent open Modal for stickies * N8N-3032 Added ID props to n8n-sticky // dynamic id for multi resizing in NodeView * N8N-3033 Add dynamic size Tooltip on Sticky * N8N-3033 Updated Z-index for Sticky Component * N8N-3033 Updated N8N-Resize Component, Fixed SelectedBackround for Sticky Component * N8N-3033 Refactor * N8N-3033 Focus/Defocus on TextArea * N8N-3033 Fixed Resizing on NW Point * N8N-3030 Save content in vuex on input change * N8N-3033 Fixed Resizer, Save Width and Height in Vue * N8N-3033 Hide Sticky Footer on small height/width * N8N-3033 Fixed Resizer * N8N-3033 Dynamic Z-index for Stickies * N8N-3033 Dynamic Z-index for Stickies * N8N-3033 Removed static z-index for select sticky class * N8N-3034 Added Telemetry * N8N-3030 Formatter * N8N-3030 Format code * N8N-3030 Fixed Selecting Stickies * N8N-3033 Fixed Notifications * N8N-3030 Added new paddings for Default Stickies * N8N-3033 Prevent Scrolling NodeView when Sticky is in Edit mode and Mouse is Over the TextArea * N8N-3030 Prevent double clicking to switch state of Sticky component in Edit Mode * N8N-3033 Fixed Z-index of Stickies * N8N-3033 Prevent delete node when in EditMode * N8N-3030 Prevent Delete Button to delete the Sticky while in Edit Mode * N8N-3030 Change EditMode (emit) on keyboard shortucts, update Markdown Links & Images, Added new props * N8N-3030 Sticky Component - No padding when hiding footer text * N8N-3033 Fix Resizing enter into Edit Mode * N8N-3033 Selecting different nodes - exit the edit mode * N8N-3033 Auto Select Text in text-area by default - Sticky Component * N8N-3033 Prevent Default behaviour for CTRL + X, CTRL + A when Sticky is Active && inEditMode * N8N-3033 Refactor Resizer, Refactor Sticky, Update zIndex inEditMode * N8N-3033 Updated Default Text // Node-base, Storybook * N8N-3033 Add Resizing in EditMode - Components update * N8N-3033 Fixed Footer - Show/Hide on Resize in EditMode * N8N-3033 Fix ActiveSticky on Init * N8N-3033 Refactor Sticky in Vuex, Fixed Init Sticky Tweaks, Prevent Modal Openning, Save on Keyboard shortcuts * Stickies - Update Note node with new props * N8N-3030 Updated Default Note text, Update the Markdown Link * N8N-3030 CMD-C does not copy the text fix * N8N-3030 Fix Max Zoom / Zoom out shortcuts disabled in editState * N8N-3030 Z-index fixed during Edit Mode typing * N8N-3030 Prevent Autoselect Text in Stickies if the text is not default * N8N-3030 Fixed ReadOnly Bugs / Prevent showing Tooltip, Resizing * N8N-3030 Added Sticky Creator Button * N8N-3030 Update Icon / Sticky Creator Button * N8N-3033 Update Sticky Icon / StickyCreator Button * update package lock * 🔩 update note props * 🚿 clean props * 🔧 linting * 🔧 fix spacing * remove resize component * remove resize component * ✂ clean up sticky * revert back to height width * revert back to height/width * replace zindex property * replace default text property * use i18n to translate * update package lock * move resize * clean up how height/width are set * fix resize for sticky to support left/top * clean up resize * fix lasso/highlight bug * remove unused props * fix zoom to fit * fix padding for demo view * fix readonly * remove iseditable, use active state * clean up keyboard events * chang button size, no edit on insert * scale resizing correctly * make active on resize * fix select on resize/move * use outline icon * allow for multiple line breaks * fix multi line bug * fix edit mode outline * keep edit open as one resizes * respect multiple spaces * fix scrolling bug * clean up hover impl * clean up references to note * disable for rename * fix drifting while drag * fix mouse cursor on resize * fix sticky min height * refactor resize into component * fix pulling too far bug * fix delete/cut all bug * fix padding bottom * fix active change on resize * add transition to button * Fix sticky markdown click * add solid fa icon * update node graph, telemetry event * add snapping * change alt text * update package lock * fix bug in button hover * add back transition * clean up resize * add grid size as param * remove breaks * clean up markdown * lint fixes * fix spacing * clean up markdown colors * clean up classes in resize * clean up resize * update sticky story * fix spacing * clean up classes * revert change * revert change * revert change * clean up sticky component * remove unused component * remove unnessary data * remove unnessary data * clean up actions * clean up sticky size * clean up unnessary border style * fix bug * replace sticky note name * update description * remove support for multi spaces * update tracking name * update telemetry reqs * fix enter bug * update alt text * update sticky notes doc url * fix readonly bug * update class name * update quote marks Co-authored-by: SchnapsterDog <olivertrajceski@yahoo.com>
297 lines
5.4 KiB
Vue
297 lines
5.4 KiB
Vue
<template>
|
|
<div>
|
|
<div
|
|
v-if="!loading"
|
|
ref="editor"
|
|
:class="$style[theme]" v-html="htmlContent"
|
|
/>
|
|
<div v-else :class="$style.markdown">
|
|
<div v-for="(block, index) in loadingBlocks"
|
|
:key="index">
|
|
<n8n-loading
|
|
:loading="loading"
|
|
:rows="loadingRows"
|
|
animated
|
|
variant="p"
|
|
/>
|
|
<div :class="$style.spacer" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import N8nLoading from '../N8nLoading';
|
|
import Markdown from 'markdown-it';
|
|
const markdownLink = require('markdown-it-link-attributes');
|
|
const markdownEmoji = require('markdown-it-emoji');
|
|
const markdownTasklists = require('markdown-it-task-lists');
|
|
|
|
import xss from 'xss';
|
|
import { escapeMarkdown } from '../../utils/markdown';
|
|
|
|
const DEFAULT_OPTIONS_MARKDOWN = {
|
|
html: true,
|
|
linkify: true,
|
|
typographer: true,
|
|
breaks: true,
|
|
};
|
|
|
|
const DEFAULT_OPTIONS_LINK_ATTRIBUTES = {
|
|
attrs: {
|
|
target: '_blank',
|
|
rel: 'noopener',
|
|
},
|
|
};
|
|
|
|
const DEFAULT_OPTIONS_TASKLISTS = {
|
|
label: true,
|
|
labelAfter: true,
|
|
};
|
|
|
|
interface IImage {
|
|
id: string;
|
|
url: string;
|
|
}
|
|
|
|
export default {
|
|
components: {
|
|
N8nLoading,
|
|
},
|
|
name: 'n8n-markdown',
|
|
props: {
|
|
content: {
|
|
type: String,
|
|
},
|
|
withMultiBreaks: {
|
|
type: Boolean,
|
|
},
|
|
images: {
|
|
type: Array,
|
|
},
|
|
loading: {
|
|
type: Boolean,
|
|
},
|
|
loadingBlocks: {
|
|
type: Number,
|
|
default: 2,
|
|
},
|
|
loadingRows: {
|
|
type: Number,
|
|
default: () => {
|
|
return 3;
|
|
},
|
|
},
|
|
theme: {
|
|
type: String,
|
|
default: 'markdown',
|
|
},
|
|
options: {
|
|
type: Object,
|
|
default() {
|
|
return {
|
|
markdown: DEFAULT_OPTIONS_MARKDOWN,
|
|
linkAttributes: DEFAULT_OPTIONS_LINK_ATTRIBUTES,
|
|
tasklists: DEFAULT_OPTIONS_TASKLISTS,
|
|
};
|
|
},
|
|
},
|
|
},
|
|
computed: {
|
|
htmlContent(): string {
|
|
if (!this.content) {
|
|
return '';
|
|
}
|
|
|
|
const imageUrls: { [key: string]: string } = {};
|
|
if (this.images) {
|
|
// @ts-ignore
|
|
this.images.forEach((image: IImage) => {
|
|
if (!image) {
|
|
// Happens if an image got deleted but the workflow
|
|
// still has a reference to it
|
|
return;
|
|
}
|
|
imageUrls[image.id] = image.url;
|
|
});
|
|
}
|
|
|
|
const fileIdRegex = new RegExp('fileId:([0-9]+)');
|
|
let contentToRender = this.content;
|
|
if (this.withMultiBreaks) {
|
|
contentToRender = contentToRender.replaceAll('\n\n', '\n \n');
|
|
}
|
|
const html = this.md.render(escapeMarkdown(contentToRender));
|
|
const safeHtml = xss(html, {
|
|
onTagAttr: (tag, name, value, isWhiteAttr) => {
|
|
if (tag === 'img' && name === 'src') {
|
|
if (value.match(fileIdRegex)) {
|
|
const id = value.split('fileId:')[1];
|
|
return `src=${xss.friendlyAttrValue(imageUrls[id])}` || '';
|
|
}
|
|
if (!value.startsWith('https://')) {
|
|
return '';
|
|
}
|
|
}
|
|
// Return nothing, means keep the default handling measure
|
|
},
|
|
onTag: function (tag, html, options) {
|
|
if (tag === 'img' && html.includes(`alt="workflow-screenshot"`)) {
|
|
return '';
|
|
}
|
|
// return nothing, keep tag
|
|
},
|
|
});
|
|
|
|
return safeHtml;
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
md: new Markdown(this.options.markdown)
|
|
.use(markdownLink, this.options.linkAttributes)
|
|
.use(markdownEmoji)
|
|
.use(markdownTasklists, this.options.tasklists),
|
|
};
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" module>
|
|
.markdown {
|
|
color: var(--color-text-base);
|
|
|
|
* {
|
|
font-size: var(--font-size-m);
|
|
line-height: var(--font-line-height-xloose);
|
|
}
|
|
|
|
h1, h2, h3, h4 {
|
|
margin-bottom: var(--spacing-s);
|
|
font-size: var(--font-size-m);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
h3, h4 {
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
p,
|
|
span {
|
|
margin-bottom: var(--spacing-s);
|
|
}
|
|
|
|
ul, ol {
|
|
margin-bottom: var(--spacing-s);
|
|
padding-left: var(--spacing-m);
|
|
|
|
li {
|
|
margin-top: 0.25em;
|
|
}
|
|
}
|
|
|
|
pre {
|
|
margin-bottom: var(--spacing-s);
|
|
display: grid;
|
|
}
|
|
|
|
pre > code {
|
|
display: block;
|
|
padding: var(--spacing-s);
|
|
color: var(--color-text-dark);
|
|
background-color: var(--color-background-base);
|
|
overflow-x: auto;
|
|
}
|
|
|
|
li > code,
|
|
p > code {
|
|
padding: 0 var(--spacing-4xs);
|
|
color: var(--color-text-dark);
|
|
background-color: var(--color-background-base);
|
|
}
|
|
|
|
.label {
|
|
color: var(--color-text-base);
|
|
}
|
|
|
|
img {
|
|
width: 100%;
|
|
max-height: 90vh;
|
|
object-fit: cover;
|
|
border: var(--border-width-base) var(--color-foreground-base) var(--border-style-base);
|
|
border-radius: var(--border-radius-large);
|
|
}
|
|
|
|
blockquote {
|
|
padding-left: 10px;
|
|
font-style: italic;
|
|
border-left: var(--border-color-base) 2px solid;
|
|
}
|
|
}
|
|
|
|
.sticky {
|
|
color: var(--color-text-dark);
|
|
|
|
h1, h2, h3, h4 {
|
|
margin-bottom: var(--spacing-2xs);
|
|
font-weight: var(--font-weight-bold);
|
|
line-height: var(--font-line-height-loose);
|
|
}
|
|
|
|
h1 {
|
|
font-size: 36px;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 24px;
|
|
}
|
|
|
|
h3, h4, h5, h6 {
|
|
font-size: var(--font-size-m);
|
|
}
|
|
|
|
p {
|
|
margin-bottom: var(--spacing-2xs);
|
|
font-size: var(--font-size-s);
|
|
font-weight: var(--font-weight-regular);
|
|
line-height: var(--font-line-height-loose);
|
|
}
|
|
|
|
ul, ol {
|
|
margin-bottom: var(--spacing-2xs);
|
|
padding-left: var(--spacing-m);
|
|
|
|
li {
|
|
margin-top: 0.25em;
|
|
font-size: var(--font-size-s);
|
|
font-weight: var(--font-weight-regular);
|
|
line-height: var(--font-line-height-regular);
|
|
}
|
|
}
|
|
|
|
code {
|
|
background-color: var(--color-background-base);
|
|
padding: 0 var(--spacing-4xs);
|
|
color: var(--color-secondary);
|
|
}
|
|
|
|
pre > code,li > code, p > code {
|
|
color: var(--color-secondary);
|
|
}
|
|
|
|
a {
|
|
&:hover {
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
|
|
img {
|
|
object-fit: contain;
|
|
}
|
|
}
|
|
|
|
.spacer {
|
|
margin: var(--spacing-2xl);
|
|
}
|
|
</style>
|