Skip to content

Commit

Permalink
first beta graph explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
KelvinTegelaar committed Mar 7, 2022
1 parent 7e827b0 commit dfb9b99
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 14 deletions.
40 changes: 27 additions & 13 deletions src/_nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,26 +105,40 @@ const _nav = [
},
{
component: CNavItem,
name: 'List Licences',
name: 'Alerts Wizard',
to: '/tenant/administration/alertswizard',
},

{
component: CNavItem,
name: 'List Scheduled Alerts',
to: '/tenant/administration/alertsqueue',
},
],
},
{
component: CNavGroup,
name: 'Reports',
section: 'Reports',
to: '/tenant/reports',
icon: <FontAwesomeIcon icon={faChartBar} className="nav-icon" />,
items: [
{
component: CNavItem,
name: 'Graph Explorer',
to: '/tenant/administration/graph-explorer',
},
{
component: CNavItem,
name: 'Licence Report',
to: '/tenant/administration/list-licenses',
},

{
component: CNavItem,
name: 'Conditional Access Policies',
to: '/tenant/administration/conditional-access-policies',
},
// Temp removed due to not ready for release
// {
// component: CNavItem,
// name: 'Alerts Wizard',
// to: '/tenant/administration/alertswizard',
// },
// Temp removed due to not ready for release
// {
// component: CNavItem,
// name: 'List Scheduled Alerts',
// to: '/tenant/administration/alertsqueue',
// },
],
},
{
Expand Down
2 changes: 2 additions & 0 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const MFAReport = React.lazy(() => import('src/views/identity/reports/MFAReport'
const Tenants = React.lazy(() => import('src/views/tenant/administration/Tenants'))
const AlertWizard = React.lazy(() => import('src/views/tenant/administration/AlertWizard'))
const AlertsQueue = React.lazy(() => import('src/views/tenant/administration/ListAlertsQueue'))
const GraphExplorer = React.lazy(() => import('src/views/tenant/administration/GraphExplorer'))

const Domains = React.lazy(() => import('src/views/tenant/administration/Domains'))
const EditTenant = React.lazy(() => import('src/views/tenant/administration/EditTenant'))
Expand Down Expand Up @@ -166,6 +167,7 @@ const routes = [
{ path: '/tenant/administration/domains', name: 'Domains', component: Domains },
{ path: '/tenant/administration/alertswizard', name: 'Alerts Wizard', component: AlertWizard },
{ path: '/tenant/administration/alertsqueue', name: 'Alerts Queue', component: AlertsQueue },
{ path: '/tenant/administration/graph-explorer', name: 'Graph Explorer', component: GraphExplorer },

{
path: '/tenant/administration/conditional-access-policies',
Expand Down
1 change: 0 additions & 1 deletion src/views/email-exchange/reports/MessageTrace.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ const MessageTrace = () => {
<CForm onSubmit={handleSubmit}>
<CRow>
<CCol>
Select a tenant
<TenantSelector />
</CCol>
</CRow>
Expand Down
195 changes: 195 additions & 0 deletions src/views/tenant/administration/GraphExplorer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import React, { useEffect, useState } from 'react'
import {
CButton,
CCard,
CCardBody,
CCardHeader,
CCardTitle,
CCol,
CCollapse,
CForm,
CRow,
} from '@coreui/react'
import useQuery from 'src/hooks/useQuery'
import { Form } from 'react-final-form'
import { RFFCFormInput, RFFCFormSelect } from 'src/components/forms'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faChevronRight, faChevronDown, faSearch } from '@fortawesome/free-solid-svg-icons'
import { CippTable } from 'src/components/tables'
import { TenantSelector } from 'src/components/utilities'
import { useSelector } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import { CippPage } from 'src/components/layout/CippPage'
import { useLazyGenericGetRequestQuery } from 'src/store/api/app'

const GraphExplorer = () => {
let navigate = useNavigate()
const tenant = useSelector((state) => state.app.currentTenant)
let query = useQuery()
const endpoint = query.get('endpoint')
const SearchNow = query.get('SearchNow')
const [visibleA, setVisibleA] = useState(true)
const handleSubmit = async (values) => {
setVisibleA(false)
Object.keys(values).filter(function (x) {
if (values[x] === null) {
delete values[x]
}
return null
})
const shippedValues = {
tenantFilter: tenant.defaultDomainName,
SearchNow: true,
...values,
}
var queryString = Object.keys(shippedValues)
.map((key) => key + '=' + shippedValues[key])
.join('&')

navigate(`?${queryString}`)
}
const [execGraphRequest, graphrequest] = useLazyGenericGetRequestQuery()
const QueryColumns = { set: false, data: [] }
const flattenObject = (obj) => {
const flattened = {}

Object.keys(obj).forEach((key) => {
const value = obj[key]

if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
Object.assign(flattened, flattenObject(value))
console.log('flattend')
} else {
flattened[key] = value
console.log('no need to flatten')
}
})

return flattened
}

if (graphrequest.isSuccess) {
//set data
const finalData = graphrequest.data.forEach((obj) => {
flattenObject(obj)
})

console.log(finalData)
//set columns
const flatObj = Object.keys(graphrequest.data[0]).flat(100)
flatObj.map((value) =>
QueryColumns.data.push({
name: value,
selector: (row) => row[`${value.toString()}`],
sortable: true,
exportSelector: value,
}),
)
QueryColumns.set = true
}

useEffect(() => {
execGraphRequest({
path: 'api/execGraphRequest',
params: { tenantFilter: tenant.defaultDomainName, endpoint: endpoint },
})
}, [endpoint, execGraphRequest, tenant.defaultDomainName])
return (
<>
<CRow>
<CCol>
<CCard className="options-card">
<CCardHeader>
<CCardTitle className="d-flex justify-content-between">
Message Trace Settings
<CButton size="sm" variant="ghost" onClick={() => setVisibleA(!visibleA)}>
<FontAwesomeIcon icon={visibleA ? faChevronDown : faChevronRight} />
</CButton>
</CCardTitle>
</CCardHeader>
<CCollapse visible={visibleA}>
<CCardBody>
<Form
initialValues={{
tenantFilter: tenant.defaultDomainName,
}}
onSubmit={handleSubmit}
render={({ handleSubmit, submitting, values }) => {
return (
<CForm onSubmit={handleSubmit}>
<CRow>
<CCol>
<TenantSelector showAllTenantSelector />
</CCol>
</CRow>
<hr className="my-4" />
<CRow>
<CCol>
<RFFCFormSelect
/*Clicking here populates the endpoint so users can edit their own desired fields too*/
name="reportTemplate"
label="Select a report"
placeholder="Select a report"
values={[
{ label: '2', value: '2' },
{ label: '3', value: '3' },
{ label: '4', value: '4' },
{ label: '5', value: '5' },
{ label: '6', value: '6' },
{ label: '7', value: '7' },
{ label: '8', value: '8' },
{ label: '9', value: '9' },
{ label: '10', value: '10' },
]}
/>
</CCol>
</CRow>
<CRow>
<CCol>
<RFFCFormInput
type="text"
name="endpoint"
label="Or enter an endpoint"
placeholder="Enter the Graph Endpoint you'd like to run the custom report for."
/>
</CCol>
</CRow>
<CRow className="mb-3">
<CCol>
<CButton type="submit" disabled={submitting}>
<FontAwesomeIcon className="me-2" icon={faSearch} />
Query
</CButton>
</CCol>
</CRow>
{/*<CRow>*/}
{/* <CCol>*/}
{/* <pre>{JSON.stringify(values, null, 2)}</pre>*/}
{/* </CCol>*/}
{/*</CRow>*/}
</CForm>
)
}}
/>
</CCardBody>
</CCollapse>
</CCard>
</CCol>
</CRow>
<hr />
<CippPage title="Report Results" tenantSelector={false}>
{!SearchNow && <span>Execute a search to get started.</span>}
{graphrequest.isSuccess && QueryColumns.set && (
<CippTable
reportName="GraphExplorer"
columns={QueryColumns.data}
data={graphrequest.data}
isFetching={graphrequest.isFetching}
/>
)}
</CippPage>
</>
)
}

export default GraphExplorer

0 comments on commit dfb9b99

Please sign in to comment.