diff --git a/docker/images/n8n-custom/docker-entrypoint.sh b/docker/images/n8n-custom/docker-entrypoint.sh index 2c9c35eb48..2dd4dae105 100755 --- a/docker/images/n8n-custom/docker-entrypoint.sh +++ b/docker/images/n8n-custom/docker-entrypoint.sh @@ -8,9 +8,16 @@ fi if [ "$#" -gt 0 ]; then # Got started with arguments - shift - exec su-exec node ./packages/cli/bin/n8n "$@" + COMMAND=$1; + + if [[ "$COMMAND" == "n8n" ]]; then + shift + exec su-exec node ./packages/cli/bin/n8n "$@" + else + exec su-exec node "$@" + fi + else - # Got started without arguments - exec su-exec node ./packages/cli/bin/n8n +# Got started without arguments +exec su-exec node ./packages/cli/bin/n8n fi diff --git a/docker/images/n8n/README.md b/docker/images/n8n/README.md index 8088150821..e1b39d82d6 100644 --- a/docker/images/n8n/README.md +++ b/docker/images/n8n/README.md @@ -17,6 +17,7 @@ n8n is a free and open [fair-code](http://faircode.io) licensed node based Workf - [Securing n8n](#securing-n8n) - [Persist data](#persist-data) - [Passing Sensitive Data via File](#passing-sensitive-data-via-file) +- [Updating a Running docker-compose Instance](#updating-a-running-docker-compose-instance) - [Example Setup with Lets Encrypt](#example-setup-with-lets-encrypt) - [What does n8n mean and how do you pronounce it](#what-does-n8n-mean-and-how-do-you-pronounce-it) - [Support](#support) @@ -226,6 +227,18 @@ The following environment variables support file input: A basic step by step example setup of n8n with docker-compose and Lets Encrypt is available on the [Server Setup](https://docs.n8n.io/#/server-setup) page. +## Updating a running docker-compose instance + +``` +# Pull down the latest version from dockerhub +docker pull n8nio/n8n +# Stop current setup +sudo docker-compose stop +# Delete it (will only delete the docker-containers, data is stored separately) +sudo docker-compose rm +# Then start it again +sudo docker-compose up -d +``` ## Setting Timezone diff --git a/packages/cli/src/LoadNodesAndCredentials.ts b/packages/cli/src/LoadNodesAndCredentials.ts index eccfcb0804..0d0eb21df3 100644 --- a/packages/cli/src/LoadNodesAndCredentials.ts +++ b/packages/cli/src/LoadNodesAndCredentials.ts @@ -192,7 +192,7 @@ class LoadNodesAndCredentialsClass { * @memberof N8nPackagesInformationClass */ async loadDataFromDirectory(setPackageName: string, directory: string): Promise { - const files = await glob(path.join(directory, '*\.@(node|credentials)\.js')); + const files = await glob(path.join(directory, '**/*\.@(node|credentials)\.js')); let fileName: string; let type: string; diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 245f31b500..b3729e4f68 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -19,7 +19,16 @@
- Results: {{ dataCount }}  + + Results: {{ dataCount }} + + Results: + + +  / + {{ dataCount }} + +   option <= this.dataCount); + }, node (): INodeUi | null { return this.$store.getters.activeNode; }, @@ -323,19 +344,27 @@ export default mixins( return 0; }, jsonData (): IDataObject[] { - const inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); + let inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); if (inputData.length === 0 || !Array.isArray(inputData)) { return []; } + if (this.maxDisplayItems !== null) { + inputData = inputData.slice(0, this.maxDisplayItems); + } + return this.convertToJson(inputData); }, tableData (): ITableData | undefined { - const inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); + let inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); if (inputData.length === 0) { return undefined; } + if (this.maxDisplayItems !== null) { + inputData = inputData.slice(0,this.maxDisplayItems); + } + return this.convertToTable(inputData); }, binaryData (): IBinaryKeyData[] { @@ -450,9 +479,12 @@ export default mixins( // Check how much data there is to display const inputData = this.getNodeInputData(this.node, this.runIndex, this.outputIndex); - this.dataSize = JSON.stringify(inputData).length; - if (this.dataSize < 204800) { + const jsonItems = inputData.slice(0, this.maxDisplayItems || inputData.length).map(item => item.json); + + this.dataSize = JSON.stringify(jsonItems).length; + + if (this.dataSize < this.MAX_DISPLAY_DATA_SIZE) { // Data is reasonable small (< 200kb) so display it directly this.showData = true; } @@ -466,6 +498,7 @@ export default mixins( node (newNode, oldNode) { // Reset the selected output index every time another node gets selected this.outputIndex = 0; + this.maxDisplayItems = 25; this.refreshDataSize(); }, jsonData () { diff --git a/packages/editor-ui/src/components/mixins/nodeBase.ts b/packages/editor-ui/src/components/mixins/nodeBase.ts index ccefba5463..03ad84db00 100644 --- a/packages/editor-ui/src/components/mixins/nodeBase.ts +++ b/packages/editor-ui/src/components/mixins/nodeBase.ts @@ -65,6 +65,7 @@ export const nodeBase = mixins(nodeIndex).extend({ 'name', 'nodeId', 'instance', + 'isReadOnly', ], methods: { __addNode (node: INodeUi) { @@ -182,7 +183,7 @@ export const nodeBase = mixins(nodeIndex).extend({ endpoint: inputData.endpoint, endpointStyle: inputData.endpointStyle, isSource: false, - isTarget: true, + isTarget: !this.isReadOnly, parameters: { nodeIndex: this.nodeIndex, type: inputName, @@ -246,7 +247,7 @@ export const nodeBase = mixins(nodeIndex).extend({ maxConnections: inputData.maxConnections, endpoint: inputData.endpoint, endpointStyle: inputData.endpointStyle, - isSource: true, + isSource: !this.isReadOnly, isTarget: false, parameters: { nodeIndex: this.nodeIndex, @@ -275,61 +276,63 @@ export const nodeBase = mixins(nodeIndex).extend({ this.instance.addEndpoint(this.nodeName, newEndpointData); }); - // Make nodes draggable - this.instance.draggable(this.nodeName, { - grid: [10, 10], - start: (params: { e: MouseEvent }) => { - if (params.e && !this.$store.getters.isNodeSelected(this.data.name)) { - // Only the node which gets dragged directly gets an event, for all others it is - // undefined. So check if the currently dragged node is selected and if not clear - // the drag-selection. - this.instance.clearDragSelection(); - this.$store.commit('resetSelectedNodes'); - } - - this.$store.commit('addActiveAction', 'dragActive'); - }, - stop: (params: { e: MouseEvent}) => { - if (this.$store.getters.isActionActive('dragActive')) { - const moveNodes = this.$store.getters.getSelectedNodes.slice(); - const selectedNodeNames = moveNodes.map((node: INodeUi) => node.name); - if (!selectedNodeNames.includes(this.data.name)) { - // If the current node is not in selected add it to the nodes which - // got moved manually - moveNodes.push(this.data); + if (this.isReadOnly === false) { + // Make nodes draggable + this.instance.draggable(this.nodeName, { + grid: [10, 10], + start: (params: { e: MouseEvent }) => { + if (params.e && !this.$store.getters.isNodeSelected(this.data.name)) { + // Only the node which gets dragged directly gets an event, for all others it is + // undefined. So check if the currently dragged node is selected and if not clear + // the drag-selection. + this.instance.clearDragSelection(); + this.$store.commit('resetSelectedNodes'); } - // This does for some reason just get called once for the node that got clicked - // even though "start" and "drag" gets called for all. So lets do for now - // some dirty DOM query to get the new positions till I have more time to - // create a proper solution - let newNodePositon: XYPositon; - moveNodes.forEach((node: INodeUi) => { - const nodeElement = `node-${this.getNodeIndex(node.name)}`; - const element = document.getElementById(nodeElement); - if (element === null) { - return; + this.$store.commit('addActiveAction', 'dragActive'); + }, + stop: (params: { e: MouseEvent }) => { + if (this.$store.getters.isActionActive('dragActive')) { + const moveNodes = this.$store.getters.getSelectedNodes.slice(); + const selectedNodeNames = moveNodes.map((node: INodeUi) => node.name); + if (!selectedNodeNames.includes(this.data.name)) { + // If the current node is not in selected add it to the nodes which + // got moved manually + moveNodes.push(this.data); } - newNodePositon = [ - parseInt(element.style.left!.slice(0, -2), 10), - parseInt(element.style.top!.slice(0, -2), 10), - ]; + // This does for some reason just get called once for the node that got clicked + // even though "start" and "drag" gets called for all. So lets do for now + // some dirty DOM query to get the new positions till I have more time to + // create a proper solution + let newNodePositon: XYPositon; + moveNodes.forEach((node: INodeUi) => { + const nodeElement = `node-${this.getNodeIndex(node.name)}`; + const element = document.getElementById(nodeElement); + if (element === null) { + return; + } - const updateInformation = { - name: node.name, - properties: { - // @ts-ignore, draggable does not have definitions - position: newNodePositon, - }, - }; + newNodePositon = [ + parseInt(element.style.left!.slice(0, -2), 10), + parseInt(element.style.top!.slice(0, -2), 10), + ]; - this.$store.commit('updateNodeProperties', updateInformation); - }); - } - }, - filter: '.node-description, .node-description .node-name, .node-description .node-subtitle', - }); + const updateInformation = { + name: node.name, + properties: { + // @ts-ignore, draggable does not have definitions + position: newNodePositon, + }, + }; + + this.$store.commit('updateNodeProperties', updateInformation); + }); + } + }, + filter: '.node-description, .node-description .node-name, .node-description .node-subtitle', + }); + } }, isCtrlKeyPressed (e: MouseEvent | KeyboardEvent): boolean { diff --git a/packages/editor-ui/src/constants.ts b/packages/editor-ui/src/constants.ts index 90f8808986..22ec0a5198 100644 --- a/packages/editor-ui/src/constants.ts +++ b/packages/editor-ui/src/constants.ts @@ -1,2 +1,4 @@ +export const MAX_DISPLAY_DATA_SIZE = 204800; +export const MAX_DISPLAY_ITEMS_AUTO_ALL = 250; export const NODE_NAME_PREFIX = 'node-'; export const PLACEHOLDER_EMPTY_WORKFLOW_ID = '__EMPTY__'; diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index 03f1ff28d1..de89534e09 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -20,6 +20,7 @@ :id="'node-' + getNodeIndex(nodeData.name)" :key="getNodeIndex(nodeData.name)" :name="nodeData.name" + :isReadOnly="isReadOnly" :instance="instance" >
@@ -102,6 +103,9 @@