Skip to content

Commit

Permalink
Merge pull request KelvinTegelaar#1905 from lwhitelock/NinjaOnev2
Browse files Browse the repository at this point in the history
NinjaOne Integration
  • Loading branch information
KelvinTegelaar authored Nov 24, 2023
2 parents 3eec3b1 + 66a378a commit b4ea8a7
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 0 deletions.
Binary file added src/assets/images/ninjaone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/layout/AppFooter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import huntressLogo from 'src/assets/images/huntress_teal.png'
import dattoLogo from 'src/assets/images/datto.png'
import rewstLogo from 'src/assets/images/rewst.png'
import netfriends from 'src/assets/images/netfriends.png'
import ninjaLogo from 'src/assets/images/ninjaone.png'
//todo: Add darkmode detection and change logos accordingly.
const AppFooter = () => {
return (
Expand All @@ -24,6 +25,9 @@ const AppFooter = () => {
<CLink href="https://netfriends.com">
<CImage src={netfriends} alt="Netfriends" />
</CLink>
<CLink href="https://ninjaone.com">
<CImage src={ninjaLogo} alt="NinjaOne" />
</CLink>
</p>
</div>
<nav className="footer-nav">
Expand Down
50 changes: 50 additions & 0 deletions src/data/Extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,55 @@
"label": "Enable Integration"
}
]
},
{
"name": "NinjaOne Integration",
"type": "NinjaOne",
"cat": "Documentation & Monitoring",
"forceSyncButton": true,
"helpText": "NOTE: This integration requires version 5.6 of NinjaOne, which rolls out regionally between the end of November and mid-December. This integration allows you to populate custom fields with Tenant information, monitor device compliance state, document other items and generate relationships inside NinjaOne.",
"SettingOptions": [
{
"type": "input",
"fieldtype": "input",
"name": "NinjaOne.Instance",
"label": "Please enter your NinjaOne Instance",
"placeholder": "app.ninjarmm.com, eu.ninjarmm.com, oc.ninjarmm.com, ca.ninjarmm.com, us2.ninjarmm.com"
},
{
"type": "input",
"fieldtype": "password",
"name": "NinjaOne.ClientID",
"label": "NinjaOne API Client ID",
"placeholder": "Enter your NinjaOne API Client ID"
},
{
"type": "input",
"fieldtype": "password",
"name": "NinjaOne.APIKey",
"label": "NinjaOne API Client Secret",
"placeholder": "Enter your NinjaOne API Client Secret"
},
{
"type": "checkbox",
"name": "NinjaOne.UserDocumentsEnabled",
"label": "Synchronize Detailed User Information (Requires NinjaOne Documentation)"
},
{
"type": "checkbox",
"name": "NinjaOne.LicenseDocumentsEnabled",
"label": "Synchronize Detailed License Information (Requires NinjaOne Documentation)"
},
{
"type": "checkbox",
"name": "NinjaOne.LicensedOnly",
"label": "Only Synchronize Licensed Users"
},
{
"type": "checkbox",
"name": "NinjaOne.Enabled",
"label": "Enable Integration"
}
]
}
]
184 changes: 184 additions & 0 deletions src/views/cipp/CIPPSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1766,18 +1766,54 @@ const ExtensionsTab = () => {

const MappingsTab = () => {
const [listHaloBackend, listBackendHaloResult = []] = useLazyGenericGetRequestQuery()
const [listNinjaOrgsBackend, listBackendNinjaOrgsResult] = useLazyGenericGetRequestQuery()
const [listNinjaFieldsBackend, listBackendNinjaFieldsResult] = useLazyGenericGetRequestQuery()
const [setHaloExtensionconfig, extensionHaloConfigResult = []] = useLazyGenericPostRequestQuery()
const [setNinjaOrgsExtensionconfig, extensionNinjaOrgsConfigResult] =
useLazyGenericPostRequestQuery()
const [setNinjaOrgsExtensionAutomap, extensionNinjaOrgsAutomapResult] =
useLazyGenericPostRequestQuery()
const [setNinjaFieldsExtensionconfig, extensionNinjaFieldsConfigResult] =
useLazyGenericPostRequestQuery()

const onHaloSubmit = (values) => {
setHaloExtensionconfig({
path: 'api/ExecExtensionMapping?AddMapping=Halo',
values: { mappings: values },
})
}
const onNinjaOrgsSubmit = (values) => {
setNinjaOrgsExtensionconfig({
path: 'api/ExecExtensionMapping?AddMapping=NinjaOrgs',
values: { mappings: values },
})
}

const onNinjaOrgsAutomap = async (values) => {
await setNinjaOrgsExtensionAutomap({
path: 'api/ExecExtensionMapping?AutoMapping=NinjaOrgs',
values: { mappings: values },
})
await listNinjaOrgsBackend({
path: 'api/ExecExtensionMapping?List=NinjaOrgs',
})
}

const onNinjaFieldsSubmit = (values) => {
setNinjaFieldsExtensionconfig({
path: 'api/ExecExtensionMapping?AddMapping=NinjaFields',

values: { mappings: values },
})
}
return (
<div>
{listBackendHaloResult.isUninitialized &&
listHaloBackend({ path: 'api/ExecExtensionMapping?List=Halo' })}
{listBackendNinjaOrgsResult.isUninitialized &&
listNinjaOrgsBackend({ path: 'api/ExecExtensionMapping?List=NinjaOrgs' })}
{listBackendNinjaFieldsResult.isUninitialized &&
listNinjaFieldsBackend({ path: 'api/ExecExtensionMapping?List=NinjaFields' })}
<>
<CCard className="mb-3">
<CCardHeader>
Expand Down Expand Up @@ -1831,6 +1867,154 @@ const MappingsTab = () => {
)}
</CCardBody>
</CCard>
<CCard className="mb-3">
<CCardHeader>
<CCardTitle>NinjaOne Field Mapping Table</CCardTitle>
</CCardHeader>
<CCardBody>
{listBackendNinjaFieldsResult.isFetching ? (
<CSpinner color="primary" />
) : (
<Form
onSubmit={onNinjaFieldsSubmit}
initialValues={listBackendNinjaFieldsResult.data?.Mappings}
render={({ handleSubmit, submitting, values }) => {
return (
<CForm onSubmit={handleSubmit}>
<CCardText>
<h5>Organization Global Custom Field Mapping</h5>
<p>
Use the table below to map your Organization Field to the correct NinjaOne
Field
</p>
{listBackendNinjaFieldsResult.isSuccess &&
listBackendNinjaFieldsResult.data.CIPPOrgFields.map((CIPPOrgFields) => (
<RFFSelectSearch
key={CIPPOrgFields.InternalName}
name={CIPPOrgFields.InternalName}
label={CIPPOrgFields.Type + ' - ' + CIPPOrgFields.Description}
values={listBackendNinjaFieldsResult.data.NinjaOrgFields.filter(
(item) => item.type === CIPPOrgFields.Type || item.type === 'unset',
)}
placeholder="Select a Field"
/>
))}
</CCardText>
<CCardText>
<h5>Device Custom Field Mapping</h5>
<p>
Use the table below to map your Device field to the correct NinjaOne
WYSIWYG Field
</p>
{listBackendNinjaFieldsResult.isSuccess &&
listBackendNinjaFieldsResult.data.CIPPNodeFields.map((CIPPNodeFields) => (
<RFFSelectSearch
key={CIPPNodeFields.InternalName}
name={CIPPNodeFields.InternalName}
label={CIPPNodeFields.Type + ' - ' + CIPPNodeFields.Description}
values={listBackendNinjaFieldsResult.data.NinjaNodeFields.filter(
(item) =>
item.type === CIPPNodeFields.Type || item.type === 'unset',
)}
placeholder="Select a Field"
/>
))}
</CCardText>
<CCol className="me-2">
<CButton className="me-2" type="submit">
{extensionNinjaFieldsConfigResult.isFetching && (
<FontAwesomeIcon icon={faCircleNotch} spin className="me-2" size="1x" />
)}
Set Mappings
</CButton>
{(extensionNinjaFieldsConfigResult.isSuccess ||
extensionNinjaFieldsConfigResult.isError) && (
<CCallout
color={
extensionNinjaFieldsConfigResult.isSuccess ? 'success' : 'danger'
}
>
{extensionNinjaFieldsConfigResult.isSuccess
? extensionNinjaFieldsConfigResult.data.Results
: 'Error'}
</CCallout>
)}
</CCol>
</CForm>
)
}}
/>
)}
</CCardBody>
</CCard>
<CCard className="mb-3">
<CCardHeader>
<CCardTitle>NinjaOne Organization Mapping Table</CCardTitle>
</CCardHeader>
<CCardBody>
{listBackendNinjaOrgsResult.isFetching ? (
<CSpinner color="primary" />
) : (
<Form
onSubmit={onNinjaOrgsSubmit}
initialValues={listBackendNinjaOrgsResult.data?.Mappings}
render={({ handleSubmit, submitting, values }) => {
return (
<CForm onSubmit={handleSubmit}>
<CCardText>
Use the table below to map your client to the correct NinjaOne Organization
{listBackendNinjaOrgsResult.isSuccess &&
listBackendNinjaOrgsResult.data.Tenants.map((tenant) => (
<RFFSelectSearch
key={tenant.customerId}
name={tenant.customerId}
label={tenant.displayName}
values={listBackendNinjaOrgsResult.data.NinjaOrgs}
placeholder="Select an Organization"
/>
))}
</CCardText>
<CCol className="me-2">
<CButton className="me-2" type="submit">
{extensionNinjaOrgsConfigResult.isFetching && (
<FontAwesomeIcon icon={faCircleNotch} spin className="me-2" size="1x" />
)}
Set Mappings
</CButton>
<CButton onClick={() => onNinjaOrgsAutomap()} className="me-2">
{extensionNinjaOrgsAutomapResult.isFetching && (
<FontAwesomeIcon icon={faCircleNotch} spin className="me-2" size="1x" />
)}
Automap NinjaOne Organizations
</CButton>
{(extensionNinjaOrgsConfigResult.isSuccess ||
extensionNinjaOrgsConfigResult.isError) && (
<CCallout
color={extensionNinjaOrgsConfigResult.isSuccess ? 'success' : 'danger'}
>
{extensionNinjaOrgsConfigResult.isSuccess
? extensionNinjaOrgsConfigResult.data.Results
: 'Error'}
</CCallout>
)}
{(extensionNinjaOrgsAutomapResult.isSuccess ||
extensionNinjaOrgsAutomapResult.isError) && (
<CCallout
color={extensionNinjaOrgsAutomapResult.isSuccess ? 'success' : 'danger'}
>
{extensionNinjaOrgsAutomapResult.isSuccess
? extensionNinjaOrgsAutomapResult.data.Results
: 'Error'}
</CCallout>
)}
</CCol>
</CForm>
)
}}
/>
)}
</CCardBody>
</CCard>
</>
</div>
)
Expand Down

0 comments on commit b4ea8a7

Please sign in to comment.