diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..4257b33
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,11 @@
+## v1.1.0 [2023-08-25]
+
+* Add the ability to set [render options](https://carbone.io/api-reference.html#options). Thanks, [@mrtnblv](https://github.com/mrtnblv)!
+
+## v1.0.1 [2023-05-30]
+
+* Add docs suggesting alternative for PDF rendering when running N8N on Docker (i.e. Gotenberg)
+
+## v1.0.0 [2023-50-27]
+
+* Initial release
diff --git a/README.md b/README.md
index d870bd7..15c8e07 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,10 @@ Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes
Must receive an input item with both `$json` and `$binary` keys. The `$json` key may be used to compose the "context", which will be provided to the templating engine. The `$binary` key should contain a DOCX document that contains a valid Carbone template.
+This operation can take "advanced options", which are passed directly to Carbone's rendering engine. See [Carbone's docs](https://carbone.io/api-reference.html#options) for information about each option. They appear in the Options dropdown, at the bottom of the Render operation:
+
+
+
### Convert to PDF
> **NOTE:** This operation requires LibreOffice to be installed. If using the native NPM install, you should install LibreOffice system-wide. If using the Docker images, this operation doesn't seem to work :(
@@ -170,3 +174,27 @@ By default, this configuration will override the incoming file with the response
1. In the new Put Output in Field textfield that appears, set it to a name that is different to the name of the input file (e.g., if the input file is in `data`, set it to `data_pdf` or something)

+
+## Development
+
+More information [here](https://docs.n8n.io/integrations/creating-nodes/test/run-node-locally/).
+
+You must have a local (non-Docker) installation of N8N.
+
+1. Clone this repo
+1. `npm i`
+1. Make changes as required
+1. `npm run build`
+1. `npm link`
+1. Go to N8N's install dir (`~/.n8n/nodes/` on Linux), then run `npm link n8n-nodes-carbonejs`
+1. `n8n start`. If you need to start the N8N instance on another port, `N8N_PORT=5679 n8n start`
+1. There's no need to visit the web UI to install the node: it's already installed since it lives in the correct directory
+1. After making changes in the code and rebuilding, you'll need to stop N8N (Ctrl+C) and restart it (`n8n start`)
+1. For faster changes, instead of rebuilding the code each time, run `npm run dev`. This will start the TypeScript compiler in watch mode, which will recompile the code on every change. You'll still need to restart N8N manually, though.
+
+### Releasing changes
+
+- [ ] Bump the version in `package.json`. We use [SemVer](https://semver.org/).
+- [ ] Add an entry to the top of `CHANGELOG.md` describing the changes.
+- [ ] Push changes, open a PR and merge it to master branch (if developing on another branch)
+- [ ] Create a release. This will kick off the CI which will build and publish the package on NPM
diff --git a/images/image.png b/images/image.png
new file mode 100644
index 0000000..204e9e6
Binary files /dev/null and b/images/image.png differ
diff --git a/nodes/CarboneNode/CarboneNode.node.ts b/nodes/CarboneNode/CarboneNode.node.ts
index 16b97c0..92b261a 100644
--- a/nodes/CarboneNode/CarboneNode.node.ts
+++ b/nodes/CarboneNode/CarboneNode.node.ts
@@ -9,7 +9,7 @@ import {
} from 'n8n-workflow';
import type { Readable } from 'stream';
import { BINARY_ENCODING } from 'n8n-workflow';
-import { convertDocumentToPdf, isWordDocument, renderDocument } from './CarboneUtils';
+import { convertDocumentToPdf, isWordDocument, renderDocument, buildOptions } from './CarboneUtils';
const nodeOperations: INodePropertyOptions[] = [
{
@@ -60,6 +60,69 @@ const nodeOperationOptions: INodeProperties[] = [
},
];
+const nodeOptions: INodeProperties[] = [
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Option',
+ default: {},
+ options: [
+ {
+ displayName: 'Timezone',
+ name: 'timezone',
+ type: 'string',
+ default: 'Europe/Paris',
+ description:
+ 'Convert document dates to a timezone. The date must be chained with the `:formatD` formatter. See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List, in the column "TZ identifier"',
+ },
+ {
+ displayName: 'Locale',
+ name: 'lang',
+ type: 'string',
+ default: 'en',
+ description:
+ 'Locale of the generated document, it will used for translation `{t()}`, formatting numbers with `:formatN`, and currencies `:formatC`. See https://github.com/carboneio/carbone/blob/master/formatters/_locale.js.',
+ },
+ {
+ displayName: 'Complement',
+ name: 'complement',
+ type: 'json',
+ default: '{}',
+ description: 'Extra data accessible in the template with {c.} instead of {d.}',
+ },
+ {
+ displayName: 'Alias',
+ name: 'variableStr',
+ type: 'string',
+ default: '',
+ placeholder: 'e.g. {#def = d.id}', // eslint-disable-line n8n-nodes-base/node-param-placeholder-miscased-id
+ description: 'Predefined alias. See https://carbone.io/documentation.html#alias.',
+ },
+ {
+ displayName: 'Enums',
+ name: 'enum',
+ type: 'json',
+ default: '',
+ placeholder: 'e.g. {"ORDER_STATUS": ["open", "close"]}',
+ description: 'Object with enumerations, use it in reports with `convEnum` formatters',
+ },
+ {
+ displayName: 'Translations',
+ name: 'translations',
+ type: 'json',
+ default: '',
+ placeholder: 'e.g. {"es-es": {"one": "uno"}}',
+ description:
+ 'When the report is generated, all text between `{t( )}` is replaced with the corresponding translation. The `lang` option is required to select the correct translation. See https://carbone.io/documentation.html#translations',
+ },
+ ],
+ displayOptions: {
+ show: { operation: ['render'] },
+ },
+ },
+];
+
export class CarboneNode implements INodeType {
description: INodeTypeDescription = {
displayName: 'Carbone',
@@ -84,7 +147,8 @@ export class CarboneNode implements INodeType {
default: 'render',
},
{
- displayName: 'This operation requires LibreOffice to be installed! If using Docker, see this link for a suggested alternative.',
+ displayName:
+ 'This operation requires LibreOffice to be installed! If using Docker, see this link for a suggested alternative.',
name: 'notice',
type: 'notice',
default: '',
@@ -93,6 +157,7 @@ export class CarboneNode implements INodeType {
},
},
...nodeOperationOptions,
+ ...nodeOptions,
],
};
@@ -130,7 +195,8 @@ export class CarboneNode implements INodeType {
fileContent = Buffer.from(binaryData.data, BINARY_ENCODING);
}
- const rendered = await renderDocument(fileContent, context);
+ const options = buildOptions(this, itemIndex);
+ const rendered = await renderDocument(fileContent, context, options);
item.json = context; // Overwrite the item's JSON data with the used context
diff --git a/nodes/CarboneNode/CarboneUtils.ts b/nodes/CarboneNode/CarboneUtils.ts
index a4ebd5b..148bd92 100644
--- a/nodes/CarboneNode/CarboneUtils.ts
+++ b/nodes/CarboneNode/CarboneUtils.ts
@@ -5,7 +5,7 @@ import path from 'path';
import carbone from 'carbone';
import type { Readable } from 'stream';
-import { IBinaryData } from 'n8n-workflow';
+import { IBinaryData, IExecuteFunctions } from 'n8n-workflow';
// These two functions come straight from https://advancedweb.hu/secure-tempfiles-in-nodejs-without-dependencies/#solution,
// plus typing. These should be safe (from pesky hackers and race conditions), and require no third-party dependencies
@@ -24,15 +24,32 @@ const withTempDir = async (fn: (dirPath: string) => T): Promise => {
const isWordDocument = (data: IBinaryData) =>
data.mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+const buildOptions = (node: IExecuteFunctions, index: number): object => {
+ const additionalFields = node.getNodeParameter('options', index);
+ // console.debug(additionalFields);
+
+ let options: any = {};
+ if(additionalFields.timezone) options.timezone = additionalFields.timezone;
+ if(additionalFields.lang) options.lang = additionalFields.lang;
+ if(additionalFields.variableStr) options.variableStr = additionalFields.variableStr;
+ if(additionalFields.complement) options.complement = JSON.parse(additionalFields.complement as string);
+ if(additionalFields.enum) options.enum = JSON.parse(additionalFields.enum as string);
+ if(additionalFields.translations) options.translations = JSON.parse(additionalFields.translations as string);
+
+ // console.debug(options)
+ return options;
+};
+
const renderDocument = async (
document: Buffer | Readable,
context: any,
+ options: object,
): Promise => {
return withTempFile(async (file) => {
await fs.writeFile(file, document); // Save the template to temp dir, since Carbone needs to read from disk
return await new Promise((resolve, reject) => {
- carbone.render(file, context, {}, function (err, result) {
+ carbone.render(file, context, options, function (err, result) {
if (err) {
reject(err);
}
@@ -65,4 +82,11 @@ const convertDocumentToPdf = async (document: Buffer): Promise => {
});
};
-export { withTempFile, withTempDir, isWordDocument, renderDocument, convertDocumentToPdf };
+export {
+ withTempFile,
+ withTempDir,
+ isWordDocument,
+ buildOptions,
+ renderDocument,
+ convertDocumentToPdf,
+};
diff --git a/package-lock.json b/package-lock.json
index 326a6a4..ec6e89b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "n8n-nodes-carbonejs",
- "version": "0.1.0",
+ "version": "1.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "n8n-nodes-carbonejs",
- "version": "0.1.0",
+ "version": "1.1.0",
"license": "SEE LICENSE IN LICENSE_CARBONE.md AND SEE LICENSE IN LICENSE_N8N.md",
"dependencies": {
"carbone": "^3.5.5",
diff --git a/package.json b/package.json
index e443b74..afee226 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "n8n-nodes-carbonejs",
- "version": "1.0.1",
+ "version": "1.1.0",
"description": "A Carbone JS node that renders Word templates on n8n.io",
"keywords": [
"n8n-community-node-package"