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
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-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>
+        <certificate cert="certificate" reload="loadCertificates()"></certificate>
       </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>
-
-    </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 @@
           toastService.error('Certificate must be a .pem file.');
           return;
         }
-        $scope.addCertificateModal = false;
         APIUtils
             .addNewCertificate(
                 $scope.newCertificate.file, $scope.newCertificate.selectedType)
@@ -131,7 +125,6 @@
         }
       };
 
-
       // create a CSR object to send to the backend
       $scope.getCSRCode = function() {
         var addCSR = {};
@@ -143,7 +136,6 @@
             alternativeNames.push($scope.newCSR.firstAlternativeName) :
             $scope.newCSR.firstAlternativeName = '';
 
-
         addCSR.CertificateCollection = {
           '@odata.id': $scope.newCSR.certificateCollection.location
         };
@@ -163,21 +155,72 @@
 
         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;
+    padding: 0.8em 1.8em 0.8em 0.8em;
+    height: 4rem;
+    display: flex;
   }
-}
-.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;
-  }
-  .file__name {
-    background-color: $background-02;
-    padding: 0.5em;
+  .replace-btn {
+    margin-left: auto;
   }
 }
 
-.add-certificate__section {
-  padding-left: 0;
+.cert-dropdown{
+  margin-bottom: 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;
-}
-
+// 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 @@
 }
 
 .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 {