Any way to get list of all triggers?

I have a lot of triggers. Some just run once, others every set time interval. Is there a way of getting a list of all these triggers and showing when they fire?

My initial thought would be to parse the flows.json file and grab the data from there. Is there a better way?

What types of triggers are you referring to? Is that a particular node type you are using? Or are you using that as a general term for how your flows are started?

Sorry, I should use the proper name! The inject nodes.
I use them as triggers, so that's what I got used to calling them :slight_smile:

this might be stupid, but here's my solve for stuff like this

ctrl+F on the backend
type 'inject' in and you should get a list of all of them

you can also search inside of function nodes using this, which has been a debugging lifesaver for me

it doesn't show 'when they fire' though, but maybe this is a good start

ps- i name my (i call them triggers too) inject nodes so they tell me how long between repeats ie: 10 sec trigger) or just once (reset flow variables)

You could use the admin API and retrieve the details

I created this trivial flow

[
    {
        "id": "4c65c2239626cd4b",
        "type": "inject",
        "z": "5a088fb39c10237a",
        "name": "Trigger",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "300",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payloadType": "date",
        "x": 210,
        "y": 2280,
        "wires": [
            [
                "70ccc2a69aaf2bf0"
            ]
        ]
    },
    {
        "id": "70ccc2a69aaf2bf0",
        "type": "http request",
        "z": "5a088fb39c10237a",
        "name": "Get flows",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "localhost:1880/flows",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 430,
        "y": 2280,
        "wires": [
            [
                "946dd11ca12996c0"
            ]
        ]
    },
    {
        "id": "97a4cf26b852bf9d",
        "type": "debug",
        "z": "5a088fb39c10237a",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 830,
        "y": 2280,
        "wires": []
    },
    {
        "id": "946dd11ca12996c0",
        "type": "function",
        "z": "5a088fb39c10237a",
        "name": "Filter only ",
        "func": "const injectNodes = msg.payload.filter((element) => element.type == \"inject\" )\nconst tabs = msg.payload.filter((element) => element.type == \"tab\" )\n\nconst injectNodeList = []\n\ninjectNodes.forEach((node) => {\n    const tab = tabs.find((tab) => tab.id == node.z )\n    const inject = node\n    inject.name = node.name != \"\" ? node.name  : \"blank\"\n    inject.tab = tab.label\n    injectNodeList.push(inject)\n})\nmsg.injectNodes = injectNodes\nmsg.injectNodeList = injectNodeList\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 640,
        "y": 2280,
        "wires": [
            [
                "97a4cf26b852bf9d"
            ]
        ]
    }
]

It would return an array of objects like

{"id":"4c65c2239626cd4b","type":"inject","z":"5a088fb39c10237a","name":"Trigger","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"300","crontab":"","once":true,"onceDelay":0.1,"topic":"","payloadType":"date","x":210,"y":2280,"wires":[["70ccc2a69aaf2bf0"]],"tab":"CSV Load"}
1 Like

instead of

    inject.tab = tab.label

should be

    inject.tab = node.label

otherwise I'm getting: "TypeError: Cannot read property 'label' of undefined"

Interesting - while I am not checking tab exists I am not sure why it does not

regardless, If I was going to change the code it would be to

inject.tab = tab != null ? tab.label : "no tab label"

That's awesome, thanks.
I'll have a play and dump it into a pretty table :slight_smile:

Using @chrisn-au example and the table node from node-red-node-ui-table I have put together a little display that I may still tweak with, but looks OK so far. You'll also need the cronstrue npm module for the human readable timings.

[{"id":"4c65c2239626cd4b","type":"inject","z":"da204325.2b65f","name":"Get Triggers","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[]","payloadType":"json","x":130,"y":260,"wires":[["70ccc2a69aaf2bf0","0b3b8f8728bf56eb"]]},{"id":"70ccc2a69aaf2bf0","type":"http request","z":"da204325.2b65f","name":"Get flows","method":"GET","ret":"obj","paytoqs":"ignore","url":"localhost:1880/flows","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":320,"y":280,"wires":[["946dd11ca12996c0"]]},{"id":"946dd11ca12996c0","type":"function","z":"da204325.2b65f","name":"Filter only ","func":"function nodeType(node) {\n return ((node.type == \"inject\") || (node.type == \"cronplus\"))\n}\nconst injectNodes = msg.payload.filter(nodeType);\nconst injectNodeList = [];\n\ninjectNodes.forEach((node) => {\n const inject = node;\n inject.name = node.name != \"\" ? node.name : \"blank\";\n injectNodeList.push(inject);\n})\n\n//msg.injectNodes = injectNodes\nmsg.injectNodeList = injectNodeList;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":280,"wires":[["14a8b8bde7b3cb2b"]]},{"id":"14a8b8bde7b3cb2b","type":"function","z":"da204325.2b65f","name":"Parse Data","func":"//const cronstrue = require('cronstrue');\n\nmsg.injectNodeList.forEach(item => {\n var linksTo = [];\n\n if (item.wires) {\n (item.wires[0]).forEach(linkOut => {\n const foundOut = msg.payload.find((foundOut) => foundOut.id == linkOut);\n\n if (foundOut.type === \"link out\") {\n (foundOut.links).forEach(linkIn => {\n const foundIn = msg.payload.find((foundIn) => foundIn.id == foundOut);\n linksTo.push(`[L] ${foundOut.name}`);\n })\n }\n else {\n linksTo.push(`[N] ${foundOut.name}`);\n }\n })\n }\n\n var cronString = \"\";\n if (item.options) { item.crontab = item.options[0].expression }\n if (item.crontab) {\n cronString = cronstrue.toString(item.crontab, {use24HourTimeFormat: true, monthStartIndexZero: true});\n }\n\n node.send({\n \"payload\":{\n name: item.name,\n once: item.once,\n delay: item.oncedelay,\n repeat: item.repeat,\n crontab: cronString,\n n: linksTo.length,\n linksTo: linksTo\n }\n });\n});\n\nnode.done;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"cronstrue","module":"cronstrue"}],"x":650,"y":280,"wires":[["ae065a9af46dba6f"]]},{"id":"ae065a9af46dba6f","type":"join","z":"da204325.2b65f","name":"Join","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"1","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":810,"y":280,"wires":[["7d0dfd0e0757cca2"]]},{"id":"7d0dfd0e0757cca2","type":"ui_table","z":"da204325.2b65f","group":"cdb12a338f126946","name":"Trigger List","order":0,"width":"24","height":"19","columns":[],"outputs":0,"cts":false,"x":990,"y":240,"wires":[]},{"id":"0b3b8f8728bf56eb","type":"change","z":"da204325.2b65f","name":"Format Columns","rules":[{"t":"set","p":"ui_control","pt":"msg","to":"{\"tabulator\":{\"layout\":\"fitDataFill\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":240,"wires":[["7d0dfd0e0757cca2"]]},{"id":"cdb12a338f126946","type":"ui_group","name":"Testing","tab":"cf15d7badfb5510b","order":2,"disp":true,"width":"24","collapse":false,"className":""},{"id":"cf15d7badfb5510b","type":"ui_tab","name":"Testing","icon":"dashboard","order":11,"disabled":false,"hidden":false}]

1 Like

The admin API is pretty cool, great to see it worked for you, actually, you have solved an issue I didn't even know I had. A nice way to get the data on what is been injected - Just need to make sure we name nodes nicely - :slight_smile: