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
Comment thread plugins/NinjaOne/v1/metadata.json
Comment thread plugins/NinjaOne/v1/dataStreams/organizationDevices.json Outdated
Comment thread plugins/NinjaOne/v1/defaultContent/backupManagement.dash.json Outdated
Comment thread plugins/NinjaOne/v1/ui.json
Comment thread plugins/NinjaOne/v1/dataStreams/activities.json
@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
  }
}

Copy link
Copy Markdown
Contributor

@vinbab vinbab left a comment

Choose a reason for hiding this comment

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

@Deenk feedback on the setup screen:

  • Do we need to ask both the Region and API Region? Would one suffice to derive the API endpoint?
  • Client Secret: lowercase secret in field title, placeholder and tooltip

Copy link
Copy Markdown
Contributor

@vinbab vinbab left a comment

Choose a reason for hiding this comment

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

@Deenk feedback on Objects

  • My recommendation is to use a Source Type name that reflects how it's called in NinjaOne / API. For instance, in Pingdom, the SourceType is probes / checks not Pingdom Probes. It does not look best but we have a mechanism that lets us define custom friendly name if we wanted to. In short, I'd recommend not artificially adding NinjaOne.... Akin to HaloPSA, we have Agent, not HaloPSA Agent

Copy link
Copy Markdown
Contributor

@vinbab vinbab left a comment

Choose a reason for hiding this comment

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

@Deenk feedback on OOB dashboards:

  • I recommend setting a fixed timeframe for some of the Overview dashboard so they don't try to load too much / everything. First time users might find that slow. For instance, the Activity Log dashboard times out OOB for me. I'd recommend either setting a timeframe (7 days is often a good middle ground) or filtering to a specific Status (Open)
  • It would be useful on the Device Overview to have at tile towards the top with a drilldown link to the Device perspective, gives a sense of endless exploration out-of-the-box
  • Same with Orgnization Overview
  • Check to see if other Overview dashboards have a relevant drilldown to add too
  • TicketBoards folder -> Ticket Boards

@gdorward
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

I think this goes beyond just the OOB dashboards. I set up an Alerts tile and it warns based on the dashboard timeframe, applies None which isn't an option, so a bit confusing. It seems like no timeframes should be listed if they can't be supported
Screenshot 2026-04-14 at 13 50 47
Screenshot 2026-04-14 at 13 51 07

Copy link
Copy Markdown
Contributor

@vinbab vinbab left a comment

Choose a reason for hiding this comment

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

@Deenk data streams list

  • Devices, Location Devices and Organization Devices: those data streams look similar. If that is from one endpoint with query / URL filters, could they be merged into one data stream with Parameters to filter? Else could they be named to start with Devices (...
  • Same as above with Locations and Organization Locations
  • Software (Global) and Volume (Global) don't return anything. I see they have different API endpoints, so probably makes sense to have them separate to Software or Volume like you have done.
  • Should these data streams be named to be grouped together, e.g. Devices(...: Disks, Volumes, Network Interfaces, Processors, Operating Systems
  • Could Device Health and Health be merged? Same endpoint, different URL query filters it seems

Copy link
Copy Markdown
Contributor

@vinbab vinbab left a comment

Choose a reason for hiding this comment

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

@Deenk Activities data stream constantly times out for me. I'll pause my review here and wait for @AliceG-Sq 's test comments and @gdorward about timeframe to be addressed. Then I'll do some final checks on column data types.

@vinbab vinbab removed their assignment Apr 14, 2026
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