{ "kind": "open-flow-workflow", "version": 1, "name": "New Google Sheet Rows to Mattermost", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_cf2be5aa437c131c": { "name": "Every minute", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "* * * * *", "timezone": "UTC" } ] }, "n_fe834aad6fd8bf03": { "inputs": { "spreadsheetId": { "kind": "value", "value": "YOUR_SPREADSHEET_ID" }, "range": { "kind": "value", "value": "'Sheet1'!A:Z" }, "majorDimension": { "kind": "value", "value": "ROWS" }, "valueRenderOption": { "kind": "value", "value": "UNFORMATTED_VALUE" } }, "name": "Read the sheet", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The A1 notation of the range to retrieve.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to retrieve." }, "nullable": false, "handle": "range" }, { "description": "The major dimension for the returned values.", "jsonSchema": { "type": "string", "enum": [ "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" ], "description": "The major dimension for the returned values." }, "nullable": true, "handle": "majorDimension", "value": null }, { "description": "How values should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values should be rendered in the output." }, "nullable": true, "handle": "valueRenderOption", "value": null }, { "description": "How dates and times should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates and times should be rendered in the output." }, "nullable": true, "handle": "dateTimeRenderOption", "value": null } ], "outputs": [ { "description": "The A1 notation of the range.", "jsonSchema": { "type": "string", "description": "The A1 notation of the range." }, "nullable": false, "handle": "range" }, { "description": "The major dimension of the values (ROWS or COLUMNS).", "jsonSchema": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "nullable": false, "handle": "majorDimension" }, { "description": "The data values in the range.", "jsonSchema": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" } ], "name": "Read the sheet", "executor": { "kind": "connector", "action": "googlesheets.values_get" } } }, "n_496d95df195216d3": { "inputs": { "values": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fe834aad6fd8bf03", "output": "values" } ] }, "chatId": { "kind": "value", "value": "YOUR_MATTERMOST_CHANNEL_ID" } }, "name": "Find new rows", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "chatId" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "rows" }, { "jsonSchema": { "type": "array" }, "nullable": false, "handle": "ids" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "chatId" } ], "name": "Find new rows", "moduleId": "n_c643582a8249c679", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_1461e6972896794c": { "inputs": { "rows": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_496d95df195216d3", "output": "rows" } ] }, "chatId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_496d95df195216d3", "output": "chatId" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1461e6972896794c", "output": "state" } ] } }, "name": "Prepare next notice", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "rows" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "chatId" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "A Mattermost object ID." }, "nullable": false, "handle": "channelId" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The Markdown message body to post." }, "nullable": false, "handle": "text" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Prepare next notice", "moduleId": "n_4abd3fb9bf08d82f", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_07139fbcffa2bfcb": { "inputs": {}, "name": "More rows to notify", "kind": "condition", "matchMode": "first", "cases": [ { "output": "more", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_1461e6972896794c", "output": "more" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_de220f17c41c53b6": { "inputs": { "channelId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1461e6972896794c", "output": "channelId" } ] }, "message": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1461e6972896794c", "output": "text" } ] } }, "name": "Send a Mattermost notice", "kind": "task", "task": { "inputs": [ { "description": "A Mattermost object ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "A Mattermost object ID." }, "nullable": false, "handle": "channelId" }, { "description": "The Markdown message body to post.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The Markdown message body to post." }, "nullable": false, "handle": "message" }, { "description": "Optional root post ID for replying in a thread.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional root post ID for replying in a thread." }, "nullable": true, "handle": "rootId", "value": null }, { "description": "Optional Mattermost post props object.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Optional Mattermost post props object." }, "nullable": true, "handle": "props", "value": null } ], "outputs": [ { "description": "A Mattermost post object.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Mattermost post object." }, "nullable": false, "handle": "post" }, { "description": "The raw Mattermost API JSON response.", "jsonSchema": { "description": "The raw Mattermost API JSON response." }, "nullable": false, "handle": "raw" } ], "name": "Send a Mattermost notice", "executor": { "kind": "connector", "action": "mattermost.create_post" } } }, "n_cc7cfccb6ecc2437": { "name": "Notification count", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "outputMappings": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1461e6972896794c", "output": "count" } ] } } } }, "edges": [ { "source": "n_cf2be5aa437c131c", "target": "n_fe834aad6fd8bf03" }, { "source": "n_fe834aad6fd8bf03", "target": "n_496d95df195216d3" }, { "source": "n_496d95df195216d3", "target": "n_1461e6972896794c" }, { "source": "n_1461e6972896794c", "target": "n_07139fbcffa2bfcb" }, { "source": "n_07139fbcffa2bfcb", "target": "n_de220f17c41c53b6", "sourceHandle": "more" }, { "source": "n_de220f17c41c53b6", "target": "n_1461e6972896794c" }, { "source": "n_07139fbcffa2bfcb", "target": "n_cc7cfccb6ecc2437", "sourceHandle": "otherwise" } ] } }, "modules": { "n_c643582a8249c679": { "name": "Find new rows", "imports": [], "source": "export default async function plan({values,chatId},context){\n if(!chatId || chatId.startsWith('YOUR_')) throw new Error('Set the Mattermost channel ID');\n if(!Array.isArray(values)) throw new Error('Expected sheet rows');\n const old=await context.state.get('sheet-ids'),ids=old===null?[]:old;\n if(!Array.isArray(ids)) throw new Error('Invalid saved sheet state');\n if(!values.length)return {rows:[],ids,chatId};\n const headers=values[0],names=['ID','Name','Email'],indexes=names.map(n=>headers.indexOf(n));\n const data=values.slice(1).filter(r=>r.some((_,i)=>Boolean(headers[i])));\n if(!data.length)return {rows:[],ids,chatId};\n if(indexes.some((i,j)=>i<0 || headers.lastIndexOf(names[j])!==i)) throw new Error('Sheet needs unique ID, Name and Email headers');\n const rows=data.map(r=>({id:r[indexes[0]],name:r[indexes[1]]??null,email:r[indexes[2]]??null})),selected=[];\n for(let i=rows.length-1;i>=0;i--){if(ids.includes(rows[i].id))break;selected.push(rows[i]);}\n if(rows.some(r=>r.id===undefined || r.id===null || r.id==='')) throw new Error('Every row needs an ID');\n const current=rows.map(r=>r.id);\n await context.state.set('sheet-ids',current);\n return {rows:selected,ids:current,chatId};\n}\n" }, "n_4abd3fb9bf08d82f": { "name": "Prepare next notice", "imports": [], "source": "export default function next({rows,chatId,previousState}){\n const index=previousState===null?0:previousState.index+1;\n if(index>=rows.length)return {state:{index},more:false,channelId:chatId,text:'-',count:rows.length};\n const row=rows[index],v=x=>x==null?'undefined':String(x);\n return {state:{index},more:true,channelId:chatId,text:`New information was added to your Google Sheet.\\nID: ${v(row.id)}\\nName: ${v(row.name)}\\nEmail: ${v(row.email)}`,count:rows.length};\n}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }