From bdc90b4ee31c00e39169d9c52247c60a7b4ee1fa Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 Feb 2024 20:39:40 -0500 Subject: [PATCH 01/14] Graph Explorer - Add import/export option - Add custom path to CippCodeOffcanvas --- .../utilities/CippCodeOffcanvas.jsx | 37 +++++++++++++------ src/components/utilities/SharedModal.jsx | 2 +- .../tenant/administration/GraphExplorer.jsx | 31 +++++++++++++++- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/components/utilities/CippCodeOffcanvas.jsx b/src/components/utilities/CippCodeOffcanvas.jsx index 589c27ce3cb8..32572357e565 100644 --- a/src/components/utilities/CippCodeOffcanvas.jsx +++ b/src/components/utilities/CippCodeOffcanvas.jsx @@ -6,6 +6,8 @@ import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 's import { Editor } from '@monaco-editor/react' import { useSelector } from 'react-redux' import PropTypes from 'prop-types' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import CopyToClipboard from 'react-copy-to-clipboard' function CippCodeOffCanvas({ row, @@ -14,6 +16,7 @@ function CippCodeOffCanvas({ type, title = 'Template JSON', hideButton = false, + path = `/api/ExecEditTemplate?type=${type}`, }) { const [SaveTemplate, templateDetails] = useLazyGenericPostRequestQuery() const currentTheme = useSelector((state) => state.app.currentTheme) @@ -53,18 +56,27 @@ function CippCodeOffCanvas({ {!hideButton && ( - - SaveTemplate({ - path: `/api/ExecEditTemplate?type=${type}`, - method: 'POST', - values: templateData, - }) - } - > - Save changes {templateDetails.isFetching && } - + <> + + SaveTemplate({ + path: path, + method: 'POST', + values: templateData, + }) + } + className="me-2" + > + Save changes + {templateDetails.isFetching && } + + + + Copy to Clipboard + + + )} @@ -83,6 +95,7 @@ CippCodeOffCanvas.propTypes = { type: PropTypes.string, title: PropTypes.string, hideButton: PropTypes.bool, + path: PropTypes.string, } export default CippCodeOffCanvas diff --git a/src/components/utilities/SharedModal.jsx b/src/components/utilities/SharedModal.jsx index fb8501fc93ca..9167b7a2073b 100644 --- a/src/components/utilities/SharedModal.jsx +++ b/src/components/utilities/SharedModal.jsx @@ -29,7 +29,7 @@ function mapBodyComponent({ componentType, data, componentProps }) { } const sharedProps = { - componentType: PropTypes.oneOf(['table', 'list', 'text', 'confirm']), + componentType: PropTypes.oneOf(['table', 'list', 'text', 'confirm', 'codeblock']), componentProps: PropTypes.object, body: PropTypes.oneOfType([PropTypes.node, PropTypes.element]), data: PropTypes.any, diff --git a/src/views/tenant/administration/GraphExplorer.jsx b/src/views/tenant/administration/GraphExplorer.jsx index dea2ff3b06e1..1f77b38648ac 100644 --- a/src/views/tenant/administration/GraphExplorer.jsx +++ b/src/views/tenant/administration/GraphExplorer.jsx @@ -30,7 +30,7 @@ import { import { OnChange } from 'react-final-form-listeners' import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' import PropTypes from 'prop-types' -import { ModalService } from 'src/components/utilities' +import { CippCodeOffCanvas, ModalService } from 'src/components/utilities' const GraphExplorer = () => { const tenant = useSelector((state) => state.app.currentTenant) @@ -39,6 +39,7 @@ const GraphExplorer = () => { const [alertVisible, setAlertVisible] = useState() const [random, setRandom] = useState('') const [random2, setRandom2] = useState('') + const [ocVisible, setOCVisible] = useState(false) const [searchNow, setSearchNow] = useState(false) const [visibleA, setVisibleA] = useState(true) const handleSubmit = async (values) => { @@ -316,7 +317,11 @@ const GraphExplorer = () => { - + + + + + {(props) => { @@ -326,6 +331,14 @@ const GraphExplorer = () => { return ( <>
+ + setOCVisible(true)} + className="me-2" + > + + + {!preset[0]?.isBuiltin && preset[0]?.id && preset[0]?.IsMyPreset && ( @@ -373,6 +386,7 @@ const GraphExplorer = () => { values: props.values, }) } + className="me-2" > @@ -394,6 +408,19 @@ const GraphExplorer = () => { {postResults.data?.Results} )} + { + setOCVisible(false) + setRandom2((Math.random() + 1).toString(36).substring(7)) + }} + /> ) }} From 3722ee348361b891ab5940b902e8ec364604afdf Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 Feb 2024 21:35:23 -0500 Subject: [PATCH 02/14] Add copied state --- src/components/utilities/CippCodeOffcanvas.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/utilities/CippCodeOffcanvas.jsx b/src/components/utilities/CippCodeOffcanvas.jsx index 32572357e565..f17433ff2e4a 100644 --- a/src/components/utilities/CippCodeOffcanvas.jsx +++ b/src/components/utilities/CippCodeOffcanvas.jsx @@ -22,6 +22,7 @@ function CippCodeOffCanvas({ const currentTheme = useSelector((state) => state.app.currentTheme) const [templateData, setFormData] = useState(row) const [invalidJSON, setInvalid] = useState(false) + const [copied, setCopied] = useState(false) function handleEditorChange(value, event) { try { @@ -71,9 +72,10 @@ function CippCodeOffCanvas({ Save changes {templateDetails.isFetching && } - + setCopied(true)}> - Copy to Clipboard + Copy + to Clipboard From 03cb55e4f7335f412a07fd61c7ca66cd3f470b8a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 20 Feb 2024 22:02:09 -0500 Subject: [PATCH 03/14] Update CippCodeOffcanvas.jsx --- src/components/utilities/CippCodeOffcanvas.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/utilities/CippCodeOffcanvas.jsx b/src/components/utilities/CippCodeOffcanvas.jsx index f17433ff2e4a..edd5abc34b74 100644 --- a/src/components/utilities/CippCodeOffcanvas.jsx +++ b/src/components/utilities/CippCodeOffcanvas.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import { CButton, CCallout, CCol, CRow, CSpinner } from '@coreui/react' import { CippOffcanvas } from 'src/components/utilities' import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' @@ -33,6 +33,10 @@ function CippCodeOffCanvas({ } } + useEffect(() => { + setCopied(false) + }, [setCopied, templateData]) + return ( <> Date: Wed, 21 Feb 2024 11:14:55 +0100 Subject: [PATCH 04/14] add bulk remove and add of users --- src/components/tables/CippTable.jsx | 34 +++++++++++++- src/views/identity/administration/Users.jsx | 52 +++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/components/tables/CippTable.jsx b/src/components/tables/CippTable.jsx index 99c36ae46708..74dbf52ecd53 100644 --- a/src/components/tables/CippTable.jsx +++ b/src/components/tables/CippTable.jsx @@ -389,14 +389,43 @@ export default function CippTable({ } const newModalBody = {} for (let [objName, objValue] of Object.entries(modalBody)) { - if (objValue.toString().startsWith('!')) { + if (typeof objValue === 'object' && objValue !== null) { + newModalBody[objName] = {} + for (let [nestedObjName, nestedObjValue] of Object.entries(objValue)) { + if (typeof nestedObjValue === 'string' && nestedObjValue.startsWith('!')) { + newModalBody[objName][nestedObjName] = row[nestedObjValue.replace('!', '')] + } else { + newModalBody[objName][nestedObjName] = nestedObjValue + } + } + } else if (typeof objValue === 'string' && objValue.startsWith('!')) { newModalBody[objName] = row[objValue.replace('!', '')] + } else { + newModalBody[objName] = objValue } } const NewModalUrl = `${modalUrl.split('?')[0]}?${urlParams.toString()}` + const selectedValue = inputRef.current.value + let additionalFields = {} + if (inputRef.current.nodeName === 'SELECT') { + const selectedItem = dropDownInfo.data.find( + (item) => item[modalDropdown.valueField] === selectedValue, + ) + if (selectedItem && modalDropdown.addedField) { + Object.keys(modalDropdown.addedField).forEach((key) => { + additionalFields[key] = selectedItem[modalDropdown.addedField[key]] + }) + } + } + const results = await genericPostRequest({ path: NewModalUrl, - values: { ...modalBody, ...newModalBody, ...{ input: inputRef.current.value } }, + values: { + ...modalBody, + ...newModalBody, + ...additionalFields, + ...{ input: inputRef.current.value }, + }, }) resultsarr.push(results) setMassResults(resultsarr) @@ -466,6 +495,7 @@ export default function CippTable({ } const executeselectedAction = (item) => { + console.log(item) setModalContent({ item, }) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index e6e4cbc30539..1d060f02d59d 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -551,6 +551,58 @@ const Users = (row) => { valueField: 'URL', }, }, + { + label: 'Add to group', + color: 'info', + modal: true, + modalType: 'POST', + modalBody: { + username: '!userPrincipalName', + userid: '!id', + TenantId: tenant.defaultDomainName, + Addmember: { + value: '!userPrincipalName', + }, + }, + modalUrl: `/api/EditGroup`, + modalMessage: 'Select the group to add', + modalDropdown: { + url: `/api/listGroups?TenantFilter=${tenant.defaultDomainName}`, + labelField: 'displayName', + valueField: 'id', + addedField: { + groupId: 'id', + groupType: 'calculatedGroupType', + groupName: 'displayName', + }, + }, + }, + { + label: 'Remove from group', + color: 'info', + modal: true, + modalType: 'POST', + modalBody: { + username: '!userPrincipalName', + userid: '!id', + TenantId: tenant.defaultDomainName, + RemoveMember: { + value: '!userPrincipalName', + }, + }, + modalUrl: `/api/EditGroup`, + modalMessage: 'Select the group to remove', + modalDropdown: { + url: `/api/listGroups?TenantFilter=${tenant.defaultDomainName}`, + labelField: 'displayName', + valueField: 'id', + addedField: { + groupId: 'id', + groupType: 'calculatedGroupType', + groupName: 'displayName', + }, + }, + }, { label: 'Set Out of Office', color: 'info', From 3618f88c229b57bf484ed26eafbed5d1c7d197c6 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 21 Feb 2024 11:20:16 +0100 Subject: [PATCH 05/14] text changes --- src/views/email-exchange/connectors/ConnectorList.jsx | 2 +- src/views/email-exchange/spamfilter/Spamfilter.jsx | 2 +- src/views/email-exchange/transport/TransportRules.jsx | 2 +- src/views/endpoint/autopilot/AutopilotListDevices.jsx | 2 +- src/views/identity/administration/Deleted.jsx | 2 +- src/views/teams-share/onedrive/OneDriveList.jsx | 2 +- src/views/teams-share/sharepoint/SharepointList.jsx | 2 +- src/views/tenant/administration/ListAlertsQueue.jsx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/views/email-exchange/connectors/ConnectorList.jsx b/src/views/email-exchange/connectors/ConnectorList.jsx index e4e887adbd71..990e1d555199 100644 --- a/src/views/email-exchange/connectors/ConnectorList.jsx +++ b/src/views/email-exchange/connectors/ConnectorList.jsx @@ -18,7 +18,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { { { { { { { { ({ label: key, value: From faf371e514e99360e21941e85c2c408de48c19a5 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 21 Feb 2024 11:39:34 +0100 Subject: [PATCH 06/14] add urlonly --- src/views/identity/administration/Users.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index 1d060f02d59d..f3a4644eb1ec 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -129,7 +129,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { }, modalUrl: `/api/ExecOneDriveShortCut`, modalDropdown: { - url: `/api/listSites?TenantFilter=${tenant.defaultDomainName}&type=SharePointSiteUsage`, + url: `/api/listSites?TenantFilter=${tenant.defaultDomainName}&type=SharePointSiteUsage?URLOnly=true`, labelField: 'URL', valueField: 'URL', }, From be6fdbaa68b7911ca564529b8f061b49b6645dfe Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 21 Feb 2024 11:41:02 +0100 Subject: [PATCH 07/14] add urlonly --- src/views/identity/administration/Users.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index f3a4644eb1ec..774f25a29c2d 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -129,7 +129,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { }, modalUrl: `/api/ExecOneDriveShortCut`, modalDropdown: { - url: `/api/listSites?TenantFilter=${tenant.defaultDomainName}&type=SharePointSiteUsage?URLOnly=true`, + url: `/api/listSites?TenantFilter=${tenant.defaultDomainName}&type=SharePointSiteUsage&URLOnly=true`, labelField: 'URL', valueField: 'URL', }, From 35c31a5b141c544f22d01851b89fe27b0cade1da Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 21 Feb 2024 12:30:07 +0100 Subject: [PATCH 08/14] add device list --- src/_nav.jsx | 5 + src/routes.js | 4 + src/views/identity/administration/Devices.jsx | 105 ++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 src/views/identity/administration/Devices.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index a17d7e73a344..abbc9c2e9835 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -50,6 +50,11 @@ const _nav = [ name: 'Groups', to: '/identity/administration/groups', }, + { + component: CNavItem, + name: 'Devices', + to: '/identity/administration/devices', + }, { component: CNavItem, name: 'Deploy Group Template', diff --git a/src/routes.js b/src/routes.js index 2f41ef51dff5..e5d7082719fc 100644 --- a/src/routes.js +++ b/src/routes.js @@ -30,6 +30,8 @@ const EditGroup = React.lazy(() => import('src/views/identity/administration/Edi const ViewGroup = React.lazy(() => import('src/views/identity/administration/ViewGroup')) const Roles = React.lazy(() => import('src/views/identity/administration/Roles')) const Devices = React.lazy(() => import('src/views/endpoint/intune/Devices')) +const allDevices = React.lazy(() => import('src/views/identity/administration/Devices')) + const PageLogOut = React.lazy(() => import('src/views/pages/LogoutRedirect/PageLogOut')) const Page404 = React.lazy(() => import('src/views/pages/page404/Page404')) @@ -258,6 +260,8 @@ const routes = [ { path: '/identity/administration/ViewBec', name: 'View BEC', component: ViewBEC }, { path: '/identity/administration', name: 'Administration' }, { path: '/identity/administration/users', name: 'Users', component: Users }, + { path: '/identity/administration/devices', name: 'Devices', component: allDevices }, + { path: '/identity/administration/groups/add', name: 'Add Group', component: AddGroup }, { path: '/identity/administration/group-templates', diff --git a/src/views/identity/administration/Devices.jsx b/src/views/identity/administration/Devices.jsx new file mode 100644 index 000000000000..935f5af5dcc1 --- /dev/null +++ b/src/views/identity/administration/Devices.jsx @@ -0,0 +1,105 @@ +import React, { useEffect, useState } from 'react' +import { useSelector } from 'react-redux' +import { CellTip, cellBooleanFormatter } from 'src/components/tables' +import { CippPageList } from 'src/components/layout' + +const DevicesList = () => { + const [tenantColumnSet, setTenantColumn] = useState(true) + const tenant = useSelector((state) => state.app.currentTenant) + + const columns = [ + { + name: 'Tenant', + selector: (row) => row['Tenant'], + sortable: true, + cell: (row) => CellTip(row['Tenant']), + exportSelector: 'Tenant', + omit: tenantColumnSet, + }, + { + name: 'Retrieval Status', + selector: (row) => row['CippStatus'], + sortable: true, + cell: (row) => CellTip(row['CippStatus']), + exportSelector: 'CippStatus', + omit: tenantColumnSet, + }, + { + selector: (row) => row['displayName'], + name: 'Display Name', + sortable: true, + cell: (row) => CellTip(row['displayName']), + exportSelector: 'displayName', + }, + { + selector: (row) => row['deviceOwnership'], + name: 'Device Ownership', + sortable: true, + cell: (row) => CellTip(row['deviceOwnership']), + exportSelector: 'recipientType', + }, + { + selector: (row) => row['enrollmentType'], + name: 'Enrollment Type', + sortable: true, + exportSelector: 'enrollmentType', + }, + { + selector: (row) => row['manufacturer'], + name: 'Manufacturer', + sortable: true, + exportSelector: 'manufacturer', + }, + { + selector: (row) => row['model'], + name: 'Model', + sortable: true, + exportSelector: 'model', + }, + { + selector: (row) => row['operatingSystem'], + name: 'OS', + sortable: true, + exportSelector: 'operatingSystem', + }, + { + selector: (row) => row['operatingSystemVersion'], + name: 'Version', + sortable: true, + exportSelector: 'operatingSystemVersion', + }, + { + selector: (row) => row['profileType'], + name: 'Profile Type', + sortable: true, + exportSelector: 'profileType', + }, + ] + useEffect(() => { + if (tenant.defaultDomainName === 'AllTenants') { + setTenantColumn(false) + } + if (tenant.defaultDomainName !== 'AllTenants') { + setTenantColumn(true) + } + }, [tenant.defaultDomainName, tenantColumnSet]) + return ( + + ) +} + +export default DevicesList From 06b708f86c1574780c34a67133e0a3825010346e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 21 Feb 2024 13:06:48 +0100 Subject: [PATCH 09/14] add device actions --- src/views/identity/administration/Devices.jsx | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/views/identity/administration/Devices.jsx b/src/views/identity/administration/Devices.jsx index 935f5af5dcc1..aa608f343977 100644 --- a/src/views/identity/administration/Devices.jsx +++ b/src/views/identity/administration/Devices.jsx @@ -2,11 +2,55 @@ import React, { useEffect, useState } from 'react' import { useSelector } from 'react-redux' import { CellTip, cellBooleanFormatter } from 'src/components/tables' import { CippPageList } from 'src/components/layout' +import { Link } from 'react-router-dom' +import { CButton } from '@coreui/react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faEdit, faEllipsisV } from '@fortawesome/free-solid-svg-icons' +import { CippActionsOffcanvas } from 'src/components/utilities' const DevicesList = () => { const [tenantColumnSet, setTenantColumn] = useState(true) const tenant = useSelector((state) => state.app.currentTenant) - + const Offcanvas = (row, rowIndex, formatExtraData) => { + const tenant = useSelector((state) => state.app.currentTenant) + const [ocVisible, setOCVisible] = useState(false) + const editLink = `/identity/administration/groups/edit?groupId=${row.id}&tenantDomain=${tenant.defaultDomainName}` + return ( + <> + setOCVisible(true)}> + + + setOCVisible(false)} + /> + + ) + } const columns = [ { name: 'Tenant', @@ -74,6 +118,11 @@ const DevicesList = () => { sortable: true, exportSelector: 'profileType', }, + { + name: 'Actions', + cell: Offcanvas, + maxWidth: '20px', + }, ] useEffect(() => { if (tenant.defaultDomainName === 'AllTenants') { From 375459f3a19f66dc02afe95369cb7c3f19ee9d89 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 21 Feb 2024 16:57:50 -0500 Subject: [PATCH 10/14] Cleanup graph explorer import/export --- src/components/utilities/CippCodeOffcanvas.jsx | 8 ++++++-- src/views/tenant/administration/GraphExplorer.jsx | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/utilities/CippCodeOffcanvas.jsx b/src/components/utilities/CippCodeOffcanvas.jsx index edd5abc34b74..a9b5cf41a055 100644 --- a/src/components/utilities/CippCodeOffcanvas.jsx +++ b/src/components/utilities/CippCodeOffcanvas.jsx @@ -73,8 +73,12 @@ function CippCodeOffCanvas({ } className="me-2" > - Save changes - {templateDetails.isFetching && } + {templateDetails.isFetching ? ( + + ) : ( + + )} + Save changes setCopied(true)}> diff --git a/src/views/tenant/administration/GraphExplorer.jsx b/src/views/tenant/administration/GraphExplorer.jsx index 1f77b38648ac..3664f42caed6 100644 --- a/src/views/tenant/administration/GraphExplorer.jsx +++ b/src/views/tenant/administration/GraphExplorer.jsx @@ -83,7 +83,7 @@ const GraphExplorer = () => { const handleManagePreset = ({ values, action, message }) => { var params = { action: action, - values: values, + preset: values, } ModalService.confirm({ title: 'Confirm', @@ -260,6 +260,15 @@ const GraphExplorer = () => { field: PropTypes.node, set: PropTypes.string, } + + function getPresetProps(values) { + var newvals = Object.assign({}, values) + delete newvals['reportTemplate'] + delete newvals['tenantFilter'] + delete newvals['IsShared'] + return newvals + } + console.log(graphrequest.data) return ( @@ -301,6 +310,7 @@ const GraphExplorer = () => { name="reportTemplate" label="Select a report preset" placeholder="Select a report" + retainInput={false} multi={false} values={presets.map((preset) => { return { @@ -411,8 +421,7 @@ const GraphExplorer = () => { Date: Fri, 23 Feb 2024 00:46:24 -0500 Subject: [PATCH 11/14] Function Statistics --- src/_nav.jsx | 5 ++ src/routes.js | 3 +- src/views/cipp/Statistics.jsx | 153 ++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/views/cipp/Statistics.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index abbc9c2e9835..d701c055f36d 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -742,6 +742,11 @@ const _nav = [ name: 'Logbook', to: '/cipp/logs', }, + { + component: CNavItem, + name: 'Statistics', + to: '/cipp/statistics', + }, { component: CNavItem, name: 'SAM Setup Wizard', diff --git a/src/routes.js b/src/routes.js index e5d7082719fc..4f119b52d8c8 100644 --- a/src/routes.js +++ b/src/routes.js @@ -3,6 +3,7 @@ import React from 'react' const Home = React.lazy(() => import('src/views/home/Home')) const Logs = React.lazy(() => import('src/views/cipp/Logs')) const Scheduler = React.lazy(() => import('src/views/cipp/Scheduler')) +const Statistics = React.lazy(() => import('src/views/cipp/Statistics')) const Users = React.lazy(() => import('src/views/identity/administration/Users')) const DeletedItems = React.lazy(() => import('src/views/identity/administration/Deleted')) const ViewBEC = React.lazy(() => import('src/views/identity/administration/ViewBEC')) @@ -244,7 +245,7 @@ const routes = [ { path: '/home', name: 'Home', component: Home }, { path: '/cipp/logs', name: 'Logs', component: Logs }, { path: '/cipp/scheduler', name: 'Scheduler', component: Scheduler }, - + { path: '/cipp/statistics', name: 'Statistics', component: Statistics }, { path: '/cipp/404', name: 'Error', component: Page404 }, { path: '/cipp/403', name: 'Error', component: Page403 }, { path: '/cipp/500', name: 'Error', component: Page500 }, diff --git a/src/views/cipp/Statistics.jsx b/src/views/cipp/Statistics.jsx new file mode 100644 index 000000000000..6fba968ca726 --- /dev/null +++ b/src/views/cipp/Statistics.jsx @@ -0,0 +1,153 @@ +import React, { useState } from 'react' +import { CippPage } from 'src/components/layout' +import { + CButton, + CCard, + CCardBody, + CCardHeader, + CCardTitle, + CCol, + CCollapse, + CFormInput, + CFormLabel, + CFormSelect, + CRow, + CSpinner, +} from '@coreui/react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faChevronRight, faChevronDown } from '@fortawesome/free-solid-svg-icons' +import { CippTable } from 'src/components/tables' +import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' +import { useSelector } from 'react-redux' +import { useGenericGetRequestQuery } from 'src/store/api/app' +import { RFFCFormSelect } from 'src/components/forms' + +const columns = [ + { + name: 'Name', + selector: (row) => row['Name'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'Name', + minWidth: '145px', + maxWidth: '145px', + }, + { + name: 'Executions', + selector: (row) => row['ExecutionCount'], + sortable: true, + exportSelector: 'ExecutionCount', + }, + { + name: 'Total (seconds)', + selector: (row) => row['TotalSeconds'], + sortable: true, + exportSelector: 'TotalSeconds', + }, + { + name: 'Max (seconds)', + selector: (row) => row['MaxSeconds'], + sortable: true, + exportSelector: 'MaxSeconds', + }, + { + name: 'Avg (seconds)', + selector: (row) => row['AvgSeconds'], + sortable: true, + exportSelector: 'AvgSeconds', + cell: (row) => Math.round(row['AvgSeconds'] * 100) / 100, + }, +] + +const Statistics = () => { + const [visibleA, setVisibleA] = useState(false) + const [type, setType] = useState('Functions') + const [interval, setInterval] = useState('Days') + const [time, setTime] = useState(1) + const tenant = useSelector((state) => state.app.currentTenant) + const { data, isFetching, error, isSuccess } = useGenericGetRequestQuery({ + path: '/api/ListFunctionStats', + params: { + FunctionType: 'Queue', + Interval: interval, + Time: time, + TenantFilter: tenant?.defaultDomainName, + }, + }) + + return ( + <> + + + + + + Options + setVisibleA(!visibleA)} + > + + + + + + + + + + + + Report + setType(e.target.value)}> + + + + + +
+ Interval + setInterval(e.target.value)}> + + + + +
+
+ Time + setTime(e.target.value)} + defaultValue={1} + /> +
+
+
+
+
+
+
+
+
+ + + + Statistics + + + {isFetching && } + {isSuccess && ( + + )} + + + + + ) +} + +export default Statistics From b501b21fa5834df5adc883c67c7680dc70813c43 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 23 Feb 2024 12:21:31 +0100 Subject: [PATCH 12/14] fix interface bug for all tenants overview --- .../tenant/standards/ListAppliedStandards.jsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index 1d0979924189..61c50f1a0d99 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -207,10 +207,16 @@ const ApplyNewStandard = () => { (tenant) => tenant.displayName === 'AllTenants', ) - function getLabel(item) { + function getLabel(item, type) { + if (!item || !item.name) { + return '' + } const keys = item.name.split('.') let value = keys.reduce((prev, curr) => prev && prev[curr], allTenantsStandard) - return value ? `* Enabled via All Tenants` : '' + if (!value || !value[type]) { + return '' + } + return `* Enabled via All Tenants` } const groupedStandards = allStandardsList.reduce((acc, obj) => { @@ -437,7 +443,7 @@ const ApplyNewStandard = () => { name={`${obj.name}.report`} disabled={obj.disabledFeatures?.report} helpText="Report stores the data in the database to use in custom BPA reports." - sublabel={getLabel(obj)} + sublabel={getLabel(obj, 'report')} /> @@ -446,7 +452,7 @@ const ApplyNewStandard = () => { name={`${obj.name}.alert`} disabled={obj.disabledFeatures?.warn} helpText="Alert Generates an alert in the log, if remediate is enabled the log entry will also say if the remediation was successful." - sublabel={getLabel(obj)} + sublabel={getLabel(obj, 'alert')} /> @@ -455,7 +461,7 @@ const ApplyNewStandard = () => { name={`${obj.name}.remediate`} disabled={obj.disabledFeatures?.remediate} helpText={'Remediate executes the fix for standard.'} - sublabel={getLabel(obj)} + sublabel={getLabel(obj, 'remediate')} /> From 3b64090129bff0d3f2a4e4dca637c670b23c960a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 23 Feb 2024 14:40:35 +0100 Subject: [PATCH 13/14] add exchange standard --- src/data/standards.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 5d8788197e96..01394297cd34 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -440,6 +440,16 @@ "impact": "Low Impact", "impactColour": "info" }, + { + "name": "standards.MessageExpiration", + "cat": "Exchange Standards", + "tag": ["lowimpact"], + "helpText": "Sets the transport message configuration to timeout a message at 12 hours.", + "addedComponent": [], + "label": "Lower Transport Message Expiration to 12 hours", + "impact": "Low Impact", + "impactColour": "info" + }, { "name": "standards.AutoExpandArchive", "cat": "Exchange Standards", From 129d3a778234588cc2680bd1eaa83f7b22f0c835 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 23 Feb 2024 14:57:33 +0100 Subject: [PATCH 14/14] version up --- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/version_latest.txt b/public/version_latest.txt index 3bff059174b8..7cbea073bea1 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -5.1.1 \ No newline at end of file +5.2.0 \ No newline at end of file diff --git a/version_latest.txt b/version_latest.txt index 3bff059174b8..7cbea073bea1 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.1.1 \ No newline at end of file +5.2.0 \ No newline at end of file