Skip to content

Commit

Permalink
Merge branch 'KelvinTegelaar:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
RockfieldIT authored Apr 8, 2024
2 parents 5a2c81a + 57d0bf6 commit a85e212
Show file tree
Hide file tree
Showing 28 changed files with 1,246 additions and 168 deletions.
10 changes: 10 additions & 0 deletions Tools/Update-Version.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Param($Version)
Set-Location (Get-Item $PSScriptRoot).Parent.FullName
$Files = @('version_latest.txt', 'public/version_latest.txt')
foreach ($File in $Files) {
Set-Content $File -Value $Version
}

$Package = Get-Content package.json | ConvertFrom-Json
$Package.version = $Version
$Package | ConvertTo-Json -Depth 10 | Set-Content package.json
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cipp",
"version": "5.3.2",
"version": "5.4.2",
"description": "The CyberDrain Improved Partner Portal is a portal to help manage administration for Microsoft Partners.",
"homepage": "https://cipp.app/",
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion public/version_latest.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.3.2
5.4.2
17 changes: 16 additions & 1 deletion src/_nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,19 @@ const _nav = [
},
{
component: CNavItem,
name: 'MEM Policies',
name: 'Configuration Policies',
to: '/endpoint/MEM/list-policies',
},
{
component: CNavItem,
name: 'Compliance Policies',
to: '/endpoint/MEM/list-compliance-policies',
},
{
component: CNavItem,
name: 'Protection Policies',
to: '/endpoint/MEM/list-appprotection-policies',
},
{
component: CNavItem,
name: 'Apply Policy',
Expand Down Expand Up @@ -612,6 +622,11 @@ const _nav = [
name: 'Mailbox Restores',
to: '/email/tools/mailbox-restores',
},
{
component: CNavItem,
name: 'Mail Test',
to: '/email/tools/mail-test',
},
],
},
{
Expand Down
17 changes: 15 additions & 2 deletions src/components/forms/RFFComponents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Select from 'react-select'
import Creatable, { useCreatable } from 'react-select/creatable'
import { Field } from 'react-final-form'
import { FieldArray } from 'react-final-form-arrays'
import React, { useState, useMemo, useRef } from 'react'
import React, { useState, useMemo } from 'react'
import PropTypes from 'prop-types'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { debounce } from 'lodash-es'
Expand All @@ -37,6 +37,7 @@ const sharedPropTypes = {
error: PropTypes.any,
}),
}),
onClick: PropTypes.func,
}

export const RFFCFormFeedback = ({ meta }) => {
Expand All @@ -54,7 +55,14 @@ RFFCFormFeedback.propTypes = {
}),
}

export const RFFCFormCheck = ({ name, label, className = 'mb-3', validate, disabled = false }) => {
export const RFFCFormCheck = ({
name,
label,
className = 'mb-3',
validate,
disabled = false,
onClick,
}) => {
return (
<Field name={name} type="checkbox" validate={validate}>
{({ input, meta }) => (
Expand All @@ -67,6 +75,7 @@ export const RFFCFormCheck = ({ name, label, className = 'mb-3', validate, disab
disabled={disabled}
id={name}
label={label}
onClick={onClick}
/>
<RFFCFormFeedback meta={meta} />
</div>
Expand All @@ -92,6 +101,7 @@ export const RFFCFormSwitch = ({
validate,
disabled = false,
initialValue,
onClick,
}) => {
return (
<Field initialValue={initialValue} name={name} type="checkbox" validate={validate}>
Expand All @@ -113,6 +123,7 @@ export const RFFCFormSwitch = ({
disabled={disabled}
id={name}
label={label}
onClick={onClick}
/>
{input.value && <RFFCFormFeedback meta={meta} />}
<sub>{sublabel}</sub>
Expand Down Expand Up @@ -239,6 +250,7 @@ export const RFFCFormRadio = ({
className = 'mb-3',
validate,
disabled = false,
onClick,
}) => {
return (
<Field name={name} type="radio" value={value} validate={validate}>
Expand All @@ -252,6 +264,7 @@ export const RFFCFormRadio = ({
type="radio"
name={name}
label={label}
onClick={onClick}
/>
<RFFCFormFeedback meta={meta} />
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/components/tables/CellTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ export default function cellTable(
}

if (!Array.isArray(columnProp) && typeof columnProp === 'object') {
columnProp = [columnProp]
columnProp = Object.keys(columnProp).map((key) => {
return {
[key]: columnProp[key],
}
})
}

if (Array.isArray(columnProp) && typeof columnProp[0] !== 'object') {
Expand Down
145 changes: 69 additions & 76 deletions src/components/tables/CippTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ import {
import { cellGenericFormatter } from './CellGenericFormat'
import { ModalService } from '../utilities'
import { useLazyGenericGetRequestQuery, useLazyGenericPostRequestQuery } from 'src/store/api/app'
import { debounce, update } from 'lodash-es'
import { debounce } from 'lodash-es'
import { useSearchParams } from 'react-router-dom'
import CopyToClipboard from 'react-copy-to-clipboard'
import { setDefaultColumns } from 'src/store/features/app'
import { end } from '@popperjs/core'
import M365Licenses from 'src/data/M365Licenses'

const FilterComponent = ({ filterText, onFilter, onClear, filterlist, onFilterPreset }) => (
<>
Expand Down Expand Up @@ -277,28 +277,29 @@ export default function CippTable({
debounceSetGraphFilter(query)
return data
} else if (filterText.startsWith('Complex:')) {
const conditions = filterText.slice(9).split(';')
// Split conditions by ';' and 'or', and trim spaces
const conditions = filterText
.slice(9)
.split(/\s*or\s*|\s*;\s*/i) // Split by 'or' or ';', case insensitive, with optional spaces
.map((condition) => condition.trim())

return conditions.reduce((filteredData, condition) => {
const match = condition.trim().match(/(\w+)\s*(eq|ne|like|notlike|gt|lt)\s*(.+)/)
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 filteredData // Keep the current filtered data as is
}
if (!match) return false

let [property, operator, value] = match.slice(1)
value = escapeRegExp(value) // Escape special characters
let [property, operator, value] = match.slice(1)
value = escapeRegExp(value) // Escape special characters

return filteredData.filter((item) => {
// Find the actual key in the item that matches the property (case insensitive)
const actualKey = Object.keys(item).find(
(key) => key.toLowerCase() === property.toLowerCase(),
)

if (!actualKey) {
//set the error message so the user understands the key is not found.
console.error(`FilterError: Property "${property}" not found.`)
return false // Keep the item if the property is not found
return false
}

switch (operator) {
Expand All @@ -315,17 +316,19 @@ export default function CippTable({
case 'lt':
return parseFloat(item[actualKey]) < parseFloat(value)
default:
return true
return false // Should not reach here normally
}
})
}, data)
})
} else {
return data.filter(
(item) => JSON.stringify(item).toLowerCase().indexOf(filterText.toLowerCase()) !== -1,
)
}
}

// Helper functions like `debounce` and `escapeRegExp` should be defined somewhere in your code
// For example, a simple escapeRegExp function could be:
const filteredItems = Array.isArray(data) ? filterData(data, filterText) : []

const applyFilter = (e) => {
Expand Down Expand Up @@ -630,74 +633,64 @@ export default function CippTable({
return null
})

var exportData = filteredItems

var filtered =
Array.isArray(exportData) && exportData.length > 0
? exportData.map((obj) =>
// eslint-disable-next-line no-sequences
/* keys.reduce((acc, curr) => ((acc[curr] = obj[curr]), acc), {}),*/
keys.reduce((acc, curr) => {
const key = curr.split('/')
if (key.length > 1) {
let property = obj
for (let x = 0; x < key.length; x++) {
if (
Object.prototype.hasOwnProperty.call(property, key[x]) &&
property[key[x]] !== null
) {
property = property[key[x]]
} else {
property = 'n/a'
break
}
}
acc[curr] = property
} else {
if (typeof exportFormatter[curr] === 'function') {
acc[curr] = exportFormatter[curr]({ cell: obj[curr] })
} else {
acc[curr] = obj[curr]
}
}
return acc
}, {}),
)
: []
// Define the flatten function
const flatten = (obj, prefix = '') => {
return Object.keys(obj).reduce((output, key) => {
const newKey = prefix ? `${prefix}.${key}` : key
const value = obj[key] === null ? '' : obj[key]

const flatten = (obj, prefix) => {
let output = {}
for (let k in obj) {
let val = obj[k]
if (val === null) {
val = ''
}
const newKey = prefix ? prefix + '.' + k : k
if (typeof val === 'object') {
if (Array.isArray(val)) {
const { ...arrToObj } = val
const newObj = flatten(arrToObj, newKey)
output = { ...output, ...newObj }
} else {
const newObj = flatten(val, newKey)
output = { ...output, ...newObj }
}
if (typeof value === 'object' && !Array.isArray(value)) {
Object.assign(output, flatten(value, newKey))
} else {
output = { ...output, [newKey]: val }
output[newKey] = value
}
}
return output
return output
}, {})
}
filtered = filtered.map((item) => flatten(item))

let dataFlat
// Define the applyFormatter function
const applyFormatter = (obj) => {
return Object.keys(obj).reduce((acc, key) => {
const formatter = exportFormatter[key]
// Since the keys after flattening will be dot-separated, we need to adjust this to support nested keys if necessary.
const keyParts = key.split('.')
const finalKeyPart = keyParts[keyParts.length - 1]
const formattedValue =
typeof formatter === 'function' ? formatter({ cell: obj[key] }) : obj[key]
acc[key] = formattedValue
return acc
}, {})
}

if (Array.isArray(data)) {
dataFlat = data.map((item) => flatten(item))
} else {
dataFlat = []
// Process exportData function
const processExportData = (exportData, selectedColumns) => {
//filter out the columns that are not selected via selectedColumns
exportData = exportData.map((item) => {
return Object.keys(item)
.filter((key) => selectedColumns.find((o) => o.exportSelector === key))
.reduce((obj, key) => {
obj[key] = item[key]
return obj
}, {})
})
return Array.isArray(exportData) && exportData.length > 0
? exportData.map((obj) => {
const flattenedObj = flatten(obj)
return applyFormatter(flattenedObj)
})
: []
}

// Applying the processExportData function to both filteredItems and data
var filtered = processExportData(filteredItems, updatedColumns)

// Adjusted dataFlat processing to include formatting
let dataFlat = Array.isArray(data)
? data.map((item) => {
const flattenedItem = flatten(item)
return applyFormatter(flattenedItem)
})
: []
if (!disablePDFExport) {
if (dynamicColumns === true) {
defaultActions.push([
Expand Down
1 change: 1 addition & 0 deletions src/components/tables/WizardTableField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export default class WizardTableField extends React.Component {
selectableRows: true,
onSelectedRowsChange: this.handleSelect,
}}
dynamicColumns={false}
{...props}
/>
)
Expand Down
Loading

0 comments on commit a85e212

Please sign in to comment.