From 5799b41728514d5cff253af6721ca000c0a0151d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 15 Apr 2024 16:33:29 +0200 Subject: [PATCH 01/11] remove blank items from favourites. --- src/views/cipp/UserSettings.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/cipp/UserSettings.jsx b/src/views/cipp/UserSettings.jsx index 955101c02921..8a4081b8c29b 100644 --- a/src/views/cipp/UserSettings.jsx +++ b/src/views/cipp/UserSettings.jsx @@ -216,6 +216,8 @@ const UserSettings = () => { multi={true} values={_nav .reduce((acc, val) => acc.concat(val.items), []) + //only map if 'name' property is not null + .filter((item) => item?.name) .map((item) => // console.log(item), ({ From 128d98b4080c4cf8d1f6f63f448a0f0d409e9b82 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 15 Apr 2024 16:59:55 +0200 Subject: [PATCH 02/11] add tab browsing --- src/views/cipp/app-settings/CIPPSettings.jsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/views/cipp/app-settings/CIPPSettings.jsx b/src/views/cipp/app-settings/CIPPSettings.jsx index c1e6b9463fd7..6e45b3ba5780 100644 --- a/src/views/cipp/app-settings/CIPPSettings.jsx +++ b/src/views/cipp/app-settings/CIPPSettings.jsx @@ -2,7 +2,7 @@ import React, { useState } from 'react' import { CNav, CNavItem, CTabContent, CTabPane } from '@coreui/react' import { CippPage } from 'src/components/layout' import { CippLazy } from 'src/components/utilities' - +import { useNavigate } from 'react-router-dom' import { SettingsGeneral } from './SettingsGeneral.jsx' import { SettingsTenants } from 'src/views/cipp/app-settings/SettingsTenants.jsx' import { SettingsBackend } from 'src/views/cipp/app-settings/SettingsBackend.jsx' @@ -12,6 +12,7 @@ import { SettingsExtensions } from 'src/views/cipp/app-settings/SettingsExtensio 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' /** * This function returns the settings page content for CIPP. @@ -19,7 +20,18 @@ import { SettingsPartner } from 'src/views/cipp/app-settings/SettingsPartner.jsx * @returns {JSX.Element} The settings page content. */ export default function CIPPSettings() { - const [active, setActive] = useState(1) + const queryString = useQuery() + const navigate = useNavigate() + + const tab = queryString.get('tab') + const [active, setActiveTab] = useState(tab ? parseInt(tab) : 1) + + const setActive = (tab) => { + setActiveTab(tab) + queryString.set('tab', tab.toString()) + navigate(`${location.pathname}?${queryString}`) + } + return ( From d184d12388778631d5c3881614afe8442ef6bca8 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 15 Apr 2024 17:14:51 +0200 Subject: [PATCH 03/11] added refresh to list tenants. --- src/components/utilities/TenantSelector.jsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/utilities/TenantSelector.jsx b/src/components/utilities/TenantSelector.jsx index a7c059c39d4f..df8eb7d00459 100644 --- a/src/components/utilities/TenantSelector.jsx +++ b/src/components/utilities/TenantSelector.jsx @@ -13,6 +13,7 @@ import CippTenantOffcanvas from './CippTenantOffcanvas' import CippfuzzySearch from './CippFuzzySearch' const TenantSelector = ({ action, showAllTenantSelector = true, NavSelector = false }) => { + const [refreshState, setRefreshState] = React.useState(false) const currentTenant = useSelector((state) => state.app.currentTenant) const { data: tenants = [ @@ -23,9 +24,10 @@ const TenantSelector = ({ action, showAllTenantSelector = true, NavSelector = fa }, ], isLoading, + isFetching, isSuccess, error, - } = useListTenantsQuery({ showAllTenantSelector }) + } = useListTenantsQuery({ showAllTenantSelector, Refresh: refreshState }) const dispatch = useDispatch() const navigate = useNavigate() @@ -90,10 +92,10 @@ const TenantSelector = ({ action, showAllTenantSelector = true, NavSelector = fa )} -
+
+ + //set a random number to force a refresh + setRefreshState(Math.random()) + } + variant="ghost" + className="ml-2" + > + +
)} From 450858ff7a44c6a42ab7bb922e1f1646fb366b63 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 15 Apr 2024 17:28:43 +0200 Subject: [PATCH 04/11] fixes or/ands --- src/components/tables/CippTable.jsx | 74 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/components/tables/CippTable.jsx b/src/components/tables/CippTable.jsx index 510aaa3ec9f0..dbcde884e90d 100644 --- a/src/components/tables/CippTable.jsx +++ b/src/components/tables/CippTable.jsx @@ -277,47 +277,45 @@ export default function CippTable({ debounceSetGraphFilter(query) return data } else if (filterText.startsWith('Complex:')) { - // Split conditions by ';' and 'or', and trim spaces - const conditions = filterText + // Split conditions by ';' for AND + const conditionGroups = filterText .slice(9) - .split(/\s*or\s*|\s*;\s*/i) // Split by 'or' or ';', case insensitive, with optional spaces - .map((condition) => condition.trim()) + .split(/\s*;\s*/) + .map((group) => group.trim().split(/\s+or\s+/i)) // Split each group by 'or' for OR return data.filter((item) => { - // Check if any condition is met for the item - return conditions.some((condition) => { - const match = condition.match(/(\w+)\s*(eq|ne|like|notlike|gt|lt)\s*(.+)/) - - if (!match) return false - - let [property, operator, value] = match.slice(1) - value = escapeRegExp(value) // Escape special characters - - const actualKey = Object.keys(item).find( - (key) => key.toLowerCase() === property.toLowerCase(), - ) - - if (!actualKey) { - console.error(`FilterError: Property "${property}" not found.`) - return false - } - - switch (operator) { - case 'eq': - return String(item[actualKey]).toLowerCase() === value.toLowerCase() - case 'ne': - return String(item[actualKey]).toLowerCase() !== value.toLowerCase() - case 'like': - return String(item[actualKey]).toLowerCase().includes(value.toLowerCase()) - case 'notlike': - return !String(item[actualKey]).toLowerCase().includes(value.toLowerCase()) - case 'gt': - return parseFloat(item[actualKey]) > parseFloat(value) - case 'lt': - return parseFloat(item[actualKey]) < parseFloat(value) - default: - return false // Should not reach here normally - } + // Check if all condition groups are met for the item (AND logic) + return conditionGroups.every((conditions) => { + // Check if any condition within a group is met for the item (OR logic) + return conditions.some((condition) => { + const match = condition.match(/(\w+)\s*(eq|ne|like|notlike|gt|lt)\s*(.+)/) + if (!match) return false + let [property, operator, value] = match.slice(1) + value = escapeRegExp(value) // Escape special characters + const actualKey = Object.keys(item).find( + (key) => key.toLowerCase() === property.toLowerCase(), + ) + if (!actualKey) { + console.error(`FilterError: Property "${property}" not found.`) + return false + } + switch (operator) { + case 'eq': + return String(item[actualKey]).toLowerCase() === value.toLowerCase() + case 'ne': + return String(item[actualKey]).toLowerCase() !== value.toLowerCase() + case 'like': + return String(item[actualKey]).toLowerCase().includes(value.toLowerCase()) + case 'notlike': + return !String(item[actualKey]).toLowerCase().includes(value.toLowerCase()) + case 'gt': + return parseFloat(item[actualKey]) > parseFloat(value) + case 'lt': + return parseFloat(item[actualKey]) < parseFloat(value) + default: + return false // Should not reach here normally + } + }) }) }) } else { From f7bdf2d39f8a79b200653568c87d1d85560dbaf6 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 15 Apr 2024 23:18:59 +0200 Subject: [PATCH 05/11] fix bpa --- src/components/tables/CellTable.jsx | 1 - src/components/utilities/Toasts.jsx | 16 +++--- src/store/middleware/errorMiddleware.js | 2 +- .../tenant/standards/BestPracticeAnalyser.jsx | 50 +++++++++++++++---- 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/components/tables/CellTable.jsx b/src/components/tables/CellTable.jsx index 8c259bc06200..0fffd6da5637 100644 --- a/src/components/tables/CellTable.jsx +++ b/src/components/tables/CellTable.jsx @@ -39,7 +39,6 @@ export default function cellTable( const handleTable = ({ columnProp }) => { const QueryColumns = [] - const columns = Object.keys(columnProp[0]).map((key) => { QueryColumns.push({ name: key, diff --git a/src/components/utilities/Toasts.jsx b/src/components/utilities/Toasts.jsx index cfc6d99c3b4d..e06bc398d5c7 100644 --- a/src/components/utilities/Toasts.jsx +++ b/src/components/utilities/Toasts.jsx @@ -3,8 +3,9 @@ import PropTypes from 'prop-types' import { useDispatch, useSelector } from 'react-redux' import { CToast, CToastBody, CToaster, CToastHeader, CCollapse, CButton } from '@coreui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faExpandAlt, faCompressAlt, faTimes } from '@fortawesome/free-solid-svg-icons' +import { faTimes } from '@fortawesome/free-solid-svg-icons' import { closeToast } from 'src/store/features/toasts' +import ReactTimeAgo from 'react-time-ago' const Toasts = () => { const dispatch = useDispatch() @@ -32,15 +33,18 @@ const Toast = ({ message, title, onClose, error }) => { return ( - -
{title}
- + +
{title}
+ Just Now +
+ +
diff --git a/src/store/middleware/errorMiddleware.js b/src/store/middleware/errorMiddleware.js index d09c48915ff3..14e868882709 100644 --- a/src/store/middleware/errorMiddleware.js +++ b/src/store/middleware/errorMiddleware.js @@ -39,7 +39,7 @@ export const errorMiddleware = dispatch( showToast({ - title: 'An Error Has Occurred', + title: 'An error has occurred', message: message, toastError, }), diff --git a/src/views/tenant/standards/BestPracticeAnalyser.jsx b/src/views/tenant/standards/BestPracticeAnalyser.jsx index 3c94d28db3fd..10e7c480c29f 100644 --- a/src/views/tenant/standards/BestPracticeAnalyser.jsx +++ b/src/views/tenant/standards/BestPracticeAnalyser.jsx @@ -164,7 +164,17 @@ const BestPracticeAnalyser = () => { }, ], } - + const normalizeTableData = (value) => { + if (Array.isArray(value)) { + return value + } else if (value === null) { + return null + } else if (typeof value === 'object') { + return [value] + } else { + return value + } + } if (graphrequest.isSuccess) { if (graphrequest.data.length === 0) { graphrequest.data = [{ data: 'No Data Found' }] @@ -384,14 +394,36 @@ const BestPracticeAnalyser = () => { )} {info.formatter === 'table' && ( - + <> + + )} {info.formatter === 'number' && ( From bb6c7bd0f9e42eef79c6b391fb6e038a19c2ff5d Mon Sep 17 00:00:00 2001 From: Woody Date: Mon, 15 Apr 2024 21:30:56 -0400 Subject: [PATCH 06/11] Added Tenant ID to Tenant Information Offcanvas --- src/components/utilities/CippTenantOffcanvas.jsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/utilities/CippTenantOffcanvas.jsx b/src/components/utilities/CippTenantOffcanvas.jsx index 0538ecbf4344..dc9310d7aa81 100644 --- a/src/components/utilities/CippTenantOffcanvas.jsx +++ b/src/components/utilities/CippTenantOffcanvas.jsx @@ -58,6 +58,10 @@ function CippTenantOffcanvas({ tenant, buildingIcon = false }) { label: 'Display Name', value: tenantProperty(tenantDetails, 'displayName'), }, + { + label: 'Tenant ID', + value: tenantProperty(tenantDetails, 'id'), + }, { label: 'Business Phones', value: tenantProperty(tenantDetails, 'businessPhones'), From eeee870f0e262b9ae9557405d5346bc88f948afd Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 16 Apr 2024 20:33:26 +0200 Subject: [PATCH 07/11] add superadmin compare --- src/hooks/useRouteNavCompare.jsx | 43 ++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/hooks/useRouteNavCompare.jsx b/src/hooks/useRouteNavCompare.jsx index 27fc1f9a3a14..7d122ef5d927 100644 --- a/src/hooks/useRouteNavCompare.jsx +++ b/src/hooks/useRouteNavCompare.jsx @@ -6,28 +6,33 @@ import routes from 'src/routes' export const useRouteNavCompare = (navigation) => { const dispatch = useDispatch() const { data: profile, isFetching } = useLoadClientPrincipalQuery() + if (isFetching) { return { isLoading: true, component: null } } + dispatch(updateAccessToken(profile)) - let roles = profile?.clientPrincipal?.userRoles || [] - let newNavigation = navigation.map((nav) => { - if (nav.items) { - nav.items = nav.items.filter((item) => { - const route = routes.find((r) => r.path === item.to) - if ( - !route || - (route.allowedRoles && route.allowedRoles.some((role) => roles.includes(role))) - ) { - return true - } else { - //console.log('Removing route', item) - return false - } - }) - } - return nav - }) + const roles = profile?.clientPrincipal?.userRoles || [] + + if (roles.includes('superadmin')) { + // For 'superadmin', simplify to Dashboard and /cipp/ routes directly so people don't work under this account. + return navigation.filter((nav) => nav.to === '/home' || nav.to?.startsWith('/cipp')) + } - return newNavigation + // For other roles, use existing filtering logic + return navigation + .map((nav) => { + if (nav.items) { + nav.items = nav.items.filter((item) => { + const route = routes.find((r) => r.path === item.to) + return ( + route && + (!route.allowedRoles || route.allowedRoles.some((role) => roles.includes(role))) + ) + }) + return nav + } + return nav + }) + .filter((nav) => nav.items && nav.items.length > 0) // Remove empty navigation groups } From 894c017c0b819258416e91848294be943535d361 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 16 Apr 2024 22:05:19 +0200 Subject: [PATCH 08/11] added easier way of setting up multitenant/partner/singletenant mode. --- src/hooks/useRouteNavCompare.jsx | 43 +++---- src/views/cipp/app-settings/CIPPSettings.jsx | 16 ++- .../cipp/app-settings/SettingsSuperAdmin.jsx | 113 ++++++++++++++++++ 3 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 src/views/cipp/app-settings/SettingsSuperAdmin.jsx diff --git a/src/hooks/useRouteNavCompare.jsx b/src/hooks/useRouteNavCompare.jsx index 7d122ef5d927..27fc1f9a3a14 100644 --- a/src/hooks/useRouteNavCompare.jsx +++ b/src/hooks/useRouteNavCompare.jsx @@ -6,33 +6,28 @@ import routes from 'src/routes' export const useRouteNavCompare = (navigation) => { const dispatch = useDispatch() const { data: profile, isFetching } = useLoadClientPrincipalQuery() - if (isFetching) { return { isLoading: true, component: null } } - dispatch(updateAccessToken(profile)) - const roles = profile?.clientPrincipal?.userRoles || [] - - if (roles.includes('superadmin')) { - // For 'superadmin', simplify to Dashboard and /cipp/ routes directly so people don't work under this account. - return navigation.filter((nav) => nav.to === '/home' || nav.to?.startsWith('/cipp')) - } + let roles = profile?.clientPrincipal?.userRoles || [] + let newNavigation = navigation.map((nav) => { + if (nav.items) { + nav.items = nav.items.filter((item) => { + const route = routes.find((r) => r.path === item.to) + if ( + !route || + (route.allowedRoles && route.allowedRoles.some((role) => roles.includes(role))) + ) { + return true + } else { + //console.log('Removing route', item) + return false + } + }) + } + return nav + }) - // For other roles, use existing filtering logic - return navigation - .map((nav) => { - if (nav.items) { - nav.items = nav.items.filter((item) => { - const route = routes.find((r) => r.path === item.to) - return ( - route && - (!route.allowedRoles || route.allowedRoles.some((role) => roles.includes(role))) - ) - }) - return nav - } - return nav - }) - .filter((nav) => nav.items && nav.items.length > 0) // Remove empty navigation groups + return newNavigation } diff --git a/src/views/cipp/app-settings/CIPPSettings.jsx b/src/views/cipp/app-settings/CIPPSettings.jsx index 6e45b3ba5780..965e1f98f11f 100644 --- a/src/views/cipp/app-settings/CIPPSettings.jsx +++ b/src/views/cipp/app-settings/CIPPSettings.jsx @@ -13,6 +13,8 @@ import { SettingsMaintenance } from 'src/views/cipp/app-settings/SettingsMainten 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' +import { useLoadClientPrincipalQuery } from 'src/store/api/auth.js' /** * This function returns the settings page content for CIPP. @@ -25,13 +27,13 @@ export default function CIPPSettings() { const tab = queryString.get('tab') const [active, setActiveTab] = useState(tab ? parseInt(tab) : 1) - + const { data: profile, isFetching } = useLoadClientPrincipalQuery() const setActive = (tab) => { setActiveTab(tab) queryString.set('tab', tab.toString()) navigate(`${location.pathname}?${queryString}`) } - + const superAdmin = profile?.clientPrincipal?.userRoles?.includes('superadmin') return ( @@ -62,6 +64,11 @@ export default function CIPPSettings() { setActive(9)} href="#"> Extension Mappings + {superAdmin && ( + setActive(10)} href="#"> + SuperAdmin Settings + + )} @@ -107,6 +114,11 @@ export default function CIPPSettings() { + + + + + ) diff --git a/src/views/cipp/app-settings/SettingsSuperAdmin.jsx b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx new file mode 100644 index 000000000000..41d8332387a3 --- /dev/null +++ b/src/views/cipp/app-settings/SettingsSuperAdmin.jsx @@ -0,0 +1,113 @@ +import { useGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app.js' +import { + CButton, + CCallout, + CCard, + CCardBody, + CCardHeader, + 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' + +export function SettingsSuperAdmin() { + const partnerConfig = useGenericGetRequestQuery({ + path: '/api/ExecPartnerMode', + params: { Action: 'ListCurrent' }, + }) + + const [submitWebhook, webhookCreateResult] = useLazyGenericPostRequestQuery() + + const onSubmit = (values) => { + submitWebhook({ + path: '/api/ExecPartnerMode', + values: values, + }).then((res) => {}) + } + + return ( + + + + <> + <> +

Super Admin Configuration

+ + +

+ 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.isFetching ? ( + <> + + Saving... + + ) : ( + 'Save' + )} + + + + )} + /> + {webhookCreateResult.isSuccess && ( + + {webhookCreateResult?.data?.results} + + )} + + + + + + + ) +} From 1665004feec99e4bfbbc32de3354bc743f7742f2 Mon Sep 17 00:00:00 2001 From: greenchiip Date: Wed, 10 Apr 2024 12:36:38 +0200 Subject: [PATCH 09/11] New Sort function New Sort function --- src/components/utilities/index.js | 2 ++ .../utilities/validateAlphabeticalSort.jsx | 23 +++++++++++++++++++ src/views/endpoint/intune/MEMAddPolicy.jsx | 20 +++++++++++----- .../tenant/standards/ListAppliedStandards.jsx | 7 ++++-- 4 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 src/components/utilities/validateAlphabeticalSort.jsx diff --git a/src/components/utilities/index.js b/src/components/utilities/index.js index 11fc6a9581d5..24fed1e5aecb 100644 --- a/src/components/utilities/index.js +++ b/src/components/utilities/index.js @@ -18,6 +18,7 @@ import PageSizeSwitcher from 'src/components/utilities/PageSizeSwitcher' import Toasts from 'src/components/utilities/Toasts' import UsageLocation from 'src/components/utilities/UsageLocation' import CippTableOffcanvas from './CippTableOffcanvas' +import validateAlphabeticalSort from './validateAlphabeticalSort' export { CippActionsOffcanvas, @@ -43,4 +44,5 @@ export { PageSizeSwitcher, Toasts, UsageLocation, + validateAlphabeticalSort, } diff --git a/src/components/utilities/validateAlphabeticalSort.jsx b/src/components/utilities/validateAlphabeticalSort.jsx new file mode 100644 index 000000000000..ff19bc21023e --- /dev/null +++ b/src/components/utilities/validateAlphabeticalSort.jsx @@ -0,0 +1,23 @@ +export default function validateAlphabeticalSort(data, sortKeys) { + if (!sortKeys || sortKeys.length === 0) return data + try { + if (!data) return data + const newList = data.filter((element) => { + return sortKeys.every((key) => { + return (element) => element[key] != null && element[key] != undefined + }) + }) + return newList.sort((a, b) => { + try { + return sortKeys.reduce((acc, key) => { + if (acc !== 0) return acc + return (a[key] ?? '').toString().localeCompare(b[key] ?? '') + }, 0) + } catch (error) { + return 0 + } + }) + } catch (error) { + return data + } +} diff --git a/src/views/endpoint/intune/MEMAddPolicy.jsx b/src/views/endpoint/intune/MEMAddPolicy.jsx index 161b0134665f..0b1de079d1e0 100644 --- a/src/views/endpoint/intune/MEMAddPolicy.jsx +++ b/src/views/endpoint/intune/MEMAddPolicy.jsx @@ -2,9 +2,15 @@ import React, { useState } from 'react' import { CCol, CRow, CListGroup, CListGroupItem, CCallout, CSpinner } from '@coreui/react' import { Field, FormSpy } from 'react-final-form' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faCheck, faExclamationTriangle, faTimes } from '@fortawesome/free-solid-svg-icons' +import { + faCheck, + faExclamationTriangle, + faFunnelDollar, + faTimes, +} from '@fortawesome/free-solid-svg-icons' import { CippWizard } from 'src/components/layout' import { WizardTableField } from 'src/components/tables' +import { validateAlphabeticalSort } from 'src/components/utilities' import PropTypes from 'prop-types' import { Condition, @@ -16,6 +22,7 @@ import { import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app' import { OnChange } from 'react-final-form-listeners' import CippJsonView from 'src/components/utilities/CippJsonView' +import { value } from 'lodash-es' const Error = ({ name }) => ( { let template = intuneTemplates.data.filter(function (obj) { return obj.GUID === value }) - // console.log(template[0][set]) onChange(template[0][set]) }} @@ -145,10 +151,12 @@ const AddPolicy = () => { {intuneTemplates.isSuccess && ( ({ - value: template.GUID, - label: template.Displayname, - }))} + values={validateAlphabeticalSort(intuneTemplates.data, ['Displayname'])?.map( + (template) => ({ + value: template.GUID, + label: template.Displayname, + }), + )} placeholder="Select a template" label="Please choose a template to apply." /> diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index 62a679ff1d9a..72852dfd13dd 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -31,7 +31,7 @@ import { import { faCheck, faCircleNotch, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' import { CippContentCard, CippPage } from 'src/components/layout' import { useSelector } from 'react-redux' -import { ModalService } from 'src/components/utilities' +import { ModalService, validateAlphabeticalSort } from 'src/components/utilities' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import Skeleton from 'react-loading-skeleton' import { CippTable, cellBooleanFormatter } from 'src/components/tables' @@ -613,7 +613,10 @@ const ApplyNewStandard = () => { name={`${template.switchName}.TemplateList`} className="mb-3" multi={true} - values={template.templates.data?.map((t) => ({ + values={validateAlphabeticalSort( + template.templates.data, + ['Displayname', 'name'], + )?.map((t) => ({ value: t.GUID, name: t.name || t.Displayname || t.displayName, }))} From 091aa6fcd56acafd7ca3bbd4ec1cdb0afd4a037a Mon Sep 17 00:00:00 2001 From: greenchiip Date: Wed, 17 Apr 2024 13:02:27 +0200 Subject: [PATCH 10/11] added number as type to RFFCFormInput --- src/components/forms/RFFComponents.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/forms/RFFComponents.jsx b/src/components/forms/RFFComponents.jsx index 0d07909c5975..234e990ca5c5 100644 --- a/src/components/forms/RFFComponents.jsx +++ b/src/components/forms/RFFComponents.jsx @@ -193,7 +193,7 @@ export const RFFCFormInput = ({ } RFFCFormInput.propTypes = { ...sharedPropTypes, - type: PropTypes.oneOf(['color', 'file', 'text', 'password']), + type: PropTypes.oneOf(['color', 'file', 'text', 'password', 'number']), placeholder: PropTypes.string, } From 139d1cdfb01cd61ee8472f34385e6b40e370cafe Mon Sep 17 00:00:00 2001 From: greenchiip Date: Wed, 17 Apr 2024 13:05:54 +0200 Subject: [PATCH 11/11] Added missing placeholder tag --- src/views/tenant/standards/ListAppliedStandards.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/tenant/standards/ListAppliedStandards.jsx b/src/views/tenant/standards/ListAppliedStandards.jsx index 72852dfd13dd..8a280ca6f830 100644 --- a/src/views/tenant/standards/ListAppliedStandards.jsx +++ b/src/views/tenant/standards/ListAppliedStandards.jsx @@ -509,6 +509,7 @@ const ApplyNewStandard = () => { <> {component.type === 'Select' && (