diff --git a/src/components/CippProfile.js b/src/components/CippProfile.js new file mode 100644 index 000000000000..d75ba9300f02 --- /dev/null +++ b/src/components/CippProfile.js @@ -0,0 +1,58 @@ +import React from 'react' +import { + CRow, + CCol, + CCard, + CCardImage, + CCardTitle, + CCardBody, + CListGroup, + CListGroupItem, + CSpinner, +} from '@coreui/react' +import avatar0 from './../assets/images/avatars/0.jpg' +import { useLoadClientPrincipalQuery } from '../store/api/auth' +import ThemeSwitcher from 'src/components/cipp/ThemeSwitcher' + +const CippProfile = () => { + const { data: profile, isFetching, isLoading } = useLoadClientPrincipalQuery() + + return ( + <> + + + + {(isFetching || isLoading) && } + {!isLoading && ( + <> + + + {profile.clientPrincipal.userDetails} + + + + Identity Provider: {profile.clientPrincipal.identityProvider} + + User ID: {profile.clientPrincipal.userId} + + Roles ({profile.clientPrincipal.userRoles.length}) +
    + {profile.clientPrincipal.userRoles.map((r, index) => ( +
  • {r}
  • + ))} +
+
+
+ + )} +
+
+ + + +
+ + ) +} + +export default CippProfile diff --git a/src/components/header/AppHeaderDropdown.js b/src/components/header/AppHeaderDropdown.js index 28b20c209ab0..748bd6c92a2a 100644 --- a/src/components/header/AppHeaderDropdown.js +++ b/src/components/header/AppHeaderDropdown.js @@ -1,31 +1,52 @@ -import React from 'react' -import { CAvatar, CDropdown, CDropdownHeader, CDropdownMenu, CDropdownToggle } from '@coreui/react' -import { faUser, faBook } from '@fortawesome/free-solid-svg-icons' +import React, { useState } from 'react' +import { + CAvatar, + CDropdown, + CDropdownHeader, + CDropdownMenu, + CDropdownToggle, + CLink, +} from '@coreui/react' +import { faUser, faBook, faTimes } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Link } from 'react-router-dom' import { authApi } from '../../store/api/auth' +import CippProfile from '../CippProfile' +import CippOffcanvas from '../cipp/CippOffcanvas' const AppHeaderDropdown = () => { + const [profileVisible, setProfileVisible] = useState(false) const { data: profile } = authApi.endpoints.loadClientPrincipal.useQueryState() + const cippProfile = return ( - - - - {profile.clientPrincipal.userDetails[0].toUpperCase()} - - - - Settings - - - Profile - - - - Logbook - - - + <> + + + + {profile.clientPrincipal.userDetails[0].toUpperCase()} + + + + Settings + setProfileVisible(true)}> + + Profile + + + + Logbook + + + + setProfileVisible(false)} + title="Profile" + placement="end" + children={cippProfile} + /> + ) } diff --git a/src/views/tenant/standards/DomainsAnalyser.js b/src/views/tenant/standards/DomainsAnalyser.js index 797df763aada..da7e78ac5e08 100644 --- a/src/views/tenant/standards/DomainsAnalyser.js +++ b/src/views/tenant/standards/DomainsAnalyser.js @@ -1,9 +1,15 @@ -import React from 'react' +import React, { useState } from 'react' import PropTypes from 'prop-types' import { CButton, CCard, CCardHeader, CCardTitle, CCardBody } from '@coreui/react' -import { CellBadge, CippDatatable, cellProgressBarFormatter } from '../../../components/cipp' -import { ModalService } from '../../../components' +import { + CellBadge, + CippDatatable, + cellProgressBarFormatter, + CippOffcanvas, +} from '../../../components/cipp' +/*import { ModalService } from '../../../components'*/ import cellGetProperty from '../../../components/cipp/cellGetProperty' +import IndividualDomainCheck from './IndividualDomain' const MoreInfoCard = ({ row }) => { return ( @@ -48,12 +54,28 @@ MoreInfoCard.propTypes = { row: PropTypes.object.isRequired, } +function checkDomain(tenantDomain) { + return ( +
+ +
+ ) +} +checkDomain.propTypes = { + tenantDomain: PropTypes.string, +} + const DomainsAnalyser = () => { + const [individualDomainResults, setIndividualDomainResults] = useState() + const [domainCheckVisible, setDomainCheckVisible] = useState(false) + const handleMoreInfo = ({ row }) => { - ModalService.open({ + /*ModalService.open({ body: , title: `${row.Tenant} More Information`, - }) + })*/ + setIndividualDomainResults(checkDomain(row.Domain)) + setDomainCheckVisible(true) } const columns = [ @@ -226,6 +248,15 @@ const DomainsAnalyser = () => { /> + + setDomainCheckVisible(false)} + title="More Info" + placement="end" + children={individualDomainResults} + /> ) } diff --git a/src/views/tenant/standards/IndividualDomain.js b/src/views/tenant/standards/IndividualDomain.js index 76568f284efc..7a739b184458 100644 --- a/src/views/tenant/standards/IndividualDomain.js +++ b/src/views/tenant/standards/IndividualDomain.js @@ -1,9 +1,10 @@ import React, { useEffect, useState, useRef } from 'react' import PropTypes from 'prop-types' -import { Form } from 'react-final-form' +import { Form, Field } from 'react-final-form' import { useSearchParams } from 'react-router-dom' import { useLazyListDomainTestsQuery, useListDomainTestsQuery } from '../../../store/api/domains' import StatusIcon from 'src/components/cipp/StatusIcon' +import CippOffcanvas from 'src/components/cipp/CippOffcanvas' import { CAlert, CButton, @@ -14,6 +15,8 @@ import { CCol, CCollapse, CForm, + CFormLabel, + CFormInput, CFormTextarea, CRow, CCardTitle, @@ -27,6 +30,8 @@ import { CTableBody, CBadge, CTooltip, + COffcanvasTitle, + CInputGroup, } from '@coreui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { @@ -39,7 +44,6 @@ import { faCopy, faExternalLinkAlt, } from '@fortawesome/free-solid-svg-icons' -import { RFFCFormInput } from '../../../components/RFFComponents' // const required = (value) => (value ? undefined : 'Required') @@ -51,19 +55,42 @@ const IconWarning = () => ( const IconExternalLink = () => const IconCopy = () => -const IndividualDomainCheck = () => { +const domainCheckProps = { + readOnly: PropTypes.bool, + isOffcanvas: PropTypes.bool, + initialDomain: PropTypes.string, +} + +export default function IndividualDomainCheck({ + initialDomain = '', + readOnly = false, + isOffcanvas = false, +}) { const [searchParams, setSearchParams] = useSearchParams() const [domain, setDomain] = useState('') + const [rowXs, setRowXs] = useState() + const [rowXl, setRowXl] = useState() const [trigger, { data, isFetching, isSuccess, ...rest }] = useLazyListDomainTestsQuery() useEffect(() => { + if (initialDomain) { + searchParams.set('domain', initialDomain) + } // check if domain query is set const domainQuery = searchParams.get('domain') if (domainQuery) { setDomain(domainQuery) trigger({ domain: domainQuery }) } - }, [searchParams, trigger]) + + if (isOffcanvas) { + setRowXs({ cols: 1, gutter: 3 }) + setRowXl({ cols: 1, gutter: 3 }) + } else { + setRowXs({ cols: 1, gutter: 4 }) + setRowXl({ cols: 2, gutter: 4 }) + } + }, [searchParams, trigger, isOffcanvas, initialDomain]) const onSubmit = (values) => { setDomain(values.domain) @@ -72,11 +99,11 @@ const IndividualDomainCheck = () => { } return ( - + - Email Security Domain Checker + Email Security Domain Checker
{ render={({ handleSubmit, submitting, pristine }) => { return ( - - - {isFetching && ( - - )} - Check Domain - + + {({ input, meta }) => { + return ( + + + + + {isFetching && ( + + )} + Check + + + ) + }} + ) }} @@ -114,7 +163,9 @@ const IndividualDomainCheck = () => { ) } -export default IndividualDomainCheck +IndividualDomainCheck.propTypes = domainCheckProps + +/*export default IndividualDomainCheck*/ const sharedProps = { domain: PropTypes.string, @@ -137,7 +188,7 @@ const ResultsCard = ({ children, data, type }) => { return ( - + {type} Results @@ -238,94 +289,103 @@ const SPFResultsCard = ({ domain }) => { SPFResultsCard.propTypes = sharedProps -const MXResultsCard = ({ domain }) => { - const { data } = useListDomainTestsQuery({ domain }) - const mailProviderName = data?.MXResults?.MailProvider?.Name +const MXDetailView = (data) => { let records = data?.MXResults?.Records || [] if (!Array.isArray(records)) { records = [records] } + + return ( + <> + {records.length > 0 && ( +
+ MX Records + + + + Priority + Hostname + + + + {records.map((record, key) => ( + + {record?.Priority} + {record?.Hostname} + + ))} + + +
+ )} + Documentation + + {data?.MXResults?.MailProvider?._MxComment && ( + + MX Record + + )} + {data?.MXResults?.MailProvider?._SpfComment && ( + + SPF Record + + )} + {data?.MXResults?.MailProvider?._DkimComment && ( + + DKIM Record + + )} + + + ) +} +MXDetailView.propTypes = { + data: PropTypes.object, +} + +const MXResultsCard = ({ domain }) => { + const { data } = useListDomainTestsQuery({ domain }) + const mailProviderName = data?.MXResults?.MailProvider?.Name + const [visible, setVisible] = useState(false) return (
- + Mail Provider: {mailProviderName || 'Unknown'} setVisible(!visible)} + onClick={() => setVisible(true)} style={{ fontSize: 14 }} color="primary" > - {(visible && 'Hide') || 'Show'} Details + Details
- - - - {records.length > 0 && ( -
- MX Records - - - - Priority - Hostname - - - - {records.map((record, key) => ( - - {record?.Priority} - {record?.Hostname} - - ))} - - -
- )} -
- - Mail Provider Info - - {data?.MXResults?.MailProvider?._MxComment && ( - - MX Record - - )} - {data?.MXResults?.MailProvider?._SpfComment && ( - - SPF Record - - )} - {data?.MXResults?.MailProvider?._DkimComment && ( - - DKIM Record - - )} - - -
-
+ setVisible(false)} + title="Mail Provider Info" + children={MXDetailView(data)} + />
) } @@ -461,8 +521,7 @@ const DKIMResultsCard = ({ domain }) => { {records.map((record, idx) => (
- {/*{record?.Selector} - # TODO: Update API to expose selector name */} + {record?.Selector}._domainkey