Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 19 additions & 40 deletions nodes/Feather/operations/cancelWorkflowExecution.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,28 @@
import { IExecuteFunctions, INodeExecutionData, LoggerProxy as Logger } from 'n8n-workflow';
import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';

export async function executeCancelWorkflowExecution(
this: IExecuteFunctions,
i: number,
baseURL: string,
): Promise<INodeExecutionData> {
try {
Logger.info('Starting workflow execution cancellation...');
// Get the workflow and execution IDs
const workflowId = this.getNodeParameter('workflowId', i) as string;
const executionId = this.getNodeParameter('executionId', i) as string;

// Get the workflow and execution IDs
const workflowId = this.getNodeParameter('workflowId', i) as string;
const executionId = this.getNodeParameter('executionId', i) as string;
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', {
method: 'POST',
url: `${baseURL}/api/v1/workflow/${workflowId}/executions/${executionId}/cancel`,
headers: {
'Content-Type': 'application/json',
accept: 'application/json, text/plain, */*',
},
json: true,
});

Logger.info('Parameters:', { workflowId, executionId });

try {
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', {
method: 'POST',
url: `${baseURL}/api/v1/workflow/${workflowId}/executions/${executionId}/cancel`,
headers: {
'Content-Type': 'application/json',
accept: 'application/json, text/plain, */*',
},
json: true,
});

Logger.info('Workflow execution cancelled successfully:', { response });

return {
json: response,
pairedItem: {
item: i,
},
};
} catch (apiError) {
Logger.error('API request failed:', { error: apiError });
Logger.error('Request details:', {
url: `${baseURL}/api/v1/workflow/${workflowId}/executions/${executionId}/cancel`,
workflowId,
executionId,
});
throw apiError;
}
} catch (error) {
Logger.error('Error in workflow execution cancellation:', { error });
throw error;
}
return {
json: response,
pairedItem: {
item: i,
},
};
}
281 changes: 122 additions & 159 deletions nodes/Feather/operations/createAgentWorkflow.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IExecuteFunctions, INodeExecutionData, LoggerProxy as Logger } from 'n8n-workflow';
import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';

type WorkflowStep = {
id: string;
Expand Down Expand Up @@ -71,168 +71,131 @@ export async function executeCreateAgentWorkflow(
i: number,
baseURL: string,
): Promise<INodeExecutionData> {
try {
Logger.info('Starting workflow creation...');

// Get basic workflow information
const name = this.getNodeParameter('name', i) as string;
const description = this.getNodeParameter('description', i) as string;
const active = this.getNodeParameter('active', i) as boolean;
const timezone = this.getNodeParameter('timezone', i) as string;
const agentId = this.getNodeParameter('agentId', i) as string;

Logger.info('Basic parameters:', { name, description, active, timezone, agentId });

// Get step configuration
const stepConfig = this.getNodeParameter('stepConfiguration', i) as Record<string, unknown>;
Logger.info('Step configuration:', stepConfig);

// Get schedule configurations
const workflowScheduleUi = this.getNodeParameter('workflowScheduleUi', i) as Record<
string,
unknown
>;
const tcpaScheduleUi = this.getNodeParameter('tcpaScheduleUi', i) as Record<string, unknown>;

const workflowScheduleData = workflowScheduleUi?.scheduleConfiguration || {};
const tcpaScheduleData = tcpaScheduleUi?.tcpaConfiguration || {};

Logger.info('Schedule configurations:', { workflowScheduleData, tcpaScheduleData });

// Build workflow schedule
const workflowSchedule: Schedule = {
monday: { enabled: false, timeRanges: [] },
tuesday: { enabled: false, timeRanges: [] },
wednesday: { enabled: false, timeRanges: [] },
thursday: { enabled: false, timeRanges: [] },
friday: { enabled: false, timeRanges: [] },
saturday: { enabled: false, timeRanges: [] },
sunday: { enabled: false, timeRanges: [] },
};

// Build TCPA schedule
const tcpaSchedule: Schedule = {
monday: { enabled: false, timeRanges: [] },
tuesday: { enabled: false, timeRanges: [] },
wednesday: { enabled: false, timeRanges: [] },
thursday: { enabled: false, timeRanges: [] },
friday: { enabled: false, timeRanges: [] },
saturday: { enabled: false, timeRanges: [] },
sunday: { enabled: false, timeRanges: [] },
};

// Configure workflow schedule
if (workflowScheduleData) {
Logger.info('Configuring workflow schedule...');
const scheduleData = workflowScheduleData as Record<string, unknown>;
const {
workingDays = [],
workingHoursStart = 9,
workingHoursEnd = 17,
workingMinutesStart = 0,
workingMinutesEnd = 0,
} = scheduleData;

Logger.info('Working days configuration:', { workingDays });

if (Array.isArray(workingDays) && workingDays.length > 0) {
for (const day of workingDays) {
workflowSchedule[day as keyof Schedule] = {
enabled: true,
timeRanges: [
{
startHour: Number(workingHoursStart),
startMinute: Number(workingMinutesStart),
endHour: Number(workingHoursEnd),
endMinute: Number(workingMinutesEnd),
},
],
};
}
Logger.info('Workflow schedule configured:', workflowSchedule);
} else {
Logger.info('No working days configured, using default empty schedule');
}
}
// Get basic workflow information
const name = this.getNodeParameter('name', i) as string;
const description = this.getNodeParameter('description', i) as string;
const active = this.getNodeParameter('active', i) as boolean;
const timezone = this.getNodeParameter('timezone', i) as string;
const agentId = this.getNodeParameter('agentId', i) as string;

// Get step configuration
const stepConfig = this.getNodeParameter('stepConfiguration', i) as Record<string, unknown>;

// Get schedule configurations
const workflowScheduleUi = this.getNodeParameter('workflowScheduleUi', i) as Record<
string,
unknown
>;
const tcpaScheduleUi = this.getNodeParameter('tcpaScheduleUi', i) as Record<string, unknown>;

const workflowScheduleData = workflowScheduleUi?.scheduleConfiguration || {};
const tcpaScheduleData = tcpaScheduleUi?.tcpaConfiguration || {};

// Build workflow schedule
const workflowSchedule: Schedule = {
monday: { enabled: false, timeRanges: [] },
tuesday: { enabled: false, timeRanges: [] },
wednesday: { enabled: false, timeRanges: [] },
thursday: { enabled: false, timeRanges: [] },
friday: { enabled: false, timeRanges: [] },
saturday: { enabled: false, timeRanges: [] },
sunday: { enabled: false, timeRanges: [] },
};

// Configure TCPA schedule
if (tcpaScheduleData) {
Logger.info('Configuring TCPA schedule...');
const tcpaData = tcpaScheduleData as Record<string, unknown>;
const {
tcpaDays = [],
tcpaHoursStart = 8,
tcpaHoursEnd = 21,
tcpaMinutesStart = 0,
tcpaMinutesEnd = 0,
} = tcpaData;

Logger.info('TCPA days configuration:', { tcpaDays });

if (Array.isArray(tcpaDays) && tcpaDays.length > 0) {
for (const day of tcpaDays) {
tcpaSchedule[day as keyof Schedule] = {
enabled: true,
timeRanges: [
{
startHour: Number(tcpaHoursStart),
startMinute: Number(tcpaMinutesStart),
endHour: Number(tcpaHoursEnd),
endMinute: Number(tcpaMinutesEnd),
},
],
};
}
Logger.info('TCPA schedule configured:', tcpaSchedule);
} else {
Logger.info('No TCPA days configured, using default empty schedule');
// Build TCPA schedule
const tcpaSchedule: Schedule = {
monday: { enabled: false, timeRanges: [] },
tuesday: { enabled: false, timeRanges: [] },
wednesday: { enabled: false, timeRanges: [] },
thursday: { enabled: false, timeRanges: [] },
friday: { enabled: false, timeRanges: [] },
saturday: { enabled: false, timeRanges: [] },
sunday: { enabled: false, timeRanges: [] },
};

// Configure workflow schedule
if (workflowScheduleData) {
const scheduleData = workflowScheduleData as Record<string, unknown>;
const {
workingDays = [],
workingHoursStart = 9,
workingHoursEnd = 17,
workingMinutesStart = 0,
workingMinutesEnd = 0,
} = scheduleData;

if (Array.isArray(workingDays) && workingDays.length > 0) {
for (const day of workingDays) {
workflowSchedule[day as keyof Schedule] = {
enabled: true,
timeRanges: [
{
startHour: Number(workingHoursStart),
startMinute: Number(workingMinutesStart),
endHour: Number(workingHoursEnd),
endMinute: Number(workingMinutesEnd),
},
],
};
}
}
}

const stepDefinition = buildWorkflowDefinition(agentId, stepConfig?.stepSettings || {});

const workflow = {
name,
description,
active,
timezone,
workflowSchedule,
tcpaSchedule,
definition: stepDefinition,
};

Logger.info('Preparing API request with workflow:', { workflow });

try {
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', {
method: 'POST',
url: `${baseURL}/api/v1/workflow`,
headers: {
'Content-Type': 'application/json',
accept: 'application/json, text/plain, */*',
},
body: workflow,
json: true,
});

Logger.info('Workflow created successfully:', { response });

return {
json: response,
pairedItem: {
item: i,
},
};
} catch (apiError) {
Logger.error('API request failed:', apiError);
Logger.error('Request details:', {
url: `${baseURL}/api/v1/workflow`,
workflow,
});
throw apiError;
// Configure TCPA schedule
if (tcpaScheduleData) {
const tcpaData = tcpaScheduleData as Record<string, unknown>;
const {
tcpaDays = [],
tcpaHoursStart = 8,
tcpaHoursEnd = 21,
tcpaMinutesStart = 0,
tcpaMinutesEnd = 0,
} = tcpaData;

if (Array.isArray(tcpaDays) && tcpaDays.length > 0) {
for (const day of tcpaDays) {
tcpaSchedule[day as keyof Schedule] = {
enabled: true,
timeRanges: [
{
startHour: Number(tcpaHoursStart),
startMinute: Number(tcpaMinutesStart),
endHour: Number(tcpaHoursEnd),
endMinute: Number(tcpaMinutesEnd),
},
],
};
}
}
} catch (error) {
Logger.error('Error in workflow creation:', error);
throw error;
}

const stepDefinition = buildWorkflowDefinition(agentId, stepConfig?.stepSettings || {});

const workflow = {
name,
description,
active,
timezone,
workflowSchedule,
tcpaSchedule,
definition: stepDefinition,
};

const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', {
method: 'POST',
url: `${baseURL}/api/v1/workflow`,
headers: {
'Content-Type': 'application/json',
accept: 'application/json, text/plain, */*',
},
body: workflow,
json: true,
});

return {
json: response,
pairedItem: {
item: i,
},
};
}
Loading