mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-27 23:07:12 +02:00
113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import type {
|
||
IExecuteFunctions,
|
||
INodeExecutionData,
|
||
INodeType,
|
||
INodeTypeDescription,
|
||
} from 'n8n-workflow';
|
||
import { assertParamIsNumber, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||
|
||
export class TimeSaved implements INodeType {
|
||
description: INodeTypeDescription = {
|
||
displayName: 'Track Time Saved',
|
||
name: 'timeSaved',
|
||
icon: 'node:track-time-saved',
|
||
iconColor: 'black',
|
||
group: ['organization'],
|
||
version: 1,
|
||
description:
|
||
'Dynamically track time saved based on the workflow’s execution path and the number of items processed',
|
||
defaults: {
|
||
name: 'Time Saved',
|
||
},
|
||
inputs: [NodeConnectionTypes.Main],
|
||
outputs: [NodeConnectionTypes.Main],
|
||
properties: [
|
||
{
|
||
displayName:
|
||
'For each run, time saved is the sum of all Time Saved nodes that execute. Use this when different execution paths or items save different amounts of time.',
|
||
name: 'notice',
|
||
type: 'notice',
|
||
default: '',
|
||
},
|
||
{
|
||
displayName: 'Calculation Mode',
|
||
name: 'mode',
|
||
type: 'options',
|
||
default: 'once',
|
||
noDataExpression: true,
|
||
options: [
|
||
{
|
||
name: 'Once For All Items',
|
||
value: 'once',
|
||
description: 'Counts minutes saved once for all input items',
|
||
},
|
||
{
|
||
name: 'Per Item',
|
||
value: 'perItem',
|
||
description: 'Multiply minutes saved by the number of input items',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
displayName: 'Minutes Saved',
|
||
name: 'minutesSaved',
|
||
type: 'number',
|
||
default: 0,
|
||
noDataExpression: true,
|
||
typeOptions: {
|
||
minValue: 0,
|
||
numberPrecision: 0,
|
||
},
|
||
description: 'Number of minutes saved by this workflow execution',
|
||
},
|
||
],
|
||
hints: [
|
||
{
|
||
type: 'info',
|
||
message:
|
||
'Multiple Saved Time nodes in the same workflow will have their values summed together.',
|
||
displayCondition: '=true',
|
||
whenToDisplay: 'beforeExecution',
|
||
location: 'outputPane',
|
||
},
|
||
],
|
||
};
|
||
|
||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||
const items = this.getInputData();
|
||
const mode = this.getNodeParameter('mode', 0) as 'fixed' | 'perItem' | 'expression';
|
||
|
||
let timeSavedMinutes = this.getNodeParameter('minutesSaved', 0);
|
||
assertParamIsNumber('minutesSaved', timeSavedMinutes, this.getNode());
|
||
|
||
try {
|
||
if (mode === 'perItem') {
|
||
timeSavedMinutes = items.length * timeSavedMinutes;
|
||
}
|
||
|
||
// Ensure non-negative
|
||
if (timeSavedMinutes < 0) {
|
||
throw new NodeOperationError(
|
||
this.getNode(),
|
||
`Time saved cannot be negative, got: ${timeSavedMinutes}`,
|
||
);
|
||
}
|
||
|
||
// Set metadata using the clean API
|
||
this.setMetadata({
|
||
timeSaved: {
|
||
minutes: timeSavedMinutes,
|
||
},
|
||
});
|
||
|
||
// Pass through all items unchanged
|
||
return [items];
|
||
} catch (error) {
|
||
if (this.continueOnFail()) {
|
||
return [[{ json: { error: error.message } }]];
|
||
}
|
||
throw error;
|
||
}
|
||
}
|
||
}
|