[MM-21974] improve CSS for client certificate screens (#1164)

* [MM-21974]make certificate selection look better

* fix console errors

* wip

* first css iteration

* css fixes

* use single quotes

* suggested tweaks

* some extra tweaks

* remove console.log

* Fix CR comments

Co-authored-by: Dean Whillier <deanwhillier@users.noreply.github.com>
This commit is contained in:
Guillermo Vayá
2020-02-03 10:15:03 +01:00
committed by GitHub
parent 6551483db7
commit a39c16a523
3 changed files with 274 additions and 183 deletions

View File

@@ -7,9 +7,6 @@ import {Modal, Button, Table, Row, Col} from 'react-bootstrap';
import ShowCertificateModal from './showCertificateModal.jsx';
const CELL_SIZE = 23;
const ELIPSIS_SIZE = 3;
export default class SelectCertificateModal extends React.Component {
static propTypes = {
onSelect: PropTypes.func.isRequired,
@@ -28,14 +25,6 @@ export default class SelectCertificateModal extends React.Component {
};
}
maxSize = (item, max) => {
if (!item || item.length <= max) {
return item;
}
const sub = item.substring(0, max - ELIPSIS_SIZE);
return `${sub}...`;
}
selectfn = (index) => {
return (() => {
this.setState({selectedIndex: index});
@@ -47,29 +36,21 @@ export default class SelectCertificateModal extends React.Component {
const subject = (cert.subjectName || (cert.subject && cert.subject.commonName) || '');
const serial = cert.serialNumber || '';
const issuerShort = this.maxSize(cert.issuer.commonName, CELL_SIZE);
const subjectShort = this.maxSize(cert.subject.commonName, CELL_SIZE);
const serialShort = this.maxSize(cert.serialNumber, CELL_SIZE);
const style = this.state.selectedIndex === index ? {background: '#457AB2', color: '#FFFFFF'} : {};
return (
<tr
key={`cert-${index}`}
onClick={this.selectfn(index)}
style={style}
className={this.state.selectedIndex === index ? 'selected' : ''}
>
<td
style={style}
title={issuer}
>{issuerShort}</td>
<td
style={style}
title={subject}
>{subjectShort}</td>
>{subject}</td>
<td
title={issuer}
>{issuer}</td>
<td
style={style}
title={serial}
>{serialShort}</td>
>{serial}</td>
</tr>);
};
@@ -119,19 +100,21 @@ export default class SelectCertificateModal extends React.Component {
return (
<Modal
bsClass='modal'
className='certificateModal'
show={this.props.certificateRequests.length}
className='certificate-modal'
show={this.props.certificateRequests.length > 0}
>
<Modal.Header className={'noBorder'}>
<Modal.Title className={'bottomBorder'}>{'Select a certificate'}</Modal.Title>
<Modal.Header>
<Modal.Title >{'Select a certificate'}</Modal.Title>
</Modal.Header>
<Modal.Body>
<p className={'subtitle'}>{`Select a certificate to authenticate yourself to ${server}`}</p>
<Table
stripped={'true'}
striped={true}
hover={true}
size={'sm'}
className='certificateList'
responsive={true}
className='certificate-list'
tabIndex={1}
>
<thead>
<tr>
@@ -146,30 +129,32 @@ export default class SelectCertificateModal extends React.Component {
</tbody>
</Table>
</Modal.Body>
<Modal.Footer className={'noBorder'}>
<Row className={'topBorder'}>
<Col sm={4}>
<Button
variant={'info'}
disabled={this.state.selectedIndex === null}
onClick={this.handleCertificateInfo}
className={'info'}
>{'Certificate Information'}</Button>
</Col>
<Col sm={8}>
<Button
onClick={this.props.onCancel}
variant={'secondary'}
className={'secondary'}
>{'Cancel'}</Button>
<Button
variant={'primary'}
onClick={this.handleOk}
disabled={this.state.selectedIndex === null}
className={'primary'}
>{'Ok'}</Button>
</Col>
</Row>
<Modal.Footer className={'no-border'}>
<div className={'container-fluid'}>
<Row>
<Col sm={4}>
<Button
variant={'info'}
disabled={this.state.selectedIndex === null}
onClick={this.handleCertificateInfo}
className={'info'}
>{'Certificate Information'}</Button>
</Col>
<Col sm={8}>
<Button
onClick={this.props.onCancel}
variant={'secondary'}
className={'secondary'}
>{'Cancel'}</Button>
<Button
variant={'primary'}
onClick={this.handleOk}
disabled={this.state.selectedIndex === null}
className={'primary'}
>{'OK'}</Button>
</Col>
</Row>
</div>
</Modal.Footer>
</Modal>
);

View File

@@ -3,7 +3,7 @@
import React, {Fragment} from 'react';
import PropTypes from 'prop-types';
import {Modal, Button, Row} from 'react-bootstrap';
import {Modal, Button, Row, Col} from 'react-bootstrap';
export default class ShowCertificateModal extends React.Component {
static propTypes = {
@@ -24,20 +24,30 @@ export default class ShowCertificateModal extends React.Component {
}
render() {
const certificateSection = (descriptor) => {
return (
<Fragment>
<dt className={'certificate-key'}>{descriptor}</dt>
<dd className={'certificate-section'}><span/></dd>
</Fragment>
);
};
const certificateItem = (descriptor, value) => {
const ddclass = value ? '' : 'emtpyDescriptor';
const val = value ? `${value}` : <span/>;
return (
<Fragment>
<dt>{descriptor}</dt>
<dd className={ddclass}>{val}</dd>
<dt className={'certificate-key'}>{descriptor}</dt>
<dd className={'certificate-value'}>{val}</dd>
</Fragment>
);
};
if (this.state.certificate === null) {
return (
<Modal>
<Modal
bsClass='modal'
className='show-certificate'
>
<Modal.Body>
{'No certificate Selected'}
</Modal.Body>
@@ -58,38 +68,45 @@ export default class ShowCertificateModal extends React.Component {
return (
<Modal
bsClass='modal'
className='certificateModal'
className='show-certificate'
show={this.state.certificate !== null}
scrollable={true}
scrollable={'true'}
>
<Modal.Header className={'noBorder'}>
<Modal.Title className={'bottomBorder'}>{'Certificate Information'}</Modal.Title>
<Modal.Header className={'no-border'}>
<Modal.Title>{'Certificate information'}</Modal.Title>
</Modal.Header>
<Modal.Body>
<h3 className={'certificateKey'}>{`${this.state.certificate.subject.commonName}`}</h3>
<p className={'certInfo'}>{`Issued by: ${this.state.certificate.issuer.commonName}`}</p>
<p className={'certInfo'}>{`Expires: ${expiration.toLocaleString(dateLocale, dateDisplayOptions)}`}</p>
<p>{'Details'}</p>
<p className='details'>{'Details'}</p>
<dl>
{certificateItem('Subject Name')}
{certificateSection('Subject Name')}
{certificateItem('Common Name', this.state.certificate.subject.commonName)}
{certificateItem('Issuer Name')}
</dl>
<dl>
{certificateSection('Issuer Name')}
{certificateItem('Common Name', this.state.certificate.issuer.commonName)}
</dl>
<dl>
{certificateItem('Serial Number', this.state.certificate.serialNumber)}
{certificateItem('Not Valid Before', creation.toLocaleString(dateLocale, dateDisplayOptions))}
{certificateItem('Not Valid After', expiration.toLocaleString(dateLocale, dateDisplayOptions))}
{certificateItem('Public Key Info')}
</dl>
<dl>
{certificateSection('Public Key Info')}
{certificateItem('Algorithm', this.state.certificate.fingerprint.split('/')[0])}
</dl>
</Modal.Body>
<Modal.Footer className={'noBorder'}>
<Row className={'topBorder'}>
<Button
variant={'primary'}
onClick={this.handleOk}
className={'primary'}
>{'Close'}</Button>
</Row>
<Modal.Footer className={'no-border'}>
<div className='container-fluid'>
<Row>
<Col>
<Button
variant={'primary'}
onClick={this.handleOk}
className={'primary'}
>{'Close'}</Button>
</Col>
</Row>
</div>
</Modal.Footer>
</Modal>
);

View File

@@ -1,121 +1,210 @@
.certificateModal dialog {
.certificate-modal .modal,
.show-certificate .modal {
background-color: aliceblue;
margin-top: 40px;
}
.certificateList thead {
.show-certificate .modal-dialog {
width: 800px;
}
.modal-header {
border-bottom: 0px;
}
.modal-header::after {
border-bottom: solid 1px #E5E5E5;
width: 100%;
transform: translateY(15px);
}
.modal-footer::before {
border-top: solid 1px #E5E5E5;
width: 100%;
transform: translateY(-15px);
}
.modal-body :last-child {
margin-bottom: 0;
}
.certificate-modal .col-sm-4 {
padding: 0px;
text-align: left;
}
.certificate-modal .col-sm-8 {
padding: 0px;
}
.certificate-list thead {
width: 557.89px;
height: 22px;
}
.certificateList thead>tr>th {
font-family: Helvetica Neue;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 14px;
padding: 2px;
border-bottom: 1px solid #CCCCCC;
color: #333333;
}
.certificateList tbody>tr>td {
width: 227.17px;
height: 47px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 17px;
color: #555555;
.certificate-list thead>tr {
padding: 0px 5px;
}
table.certificateList {
background: #FFFFFF;
border: 1px solid #CCCCCC;
box-sizing: border-box;
box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.0008);
border-radius: 4px;
border-collapse: unset;
height: 150px;
}
.certificateModal button {
background: #FFFFFF;
border: 1px solid #CCCCCC;
box-sizing: border-box;
border-radius: 4px;
padding: 9px 12px;
}
.certificateModal button:disabled {
opacity: 0.5;
}
.certificateModal button.primary {
background: #457AB2;
color: #FFFFFF;
border: 1px solid #2E6DA4;
}
.certificateModal button.info {
color: #457AB2;
}
.certificateModal button.primary:hover {
background: #659AD2;
}
.certificateModal .subtitle {
color: #737373;
margin: 0px 15px 10px;
}
.certificateModal .bottomBorder {
padding-bottom: 10px;
border-bottom: 1px solid #CCCCCC;
}
.certificateModal .topBorder {
border-top: 1px solid #CCCCCC;
margin: 0 1px 0 1px;
padding-top: 15px;
}
.certificateModal .noBorder {
border: none;
}
.divider {
border-right: 1px solid #CCCCCC;
display: block;
}
.certificateModal dt, dd {
float: left;
margin: 5px;
}
.certificateModal dt { clear:both }
.certificateModal dl {
overflow-y: auto;
}
.certificateKey {
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 17px;
color: #737373;
}
.certInfo {
.certificate-list thead>tr>th {
font-family: Helvetica Neue;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
padding: 3px 5px;
border-bottom: 1px solid #CCCCCC;
color: #333333;
height: 22px;
}
.certificate-list thead tr th:first-child span {
padding-left: 5px;
}
.certificate-list thead tr th span {
border-right: solid 1px #E5E5E5;
display: block;
}
.certificate-list thead tr th:last-child span {
border-right: none;
}
.certificate-list tbody tr {
user-select: none;
cursor: pointer;
color: #555555;
}
.certificate-list tbody>tr>td {
max-width: 165px;
height: 47px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 17px;
padding: 15px 10px;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
.certificate-list tbody tr td:first-child {
padding-left: 15px;
max-width: 227px;
}
.certificate-list tbody tr.selected {
background: #457AB2;
color: #FFFFFF;
}
table.certificate-list {
background: #FFFFFF;
border: 1px solid #CCCCCC;
border-radius: 4px;
border-collapse: unset;
box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.0008);
height: 150px;
}
table.certificate-list:focus {
border: 1px solid #66AFE9;
box-sizing: border-box;
box-shadow: 0px 0px 8px rgba(102, 175, 233, 0.6), inset 1px 1px 0px rgba(0, 0, 0, 0.00075);
}
.show-certificate button,
.certificate-modal button {
background: #FFFFFF;
border: 1px solid #CCCCCC;
box-sizing: border-box;
border-radius: 4px;
padding: 9px 12px;
line-height: 16px;
}
.show-certificate button:disabled,
.certificate-modal button:disabled {
opacity: 0.5;
}
.show-certificate button.primary,
.certificate-modal button.primary {
background: #457AB2;
color: #FFFFFF;
border: 1px solid #2E6DA4;
}
.show-certificate button.primary:hover,
.certificate-modal button.primary:hover {
background: #659AD2;
}
.certificate-modal button.info {
color: #457AB2;
}
.certificate-modal button.info:disabled {
color: #000;
}
.show-certificate .subtitle,
.certificate-modal .subtitle {
color: #737373;
margin: 0px 0px 15px 0px;
}
.show-certificate .no-border,
.certificate-modal .no-border {
border: none;
}
.show-certificate dl {
overflow-y: auto;
}
.show-certificate dt, dd {
float: left;
margin: 5px;
}
.show-certificate dt {
width: 150px;
clear:both
}
.show-certificate dd {
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
}
.certificate-key {
font-style: normal;
font-weight: bold;
font-size: 12px;
line-height: 15px;
color: #333333;
text-align: right;
}
.certificate-value {
padding-top: 1px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 14px;
text-align: left;
color: #333333;
}
.emtpyDescriptor {
border-bottom: 1px solid #CCCCCC;
.certificate-section {
border-bottom: 1px solid #E5E5E5;
width: 598px;
height: 8px;
}
.show-certificate .details {
margin: 15px;
font-weight: bold;
font-style: normal;
font-size: 12px;
line-height: 15px;
color: #333333;
}