🎉 dropALog for n8n 1.x
This commit is contained in:
parent
7eb8838df5
commit
1a75c1ba1c
12 changed files with 182 additions and 542 deletions
6
nodes/DropALog/DropALog.node.json
Normal file
6
nodes/DropALog/DropALog.node.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"node":"n8n-nodes-drop-a-log.DropALog",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories":["Miscellaneous"],
|
||||
}
|
||||
142
nodes/DropALog/DropALog.node.ts
Normal file
142
nodes/DropALog/DropALog.node.ts
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { execFile } from 'child_process';
|
||||
|
||||
interface IExecReturnData {
|
||||
exitCode: number;
|
||||
error?: Error;
|
||||
stderr: string;
|
||||
stdout: string;
|
||||
}
|
||||
|
||||
interface ILogData {
|
||||
log: string;
|
||||
title: string;
|
||||
date: string;
|
||||
includeJson: boolean;
|
||||
item: any;
|
||||
out: IExecReturnData|null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Promisifiy exec manually to also get the exit code
|
||||
*
|
||||
* @param {string} command
|
||||
* @returns {Promise<IExecReturnData>}
|
||||
*/
|
||||
function execPromise(command: string, args: string[]): Promise<IExecReturnData> {
|
||||
const returnData: IExecReturnData = {
|
||||
exitCode: 0,
|
||||
stderr: '',
|
||||
stdout: '',
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
execFile(command, args, { cwd: process.cwd() }, (error, stdout, stderr) => {
|
||||
returnData.stdout = stdout.trim();
|
||||
returnData.stderr = stderr.trim();
|
||||
|
||||
if (error) {
|
||||
returnData.error = error;
|
||||
}
|
||||
|
||||
resolve(returnData);
|
||||
}).on('exit', code => { returnData.exitCode = code || 0; });
|
||||
});
|
||||
}
|
||||
|
||||
export class DropALog implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Drop A Log',
|
||||
name: 'dropALog',
|
||||
icon: 'file:dropalog.svg',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
description: 'Drops data into droplog',
|
||||
defaults: {
|
||||
name: 'Drop A Log',
|
||||
color: '#772244',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
properties: [
|
||||
// Node properties which the user gets displayed and
|
||||
// can change on the node.
|
||||
{
|
||||
displayName: 'Log',
|
||||
name: 'log',
|
||||
type: 'string',
|
||||
default: 'n8n',
|
||||
placeholder: 'posts',
|
||||
description: 'Name of log to use',
|
||||
},
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: 'New Post',
|
||||
placeholder: '',
|
||||
description: 'Name of title for each post'
|
||||
},
|
||||
{
|
||||
displayName: 'Date',
|
||||
name: 'date',
|
||||
type: 'string',
|
||||
default: 'now',
|
||||
placeholder: '',
|
||||
description: 'Date to use for each post'
|
||||
},
|
||||
{
|
||||
displayName: 'Include entire post',
|
||||
name: 'includeJson',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'If activated, the entire item will be logged. If inactive, only title and date will be used'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
for (let idx = 0; idx < items.length; idx++) {
|
||||
let item = items[idx];
|
||||
|
||||
let data: ILogData = {
|
||||
log: this.getNodeParameter('log', idx) as string,
|
||||
title: this.getNodeParameter('title', idx) as string,
|
||||
date: this.getNodeParameter('date', idx) as string,
|
||||
includeJson: this.getNodeParameter('includeJson', idx) as boolean,
|
||||
item: null,
|
||||
out: null,
|
||||
};
|
||||
|
||||
const args: string[] = ['drop'];
|
||||
|
||||
args.push(data.log, data.title, '-d', data.date);
|
||||
|
||||
if (data.includeJson) {
|
||||
const copy = JSON.parse(JSON.stringify(item.json));
|
||||
delete copy.title;
|
||||
delete copy.date;
|
||||
|
||||
args.push('-j', JSON.stringify(copy));
|
||||
data.item = copy;
|
||||
}
|
||||
|
||||
const exit = await execPromise('my-log', args);
|
||||
data.out = exit;
|
||||
returnData.push(data as unknown as IDataObject);
|
||||
}
|
||||
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
||||
11
nodes/DropALog/dropalog.svg
Normal file
11
nodes/DropALog/dropalog.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 -5.99 48.891 48.891" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="log_book" data-name="log book" transform="translate(-130.272 -425.601)">
|
||||
<path id="Path_135" data-name="Path 135" d="M178.663,434.083H142.745v23.323h35.918V434.083Z" fill="#ffe959" fill-rule="evenodd"/>
|
||||
<path id="Path_136" data-name="Path 136" d="M150.727,454.038V430.092a3.99,3.99,0,0,0-3.991-3.991H130.772v23.946h15.964a3.99,3.99,0,0,1,3.991,3.991Z" fill="#ffe959" fill-rule="evenodd"/>
|
||||
<path id="Path_137" data-name="Path 137" d="M178.663,457.406H142.745v4.613h35.918v-4.613Z" fill="#354077" fill-rule="evenodd"/>
|
||||
<path id="Path_138" data-name="Path 138" d="M150.727,457.406h-7.982v4.613h7.982v-4.613Z" fill="#354077" fill-rule="evenodd"/>
|
||||
<path id="Path_139" data-name="Path 139" d="M150.727,457.406h-7.982v4.613h7.982v-4.613Zm19.954,4.613h7.982v-4.613H142.745v4.613H162.7m3.492,0h1m7.483-7.981H166.69m-11.972-15.964h19.954m-23.945,19.332v-3.368m0,0V430.092a3.99,3.99,0,0,0-3.991-3.991H130.772v23.946h15.964a3.99,3.99,0,0,1,3.991,3.991Zm-7.982-3.991v7.359h35.918V434.083H150.727" fill="none" stroke="#0f0e0b" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -1,76 +0,0 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ExampleNode implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Example Node',
|
||||
name: 'exampleNode',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
description: 'Basic Example Node',
|
||||
defaults: {
|
||||
name: 'Example Node',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
properties: [
|
||||
// Node properties which the user gets displayed and
|
||||
// can change on the node.
|
||||
{
|
||||
displayName: 'My String',
|
||||
name: 'myString',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'Placeholder value',
|
||||
description: 'The description text',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// The function below is responsible for actually doing whatever this node
|
||||
// is supposed to do. In this case, we're just appending the `myString` property
|
||||
// with whatever the user has entered.
|
||||
// You can make async calls and use `await`.
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
|
||||
let item: INodeExecutionData;
|
||||
let myString: string;
|
||||
|
||||
// Iterates over all input items and add the key "myString" with the
|
||||
// value the parameter "myString" resolves to.
|
||||
// (This could be a different value for each item in case it contains an expression)
|
||||
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
||||
try {
|
||||
myString = this.getNodeParameter('myString', itemIndex, '') as string;
|
||||
item = items[itemIndex];
|
||||
|
||||
item.json['myString'] = myString;
|
||||
} catch (error) {
|
||||
// This node should never fail but we want to showcase how
|
||||
// to handle errors.
|
||||
if (this.continueOnFail()) {
|
||||
items.push({ json: this.getInputData(itemIndex)[0].json, error, pairedItem: itemIndex });
|
||||
} else {
|
||||
// Adding `itemIndex` allows other workflows to handle this error
|
||||
if (error.context) {
|
||||
// If the error thrown already contains the context property,
|
||||
// only append the itemIndex
|
||||
error.context.itemIndex = itemIndex;
|
||||
throw error;
|
||||
}
|
||||
throw new NodeOperationError(this.getNode(), error, {
|
||||
itemIndex,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.prepareOutputData(items);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"node": "n8n-nodes-base.httpbin",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Development", "Developer Tools"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "http://httpbin.org/#/Auth/get_bearer"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "http://httpbin.org/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import { INodeType, INodeTypeDescription } from 'n8n-workflow';
|
||||
import { httpVerbFields, httpVerbOperations } from './HttpVerbDescription';
|
||||
|
||||
export class HttpBin implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'HttpBin',
|
||||
name: 'httpBin',
|
||||
icon: 'file:httpbin.svg',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Interact with HttpBin API',
|
||||
defaults: {
|
||||
name: 'HttpBin',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'httpbinApi',
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
requestDefaults: {
|
||||
baseURL: 'https://httpbin.org',
|
||||
url: '',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
/**
|
||||
* In the properties array we have two mandatory options objects required
|
||||
*
|
||||
* [Resource & Operation]
|
||||
*
|
||||
* https://docs.n8n.io/integrations/creating-nodes/code/create-first-node/#resources-and-operations
|
||||
*
|
||||
* In our example, the operations are separated into their own file (HTTPVerbDescription.ts)
|
||||
* to keep this class easy to read.
|
||||
*
|
||||
*/
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'HTTP Verb',
|
||||
value: 'httpVerb',
|
||||
},
|
||||
],
|
||||
default: 'httpVerb',
|
||||
},
|
||||
|
||||
...httpVerbOperations,
|
||||
...httpVerbFields,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
// When the resource `httpVerb` is selected, this `operation` parameter will be shown.
|
||||
export const httpVerbOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['httpVerb'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'GET',
|
||||
value: 'get',
|
||||
description: 'Perform a GET request',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: '/get',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'DELETE',
|
||||
value: 'delete',
|
||||
description: 'Perform a DELETE request',
|
||||
routing: {
|
||||
request: {
|
||||
method: 'DELETE',
|
||||
url: '/delete',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
default: 'get',
|
||||
},
|
||||
];
|
||||
|
||||
// Here we define what to show when the `get` operation is selected.
|
||||
// We do that by adding `operation: ["get"]` to `displayOptions.show`
|
||||
const getOperation: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Type of Data',
|
||||
name: 'typeofData',
|
||||
default: 'queryParameter',
|
||||
description: 'Select type of data to send [Query Parameters]',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['httpVerb'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Query',
|
||||
value: 'queryParameter',
|
||||
},
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Query Parameters',
|
||||
name: 'arguments',
|
||||
default: {},
|
||||
description: "The request's query parameters",
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['httpVerb'],
|
||||
operation: ['get'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'keyvalue',
|
||||
displayName: 'Key:Value',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Key',
|
||||
name: 'key',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Key of query parameter',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
property: '={{$parent.key}}',
|
||||
type: 'query',
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description: 'Value of query parameter',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Here we define what to show when the DELETE Operation is selected.
|
||||
// We do that by adding `operation: ["delete"]` to `displayOptions.show`
|
||||
const deleteOperation: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Type of Data',
|
||||
name: 'typeofData',
|
||||
default: 'queryParameter',
|
||||
description: 'Select type of data to send [Query Parameter Arguments, JSON-Body]',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['httpVerb'],
|
||||
operation: ['delete'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Query',
|
||||
value: 'queryParameter',
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
value: 'jsonData',
|
||||
},
|
||||
],
|
||||
required: true,
|
||||
type: 'options',
|
||||
},
|
||||
{
|
||||
displayName: 'Query Parameters',
|
||||
name: 'arguments',
|
||||
default: {},
|
||||
description: "The request's query parameters",
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['httpVerb'],
|
||||
operation: ['delete'],
|
||||
typeofData: ['queryParameter'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'keyvalue',
|
||||
displayName: 'Key:Value',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Key',
|
||||
name: 'key',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Key of query parameter',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
property: '={{$parent.key}}',
|
||||
type: 'query',
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description: 'Value of query parameter',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'JSON Object',
|
||||
name: 'arguments',
|
||||
default: {},
|
||||
description: "The request's JSON properties",
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['httpVerb'],
|
||||
operation: ['delete'],
|
||||
typeofData: ['jsonData'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'keyvalue',
|
||||
displayName: 'Key:Value',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Key',
|
||||
name: 'key',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Key of JSON property',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
routing: {
|
||||
send: {
|
||||
property: '={{$parent.key}}',
|
||||
type: 'body',
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
description: 'Value of JSON property',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const httpVerbFields: INodeProperties[] = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* httpVerb:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
...getOperation,
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* httpVerb:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
...deleteOperation,
|
||||
];
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve"> <image id="image0" width="32" height="32" x="0" y="0"
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJN
|
||||
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElN
|
||||
RQfmBg4UAC/TqOZZAAACA0lEQVRIx5XVv09TURwF8M+jFHDSyRkGFhPAEfyRdDHi5uriXyDoYgKT
|
||||
MJDWzUT/Ahf/AiOEpajEgCESmpiYmDCxGowDTYE+h76+vte+15Zzk753b7733HNO772PbEw7ECba
|
||||
genswtEcgl0/PHARV72066YrIDSZ6k8KBym4741r0XsB284TdUX8chn1zrzwJUmw4KFXPqjFE0Y0
|
||||
u5YKEhpmfLZuy7f2wLKGI8WhDRYdaVhurdTCidmU5P44N+skaaGQH1IfFFrOYMotT932zNgQExve
|
||||
OfTeT8dtBceO3TFlOyopY7UPxV+/fWyn3Y0xrFhJjZWFXhs12pKdRO9ObGSuyB8Xbd9JjMjDc6HQ
|
||||
IcrKqAiVe8vyCEJPrGBWxZYqqtZt9RbmHabAvAAVdVUlJTvWshbMt0AYn40OmlchSKOePTyYIMQn
|
||||
rb8yI8TsDCrRs4od7Jv3KOoPGWKboBqp2LN3FQvdO7EPshSsRSTXrSop2cSiiUGkG/bj2JqaQiHW
|
||||
4nv50mFcu28j30KQarAnEPhuzvwwGYQ975vx7+JwGXTjTIAzoYlhCArR5d0KkfauqJAVY6+FG5hD
|
||||
OS6veqyCuSiTAQT/jKmlQtyxIBCoZV28HQvN6LuQvJFC4xjvibfYOZUdUXd9taTWJbOubiIVXmjG
|
||||
W/fs9qpZcpr6pOe1U0udSf8BR7ef4yxyOskAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjItMDYtMTRU
|
||||
MTc6MDA6NDcrMDM6MDBfo1sRAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIyLTA2LTE0VDE3OjAwOjQ3
|
||||
KzAzOjAwLv7jrQAAAABJRU5ErkJggg==" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
Loading…
Add table
Add a link
Reference in a new issue