Fix system overview edit hostname form validation

- Add pattern for no spaces
- Fix character count
- Prepopulate hostname in input field
- Show error for invalid input
- Improve form accessibility
- Correct global disabled primary button style

Resolves openbmc/phosphor-webui#71

Signed-off-by: Dixsie Wolmers <dixsiew@gmail.com>
Change-Id: Ia0601ac7c52229d0606dc5b13397b468fa81426d
diff --git a/app/common/styles/base/buttons.scss b/app/common/styles/base/buttons.scss
index 31b72ff..70b70cc 100644
--- a/app/common/styles/base/buttons.scss
+++ b/app/common/styles/base/buttons.scss
@@ -11,7 +11,6 @@
     cursor: pointer;
   }
   &.disabled {
-    opacity: 0.2;
     color: $btn__disabled-txt;
     &:hover {
       cursor: default;
@@ -30,8 +29,8 @@
     @include fastTransition-all;
   }
   &.disabled {
-    background: $btn__disabled-bg;
-    color: $btn__disabled-txt;
+    background: $primebtn__disabled-bg;
+    color: $primebtn__disabled-txt;
     @include fastTransition-all;
     &:hover {
       cursor: default;
diff --git a/app/common/styles/base/colors.scss b/app/common/styles/base/colors.scss
index 6761967..03e8e19 100644
--- a/app/common/styles/base/colors.scss
+++ b/app/common/styles/base/colors.scss
@@ -12,6 +12,8 @@
 $field__focus: #3C6DEF;
 $btn__disabled-txt: #a6a5a6;
 $btn__disabled-bg: #d8d8d8;
+$primebtn__disabled-txt: #999999;
+$primebtn__disabled-bg: #CCCCCC;
 
 // Dark background
 $darkbg__grey: #E3ECEC;
diff --git a/app/overview/controllers/system-overview-controller.html b/app/overview/controllers/system-overview-controller.html
index 629e0ab..ca128bb 100644
--- a/app/overview/controllers/system-overview-controller.html
+++ b/app/overview/controllers/system-overview-controller.html
@@ -2,7 +2,7 @@
 <div class="overview">
   <div class="row column">
     <h1 class="inline">{{dataService.hostname}}</h1>
-    <button class="link" ng-click="edit_hostname = !edit_hostname">Edit</button><!-- this is default name. Will show custom server name if set -->
+    <button class="link" ng-click="edit_hostname = !edit_hostname">Edit</button>
   </div>
   <section class="row">
     <div class="column large-8">
@@ -21,8 +21,8 @@
             </li>
             <li class="overview__metadata-block">
               <dl>
-                  <dt class="content-label">Manufacturer</dt>
-                  <dd class="courier-bold">{{server_info.Manufacturer}}</dd>
+                <dt class="content-label">Manufacturer</dt>
+                <dd class="courier-bold">{{server_info.Manufacturer}}</dd>
               </dl>
             </li>
             <li class="overview__metadata-block">
@@ -100,24 +100,24 @@
     </div>
     <div class="column large-4 no-padding">
       <div class="quick-links">
-        <a href="#/server-health/event-log/high" class="quick-links__item quick-links__events event-log__events" ng-show="logs.length">
-          <p class="inline quick-links__event-copy">View {{logs.length}} high priority events</p><!-- link to event log filtered to the high priority events -->
+        <a href="#/server-health/event-log/high" class="quick-links__item quick-links__events event-log__events"
+          ng-show="logs.length">
+          <!-- link to event log filtered to the high priority events -->
+          <p class="inline quick-links__event-copy">View {{logs.length}} high priority events</p>
         </a>
         <dl class="quick-links__item no-icon">
           <dt class="inline quick-links__label">BMC time</dt>
           <dd class="inline courier-bold float-right bmc-time">{{ bmc_time | localeDate }}</dd>
         </dl>
         <div class="quick-links__item no-icon">
-          <p class="inline quick-links__label">Turn <span ng-if="dataService.LED_state == 'off'">on</span><span ng-if="dataService.LED_state == 'on'">off</span> server LED</p>
+          <p class="inline quick-links__label">Turn <span ng-if="dataService.LED_state == 'off'">on</span><span
+              ng-if="dataService.LED_state == 'on'">off</span> server LED</p>
           <div class="toggle inline float-right">
-            <input id="toggle__switch-round"
-                class="toggle-switch toggle-switch__round-flat"
-                type="checkbox"
-                tabindex="0"
-                ng-click="toggleLED()"
-                ng-checked="dataService.LED_state == 'on'"
-                ng-disabled="dataService.server_unreachable">
-            <label for="toggle__switch-round" tabindex="0">Server LED is <span class="led-switch__status">{{dataService.LED_state}}</span></label>
+            <input id="toggle__switch-round" class="toggle-switch toggle-switch__round-flat" type="checkbox"
+              tabindex="0" ng-click="toggleLED()" ng-checked="dataService.LED_state == 'on'"
+              ng-disabled="dataService.server_unreachable">
+            <label for="toggle__switch-round" tabindex="0">Server LED is <span
+                class="led-switch__status">{{dataService.LED_state}}</span></label>
           </div>
         </div>
         <a href="#/server-control/remote-console" class="no-icon quick-links__item">
@@ -127,8 +127,8 @@
         <a href="#/configuration/network" class="quick-links__item">
           <p class="inline quick-links__label">Edit network settings</p>
         </a>
-      </d>
-    </div>
+        </d>
+      </div>
   </section>
   <section class="row">
     <div class="column large-12 overview__event-log event-log__events" ng-show="logs.length">
@@ -141,7 +141,8 @@
       <a href="#/server-health/event-log/high" ng-repeat="event in logs|orderBy:'-Id'|limitTo : 5">
         <div class="row column event-log__single-event">
           <div class="row">
-            <div class="column small-9 large-10 event-log__event-info" ng-click=""><!-- click will go to specific event in event log page-->
+            <!-- click will go to specific event in event log page-->
+            <div class="column small-9 large-10 event-log__event-info" ng-click="">
               <p class="inline event__id">#{{event.Id}}</p>
               <p class="inline event__priority high-priority">High</p>
               <p class="inline event__severity high-priority">{{event.severity_code}}</p>
@@ -167,29 +168,40 @@
   </section>
 </div>
 <!-- edit server name modal -->
-<section class="modal" aria-hidden="true" aria-labelledby="modalTitle" aria-describedby="modalDescription" role="dialog" ng-class="{'active': edit_hostname}">
+<section class="modal" aria-hidden="true" aria-labelledby="modalTitle" aria-describedby="modalDescription" role="dialog"
+  ng-class="{'active': edit_hostname}">
   <div class="modal__upload" role="document">
-    <div class="screen-reader-offscreen modal-description">Edit hostname</div><!-- accessibility only; used for screen readers -->
+    <!-- accessibility only; used for screen readers -->
+    <div class="screen-reader-offscreen modal-description">Edit hostname</div>
     <div class="page-header ">
-      <h2 class="modal-title"><span class="icon icon__info"><svg xmlns="http://www.w3.org/2000/svg"
-          viewBox="0 0 32 32"><path
-          d="M18 14h-6v2h1v6h-2v2h8v-2h-2z"/><circle cx="16" cy="10" r="2"/><path
-          d="M16 2C8.269 2 2 8.269 2 16s6.269 14 14 14 14-6.269 14-14S23.731 2 16 2zm0 26C9.383 28 4 22.617 4 16S9.383 4 16 4s12 5.383 12 12-5.383 12-12 12z"/></svg></span>
+      <h2 class="modal-title"><span class="icon icon__info"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
+            <path d="M18 14h-6v2h1v6h-2v2h8v-2h-2z" />
+            <circle cx="16" cy="10" r="2" />
+            <path
+              d="M16 2C8.269 2 2 8.269 2 16s6.269 14 14 14 14-6.269 14-14S23.731 2 16 2zm0 26C9.383 28 4 22.617 4 16S9.383 4 16 4s12 5.383 12 12-5.383 12-12 12z" />
+          </svg></span>
         Edit hostname
       </h2>
     </div>
     <div class="modal__content">
-      <p>The hostname is displayed in the header and can contain any characters up to a total of 64</p>
-      <form>
-        <label for="editServerName" class="hide"></label>
-        <input id="editServerName" class="modal__edit-server-name" maxlength="64" type="text" ng-model="char_count" ng-trim="false">
-        <p class="modal__char-count">{{64 - char_count.length}}/64</p>
+
+      <form name="edit_hostname_text">
+        <label for="editServerName">Hostname</label>
+        <p>Hostname must be less than 64 characters and must not contain spaces.</p>
+        <input id="editServerName" class="modal__edit-server-name" type="text" ng-model="newHostname" ng-trim="false"
+          name="hostname" ng-pattern="/^\S{0,64}$/" required autofocus />
+        <span class="modal__error" ng-show="edit_hostname_text.hostname.$error.pattern">Invalid format.
+          Remove spaces.</span>
+        <span class="modal__char-count"
+          ng-hide="edit_hostname_text.hostname.$error.pattern">{{0 + newHostname.length}}/64</span>
       </form>
     </div>
     <div class="modal__button-wrapper">
-      <button class="inline btn-secondary" ng-click="edit_hostname= false;">Cancel</button>
-      <button class="inline btn-primary" ng-click="saveHostname(char_count);">Save</button>
+      <button class="inline btn-secondary"
+        ng-click="edit_hostname= false; newHostname = dataService.hostname">Cancel</button>
+      <button class="inline btn-primary" ng-click="saveHostname(newHostname);" ng-disabled="edit_hostname_text.$invalid"
+        ng-class="{'disabled' : edit_hostname_text.$invalid}">Save</button>
     </div>
   </div>
 </section>
-<div class="modal-overlay" tabindex="-1" ng-class="{'active': edit_hostname}"></div>
+<div class="modal-overlay" tabindex="-1" ng-class="{'active': edit_hostname}"></div>
\ No newline at end of file
diff --git a/app/overview/controllers/system-overview-controller.js b/app/overview/controllers/system-overview-controller.js
index 0b7d2f0..8d43613 100644
--- a/app/overview/controllers/system-overview-controller.js
+++ b/app/overview/controllers/system-overview-controller.js
@@ -24,6 +24,7 @@
       $scope.bmc_ip_addresses = [];
       $scope.loading = false;
       $scope.edit_hostname = false;
+      $scope.newHostname = '';
 
       loadOverviewData();
 
@@ -103,6 +104,7 @@
               // TODO: openbmc/openbmc#3150 Support IPV6 when
               // officially supported by the backend
               $scope.bmc_ip_addresses = data.formatted_data.ip_addresses.ipv4;
+              $scope.newHostname = data.hostname;
             },
             function(error) {
               console.log(JSON.stringify(error));
diff --git a/app/overview/styles/system-overview.scss b/app/overview/styles/system-overview.scss
index 01b7bc9..6bef6ed 100644
--- a/app/overview/styles/system-overview.scss
+++ b/app/overview/styles/system-overview.scss
@@ -46,8 +46,12 @@
   margin-bottom: 0;
 }
 
-.modal__char-count {
-  text-align: right;
+.modal__char-count,
+.modal__error {
   font-size: .8em;
   color: $darkgrey;
 }
+
+.modal__error {
+  color: $error-color;
+}
\ No newline at end of file