summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorDixsie Wolmers <dixsiew@gmail.com>2019-09-11 15:26:38 -0500
committerGunnar Mills <gmills@us.ibm.com>2019-10-21 18:41:51 +0000
commitc15f66b0d52e855ca0c03e20f875f7c4bd67282f (patch)
tree327202e6525858a0154d6231d08e7c4a73fc2273 /app
parent2ac4eda38aff10e8647ded62569f102290f3331a (diff)
downloadphosphor-webui-c15f66b0d52e855ca0c03e20f875f7c4bd67282f.tar.gz
phosphor-webui-c15f66b0d52e855ca0c03e20f875f7c4bd67282f.zip
Update certificate management page consistency
This change applies global styles to improve page layout consistency and modal management - Adds page and section styles - Removes unused styles - Creates individual html files for modals - Updates certificate modals to bootstrap modal - Updates global styles for input file field in file-upload.scss TODO: - Update certificate table with table component in separate commit - Update CSR modal to use global form-field styles in separate commit Signed-off-by: Dixsie Wolmers <dixsiew@gmail.com> Change-Id: I9b800cb684740da1a9168294433e726efb0f9d0e
Diffstat (limited to 'app')
-rw-r--r--app/access-control/controllers/certificate-controller.html312
-rw-r--r--app/access-control/controllers/certificate-controller.js79
-rw-r--r--app/access-control/controllers/certificate-modal-add-cert.html86
-rw-r--r--app/access-control/controllers/certificate-modal-csr-download.html41
-rw-r--r--app/access-control/controllers/certificate-modal-csr-gen.html351
-rw-r--r--app/access-control/styles/certificate.scss72
-rw-r--r--app/common/directives/certificate.html75
-rw-r--r--app/common/styles/elements/file-upload.scss56
-rw-r--r--app/common/styles/elements/index.scss2
-rw-r--r--app/common/styles/elements/input-file.scss25
-rw-r--r--app/common/styles/elements/modals.scss42
11 files changed, 736 insertions, 405 deletions
diff --git a/app/access-control/controllers/certificate-controller.html b/app/access-control/controllers/certificate-controller.html
index c1f64fa..d2db65c 100644
--- a/app/access-control/controllers/certificate-controller.html
+++ b/app/access-control/controllers/certificate-controller.html
@@ -1,32 +1,44 @@
<loader loading="loading"></loader>
-<div id="configuration-cert">
- <div class="row column">
- <h1>SSL certificates</h1>
- </div>
- <div ng-repeat="certificate in certificates | filter:{isExpiring:true}" class="row column">
- <div class="small-12 alert alert-warning" role="alert">
- <icon file="icon-warning.svg" aria-hidden="true"></icon>
- The uploaded {{certificate.name}} is expiring in {{getDays(certificate.ValidNotAfter) === 0 ? 'less than one day!' : getDays(certificate.ValidNotAfter)
- + ' days!'}} Consider replacing it with a new certificate.
+<div id="configuration-cert" class="page">
+ <h1 class="page-title">SSL certificates</h1>
+ <section class="section">
+ <div class="section-content">
+ <div ng-repeat="certificate in certificates | filter:{isExpiring:true}">
+ <div class="alert alert-warning" role="alert">
+ <icon file="icon-warning.svg" aria-hidden="true"></icon>
+ The uploaded {{ certificate.name }} is expiring in
+ {{ getDays(certificate.ValidNotAfter) === 0
+ ? "less than one day!"
+ : getDays(certificate.ValidNotAfter) + " days!" }}
+ Consider replacing it with a new certificate.
+ </div>
+ </div>
+ <div ng-repeat="certificate in certificates | filter:{isExpired:true}">
+ <div class="alert alert-danger" role="alert">
+ <icon file="icon-critical.svg" aria-hidden="true"></icon>
+ The uploaded {{ certificate.name }} has expired! Consider replacing it
+ with a new certificate.
+ </div>
+ </div>
</div>
- </div>
- <div ng-repeat="certificate in certificates|filter:{isExpired:true}" class="row column">
- <div class="small-12 alert alert-danger" role="alert">
- <icon file="icon-critical.svg" aria-hidden="true"></icon> The uploaded {{certificate.name}} has expired! Consider replacing it with a new certificate.
+ </section>
+ <section class="section">
+ <div class="section-content">
+ <button
+ type="button"
+ class="btn btn-tertiary"
+ ng-disabled="availableCertificateTypes.length === 0"
+ ng-click="addCertModal()">
+ <icon class="icon-add" file="icon-plus.svg" aria-hidden="true"></icon>
+ Add new certificate
+ </button>
+ <button type="button" class="btn btn-tertiary" ng-click="addCsrModal()">
+ <icon class="icon-add" file="icon-plus.svg" aria-hidden="true"></icon>
+ Generate CSR
+ </button>
</div>
- </div>
- <div class="row column">
- <button type="button" class="btn btn-tertiary" ng-disabled="availableCertificateTypes.length === 0" ng-click="addCertificateModal=true">
- <icon class="icon-add" file="icon-plus.svg"></icon>
- Add new certificate
- </button>
- <button type="button" class="btn btn-tertiary" ng-click="addCSRModal=true">
- <icon class="icon-add" file="icon-plus.svg"></icon>
- Generate CSR
- </button>
- </div>
- <div class="row column">
- <div class="small-12 certificate__table">
+ <!-- TODO: Replace table with resusable table component -->
+ <div class="section-content certificate__table">
<div class="table__row-header">
<div class="row column">
<div class="certificate__type-header">
@@ -41,254 +53,18 @@
<div class="certificate__date-header">
Valid from
</div>
- <div class="certificate__status-header">
- </div>
+ <div class="certificate__status-header"></div>
<div class="certificate__date-header">
Valid until
</div>
</div>
</div>
- <div ng-if="certificates.length < 1" class="empty__logs">There have been no certificates added.</div>
- <div ng-repeat="certificate in certificates">
- <certificate cert="certificate" reload="loadCertificates()" )></certificate>
+ <div ng-if="certificates.length < 1" class="empty__logs">
+ There have been no certificates added.
</div>
- </div>
- </div>
- <section class="modal add__certificate__modal" aria-hidden="true" role="dialog" ng-class="{'active': addCertificateModal}">
- <form name="add__cert__form" id="add__cert__form" ng-class="{'submitted': submitted}">
- <div class="modal__content">
- <button class="certificate__close-modal" ng-click="addCertificateModal = false; add__cert__form.$setUntouched()">
- <icon aria-hidden="true" file="icon-close.svg">
- </button>
- <h2 class="page-header">Add new certificate</h2>
- <div class="row column add-certificate__section ">
- <div class="small-12">
- <label for="cert__type">Certificate type</label>
- <select id="cert__type" name="cert__type" ng-model="newCertificate.selectedType" required>
- <option class="courier-bold" ng-value="">Select an option</option>
- <option class="courier-bold" ng-value="type" ng-repeat="type in availableCertificateTypes">
- {{type.name}}</option>
- </select>
- <div ng-messages="add__cert__form.cert__type.$error" class="form-error" ng-class="{'visible' : add__cert__form.cert__type.$touched || submitted }">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
- </div>
- <div class="row column add-certificate__section">
- <div class="small-12">
- <label class="select__new-label" for="upload_cert_new">Certificate file</label>
- </div>
- <div class="row column file__upload add-certificate__section ">
- <label for='upload_cert_new'>
- <input name="upload_cert_new" id="upload_cert_new" type="file" file="newCertificate.file" class="hide" />
- <span class="btn btn-secondary select__new-button">Choose file</span>
- </label>
- </div>
- <div class="row column add-certificate__section ">
- <div ng-if="newCertificate.file" class="small-7 file__name">
- <span>{{newCertificate.file.name}}</span>
- <icon file="icon-close.svg" ng-if="newCertificate.file.name" ng-click="newCertificate.file = '';" class="float-right"></icon>
- </div>
- </div>
- </div>
- </div>
- <div class="modal__button-wrapper">
- <button class="btn btn-secondary" ng-click="addCertificateModal = false; newCertificate={};add__cert__form.$setUntouched();">Cancel</button>
- <button class="btn btn-primary" ng-disabled="add__cert__form.$invalid || !newCertificate.file" ng-click="submitted = true; uploadCertificate();">Save</button>
- </div>
- </form>
- </section>
-
- <section class="modal add-csr__modal" aria-hidden="true" role="dialog" ng-class="{'active': addCSRModal}">
- <!--Close button for displaying CSR Code, we need a close button within form to reset form validation correctly-->
- <button class="certificate__close-modal" ng-click="resetCSRModal();" ng-if="displayCSRCode==true">
- <icon aria-hidden="true" file="icon-close.svg">
- </button>
-
- <!-- CSR Code display content-->
-
- <div ng-if="displayCSRCode==true">
- <h2 class="page-header">Certificate Signing Request (CSR)</h2>
- <div class="modal__content add-csr__container">
- <span id="csrCode" class="add-csr__container-csr-code">{{csrCode}}</span>
- </div>
- <div class="modal__button-wrapper">
- <button class="btn btn-secondary" clipboard text="csrCode" on-copied="copySuccess(event)" on-error="copyfailed(err)">
- <span ng-if="!copied">Copy</span>
- <span ng-if="copied">
- <icon aria-hidden="true" file="icon-check.svg"></icon>
- <span>Copied</span>
- </span>
- </button>
- <button class="btn btn-primary" ng-click="addCSRModal = false;">
- <a ng-href="data:text/json;charset=utf-8,{{csrCode}}" download="csrCode.txt" class="add-csr__text-download">
- Download</a>
- </button>
+ <div ng-repeat="certificate in certificates">
+ <certificate cert="certificate" reload="loadCertificates()"></certificate>
</div>
-
</div>
-
-
-
- <form name="add__csr__form" id="add__csr__form" novalidate ng-if="displayCSRCode==false">
- <div class="modal__content add-csr__container">
- <button class="certificate__close-modal" ng-click="resetCSRModal(); add__csr__form.$setUntouched()">
- <icon aria-hidden="true" file="icon-close.svg">
- </button>
- <h2 class="page-header">Generate a Certificate Signing Request (CSR)</h2>
- <div class="row">
- <fieldset class="column medium-8 add-csr__section">
- <legend class="add-csr__section-title">General</legend>
- <div class="row">
- <div class="column medium-6">
- <label for="cert__type" class="add-csr__label">Certificate Type *</label>
- <select class="add-csr__select" id="cert__type" name="cert__type" ng-model="newCSR.certificateCollection" required>
- <option class="courier-bold" ng-value="default" ng-model="selectOption">Select an option</option>
- <!-- Do not show CA certificate as an option. Only a certificate authority can generate a CA certificate (known as TrustStore Certificate in Redfish) -->
- <option class="courier-bold" ng-value="type" ng-repeat="type in allCertificateTypes" ng-if="type.Description !== 'TrustStore Certificate'">
- {{type.name}}</option>
- </select>
- <div ng-messages="add__csr__form.cert__type.$error" class="form-error" ng-class="{'visible' : add__csr__form.cert__type.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
- <div class="column medium-6">
- <label for="countryCode" class="add-csr__label">Country *</label>
- <select class="add-csr__select" id="countryCode" name="countryCode" ng-model="newCSR.countryCode" required>
- <option class="courier-bold" ng-value="" ng-model="selectOption">Select an option</option>
- <option class="courier-bold" ng-value="country" ng-repeat="country in countryList">{{country.Name}}
- </option>
- </select>
- <div ng-messages="add__csr__form.countryCode.$error" class="form-error" ng-class="{'visible' : add__csr__form.countryCode.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- <div class="column medium-6">
- <label for="state" class="add-csr__label">State *</label>
- <input class="add-csr__input" ng-model="newCSR.state" type="text" id="state" name="state" required></input>
- <div ng-messages="add__csr__form.state.$error" class="form-error" ng-class="{'visible' : add__csr__form.state.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- <div class="column medium-6">
- <label for="city" class="add-csr__label">City *</label>
- <input class="add-csr__input" id="city" name="city" ng-model="newCSR.city" type="text" required></input>
- <div ng-messages="add__csr__form.city.$error" class="form-error" ng-class="{'visible' : add__csr__form.city.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- <div class="column medium-6">
- <label for="companyName" class="add-csr__label">Company Name *</label>
- <input class="add-csr__input" type="text" ng-model="newCSR.organization" id="companyName" name="companyName" required></input>
- <div ng-messages="add__csr__form.companyName.$error" class="form-error" ng-class="{'visible' : add__csr__form.companyName.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- <div class="column medium-6">
- <label for="companyUnit" class="add-csr__label">Company Unit *</label>
- <input class="add-csr__input" ng-model="newCSR.companyUnit" name="companyUnit" id="companyUnit" type="text" required></input>
- <div ng-messages="add__csr__form.companyUnit.$error" class="form-error" ng-class="{'visible' : add__csr__form.companyUnit.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- <div class="column medium-6">
- <label for="commonName" class="add-csr__label">Common Name *</label>
- <input class="add-csr__input" ng-model="newCSR.commonName" name="commonName" type="text" id="commonName" required></input>
- <div ng-messages="add__csr__form.commonName.$error" class="form-error" ng-class="{'visible' : add__csr__form.commonName.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- <div class="column medium-6">
- <label for="challengePassword" class="add-csr__label">Challenge Password</label>
- <input class="add-csr__input-no-validation" id="challengePassword" ng-model="newCSR.challengePassword" type="text"></input>
- </div>
-
- <div class="column medium-6">
- <label for="contactPerson" class="add-csr__label">Contact Person</label>
- <input class="add-csr__input-no-validation" id="contactPerson" ng-model="newCSR.contactPerson" type="text"></input>
- </div>
-
- <div class="column medium-6">
- <label for="emailAddress" class="add-csr__label">Email Address</label>
- <input class="add-csr__input-no-validation" id="emailAddress" ng-model="newCSR.emailAddress" type="text"></input>
- </div>
-
- <div class="column medium-6">
- <div>
- <label id="alternate-name-label" for="alternateName" class="add-csr__label">Alternate Name</label>
- <input class="add-csr__input-no-validation" ng-model="newCSR.firstAlternativeName" id="alternateName" name="alternativeName"
- type="text"></input>
- </div>
- <div class="add-csr__additional-alt-names" ng-repeat="name in names">
- <input id="alternate-name-input-{{$index}}" aria-describedby="alternate-name-label" class="add-csr__input-no-validation"
- ng-model="name.Value" type="text"></input>
- <button aria-label="Delete alternate name field" aria-controls="alternate-name-input-{{$index}}" class="btn btn-tertiary add-csr__alt-name-delete-btn"
- ng-click="deleteOptionalRow($index)" ng-disabled="multiSelected">
- <icon aria-hidden="true" file="icon-trashcan.svg">
- </button>
- </div>
- </div>
-
- <div class="column medium-6">
- <button class="btn btn-tertiary add-csr__alt-name-add-btn" ng-click="addOptionalRow()">
- <icon file="icon-plus.svg"></icon>
- Add another alternate name
- </button>
- </div>
- </div>
- </fieldset>
-
- <fieldset class="column medium-4 add-csr__section add-csr__section--border ">
- <legend class="add-csr__section-title">Private key</legend>
- <div class="add-csr__container-private-key">
- <div class="add-csr__content-private-key">
- <label for="keyPairAlgorithm" class="add-csr__label">Key Pair Algorithm *</label>
- <select class="add-csr__select" ng-model="newCSR.keyPairAlgorithm" id="keyPairAlgorithm" name="keyPairAlgorithm" required>
- <option class="courier-bold" ng-value="" ng-model="selectOption">Select an option</option>
- <option class="courier-bold" ng-value="data" ng-repeat="data in keyPairAlgorithm">{{data}}</option>
- </select>
- <div ng-messages="add__csr__form.keyPairAlgorithm.$error" class="form-error" ng-class="{'visible' : add__csr__form.keyPairAlgorithm.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
-
- <div ng-if="newCSR.keyPairAlgorithm == 'EC'">
- <label for="keyCurveId" class="add-csr__label">Key Curve ID</label>
- <select class="add-csr__select" ng-model="newCSR.keyCurveId" id="keyCurveId" name="keyCurveId" required>
- <option class="courier-bold" ng-value="">None</option>
- <option class="courier-bold" ng-value="data" ng-repeat="data in keyCurveId">{{data}}</option>
- </select>
- <div ng-messages="add__csr__form.keyCurveId.$error" class="form-error" ng-class="{'visible' : add__csr__form.keyCurveId.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
-
- <div ng-if="newCSR.keyPairAlgorithm =='RSA'">
- <label for="keyBitLength" class="add-csr__label">Key Bit Length *</label>
- <select class="add-csr__select" ng-model="newCSR.keyBitLength" id="keyBitLength" name="keyBitLength" required>
- <option class="courier-bold" ng-value="">Select an option</option>
- <option class="courier-bold" ng-value="data" ng-repeat="data in keyBitLength">{{data}}</option>
- </select>
- <div ng-messages="add__csr__form.keyBitLength.$error" class="form-error" ng-class="{'visible' : add__csr__form.keyBitLength.$touched}">
- <p ng-message="required">Field is required</p>
- </div>
- </div>
-
- </div>
- </fieldset>
- </div>
- </div>
- <div class="modal__button-wrapper">
- <button class="btn btn-secondary" ng-click="resetCSRModal();add__csr__form.$setUntouched();">Cancel</button>
- <button class="btn btn-primary" ng-click="csrSubmitted = true; getCSRCode();add__csr__form.$setUntouched();" ng-disabled="add__csr__form.$invalid">Generate CSR</button>
- </div>
- </div>
- </form>
</section>
- <div class="modal-overlay" tabindex="-1" ng-class="{'active': addCertificateModal || addCSRModal}"></div> \ No newline at end of file
+</div>
diff --git a/app/access-control/controllers/certificate-controller.js b/app/access-control/controllers/certificate-controller.js
index 8c2992a..ad9a060 100644
--- a/app/access-control/controllers/certificate-controller.js
+++ b/app/access-control/controllers/certificate-controller.js
@@ -9,27 +9,22 @@
window.angular && (function(angular) {
'use strict';
- angular.module('app.accessControl').controller('certificateController', [
- '$scope', 'APIUtils', '$q', 'Constants', 'toastService',
- function($scope, APIUtils, $q, Constants, toastService) {
+ angular.module('app.configuration').controller('certificateController', [
+ '$scope', 'APIUtils', '$q', 'Constants', 'toastService', '$timeout',
+ '$uibModal',
+ function(
+ $scope, APIUtils, $q, Constants, toastService, $timeout, $uibModal) {
$scope.loading = false;
$scope.certificates = [];
$scope.availableCertificateTypes = [];
$scope.allCertificateTypes = Constants.CERTIFICATE_TYPES;
- $scope.addCertificateModal = false;
- $scope.addCSRModal = false;
$scope.newCertificate = {};
$scope.newCSR = {};
- $scope.submitted = false;
- $scope.csrSubmitted = false;
- $scope.csrCode = '';
- $scope.displayCSRCode = false;
$scope.keyBitLength = Constants.CERTIFICATE.KEY_BIT_LENGTH;
$scope.keyPairAlgorithm = Constants.CERTIFICATE.KEY_PAIR_ALGORITHM;
$scope.keyCurveId = Constants.CERTIFICATE.KEY_CURVE_ID;
$scope.countryList = Constants.COUNTRIES;
-
$scope.$on('$viewContentLoaded', () => {
getBmcTime();
})
@@ -70,7 +65,6 @@ window.angular && (function(angular) {
toastService.error('Certificate must be a .pem file.');
return;
}
- $scope.addCertificateModal = false;
APIUtils
.addNewCertificate(
$scope.newCertificate.file, $scope.newCertificate.selectedType)
@@ -131,7 +125,6 @@ window.angular && (function(angular) {
}
};
-
// create a CSR object to send to the backend
$scope.getCSRCode = function() {
var addCSR = {};
@@ -143,7 +136,6 @@ window.angular && (function(angular) {
alternativeNames.push($scope.newCSR.firstAlternativeName) :
$scope.newCSR.firstAlternativeName = '';
-
addCSR.CertificateCollection = {
'@odata.id': $scope.newCSR.certificateCollection.location
};
@@ -163,21 +155,72 @@ window.angular && (function(angular) {
APIUtils.createCSRCertificate(addCSR).then(
function(data) {
- $scope.displayCSRCode = true;
$scope.csrCode = data;
+ openDownloadCsrModal();
},
function(error) {
- $scope.addCSRModal = false;
toastService.error('Unable to generate CSR. Try again.');
console.log(JSON.stringify(error));
})
};
+ function openDownloadCsrModal() {
+ const modalTemplateCsrDownload =
+ require('./certificate-modal-csr-download.html');
+ $uibModal
+ .open({
+ template: modalTemplateCsrDownload,
+ windowTopClass: 'uib-modal',
+ scope: $scope,
+ ariaLabelledBy: 'modal_label',
+ size: 'lg',
+ })
+ .result.catch(function() {
+ resetCSRModal();
+ });
+ };
+
+ $scope.addCertModal = function() {
+ openAddCertModal();
+ };
+
+ function openAddCertModal() {
+ const modalTemplateAddCert =
+ require('./certificate-modal-add-cert.html');
+ $uibModal
+ .open({
+ template: modalTemplateAddCert,
+ windowTopClass: 'uib-modal',
+ scope: $scope,
+ ariaLabelledBy: 'modal_label',
+ })
+ .result.catch(function() {
+ // do nothing
+ });
+ };
+
+ $scope.addCsrModal = function() {
+ openCsrModal();
+ };
+
+ function openCsrModal() {
+ const modalTemplateCsrGen = require('./certificate-modal-csr-gen.html');
+ $uibModal
+ .open({
+ template: modalTemplateCsrGen,
+ windowTopClass: 'uib-modal',
+ scope: $scope,
+ ariaLabelledBy: 'modal_label',
+ size: 'lg',
+ })
+ .result.catch(function() {
+ resetCSRModal();
+ });
+ };
+
// resetting the modal when user clicks cancel/closes the
// modal
- $scope.resetCSRModal = function() {
- $scope.addCSRModal = false;
- $scope.displayCSRCode = false;
+ const resetCSRModal = function() {
$scope.newCSR.certificateCollection = $scope.selectOption;
$scope.newCSR.commonName = '';
$scope.newCSR.contactPerson = '';
diff --git a/app/access-control/controllers/certificate-modal-add-cert.html b/app/access-control/controllers/certificate-modal-add-cert.html
new file mode 100644
index 0000000..208bf1b
--- /dev/null
+++ b/app/access-control/controllers/certificate-modal-add-cert.html
@@ -0,0 +1,86 @@
+<div class="uib-modal__content">
+ <div class="modal-header">
+ <h2 class="modal-title" id="modal_label">
+ Add new certificate
+ </h2>
+ <button
+ type="button"
+ class="btn btn--close"
+ ng-click="$dismiss()"
+ aria-label="close">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ <form
+ name="addCertForm"
+ id="addCertForm"
+ ng-class="{'submitted': submitted}">
+ <div class="modal-body">
+ <div class="form__field">
+ <label class="content-label" for="certType">Certificate type</label>
+ <select
+ class="cert-dropdown"
+ id="certType"
+ name="certType"
+ ng-model="newCertificate.selectedType"
+ required>
+ <option class="courier-bold" ng-value="">Select an option</option>
+ <option
+ class="courier-bold"
+ ng-value="type"
+ ng-repeat="type in availableCertificateTypes">
+ {{ type.name }}
+ </option>
+ </select>
+ <div
+ ng-messages="addCertForm.certType.$error"
+ class="form-error"
+ ng-class="{'visible' : addCertForm.certType.$touched || submitted }">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="content-label form__field">Certificate file</div>
+ <div class="file-upload">
+ <label
+ for="upload_cert_new"
+ class="file-upload-btn btn btn-secondary"
+ tabindex="0">
+ Choose file
+ </label>
+ <input
+ name="uploadCertNew"
+ id="upload_cert_new"
+ type="file"
+ file="newCertificate.file"
+ class="file-upload-input"/>
+ <div class="form__field file-upload-container">
+ <span ng-hide="newCertificate.file">No file selected</span>
+ <span>{{ newCertificate.file.name }}</span>
+ <button
+ type="reset"
+ class="btn file-upload-reset"
+ ng-if="newCertificate.file.name"
+ ng-click="newCertificate.file = '';"
+ aria-label="remove selected file">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button
+ type="button"
+ class="btn btn-secondary"
+ ng-click="$dismiss(); addCertForm.$setUntouched();">
+ Cancel
+ </button>
+ <button
+ type="submit"
+ class="btn btn-primary"
+ ng-click="submitted = true; uploadCertificate(); $dismiss()"
+ ng-disabled="addCertForm.$invalid || !newCertificate.file">
+ Save
+ </button>
+ </div>
+ </form>
+</div>
diff --git a/app/access-control/controllers/certificate-modal-csr-download.html b/app/access-control/controllers/certificate-modal-csr-download.html
new file mode 100644
index 0000000..6e31426
--- /dev/null
+++ b/app/access-control/controllers/certificate-modal-csr-download.html
@@ -0,0 +1,41 @@
+<div class="uib-modal__content">
+ <div class="modal-header">
+ <h2 class="modal-title" id="modal_label">
+ Certificate Signing Request (CSR)
+ </h2>
+ <button
+ type="button"
+ class="btn btn--close"
+ ng-click="$dismiss()"
+ aria-label="close">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ <div class="modal-body">
+ <span id="csrCode" class="add-csr__container-csr-code">{{ csrCode }}</span>
+ </div>
+ <div class="modal-footer">
+ <button
+ type="button"
+ class="btn btn-secondary"
+ clipboard
+ text="csrCode"
+ on-copied="copySuccess(event)"
+ on-error="copyfailed(err)">
+ <span ng-if="!copied">Copy</span>
+ <span ng-if="copied">
+ <icon aria-hidden="true" file="icon-check.svg"></icon>
+ <span>Copied</span>
+ </span>
+ </button>
+ <button
+ type="button"
+ class="btn btn-primary">
+ <a ng-href="data:text/json;charset=utf-8,{{ csrCode }}"
+ download="csrCode.txt"
+ class="add-csr__text-download">
+ Download
+ </a>
+ </button>
+ </div>
+ </div> \ No newline at end of file
diff --git a/app/access-control/controllers/certificate-modal-csr-gen.html b/app/access-control/controllers/certificate-modal-csr-gen.html
new file mode 100644
index 0000000..bde00cf
--- /dev/null
+++ b/app/access-control/controllers/certificate-modal-csr-gen.html
@@ -0,0 +1,351 @@
+<div class="uib-modal__content">
+ <div class="modal-header">
+ <h2 class="modal-title" id="modal_label">
+ Generate a Certificate Signing Request (CSR)
+ </h2>
+ <button
+ type="button"
+ class="btn btn--close"
+ ng-click="$dismiss()"
+ aria-label="close">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ <form name="addCsrForm" id="addCsrForm" novalidate>
+ <div class="modal-body">
+ <div class="row">
+ <fieldset class="column large-8 add-csr__section">
+ <legend class="content-label">General</legend>
+ <div class="row">
+ <div class="column large-6">
+ <label for="certType" class="content-label">
+ Certificate Type *
+ </label>
+ <select
+ class="add-csr__select"
+ id="certType"
+ name="certType"
+ ng-model="newCSR.certificateCollection"
+ required>
+ <option
+ class="courier-bold"
+ ng-value="default"
+ ng-model="selectOption">
+ Select an option
+ </option>
+ <!-- Do not show CA certificate as an option.
+ Only a certificate authority can generate a CA certificate
+ (known as TrustStore Certificate in Redfish) -->
+ <option
+ class="courier-bold"
+ ng-value="type"
+ ng-repeat="type in allCertificateTypes"
+ ng-if="type.Description !== 'TrustStore Certificate'">
+ {{ type.name }}
+ </option>
+ </select>
+ <div
+ ng-messages="addCsrForm.certType.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.certType.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="countryCode" class="content-label">Country *</label>
+ <select
+ class="add-csr__select"
+ id="countryCode"
+ name="countryCode"
+ ng-model="newCSR.countryCode"
+ required>
+ <option
+ class="courier-bold"
+ ng-value=""
+ ng-model="selectOption">
+ Select an option
+ </option>
+ <option
+ class="courier-bold"
+ ng-value="country"
+ ng-repeat="country in countryList">
+ {{ country.Name }}
+ </option>
+ </select>
+ <div
+ ng-messages="addCsrForm.countryCode.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.countryCode.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="state" class="content-label">State *</label>
+ <input
+ class="add-csr__input"
+ ng-model="newCSR.state"
+ type="text"
+ id="state"
+ name="state"
+ required/>
+ <div
+ ng-messages="addCsrForm.state.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.state.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="city" class="content-label">City *</label>
+ <input
+ class="add-csr__input"
+ id="city"
+ name="city"
+ ng-model="newCSR.city"
+ type="text"
+ required/>
+ <div
+ ng-messages="addCsrForm.city.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.city.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="companyName" class="content-label">
+ Company Name *
+ </label>
+ <input
+ class="add-csr__input"
+ type="text"
+ ng-model="newCSR.organization"
+ id="companyName"
+ name="companyName"
+ required/>
+ <div
+ ng-messages="addCsrForm.companyName.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.companyName.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="companyUnit" class="content-label">
+ Company Unit *
+ </label>
+ <input
+ class="add-csr__input"
+ ng-model="newCSR.companyUnit"
+ name="companyUnit"
+ id="companyUnit"
+ type="text"
+ required/>
+ <div
+ ng-messages="addCsrForm.companyUnit.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.companyUnit.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="commonName" class="content-label">
+ Common Name *
+ </label>
+ <input
+ class="add-csr__input"
+ ng-model="newCSR.commonName"
+ name="commonName"
+ type="text"
+ id="commonName"
+ required/>
+ <div
+ ng-messages="addCsrForm.commonName.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.commonName.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div class="column large-6">
+ <label for="challengePassword" class="content-label">
+ Challenge Password
+ </label>
+ <input
+ class="add-csr__input-no-validation"
+ id="challengePassword"
+ ng-model="newCSR.challengePassword"
+ type="text"/>
+ </div>
+ <div class="column large-6">
+ <label for="contactPerson" class="content-label">
+ Contact Person
+ </label>
+ <input
+ class="add-csr__input-no-validation"
+ id="contactPerson"
+ ng-model="newCSR.contactPerson"
+ type="text"/>
+ </div>
+ <div class="column large-6">
+ <label for="emailAddress" class="content-label">
+ Email Address
+ </label>
+ <input
+ class="add-csr__input-no-validation"
+ id="emailAddress"
+ ng-model="newCSR.emailAddress"
+ type="text"/>
+ </div>
+ <div class="column large-6">
+ <label
+ id="alternate-name-label"
+ for="alternateName"
+ class="content-label">
+ Alternate Name
+ </label>
+ <input
+ class="add-csr__input-no-validation"
+ ng-model="newCSR.firstAlternativeName"
+ id="alternateName"
+ name="alternativeName"
+ type="text"/>
+ <div
+ class="add-csr__additional-alt-names"
+ ng-repeat="name in names">
+ <input
+ id="alternate-name-input-{{ $index }}"
+ aria-describedby="alternate-name-label"
+ class="add-csr__input-no-validation"
+ ng-model="name.Value"
+ type="text"/>
+ <button
+ aria-label="Delete alternate name field"
+ aria-controls="alternate-name-input-{{ $index }}"
+ class="btn btn-tertiary add-csr__alt-name-delete-btn"
+ ng-click="deleteOptionalRow($index)"
+ ng-disabled="multiSelected">
+ <icon aria-hidden="true" file="icon-trashcan.svg"></icon>
+ </button>
+ </div>
+ </div>
+ <div class="column large-6">
+ <button
+ class="btn btn-tertiary add-csr__alt-name-add-btn"
+ ng-click="addOptionalRow()">
+ <icon file="icon-plus.svg" aria-hidden="true"></icon>
+ Add another alternate name
+ </button>
+ </div>
+ </div>
+ </fieldset>
+ <fieldset
+ class="column medium-12 large-4 add-csr__section add-csr__section--border">
+ <legend class="content-label">Private key</legend>
+ <div class="add-csr__container-private-key">
+ <div class="add-csr__container-private-key">
+ <label for="keyPairAlgorithm" class="content-label">
+ Key Pair Algorithm *
+ </label>
+ <select
+ class="add-csr__select"
+ ng-model="newCSR.keyPairAlgorithm"
+ id="keyPairAlgorithm"
+ name="keyPairAlgorithm"
+ required>
+ <option
+ class="courier-bold"
+ ng-value=""
+ ng-model="selectOption">
+ Select an option
+ </option>
+ <option
+ class="courier-bold"
+ ng-value="data"
+ ng-repeat="data in keyPairAlgorithm">
+ {{ data }}
+ </option>
+ </select>
+ <div
+ ng-messages="addCsrForm.keyPairAlgorithm.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.keyPairAlgorithm.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ <div ng-if="newCSR.keyPairAlgorithm == 'EC'">
+ <div class="large-12">
+ <label for="keyCurveId" class="content-label">
+ Key Curve ID
+ </label>
+ <select
+ class="add-csr__select"
+ ng-model="newCSR.keyCurveId"
+ id="keyCurveId"
+ name="keyCurveId"
+ required>
+ <option class="courier-bold" ng-value="">None</option>
+ <option
+ class="courier-bold"
+ ng-value="data"
+ ng-repeat="data in keyCurveId">
+ {{ data }}
+ </option>
+ </select>
+ <div
+ ng-messages="addCsrForm.keyCurveId.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.keyCurveId.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ </div>
+ <div ng-if="newCSR.keyPairAlgorithm =='RSA'">
+ <div class="large-12">
+ <label for="keyBitLength" class="content-label">
+ Key Bit Length *
+ </label>
+ <select
+ class="add-csr__select"
+ ng-model="newCSR.keyBitLength"
+ id="keyBitLength"
+ name="keyBitLength"
+ required>
+ <option class="courier-bold" ng-value="">
+ Select an option
+ </option>
+ <option
+ class="courier-bold"
+ ng-value="data"
+ ng-repeat="data in keyBitLength">
+ {{ data }}
+ </option>
+ </select>
+ <div
+ ng-messages="addCsrForm.keyBitLength.$error"
+ class="form-error"
+ ng-class="{'visible' : addCsrForm.keyBitLength.$touched}">
+ <p ng-message="required">Field is required</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button
+ type="reset"
+ class="btn btn-secondary"
+ ng-click="$dismiss()">
+ Cancel
+ </button>
+ <button
+ type="submit"
+ class="btn btn-primary"
+ ng-click="getCSRCode();addCsrForm.$setUntouched();$dismiss()"
+ ng-disabled="addCsrForm.$invalid">
+ Generate CSR
+ </button>
+ </div>
+ </form>
+ </div>
+</div>
diff --git a/app/access-control/styles/certificate.scss b/app/access-control/styles/certificate.scss
index a7c57f2..2d882f4 100644
--- a/app/access-control/styles/certificate.scss
+++ b/app/access-control/styles/certificate.scss
@@ -1,7 +1,7 @@
+// TODO: replace cert table with table component
.certificate__table {
border-left: 1px solid $border-color-01;
border-right: 1px solid $border-color-01;
- margin-top: 0.5em;
.table__row-header {
width: 100%;
border-bottom: 1px solid $border-color-01;
@@ -104,60 +104,22 @@
padding: 0.8em 0.8em 0.8em 1.5em;
}
.upload__certificate {
- border-top: 1px solid $border-color-01;
width: 100%;
background: $background-02;
- padding: 0.8em;
- }
-}
-.certificate__upload-chooser {
- background: $background-02;
-}
-
-
-.certificate__close-modal {
- float: right;
- position: relative;
- bottom: 1rem;
- left: 2rem;
-}
-.certificate__table__icon {
- margin-left: 1.5em;
- margin-bottom: .4em;
-}
-
-.add__certificate__modal {
- select {
- margin-bottom: 0;
- }
- .file__upload {
- margin-bottom: 2em;
- }
- .select__new-label {
- margin-bottom: 1em;
- }
- .select__new-button {
- font-size: 1.2em;
+ padding: 0.8em 1.8em 0.8em 0.8em;
+ height: 4rem;
+ display: flex;
}
- .file__name {
- background-color: $background-02;
- padding: 0.5em;
+ .replace-btn {
+ margin-left: auto;
}
}
-.add-certificate__section {
- padding-left: 0;
-}
-
-// Combinator needed to match specificity
-// of default modal settings
-.modal.add-csr__modal {
- width: 100%;
- max-height: 100vh;
- overflow-y: auto;
- z-index: 1001;
+.cert-dropdown{
+ margin-bottom: 0;
}
+// TODO: Update CSR modal with global form-field styles
.add-csr__section:first-of-type {
padding-left: 0;
}
@@ -171,11 +133,6 @@
}
}
-.add-csr__section-title {
- margin-bottom: 1rem;
- font-weight: 700;
-}
-
.add-csr__section--border {
@media (min-width: 640px) {
padding-left: 2rem;
@@ -183,11 +140,6 @@
}
}
-.add-csr__label {
- white-space: nowrap;
- display: inline-block;
-}
-
.add-csr__text-helper {
color: $base-02--02;
font-weight: 400;
@@ -224,10 +176,8 @@ input.add-csr__input-no-validation {
}
.add-csr__alt-name-delete-btn {
- width: 20px;
- height: 30px;
- padding: 0;
-
+ height: 34px;
+ padding: 0 0 0 1rem;
icon {
margin-right: 0;
}
diff --git a/app/common/directives/certificate.html b/app/common/directives/certificate.html
index 1a7d091..cf7b46d 100644
--- a/app/common/directives/certificate.html
+++ b/app/common/directives/certificate.html
@@ -1,4 +1,5 @@
-<div class="table__row-value row column">
+<!-- TODO: Replace table with resusable table component -->
+<div class="table__row-value row">
<div class="certificate__type-cell bold">
{{getCertificateName(cert.Description)}}
</div>
@@ -39,35 +40,55 @@
{{cert.ValidNotAfter | date:medium}}
</div>
<div class="certificate__buttons-cell">
- <button type="button" ng-click="cert.upload = true" aria-label="Replace certificate" class="btn btn-tertiary certificate__button">
+ <button
+ type="button"
+ ng-click="cert.upload = true"
+ aria-label="Replace certificate"
+ class="btn btn-tertiary certificate__button">
<icon file="icon-replace.svg" aria-hidden="true"></icon>
</button>
</div>
<div ng-show="cert.upload === true" class="upload__certificate">
- <div class="certificate__upload-chooser row">
- <div class="small-1 column">
- <button type="button" ng-click="cert.upload=false" aria-label="close replace certificate upload form">
- <icon file="icon-close.svg" aria-hidden="true"></icon>
- </button>
- </div>
- <div class="small-2 column">
- <label>
- <input id="upload_{{cert.Description + cert.Id}}" type="file" file="cert.file" class="input-file" />
- <span class="btn btn-secondary">Choose file</span>
- </label>
- </div>
- <div class="small-6 column">
- <span ng-if="!cert.file">No file selected</span>
- <span>{{cert.file.name}}</span>
- <button type="reset" ng-if="cert.file.name" ng-click="cert.file = '';" aria-label="remove selected file">
- <icon file="icon-close.svg" aria-hidden="true"></icon>
- </button>
- </div>
- <div class="small-3 column">
- <button type="submit" ng-class="{disabled:!cert.file}" class="btn btn-primary" ng-click="replaceCertificate(cert)">
- Replace
- </button>
- </div>
+ <div class="close-btn">
+ <button
+ type="button"
+ ng-click="cert.upload=false"
+ aria-label="close replace certificate upload form">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ <div class="file-upload">
+ <label
+ for="upload_{{ cert.Description + cert.Id }}"
+ class="file-upload-btn btn btn-secondary"
+ tabindex="0">Choose file</label>
+ <input
+ name="upload_{{ cert.Description + cert.Id }}"
+ id="upload_{{ cert.Description + cert.Id }}"
+ type="file"
+ file="cert.file"
+ class="file-upload-input"/>
+ </div>
+ <div class="file-upload-container file-upload-field">
+ <span ng-if="!cert.file">No file selected</span>
+ <span>{{ cert.file.name }}</span>
+ <button
+ type="reset"
+ class="btn file-upload-reset"
+ ng-if="cert.file.name"
+ ng-click="cert.file = '';"
+ aria-label="remove selected file">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ <div class="replace-btn">
+ <button
+ type="submit"
+ ng-disabled="!cert.file"
+ class="btn btn-primary"
+ ng-click="replaceCertificate(cert)">
+ Replace
+ </button>
</div>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/app/common/styles/elements/file-upload.scss b/app/common/styles/elements/file-upload.scss
new file mode 100644
index 0000000..4704d6d
--- /dev/null
+++ b/app/common/styles/elements/file-upload.scss
@@ -0,0 +1,56 @@
+/**
+ * Used for file upload
+ * Markup
+ <div class="file-upload">
+ <label for="upload_cert_new" class="file-upload-btn btn btn-secondary" tabindex="0">Choose file</label>
+ <input
+ name="upload_cert_new"
+ id="upload_cert_new"
+ type="file"
+ file="newCertificate.file"
+ class="file-upload-input"/>
+ <div class="form__field file-upload-container">
+ <span ng-hide="newCertificate.file">No file selected</span>
+ <span>{{ newCertificate.file.name }}</span>
+ <button
+ type="reset"
+ class="btn file-upload-reset"
+ ng-if="newCertificate.file.name"
+ ng-click="newCertificate.file = '';"
+ aria-label="remove selected file">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ </div>
+*/
+
+// Choose/upload button
+.file-upload-input {
+ width: 1px;
+ height: 1px;
+ opacity: 0;
+ overflow: hidden;
+ position: absolute;
+ z-index: -1;
+}
+
+.file-upload-input:focus {
+ outline: 0.2rem solid $base-02--04;
+}
+
+// File name of uploaded file field
+.file-upload-container {
+ background: $background-02;
+ padding: 0.5rem;
+ span {
+ padding-left: .5rem;
+ }
+ .file-upload-reset {
+ float: right;
+ margin-top: -.5rem;
+ icon {
+ margin-right: -1.7em;
+ margin-left: -1.5em;
+ }
+ }
+}
diff --git a/app/common/styles/elements/index.scss b/app/common/styles/elements/index.scss
index b1df113..9fee615 100644
--- a/app/common/styles/elements/index.scss
+++ b/app/common/styles/elements/index.scss
@@ -2,7 +2,7 @@
@import "toggle-filter";
@import "alerts";
@import "inline-confirm";
-@import "input-file";
+@import "file-upload";
@import "accordion";
@import "loader";
@import "content-search";
diff --git a/app/common/styles/elements/input-file.scss b/app/common/styles/elements/input-file.scss
deleted file mode 100644
index 3f32b2b..0000000
--- a/app/common/styles/elements/input-file.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Used for file upload "choose file" button
- * Markup (example for certificate upload)
- <label>
- <input
- id="upload_{{cert.Description + cert.Id}}"
- type="file"
- file="cert.file"
- class="input-file" />
- <span class="btn btn-secondary">Choose file</span>
- </label>
-*/
-
-.input-file {
- width: 0.1px;
- height: 0.1px;
- opacity: 0;
- overflow: hidden;
- position: absolute;
- z-index: -1;
-}
-
-.input-file:focus + span {
- outline: 0.2rem solid $box-shadow-color;
-} \ No newline at end of file
diff --git a/app/common/styles/elements/modals.scss b/app/common/styles/elements/modals.scss
index 263d285..3132934 100644
--- a/app/common/styles/elements/modals.scss
+++ b/app/common/styles/elements/modals.scss
@@ -83,9 +83,45 @@
}
}
+/**
+ * Markup for bootstrap modal
+ <div class="uib-modal__content">
+ <div class="modal-header">
+ <h2 class="modal-title" id="modal_label">
+ Title here
+ </h2>
+ <button
+ type="button"
+ class="btn btn--close"
+ ng-click="$dismiss()"
+ aria-label="close">
+ <icon file="icon-close.svg" aria-hidden="true"></icon>
+ </button>
+ </div>
+ <div class="modal-body">
+ Body content
+ </div>
+ <div class="modal-footer">
+ <button
+ type="button"
+ class="btn btn-secondary"
+ ng-click="$dismiss()">
+ Cancel
+ </button>
+ <button
+ type="submit"
+ class="btn btn-primary"
+ ng-click="function()">
+ Save
+ </button>
+ </div>
+ </div>
+*/
+
.uib-modal.fade.in {
opacity: 1;
}
+
.uib-modal.in .modal-dialog {
transform: translate(0, 10vh);
margin-top: 50px;
@@ -99,14 +135,10 @@
}
}
-.uib-modal .modal-dialog {
- // override bootstrap max-width set at 500px
- max-width: 550px;
-}
-
.modal-backdrop.in {
opacity: 0.5;
}
+
.uib-modal__content {
padding: 1em;
.modal-header {
OpenPOWER on IntegriCloud