Skip to content

Commit

Permalink
Merge pull request #24 from KelvinTegelaar/dev
Browse files Browse the repository at this point in the history
[pull] dev from KelvinTegelaar:dev
  • Loading branch information
kris6673 authored Apr 18, 2024
2 parents 91d6a55 + 296f2c1 commit 042367c
Show file tree
Hide file tree
Showing 18 changed files with 345 additions and 93 deletions.
4 changes: 2 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ const App = () => {
{routes.map((route, idx) => {
const allowedRoles = route.allowedRoles
const Routecomponent = dynamicImport(route.path)
console.log('route', route)
console.log('Routecomponent', Routecomponent)
//console.log('route', route)
//console.log('Routecomponent', Routecomponent)
return (
route.component && (
<Route
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/RFFComponents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
1 change: 0 additions & 1 deletion src/components/tables/CellTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
74 changes: 36 additions & 38 deletions src/components/tables/CippTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions src/components/utilities/CippTenantOffcanvas.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
18 changes: 15 additions & 3 deletions src/components/utilities/TenantSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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()
Expand Down Expand Up @@ -90,10 +92,10 @@ const TenantSelector = ({ action, showAllTenantSelector = true, NavSelector = fa
<FontAwesomeIcon icon={faBuilding} />
</CButton>
)}
<div className="flex-grow-1 my-auto mx-2">
<div className="flex-grow-1 my-auto d-flex align-items-center">
<SelectSearch
search
className={'select-search tenantDropdown'}
className="select-search tenantDropdown"
onChange={activated}
filterOptions={CippfuzzySearch}
placeholder={placeholder}
Expand All @@ -104,6 +106,16 @@ const TenantSelector = ({ action, showAllTenantSelector = true, NavSelector = fa
name: `${displayName} (${defaultDomainName})`,
}))}
/>
<CButton
onClick={() =>
//set a random number to force a refresh
setRefreshState(Math.random())
}
variant="ghost"
className="ml-2"
>
<FontAwesomeIcon icon={'refresh'} spin={isFetching} />
</CButton>
</div>
</>
)}
Expand Down
16 changes: 10 additions & 6 deletions src/components/utilities/Toasts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -32,15 +33,18 @@ const Toast = ({ message, title, onClose, error }) => {

return (
<CToast
autohide={true}
delay={3000}
autohide={false}
delay={5000}
visible={true}
className="align-items-center"
onClose={onClose}
>
<CToastHeader className="d-flex justify-content-between">
<div>{title}</div>
<FontAwesomeIcon size="2x" icon={faTimes} onClick={onClose} />
<CToastHeader>
<div className="fw-bold me-auto">{title}</div>
<small className="me-3">Just Now</small>
<div className="me-3">
<FontAwesomeIcon size="2x" icon={faTimes} onClick={onClose} />
</div>
</CToastHeader>
<CToastBody>
<div className="d-flex justify-content-between align-items-center text-danger">
Expand Down
2 changes: 2 additions & 0 deletions src/components/utilities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -43,4 +44,5 @@ export {
PageSizeSwitcher,
Toasts,
UsageLocation,
validateAlphabeticalSort,
}
23 changes: 23 additions & 0 deletions src/components/utilities/validateAlphabeticalSort.jsx
Original file line number Diff line number Diff line change
@@ -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
}
}
69 changes: 48 additions & 21 deletions src/store/api/baseQuery.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
import axios from 'axios'
let newController = new AbortController()

let newController = new AbortController() // Controller for managing abortion of requests

const retryDelays = [100, 200, 300] // Delays in milliseconds for retries

export const axiosQuery = async ({ path, method = 'get', params, data, hideToast }) => {
try {
const result = await axios({
signal: path === '/api/ListTenants' ? undefined : newController.signal,
method,
baseURL: window.location.origin,
url: path,
data,
params,
})
return { data: result?.data }
} catch (error) {
return {
error: {
status: error.response?.status,
data: error.response?.data,
hideToast,
message: error?.message,
},
let attempt = 0

while (attempt <= retryDelays.length) {
try {
const result = await axios({
signal: newController.signal,
method,
baseURL: window.location.origin,
url: path,
data,
params,
})
return { data: result.data } // Successful response
} catch (error) {
console.log('error', error)
console.log('path', path)
if (attempt === retryDelays.length || !shouldRetry(error, path)) {
return {
// Max retries reached or error should not trigger a retry
error: {
status: error.response?.status,
data: error.response?.data,
hideToast,
message: error.message,
},
}
}
await delay(retryDelays[attempt]) // Wait before retrying
attempt++
}
}
}

const shouldRetry = (error, path) => {
// Check if the path starts with 'List', error qualifies for a retry, and payload message is 'Backend call failure'
return (
path.toLowerCase().startsWith('/api/list') &&
error.response &&
error.response.status >= 500 &&
error.response.data === 'Backend call failure'
)
}
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

export function abortRequestSafe() {
newController.abort()
newController = new AbortController()
newController.abort() // Abort any ongoing request
newController = new AbortController() // Reset the controller for new requests
}

export const baseQuery = ({ baseUrl } = { baseUrl: '' }) => axiosQuery
2 changes: 1 addition & 1 deletion src/store/middleware/errorMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const errorMiddleware =

dispatch(
showToast({
title: 'An Error Has Occurred',
title: 'An error has occurred',
message: message,
toastError,
}),
Expand Down
2 changes: 2 additions & 0 deletions src/views/cipp/UserSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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),
({
Expand Down
Loading

0 comments on commit 042367c

Please sign in to comment.