Skip to content

NinjaOne LCP#34

Open
Deenk wants to merge 25 commits intomainfrom
ninjaone
Open

NinjaOne LCP#34
Deenk wants to merge 25 commits intomainfrom
ninjaone

Conversation

@Deenk
Copy link
Copy Markdown

@Deenk Deenk commented Apr 7, 2026

🔌 Plugin overview

  • Plugin name: NinjaOne
  • Purpose / problem solved: Enable squaredup users to monitor devices, endpoints, tickets via NinjaOne RMM
  • Primary audience (e.g. platform teams, SREs, product teams): Systems and helpdesk (Internal and MSP)
  • Authentication method(s) (e.g. OAuth, Username/Password, API Key): Oauth client secret and id

🖼️ Plugin screenshots

Plugin configuration

image image

Default dashboards

image

🧪 Testing

I have tested that every data stream returns unnested arrays and results. data types should all be correct for strings, numbers, dates


⚠️ Known limitations

There are a number of ninjaone modules/add ons based on the licence tier of the customer. I already support the backups and tickets modules, but there are 5/6 more I could add support for later.


📚 Checklist

  • Plugin, datastream and UI naming follow SquaredUp guidelines
  • Logo added
  • One or more dashboards added
  • README added including configuration guidance
  • No secrets or credentials included
  • I agree to the Code of Conduct

@Deenk Deenk added the new-plugin Used to PR newly added plugins label Apr 7, 2026
@Deenk Deenk marked this pull request as ready for review April 7, 2026 08:38
@Deenk Deenk requested a review from clarkd April 7, 2026 10:14
@gdorward
Copy link
Copy Markdown

gdorward commented Apr 7, 2026

@Deenk , I seem to be running into repeated 500 errors on the Backup Management OOB dashboards. Looking at the logs, one of the offending endpoints seems to be https://ca-api.ninjarmm.com/v2/queries/backup/usage?pageSize=1000

ERROR {"message":"handler.readDataSource threw: 500 - Internal Server Error"

@AliceG-Sq AliceG-Sq self-requested a review April 8, 2026 09:06
@Deenk
Copy link
Copy Markdown
Author

Deenk commented Apr 8, 2026

@Deenk , I seem to be running into repeated 500 errors on the Backup Management OOB dashboards. Looking at the logs, one of the offending endpoints seems to be https://ca-api.ninjarmm.com/v2/queries/backup/usage?pageSize=1000

ERROR {"message":"handler.readDataSource threw: 500 - Internal Server Error"

@gdorward This is probably because our license expired for the 'backups' module in NinjaOne. I'll investigate if that truly is the case and either request they fix it, or fix whatever is broken on our side depending on who's fault it is

@Deenk Deenk self-assigned this Apr 8, 2026
@gdorward
Copy link
Copy Markdown

gdorward commented Apr 9, 2026

I'm getting this error on imports all of a sudden @Deenk - specifically importing devices:

{ "name": "Error", "message": "ID column 'deviceId' not found in data stream response. Available columns: results.0.id, results.0.uid, results.0.organizationId, results.0.locationId, results.0.nodeClass, results.0.nodeRoleId, results.0.rolePolicyId, results.0.approvalStatus, results.0.offline, results.0.systemName, results.0.dnsName, results.0.created, results.0.lastContact, results.0.lastUpdate, results.0.deviceId, results.0.displayName, results.1.id, results.1.uid, results.1.organizationId, results.1.locationId, results.1.nodeClass, results.1.nodeRoleId, results.1.rolePolicyId, results.1.approvalStatus, results.1.offline, results.1.systemName, results.1.dnsName, results.1.created, results.1.lastContact, results.1.lastUpdate, results.1.deviceId, results.1.displayName, metadata.next_page_token", "stack": "Error: ID column 'deviceId' not found in data stream response. Available columns: results.0.id, results.0.uid, results.0.organizationId, results.0.locationId, results.0.nodeClass, results.0.nodeRoleId, results.0.rolePolicyId, results.0.approvalStatus, results.0.offline, results.0.systemName, results.0.dnsName, results.0.created, results.0.lastContact, results.0.lastUpdate, results.0.deviceId, results.0.displayName, results.1.id, results.1.uid, results.1.organizationId, results.1.locationId, results.1.nodeClass, results.1.nodeRoleId, results.1.rolePolicyId, results.1.approvalStatus, results.1.offline, results.1.systemName, results.1.dnsName, results.1.created, results.1.lastContact, results.1.lastUpdate, results.1.deviceId, results.1.displayName, metadata.next_page_token at dUe (/src/stepExecutor/mapStreamDataToVertices.ts:62:15) at E1r (/src/stepExecutor/handler.ts:172:33) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async <anonymous> (/src/createMessageHandler.ts:74:13) at async Promise.all (index 0) at async <anonymous> (/src/createMessageHandler.ts:121:32) at async Hcr (/node_modules/.pnpm/@middy+core@2.5.7/node_modules/@middy/core/index.js:86:26)" }

@Deenk
Copy link
Copy Markdown
Author

Deenk commented Apr 9, 2026

I'm getting this error on imports all of a sudden @Deenk - specifically importing devices:

{ "name": "Error", "message": "ID column 'deviceId' not found in data stream response. Available columns: results.0.id, results.0.uid, results.0.organizationId, results.0.locationId, results.0.nodeClass, results.0.nodeRoleId, results.0.rolePolicyId, results.0.approvalStatus, results.0.offline, results.0.systemName, results.0.dnsName, results.0.created, results.0.lastContact, results.0.lastUpdate, results.0.deviceId, results.0.displayName, results.1.id, results.1.uid, results.1.organizationId, results.1.locationId, results.1.nodeClass, results.1.nodeRoleId, results.1.rolePolicyId, results.1.approvalStatus, results.1.offline, results.1.systemName, results.1.dnsName, results.1.created, results.1.lastContact, results.1.lastUpdate, results.1.deviceId, results.1.displayName, metadata.next_page_token", "stack": "Error: ID column 'deviceId' not found in data stream response. Available columns: results.0.id, results.0.uid, results.0.organizationId, results.0.locationId, results.0.nodeClass, results.0.nodeRoleId, results.0.rolePolicyId, results.0.approvalStatus, results.0.offline, results.0.systemName, results.0.dnsName, results.0.created, results.0.lastContact, results.0.lastUpdate, results.0.deviceId, results.0.displayName, results.1.id, results.1.uid, results.1.organizationId, results.1.locationId, results.1.nodeClass, results.1.nodeRoleId, results.1.rolePolicyId, results.1.approvalStatus, results.1.offline, results.1.systemName, results.1.dnsName, results.1.created, results.1.lastContact, results.1.lastUpdate, results.1.deviceId, results.1.displayName, metadata.next_page_token at dUe (/src/stepExecutor/mapStreamDataToVertices.ts:62:15) at E1r (/src/stepExecutor/handler.ts:172:33) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async <anonymous> (/src/createMessageHandler.ts:74:13) at async Promise.all (index 0) at async <anonymous> (/src/createMessageHandler.ts:121:32) at async Hcr (/node_modules/.pnpm/@middy+core@2.5.7/node_modules/@middy/core/index.js:86:26)" }

I broke this during my testing adding more devices, pushing a fix for this now

@Deenk
Copy link
Copy Markdown
Author

Deenk commented Apr 9, 2026

I'm getting this error on imports all of a sudden @Deenk - specifically importing devices:
{ "name": "Error", "message": "ID column 'deviceId' not found in data stream response. Available columns: results.0.id, results.0.uid, results.0.organizationId, results.0.locationId, results.0.nodeClass, results.0.nodeRoleId, results.0.rolePolicyId, results.0.approvalStatus, results.0.offline, results.0.systemName, results.0.dnsName, results.0.created, results.0.lastContact, results.0.lastUpdate, results.0.deviceId, results.0.displayName, results.1.id, results.1.uid, results.1.organizationId, results.1.locationId, results.1.nodeClass, results.1.nodeRoleId, results.1.rolePolicyId, results.1.approvalStatus, results.1.offline, results.1.systemName, results.1.dnsName, results.1.created, results.1.lastContact, results.1.lastUpdate, results.1.deviceId, results.1.displayName, metadata.next_page_token", "stack": "Error: ID column 'deviceId' not found in data stream response. Available columns: results.0.id, results.0.uid, results.0.organizationId, results.0.locationId, results.0.nodeClass, results.0.nodeRoleId, results.0.rolePolicyId, results.0.approvalStatus, results.0.offline, results.0.systemName, results.0.dnsName, results.0.created, results.0.lastContact, results.0.lastUpdate, results.0.deviceId, results.0.displayName, results.1.id, results.1.uid, results.1.organizationId, results.1.locationId, results.1.nodeClass, results.1.nodeRoleId, results.1.rolePolicyId, results.1.approvalStatus, results.1.offline, results.1.systemName, results.1.dnsName, results.1.created, results.1.lastContact, results.1.lastUpdate, results.1.deviceId, results.1.displayName, metadata.next_page_token at dUe (/src/stepExecutor/mapStreamDataToVertices.ts:62:15) at E1r (/src/stepExecutor/handler.ts:172:33) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async <anonymous> (/src/createMessageHandler.ts:74:13) at async Promise.all (index 0) at async <anonymous> (/src/createMessageHandler.ts:121:32) at async Hcr (/node_modules/.pnpm/@middy+core@2.5.7/node_modules/@middy/core/index.js:86:26)" }

I broke this during my testing adding more devices, pushing a fix for this now

@gdorward this is now fixed

@Deenk
Copy link
Copy Markdown
Author

Deenk commented Apr 9, 2026

@Deenk , I seem to be running into repeated 500 errors on the Backup Management OOB dashboards. Looking at the logs, one of the offending endpoints seems to be https://ca-api.ninjarmm.com/v2/queries/backup/usage?pageSize=1000

ERROR {"message":"handler.readDataSource threw: 500 - Internal Server Error"

@gdorward This is probably because our license expired for the 'backups' module in NinjaOne. I'll investigate if that truly is the case and either request they fix it, or fix whatever is broken on our side depending on who's fault it is

@gdorward backups are now all fixed

@AliceG-Sq
Copy link
Copy Markdown

@Deenk Theres around 19 Data streams that don't support any timeframes but 'None' is not available in the dropdown. This is causing a lot of warnings across multiple OOBs as well as they are defaulting to 'None'
image


// Convert numeric IDs to strings
const idFields = ['deviceId', 'organizationId', 'locationId'];
idFields.forEach(field => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider just setting the shape to string for this column, you shouldn't need to coerce it here.

* @param {any} obj
* @returns {any}
*/
const convertTimestamps = (obj) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shame to have to repeat this so much, but it's not easy to share the script functionality today - are you having to do this here because SquaredUp isn't recognising the timestamp format used by NinjaOne?

"name": "totalPhysicalMemory",
"displayName": "Total Memory (Bytes)",
"shape": [
"number",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use the bytes shape for these columns & other streams? SquaredUp will use the most appropriate unit when formatting, i.e. you'll get 4.2GB rather than 421030505

"mode": "none"
},
"expandInnerObjects": true,
"endpointPath": "/v2/organization/{{objects[0].organizationId}}/locations",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this only works with a single object, we should set objectLimit here to avoid users selecting multiple objects?

"mode": "none"
},
"expandInnerObjects": false,
"endpointPath": "/v2/device/{{objects[0].deviceId}}/software",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same again with the object limit

"mode": "none"
},
"expandInnerObjects": true,
"endpointPath": "/v2/ticketing/trigger/board/{{objects[0].boardId}}/run",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same again

"h": 2,
"x": 0,
"y": 0,
"i": "sec-kpi-activethreats-001",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these IDs should be guids - though I know we don't have a full schema right now.

},
{
"category": "feedback",
"url": "https://feedback.squaredup.com/plugins/p/ninjaone",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link looks dead - have we got an alternative page, or could use the support ticket page?

"name": "name",
"type": { "value": "NinjaOne Organization" },
"properties": [{ "organizationId": "id" }, "description", "nodeApprovalMode"],
"externalLink": "{{instanceUrl}}/app/organizations/{{id}}"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be under properties?

Notably, I think you should be able to set links, but we might have an issue with the syntax as there's an open ticket: https://squaredup-eng.atlassian.net/browse/SAAS-9111?search_id=186f205d-1b37-4db8-801f-bc66ebaf628f

@github-actions
Copy link
Copy Markdown

🧩 Plugin PR Summary

📦 Modified Plugins

  • plugins/NinjaOne/v1

📋 Results

Step Status
Validation ✅ Passed
Deployment 🚀 Deployed

🔍 Validation Details

ninja-one
{
  "valid": true,
  "pluginName": "ninja-one",
  "pluginType": "cloud",
  "summary": {
    "Data Streams": 34,
    "Import Definitions": 1,
    "UI Configuration": true,
    "Has Icon": true,
    "Has Default Content": true,
    "Config Validation": false,
    "Custom Types": true
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-plugin Used to PR newly added plugins

Development

Successfully merging this pull request may close these issues.

5 participants