From f8730143678f7fcbb4209662f1f448e74d04f137 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 9 May 2024 14:39:09 -0400 Subject: [PATCH 001/115] Update DeployJITAdmin.jsx --- .../administration/DeployJITAdmin.jsx | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index dfbdf4090964..49dc5238b3bb 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -2,7 +2,14 @@ import React, { useState } from 'react' import { CButton, CCallout, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react' import { useSelector } from 'react-redux' import { Field, Form, FormSpy } from 'react-final-form' -import { Condition, RFFCFormRadio, RFFCFormSwitch, RFFSelectSearch } from 'src/components/forms' +import { + Condition, + RFFCFormInput, + RFFCFormRadio, + RFFCFormRadioList, + RFFCFormSwitch, + RFFSelectSearch, +} from 'src/components/forms' import { useGenericGetRequestQuery, useLazyGenericGetRequestQuery, @@ -82,35 +89,40 @@ const DeployJITAdmin = () => { - - - - - - ({ - value: user.id, - name: `${user.displayName} <${user.userPrincipalName}>`, - }))} - placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} - name="UserId" - isLoading={usersIsFetching} - /> - - + + + + + + + + + + + ({ + value: user.id, + name: `${user.displayName} <${user.userPrincipalName}>`, + }))} + placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} + name="UserId" + isLoading={usersIsFetching} + /> + + + Date: Thu, 9 May 2024 15:10:45 -0400 Subject: [PATCH 002/115] Update DeployJITAdmin.jsx --- .../identity/administration/DeployJITAdmin.jsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index 49dc5238b3bb..126150f95360 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -80,7 +80,7 @@ const DeployJITAdmin = () => {

- + {(props) => } @@ -92,11 +92,12 @@ const DeployJITAdmin = () => {
@@ -141,7 +142,7 @@ const DeployJITAdmin = () => { { { /> - + Add JIT Admin From eef83c80d49f51607badbbcb1941d0f40ab8b61f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 17 May 2024 13:23:19 -0400 Subject: [PATCH 003/115] Prevent mapping with API errors --- src/views/cipp/app-settings/SettingsExtensionMappings.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/cipp/app-settings/SettingsExtensionMappings.jsx b/src/views/cipp/app-settings/SettingsExtensionMappings.jsx index de3246422499..33d7491795bf 100644 --- a/src/views/cipp/app-settings/SettingsExtensionMappings.jsx +++ b/src/views/cipp/app-settings/SettingsExtensionMappings.jsx @@ -337,6 +337,7 @@ export function SettingsExtensionMappings() { onClick={() => { if ( mappingValue.value !== undefined && + mappingValue.value !== '-1' && Object.values(haloMappingsArray) .map((item) => item.haloId) .includes(mappingValue.value) === false @@ -481,6 +482,7 @@ export function SettingsExtensionMappings() { //set the new mapping in the array if ( mappingValue.value !== undefined && + mappingValue.value !== '-1' && Object.values(ninjaMappingsArray) .map((item) => item.ninjaId) .includes(mappingValue.value) === false From b217bcf973fa58826ac0ff40d1d0ca06c24af6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 17 May 2024 21:58:54 +0200 Subject: [PATCH 004/115] Update Activity Based Timeout standard to have options --- src/data/standards.json | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 92252d5a36ad..c9326b8b5f1f 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -102,9 +102,9 @@ "label": "Show header" }, { - "type":"boolean", - "name":"standards.Branding.isFooterShown", - "label":"Show footer" + "type": "boolean", + "name": "standards.Branding.isFooterShown", + "label": "Show footer" } ], "label": "Set branding for the tenant", @@ -156,8 +156,36 @@ "cat": "Global Standards", "tag": ["mediumimpact", "CIS", "spo_idle_session_timeout"], "helpText": "Enables and sets Idle session timeout for Microsoft 365 to 1 hour. This policy affects most M365 web apps", - "addedComponent": [], - "label": "Enable 1 hour Activity based Timeout", + "addedComponent": [ + { + "type": "Select", + "label": "Select value", + "name": "standards.ActivityBasedTimeout.timeout", + "values": [ + { + "label": "1 Hour", + "value": "01:00:00" + }, + { + "label": "3 Hours", + "value": "03:00:00" + }, + { + "label": "6 Hours", + "value": "06:00:00" + }, + { + "label": "12 Hours", + "value": "12:00:00" + }, + { + "label": "24 Hours", + "value": "1.00:00:00" + } + ] + } + ], + "label": "Enable Activity based Timeout", "impact": "Medium Impact", "impactColour": "warning" }, From 895ad36906dfc2e1ce615ad9a1a0b4432558005b Mon Sep 17 00:00:00 2001 From: Esco Date: Wed, 22 May 2024 13:22:10 +0200 Subject: [PATCH 005/115] Roles View Update --- src/views/identity/administration/Roles.jsx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/views/identity/administration/Roles.jsx b/src/views/identity/administration/Roles.jsx index 79383c4f007d..600d5f31cd49 100644 --- a/src/views/identity/administration/Roles.jsx +++ b/src/views/identity/administration/Roles.jsx @@ -23,7 +23,7 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { >
Role Group Name:
{row.DisplayName}



-
Member Names:
{row.Members ?

{row.Members}

:

Role has no members.

} +
Member Names:
{row.Members ? row.Members.split(',').map((member, index) =>

{member}

) :

Role has no members.

} ) @@ -53,6 +53,25 @@ const columns = [ exportSelector: 'Members', omit: true, }, + { + selector: (row) => row['Members'], + name: 'Assignments', + sortable: false, + cell: (row) => { + if (row.Members === 'none') { + return null; + } + const memberCount = row.Members ? row.Members.split(',').length : 0; + const memberText = row.Members && row.Members !== 'none' ? `Member${memberCount === 1 ? '' : 's'}` : null; + return ( + <> + {memberCount} {memberText} + + ); + }, + exportSelector: 'Members', + maxWidth: '150px', + }, { selector: (row) => 'View Members', name: 'Members', From 7a366873447d2f7c329e78b1f4908b42e5221209 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 26 May 2024 15:52:41 +0200 Subject: [PATCH 006/115] added top 300 --- src/views/tenant/administration/ListGDAPRelationships.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/tenant/administration/ListGDAPRelationships.jsx b/src/views/tenant/administration/ListGDAPRelationships.jsx index 11ae56e89e33..25b332ffdcaf 100644 --- a/src/views/tenant/administration/ListGDAPRelationships.jsx +++ b/src/views/tenant/administration/ListGDAPRelationships.jsx @@ -251,7 +251,7 @@ const GDAPRelationships = () => { columns, reportName: `GDAP-Relationships`, path: '/api/ListGraphRequest', - params: { Endpoint: 'tenantRelationships/delegatedAdminRelationships' }, + params: { Endpoint: 'tenantRelationships/delegatedAdminRelationships', $top: 300 }, }} /> From cfd802e046b6a4888167c9fbe17854caf7666483 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 26 May 2024 16:55:57 +0200 Subject: [PATCH 007/115] fixes offboarding wizard speed --- .../administration/OffboardingWizard.jsx | 45 ++++++++++--------- src/views/identity/administration/Roles.jsx | 16 ++++--- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/views/identity/administration/OffboardingWizard.jsx b/src/views/identity/administration/OffboardingWizard.jsx index b5b344969c7a..571eba706e8b 100644 --- a/src/views/identity/administration/OffboardingWizard.jsx +++ b/src/views/identity/administration/OffboardingWizard.jsx @@ -47,7 +47,18 @@ const OffboardingWizard = () => { data: users = [], isFetching: usersIsFetching, error: usersError, - } = useListUsersQuery({ tenantDomain }) + } = useGenericGetRequestQuery({ + path: `/api/ListGraphRequest`, + params: { + TenantFilter: tenantDomain, + Endpoint: 'users', + $select: + 'id,displayName,givenName,mail,mailNickname,proxyAddresses,usageLocation,userPrincipalName,userType,assignedLicenses,onPremisesSyncEnabled', + $count: true, + $orderby: 'displayName', + $top: 999, + }, + }) const { data: recipients = [], @@ -121,7 +132,7 @@ const OffboardingWizard = () => { ({ + values={users?.Results?.map((user) => ({ value: user.userPrincipalName, name: `${user.displayName} <${user.userPrincipalName}>`, }))} @@ -177,36 +188,30 @@ const OffboardingWizard = () => { x.mail) - .map((user) => ({ - value: user.mail, - name: `${user.displayName} <${user.mail}>`, - }))} + values={users.Results?.filter((x) => x.mail).map((user) => ({ + value: user.mail, + name: `${user.displayName} <${user.mail}>`, + }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="AccessNoAutomap" /> x.mail) - .map((user) => ({ - value: user.mail, - name: `${user.displayName} <${user.mail}>`, - }))} + values={users.Results?.filter((x) => x.mail).map((user) => ({ + value: user.mail, + name: `${user.displayName} <${user.mail}>`, + }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="AccessAutomap" /> x.mail) - .map((user) => ({ - value: user.mail, - name: `${user.displayName} <${user.mail}>`, - }))} + values={users.Results?.filter((x) => x.mail).map((user) => ({ + value: user.mail, + name: `${user.displayName} <${user.mail}>`, + }))} placeholder={!usersIsFetching ? 'Select user' : 'Loading...'} name="OnedriveAccess" /> diff --git a/src/views/identity/administration/Roles.jsx b/src/views/identity/administration/Roles.jsx index 600d5f31cd49..7e103a130920 100644 --- a/src/views/identity/administration/Roles.jsx +++ b/src/views/identity/administration/Roles.jsx @@ -23,7 +23,12 @@ const Offcanvas = (row, rowIndex, formatExtraData) => { >
Role Group Name:
{row.DisplayName}



-
Member Names:
{row.Members ? row.Members.split(',').map((member, index) =>

{member}

) :

Role has no members.

} +
Member Names:
{' '} + {row.Members ? ( + row.Members.split(',').map((member, index) =>

{member}

) + ) : ( +

Role has no members.

+ )} ) @@ -59,15 +64,16 @@ const columns = [ sortable: false, cell: (row) => { if (row.Members === 'none') { - return null; + return null } - const memberCount = row.Members ? row.Members.split(',').length : 0; - const memberText = row.Members && row.Members !== 'none' ? `Member${memberCount === 1 ? '' : 's'}` : null; + const memberCount = row.Members ? row.Members.split(',').length : 0 + const memberText = + row.Members && row.Members !== 'none' ? `Member${memberCount === 1 ? '' : 's'}` : null return ( <> {memberCount} {memberText} - ); + ) }, exportSelector: 'Members', maxWidth: '150px', From 202962fec5c052656197c6b4d0ac0f3e07f32117 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 26 May 2024 18:34:14 +0200 Subject: [PATCH 008/115] removed data from loop --- src/components/tables/CippTable.jsx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/tables/CippTable.jsx b/src/components/tables/CippTable.jsx index f3ea486ee243..e858c5e28fc6 100644 --- a/src/components/tables/CippTable.jsx +++ b/src/components/tables/CippTable.jsx @@ -414,6 +414,7 @@ export default function CippTable({ (modalMessage, modalUrl, modalType = 'GET', modalBody, modalInput, modalDropdown) => { if (modalType === 'GET') { ModalService.confirm({ + getData: () => inputRef.current?.value, body: (
{modalMessage}
@@ -466,6 +467,18 @@ export default function CippTable({ title: 'Confirm', onConfirm: async () => { const resultsarr = [] + 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]] + }) + } + } for (const row of selectedRows) { setLoopRunning(true) const urlParams = new URLSearchParams(modalUrl.split('?')[1]) @@ -492,26 +505,13 @@ export default function CippTable({ } } 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, ...additionalFields, - ...{ input: inputRef.current.value }, + ...{ input: selectedValue }, }, }) resultsarr.push(results) From fe06f78873324dcbc6ce7a2d02a1445f1a6c7439 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 26 May 2024 19:00:18 +0200 Subject: [PATCH 009/115] added bulk options for policies --- src/views/endpoint/intune/MEMListAppProtection.jsx | 11 ++++++++++- src/views/endpoint/intune/MEMListCompliance.jsx | 11 ++++++++++- src/views/endpoint/intune/MEMListPolicies.jsx | 9 +++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/views/endpoint/intune/MEMListAppProtection.jsx b/src/views/endpoint/intune/MEMListAppProtection.jsx index 569608ec916c..f017ba2f2065 100644 --- a/src/views/endpoint/intune/MEMListAppProtection.jsx +++ b/src/views/endpoint/intune/MEMListAppProtection.jsx @@ -48,7 +48,7 @@ const Actions = (row, rowIndex, formatExtraData) => { color: 'danger', modal: true, icon: , - modalUrl: `/api/RemovePolicy?TenantFilter=${tenant.defaultDomainName}&ID=${row.id}&URLName=${row.URLName}`, + modalUrl: `/api/RemovePolicy?TenantFilter=${tenant.defaultDomainName}&ID=${row.id}&URLName=managedAppPolicies`, modalMessage: 'Are you sure you want to delete this policy?', }, ]} @@ -122,6 +122,15 @@ const AppProtectionList = () => { expandableRows: true, expandableRowsComponent: ExpandedComponent, expandOnRowClicked: true, + selectableRows: true, + actionsList: [ + { + label: 'Delete Policy', + modal: true, + modalUrl: `api/RemovePolicy?TenantFilter=${tenant?.defaultDomainName}&ID=!id&URLName=managedAppPolicies`, + modalMessage: 'Are you sure you want to convert these users to a shared mailbox?', + }, + ], }, }} /> diff --git a/src/views/endpoint/intune/MEMListCompliance.jsx b/src/views/endpoint/intune/MEMListCompliance.jsx index 6fbe0cdf84ce..9b970031bb1d 100644 --- a/src/views/endpoint/intune/MEMListCompliance.jsx +++ b/src/views/endpoint/intune/MEMListCompliance.jsx @@ -71,7 +71,7 @@ const Actions = (row, rowIndex, formatExtraData) => { color: 'danger', modal: true, icon: , - modalUrl: `/api/RemovePolicy?TenantFilter=${tenant.defaultDomainName}&ID=${row.id}&URLName=${row.URLName}`, + modalUrl: `/api/RemovePolicy?TenantFilter=${tenant.defaultDomainName}&ID=${row.id}&URLName=deviceCompliancePolicies`, modalMessage: 'Are you sure you want to delete this policy?', }, ]} @@ -145,6 +145,15 @@ const ComplianceList = () => { expandableRows: true, expandableRowsComponent: ExpandedComponent, expandOnRowClicked: true, + selectableRows: true, + actionsList: [ + { + label: 'Delete Policy', + modal: true, + modalUrl: `api/RemovePolicy?TenantFilter=${tenant?.defaultDomainName}&ID=!id&URLName=deviceCompliancePolicies`, + modalMessage: 'Are you sure you want to convert these users to a shared mailbox?', + }, + ], }, }} /> diff --git a/src/views/endpoint/intune/MEMListPolicies.jsx b/src/views/endpoint/intune/MEMListPolicies.jsx index 0ea3ed1a26f4..f9f82026cd52 100644 --- a/src/views/endpoint/intune/MEMListPolicies.jsx +++ b/src/views/endpoint/intune/MEMListPolicies.jsx @@ -140,6 +140,15 @@ const IntuneList = () => { expandableRows: true, expandableRowsComponent: ExpandedComponent, expandOnRowClicked: true, + selectableRows: true, + actionsList: [ + { + label: 'Delete Policy', + modal: true, + modalUrl: `api/RemovePolicy?TenantFilter=${tenant?.defaultDomainName}&ID=!id&URLName=!URLName`, + modalMessage: 'Are you sure you want to convert these users to a shared mailbox?', + }, + ], }, }} /> From a5505d3c0786665680df5cb3c90888f6166a23ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sun, 26 May 2024 21:54:13 +0200 Subject: [PATCH 010/115] Add shorten meetings standard --- src/data/standards.json | 42 +++++++++++++++++++++++++++++++++++++++++ src/views/home/Home.jsx | 3 +-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index c9326b8b5f1f..3efbc09ea197 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -830,6 +830,48 @@ "impact": "Low Impact", "impactColour": "info" }, + { + "name": "standards.ShortenMeetings", + "cat": "Exchange Standards", + "tag": ["mediumimpact"], + "helpText": "Sets the shorten meetings settings on a tenant level. This will shorten meetings by the selected amount of minutes. Valid values are 0 to 29. Short meetings are under 60 minutes, long meetings are over 60 minutes.", + "addedComponent": [ + { + "type": "Select", + "label": "Select value", + "name": "standards.ShortenMeetings.ShortenEventScopeDefault", + "values": [ + { + "label": "Disabled/None", + "value": "None" + }, + { + "label": "End early", + "value": "EndEarly" + }, + { + "label": "Start late", + "value": "StartLate" + } + ] + }, + { + "type": "number", + "name": "standards.ShortenMeetings.DefaultMinutesToReduceShortEventsBy", + "label": "Minutes to reduce short calendar events by (Default is 5)", + "default": 5 + }, + { + "type": "number", + "name": "standards.ShortenMeetings.DefaultMinutesToReduceLongEventsBy", + "label": "Minutes to reduce long calendar events by (Default is 10)", + "default": 10 + } + ], + "label": "Set shorten meetings state", + "impact": "Medium Impact", + "impactColour": "warning" + }, { "name": "standards.DisableOutlookAddins", "cat": "Exchange Standards", diff --git a/src/views/home/Home.jsx b/src/views/home/Home.jsx index 432bd10e0870..7111f9e41bb2 100644 --- a/src/views/home/Home.jsx +++ b/src/views/home/Home.jsx @@ -30,8 +30,7 @@ import CippCopyToClipboard from 'src/components/utilities/CippCopyToClipboard' import { CChart } from '@coreui/react-chartjs' import { getStyle } from '@coreui/utils' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { Link } from 'react-router-dom' -import { useNavigate } from 'react-router-dom' +import { useNavigate, Link } from 'react-router-dom' import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' import { ModalService } from 'src/components/utilities' From 5059a0301d63b011b405595781e84d37e15ee2e4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 May 2024 16:05:13 -0400 Subject: [PATCH 011/115] Graph Explorer Scheduler Add CippScheduleOffcanvas --- .../utilities/CippScheduleOffcanvas.jsx | 273 ++++++++++++++++++ src/views/cipp/Scheduler.jsx | 1 - .../tenant/administration/GraphExplorer.jsx | 53 ++++ 3 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 src/components/utilities/CippScheduleOffcanvas.jsx diff --git a/src/components/utilities/CippScheduleOffcanvas.jsx b/src/components/utilities/CippScheduleOffcanvas.jsx new file mode 100644 index 000000000000..b040ff031192 --- /dev/null +++ b/src/components/utilities/CippScheduleOffcanvas.jsx @@ -0,0 +1,273 @@ +import React, { useState } from 'react' +import PropTypes from 'prop-types' +import { + CButton, + CCallout, + CCard, + CCardBody, + CCardHeader, + CCol, + CForm, + CRow, + CSpinner, + CTooltip, +} from '@coreui/react' +import { CippOffcanvas, TenantSelector } from '.' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { Field, Form, FormSpy } from 'react-final-form' +import arrayMutators from 'final-form-arrays' +import { + RFFCFormInput, + RFFCFormInputArray, + RFFCFormSwitch, + RFFSelectSearch, +} from 'src/components/forms' +import { useSelector } from 'react-redux' +import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' +import DatePicker from 'react-datepicker' +import 'react-datepicker/dist/react-datepicker.css' + +export default function CippScheduleOffcanvas({ + state: visible, + hideFunction, + title, + placement, + ...props +}) { + const currentDate = new Date() + const [startDate, setStartDate] = useState(currentDate) + const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) + const [refreshState, setRefreshState] = useState(false) + const taskName = `Scheduled Task ${currentDate.toLocaleString()}` + const { data: availableCommands = [], isLoading: isLoadingcmd } = useGenericGetRequestQuery({ + path: 'api/ListFunctionParameters?Module=CIPPCore', + }) + + const recurrenceOptions = [ + { value: '0', name: 'Only once' }, + { value: '1', name: 'Every 1 day' }, + { value: '7', name: 'Every 7 days' }, + { value: '30', name: 'Every 30 days' }, + { value: '365', name: 'Every 365 days' }, + ] + + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + const onSubmit = (values) => { + const unixTime = Math.floor(startDate.getTime() / 1000) + const shippedValues = { + TenantFilter: tenantDomain, + Name: values.taskName, + Command: values.command, + Parameters: values.parameters, + ScheduledTime: unixTime, + Recurrence: values.Recurrence, + AdditionalProperties: values.additional, + PostExecution: { + Webhook: values.webhook, + Email: values.email, + PSA: values.psa, + }, + } + genericPostRequest({ path: '/api/AddScheduledItem', values: shippedValues }).then((res) => { + setRefreshState(res.requestId) + }) + } + + return ( + + + + +
{ + return ( + + + + + {(props) => } + + + + + + + + + + + setStartDate(date)} + /> + + + + + + + + + + ({ + value: cmd.Function, + name: cmd.Function, + }))} + name="command" + placeholder={ + isLoadingcmd ? ( + + ) : ( + 'Select a command or report to execute.' + ) + } + label="Command to execute" + /> + + + + {/* eslint-disable react/prop-types */} + {(props) => { + const selectedCommand = availableCommands.find( + (cmd) => cmd.Function === props.values.command?.value, + ) + return ( + + {selectedCommand?.Synopsis} + + ) + }} + + + + {/* eslint-disable react/prop-types */} + {(props) => { + const selectedCommand = availableCommands.find( + (cmd) => cmd.Function === props.values.command?.value, + ) + let paramblock = null + if (selectedCommand) { + //if the command parameter type is boolean we use else . + const parameters = selectedCommand.Parameters + if (parameters.length > 0) { + paramblock = parameters.map((param, idx) => ( + + + + {param.Type === 'System.Boolean' || + param.Type === + 'System.Management.Automation.SwitchParameter' ? ( + <> + + + + ) : ( + <> + {param.Type === 'System.Collections.Hashtable' ? ( + + ) : ( + + )} + + )} + + + + )) + } + } + return paramblock + }} + + + + + + + + + + + + + + + + + + + Add Schedule + {postResults.isFetching && ( + + )} + + + + {postResults.isSuccess && ( + +
  • {postResults.data.Results}
  • +
    + )} +
    + ) + }} + /> + + + + ) +} + +CippScheduleOffcanvas.propTypes = { + groups: PropTypes.array, + placement: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + state: PropTypes.bool, + hideFunction: PropTypes.func.isRequired, +} diff --git a/src/views/cipp/Scheduler.jsx b/src/views/cipp/Scheduler.jsx index aa07fb3722b6..7ffed5837fe0 100644 --- a/src/views/cipp/Scheduler.jsx +++ b/src/views/cipp/Scheduler.jsx @@ -157,7 +157,6 @@ const Scheduler = () => { if (typeof row?.Parameters[key] === 'object') { var nestedParamList = [] Object.keys(row?.Parameters[key]).forEach((nestedKey) => { - console.log(nestedKey) nestedParamList.push({ Key: nestedKey, Value: row?.Parameters[key][nestedKey], diff --git a/src/views/tenant/administration/GraphExplorer.jsx b/src/views/tenant/administration/GraphExplorer.jsx index 3d6950c598d4..ebc3abd8b39d 100644 --- a/src/views/tenant/administration/GraphExplorer.jsx +++ b/src/views/tenant/administration/GraphExplorer.jsx @@ -32,6 +32,7 @@ import { cellGenericFormatter } from 'src/components/tables/CellGenericFormat' import PropTypes from 'prop-types' import { CippCodeOffCanvas, ModalService } from 'src/components/utilities' import { debounce } from 'lodash-es' +import CippScheduleOffcanvas from 'src/components/utilities/CippScheduleOffcanvas' const GraphExplorer = () => { const tenant = useSelector((state) => state.app.currentTenant) @@ -57,6 +58,8 @@ const GraphExplorer = () => { error: presetsError, } = useGenericGetRequestQuery({ path: '/api/ListGraphExplorerPresets', params: { random2 } }) const QueryColumns = { set: false, data: [] } + const [scheduleVisible, setScheduleVisible] = useState(false) + const [scheduleValues, setScheduleValues] = useState({}) const debounceEndpointChange = useMemo(() => { function endpointChange(value) { @@ -148,6 +151,36 @@ const GraphExplorer = () => { }) } + function handleSchedule(values) { + var graphParameters = [] + const paramNames = ['$filter', '$format', '$search', '$select', '$top'] + paramNames.map((param) => { + if (values[param]) { + if (Array.isArray(values[param])) { + graphParameters.push({ Key: param, Value: values[param].map((p) => p.value).join(',') }) + } else { + graphParameters.push({ Key: param, Value: values[param] }) + } + } + }) + + const reportName = values.name ?? 'Graph Explorer' + const shippedValues = { + taskName: reportName + ' - ' + tenant.displayName, + command: { label: 'Get-GraphRequestList', value: 'Get-GraphRequestList' }, + parameters: { + Parameters: graphParameters, + NoPagination: values.NoPagination, + ReverseTenantLookup: values.ReverseTenantLookup, + ReverseTenantLookupProperty: values.ReverseTenantLookupProperty, + Endpoint: values.endpoint, + SkipCache: true, + }, + } + setScheduleValues(shippedValues) + setScheduleVisible(true) + } + const presets = [ { name: 'All users with email addresses', @@ -617,6 +650,19 @@ const GraphExplorer = () => { Query + + {(props) => { + return ( + handleSchedule(props.values)} + className="ms-2" + > + + Schedule Report + + ) + }} + @@ -628,6 +674,13 @@ const GraphExplorer = () => { + setScheduleVisible(false)} + initialValues={scheduleValues} + />
    {!searchNow && Execute a search to get started.} From b26aea1efb4a6f051046c5ef6aa47d9ec4dec9ed Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 28 May 2024 12:12:51 +0200 Subject: [PATCH 012/115] improvements to autopilot. --- .../endpoint/autopilot/AutopilotAddDevice.jsx | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/views/endpoint/autopilot/AutopilotAddDevice.jsx b/src/views/endpoint/autopilot/AutopilotAddDevice.jsx index 35abc7cc505f..b475e2712388 100644 --- a/src/views/endpoint/autopilot/AutopilotAddDevice.jsx +++ b/src/views/endpoint/autopilot/AutopilotAddDevice.jsx @@ -34,6 +34,28 @@ Error.propTypes = { const AddAPDevice = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() const [autopilotData, setAutopilotdata] = useState([]) + const completeColumns = [ + { + name: 'Serial Number', + selector: (row) => row['serialNumber'], + sortable: true, + }, + { + name: 'Status', + selector: (row) => row['status'], + sortable: true, + }, + { + name: 'Error Code', + selector: (row) => row['errorCode'], + sortable: true, + }, + { + name: 'Error Description', + selector: (row) => row['errorDescription'], + sortable: true, + }, + ] const tableColumns = [ { name: 'serialNumber', @@ -267,8 +289,18 @@ const AddAPDevice = () => { Loading )} - {postResults.isSuccess && {postResults.data.Results}} - {autopilotData && ( + {postResults.isSuccess && ( + <> + {postResults.data?.Results?.Status} + + + )} + {autopilotData && !postResults.isSuccess && ( Date: Tue, 28 May 2024 18:05:03 +0200 Subject: [PATCH 013/115] pretification --- src/views/identity/administration/OffboardingWizard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/identity/administration/OffboardingWizard.jsx b/src/views/identity/administration/OffboardingWizard.jsx index 571eba706e8b..4d6c496951f8 100644 --- a/src/views/identity/administration/OffboardingWizard.jsx +++ b/src/views/identity/administration/OffboardingWizard.jsx @@ -302,7 +302,7 @@ const OffboardingWizard = () => { >
    Selected User:
    - {users.find((x) => x.userPrincipalName === user.value) + {users.Results?.find((x) => x.userPrincipalName === user.value) .onPremisesSyncEnabled === true ? ( Date: Tue, 28 May 2024 13:57:57 -0500 Subject: [PATCH 014/115] Update Users.jsx Created filter for Non-guest (Member) users; Fixed "AAD users" filter to handle null values --- src/views/identity/administration/Users.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/identity/administration/Users.jsx b/src/views/identity/administration/Users.jsx index 2d0a4aa9ac49..0f34be2af7ef 100644 --- a/src/views/identity/administration/Users.jsx +++ b/src/views/identity/administration/Users.jsx @@ -447,11 +447,12 @@ const Users = (row) => { filterlist: [ { filterName: 'Enabled users', filter: '"accountEnabled":true' }, { filterName: 'Disabled users', filter: '"accountEnabled":false' }, - { filterName: 'AAD users', filter: '"onPremisesSyncEnabled":false' }, + { filterName: 'AAD users', filter: 'Complex: onPremisesSyncEnabled ne True' }, { filterName: 'Synced users', filter: '"onPremisesSyncEnabled":true', }, + { filterName: 'Non-guest users', filter: 'Complex: usertype ne Guest' }, { filterName: 'Guest users', filter: '"usertype":"guest"' }, { filterName: 'Users with a license', From 6fd3c252874e416978d754ccc13e58dd69ed2d99 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 May 2024 20:11:53 -0400 Subject: [PATCH 015/115] Custom Roles --- src/components/forms/RFFComponents.jsx | 2 - .../utilities/CippScheduleOffcanvas.jsx | 3 + .../cipp/app-settings/SettingsSuperAdmin.jsx | 130 +++---- .../components/SettingsCustomRoles.jsx | 351 ++++++++++++++++++ 4 files changed, 422 insertions(+), 64 deletions(-) create mode 100644 src/views/cipp/app-settings/components/SettingsCustomRoles.jsx diff --git a/src/components/forms/RFFComponents.jsx b/src/components/forms/RFFComponents.jsx index 737333c7dfc9..01b4ed8f083b 100644 --- a/src/components/forms/RFFComponents.jsx +++ b/src/components/forms/RFFComponents.jsx @@ -293,7 +293,6 @@ export const RFFCFormRadioList = ({ name, options, className = 'mb-3', - disabled = false, onClick, inline = false, }) => { @@ -312,7 +311,6 @@ export const RFFCFormRadioList = ({ onChange={input.onChange} type="radio" {...option} - disabled={disabled} onClick={onClick} inline={inline} /> diff --git a/src/components/utilities/CippScheduleOffcanvas.jsx b/src/components/utilities/CippScheduleOffcanvas.jsx index b040ff031192..45d5b5a62e92 100644 --- a/src/components/utilities/CippScheduleOffcanvas.jsx +++ b/src/components/utilities/CippScheduleOffcanvas.jsx @@ -70,6 +70,9 @@ export default function CippScheduleOffcanvas({ } genericPostRequest({ path: '/api/AddScheduledItem', values: shippedValues }).then((res) => { setRefreshState(res.requestId) + if (props.submitFunction) { + props.submitFunction() + } }) } diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx index 7650089b5a23..bec964fa3386 100644 --- a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx +++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx @@ -1,10 +1,11 @@ import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app.js' -import { CButton, CCol, CForm, CLink, CRow, CSpinner } from '@coreui/react' +import { CAccordion, CButton, CCol, CForm, CLink, CRow, CSpinner } from '@coreui/react' import { Form } from 'react-final-form' import { RFFCFormRadio } from 'src/components/forms/index.js' import React from 'react' import { CippCallout } from 'src/components/layout/index.js' -import CippButtonCard from 'src/components/contentcards/CippButtonCard' +import CippAccordionItem from 'src/components/contentcards/CippAccordionItem' +import SettingsCustomRoles from 'src/views/cipp/app-settings/components/SettingsCustomRoles' export function SettingsSuperAdmin() { const partnerConfig = useGenericGetRequestQuery({ @@ -38,68 +39,73 @@ export function SettingsSuperAdmin() { ) return ( - - <> + + <> - - -

    - The configuration settings below should only be modified by a super admin. Super - admins can configure what tenant mode CIPP operates in. See - - our documentation - - for more information on how to configure these modes and what they mean. -

    -
    -
    - - -

    Tenant Mode

    - ( - <> - {partnerConfig.isFetching && } - - - - - - + <> + + +

    + The configuration settings below should only be modified by a super admin. Super + admins can configure what tenant mode CIPP operates in. See + + our documentation + + for more information on how to configure these modes and what they mean. +

    +
    +
    + + +

    Tenant Mode

    + ( + <> + {partnerConfig.isFetching && } + + + + + + + )} + /> + {webhookCreateResult.isSuccess && ( + + {webhookCreateResult?.data?.results} + )} - /> - {webhookCreateResult.isSuccess && ( - - {webhookCreateResult?.data?.results} - - )} -
    -
    +
    +
    + - -
    + + + + + ) } diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx new file mode 100644 index 000000000000..ad8bb5a8db2c --- /dev/null +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -0,0 +1,351 @@ +import React, { useRef, useState } from 'react' +import { + CButton, + CCallout, + CCol, + CForm, + CRow, + CAccordion, + CAccordionHeader, + CAccordionBody, + CAccordionItem, +} from '@coreui/react' +import { Field, Form, FormSpy } from 'react-final-form' +import { RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms' +import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' +import { CippPage } from 'src/components/layout' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import Skeleton from 'react-loading-skeleton' +import { TenantSelectorMultiple, ModalService } from 'src/components/utilities' +import PropTypes from 'prop-types' +import { OnChange } from 'react-final-form-listeners' +import { useListTenantsQuery } from 'src/store/api/tenants' + +const SettingsCustomRoles = () => { + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + const [selectedTenant, setSelectedTenant] = useState([]) + const tenantSelectorRef = useRef() + const { data: tenants = [], tenantsFetching } = useListTenantsQuery({ + showAllTenantSelector: true, + }) + + const { + data: apiPermissions = [], + isFetching, + isSuccess, + } = useGenericGetRequestQuery({ + path: 'api/ExecAPIPermissionList', + }) + + const { + data: customRoleList = [], + isFetching: customRoleListFetching, + isSuccess: customRoleListSuccess, + refetch: refetchCustomRoleList, + } = useGenericGetRequestQuery({ + path: 'api/ExecCustomRole', + }) + + const handleSubmit = async (values) => { + //filter on only objects that are 'true' + genericPostRequest({ + path: '/api/ExecCustomRole?Action=AddUpdate', + values: { + RoleName: values.RoleName.value, + Permissions: values.Permissions, + AllowedTenants: selectedTenant.map((tenant) => tenant.value), + }, + }).then(() => { + refetchCustomRoleList() + }) + } + const handleDelete = async (values) => { + ModalService.confirm({ + title: 'Delete Custom Role', + body: 'Are you sure you want to delete this custom role? Any users with this role will have their permissions reset to the default for their base role.', + onConfirm: () => { + genericPostRequest({ + path: '/api/ExecCustomRole?Action=Delete', + values: { + RoleName: values.RoleName.value, + }, + }).then(() => { + refetchCustomRoleList() + }) + }, + }) + } + + const WhenFieldChanges = ({ field, set }) => ( + + {( + // No subscription. We only use Field to get to the change function + { input: { onChange } }, + ) => ( + + {({ form }) => ( + + {(value) => { + if (field === 'RoleName' && value?.value) { + let customRole = customRoleList.filter(function (obj) { + return obj.RowKey === value.value + }) + if (customRole === undefined || customRole === null || customRole.length === 0) { + return false + } else { + if (set === 'AllowedTenants') { + setSelectedTenant(customRole[0][set]) + var selectedTenants = [] + tenants.map((tenant) => { + if (customRole[0][set].includes(tenant.customerId)) { + selectedTenants.push({ + label: tenant.displayName, + value: tenant.customerId, + }) + } + }) + + tenantSelectorRef.current.setValue(selectedTenants) + } else { + onChange(customRole[0][set]) + } + } + } + if (field === 'Defaults') { + let newPermissions = {} + Object.keys(apiPermissions).forEach((cat) => { + Object.keys(apiPermissions[cat]).forEach((obj) => { + var newval = '' + if (cat == 'CIPP' && obj == 'Core' && value == 'None') { + newval = 'Read' + } else { + newval = value + } + newPermissions[`${cat}${obj}`] = `${cat}.${obj}.${newval}` + }) + }) + onChange(newPermissions) + } + }} + + )} + + )} + + ) + WhenFieldChanges.propTypes = { + field: PropTypes.node, + set: PropTypes.string, + } + return ( + + <> +

    + Custom roles can be used to restrict permissions for users with the 'editor' or 'readonly' + roles in CIPP. They can be limited to a subset of tenants and API permissions. +

    +

    + NOTE: The custom role must be added to the user in SWA in conjunction with the base role. + (e.g. editor,mycustomrole) +

    + {(isFetching || tenantsFetching) && } + {isSuccess && !isFetching && !tenantsFetching && ( + { + return ( + + + +
    + ({ + name: role.RowKey, + value: role.RowKey, + }))} + isLoading={customRoleListFetching} + refreshFunction={() => refetchCustomRoleList()} + allowCreate={true} + placeholder="Select an existing role or enter a custom role name" + /> + + +
    +
    +
    Allowed Tenants
    + setSelectedTenant(e)} + /> +
    +
    API Permissions
    + + +
    +
    Set All Permissions
    +
    +
    + + + + +
    + + <> + {Object.keys(apiPermissions) + .sort() + .map((cat, catIndex) => ( + + {cat} + + {Object.keys(apiPermissions[cat]) + .sort() + .map((obj, index) => ( + + +
    +
    {obj}
    +
    +
    + + + +
    + ))} +
    +
    + ))} + +
    +
    + + + {({ values }) => { + return ( + <> + {values['RoleName'] && selectedTenant.length > 0 && ( + <> +
    Selected Tenants
    +
      + {selectedTenant.map((tenant, idx) => ( +
    • {tenant.label}
    • + ))} +
    + + )} + {values['RoleName'] && values['Permissions'] && ( + <> +
    Selected Permissions
    +
      + {values['Permissions'] && + Object.keys(values['Permissions'])?.map((cat, idx) => ( + <> + {!values['Permissions'][cat].includes('None') && ( +
    • {values['Permissions'][cat]}
    • + )} + + ))} +
    + + )} + + ) + }} +
    +
    +
    + + {postResults.isSuccess && ( + {postResults.data.Results} + )} + + + + + Save + + + {({ values }) => { + return ( + handleDelete(values)} + disabled={!values['RoleName']} + > + + Delete + + ) + }} + + + + +
    + ) + }} + /> + )} + +
    + ) +} + +export default SettingsCustomRoles From 551ae1d27517526bcfe596774b76a42af03633f3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 01:18:21 -0400 Subject: [PATCH 016/115] Custom Role Info --- .../utilities/CippListOffcanvas.jsx | 9 +- .../components/SettingsCustomRoles.jsx | 123 +++++++++++++----- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/src/components/utilities/CippListOffcanvas.jsx b/src/components/utilities/CippListOffcanvas.jsx index 4fbde6931ce3..e3c3229ae394 100644 --- a/src/components/utilities/CippListOffcanvas.jsx +++ b/src/components/utilities/CippListOffcanvas.jsx @@ -38,7 +38,7 @@ CippListOffcanvas.propTypes = { hideFunction: PropTypes.func.isRequired, } -export function OffcanvasListSection({ title, items }) { +export function OffcanvasListSection({ title, items, showCardTitle = true }) { //console.log(items) const mappedItems = items.map((item, key) => ({ value: item.content, label: item.heading })) return ( @@ -48,7 +48,11 @@ export function OffcanvasListSection({ title, items }) { - Extended Information + {showCardTitle && ( + <> + Extended Information + + )} @@ -62,4 +66,5 @@ export function OffcanvasListSection({ title, items }) { OffcanvasListSection.propTypes = { title: PropTypes.string, items: PropTypes.array, + showCardTitle: PropTypes.bool, } diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index ad8bb5a8db2c..55215fa1400f 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -16,10 +16,11 @@ import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/s import { CippPage } from 'src/components/layout' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import Skeleton from 'react-loading-skeleton' -import { TenantSelectorMultiple, ModalService } from 'src/components/utilities' +import { TenantSelectorMultiple, ModalService, CippOffcanvas } from 'src/components/utilities' import PropTypes from 'prop-types' import { OnChange } from 'react-final-form-listeners' import { useListTenantsQuery } from 'src/store/api/tenants' +import CippListOffcanvas, { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas' const SettingsCustomRoles = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() @@ -137,6 +138,85 @@ const SettingsCustomRoles = () => { field: PropTypes.node, set: PropTypes.string, } + + const ApiPermissionRow = ({ obj, cat }) => { + const [offcanvasVisible, setOffcanvasVisible] = useState(false) + + var items = [] + for (var key in apiPermissions[cat][obj]) + for (var key2 in apiPermissions[cat][obj][key]) { + items.push({ heading: '', content: apiPermissions[cat][obj][key][key2] }) + } + var group = [{ items: items }] + + return ( + <> + +
    +
    {obj}
    +
    +
    + + setOffcanvasVisible(true)} variant="ghost" size="sm" color="info"> + + + + + + + setOffcanvasVisible(false)} + title={`${cat}.${obj}`} + placement="end" + size="lg" + > +

    + Listed below are the available API endpoints based on permission level, ReadWrite level + includes endpoints under Read. +

    + {[apiPermissions[cat][obj]].map((permissions, key) => { + var sections = Object.keys(permissions).map((type) => { + var items = [] + for (var api in permissions[type]) { + items.push({ heading: '', content: permissions[type][api] }) + } + return ( + + ) + }) + return sections + })} +
    + + ) + } + ApiPermissionRow.propTypes = { + obj: PropTypes.node, + cat: PropTypes.node, + } + return ( <> @@ -196,6 +276,7 @@ const SettingsCustomRoles = () => {
    Set All Permissions
    + { {Object.keys(apiPermissions[cat]) .sort() - .map((obj, index) => ( - - -
    -
    {obj}
    -
    -
    - - - -
    - ))} + .map((obj, index) => { + return ( + + + + ) + })}
    ))} From 17dcf396b805f66b89c5c3348fe482fa0e46d215 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 09:18:01 -0400 Subject: [PATCH 017/115] Update SettingsCustomRoles.jsx --- .../cipp/app-settings/components/SettingsCustomRoles.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index 55215fa1400f..6f439a01c832 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -188,10 +188,11 @@ const SettingsCustomRoles = () => { setOffcanvasVisible(false)} - title={`${cat}.${obj}`} + title="Permission Info" placement="end" size="lg" > +

    {`${cat}.${obj}`}

    Listed below are the available API endpoints based on permission level, ReadWrite level includes endpoints under Read. @@ -222,7 +223,8 @@ const SettingsCustomRoles = () => { <>

    Custom roles can be used to restrict permissions for users with the 'editor' or 'readonly' - roles in CIPP. They can be limited to a subset of tenants and API permissions. + roles in CIPP. They can be limited to a subset of tenants and API permissions. To restrict + direct API access, create a role with the name 'CIPP-API'.

    NOTE: The custom role must be added to the user in SWA in conjunction with the base role. From 6ed7aa3aea3b537c539b4099984e02714ba5c425 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 13:10:38 -0400 Subject: [PATCH 018/115] Fix scripted alert react error --- src/views/tenant/administration/AlertWizard.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/tenant/administration/AlertWizard.jsx b/src/views/tenant/administration/AlertWizard.jsx index 2c3bf20bf0cf..6b1daf2e77ca 100644 --- a/src/views/tenant/administration/AlertWizard.jsx +++ b/src/views/tenant/administration/AlertWizard.jsx @@ -317,7 +317,7 @@ const AlertWizard = () => { multi={true} name={`actions`} placeholder={ - 'Select one action or multple actions from the list' + 'Select one action or multiple actions from the list' } label="Then perform the following action(s)" /> @@ -382,7 +382,7 @@ const AlertWizard = () => { /> - + From 2b7edbd95bcd5a2e4f87c093c74c6fec17db81db Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 13:18:24 -0400 Subject: [PATCH 019/115] Add beta notice --- src/views/cipp/app-settings/SettingsSuperAdmin.jsx | 2 +- .../cipp/app-settings/components/SettingsCustomRoles.jsx | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx index bec964fa3386..8f1184eef32d 100644 --- a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx +++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx @@ -103,7 +103,7 @@ export function SettingsSuperAdmin() { - + diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index 6f439a01c832..f45741bcabed 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -227,8 +227,9 @@ const SettingsCustomRoles = () => { direct API access, create a role with the name 'CIPP-API'.

    - NOTE: The custom role must be added to the user in SWA in conjunction with the base role. - (e.g. editor,mycustomrole) + This functionality is in + beta and should be treated as such. The custom role must be added to the user in SWA in + conjunction with the base role. (e.g. editor,mycustomrole)

    {(isFetching || tenantsFetching) && } {isSuccess && !isFetching && !tenantsFetching && ( From 2e671927c16112c89c88ba2e8f3db96d3814bad2 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 14:37:08 -0400 Subject: [PATCH 020/115] Fix meta.error on RFFSelectSearch --- src/components/forms/RFFComponents.jsx | 6 +++++- src/views/tenant/administration/AlertWizard.jsx | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/forms/RFFComponents.jsx b/src/components/forms/RFFComponents.jsx index 01b4ed8f083b..b72a840d4989 100644 --- a/src/components/forms/RFFComponents.jsx +++ b/src/components/forms/RFFComponents.jsx @@ -587,7 +587,11 @@ export const RFFSelectSearch = ({ {...props} /> )} - {meta.error && meta.touched && {meta.error}} + {meta.error && meta.touched && ( + + {typeof meta.error === 'object' ? Object.values(meta.error).join('') : meta.error} + + )} ) }} diff --git a/src/views/tenant/administration/AlertWizard.jsx b/src/views/tenant/administration/AlertWizard.jsx index 6b1daf2e77ca..549a316beb1f 100644 --- a/src/views/tenant/administration/AlertWizard.jsx +++ b/src/views/tenant/administration/AlertWizard.jsx @@ -96,7 +96,6 @@ const AlertWizard = () => { const getRecurrenceOptions = () => { const values = currentFormState?.values if (values) { - //console.log(currentFormState) const updatedRecurrenceOptions = recurrenceOptions.map((opt) => ({ ...opt, name: opt.name.replace(' (Recommended)', ''), @@ -382,7 +381,7 @@ const AlertWizard = () => { />
    - + From 25688a661425e06aa1cc602cb8a21b685b91cf1e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 30 May 2024 00:21:28 +0200 Subject: [PATCH 021/115] remove accordian for superadmin --- src/views/cipp/app-settings/SettingsSuperAdmin.jsx | 13 ++++++------- .../app-settings/components/SettingsCustomRoles.jsx | 7 ++++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx index 8f1184eef32d..4e38038fb68c 100644 --- a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx +++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx @@ -6,6 +6,7 @@ import React from 'react' import { CippCallout } from 'src/components/layout/index.js' import CippAccordionItem from 'src/components/contentcards/CippAccordionItem' import SettingsCustomRoles from 'src/views/cipp/app-settings/components/SettingsCustomRoles' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' export function SettingsSuperAdmin() { const partnerConfig = useGenericGetRequestQuery({ @@ -39,8 +40,8 @@ export function SettingsSuperAdmin() { ) return ( - - + - - - - - + + + ) } diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index f45741bcabed..d4b8d240a668 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -21,6 +21,7 @@ import PropTypes from 'prop-types' import { OnChange } from 'react-final-form-listeners' import { useListTenantsQuery } from 'src/store/api/tenants' import CippListOffcanvas, { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' const SettingsCustomRoles = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() @@ -219,7 +220,7 @@ const SettingsCustomRoles = () => { } return ( - + <>

    Custom roles can be used to restrict permissions for users with the 'editor' or 'readonly' @@ -231,7 +232,6 @@ const SettingsCustomRoles = () => { beta and should be treated as such. The custom role must be added to the user in SWA in conjunction with the base role. (e.g. editor,mycustomrole)

    - {(isFetching || tenantsFetching) && } {isSuccess && !isFetching && !tenantsFetching && ( {
    + {({ values }) => { @@ -402,7 +403,7 @@ const SettingsCustomRoles = () => { /> )} - + ) } From 0c07f2cccae1a64f8509f9c57f088b1c83c267d7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 20:46:39 -0400 Subject: [PATCH 022/115] Update ListAppliedStandards.jsx --- src/views/tenant/standards/ListAppliedStandards.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index 484ec3862a36..c48dd3705753 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -634,20 +634,13 @@ const ApplyNewStandard = () => {
    Remediate
    From 875d47b633e4f5918519e3123a2da4fcf8bb7338 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 00:05:44 -0400 Subject: [PATCH 023/115] Custom role callouts --- .../components/SettingsCustomRoles.jsx | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index d4b8d240a668..ff0b888eed72 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -30,6 +30,8 @@ const SettingsCustomRoles = () => { const { data: tenants = [], tenantsFetching } = useListTenantsQuery({ showAllTenantSelector: true, }) + const [allTenantSelected, setAllTenantSelected] = useState(false) + const [cippApiRoleSelected, setCippApiRoleSelected] = useState(false) const { data: apiPermissions = [], @@ -48,6 +50,20 @@ const SettingsCustomRoles = () => { path: 'api/ExecCustomRole', }) + const handleTenantChange = (e) => { + var alltenant = false + e.map((tenant) => { + if (tenant.value === 'AllTenants') { + alltenant = true + } + }) + if (alltenant) { + setAllTenantSelected(true) + } else { + setAllTenantSelected(false) + } + setSelectedTenant(e) + } const handleSubmit = async (values) => { //filter on only objects that are 'true' genericPostRequest({ @@ -92,6 +108,12 @@ const SettingsCustomRoles = () => { let customRole = customRoleList.filter(function (obj) { return obj.RowKey === value.value }) + if (customRole[0].RowKey === 'CIPP-API') { + setCippApiRoleSelected(true) + } else { + setCippApiRoleSelected(false) + } + if (customRole === undefined || customRole === null || customRole.length === 0) { return false } else { @@ -255,6 +277,12 @@ const SettingsCustomRoles = () => { /> + {cippApiRoleSelected && ( + + This role will limit access for the CIPP-API integration. It is not + intended to be used for users. + + )}
    Allowed Tenants
    @@ -263,8 +291,13 @@ const SettingsCustomRoles = () => { values={selectedTenant} AllTenants={true} valueIsDomain={true} - onChange={(e) => setSelectedTenant(e)} + onChange={(e) => handleTenantChange(e)} /> + {allTenantSelected && ( + + All tenants selected, no tenant restrictions will be applied. + + )}
    API Permissions
    From 7a12be5d5da6375d686d5d516037dbf2d1b34bc6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 00:08:27 -0400 Subject: [PATCH 024/115] Update SettingsCustomRoles.jsx --- src/views/cipp/app-settings/components/SettingsCustomRoles.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index ff0b888eed72..75c0a7504487 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -108,7 +108,7 @@ const SettingsCustomRoles = () => { let customRole = customRoleList.filter(function (obj) { return obj.RowKey === value.value }) - if (customRole[0].RowKey === 'CIPP-API') { + if (customRole[0]?.RowKey === 'CIPP-API') { setCippApiRoleSelected(true) } else { setCippApiRoleSelected(false) From 9f62c0ae203bbc350d3e3b365e42b6a4a40fad2f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 30 May 2024 13:07:45 +0200 Subject: [PATCH 025/115] new extension config page --- src/_nav.jsx | 5 + src/data/Extensions.json | 12 +- src/importsMap.jsx | 1 + src/routes.json | 6 + src/views/cipp/Extensions.jsx | 173 +++++ .../SettingsExtensionMappings.jsx | 621 +++++++++--------- .../cipp/app-settings/SettingsExtensions.jsx | 16 +- 7 files changed, 513 insertions(+), 321 deletions(-) create mode 100644 src/views/cipp/Extensions.jsx diff --git a/src/_nav.jsx b/src/_nav.jsx index 902a8390b79f..81175e8886f0 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -771,6 +771,11 @@ const _nav = [ name: 'Application Settings', to: '/cipp/settings', }, + { + component: CNavItem, + name: 'Extensions Settings', + to: '/cipp/extensions', + }, { component: CNavItem, name: 'User Settings', diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 0f26e93f26a5..98a5c9a5a3f2 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -16,7 +16,8 @@ "name": "cippapi.Enabled", "label": "Enable Integration" } - ] + ], + "mappingRequired": false }, { "name": "Gradient Integration", @@ -49,7 +50,8 @@ "name": "Gradient.Enabled", "label": "Enable Integration" } - ] + ], + "mappingRequired": false }, { "name": "Halo PSA Ticketing Integration", @@ -105,7 +107,8 @@ "name": "HaloPSA.Enabled", "label": "Enable Integration" } - ] + ], + "mappingRequired": true }, { "name": "NinjaOne Integration", @@ -155,6 +158,7 @@ "name": "NinjaOne.Enabled", "label": "Enable Integration" } - ] + ], + "mappingRequired": true } ] diff --git a/src/importsMap.jsx b/src/importsMap.jsx index fd44014ae9c7..a9dd3c4843d9 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -129,6 +129,7 @@ import React from 'react' "/security/reports/list-device-compliance": React.lazy(() => import('./views/security/reports/ListDeviceComplianceReport')), "/license": React.lazy(() => import('./views/pages/license/License')), "/cipp/settings": React.lazy(() => import('./views/cipp/app-settings/CIPPSettings')), + "/cipp/extensions": React.lazy(() => import('./views/cipp/Extensions')), "/cipp/setup": React.lazy(() => import('./views/cipp/Setup')), "/tenant/administration/securescore": React.lazy(() => import('./views/tenant/administration/SecureScore')), "/tenant/administration/gdap": React.lazy(() => import('./views/tenant/administration/GDAPWizard')), diff --git a/src/routes.json b/src/routes.json index e681555e0346..26c0ed1b027f 100644 --- a/src/routes.json +++ b/src/routes.json @@ -888,6 +888,12 @@ "component": "views/cipp/app-settings/CIPPSettings", "allowedRoles": ["admin"] }, + { + "path": "/cipp/extensions", + "name": "Extensions Settings", + "component": "views/cipp/Extensions", + "allowedRoles": ["admin"] + }, { "path": "/cipp/setup", "name": "Setup", diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx new file mode 100644 index 000000000000..d42e79d9bb38 --- /dev/null +++ b/src/views/cipp/Extensions.jsx @@ -0,0 +1,173 @@ +import React, { useRef, useState } from 'react' +import { + CButton, + CCardText, + CCol, + CForm, + CNav, + CNavItem, + CRow, + CTabContent, + CTabPane, +} from '@coreui/react' +import { CippPage } from 'src/components/layout' +import { CippLazy } from 'src/components/utilities' +import { useNavigate } from 'react-router-dom' +import useQuery from 'src/hooks/useQuery.jsx' +import Extensions from 'src/data/Extensions.json' +import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app.js' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' +import CippButtonCard from 'src/components/contentcards/CippButtonCard.jsx' +import { RFFCFormInput, RFFCFormSwitch } from 'src/components/forms/RFFComponents.jsx' +import { Form } from 'react-final-form' +import { SettingsExtensionMappings } from './app-settings/SettingsExtensionMappings' + +export default function CIPPExtensions() { + const [listBackend, listBackendResult] = useLazyGenericGetRequestQuery() + const inputRef = useRef(null) + const [setExtensionconfig, extensionConfigResult] = useLazyGenericPostRequestQuery() + const [execTestExtension, listExtensionTestResult] = useLazyGenericGetRequestQuery() + const [execSyncExtension, listSyncExtensionResult] = useLazyGenericGetRequestQuery() + + const onSubmitTest = (integrationName) => { + execTestExtension({ + path: 'api/ExecExtensionTest?extensionName=' + integrationName, + }) + } + const onSubmit = (values) => { + setExtensionconfig({ + path: 'api/ExecExtensionsConfig', + values: values, + }) + } + + const ButtonGenerate = (integrationType, forceSync) => ( + <> + + {extensionConfigResult.isFetching && ( + + )} + Set Extension Settings + + onSubmitTest(integrationType)} className="me-2"> + {listExtensionTestResult.isFetching && ( + + )} + Test Extension + + {forceSync && ( + + execSyncExtension({ + path: 'api/ExecExtensionSync?Extension=' + integrationType, + }) + } + className="me-2" + > + {listSyncExtensionResult.isFetching && ( + + )} + Force Sync + + )} + + ) + const queryString = useQuery() + const navigate = useNavigate() + + const tab = queryString.get('tab') + const [active, setActiveTab] = useState(tab ? parseInt(tab) : 0) + const setActive = (tab) => { + setActiveTab(tab) + queryString.set('tab', tab.toString()) + navigate(`${location.pathname}?${queryString}`) + } + + return ( + + {listBackendResult.isUninitialized && listBackend({ path: 'api/ListExtensionsConfig' })} + + {Extensions.map((integration, idx) => ( + setActive(idx)} + href="#" + > + {integration.name} + + ))} + + + {Extensions.map((integration, idx) => ( + + + + + +

    {integration.helpText}

    + { + return ( + + + + {integration.SettingOptions.map( + (integrationOptions, idx) => + integrationOptions.type === 'input' && ( + + + + ), + )} + {integration.SettingOptions.map( + (integrationOptions, idx) => + integrationOptions.type === 'checkbox' && ( + + + + ), + )} + + + + + ) + }} + /> +
    +
    + + + +
    +
    +
    + ))} +
    +
    + ) +} diff --git a/src/views/cipp/app-settings/SettingsExtensionMappings.jsx b/src/views/cipp/app-settings/SettingsExtensionMappings.jsx index 33d7491795bf..6d7a63d2a3d0 100644 --- a/src/views/cipp/app-settings/SettingsExtensionMappings.jsx +++ b/src/views/cipp/app-settings/SettingsExtensionMappings.jsx @@ -19,13 +19,14 @@ import { CippCallout } from 'src/components/layout/index.js' import CippAccordionItem from 'src/components/contentcards/CippAccordionItem' import { CippTable } from 'src/components/tables' import { CellTip } from 'src/components/tables/CellGenericFormat' +import CippButtonCard from 'src/components/contentcards/CippButtonCard' /** * Retrieves and sets the extension mappings for HaloPSA and NinjaOne. * * @returns {JSX.Element} - JSX component representing the settings extension mappings. */ -export function SettingsExtensionMappings() { +export function SettingsExtensionMappings({ type }) { const [addedAttributes, setAddedAttribute] = React.useState(1) const [mappingArray, setMappingArray] = React.useState('defaultMapping') const [mappingValue, setMappingValue] = React.useState({}) @@ -242,310 +243,326 @@ export function SettingsExtensionMappings() { return ( - {listBackendHaloResult.isUninitialized && - listHaloBackend({ path: 'api/ExecExtensionMapping?List=Halo' })} - {listBackendNinjaOrgsResult.isUninitialized && - listNinjaOrgsBackend({ path: 'api/ExecExtensionMapping?List=NinjaOrgs' })} - {listBackendNinjaFieldsResult.isUninitialized && - listNinjaFieldsBackend({ path: 'api/ExecExtensionMapping?List=NinjaFields' })} - - - - {extensionHaloConfigResult.isFetching && ( - - )} - Save Mappings - - onHaloAutomap()} className="me-2"> - {extensionNinjaOrgsAutomapResult.isFetching && ( - - )} - Automap HaloPSA Clients - - - } - > - {listBackendHaloResult.isFetching && listBackendHaloResult.isUninitialized ? ( - - ) : ( - { - return ( - - - Use the table below to map your client to the correct PSA client. - { - //load all the existing mappings and show them first in a table. - listBackendHaloResult.isSuccess && ( - - ) - } - - - { - return !Object.keys(listBackendHaloResult.data?.Mappings).includes( - tenant.customerId, - ) - }).map((tenant) => ({ - name: tenant.displayName, - value: tenant.customerId, - }))} - onChange={(e) => { - setMappingArray(e.value) + {type === 'HaloPSA' && ( + <> + {listBackendHaloResult.isUninitialized && + listHaloBackend({ path: 'api/ExecExtensionMapping?List=Halo' })} + + + + {extensionHaloConfigResult.isFetching && ( + + )} + Save Mappings + + onHaloAutomap()} className="me-2"> + {extensionNinjaOrgsAutomapResult.isFetching && ( + + )} + Automap HaloPSA Clients + + + } + > + {listBackendHaloResult.isFetching && listBackendHaloResult.isUninitialized ? ( + + ) : ( + { + return ( + + + Use the table below to map your client to the correct PSA client. + { + //load all the existing mappings and show them first in a table. + listBackendHaloResult.isSuccess && ( + + ) + } + + + { + return !Object.keys(listBackendHaloResult.data?.Mappings).includes( + tenant.customerId, + ) + }).map((tenant) => ({ + name: tenant.displayName, + value: tenant.customerId, + }))} + onChange={(e) => { + setMappingArray(e.value) + }} + isLoading={listBackendHaloResult.isFetching} + /> + + + + + + { + return !Object.values(listBackendHaloResult.data?.Mappings) + .map((value) => { + return value.value + }) + .includes(client.value) + }).map((client) => ({ + name: client.name, + value: client.value, + }))} + onChange={(e) => setMappingValue(e)} + placeholder="Select a HaloPSA Client" + isLoading={listBackendHaloResult.isFetching} + /> + + { + if ( + mappingValue.value !== undefined && + mappingValue.value !== '-1' && + Object.values(haloMappingsArray) + .map((item) => item.haloId) + .includes(mappingValue.value) === false + ) { + //set the new mapping in the array + setHaloMappingsArray([ + ...haloMappingsArray, + { + Tenant: listBackendHaloResult.data?.Tenants.find( + (tenant) => tenant.customerId === mappingArray, + ), + haloName: mappingValue.label, + haloId: mappingValue.value, + }, + ]) + } }} - isLoading={listBackendHaloResult.isFetching} - /> - - - - - - { - return !Object.values(listBackendHaloResult.data?.Mappings) - .map((value) => { - return value.value - }) - .includes(client.value) - }).map((client) => ({ - name: client.name, - value: client.value, - }))} - onChange={(e) => setMappingValue(e)} - placeholder="Select a HaloPSA Client" - isLoading={listBackendHaloResult.isFetching} - /> - - { - if ( - mappingValue.value !== undefined && - mappingValue.value !== '-1' && - Object.values(haloMappingsArray) - .map((item) => item.haloId) - .includes(mappingValue.value) === false - ) { - //set the new mapping in the array - setHaloMappingsArray([ - ...haloMappingsArray, - { - Tenant: listBackendHaloResult.data?.Tenants.find( - (tenant) => tenant.customerId === mappingArray, - ), - haloName: mappingValue.label, - haloId: mappingValue.value, - }, - ]) - } - }} - className={`my-4 circular-button`} - title={'+'} - > - - - - - - {HaloAutoMap && ( - - Automapping has been executed. Remember to check the changes and save - them. - - )} - {(extensionHaloConfigResult.isSuccess || extensionHaloConfigResult.isError) && - !extensionHaloConfigResult.isFetching && ( - - {extensionHaloConfigResult.isSuccess - ? extensionHaloConfigResult.data.Results - : 'Error'} - + + + + + + {HaloAutoMap && ( + + Automapping has been executed. Remember to check the changes and save + them. + )} - - - - After editing the mappings you must click Save Mappings for the changes to - take effect. The table will be saved exactly as presented. - - - ) - }} - /> - )} - - - - {extensionNinjaOrgsConfigResult.isFetching && ( - - )} - Set Mappings - - onNinjaOrgsAutomap()} className="me-2"> - {extensionNinjaOrgsAutomapResult.isFetching && ( - - )} - Automap NinjaOne Organizations - - - } - > - {listBackendNinjaOrgsResult.isFetching && listBackendNinjaOrgsResult.isUninitialized ? ( - - ) : ( - { - return ( - - - Use the table below to map your client to the correct NinjaOne Organization. - { - //load all the existing mappings and show them first in a table. - listBackendNinjaOrgsResult.isSuccess && ( - - ) - } - - - { - return !Object.keys( - listBackendNinjaOrgsResult.data?.Mappings, - ).includes(tenant.customerId) - }).map((tenant) => ({ - name: tenant.displayName, - value: tenant.customerId, - }))} - onChange={(e) => { - setMappingArray(e.value) - }} - isLoading={listBackendNinjaOrgsResult.isFetching} - /> - - - - - - { - return !Object.values(listBackendNinjaOrgsResult.data?.Mappings) - .map((value) => { - return value.value - }) - .includes(client.value.toString()) - }).map((client) => ({ - name: client.name, - value: client.value, - }))} - onChange={(e) => setMappingValue(e)} - placeholder="Select a NinjaOne Organization" - isLoading={listBackendNinjaOrgsResult.isFetching} - /> - - { - //set the new mapping in the array - if ( - mappingValue.value !== undefined && - mappingValue.value !== '-1' && - Object.values(ninjaMappingsArray) - .map((item) => item.ninjaId) - .includes(mappingValue.value) === false - ) { - setNinjaMappingsArray([ - ...ninjaMappingsArray, - { - Tenant: listBackendNinjaOrgsResult.data?.Tenants.find( - (tenant) => tenant.customerId === mappingArray, - ), - ninjaName: mappingValue.label, - ninjaId: mappingValue.value, + {(extensionHaloConfigResult.isSuccess || + extensionHaloConfigResult.isError) && + !extensionHaloConfigResult.isFetching && ( + + {extensionHaloConfigResult.isSuccess + ? extensionHaloConfigResult.data.Results + : 'Error'} + + )} +
    + + + After editing the mappings you must click Save Mappings for the changes to + take effect. The table will be saved exactly as presented. + + + ) + }} + /> + )} + + + )} + {type === 'NinjaOne' && ( + <> + {listBackendNinjaOrgsResult.isUninitialized && + listNinjaOrgsBackend({ path: 'api/ExecExtensionMapping?List=NinjaOrgs' })} + {listBackendNinjaFieldsResult.isUninitialized && + listNinjaFieldsBackend({ path: 'api/ExecExtensionMapping?List=NinjaFields' })} + + + {extensionNinjaOrgsConfigResult.isFetching && ( + + )} + Set Mappings + + onNinjaOrgsAutomap()} className="me-2"> + {extensionNinjaOrgsAutomapResult.isFetching && ( + + )} + Automap NinjaOne Organizations + + + } + > + {listBackendNinjaOrgsResult.isFetching && listBackendNinjaOrgsResult.isUninitialized ? ( + + ) : ( + { + return ( + + + Use the table below to map your client to the correct NinjaOne Organization. + { + //load all the existing mappings and show them first in a table. + listBackendNinjaOrgsResult.isSuccess && ( + + ) + } + + + { + return !Object.keys( + listBackendNinjaOrgsResult.data?.Mappings, + ).includes(tenant.customerId) + }).map((tenant) => ({ + name: tenant.displayName, + value: tenant.customerId, + }))} + onChange={(e) => { + setMappingArray(e.value) + }} + isLoading={listBackendNinjaOrgsResult.isFetching} + /> + + + + + + { + return !Object.values(listBackendNinjaOrgsResult.data?.Mappings) + .map((value) => { + return value.value + }) + .includes(client.value.toString()) }, - ]) - } - }} - className={`my-4 circular-button`} - title={'+'} - > - - - - - - {(extensionNinjaOrgsAutomapResult.isSuccess || - extensionNinjaOrgsAutomapResult.isError) && - !extensionNinjaOrgsAutomapResult.isFetching && ( - - {extensionNinjaOrgsAutomapResult.isSuccess - ? extensionNinjaOrgsAutomapResult.data.Results - : 'Error'} - - )} - {(extensionNinjaOrgsConfigResult.isSuccess || - extensionNinjaOrgsConfigResult.isError) && - !extensionNinjaOrgsConfigResult.isFetching && ( - ({ + name: client.name, + value: client.value, + }))} + onChange={(e) => setMappingValue(e)} + placeholder="Select a NinjaOne Organization" + isLoading={listBackendNinjaOrgsResult.isFetching} + /> + + { + //set the new mapping in the array + if ( + mappingValue.value !== undefined && + mappingValue.value !== '-1' && + Object.values(ninjaMappingsArray) + .map((item) => item.ninjaId) + .includes(mappingValue.value) === false + ) { + setNinjaMappingsArray([ + ...ninjaMappingsArray, + { + Tenant: listBackendNinjaOrgsResult.data?.Tenants.find( + (tenant) => tenant.customerId === mappingArray, + ), + ninjaName: mappingValue.label, + ninjaId: mappingValue.value, + }, + ]) + } + }} + className={`my-4 circular-button`} + title={'+'} > - {extensionNinjaOrgsConfigResult.isSuccess - ? extensionNinjaOrgsConfigResult.data.Results - : 'Error'} - - )} -
    - - - After editing the mappings you must click Save Mappings for the changes to - take effect. The table will be saved exactly as presented. - - - ) - }} - /> - )} - - + + + + + {(extensionNinjaOrgsAutomapResult.isSuccess || + extensionNinjaOrgsAutomapResult.isError) && + !extensionNinjaOrgsAutomapResult.isFetching && ( + + {extensionNinjaOrgsAutomapResult.isSuccess + ? extensionNinjaOrgsAutomapResult.data.Results + : 'Error'} + + )} + {(extensionNinjaOrgsConfigResult.isSuccess || + extensionNinjaOrgsConfigResult.isError) && + !extensionNinjaOrgsConfigResult.isFetching && ( + + {extensionNinjaOrgsConfigResult.isSuccess + ? extensionNinjaOrgsConfigResult.data.Results + : 'Error'} + + )} + + + + After editing the mappings you must click Save Mappings for the changes to + take effect. The table will be saved exactly as presented. + + + ) + }} + /> + )} + + + )} + {type === 'NinjaOne' && ( + )} - - + + )} ) } diff --git a/src/views/cipp/app-settings/SettingsExtensions.jsx b/src/views/cipp/app-settings/SettingsExtensions.jsx index 20ebbcee9725..ab686d2c1df9 100644 --- a/src/views/cipp/app-settings/SettingsExtensions.jsx +++ b/src/views/cipp/app-settings/SettingsExtensions.jsx @@ -1,20 +1,6 @@ import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app.js' import React, { useRef } from 'react' -import { - CAccordion, - CAlert, - CButton, - CCallout, - CCard, - CCardBody, - CCardHeader, - CCardText, - CCardTitle, - CCol, - CForm, - CRow, - CSpinner, -} from '@coreui/react' +import { CAccordion, CButton, CCardText, CCol, CForm, CSpinner } from '@coreui/react' import Extensions from 'src/data/Extensions.json' import { Form } from 'react-final-form' import { RFFCFormInput, RFFCFormSwitch } from 'src/components/forms/index.js' From 40d54d669db2a636a84c93a64fd2a238c9b757bf Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 30 May 2024 15:56:09 +0200 Subject: [PATCH 026/115] remove old extensions --- src/views/cipp/app-settings/CIPPSettings.jsx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/views/cipp/app-settings/CIPPSettings.jsx b/src/views/cipp/app-settings/CIPPSettings.jsx index 965e1f98f11f..c7e7a227f75e 100644 --- a/src/views/cipp/app-settings/CIPPSettings.jsx +++ b/src/views/cipp/app-settings/CIPPSettings.jsx @@ -58,12 +58,6 @@ export default function CIPPSettings() { setActive(7)} href="#"> Maintenance - setActive(8)} href="#"> - Extensions - - setActive(9)} href="#"> - Extension Mappings - {superAdmin && ( setActive(10)} href="#"> SuperAdmin Settings @@ -104,16 +98,6 @@ export default function CIPPSettings() { - - - - - - - - - - From 15dcc67217176aeab87ab07d45bbccd6ba527a5f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 10:00:54 -0400 Subject: [PATCH 027/115] JIT admin route/nav --- src/_nav.jsx | 5 +++++ src/importsMap.jsx | 1 + src/routes.json | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/src/_nav.jsx b/src/_nav.jsx index 81175e8886f0..04fa3f3866a1 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -75,6 +75,11 @@ const _nav = [ name: 'Roles', to: '/identity/administration/roles', }, + { + component: CNavItem, + name: 'JIT Admin', + to: '/identity/administration/users/jit-admin', + }, { component: CNavItem, name: 'Offboarding Wizard', diff --git a/src/importsMap.jsx b/src/importsMap.jsx index a9dd3c4843d9..d42693788afb 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -12,6 +12,7 @@ import React from 'react' "/identity/administration/users/edit": React.lazy(() => import('./views/identity/administration/EditUser')), "/identity/administration/users/view": React.lazy(() => import('./views/identity/administration/ViewUser')), "/identity/administration/users/InviteGuest": React.lazy(() => import('./views/identity/administration/InviteGuest')), + "/identity/administration/users/jit-admin": React.lazy(() => import('./views/identity/administration/DeployJITAdmin')), "/identity/administration/ViewBec": React.lazy(() => import('./views/identity/administration/ViewBEC')), "/identity/administration/users": React.lazy(() => import('./views/identity/administration/Users')), "/identity/administration/devices": React.lazy(() => import('./views/identity/administration/Devices')), diff --git a/src/routes.json b/src/routes.json index 26c0ed1b027f..61c736f9c23d 100644 --- a/src/routes.json +++ b/src/routes.json @@ -76,6 +76,12 @@ "component": "views/identity/administration/InviteGuest", "allowedRoles": ["admin", "editor", "readonly"] }, + { + "path": "/identity/administration/users/jit-admin", + "name": "JIT Admin", + "component": "views/identity/administration/DeployJITAdmin", + "allowedRoles": ["admin", "editor", "readonly"] + }, { "path": "/identity/administration/ViewBec", "name": "View BEC", From c74cd41b543258011a13501e16d37cbd0dde2196 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 10:01:05 -0400 Subject: [PATCH 028/115] Remove extension tabs from settings --- src/views/cipp/app-settings/CIPPSettings.jsx | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/views/cipp/app-settings/CIPPSettings.jsx b/src/views/cipp/app-settings/CIPPSettings.jsx index 965e1f98f11f..14e5c3e0cb9e 100644 --- a/src/views/cipp/app-settings/CIPPSettings.jsx +++ b/src/views/cipp/app-settings/CIPPSettings.jsx @@ -58,14 +58,8 @@ export default function CIPPSettings() { setActive(7)} href="#"> Maintenance - setActive(8)} href="#"> - Extensions - - setActive(9)} href="#"> - Extension Mappings - {superAdmin && ( - setActive(10)} href="#"> + setActive(8)} href="#"> SuperAdmin Settings )} @@ -106,16 +100,6 @@ export default function CIPPSettings() { - - - - - - - - - - From a6c1f615152e68b6703378280575d71dcbd0b293 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 10:09:52 -0400 Subject: [PATCH 029/115] fix nav/route --- src/_nav.jsx | 2 +- src/routes.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_nav.jsx b/src/_nav.jsx index 04fa3f3866a1..ada800050fc5 100644 --- a/src/_nav.jsx +++ b/src/_nav.jsx @@ -78,7 +78,7 @@ const _nav = [ { component: CNavItem, name: 'JIT Admin', - to: '/identity/administration/users/jit-admin', + to: '/identity/administration/jit-admin', }, { component: CNavItem, diff --git a/src/routes.json b/src/routes.json index 61c736f9c23d..f27aaa5b148e 100644 --- a/src/routes.json +++ b/src/routes.json @@ -77,7 +77,7 @@ "allowedRoles": ["admin", "editor", "readonly"] }, { - "path": "/identity/administration/users/jit-admin", + "path": "/identity/administration/jit-admin", "name": "JIT Admin", "component": "views/identity/administration/DeployJITAdmin", "allowedRoles": ["admin", "editor", "readonly"] From 7be941d0ab1eb5530e1270763ef69c44657c3c42 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 30 May 2024 18:40:12 +0200 Subject: [PATCH 030/115] fixes bpa if never run --- .../tenant/standards/BestPracticeAnalyser.jsx | 198 ++++++++++-------- 1 file changed, 107 insertions(+), 91 deletions(-) diff --git a/src/views/tenant/standards/BestPracticeAnalyser.jsx b/src/views/tenant/standards/BestPracticeAnalyser.jsx index 10e7c480c29f..801cd1eb6838 100644 --- a/src/views/tenant/standards/BestPracticeAnalyser.jsx +++ b/src/views/tenant/standards/BestPracticeAnalyser.jsx @@ -346,99 +346,115 @@ const BestPracticeAnalyser = () => { refreshFunction={setRefreshValue} /> - {graphrequest.data.Columns.map((info, idx) => ( - - - - {info.name} - - - - {info.formatter === 'bool' && ( - - - {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} - - )} - {info.formatter === 'reverseBool' && ( - - - {graphrequest.data.Data[0][info.value] ? 'No' : 'Yes'} - - )} - {info.formatter === 'warnBool' && ( - - - {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} - - )} + {graphrequest.data?.Data[0] && + Object.keys(graphrequest.data.Data[0]).length === 0 ? ( + + + Best Practice Report + + + + No Data Found for this tenant. Please refresh the tenant data. + + + + ) : ( + graphrequest.data.Columns.map((info, idx) => ( + + + + {info.name} + + + + {info.formatter === 'bool' && ( + + + {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} + + )} + {info.formatter === 'reverseBool' && ( + + + {graphrequest.data.Data[0][info.value] ? 'No' : 'Yes'} + + )} + {info.formatter === 'warnBool' && ( + + + {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} + + )} - {info.formatter === 'table' && ( - <> - - - )} + {info.formatter === 'table' && ( + <> + + + )} - {info.formatter === 'number' && ( -

    - {getNestedValue(graphrequest.data.Data[0], info.value)} -

    - )} -
    - - {info.desc} - -
    -
    -
    - ))} + {info.formatter === 'number' && ( +

    + {getNestedValue(graphrequest.data.Data[0], info.value)} +

    + )} +
    + + {info.desc} + +
    +
    +
    + )) + )} )} From 15986ade977c349ab744270d3249d682e24c6a35 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 20:46:39 -0400 Subject: [PATCH 031/115] Update ListAppliedStandards.jsx --- src/views/tenant/standards/ListAppliedStandards.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index 484ec3862a36..c48dd3705753 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -634,20 +634,13 @@ const ApplyNewStandard = () => {
    Remediate
    From c11dd30e4dd9d4030a7cacbfbbdddeaf74fefb13 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 May 2024 13:32:16 -0400 Subject: [PATCH 032/115] up version --- package.json | 2 +- public/version_latest.txt | 2 +- version_latest.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 332ac7504f6e..76ec78f43af2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "5.7.0", + "version": "5.7.1", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index 42cdd0b540f9..64ff7ded70d3 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -5.7.0 +5.7.1 diff --git a/version_latest.txt b/version_latest.txt index 42cdd0b540f9..64ff7ded70d3 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.0 +5.7.1 From 4c031850e805fd7aec6884c043508bfc442c2237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 19:55:53 +0200 Subject: [PATCH 033/115] Add CloudMessageRecall standard --- src/data/standards.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 3efbc09ea197..3278c5631af2 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -632,6 +632,32 @@ "impact": "Low Impact", "impactColour": "info" }, + { + "name": "standards.CloudMessageRecall", + "cat": "Exchange Standards", + "tag": ["lowimpact"], + "helpText": "Sets the Cloud Message Recall state for the tenant. This allows users to recall messages from the cloud.", + "addedComponent": [ + { + "type": "Select", + "label": "Select value", + "name": "standards.CloudMessageRecall.state", + "values": [ + { + "label": "Enabled", + "value": "true" + }, + { + "label": "Disabled", + "value": "false" + } + ] + } + ], + "label": "Set Cloud Message Recall state", + "impact": "Low Impact", + "impactColour": "info" + }, { "name": "standards.AutoExpandArchive", "cat": "Exchange Standards", From 457022f47e5bf33c54c464479a061351c3355568 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 28 May 2024 12:12:51 +0200 Subject: [PATCH 034/115] improvements to autopilot. --- .../endpoint/autopilot/AutopilotAddDevice.jsx | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/views/endpoint/autopilot/AutopilotAddDevice.jsx b/src/views/endpoint/autopilot/AutopilotAddDevice.jsx index 35abc7cc505f..b475e2712388 100644 --- a/src/views/endpoint/autopilot/AutopilotAddDevice.jsx +++ b/src/views/endpoint/autopilot/AutopilotAddDevice.jsx @@ -34,6 +34,28 @@ Error.propTypes = { const AddAPDevice = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() const [autopilotData, setAutopilotdata] = useState([]) + const completeColumns = [ + { + name: 'Serial Number', + selector: (row) => row['serialNumber'], + sortable: true, + }, + { + name: 'Status', + selector: (row) => row['status'], + sortable: true, + }, + { + name: 'Error Code', + selector: (row) => row['errorCode'], + sortable: true, + }, + { + name: 'Error Description', + selector: (row) => row['errorDescription'], + sortable: true, + }, + ] const tableColumns = [ { name: 'serialNumber', @@ -267,8 +289,18 @@ const AddAPDevice = () => { Loading )} - {postResults.isSuccess && {postResults.data.Results}} - {autopilotData && ( + {postResults.isSuccess && ( + <> + {postResults.data?.Results?.Status} + + + )} + {autopilotData && !postResults.isSuccess && ( Date: Thu, 30 May 2024 18:40:12 +0200 Subject: [PATCH 035/115] fixes bpa if never run --- .../tenant/standards/BestPracticeAnalyser.jsx | 198 ++++++++++-------- 1 file changed, 107 insertions(+), 91 deletions(-) diff --git a/src/views/tenant/standards/BestPracticeAnalyser.jsx b/src/views/tenant/standards/BestPracticeAnalyser.jsx index 10e7c480c29f..801cd1eb6838 100644 --- a/src/views/tenant/standards/BestPracticeAnalyser.jsx +++ b/src/views/tenant/standards/BestPracticeAnalyser.jsx @@ -346,99 +346,115 @@ const BestPracticeAnalyser = () => { refreshFunction={setRefreshValue} /> - {graphrequest.data.Columns.map((info, idx) => ( - - - - {info.name} - - - - {info.formatter === 'bool' && ( - - - {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} - - )} - {info.formatter === 'reverseBool' && ( - - - {graphrequest.data.Data[0][info.value] ? 'No' : 'Yes'} - - )} - {info.formatter === 'warnBool' && ( - - - {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} - - )} + {graphrequest.data?.Data[0] && + Object.keys(graphrequest.data.Data[0]).length === 0 ? ( + + + Best Practice Report + + + + No Data Found for this tenant. Please refresh the tenant data. + + + + ) : ( + graphrequest.data.Columns.map((info, idx) => ( + + + + {info.name} + + + + {info.formatter === 'bool' && ( + + + {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} + + )} + {info.formatter === 'reverseBool' && ( + + + {graphrequest.data.Data[0][info.value] ? 'No' : 'Yes'} + + )} + {info.formatter === 'warnBool' && ( + + + {graphrequest.data.Data[0][info.value] ? 'Yes' : 'No'} + + )} - {info.formatter === 'table' && ( - <> - - - )} + {info.formatter === 'table' && ( + <> + + + )} - {info.formatter === 'number' && ( -

    - {getNestedValue(graphrequest.data.Data[0], info.value)} -

    - )} -
    - - {info.desc} - -
    -
    -
    - ))} + {info.formatter === 'number' && ( +

    + {getNestedValue(graphrequest.data.Data[0], info.value)} +

    + )} +
    + + {info.desc} + +
    +
    +
    + )) + )} )} From 472d523038ec66e2d290ae779089994e39037fc4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 20:42:32 +0200 Subject: [PATCH 036/115] fixes errormessages not showing up --- src/views/cipp/app-settings/SettingsGeneral.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index 04446add8ceb..346f1ac3fe53 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,7 +253,7 @@ export function SettingsGeneral() { - {permissionsResult.data.Results?.ErrorMessages?.length > 0 || + {permissionsResult.data.Results?.ErrorMessages?.length >= 0 || (permissionsResult.data.Results?.MissingPermissions.length > 0 && ( <> From 01dc70a15eae4250304f5c6c70fb43c3a59cdb5b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 21:07:59 +0200 Subject: [PATCH 037/115] update settings --- src/views/cipp/app-settings/SettingsGeneral.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index 346f1ac3fe53..bb0d16b4946b 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,7 +253,7 @@ export function SettingsGeneral() { - {permissionsResult.data.Results?.ErrorMessages?.length >= 0 || + {permissionsResult.data.Results?.ErrorMessages?.length || (permissionsResult.data.Results?.MissingPermissions.length > 0 && ( <> From 8da455d400c247574ee2d7df69c6043af953d4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 21:13:47 +0200 Subject: [PATCH 038/115] Add TeamsMeetingsByDefault standard --- src/data/standards.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 3efbc09ea197..e1cb16aadaf7 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -696,6 +696,32 @@ "impact": "Low Impact", "impactColour": "info" }, + { + "name": "standards.TeamsMeetingsByDefault", + "cat": "Exchange Standards", + "tag": ["lowimpact"], + "helpText": "Sets the default state for automatically turning meetings into Teams meetings for the tenant. This can be overridden by the user in Outlook.", + "addedComponent": [ + { + "type": "Select", + "label": "Select value", + "name": "standards.TeamsMeetingsByDefault.state", + "values": [ + { + "label": "Enabled", + "value": "true" + }, + { + "label": "Disabled", + "value": "false" + } + ] + } + ], + "label": "Set Teams Meetings by default state", + "impact": "Low Impact", + "impactColour": "info" + }, { "name": "standards.DisableViva", "cat": "Exchange Standards", From 180f176fe6f1e55692de09a044973d88aaf71ad2 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 21:20:03 +0200 Subject: [PATCH 039/115] permissions fix --- .../cipp/app-settings/SettingsGeneral.jsx | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index bb0d16b4946b..fc5472998bc8 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,37 +253,37 @@ export function SettingsGeneral() { - {permissionsResult.data.Results?.ErrorMessages?.length || - (permissionsResult.data.Results?.MissingPermissions.length > 0 && ( - + {(permissionsResult.data.Results?.ErrorMessages?.length >= 0 || + permissionsResult.data.Results?.MissingPermissions.length > 0) && ( + + <> + {permissionsResult.data.Results?.ErrorMessages?.map((m, idx) => ( +
    {m}
    + ))} + + {permissionsResult.data.Results?.MissingPermissions.length > 0 && ( <> - {permissionsResult.data.Results?.ErrorMessages?.map((m, idx) => ( -
    {m}
    - ))} + Your Secure Application Model is missing the following permissions. See + the documentation on how to add permissions{' '} + + here + + . + + {permissionsResult.data.Results?.MissingPermissions?.map( + (r, index) => ( + {r} + ), + )} + - {permissionsResult.data.Results?.MissingPermissions.length > 0 && ( - <> - Your Secure Application Model is missing the following permissions. - See the documentation on how to add permissions{' '} - - here - - . - - {permissionsResult.data.Results?.MissingPermissions?.map( - (r, index) => ( - {r} - ), - )} - - - )} -
    - ))} + )} +
    + )}
    From 900c00705b2d58c5935a08ea0425464f5c5e3d3f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 21:29:22 +0200 Subject: [PATCH 040/115] fixed --- src/views/cipp/app-settings/SettingsGeneral.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index fc5472998bc8..b5dd40624064 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,7 +253,7 @@ export function SettingsGeneral() { - {(permissionsResult.data.Results?.ErrorMessages?.length >= 0 || + {(permissionsResult.data.Results?.ErrorMessages?.length > 0 || permissionsResult.data.Results?.MissingPermissions.length > 0) && ( <> From e7738cfc584b366a5fc6950539058315adf0c382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 21:32:03 +0200 Subject: [PATCH 041/115] Add bookings standard --- src/data/standards.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 3efbc09ea197..a626c9692567 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -872,6 +872,32 @@ "impact": "Medium Impact", "impactColour": "warning" }, + { + "name": "standards.Bookings", + "cat": "Exchange Standards", + "tag": ["mediumimpact"], + "helpText": "Sets the state of Bookings on the tenant. Bookings is a scheduling tool that allows users to book appointments with others both internal and external.", + "addedComponent": [ + { + "type": "Select", + "label": "Select value", + "name": "standards.Bookings.state", + "values": [ + { + "label": "Enabled", + "value": "true" + }, + { + "label": "Disabled", + "value": "false" + } + ] + } + ], + "label": "Set Bookings state", + "impact": "Medium Impact", + "impactColour": "warning" + }, { "name": "standards.DisableOutlookAddins", "cat": "Exchange Standards", From 881232f959f82333ffd333f11c28b2df17134217 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 20:42:32 +0200 Subject: [PATCH 042/115] fixes errormessages not showing up --- src/views/cipp/app-settings/SettingsGeneral.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index 04446add8ceb..346f1ac3fe53 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,7 +253,7 @@ export function SettingsGeneral() { - {permissionsResult.data.Results?.ErrorMessages?.length > 0 || + {permissionsResult.data.Results?.ErrorMessages?.length >= 0 || (permissionsResult.data.Results?.MissingPermissions.length > 0 && ( <> From 808fbe59e9f29ab630fa1613cd87c5a8c8aeaeb5 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 21:07:59 +0200 Subject: [PATCH 043/115] update settings --- src/views/cipp/app-settings/SettingsGeneral.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index 346f1ac3fe53..bb0d16b4946b 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,7 +253,7 @@ export function SettingsGeneral() { - {permissionsResult.data.Results?.ErrorMessages?.length >= 0 || + {permissionsResult.data.Results?.ErrorMessages?.length || (permissionsResult.data.Results?.MissingPermissions.length > 0 && ( <> From af3accaa2a7e38954154b7f6162768d481b5b71d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 21:20:03 +0200 Subject: [PATCH 044/115] permissions fix --- .../cipp/app-settings/SettingsGeneral.jsx | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index bb0d16b4946b..fc5472998bc8 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,37 +253,37 @@ export function SettingsGeneral() { - {permissionsResult.data.Results?.ErrorMessages?.length || - (permissionsResult.data.Results?.MissingPermissions.length > 0 && ( - + {(permissionsResult.data.Results?.ErrorMessages?.length >= 0 || + permissionsResult.data.Results?.MissingPermissions.length > 0) && ( + + <> + {permissionsResult.data.Results?.ErrorMessages?.map((m, idx) => ( +
    {m}
    + ))} + + {permissionsResult.data.Results?.MissingPermissions.length > 0 && ( <> - {permissionsResult.data.Results?.ErrorMessages?.map((m, idx) => ( -
    {m}
    - ))} + Your Secure Application Model is missing the following permissions. See + the documentation on how to add permissions{' '} + + here + + . + + {permissionsResult.data.Results?.MissingPermissions?.map( + (r, index) => ( + {r} + ), + )} + - {permissionsResult.data.Results?.MissingPermissions.length > 0 && ( - <> - Your Secure Application Model is missing the following permissions. - See the documentation on how to add permissions{' '} - - here - - . - - {permissionsResult.data.Results?.MissingPermissions?.map( - (r, index) => ( - {r} - ), - )} - - - )} -
    - ))} + )} +
    + )}
    From 22e0be1c2aab72382f5b201d3f5db6937168c2ea Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 31 May 2024 21:29:22 +0200 Subject: [PATCH 045/115] fixed --- src/views/cipp/app-settings/SettingsGeneral.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/cipp/app-settings/SettingsGeneral.jsx b/src/views/cipp/app-settings/SettingsGeneral.jsx index fc5472998bc8..b5dd40624064 100644 --- a/src/views/cipp/app-settings/SettingsGeneral.jsx +++ b/src/views/cipp/app-settings/SettingsGeneral.jsx @@ -253,7 +253,7 @@ export function SettingsGeneral() { - {(permissionsResult.data.Results?.ErrorMessages?.length >= 0 || + {(permissionsResult.data.Results?.ErrorMessages?.length > 0 || permissionsResult.data.Results?.MissingPermissions.length > 0) && ( <> From ffdc7444b6bed4a1fba68fd2ed587c9f94917533 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 2 Jun 2024 12:54:01 -0400 Subject: [PATCH 046/115] Fix JIT route --- src/importsMap.jsx | 2 +- .../administration/DeployJITAdmin.jsx | 20 ++++--------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/importsMap.jsx b/src/importsMap.jsx index d42693788afb..b50612327848 100644 --- a/src/importsMap.jsx +++ b/src/importsMap.jsx @@ -12,7 +12,7 @@ import React from 'react' "/identity/administration/users/edit": React.lazy(() => import('./views/identity/administration/EditUser')), "/identity/administration/users/view": React.lazy(() => import('./views/identity/administration/ViewUser')), "/identity/administration/users/InviteGuest": React.lazy(() => import('./views/identity/administration/InviteGuest')), - "/identity/administration/users/jit-admin": React.lazy(() => import('./views/identity/administration/DeployJITAdmin')), + "/identity/administration/jit-admin": React.lazy(() => import('./views/identity/administration/DeployJITAdmin')), "/identity/administration/ViewBec": React.lazy(() => import('./views/identity/administration/ViewBEC')), "/identity/administration/users": React.lazy(() => import('./views/identity/administration/Users')), "/identity/administration/devices": React.lazy(() => import('./views/identity/administration/Devices')), diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index 126150f95360..0bd5af20df75 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -1,31 +1,19 @@ import React, { useState } from 'react' import { CButton, CCallout, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react' import { useSelector } from 'react-redux' -import { Field, Form, FormSpy } from 'react-final-form' -import { - Condition, - RFFCFormInput, - RFFCFormRadio, - RFFCFormRadioList, - RFFCFormSwitch, - RFFSelectSearch, -} from 'src/components/forms' -import { - useGenericGetRequestQuery, - useLazyGenericGetRequestQuery, - useLazyGenericPostRequestQuery, -} from 'src/store/api/app' +import { Field, Form } from 'react-final-form' +import { Condition, RFFCFormInput, RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms' +import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faCircleNotch, faEdit, faEye } from '@fortawesome/free-solid-svg-icons' import { CippContentCard, CippPage, CippPageList } from 'src/components/layout' import { CellTip } from 'src/components/tables/CellGenericFormat' import 'react-datepicker/dist/react-datepicker.css' -import { CippActionsOffcanvas, ModalService, TenantSelector } from 'src/components/utilities' +import { TenantSelector } from 'src/components/utilities' import arrayMutators from 'final-form-arrays' import DatePicker from 'react-datepicker' import 'react-datepicker/dist/react-datepicker.css' import { useListUsersQuery } from 'src/store/api/users' -import { useListConditionalAccessPoliciesQuery } from 'src/store/api/tenants' import GDAPRoles from 'src/data/GDAPRoles' const DeployJITAdmin = () => { From 5ede28816b0d8b0fd3a266ed9c47b740224179b4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 13:06:12 -0400 Subject: [PATCH 047/115] JIT Admin --- package.json | 2 +- public/version_latest.txt | 2 +- .../administration/DeployJITAdmin.jsx | 70 ++++++++++++++++--- version_latest.txt | 2 +- 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 332ac7504f6e..76ec78f43af2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "5.7.0", + "version": "5.7.1", "description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version_latest.txt b/public/version_latest.txt index 42cdd0b540f9..64ff7ded70d3 100644 --- a/public/version_latest.txt +++ b/public/version_latest.txt @@ -1 +1 @@ -5.7.0 +5.7.1 diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index 0bd5af20df75..40a5f88c4a9e 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -7,7 +7,7 @@ import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 's import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faCircleNotch, faEdit, faEye } from '@fortawesome/free-solid-svg-icons' import { CippContentCard, CippPage, CippPageList } from 'src/components/layout' -import { CellTip } from 'src/components/tables/CellGenericFormat' +import { CellTip, cellGenericFormatter } from 'src/components/tables/CellGenericFormat' import 'react-datepicker/dist/react-datepicker.css' import { TenantSelector } from 'src/components/utilities' import arrayMutators from 'final-form-arrays' @@ -15,6 +15,7 @@ import DatePicker from 'react-datepicker' import 'react-datepicker/dist/react-datepicker.css' import { useListUsersQuery } from 'src/store/api/users' import GDAPRoles from 'src/data/GDAPRoles' +import { CippDatatable, cellDateFormatter } from 'src/components/tables' const DeployJITAdmin = () => { const [ExecuteGetRequest, getResults] = useLazyGenericGetRequestQuery() @@ -30,12 +31,13 @@ const DeployJITAdmin = () => { const startTime = Math.floor(startDate.getTime() / 1000) const endTime = Math.floor(endDate.getTime() / 1000) const shippedValues = { - tenantFilter: tenantDomain, + TenantFilter: tenantDomain, UserId: values.UserId?.value, - PolicyId: values.PolicyId?.value, + useraction: values.useraction, + AdminRoles: values.AdminRoles?.map((role) => role.value), StartDate: startTime, EndDate: endTime, - ExpireAction: values?.expireAction ?? 'delete', + ExpireAction: values.expireAction.value, } genericPostRequest({ path: '/api/ExecJITAdmin', values: shippedValues }).then((res) => { setRefreshState(res.requestId) @@ -51,8 +53,8 @@ const DeployJITAdmin = () => { return ( <> - - + + { - {(props) => } + + {(props) => } + @@ -90,7 +94,17 @@ const DeployJITAdmin = () => { - + + + + + + + + + + + @@ -112,6 +126,7 @@ const DeployJITAdmin = () => { +
    { /> + + + row['userPrincipalName'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'userPrincipalName', + }, + { + name: 'JIT Enabled', + selector: (row) => row['jitAdminEnabled'], + sortable: true, + cell: cellGenericFormatter(), + exportSelector: 'jitAdminEnabled', + }, + { + name: 'JIT Expires', + selector: (row) => row['jitAdminExpiration'], + sortable: true, + cell: cellDateFormatter({ format: 'short' }), + exportSelector: 'jitAdminExpiration', + }, + { + name: 'Admin Roles', + selector: (row) => row['memberOf'], + sortable: false, + cell: cellGenericFormatter(), + exportSelector: 'memberOf', + }, + ]} + /> + +
    diff --git a/version_latest.txt b/version_latest.txt index 42cdd0b540f9..64ff7ded70d3 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.0 +5.7.1 From b542489ecae0e53f3bf904ed2fe466f3c86c5885 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 15:18:08 -0400 Subject: [PATCH 048/115] Update JIT actions --- src/views/identity/administration/DeployJITAdmin.jsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index 40a5f88c4a9e..aad2244ba34f 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -172,9 +172,9 @@ const DeployJITAdmin = () => { { {postResults.isSuccess && ( -
  • {postResults.data.Results}
  • + {postResults.data?.Results.map((result, idx) => ( +
  • {result}
  • + ))}
    )} {getResults.isFetching && ( From c889ed1dacaf33aa1ac45307dac57b403630eb4f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 20:39:20 -0400 Subject: [PATCH 049/115] Update DeployJITAdmin.jsx --- .../administration/DeployJITAdmin.jsx | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/views/identity/administration/DeployJITAdmin.jsx b/src/views/identity/administration/DeployJITAdmin.jsx index aad2244ba34f..b87ca67dd8f3 100644 --- a/src/views/identity/administration/DeployJITAdmin.jsx +++ b/src/views/identity/administration/DeployJITAdmin.jsx @@ -2,7 +2,13 @@ import React, { useState } from 'react' import { CButton, CCallout, CCol, CForm, CRow, CSpinner, CTooltip } from '@coreui/react' import { useSelector } from 'react-redux' import { Field, Form } from 'react-final-form' -import { Condition, RFFCFormInput, RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms' +import { + Condition, + RFFCFormInput, + RFFCFormRadioList, + RFFCFormSwitch, + RFFSelectSearch, +} from 'src/components/forms' import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faCircleNotch, faEdit, faEye } from '@fortawesome/free-solid-svg-icons' @@ -33,11 +39,19 @@ const DeployJITAdmin = () => { const shippedValues = { TenantFilter: tenantDomain, UserId: values.UserId?.value, + UserPrincipalName: values.UserPrincipalName, + FirstName: values.FirstName, + LastName: values.LastName, useraction: values.useraction, AdminRoles: values.AdminRoles?.map((role) => role.value), StartDate: startTime, EndDate: endTime, ExpireAction: values.expireAction.value, + PostExecution: { + Webhook: values.webhook, + Email: values.email, + PSA: values.psa, + }, } genericPostRequest({ path: '/api/ExecJITAdmin', values: shippedValues }).then((res) => { setRefreshState(res.requestId) @@ -181,6 +195,14 @@ const DeployJITAdmin = () => { />
    + + + + + + + + @@ -227,7 +249,7 @@ const DeployJITAdmin = () => { Date: Wed, 5 Jun 2024 11:48:23 +0200 Subject: [PATCH 050/115] Added more Anti-Phishing actions --- src/data/standards.json | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index d1b9e020ded7..2f9cbb7465c1 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1102,6 +1102,44 @@ "name": "standards.AntiPhishPolicy.EnableUnusualCharactersSafetyTips", "default": true }, + { + "type": "Select", + "label": "If a message is detected as user impersonation", + "name": "standards.AntiPhishPolicy.TargetedUserProtectionAction", + "values": [ + { + "label": "Move to Junk Folder", + "value": "MoveToJmf" + }, + { + "label": "Delete the message before its delivered", + "value": "Delete" + }, + { + "label": "Quarantine the message", + "value": "Quarantine" + } + ] + }, + { + "type": "Select", + "label": "If a message is detected as domain impersonation", + "name": "standards.AntiPhishPolicy.TargetedDomainProtectionAction", + "values": [ + { + "label": "Move to Junk Folder", + "value": "MoveToJmf" + }, + { + "label": "Delete the message before its delivered", + "value": "Delete" + }, + { + "label": "Quarantine the message", + "value": "Quarantine" + } + ] + }, { "type": "Select", "label": "If Mailbox Intelligence detects an impersonated user", From 651de591942fb4a4dedac1e340a3db4ca8c2d27c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 09:00:47 -0400 Subject: [PATCH 051/115] Tenant block list --- .../components/SettingsCustomRoles.jsx | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index 75c0a7504487..32e2ef9d6511 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -13,20 +13,20 @@ import { import { Field, Form, FormSpy } from 'react-final-form' import { RFFCFormRadioList, RFFSelectSearch } from 'src/components/forms' import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' -import { CippPage } from 'src/components/layout' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import Skeleton from 'react-loading-skeleton' import { TenantSelectorMultiple, ModalService, CippOffcanvas } from 'src/components/utilities' import PropTypes from 'prop-types' import { OnChange } from 'react-final-form-listeners' import { useListTenantsQuery } from 'src/store/api/tenants' -import CippListOffcanvas, { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas' +import { OffcanvasListSection } from 'src/components/utilities/CippListOffcanvas' import CippButtonCard from 'src/components/contentcards/CippButtonCard' const SettingsCustomRoles = () => { const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() const [selectedTenant, setSelectedTenant] = useState([]) + const [blockedTenants, setBlockedTenants] = useState([]) const tenantSelectorRef = useRef() + const blockedTenantSelectorRef = useRef() const { data: tenants = [], tenantsFetching } = useListTenantsQuery({ showAllTenantSelector: true, }) @@ -57,13 +57,21 @@ const SettingsCustomRoles = () => { alltenant = true } }) - if (alltenant) { + if (alltenant && blockedTenants.length === 0) { setAllTenantSelected(true) } else { setAllTenantSelected(false) } setSelectedTenant(e) } + + const handleBlockedTenantChange = (e) => { + setBlockedTenants(e) + if (e.length > 0) { + setAllTenantSelected(false) + } + } + const handleSubmit = async (values) => { //filter on only objects that are 'true' genericPostRequest({ @@ -72,6 +80,7 @@ const SettingsCustomRoles = () => { RoleName: values.RoleName.value, Permissions: values.Permissions, AllowedTenants: selectedTenant.map((tenant) => tenant.value), + BlockedTenants: blockedTenants.map((tenant) => tenant.value), }, }).then(() => { refetchCustomRoleList() @@ -130,6 +139,19 @@ const SettingsCustomRoles = () => { }) tenantSelectorRef.current.setValue(selectedTenants) + } else if (set === 'BlockedTenants') { + setBlockedTenants(customRole[0][set]) + var blockedTenants = [] + tenants.map((tenant) => { + if (customRole[0][set].includes(tenant.customerId)) { + blockedTenants.push({ + label: tenant.displayName, + value: tenant.customerId, + }) + } + }) + + blockedTenantSelectorRef.current.setValue(blockedTenants) } else { onChange(customRole[0][set]) } @@ -277,6 +299,7 @@ const SettingsCustomRoles = () => { /> + {cippApiRoleSelected && ( This role will limit access for the CIPP-API integration. It is not @@ -299,6 +322,18 @@ const SettingsCustomRoles = () => { )} + {selectedTenant.find((tenant) => tenant.value === 'AllTenants') && ( +
    +
    Blocked Tenants
    + handleBlockedTenantChange(e)} + /> +
    + )}
    API Permissions
    @@ -366,7 +401,7 @@ const SettingsCustomRoles = () => { <> {values['RoleName'] && selectedTenant.length > 0 && ( <> -
    Selected Tenants
    +
    Allowed Tenants
      {selectedTenant.map((tenant, idx) => (
    • {tenant.label}
    • @@ -374,6 +409,16 @@ const SettingsCustomRoles = () => {
    )} + {values['RoleName'] && blockedTenants.length > 0 && ( + <> +
    Blocked Tenants
    +
      + {blockedTenants.map((tenant, idx) => ( +
    • {tenant.label}
    • + ))} +
    + + )} {values['RoleName'] && values['Permissions'] && ( <>
    Selected Permissions
    From af8202c6118e2c99ad18c05f820b6104e45b6f37 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 09:15:32 -0400 Subject: [PATCH 052/115] Add sort --- .../components/SettingsCustomRoles.jsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index 32e2ef9d6511..f9d0bac3b359 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -424,13 +424,15 @@ const SettingsCustomRoles = () => {
    Selected Permissions
      {values['Permissions'] && - Object.keys(values['Permissions'])?.map((cat, idx) => ( - <> - {!values['Permissions'][cat].includes('None') && ( -
    • {values['Permissions'][cat]}
    • - )} - - ))} + Object.keys(values['Permissions']) + ?.sort() + .map((cat, idx) => ( + <> + {!values['Permissions'][cat].includes('None') && ( +
    • {values['Permissions'][cat]}
    • + )} + + ))}
    )} From 8b359388a022ef04616e1b4e5921e6127b15b6d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 5 Jun 2024 15:23:58 +0200 Subject: [PATCH 053/115] Add Pronouns standard --- src/data/standards.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index d1b9e020ded7..ed45971bc7fe 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -121,6 +121,16 @@ "impact": "Low Impact", "impactColour": "info" }, + { + "name": "standards.EnablePronouns", + "cat": "Global Standards", + "tag": ["lowimpact"], + "helpText": "Enables the Pronouns feature for the tenant. This allows users to set their pronouns in their profile.", + "addedComponent": [], + "label": "Enable Pronouns", + "impact": "Low Impact", + "impactColour": "info" + }, { "name": "standards.AnonReportDisable", "cat": "Global Standards", From 8a979de71eefa7af04c061d35a09a3752bc8244e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 09:50:34 -0400 Subject: [PATCH 054/115] Update SettingsCustomRoles.jsx --- .../components/SettingsCustomRoles.jsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index f9d0bac3b359..1d7d08426946 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -128,30 +128,31 @@ const SettingsCustomRoles = () => { } else { if (set === 'AllowedTenants') { setSelectedTenant(customRole[0][set]) - var selectedTenants = [] + var selectedTenantList = [] tenants.map((tenant) => { if (customRole[0][set].includes(tenant.customerId)) { - selectedTenants.push({ + selectedTenantList.push({ label: tenant.displayName, value: tenant.customerId, }) } }) - tenantSelectorRef.current.setValue(selectedTenants) + tenantSelectorRef.current.setValue(selectedTenantList) } else if (set === 'BlockedTenants') { setBlockedTenants(customRole[0][set]) - var blockedTenants = [] + var blockedTenantList = [] tenants.map((tenant) => { if (customRole[0][set].includes(tenant.customerId)) { - blockedTenants.push({ + blockedTenantList.push({ label: tenant.displayName, value: tenant.customerId, }) } }) - - blockedTenantSelectorRef.current.setValue(blockedTenants) + if (blockedTenantSelectorRef?.current) { + blockedTenantSelectorRef.current.setValue(blockedTenantList) + } } else { onChange(customRole[0][set]) } From e742061e21a8138f6a1720732b5213bb743467f4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 10:42:38 -0400 Subject: [PATCH 055/115] Add input list for string[] values --- src/components/forms/RFFComponents.jsx | 48 ++++++++++++++++++++++++++ src/components/forms/index.js | 2 ++ src/views/cipp/Scheduler.jsx | 39 +++++++++++++++------ 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/components/forms/RFFComponents.jsx b/src/components/forms/RFFComponents.jsx index b72a840d4989..292187a957db 100644 --- a/src/components/forms/RFFComponents.jsx +++ b/src/components/forms/RFFComponents.jsx @@ -253,6 +253,54 @@ RFFCFormInputArray.propTypes = { ...sharedPropTypes, } +export const RFFCFormInputList = ({ name, label, className = 'mb-3' }) => { + return ( + <> + + {({ fields }) => ( +
    +
    + {label && ( + + {label} + + )} + fields.push({ Key: '', Value: '' })} + className="circular-button" + title={'+'} + > + + +
    + {fields.map((name, index) => ( +
    +
    + + {({ input, meta }) => { + return + }} + +
    + fields.remove(index)} + className={`circular-button`} + title={'-'} + > + + +
    + ))} +
    + )} +
    + + ) +} +RFFCFormInputList.propTypes = { + ...sharedPropTypes, +} + export const RFFCFormRadio = ({ name, label, diff --git a/src/components/forms/index.js b/src/components/forms/index.js index 00a76ee4554a..aa36929d58da 100644 --- a/src/components/forms/index.js +++ b/src/components/forms/index.js @@ -10,6 +10,7 @@ import { RFFCFormSelect, RFFSelectSearch, RFFCFormInputArray, + RFFCFormInputList, } from 'src/components/forms/RFFComponents' export { @@ -24,4 +25,5 @@ export { RFFCFormSelect, RFFSelectSearch, RFFCFormInputArray, + RFFCFormInputList, } diff --git a/src/views/cipp/Scheduler.jsx b/src/views/cipp/Scheduler.jsx index 7ffed5837fe0..e0fd1aea974a 100644 --- a/src/views/cipp/Scheduler.jsx +++ b/src/views/cipp/Scheduler.jsx @@ -5,6 +5,7 @@ import { Field, Form, FormSpy } from 'react-final-form' import { RFFCFormInput, RFFCFormInputArray, + RFFCFormInputList, RFFCFormSwitch, RFFSelectSearch, } from 'src/components/forms' @@ -157,10 +158,14 @@ const Scheduler = () => { if (typeof row?.Parameters[key] === 'object') { var nestedParamList = [] Object.keys(row?.Parameters[key]).forEach((nestedKey) => { - nestedParamList.push({ - Key: nestedKey, - Value: row?.Parameters[key][nestedKey], - }) + if (nestedKey >= 0) { + nestedParamList.push(row?.Parameters[key][nestedKey]) + } else { + nestedParamList.push({ + Key: nestedKey, + Value: row?.Parameters[key][nestedKey], + }) + } }) parameters[key] = nestedParamList } else { @@ -179,6 +184,10 @@ const Scheduler = () => { }) }) + if (!recurrence) { + recurrence = { name: 'Only once', value: '0' } + } + // Set initial values var formValues = { taskName: row.Name, @@ -413,12 +422,22 @@ const Scheduler = () => { key={idx} /> ) : ( - + <> + {param.Type === 'System.String[]' ? ( + + ) : ( + + )} + )} )} From 665aafeae8e42eb5cdf7e987523cb226bcfeb6f7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 11:08:15 -0400 Subject: [PATCH 056/115] Update SettingsCustomRoles.jsx --- .../components/SettingsCustomRoles.jsx | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx index 1d7d08426946..5799c900323f 100644 --- a/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx +++ b/src/views/cipp/app-settings/components/SettingsCustomRoles.jsx @@ -150,9 +150,8 @@ const SettingsCustomRoles = () => { }) } }) - if (blockedTenantSelectorRef?.current) { - blockedTenantSelectorRef.current.setValue(blockedTenantList) - } + + blockedTenantSelectorRef.current.setValue(blockedTenantList) } else { onChange(customRole[0][set]) } @@ -323,18 +322,17 @@ const SettingsCustomRoles = () => { )} - {selectedTenant.find((tenant) => tenant.value === 'AllTenants') && ( -
    -
    Blocked Tenants
    - handleBlockedTenantChange(e)} - /> -
    - )} +
    +
    Blocked Tenants
    + handleBlockedTenantChange(e)} + /> +
    +
    API Permissions
    From 95ee2846f855aac5a30669e26361a84539cc0614 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 17:28:50 -0400 Subject: [PATCH 057/115] Extension tweaks --- src/data/Extensions.json | 60 ++++++++++++++++++++ src/views/cipp/Extensions.jsx | 26 ++++++++- src/views/cipp/app-settings/CIPPSettings.jsx | 2 - 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 98a5c9a5a3f2..e67d9784fae2 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -160,5 +160,65 @@ } ], "mappingRequired": true + }, + { + "name": "PasswordPusher", + "type": "PWPush", + "cat": "Passwords", + "forceSyncButton": false, + "helpText": "This integration allows you to generate password links instead of plain text passwords. Visit https://pwpush.com/ or https://github.com/pglombardo/PasswordPusher for more information.", + "SettingOptions": [ + { + "type": "checkbox", + "name": "PWPush.Enabled", + "label": "Replace generated passwords with PWPush links" + }, + { + "type": "input", + "fieldtype": "text", + "name": "PWPush.BaseUrl", + "label": "PWPush URL", + "placeholder": "Enter your PWPush URL. (default: https://pwpush.com)" + }, + { + "type": "input", + "fieldtype": "text", + "name": "PWPush.EmailAddress", + "label": "PWPush email address", + "placeholder": "Enter your email address for PWPush. (optional)" + }, + { + "type": "input", + "fieldtype": "password", + "name": "PWPush.ApiKey", + "label": "PWPush API Key", + "placeholder": "Enter your PWPush API Key. (optional)" + }, + { + "type": "checkbox", + "name": "PWPush.RetrievalStep", + "label": "Click to retrieve password (recommended)" + }, + { + "type": "input", + "fieldtype": "number", + "name": "PWPush.ExpireAfterDays", + "label": "Expiration in Days", + "placeholder": "Expiration time in days. (optional)" + }, + { + "type": "input", + "fieldtype": "number", + "name": "PWPush.ExpireAfterViews", + "label": "Expiration after views", + "placeholder": "Expiration after views. (optional)" + }, + { + "type": "checkbox", + "name": "PWPush.DeletableByViewer", + "label": "Allow deletion of passwords" + } + ], + "mappingRequired": false } ] diff --git a/src/views/cipp/Extensions.jsx b/src/views/cipp/Extensions.jsx index d42e79d9bb38..7bfe1d7feb86 100644 --- a/src/views/cipp/Extensions.jsx +++ b/src/views/cipp/Extensions.jsx @@ -10,7 +10,7 @@ import { CTabContent, CTabPane, } from '@coreui/react' -import { CippPage } from 'src/components/layout' +import { CippCallout, CippPage } from 'src/components/layout' import { CippLazy } from 'src/components/utilities' import { useNavigate } from 'react-router-dom' import useQuery from 'src/hooks/useQuery.jsx' @@ -104,7 +104,7 @@ export default function CIPPExtensions() { - + + {extensionConfigResult?.data?.Results && ( + + {extensionConfigResult?.data?.Results} + + )} + {listExtensionTestResult?.data?.Results && ( + + {listExtensionTestResult?.data?.Results} + {listExtensionTestResult?.data?.Link && ( + + Link + + )} + + )} - + diff --git a/src/views/cipp/app-settings/CIPPSettings.jsx b/src/views/cipp/app-settings/CIPPSettings.jsx index 14e5c3e0cb9e..5a610170e49b 100644 --- a/src/views/cipp/app-settings/CIPPSettings.jsx +++ b/src/views/cipp/app-settings/CIPPSettings.jsx @@ -8,9 +8,7 @@ import { SettingsTenants } from 'src/views/cipp/app-settings/SettingsTenants.jsx import { SettingsBackend } from 'src/views/cipp/app-settings/SettingsBackend.jsx' import { SettingsNotifications } from 'src/views/cipp/app-settings/SettingsNotifications.jsx' import { SettingsLicenses } from 'src/views/cipp/app-settings/SettingsLicenses.jsx' -import { SettingsExtensions } from 'src/views/cipp/app-settings/SettingsExtensions.jsx' import { SettingsMaintenance } from 'src/views/cipp/app-settings/SettingsMaintenance.jsx' -import { SettingsExtensionMappings } from 'src/views/cipp/app-settings/SettingsExtensionMappings.jsx' import { SettingsPartner } from 'src/views/cipp/app-settings/SettingsPartner.jsx' import useQuery from 'src/hooks/useQuery.jsx' import { SettingsSuperAdmin } from './SettingsSuperAdmin.jsx' From 362493072207d64c8e88a7022e451cefb8a5e460 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 17:46:46 -0400 Subject: [PATCH 058/115] Update Extensions.json --- src/data/Extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/Extensions.json b/src/data/Extensions.json index e67d9784fae2..1ca3a87b94d7 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -190,7 +190,7 @@ { "type": "input", "fieldtype": "password", - "name": "PWPush.ApiKey", + "name": "PWPush.APIKey", "label": "PWPush API Key", "placeholder": "Enter your PWPush API Key. (optional)" }, From 8e0710d8be42c7f8bee7a3814f30951116949c17 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 15:35:37 +0200 Subject: [PATCH 059/115] fixes bug with rffcomponents and input --- src/components/forms/RFFComponents.jsx | 111 +++++++------------------ 1 file changed, 30 insertions(+), 81 deletions(-) diff --git a/src/components/forms/RFFComponents.jsx b/src/components/forms/RFFComponents.jsx index 292187a957db..b2a0f5472619 100644 --- a/src/components/forms/RFFComponents.jsx +++ b/src/components/forms/RFFComponents.jsx @@ -511,10 +511,10 @@ export const RFFSelectSearch = ({ isLoading = false, allowCreate = false, refreshFunction, - props, + ...props }) => { const [inputText, setInputText] = useState('') - const selectSearchvalues = values.map((val) => ({ + const selectSearchValues = values.map((val) => ({ value: val.value, label: val.name, ...val.props, @@ -538,12 +538,30 @@ export const RFFSelectSearch = ({ return ( {({ meta, input }) => { - const handleChange = onChange - ? (e) => { - input.onChange(e) - onChange(e) - } - : input.onChange + const handleChange = (e) => { + if (onChange) { + onChange(e) + } + input.onChange(e) + } + + const selectProps = { + className: 'react-select-container', + classNamePrefix: 'react-select', + ...input, + name, + id: name, + disabled, + options: selectSearchValues, + placeholder, + isMulti: multi, + inputValue: inputText, + isLoading, + onChange: handleChange, + onInputChange: setOnInputChange, + ...props, + } + return (
    @@ -561,79 +579,10 @@ export const RFFSelectSearch = ({ )} - {!allowCreate && onChange && ( - - )} - {allowCreate && onChange && ( - - )} - {allowCreate && !onChange && ( - + {allowCreate ? ( + + ) : ( +