How to Reuse Code Snippets and Recreate Exports in a Pipedream Workflow and What are the Required Fields for Publishing an Action?

This topic was automatically generated from Slack. You can find the original thread here.

How can I reuse code snippets or recreate exports in multiple steps within a Pipedream workflow? Also, what are the required fields for publishing an action, as I’m encountering errors related to ‘name’, ‘key’, ‘version’, and ‘type’ fields?

To reuse code snippets or recreate exports in multiple steps within a Pipedream workflow, you can create and use actions. Actions are reusable code steps that integrate your apps, data, and APIs. You can create your own actions that can be shared across your workflows or published to all Pipedream users. To publish an action from a Node.js code step, you need to define the following fields in the defineComponent function: 1. name: A string that represents the name of the action. 2. version: A string that represents the version of the action (e.g., ‘0.0.1’). 3. key: A unique string identifier for the action. 4. type: A string that should be set to ‘action’. Here’s an example: export default defineComponent({ name: 'Format Date', version: '0.0.1', key: 'format-date', type: 'action', props: { // Your props here }, async run({ $ }) { // Your code here }, }); If you need to update the underlying code of your published Node.js code step, increment the version field and make the necessary changes. For more information on sharing code across workflows, visit the Pipedream documentation.

I’m encountering an issue while trying to publish a custom action in a Node.js code step. The error message states, “Identifier ‘defineComponent’ has already been declared,” and it points to line 192. However, my code only has 191 lines.
Here’s a snippet of my code for context:

javascript

import { defineComponent } from '@pipedreamhq/platform'; import _ from 'lodash'; export default defineComponent({ name: 'Generate Reports', version: '0.0.1', key: 'generate-reports', type: 'action', async run({ steps, $ }) { // ... (rest of the code) return { // ... (return values) }; }, }); 

I’ve already checked for duplicate imports and auto-generated code but found nothing that could be causing this issue. Could you please assist me in resolving this?

I noticed that you’re importing defineComponent from @pipedreamhq/platform. In Pipedream’s Node.js runtime, defineComponent is actually a global function, so you don’t need to import it. Please remove the import statement and your code should work without issues. Here’s the updated code snippet: ```
import _ from ‘lodash’; export default defineComponent({ name: ‘Generate Reports’, version: ‘0.0.1’, key: ‘generate-reports’, type: ‘action’, async run({ steps, $ }) { // … (rest of the code) return { // … (return values) }; }, });

am facing an issue with my node.js Pipedream action component. My code works perfectly when it’s not wrapped in defineComponent, but as soon as I wrap it in defineComponent to make it an action, my exports and logs turn up empty.
Here’s a brief overview of what my action is supposed to do:

  1. Retrieve data from multiple Notion databases.
  2. Process this data to generate reports for areas, projects, and tasks.
  3. Export these reports in various formats, including JSON.
  4. Log the schema of these reports for debugging.
    I’ve ensured that my code adheres to best practices, including the use of helper functions for code reusability and separation of concerns. Despite this, I’m unable to see any logs or exports when the code is wrapped in defineComponent.
    Could you please help me understand why this might be happening? Is there something specific about defineComponent that could be causing this issue?

It’s difficult to pinpoint the exact issue without seeing your complete code. However, I can provide some general guidance that might help you identify the problem. When using defineComponent, make sure you’re returning the desired data at the end of the run method. The data returned should be JSON-serializable. If you were using console.log() for logging in your original code, you might want to switch to using $.export() for exporting data within the run method for debugging purposes. For example: ```
$.export(“debug_data”, yourData);

complete code:

// Import lodash for deep property access
import _ from ‘lodash’;

export default defineComponent({
name: ‘Generate Reports’,
version: ‘0.0.1’,
key: ‘generate-reports’,
type: ‘action’,
async run({ steps, $ }) {
// Function to extract properties from a database item with data validation
const extractProperties = (item, schema) => {
const extracted = {};
for (const [key, path] of Object.entries(schema)) {
if (_.has(item, path)) { // Validate if the path exists in the item before extracting
const value = _.get(item, path);
if (value !== null && value !== undefined) {
extracted[key] = value;
}
}
}
return extracted;
};

_// Function to build the schema of an object_
**const** buildSchema = (obj, schema = {}) => {
  **for** (**const** key **in** obj) {
    **if** (**typeof** obj[key] === 'object' && obj[key] !== **null**) {
      schema[key] = {};
      buildSchema(obj[key], schema[key]);
    } **else** {
      schema[key] = **typeof** obj[key];
    }
  }
  **return** schema;
};
    _// Function to print the schema of an object_
**const** printSchema = (obj, indent = 0) => {
  **for** (**const** key **in** obj) {
    console.log(" ".repeat(indent) + key);
    **if** (**typeof** obj[key] === 'object' && obj[key] !== **null**) {
      printSchema(obj[key], indent + 2);
    }
  }
};

// Retrieve data from Notion databases
const taskDatabaseEntries = await steps?.retrieve_tasks_database?.$return_value || [];
const projectDatabaseEntries = await steps?.retrieve_projects_database?.$return_value || [];
const areaDatabaseEntries = await steps?.retrieve_areas_database?.$return_value || [];

// Initialize reports
let areaReports = {};
let projectReports = {};
let taskReports = {};

// Define schemas for extracting properties
const areaSchema = {
type: ‘properties.Type.select.name’,
projects: ‘properties.Projects.relation’,
name: ‘properties.Name.title[0].text.content’,
areaNotes: ‘properties[“Area Notes”].rich_text[0].text.content’,
resources: ‘properties.Resources.relation’,
subscriptions: ‘properties.Subscriptions.relation’,
goals: ‘properties.goals.relation’,
overview: ‘properties.Overview.rich_text[0].text.content’,
coverImageUrl: ‘cover.file.url’,
emoji: ‘icon.emoji’
};

const projectSchema = {
name: ‘properties.Name.title[0].text.content’,
status: ‘properties.Status.select.name’,
priority: ‘properties.Priority.checkbox’,
targetDeadlineType: ‘properties[“Target Deadline”].date’,
overdueTasks: ‘properties[“Overdue Tasks”].rollup.number’,
createdTime: ‘properties.Created.created_time’,
quarter: ‘properties.Quarter.formula.string’,
progress: ‘properties.Progress.formula.number’,
tasksDone: ‘properties[“Tasks Done”].rollup.number’,
goalRelation: ‘properties.Goal.relation’,
areaRelation: ‘properties.Area.relation’,
projectTasks: ‘properties[“Project Tasks”].rollup.number’,
pulledResourcesRelation: ‘properties[“Pulled Resources”].relation’,
notesRelation: ‘properties.Notes.relation’,
pulledNotesRelation: ‘properties[“Pulled Notes”].relation’,
summary: ‘properties.Summary.rich_text[0].text.content’,
reviewNotes: ‘properties[“Review Notes”].rich_text[0].text.content’,
meta: ‘properties.Meta.formula.string’,
completedDate: ‘properties.Completed.date’,
iconEmoji: ‘icon.emoji’,
coverUrl: ‘cover.file.url’,
url: ‘url’
};

const taskSchema = {
taskTitle: ‘properties.Task.title[0].text.content’,
priority: ‘properties.Priority.select.name’,
dueDate: ‘properties.Due.date’,
isDone: ‘properties.Done.checkbox’,
kanbanStatus: ‘properties[“Kanban Status”].select.name’,
summary: ‘properties.Summary.rich_text[0].text.content’,
assignee: ‘properties.Assignee.people’,
projectIds: ‘properties.Project.relation’,
startDate: ‘properties.Start.date’,
lastEditedTime: ‘properties.Edited.last_edited_time’,
parentTask: ‘properties[“Parent Task”].relation’,
subTaskCount: ‘properties[“Sub-Task Count”].rollup.type’,
type: ‘properties.Type.formula.string’,
kanbanTag: ‘properties[“Kanban - Tag”].select’,
recurUnit: ‘properties[“Recur Unit”].select’,
isCold: ‘properties.Cold.formula.boolean’,
note: ‘properties.Note.rich_text’,
emoji: ‘icon.emoji’,
createdBy: ‘properties[“Created By”].created_by.name’,
url: ‘url’
};

// Abstract the processing into helper functions
function processAreas(areas, schema) {
areas.forEach(area => {
const areaData = extractProperties(area, schema);
areaReports[area.id] = {
…areaData,
projects: []
};
});
}

function processProjects(projects, schema) {
projects.forEach(project => {
const projectData = extractProperties(project, schema);
projectReports[project.id] = {
…projectData,
tasks: []
};
const areaId = _.get(project, ‘properties.Area.relation[0].id’);
if (areaReports[areaId]) {
areaReports[areaId].projects.push(projectData);
}
});
}

function processTasks(tasks, schema) {
tasks.forEach(task => {
const taskData = extractProperties(task, schema);
taskReports[task.id] = taskData;
const projectId = _.get(task, ‘properties.Project.relation[0].id’);
if (projectReports[projectId]) {
projectReports[projectId].tasks.push(taskData);
}
});
}

// Call the helper functions
processAreas(areaDatabaseEntries, areaSchema);
processProjects(projectDatabaseEntries, projectSchema);
processTasks(taskDatabaseEntries, taskSchema);

// Move schema printing out
console.log(“Schema for areaReports:”);
printSchema(areaReports);

_// Generate JSON reports_
**const** areaReportsJSON = JSON.stringify(areaReports);
**const** projectReportsJSON = JSON.stringify(projectReports);
**const** taskReportsJSON = JSON.stringify(taskReports);

_// Print the schema of the reports_
console.log("Schema for areaReports:");
printSchema(areaReports);

console.log("Schema for projectReports:");
printSchema(projectReports);

console.log("Schema for taskReports:");
printSchema(taskReports);

// Build the schema of the reports
const areaReportsSchema = buildSchema(areaReports);
const projectReportsSchema = buildSchema(projectReports);
const taskReportsSchema = buildSchema(taskReports);

// Convert the schema to JSON
const areaReportsSchemaJSON = JSON.stringify(areaReportsSchema);
const projectReportsSchemaJSON = JSON.stringify(projectReportsSchema);
const taskReportsSchemaJSON = JSON.stringify(taskReportsSchema);

// Exports
return {
areaReports,
projectReports,
taskReports,
areaReportsJSON,
projectReportsJSON,
taskReportsJSON,
areaReportsSchema,
projectReportsSchema,
taskReportsSchema,
areaReportsSchemaJSON,
projectReportsSchemaJSON,
taskReportsSchemaJSON
};
},
});

Here’s the complete code you provided: ``` import _ from ‘lodash’; import { defineComponent } from “@pipedream/platform”; export default defineComponent({ name: ‘Generate Reports’, version: ‘0.0.1’, key: ‘generate-reports’, type: ‘action’, async run({ steps, $ }) { // Function to extract properties from a database item with data validation const extractProperties = (item, schema) => { const extracted = {}; for (const [key, path] of Object.entries(schema)) { if (_.has(item, path)) { // Validate if the path exists in the item before extracting const value = _.get(item, path); if (value !== null && value !== undefined) { extracted[key] = value; } } } return extracted; }; // Function to build the schema of an object const buildSchema = (obj, schema = {}) => { for (const key in obj) { if (typeof obj[key] === ‘object’ && obj[key] !== null) { schema[key] = {}; buildSchema(obj[key], schema[key]); } else { schema[key] = typeof obj[key]; } } return schema; }; // Function to print the schema of an object const printSchema = (obj, indent = 0) => { for (const key in obj) { console.log(" ".repeat(indent) + key); if (typeof obj[key] === ‘object’ && obj[key] !== null) { printSchema(obj[key], indent + 2); } } }; // Retrieve data from Notion databases const taskDatabaseEntries = await steps?.retrieve_tasks_database?.$return_value || []; const projectDatabaseEntries = await steps?.retrieve_projects_database?.$return_value || []; const areaDatabaseEntries = await steps?.retrieve_areas_database?.$return_value || []; // Initialize reports let areaReports = {}; let projectReports = {}; let taskReports = {}; // Define schemas for extracting properties const areaSchema = { type: ‘properties.Type.select.name’, projects: ‘properties.Projects.relation’, name: ‘properties.Name.title[0].text.content’, areaNotes: 'properties[“Area Notes”].rich_text[

I’m facing an issue with my Pipedream action when using defineComponent. My action is designed to generate reports based on Notion databases. It fetches data from multiple Notion databases, processes it, and then exports the reports in JSON format.

Here’s what I’ve observed:

  • When I include defineComponent, name, version, key, and type metadata, the exports and logs are empty.
  • When I remove these metadata fields, everything works as expected.

I’ve ensured that:

  • I’m returning JSON-serializable data at the end of the run method.
  • I’ve tried using $.export() for debugging.

Could you please help me understand why the action behaves differently when wrapped with defineComponent? Is there something specific that needs to be done when using defineComponent to ensure that the data is exported correctly?

It’s unusual that the action behaves differently when using defineComponent with the metadata fields. The metadata fields should not affect the execution of your action. However, I’d like to help you troubleshoot the issue. 1. Make sure you’re returning the JSON-serializable data at the end of the run method when using defineComponent. If you’re using $.export() for debugging, ensure that you’re providing a name and value for the export, like this: $.export("report", reportData); 2. Double-check if you have any syntax errors or misplaced code blocks when adding the metadata fields. 3. Ensure that you’re using the correct format for the metadata fields: ```
export default defineComponent({ name: ‘Generate Reports’, version: ‘0.0.1’, key: ‘generate-reports’, type: ‘action’, async run({ steps, $ }) { // Your code here }, });