UNPKG

n8n-nodes-monday-parser

Version:

Custom n8n node for parsing and structuring Monday.com data with advanced column type handling

499 lines (498 loc) 21.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MondayParser = void 0; const n8n_workflow_1 = require("n8n-workflow"); class MondayParser { constructor() { this.description = { displayName: 'Monday Parser', name: 'mondayParser', icon: 'file:mondayparser.svg', group: ['transform'], version: 1, description: 'Parse and structure Monday.com data with advanced column type handling', defaults: { name: 'Monday Parser', }, inputs: ['main'], outputs: ['main'], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Transform Data', value: 'transform', description: 'Parse and structure Monday.com data', action: 'Transform Monday.com data', }, ], default: 'transform', }, { displayName: 'Input JSON', name: 'inputJson', type: 'json', default: '{}', description: 'Monday.com data to be transformed (JSON format)', displayOptions: { show: { operation: ['transform'], }, }, }, ], }; } async execute() { const items = this.getInputData(); const operation = this.getNodeParameter('operation', 0); if (operation === 'transform') { const returnData = []; for (let i = 0; i < items.length; i++) { try { // Get JSON input from parameter let inputData; try { const jsonInput = this.getNodeParameter('inputJson', i); inputData = typeof jsonInput === 'string' ? JSON.parse(jsonInput) : jsonInput; } catch (jsonError) { // Fallback to incoming data if JSON parsing fails inputData = items[i].json; } const transformedData = MondayParser.transformMondayData(inputData); returnData.push({ json: transformedData }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: {}, error: new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i }), }); continue; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i, }); } } return [returnData]; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported operation: ${operation}`); } static parseColumnValue(cvValue, cvType) { if (!cvValue) { return null; } try { let valueData; // Try to parse JSON if it's a string if (typeof cvValue === 'string') { try { valueData = JSON.parse(cvValue); } catch { // If not JSON, return as is for simple types return cvValue; } } else { valueData = cvValue; } // Processing by column types switch (cvType) { case 'creation_log': return { created_at: valueData === null || valueData === void 0 ? void 0 : valueData.created_at, creator_id: valueData === null || valueData === void 0 ? void 0 : valueData.creator_id, }; case 'status': if (typeof valueData === 'object' && valueData !== null) { return { label: valueData.label, index: valueData.index, post_id: valueData.post_id, changed_at: valueData.changed_at, }; } return valueData; case 'checkbox': if (typeof valueData === 'object' && valueData !== null) { return { checked: valueData.checked === 'true' || valueData.checked === true, changed_at: valueData.changed_at, }; } return null; case 'long_text': if (typeof valueData === 'object' && valueData !== null) { return { text: valueData.text || '', changed_at: valueData.changed_at || '', }; } return { text: String(valueData) }; case 'link': if (typeof valueData === 'object' && valueData !== null) { return { url: valueData.url, text: valueData.text, changed_at: valueData.changed_at, }; } return null; case 'date': if (typeof valueData === 'object' && valueData !== null) { return { date: valueData.date, time: valueData.time, changed_at: valueData.changed_at, }; } return null; case 'timeline': if (typeof valueData === 'object' && valueData !== null) { return { from: valueData.from, to: valueData.to, changed_at: valueData.changed_at, visualization_type: valueData.visualization_type, }; } return null; case 'people': if (typeof valueData === 'object' && valueData !== null) { const personsTeams = valueData.personsAndTeams || []; return { personsAndTeams: personsTeams, changed_at: valueData.changed_at, persons_count: personsTeams.filter((p) => p.kind === 'person').length, teams_count: personsTeams.filter((p) => p.kind === 'team').length, }; } return null; case 'dropdown': if (typeof valueData === 'object' && valueData !== null) { return { ids: valueData.ids || [], changed_at: valueData.changed_at, }; } return null; case 'tags': if (typeof valueData === 'object' && valueData !== null) { return { tag_ids: valueData.tag_ids || [], changed_at: valueData.changed_at, }; } return null; case 'email': if (typeof valueData === 'object' && valueData !== null) { return { email: valueData.email, text: valueData.text || valueData.email, changed_at: valueData.changed_at, }; } return { email: String(valueData), text: String(valueData) }; case 'phone': if (typeof valueData === 'object' && valueData !== null) { return { phone: valueData.phone, countryShortName: valueData.countryShortName, changed_at: valueData.changed_at, }; } return { phone: String(valueData) }; case 'file': if (typeof valueData === 'object' && valueData !== null) { return { files: valueData.files || [], changed_at: valueData.changed_at, }; } return null; case 'board_relation': if (typeof valueData === 'object' && valueData !== null) { return { linkedPulseIds: valueData.linkedPulseIds || [], changed_at: valueData.changed_at, }; } return null; case 'dependency': if (typeof valueData === 'object' && valueData !== null) { return { linkedPulseIds: valueData.linkedPulseIds || [], changed_at: valueData.changed_at, }; } return null; case 'mirror': if (typeof valueData === 'object' && valueData !== null) { return { linkedPulseId: valueData.linkedPulseId, linkedPulseColumnId: valueData.linkedPulseColumnId, }; } return null; case 'location': if (typeof valueData === 'object' && valueData !== null) { return { address: valueData.address, lat: valueData.lat, lng: valueData.lng, changed_at: valueData.changed_at, }; } return null; case 'country': if (typeof valueData === 'object' && valueData !== null) { return { countryCode: valueData.countryCode, countryName: valueData.countryName, changed_at: valueData.changed_at, }; } return null; case 'rating': if (typeof valueData === 'object' && valueData !== null) { return { rating: valueData.rating, changed_at: valueData.changed_at, }; } return null; case 'vote': if (typeof valueData === 'object' && valueData !== null) { return { votes: valueData.votes || [], voters: valueData.voters || [], changed_at: valueData.changed_at, }; } return null; case 'hour': if (typeof valueData === 'object' && valueData !== null) { return { hour: valueData.hour, minute: valueData.minute, changed_at: valueData.changed_at, }; } return null; case 'week': if (typeof valueData === 'object' && valueData !== null) { return { week: valueData.week, startDate: valueData.startDate, endDate: valueData.endDate, changed_at: valueData.changed_at, }; } return null; case 'world_clock': if (typeof valueData === 'object' && valueData !== null) { return { timezone: valueData.timezone, changed_at: valueData.changed_at, }; } return null; case 'time_tracking': if (typeof valueData === 'object' && valueData !== null) { return { duration: valueData.duration, startDate: valueData.startDate, status: valueData.status, changed_at: valueData.changed_at, }; } return null; case 'formula': return valueData; case 'button': if (typeof valueData === 'object' && valueData !== null) { return { label: valueData.label, color: valueData.color, url: valueData.url, }; } return null; case 'last_updated': if (typeof valueData === 'object' && valueData !== null) { return { updatedAt: valueData.updatedAt, updater: valueData.updater, }; } return null; case 'item_id': return valueData; case 'doc': if (typeof valueData === 'object' && valueData !== null) { return { file_id: valueData.file_id, changed_at: valueData.changed_at, }; } return null; case 'text': case 'numbers': return valueData; default: // Special handling for color column if (cvType === 'color' || (cvType && cvType.includes('color'))) { if (typeof valueData === 'object' && valueData !== null) { return { index: valueData.index, post_id: valueData.post_id, changed_at: valueData.changed_at || '', label: valueData.label, color: valueData.color || '#00c875', }; } return null; } return valueData; } } catch (error) { console.error(`Error parsing column value of type ${cvType}:`, error); return null; } } static getMappableValue(cv, parsedValue) { const cvType = cv === null || cv === void 0 ? void 0 : cv.type; const cvText = cv === null || cv === void 0 ? void 0 : cv.text; if (parsedValue === null) { return null; } // For simple types return text representation if (['text', 'numbers', 'formula', 'item_id'].includes(cvType)) { return cvText || parsedValue; } // For status return text (label) if (cvType === 'status') { return cvText; } // For checkbox return structure with checked and text if (cvType === 'checkbox') { if (typeof parsedValue === 'object' && parsedValue !== null) { return { checked: parsedValue.checked || false, text: cvText, }; } return null; } // For other types return full structure with text field if (typeof parsedValue === 'object' && parsedValue !== null) { // Add text field if it doesn't exist if (!parsedValue.text && cvText) { parsedValue.text = cvText; } return parsedValue; } return parsedValue; } static transformMondayData(item) { var _a, _b, _c; const transformed = { id: item.id, name: item.name, created_at: item.created_at, state: item.state, email: item.email || null, updated_at: new Date().toISOString(), board: { id: ((_a = item.board) === null || _a === void 0 ? void 0 : _a.id) || null }, group: { id: ((_b = item.group) === null || _b === void 0 ? void 0 : _b.id) || null, title: ((_c = item.group) === null || _c === void 0 ? void 0 : _c.title) || null, deleted: false, archived: false, }, assets: [], parent_item: null, subitems: [], creator_id: null, column_values: [], mappable_column_values: {}, }; // Get column_values const columnValues = item.column_values || []; // Find creator_id from creation_log const creationLog = columnValues.find((cv) => cv.type === 'creation_log'); if (creationLog && creationLog.value) { const parsedCreation = MondayParser.parseColumnValue(creationLog.value, 'creation_log'); if (parsedCreation) { transformed.creator_id = parsedCreation.creator_id; } } // Process column_values const transformedColumnValues = []; const mappableColumnValues = {}; for (const cv of columnValues) { const cvId = cv.id; const cvValue = cv.value; const cvText = cv.text; const cvType = cv.type; const cvColumn = cv.column || {}; const cvTitle = cvColumn.title || ''; // Basic structure for transformed_column_values const newCv = { id: cvId, value: cvValue, text: cvText, title: cvTitle, additional_info: undefined, }; // Parse column value const parsedValue = MondayParser.parseColumnValue(cvValue, cvType); // Add additional_info for certain types if (cvType === 'status' && parsedValue && typeof parsedValue === 'object') { const additionalInfo = { label: cvText || parsedValue.label, color: '#00c875', changed_at: parsedValue.changed_at || '', }; newCv.additional_info = JSON.stringify(additionalInfo); } else if (cvType === 'numbers') { // Try to get unit from settings try { const settings = JSON.parse(cvColumn.settings_str || '{}'); if (settings.unit) { newCv.additional_info = JSON.stringify(settings.unit); } } catch { // Ignore parsing errors } } else if (cvId.startsWith('color_') && parsedValue && typeof parsedValue === 'object') { // Special handling for color columns const additionalInfo = { label: cvText || parsedValue.label, color: parsedValue.color || '#00c875', changed_at: parsedValue.changed_at || '', }; newCv.additional_info = JSON.stringify(additionalInfo); } transformedColumnValues.push(newCv); // Create mappable_column_values const mappableValue = MondayParser.getMappableValue(cv, parsedValue); mappableColumnValues[cvId] = mappableValue; } transformed.column_values = transformedColumnValues; transformed.mappable_column_values = mappableColumnValues; return transformed; } } exports.MondayParser = MondayParser;