Skip to content

Commit b4ea8a7

Browse files
Merge pull request #1905 from lwhitelock/NinjaOnev2
NinjaOne Integration
2 parents 3eec3b1 + 66a378a commit b4ea8a7

File tree

4 files changed

+238
-0
lines changed

4 files changed

+238
-0
lines changed

src/assets/images/ninjaone.png

13.3 KB
Loading

src/components/layout/AppFooter.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import huntressLogo from 'src/assets/images/huntress_teal.png'
55
import dattoLogo from 'src/assets/images/datto.png'
66
import rewstLogo from 'src/assets/images/rewst.png'
77
import netfriends from 'src/assets/images/netfriends.png'
8+
import ninjaLogo from 'src/assets/images/ninjaone.png'
89
//todo: Add darkmode detection and change logos accordingly.
910
const AppFooter = () => {
1011
return (
@@ -24,6 +25,9 @@ const AppFooter = () => {
2425
<CLink href="https://netfriends.com">
2526
<CImage src={netfriends} alt="Netfriends" />
2627
</CLink>
28+
<CLink href="https://ninjaone.com">
29+
<CImage src={ninjaLogo} alt="NinjaOne" />
30+
</CLink>
2731
</p>
2832
</div>
2933
<nav className="footer-nav">

src/data/Extensions.json

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,5 +106,55 @@
106106
"label": "Enable Integration"
107107
}
108108
]
109+
},
110+
{
111+
"name": "NinjaOne Integration",
112+
"type": "NinjaOne",
113+
"cat": "Documentation & Monitoring",
114+
"forceSyncButton": true,
115+
"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.",
116+
"SettingOptions": [
117+
{
118+
"type": "input",
119+
"fieldtype": "input",
120+
"name": "NinjaOne.Instance",
121+
"label": "Please enter your NinjaOne Instance",
122+
"placeholder": "app.ninjarmm.com, eu.ninjarmm.com, oc.ninjarmm.com, ca.ninjarmm.com, us2.ninjarmm.com"
123+
},
124+
{
125+
"type": "input",
126+
"fieldtype": "password",
127+
"name": "NinjaOne.ClientID",
128+
"label": "NinjaOne API Client ID",
129+
"placeholder": "Enter your NinjaOne API Client ID"
130+
},
131+
{
132+
"type": "input",
133+
"fieldtype": "password",
134+
"name": "NinjaOne.APIKey",
135+
"label": "NinjaOne API Client Secret",
136+
"placeholder": "Enter your NinjaOne API Client Secret"
137+
},
138+
{
139+
"type": "checkbox",
140+
"name": "NinjaOne.UserDocumentsEnabled",
141+
"label": "Synchronize Detailed User Information (Requires NinjaOne Documentation)"
142+
},
143+
{
144+
"type": "checkbox",
145+
"name": "NinjaOne.LicenseDocumentsEnabled",
146+
"label": "Synchronize Detailed License Information (Requires NinjaOne Documentation)"
147+
},
148+
{
149+
"type": "checkbox",
150+
"name": "NinjaOne.LicensedOnly",
151+
"label": "Only Synchronize Licensed Users"
152+
},
153+
{
154+
"type": "checkbox",
155+
"name": "NinjaOne.Enabled",
156+
"label": "Enable Integration"
157+
}
158+
]
109159
}
110160
]

src/views/cipp/CIPPSettings.jsx

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,18 +1766,54 @@ const ExtensionsTab = () => {
17661766

17671767
const MappingsTab = () => {
17681768
const [listHaloBackend, listBackendHaloResult = []] = useLazyGenericGetRequestQuery()
1769+
const [listNinjaOrgsBackend, listBackendNinjaOrgsResult] = useLazyGenericGetRequestQuery()
1770+
const [listNinjaFieldsBackend, listBackendNinjaFieldsResult] = useLazyGenericGetRequestQuery()
17691771
const [setHaloExtensionconfig, extensionHaloConfigResult = []] = useLazyGenericPostRequestQuery()
1772+
const [setNinjaOrgsExtensionconfig, extensionNinjaOrgsConfigResult] =
1773+
useLazyGenericPostRequestQuery()
1774+
const [setNinjaOrgsExtensionAutomap, extensionNinjaOrgsAutomapResult] =
1775+
useLazyGenericPostRequestQuery()
1776+
const [setNinjaFieldsExtensionconfig, extensionNinjaFieldsConfigResult] =
1777+
useLazyGenericPostRequestQuery()
17701778

17711779
const onHaloSubmit = (values) => {
17721780
setHaloExtensionconfig({
17731781
path: 'api/ExecExtensionMapping?AddMapping=Halo',
17741782
values: { mappings: values },
17751783
})
17761784
}
1785+
const onNinjaOrgsSubmit = (values) => {
1786+
setNinjaOrgsExtensionconfig({
1787+
path: 'api/ExecExtensionMapping?AddMapping=NinjaOrgs',
1788+
values: { mappings: values },
1789+
})
1790+
}
1791+
1792+
const onNinjaOrgsAutomap = async (values) => {
1793+
await setNinjaOrgsExtensionAutomap({
1794+
path: 'api/ExecExtensionMapping?AutoMapping=NinjaOrgs',
1795+
values: { mappings: values },
1796+
})
1797+
await listNinjaOrgsBackend({
1798+
path: 'api/ExecExtensionMapping?List=NinjaOrgs',
1799+
})
1800+
}
1801+
1802+
const onNinjaFieldsSubmit = (values) => {
1803+
setNinjaFieldsExtensionconfig({
1804+
path: 'api/ExecExtensionMapping?AddMapping=NinjaFields',
1805+
1806+
values: { mappings: values },
1807+
})
1808+
}
17771809
return (
17781810
<div>
17791811
{listBackendHaloResult.isUninitialized &&
17801812
listHaloBackend({ path: 'api/ExecExtensionMapping?List=Halo' })}
1813+
{listBackendNinjaOrgsResult.isUninitialized &&
1814+
listNinjaOrgsBackend({ path: 'api/ExecExtensionMapping?List=NinjaOrgs' })}
1815+
{listBackendNinjaFieldsResult.isUninitialized &&
1816+
listNinjaFieldsBackend({ path: 'api/ExecExtensionMapping?List=NinjaFields' })}
17811817
<>
17821818
<CCard className="mb-3">
17831819
<CCardHeader>
@@ -1831,6 +1867,154 @@ const MappingsTab = () => {
18311867
)}
18321868
</CCardBody>
18331869
</CCard>
1870+
<CCard className="mb-3">
1871+
<CCardHeader>
1872+
<CCardTitle>NinjaOne Field Mapping Table</CCardTitle>
1873+
</CCardHeader>
1874+
<CCardBody>
1875+
{listBackendNinjaFieldsResult.isFetching ? (
1876+
<CSpinner color="primary" />
1877+
) : (
1878+
<Form
1879+
onSubmit={onNinjaFieldsSubmit}
1880+
initialValues={listBackendNinjaFieldsResult.data?.Mappings}
1881+
render={({ handleSubmit, submitting, values }) => {
1882+
return (
1883+
<CForm onSubmit={handleSubmit}>
1884+
<CCardText>
1885+
<h5>Organization Global Custom Field Mapping</h5>
1886+
<p>
1887+
Use the table below to map your Organization Field to the correct NinjaOne
1888+
Field
1889+
</p>
1890+
{listBackendNinjaFieldsResult.isSuccess &&
1891+
listBackendNinjaFieldsResult.data.CIPPOrgFields.map((CIPPOrgFields) => (
1892+
<RFFSelectSearch
1893+
key={CIPPOrgFields.InternalName}
1894+
name={CIPPOrgFields.InternalName}
1895+
label={CIPPOrgFields.Type + ' - ' + CIPPOrgFields.Description}
1896+
values={listBackendNinjaFieldsResult.data.NinjaOrgFields.filter(
1897+
(item) => item.type === CIPPOrgFields.Type || item.type === 'unset',
1898+
)}
1899+
placeholder="Select a Field"
1900+
/>
1901+
))}
1902+
</CCardText>
1903+
<CCardText>
1904+
<h5>Device Custom Field Mapping</h5>
1905+
<p>
1906+
Use the table below to map your Device field to the correct NinjaOne
1907+
WYSIWYG Field
1908+
</p>
1909+
{listBackendNinjaFieldsResult.isSuccess &&
1910+
listBackendNinjaFieldsResult.data.CIPPNodeFields.map((CIPPNodeFields) => (
1911+
<RFFSelectSearch
1912+
key={CIPPNodeFields.InternalName}
1913+
name={CIPPNodeFields.InternalName}
1914+
label={CIPPNodeFields.Type + ' - ' + CIPPNodeFields.Description}
1915+
values={listBackendNinjaFieldsResult.data.NinjaNodeFields.filter(
1916+
(item) =>
1917+
item.type === CIPPNodeFields.Type || item.type === 'unset',
1918+
)}
1919+
placeholder="Select a Field"
1920+
/>
1921+
))}
1922+
</CCardText>
1923+
<CCol className="me-2">
1924+
<CButton className="me-2" type="submit">
1925+
{extensionNinjaFieldsConfigResult.isFetching && (
1926+
<FontAwesomeIcon icon={faCircleNotch} spin className="me-2" size="1x" />
1927+
)}
1928+
Set Mappings
1929+
</CButton>
1930+
{(extensionNinjaFieldsConfigResult.isSuccess ||
1931+
extensionNinjaFieldsConfigResult.isError) && (
1932+
<CCallout
1933+
color={
1934+
extensionNinjaFieldsConfigResult.isSuccess ? 'success' : 'danger'
1935+
}
1936+
>
1937+
{extensionNinjaFieldsConfigResult.isSuccess
1938+
? extensionNinjaFieldsConfigResult.data.Results
1939+
: 'Error'}
1940+
</CCallout>
1941+
)}
1942+
</CCol>
1943+
</CForm>
1944+
)
1945+
}}
1946+
/>
1947+
)}
1948+
</CCardBody>
1949+
</CCard>
1950+
<CCard className="mb-3">
1951+
<CCardHeader>
1952+
<CCardTitle>NinjaOne Organization Mapping Table</CCardTitle>
1953+
</CCardHeader>
1954+
<CCardBody>
1955+
{listBackendNinjaOrgsResult.isFetching ? (
1956+
<CSpinner color="primary" />
1957+
) : (
1958+
<Form
1959+
onSubmit={onNinjaOrgsSubmit}
1960+
initialValues={listBackendNinjaOrgsResult.data?.Mappings}
1961+
render={({ handleSubmit, submitting, values }) => {
1962+
return (
1963+
<CForm onSubmit={handleSubmit}>
1964+
<CCardText>
1965+
Use the table below to map your client to the correct NinjaOne Organization
1966+
{listBackendNinjaOrgsResult.isSuccess &&
1967+
listBackendNinjaOrgsResult.data.Tenants.map((tenant) => (
1968+
<RFFSelectSearch
1969+
key={tenant.customerId}
1970+
name={tenant.customerId}
1971+
label={tenant.displayName}
1972+
values={listBackendNinjaOrgsResult.data.NinjaOrgs}
1973+
placeholder="Select an Organization"
1974+
/>
1975+
))}
1976+
</CCardText>
1977+
<CCol className="me-2">
1978+
<CButton className="me-2" type="submit">
1979+
{extensionNinjaOrgsConfigResult.isFetching && (
1980+
<FontAwesomeIcon icon={faCircleNotch} spin className="me-2" size="1x" />
1981+
)}
1982+
Set Mappings
1983+
</CButton>
1984+
<CButton onClick={() => onNinjaOrgsAutomap()} className="me-2">
1985+
{extensionNinjaOrgsAutomapResult.isFetching && (
1986+
<FontAwesomeIcon icon={faCircleNotch} spin className="me-2" size="1x" />
1987+
)}
1988+
Automap NinjaOne Organizations
1989+
</CButton>
1990+
{(extensionNinjaOrgsConfigResult.isSuccess ||
1991+
extensionNinjaOrgsConfigResult.isError) && (
1992+
<CCallout
1993+
color={extensionNinjaOrgsConfigResult.isSuccess ? 'success' : 'danger'}
1994+
>
1995+
{extensionNinjaOrgsConfigResult.isSuccess
1996+
? extensionNinjaOrgsConfigResult.data.Results
1997+
: 'Error'}
1998+
</CCallout>
1999+
)}
2000+
{(extensionNinjaOrgsAutomapResult.isSuccess ||
2001+
extensionNinjaOrgsAutomapResult.isError) && (
2002+
<CCallout
2003+
color={extensionNinjaOrgsAutomapResult.isSuccess ? 'success' : 'danger'}
2004+
>
2005+
{extensionNinjaOrgsAutomapResult.isSuccess
2006+
? extensionNinjaOrgsAutomapResult.data.Results
2007+
: 'Error'}
2008+
</CCallout>
2009+
)}
2010+
</CCol>
2011+
</CForm>
2012+
)
2013+
}}
2014+
/>
2015+
)}
2016+
</CCardBody>
2017+
</CCard>
18342018
</>
18352019
</div>
18362020
)

0 commit comments

Comments
 (0)