[Rt-commit] rt branch, 4.6-theme-trunk, updated. rt-4.4.4-181-gf89f5f787

? sunnavy sunnavy at bestpractical.com
Tue Apr 9 20:52:46 EDT 2019


The branch, 4.6-theme-trunk has been updated
       via  f89f5f7876032a4406b0c5fe3ea4666e8685f979 (commit)
       via  87b7ac00251a76c08f3127c75b3f73cb651c2fb2 (commit)
       via  9c4070fcb18bfd84b50f50a1de1c90e31ff3b1cf (commit)
       via  319d7a6813d8e70f04e406754be304413db14d02 (commit)
       via  00ae7e993b5750d6dc6315863fa93e62fb0cac29 (commit)
      from  19983ce0c1cfabd663009ffeb3587adf9efc9e32 (commit)

Summary of changes:
 .../bootstrap-combobox.css                         |  56 +++
 .../bootstrap-combobox-1.2.0/bootstrap-combobox.js | 480 +++++++++++++++++++++
 etc/RT_Config.pm.in                                |   4 +-
 share/html/Elements/AddLinks                       |  12 +-
 share/html/Elements/CreateTicket                   |   4 +-
 share/html/Elements/EditCustomFieldAutocomplete    |   4 +-
 share/html/Elements/EditCustomFieldBinary          |  14 +-
 share/html/Elements/EditCustomFieldDate            |  10 +-
 share/html/Elements/EditCustomFieldDateTime        |   9 +-
 share/html/Elements/EditCustomFieldFreeform        |   4 +-
 share/html/Elements/EditCustomFieldImage           |  14 +-
 share/html/Elements/EditCustomFieldSelect          |  24 +-
 share/html/Elements/EditCustomFieldText            |   2 +-
 share/html/Elements/EditLink                       |  12 +-
 share/html/Elements/EditLinks                      |  36 +-
 share/html/Elements/EditTimeValue                  |   8 +-
 share/html/Elements/EmailInput                     |   1 +
 share/html/Elements/QueueSummaryByLifecycle        |   2 +-
 share/html/Elements/QueueSummaryByStatus           |   2 +-
 share/html/Elements/QuickCreate                    |   6 +-
 share/html/Elements/Refresh                        |   2 +-
 share/html/Elements/RefreshHomepage                |   8 +
 share/html/Elements/SelectAttachmentField          |   2 +-
 share/html/Elements/SelectBoolean                  |   2 +-
 share/html/Elements/SelectCustomFieldOperator      |   2 +-
 share/html/Elements/SelectCustomFieldValue         |   4 +-
 share/html/Elements/SelectDate                     |   2 +-
 share/html/Elements/SelectDateRelation             |   2 +-
 share/html/Elements/SelectDateType                 |   2 +-
 share/html/Elements/SelectEqualityOperator         |   2 +-
 share/html/Elements/SelectGroups                   |  18 +-
 share/html/Elements/SelectIPRelation               |   2 +-
 share/html/Elements/SelectMatch                    |   2 +-
 share/html/Elements/SelectNewTicketQueue           |   2 +-
 share/html/Elements/SelectObject                   |   4 +-
 share/html/Elements/SelectOwnerAutocomplete        |   2 +-
 share/html/Elements/SelectOwnerDropdown            |   2 +-
 share/html/Elements/SelectPriority                 |   2 +-
 share/html/Elements/SelectResultsPerPage           |   2 +-
 share/html/Elements/SelectSLA                      |   2 +-
 share/html/Elements/SelectStatus                   |   2 +-
 share/html/Elements/SelectTimeUnits                |   2 +-
 share/html/Elements/SelectUsers                    |  18 +-
 share/html/Elements/SelectWatcherType              |   2 +-
 share/html/Elements/ShowLinks                      |   4 +-
 share/html/Elements/Submit                         |  12 +-
 share/html/Search/Build.html                       |  43 +-
 share/html/Search/Elements/ConditionRow            |  19 +-
 share/html/Search/Elements/DisplayOptions          |   5 +
 share/html/Search/Elements/EditFormat              | 152 ++++---
 share/html/Search/Elements/EditQuery               |  26 +-
 share/html/Search/Elements/EditSearches            |  43 +-
 share/html/Search/Elements/EditSort                |  51 +--
 share/html/Search/Elements/PickBasics              |   3 +-
 share/html/Search/Elements/PickCriteria            |  15 +-
 share/html/Search/Elements/SelectAndOr             |  10 +-
 share/html/Search/Elements/SelectLinks             |   2 +-
 share/html/Search/Elements/SelectPersonType        |   2 +-
 share/html/Search/Elements/SelectSearchObject      |   2 +-
 .../html/Search/Elements/SelectSearchesForObjects  |   2 +-
 share/html/Ticket/Elements/AddWatchers             | 107 +++--
 share/html/Ticket/Elements/EditBasics              |   2 +-
 share/html/Ticket/Elements/EditDates               |  32 +-
 share/html/Ticket/Elements/EditMerge               |   2 +-
 share/html/Ticket/Elements/EditPeople              |  87 ++--
 share/html/Ticket/Elements/EditWatchers            |  14 +-
 share/html/Ticket/ModifyAll.html                   |  12 +-
 share/html/Ticket/ModifyPeople.html                |  19 +-
 share/html/Widgets/ComboBox                        |  13 +
 share/static/css/base-responsive/forms.css         |   8 +-
 .../css/elevator-light/bootstrap-combobox.css      |  56 +++
 share/static/css/elevator-light/forms.css          |  46 +-
 share/static/css/elevator-light/main.css           |   1 +
 share/static/css/elevator-light/nav.css            |  19 +-
 share/static/css/elevator-light/ticket-search.css  |  39 +-
 share/static/js/bootstrap-combobox.js              | 480 +++++++++++++++++++++
 share/static/js/util.js                            |  12 +
 t/assets/web.t                                     |   6 +-
 78 files changed, 1733 insertions(+), 407 deletions(-)
 create mode 100644 devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.css
 create mode 100644 devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.js
 create mode 100644 share/static/css/elevator-light/bootstrap-combobox.css
 create mode 100644 share/static/js/bootstrap-combobox.js

- Log -----------------------------------------------------------------
commit 00ae7e993b5750d6dc6315863fa93e62fb0cac29
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue Apr 9 02:26:59 2019 +0800

    Migrate search builder for elevator themes

diff --git a/share/html/Elements/EditTimeValue b/share/html/Elements/EditTimeValue
index d1cea05c8..803a3f8cf 100644
--- a/share/html/Elements/EditTimeValue
+++ b/share/html/Elements/EditTimeValue
@@ -45,8 +45,14 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<input name="<% $ValueName %>" type="text" value="<% $Default || '' %>" size="5" />
+<div class="form-row">
+  <div class="col-auto">
+<input name="<% $ValueName %>" type="text" value="<% $Default || '' %>" size="5" class="form-control" />
+  </div>
+  <div class="col-auto">
 <& /Elements/SelectTimeUnits, Name => $UnitName, Default => $InUnits &>
+  </div>
+</div>
 <%ARGS>
 $Default    => ''
 $Name       => ''
diff --git a/share/html/Elements/SelectAttachmentField b/share/html/Elements/SelectAttachmentField
index e8cf5b671..5cc4b841f 100644
--- a/share/html/Elements/SelectAttachmentField
+++ b/share/html/Elements/SelectAttachmentField
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 <option value="Subject"><&|/l&>Subject</&></option>
 % if ( RT->Config->Get('FullTextSearch')->{'Enable'} ) {
 <option value="Content"><&|/l&>Content</&></option>
diff --git a/share/html/Elements/SelectBoolean b/share/html/Elements/SelectBoolean
index 23291ad7c..81b422893 100644
--- a/share/html/Elements/SelectBoolean
+++ b/share/html/Elements/SelectBoolean
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 <option value="<%$TrueVal%>" <%$TrueDefault|n%>><%$True%></option>
 <option value="<%$FalseVal%>" <%$FalseDefault|n%>><%$False%></option>
 </select>
diff --git a/share/html/Elements/SelectCustomFieldOperator b/share/html/Elements/SelectCustomFieldOperator
index db47f2ad1..f200abe5d 100644
--- a/share/html/Elements/SelectCustomFieldOperator
+++ b/share/html/Elements/SelectCustomFieldOperator
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<% $Name %>">
+<select name="<% $Name %>" class="form-contorl selectpicker">
 % while (my $option = shift @Options) {
 % my $value = shift @Values;
 <option value="<% $value %>"
diff --git a/share/html/Elements/SelectCustomFieldValue b/share/html/Elements/SelectCustomFieldValue
index f0c614b0f..9b39e897f 100644
--- a/share/html/Elements/SelectCustomFieldValue
+++ b/share/html/Elements/SelectCustomFieldValue
@@ -49,7 +49,7 @@
 % $Default = "" unless defined $Default;
 % if ($CustomField->Type =~ /Select/i) {
 % my $values = $CustomField->Values;
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 <option value="" selected="selected">-</option>
 <option value="NULL"><&|/l&>(no value)</&></option>
 % while (my $value = $values->Next) {
@@ -72,7 +72,7 @@
 jQuery('#'+'CF-' + <% $CustomField->id %>).autocomplete({ source: <% JSON::to_json(\@options) |n %> });
 </script>
 % } else {
-<input name="<%$Name%>" size="20" value="<% $Default %>" type="text" />
+<input name="<%$Name%>" size="20" value="<% $Default %>" type="text" class="form-control" />
 % }
 <%args>
 $Name => undef
diff --git a/share/html/Elements/SelectDate b/share/html/Elements/SelectDate
index a7958952a..a16f9053b 100644
--- a/share/html/Elements/SelectDate
+++ b/share/html/Elements/SelectDate
@@ -46,7 +46,7 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 % $m->callback( %ARGS, Name => $Name, CallbackName => 'BeforeDateInput', Object => $Object, ARGSRef => $ARGSRef, ShowTimeRef => \$ShowTime, );
-<input type="text" class="datepicker<% $ShowTime ? ' withtime' : '' %>" id="<% $Name %>" name="<% $Name %>" value="<% $Default %>" size="<% $Size %>" autocomplete="off" />
+<input type="text" class="datepicker<% $ShowTime ? ' withtime' : '' %> form-control" id="<% $Name %>" name="<% $Name %>" value="<% $Default %>" size="<% $Size %>" autocomplete="off" />
 % $m->callback( %ARGS, Name => $Name, CallbackName => 'AfterDateInput', Object => $Object, ARGSRef => $ARGSRef, );
 <%init>
 unless ((defined $Default) or ($current <= 0)) {
diff --git a/share/html/Elements/SelectDateRelation b/share/html/Elements/SelectDateRelation
index 9e9214c9d..17c542050 100644
--- a/share/html/Elements/SelectDateRelation
+++ b/share/html/Elements/SelectDateRelation
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 <option value="<"><%$Before%></option>
 <option value="="><%$On%></option>
 <option value=">"><%$After%></option>
diff --git a/share/html/Elements/SelectDateType b/share/html/Elements/SelectDateType
index c94780c7b..60e2979af 100644
--- a/share/html/Elements/SelectDateType
+++ b/share/html/Elements/SelectDateType
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 <option value="Created"><&|/l&>Created</&></option>
 <option value="Started"><&|/l&>Started</&></option>
 <option value="Resolved"><&|/l&>Resolved</&></option>
diff --git a/share/html/Elements/SelectEqualityOperator b/share/html/Elements/SelectEqualityOperator
index 9d3219398..bfb3d7e9a 100644
--- a/share/html/Elements/SelectEqualityOperator
+++ b/share/html/Elements/SelectEqualityOperator
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 % while (my $option = shift @Options) {
 % my $value = shift @Values;
 <option value="<%$value%>"
diff --git a/share/html/Elements/SelectIPRelation b/share/html/Elements/SelectIPRelation
index 73862a256..d9b139245 100644
--- a/share/html/Elements/SelectIPRelation
+++ b/share/html/Elements/SelectIPRelation
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<% $Name %>">
+<select name="<% $Name %>" class="form-control selectpicker">
 % while (my $option = shift @Options) {
 % my $value = shift @Values;
 <option value="<% $value %>"
diff --git a/share/html/Elements/SelectMatch b/share/html/Elements/SelectMatch
index 94cd69e24..7f4a103cd 100644
--- a/share/html/Elements/SelectMatch
+++ b/share/html/Elements/SelectMatch
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="selectpicker form-control">
 <option value="LIKE" <%$LikeDefault|n%>><%$Like%></option>
 <option value="NOT LIKE" <%$NotLikeDefault|n%>><%$NotLike%></option>
 <option value="=" <%$TrueDefault|n%>><%$True%></option>
diff --git a/share/html/Elements/SelectObject b/share/html/Elements/SelectObject
index c6f9f0aca..02b154a52 100644
--- a/share/html/Elements/SelectObject
+++ b/share/html/Elements/SelectObject
@@ -48,7 +48,7 @@
 % if ($Lite) {
 %     my $d = $ObjectType->new($session{'CurrentUser'});
 %     $d->Load($Default);
-<input type="text" name="<%$Name%>" size="25" value="<%$d->Name%>" class="<%$Class%>" />
+<input type="text" name="<%$Name%>" size="25" value="<%$d->Name%>" class="<%$Class%> form-control" />
 % }
 % elsif ($Hyperlink) {
 <ul class="<%$Class%>">
@@ -64,7 +64,7 @@
 </ul>
 % }
 % else {
-<select name="<%$Name%>" <% ($Multiple) ? qq{class="tall" multiple="multiple" size="$Size"} : '' |n%> <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
+<select name="<%$Name%>" <% ($Multiple) ? qq{class="tall" multiple="multiple" size="$Size"} : '' |n%> <% ($OnChange) ?  'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%> selectpicker form-control">
 %     if ($ShowNullOption) {
   <option value=""><% $DefaultLabel %></option>
 %     }
diff --git a/share/html/Elements/SelectOwnerAutocomplete b/share/html/Elements/SelectOwnerAutocomplete
index e2993b207..b47b5c750 100644
--- a/share/html/Elements/SelectOwnerAutocomplete
+++ b/share/html/Elements/SelectOwnerAutocomplete
@@ -74,7 +74,7 @@ my $query = $m->comp('/Elements/QueryString',
 );
 </%INIT>
 
-<input type="text" name="<%$Name%>" id="<%$Name%>" value="<% $value %>" />
+<input type="text" name="<%$Name%>" id="<%$Name%>" value="<% $value %>" class="form-control" />
 <script type="text/javascript">
     jQuery(function() {
         var cache = {};
diff --git a/share/html/Elements/SelectOwnerDropdown b/share/html/Elements/SelectOwnerDropdown
index 33125a0f8..b685df8bd 100644
--- a/share/html/Elements/SelectOwnerDropdown
+++ b/share/html/Elements/SelectOwnerDropdown
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>" id="<%$Name%>">
+<select name="<%$Name%>" id="<%$Name%>" class="selectpicker form-control">
 %if ($DefaultValue) {
 <option value=""<% !$Default ? qq[ selected="selected"] : '' |n %>><%$DefaultLabel |n%></option>
 %}
diff --git a/share/html/Elements/SelectPriority b/share/html/Elements/SelectPriority
index 75c751949..2889b4629 100644
--- a/share/html/Elements/SelectPriority
+++ b/share/html/Elements/SelectPriority
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<input name="<% $Name %>" type="text" value="<% $Default %>" size="5" />
+<input name="<% $Name %>" type="text" value="<% $Default %>" size="5" class="form-control" />
 <%ARGS>
 $Name => 'Priority'
 $Default => ''
diff --git a/share/html/Elements/SelectResultsPerPage b/share/html/Elements/SelectResultsPerPage
index c016835ee..6f5c21ac6 100644
--- a/share/html/Elements/SelectResultsPerPage
+++ b/share/html/Elements/SelectResultsPerPage
@@ -47,7 +47,7 @@
 %# END BPS TAGGED BLOCK }}}
 %# TODO: Better default handling
 
-<select name="<% $Name %>">
+<select name="<% $Name %>" class="form-control selectpicker">
 % foreach my $value ( @values ) {
 <option value="<% $value %>" <% $value == $Default? 'selected="selected"': '' |n%>>
 <% shift @labels %>
diff --git a/share/html/Elements/SelectSLA b/share/html/Elements/SelectSLA
index 93861d508..e4759901d 100644
--- a/share/html/Elements/SelectSLA
+++ b/share/html/Elements/SelectSLA
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>" id="<%$Name%>">
+<select name="<%$Name%>" id="<%$Name%>" class="form-control selectpicker">
 % if ($DefaultValue) {
 <option value=""<% !$Default ? qq[ selected="selected"] : '' |n %>><%$DefaultLabel |n%></option>
 % }
diff --git a/share/html/Elements/SelectStatus b/share/html/Elements/SelectStatus
index ff0fef48a..d67cfe292 100644
--- a/share/html/Elements/SelectStatus
+++ b/share/html/Elements/SelectStatus
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>" <% $Multiple ? qq{class="tall" multiple="multiple" size="$Size"} : '' |n %>>
+<select name="<%$Name%>" <% $Multiple ? qq{class="selectpicker form-control tall" multiple="multiple" size="$Size"} : 'class="selectpicker form-control"' |n %>>
 % if ( $DefaultValue ) {
 <option value=""<% !$Default && qq[ selected="selected"] |n %>><% $DefaultLabel %></option>
 % }
diff --git a/share/html/Elements/SelectTimeUnits b/share/html/Elements/SelectTimeUnits
index 4c0e9a684..bbda067ad 100644
--- a/share/html/Elements/SelectTimeUnits
+++ b/share/html/Elements/SelectTimeUnits
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select class="TimeUnits" id="<% $Name %>" name="<% $Name %>">
+<select class="selectpicker form-control TimeUnits" id="<% $Name %>" name="<% $Name %>">
 <option value="minutes" <% $Default eq 'minutes' ? 'selected="selected"' : '' |n%>>
     <% loc('Minutes') %>
 </option>
diff --git a/share/html/Elements/SelectWatcherType b/share/html/Elements/SelectWatcherType
index 6214be51a..0fe850d0b 100644
--- a/share/html/Elements/SelectWatcherType
+++ b/share/html/Elements/SelectWatcherType
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="selectpicker form-control">
 % if ($AllowNull) {
 <option value="">-</option>
 % }
diff --git a/share/html/Elements/Submit b/share/html/Elements/Submit
index 30e9c7206..64c8cbb30 100644
--- a/share/html/Elements/Submit
+++ b/share/html/Elements/Submit
@@ -52,13 +52,13 @@ id="<%$id%>"
 >
   <div class="extra-buttons">
 % if ($CheckAll) {
-  <input type="button" value="<%$CheckAllLabel%>" onclick="setCheckbox(this, <% $match %>, true);return false;" class="button" />
+  <input type="button" value="<%$CheckAllLabel%>" onclick="setCheckbox(this, <% $match %>, true);return false;" class="button btn btn-primary form-control" />
 % }
 % if ($ClearAll) {
-  <input type="button" value="<%$ClearAllLabel%>" onclick="setCheckbox(this, <% $match %>, false);return false;" class="button" />
+  <input type="button" value="<%$ClearAllLabel%>" onclick="setCheckbox(this, <% $match %>, false);return false;" class="button btn btn-primary form-control" />
 % }
 % if ($Reset) {
-  <input type="reset" value="<%$ResetLabel%>" class="button" />
+  <input type="reset" value="<%$ResetLabel%>" class="button btn btn-primary form-control" />
 % }
   </div>
   <div class="buttons">
@@ -68,10 +68,10 @@ id="<%$id%>"
 
 % if ($AlternateLabel) {
   <span class="caption"><%$AlternateCaption%></span>
-  <input type="submit" <% $OnClick ? qq[ onclick="$OnClick"] : '' | n %> <% $Name ? qq[ name="$Name"] : '' | n %> <% $SubmitId ? qq[ id="$SubmitId"] : '' | n %> value="<%$AlternateLabel%>" class="button" />
+  <input type="submit" <% $OnClick ? qq[ onclick="$OnClick"] : '' | n %> <% $Name ? qq[ name="$Name"] : '' | n %> <% $SubmitId ? qq[ id="$SubmitId"] : '' | n %> value="<%$AlternateLabel%>" class="btn btn-primary form-control button" />
 % } else {
   <span class="caption"><%$Caption%></span>
-  <input type="submit" <% $OnClick ? qq[ onclick="$OnClick"] : '' | n %> <% $Name ? qq[ name="$Name"] : '' | n %> <% $SubmitId ? qq[ id="$SubmitId"] : '' | n %> value="<%$Label%>" class="button" />
+  <input type="submit" <% $OnClick ? qq[ onclick="$OnClick"] : '' | n %> <% $Name ? qq[ name="$Name"] : '' | n %> <% $SubmitId ? qq[ id="$SubmitId"] : '' | n %> value="<%$Label%>" class="button btn btn-primary form-control" />
 % }
 
 % if ( $Back ) {
@@ -83,7 +83,7 @@ id="<%$id%>"
   <div class="back">
   <span class="caption"><%$BackCaption%></span>
   <input type="submit" <% $BackOnClick ? qq[ onclick="$BackOnClick"] : '' | n %> <%
-      $BackName ? qq[ name="$BackName"] : '' | n %> value="<%$BackLabel%>" class="button" />
+      $BackName ? qq[ name="$BackName"] : '' | n %> value="<%$BackLabel%>" class="button btn btn-primary form-control" />
   </div>
 % }
 
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index b887b81e9..6c672bcb4 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -76,33 +76,36 @@
 
 
 
-
-<div id="pick-criteria">
-    <& Elements/PickCriteria, query => $query{'Query'}, queues => $queues &>
+<div class="row">
+  <div class="col-xl-7">
+    <div id="pick-criteria">
+      <& Elements/PickCriteria, query => $query{'Query'}, queues => $queues &>
+    </div>
+    <& /Elements/Submit,  Label => loc('Add these terms'), SubmitId => 'AddClause', Name => 'AddClause'&>
+    <& /Elements/Submit, Label => loc('Add these terms and Search'), SubmitId => 'DoSearch', Name => 'DoSearch'&>
+  </div>
+
+  <div id="editquery" class="col-xl-5">
+    <& Elements/EditQuery,
+      %ARGS,
+      actions => \@actions,
+      optionlist => $optionlist,
+      Description => $saved_search{'Description'},
+      &>
+    <div id="editsearches">
+      <& Elements/EditSearches, %saved_search, CurrentSearch => \%query &>
+    </div>
+  </div>
 </div>
-<& /Elements/Submit,  Label => loc('Add these terms'), SubmitId => 'AddClause', Name => 'AddClause'&>
-<& /Elements/Submit, Label => loc('Add these terms and Search'), SubmitId => 'DoSearch', Name => 'DoSearch'&>
-
 
-<div id="editquery">
-<& Elements/EditQuery,
-    %ARGS,
-    actions => \@actions,
-    optionlist => $optionlist,
-    Description => $saved_search{'Description'},
-    &>
-</div>
-<div id="editsearches">
-    <& Elements/EditSearches, %saved_search, CurrentSearch => \%query &>
-</div>
-
-<span id="display-options">
+<div id="display-options" class="row">
 <& Elements/DisplayOptions,
     %ARGS, %query,
     AvailableColumns => $AvailableColumns,
     CurrentFormat    => $CurrentFormat,
 &>
-</span>
+</div>
+
 <& /Elements/Submit, Label => loc('Update format and Search'), Name => 'DoSearch', id=>"formatbuttons"&>
 </form>
 
diff --git a/share/html/Search/Elements/ConditionRow b/share/html/Search/Elements/ConditionRow
index d49facc4a..b7728d716 100644
--- a/share/html/Search/Elements/ConditionRow
+++ b/share/html/Search/Elements/ConditionRow
@@ -45,11 +45,17 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<tr>
-<td class="label"><% $handle_block->( $Condition->{'Field'}, $Condition->{'Name'} .'Field' ) |n %></td>
-<td class="operator"><% $handle_block->( $Condition->{'Op'}, $Condition->{'Name'} .'Op') |n %></td>
-<td class="value"><% $handle_block->( $Condition->{'Value'}, 'ValueOf'. $Condition->{'Name'} ) |n %></td>
-</tr>
+<div class="form-row">
+  <div class="col-md-3 label">
+    <% $handle_block->( $Condition->{'Field'}, $Condition->{'Name'} .'Field' ) |n %>
+  </div>
+  <div class="col-md-2 operator">
+    <% $handle_block->( $Condition->{'Op'}, $Condition->{'Name'} .'Op') |n %>
+  </div>
+  <div class="col-md-7 value">
+    <% $handle_block->( $Condition->{'Value'}, 'ValueOf'. $Condition->{'Name'} ) |n %>
+  </div>
+</div>
 <%INIT>
 return unless $Condition && $Condition->{'Name'};
 
@@ -76,13 +82,14 @@ $handle_block = sub {
     if ( $box->{'Type'} eq 'text' ) {
         $box->{id} ||= $box->{name} ||= $name;
         $box->{value} ||= delete($box->{Default}) || '';
+        $box->{class} ||= "form-control";
         return "<input ".join(" ", map{$m->interp->apply_escapes(lc($_),'h')
                                       .q{="}.$m->interp->apply_escapes($box->{$_},'h').q{"}}
                                    sort keys %$box)." />";
     }
     if ( $box->{'Type'} eq 'select' ) {
         my $res = '';
-        $res .= qq{<select id="$name" name="$name">};
+        $res .= qq{<select id="$name" name="$name" class="form-control selectpicker">};
         my @options = @{ $box->{'Options'} };
         while( my $k = shift @options ) {
             my $v = shift @options;
diff --git a/share/html/Search/Elements/DisplayOptions b/share/html/Search/Elements/DisplayOptions
index 4a3939d0d..89326707e 100644
--- a/share/html/Search/Elements/DisplayOptions
+++ b/share/html/Search/Elements/DisplayOptions
@@ -45,9 +45,14 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
+<div class="col-xl-5">
 <&| /Widgets/TitleBox, title => loc("Sorting"), id => 'sorting' &>
 <& EditSort, %ARGS &>
 </&>
+</div>
+
+<div class="col-xl-7">
 <&| /Widgets/TitleBox, title => loc("Display Columns"), id => 'columns' &>
 <& EditFormat, %ARGS &>
 </&>
+</div>
diff --git a/share/html/Search/Elements/EditFormat b/share/html/Search/Elements/EditFormat
index 28e6c12d9..31a2ca9a1 100644
--- a/share/html/Search/Elements/EditFormat
+++ b/share/html/Search/Elements/EditFormat
@@ -45,18 +45,20 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<table class="edit-columns">
+<div class="edit-columns">
 
-<tr>
-<th><&|/l&>Add Columns</&>:</th>
-<th><&|/l&>Format</&>:</th>
-<th></th>
-<th><&|/l&>Show Columns</&>:</th>
-</tr>
+  <div class="form-row text-center">
+    <div class="col-md-3"><&|/l&>Add Columns</&>:</div>
+    <div class="col-md-3"><&|/l&>Format</&>:</div>
+    <div class="col-md-1"></div>
+    <div class="col-md-4"><&|/l&>Show Columns</&>:</div>
+  </div>
 
 <script type="text/javascript">
 jQuery( function() {
-    jQuery('select[name=SelectDisplayColumns].chosen').chosen({ width: '12em', placeholder_text_multiple: ' ', no_results_text: ' ', search_contains: true });
+    if ( !jQuery.prototype.selectpicker ) {
+        jQuery('select[name=SelectDisplayColumns].chosen').chosen({ width: '12em', placeholder_text_multiple: ' ', no_results_text: ' ', search_contains: true });
+    }
     jQuery('[name=AddCol], [name=RemoveCol], [name=ColUp], [name=ColDown]').click( function() {
         var name = jQuery(this).attr('name');
         var form = jQuery(this).closest('form');
@@ -66,7 +68,12 @@ jQuery( function() {
                 if ( data.status == 'success' ) {
                     form.find('input[name=Format]').val(data.Format);
                     form.find('select[name=CurrentDisplayColumns]').html(data.CurrentDisplayColumns);
-                    form.find('select[name=SelectDisplayColumns]').val('').trigger("chosen:updated");
+                    if ( jQuery.prototype.selectpicker ) {
+                        form.find('select[name=SelectDisplayColumns]').val('').change();
+                    }
+                    else {
+                        form.find('select[name=SelectDisplayColumns]').val('').trigger("chosen:updated");
+                    }
                     form.find('[name=Link],[name=Title],[name=Size],[name=Face]').val('');
                 }
                 else {
@@ -81,76 +88,91 @@ jQuery( function() {
     });
 });
 </script>
-<tr>
 
-<td valign="top"><select name="SelectDisplayColumns" multiple="multiple" class="chosen">
+  <div class="form-row">
+
+    <div class="col-md-3">
+      <div class="form-row">
+        <select name="SelectDisplayColumns" multiple="multiple" class="form-control selectpicker">
 % my %seen;
 % foreach my $field ( grep !$seen{lc $_}++, @$AvailableColumns) {
-<option value="<% $field %>" <% $selected{$field} ? 'selected="selected"' : '' |n%>>\
-<% $field =~ /^(?:CustomField|CF)\./ ? $field : loc($field) %></option>
+        <option value="<% $field %>" <% $selected{$field} ? 'selected="selected"' : '' |n%>>\
+        <% $field =~ /^(?:CustomField|CF)\./ ? $field : loc($field) %></option>
 % }
-</select></td>
-<td>
-<div class="row">
-<span class="label"><&|/l&>Link</&>:</span>
-<span class="value">
-<select name="Link">
-<option value="None">-</option>
-<option value="Display"><&|/l&>Display</&></option>
+        </select>
+      </div>
+    </div>
+
+    <div class="col-md-3">
+      <div class="form-row">
+        <div class="col-md-3 label"><&|/l&>Link</&>:</div>
+%# leave 1 col to save some space to the right "->"
+        <div class="col-md-8 value">
+          <select name="Link" class="form-control selectpicker">
+              <option value="None">-</option>
+              <option value="Display"><&|/l&>Display</&></option>
 % if ($IncludeTicketLinks) {
-<option value="Take"><&|/l&>Take</&></option>
-<option value="Respond"><&|/l&>Respond</&></option>
-<option value="Comment"><&|/l&>Comment</&></option>
-<option value="Resolve"><&|/l&>Resolve</&></option>
+              <option value="Take"><&|/l&>Take</&></option>
+              <option value="Respond"><&|/l&>Respond</&></option>
+              <option value="Comment"><&|/l&>Comment</&></option>
+              <option value="Resolve"><&|/l&>Resolve</&></option>
 % }
-</select>
-</span>
-</div>
-<div class="row">
-<span class="label"><&|/l&>Title</&>:</span>
-<span class="value"><input type="text" name="Title" size="10" /></span>
-</div>
-<div class="row">
-<span class="label"><&|/l&>Size</&>:</span>
-<span class="value"><select name="Size">
-<option value="">-</option>
-<option value="Small"><&|/l&>Small</&></option>
-<option value="Large"><&|/l&>Large</&></option>
-</select>
-</span>
-</div>
-<div class="row">
-<span class="label"><&|/l&>Style</&>:</span>
-<span class="value"><select name="Face">
-<option value="">-</option>
-<option value="Bold"><&|/l&>Bold</&></option>
-<option value="Italic"><&|/l&>Italic</&></option>
-</select>
-</span>
-</div>
-</td>
+          </select>
+        </div>
+      </div>
+
+      <div class="form-row">
+        <div class="col-md-3 label"><&|/l&>Title</&>:</div>
+        <div class="col-md-8 value"><input type="text" name="Title" size="10" class="form-control" /></div>
+      </div>
+
+      <div class="form-row">
+        <div class="col-md-3 label"><&|/l&>Size</&>:</div>
+        <div class="col-md-8 value">
+          <select name="Size" class="form-control selectpicker">
+            <option value="">-</option>
+            <option value="Small"><&|/l&>Small</&></option>
+            <option value="Large"><&|/l&>Large</&></option>
+          </select>
+        </div>
+      </div>
 
-<td><input type="submit" class="button" name="AddCol" value=" → " /></td>
+      <div class="form-row">
+        <div class="col-md-3 label"><&|/l&>Style</&>:</div>
+        <div class="col-md-8 value">
+          <select name="Face" class="form-controll selectpicker">
+            <option value="">-</option>
+            <option value="Bold"><&|/l&>Bold</&></option>
+            <option value="Italic"><&|/l&>Italic</&></option>
+          </select>
+        </div>
+      </div>
+    </div>
 
-<td valign="top">
-<select size="8" class="tall" name="CurrentDisplayColumns">
+    <div class="col-md-1"><input type="submit" class="button btn btn-primary" name="AddCol" value=" → " /></div>
+
+    <div class="col-md-4">
+      <div class="form-row">
+        <select size="8" class="tall form-control" name="CurrentDisplayColumns">
 % my $i=0;
 % my $current = $ARGS{CurrentDisplayColumns} || ''; $current =~ s/^\d+>//;
 % foreach my $field ( @$CurrentFormat ) {
-<option value="<% $i++ %>><% $field->{Column} %>" <% $field->{Column} eq $current ? 'selected="selected"' : '' |n%>>\
+          <option value="<% $i++ %>><% $field->{Column} %>" <% $field->{Column} eq $current ? 'selected="selected"' : '' |n%>>\
 <% $field->{Column} =~ /^(?:CustomField|CF)\./ ? $field->{Column} : loc( $field->{Column} ) %></option>
 % }
-</select>
-<br />
-<center>
-<input type="submit" class="button" name="ColUp" value=" ↑ " />
-<input type="submit" class="button" name="ColDown" value=" ↓ " />
-<input type="submit" class="button" name="RemoveCol" value="<%loc('Delete')%>" />
-</center>
-</td>
+        </select>
+      </div>
 
-</tr>
-</table>
+      <div class="form-row">
+        <div class="col-md-12 text-center">
+          <input type="submit" class="button btn btn-primary" name="ColUp" value=" ↑ " />
+          <input type="submit" class="button btn btn-primary" name="ColDown" value=" ↓ " />
+          <input type="submit" class="button btn btn-primary" name="RemoveCol" value="<%loc('Delete')%>" />
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
 
 <%init>
 my $selected = $ARGS{AddCol} ? [] : $ARGS{SelectDisplayColumns};
diff --git a/share/html/Search/Elements/EditQuery b/share/html/Search/Elements/EditQuery
index 7cdc0af06..33c2def28 100644
--- a/share/html/Search/Elements/EditQuery
+++ b/share/html/Search/Elements/EditQuery
@@ -48,19 +48,21 @@
 <& NewListActions, actions => $actions &>
 <&|/Widgets/TitleBox, title => join(': ', grep defined, loc("Current search"), $Description) &>
 
-<select size="10" name="clauses" class="tall" style="width: 100%" multiple="multiple">
+<div class="form-group">
+  <select size="10" name="clauses" class="tall form-control" style="width: 100%" multiple="multiple">
 % $m->out($optionlist);
-</select>
-
-<p align="center">
-<input type="submit" class="button" name="Up" value=" ↑ " />
-<input type="submit" class="button" name="Down" value=" ↓ " />
-<input type="submit" class="button" name="Left" value=" ← " />
-<input type="submit" class="button" name="Right" value=" → " />
-<input type="submit" class="button" name="Toggle" value="<&|/l&>And/Or</&>" />
-<input type="submit" class="button" name="DeleteClause" value="<&|/l&>Delete</&>" />
-%#<input type="submit" class="button" name="EditQuery" value="Advanced" />
-</p>
+  </select>
+</div>
+
+<div align="center" class="text-center">
+  <input type="submit" class="button btn btn-primary" name="Up" value=" ↑ " />
+  <input type="submit" class="button btn btn-primary" name="Down" value=" ↓ " />
+  <input type="submit" class="button btn btn-primary" name="Left" value=" ← " />
+  <input type="submit" class="button btn btn-primary" name="Right" value=" → " />
+  <input type="submit" class="button btn btn-primary" name="Toggle" value="<&|/l&>And/Or</&>" />
+  <input type="submit" class="button btn btn-primary" name="DeleteClause" value="<&|/l&>Delete</&>" />
+%#<input type="submit" class="button btn btn-primary" name="EditQuery" value="Advanced" />
+</div>
 
 </&>
 <%ARGS>
diff --git a/share/html/Search/Elements/EditSearches b/share/html/Search/Elements/EditSearches
index 482c3d7fc..e009e735d 100644
--- a/share/html/Search/Elements/EditSearches
+++ b/share/html/Search/Elements/EditSearches
@@ -47,37 +47,46 @@
 %# END BPS TAGGED BLOCK }}}
 <div class="edit-saved-searches">
 <&| /Widgets/TitleBox, title => loc($Title)&>
-
 %# Hide all the save functionality if the user shouldn't see it.
 % if ( $can_modify ) {
-<span class="label"><&|/l&>Privacy</&>:</span>
-<& SelectSearchObject, Name => 'SavedSearchOwner', Objects => \@Objects, Object => ( $Object && $Object->id ) ? $Object->Object : '' &>
-<br />
-<span class="label"><&|/l&>Description</&>:</span>
-<input type="text" size="25" name="SavedSearchDescription" value="<% $Description || '' %>" />
 
+<div class="form-row">
+  <div class="col-md-3 label"><&|/l&>Privacy</&>:</div>
+  <div class="col-md-9">
+<& SelectSearchObject, Name => 'SavedSearchOwner', Objects => \@Objects, Object => ( $Object && $Object->id ) ? $Object->Object : '' &>
+  </div>
+</div>
+  <div class="form-row">
+    <div class="col-md-3 label"><&|/l&>Description</&>:</div>
+    <div class="col-md-9 input-group">
+      <input type="text" size="25" name="SavedSearchDescription" value="<% $Description || '' %>" class="form-control" />
 % if ($Id ne 'new') {
-<nobr>
 % if ( $Dirty ) {
-<input type="submit" class="button" name="SavedSearchRevert" value="<%loc('Revert')%>" />
+<input type="submit" class="button btn btn-primary" name="SavedSearchRevert" value="<%loc('Revert')%>" />
 % }
-<input type="submit" class="button" name="SavedSearchDelete" value="<%loc('Delete')%>" />
+<input type="submit" class="button btn btn-primary" name="SavedSearchDelete" value="<%loc('Delete')%>" />
 % if ( $AllowCopy ) {
-<input type="submit" class="button" name="SavedSearchCopy"   value="<%loc('Save as New')%>" />
+<input type="submit" class="button btn btn-primary" name="SavedSearchCopy"   value="<%loc('Save as New')%>" />
 % }
-</nobr>
 % }
+
 % if ( $Object && $Object->Id && $Object->CurrentUserHasRight('update') ) {
-<input type="submit" class="button" id="SavedSearchSave" name="SavedSearchSave"   value="<%loc('Update')%>" />
+<input type="submit" class="button btn btn-primary" id="SavedSearchSave" name="SavedSearchSave"   value="<%loc('Update')%>" />
 % } elsif ( !$Object ) {
-<input type="submit" class="button" id="SavedSearchSave" name="SavedSearchSave"   value="<%loc('Save')%>" />
+<input type="submit" class="button btn btn-primary" id="SavedSearchSave" name="SavedSearchSave"   value="<%loc('Save')%>" />
 %}
 % }
-<br />
-<hr />
-<span class="label"><&|/l&>Load saved search</&>:</span>
+    </div>
+  </div>
+
+  <hr />
+  <div class="form-row">
+    <div class="col-md-3 label"><&|/l&>Load saved search</&>:</div>
+    <div class="col-md-9 input-group">
 <& SelectSearchesForObjects, Name => 'SavedSearchLoad', Objects => \@Objects, SearchType => $Type &>
-<input type="submit" value="<% loc('Load') %>" id="SavedSearchLoadSubmit" name="SavedSearchLoadSubmit" class="button" />
+<input type="submit" class="button btn btn-primary" value="<% loc('Load') %>" id="SavedSearchLoadSubmit" name="SavedSearchLoadSubmit" />
+    </div>
+  </div>
 
 </&>
 </div>
diff --git a/share/html/Search/Elements/EditSort b/share/html/Search/Elements/EditSort
index 7b70b923e..9cfa2aebd 100644
--- a/share/html/Search/Elements/EditSort
+++ b/share/html/Search/Elements/EditSort
@@ -45,34 +45,34 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<table valign="top">
-
 % for my $o (0..3) {
 % $Order[$o] ||= ''; $OrderBy[$o] ||= '';
-<tr>
-<td class="label">
+<div class="form-row">
+  <div class="col-md-4 label">
 % if ($o == 0) {
 <&|/l&>Order by</&>:
 % }
-</td>
-<td class="value">
-<select name="OrderBy">
+  </div>
+  <div class="col-md-4 value">
+    <select name="OrderBy" class="form-control selectpicker">
 % if ($o > 0) {
-<option value=""><&|/l&>~[none~]</&></option>
+      <option value=""><&|/l&>~[none~]</&></option>
 % }
 % # %fields maps display name to SQL column/function
 % foreach my $field (sort keys %fields) {
 %    next unless $field;
 %    my $fieldval = $fields{$field};
-<option value="<%$fieldval%>"
+      <option value="<%$fieldval%>"
 % if (defined $OrderBy[$o] and $fieldval eq $OrderBy[$o]) {
 selected="selected"
 % }
 ><% $field =~ /^(?:CustomField|CF)\./ ? $field : loc($field) %></option>
 % }
-</select>
-<select name="Order">
-<option value="ASC"
+    </select>
+  </div>
+  <div class="col-md-4">
+    <select name="Order" class="form-control selectpicker">
+      <option value="ASC"
 % unless ( ($Order[$o]||'') eq "DESC" ) {
 selected="selected"
 % }
@@ -82,20 +82,21 @@ selected="selected"
 selected="selected"
 % }
 ><&|/l&>Desc</&></option>
-</select>
-</td>
-</tr>
+    </select>
+  </div>
+</div>
 % }
-<tr>
-<td class="label">
-<&|/l&>Rows per page</&>:
-</td><td class="value">
-<& /Elements/SelectResultsPerPage, 
-    Name => "RowsPerPage", 
-    Default => $RowsPerPage &>
-</td>
-</tr>
-</table>
+
+<div class="form-row">
+  <div class="col-md-4 label">
+    <&|/l&>Rows per page</&>:
+  </div>
+  <div class="col-md-4 value">
+    <& /Elements/SelectResultsPerPage, 
+        Name => "RowsPerPage", 
+        Default => $RowsPerPage &>
+  </div>
+</div>
 
 <%INIT>
 my $tickets = RT::Tickets->new($session{'CurrentUser'});
diff --git a/share/html/Search/Elements/PickBasics b/share/html/Search/Elements/PickBasics
index 08f7c949a..e2a5229d9 100644
--- a/share/html/Search/Elements/PickBasics
+++ b/share/html/Search/Elements/PickBasics
@@ -199,10 +199,9 @@ my @lines = (
             Path => '/Elements/SelectEqualityOperator',
         },
         Value => [
-            { Type => 'text', Size => 5 },
             {
                 Type => 'component',
-                Path => '/Elements/SelectTimeUnits',
+                Path => '/Elements/EditTimeValue',
             },
         ],
     },
diff --git a/share/html/Search/Elements/PickCriteria b/share/html/Search/Elements/PickCriteria
index d0820f18a..4b411a694 100644
--- a/share/html/Search/Elements/PickCriteria
+++ b/share/html/Search/Elements/PickCriteria
@@ -47,9 +47,6 @@
 %# END BPS TAGGED BLOCK }}}
 <&| /Widgets/TitleBox, title => loc('Add Criteria')&>
 
-<table width="100%" cellspacing="0" cellpadding="0" border="0">
-
-
 % $m->callback( %ARGS, CallbackName => "BeforeBasics" );
 <& PickBasics, queues => \%queues &>
 <& PickCustomRoles, queues => \%queues &>
@@ -58,14 +55,10 @@
 <& PickObjectCFs, Class => 'Queue', queues => \%queues &>
 % $m->callback( %ARGS, CallbackName => "AfterCFs" );
 
-<tr class="separator"><td colspan="3"><hr /></td></tr>
-<tr>
-<td class="label"><&|/l&>Aggregator</&></td>
-<td class="operator" colspan="2"><& SelectAndOr, Name => "AndOr" &></td>
-
-</tr>
-
-</table>
+<div class="form-row">
+  <div class="col-md-3 label"><&|/l&>Aggregator</&></div>
+  <div class="col-md-9 operator"><& SelectAndOr, Name => "AndOr" &></div>
+</div>
 
 </&>
 
diff --git a/share/html/Search/Elements/SelectAndOr b/share/html/Search/Elements/SelectAndOr
index f2ecc492c..2b48a9a77 100644
--- a/share/html/Search/Elements/SelectAndOr
+++ b/share/html/Search/Elements/SelectAndOr
@@ -45,8 +45,14 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<label><input type="radio" class="radio" name="<%$Name%>" checked="checked" value="AND" /><&|/l&>AND</&></label>
-<label><input type="radio" class="radio" name="<%$Name%>" value="OR" /><&|/l&>OR</&></label>
+<div class="form-check form-check-inline">
+  <input class="form-check-input" type="radio" name="<% $Name %>" checked="checked" id="<% $Name %>-and" value="AND">
+  <label class="form-check-label" for="<% $Name %>-and"><&|/l&>AND</&></label>
+</div>
+<div class="form-check form-check-inline">
+  <input class="form-check-input" type="radio" name="<% $Name %>" id="<% $Name %>-or" value="AND">
+  <label class="form-check-label" for="<% $Name %>-or"><&|/l&>OR</&></label>
+</div>
 
 <%ARGS>
 $Name => "Operator"
diff --git a/share/html/Search/Elements/SelectLinks b/share/html/Search/Elements/SelectLinks
index 2b0ab5ceb..9b486390f 100644
--- a/share/html/Search/Elements/SelectLinks
+++ b/share/html/Search/Elements/SelectLinks
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="form-control selectpicker">
 % foreach (@fields) {
 <option value="<%$_->[0]%>"><% $_->[1] %></option>
 % }
diff --git a/share/html/Search/Elements/SelectPersonType b/share/html/Search/Elements/SelectPersonType
index f9ea120a0..f59ac8389 100644
--- a/share/html/Search/Elements/SelectPersonType
+++ b/share/html/Search/Elements/SelectPersonType
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select id="<%$Name%>" name="<%$Name%>">
+<select id="<%$Name%>" name="<%$Name%>" class="form-control selectpicker">
 % if ($AllowNull) {
 <option value="">-</option>
 % }
diff --git a/share/html/Search/Elements/SelectSearchObject b/share/html/Search/Elements/SelectSearchObject
index d7a3421a0..acce1175e 100644
--- a/share/html/Search/Elements/SelectSearchObject
+++ b/share/html/Search/Elements/SelectSearchObject
@@ -56,7 +56,7 @@ if ( $Object && $Object->Id ) {
     $default_privacy = ref($Object).'-'.$Object->Id;
 }
 </%init>
-<select id="<%$Name%>" name="<%$Name%>">
+<select id="<%$Name%>" name="<%$Name%>" class="form-control selectpicker">
 % foreach my $object (@Objects) {
 % my $privacy = ref($object).'-'.$object->id;
 <option value="<%$privacy%>" <% ( $privacy eq $default_privacy ) ? "selected='selected'" : '' |n %>><& SearchPrivacy, Object => $object &></option>
diff --git a/share/html/Search/Elements/SelectSearchesForObjects b/share/html/Search/Elements/SelectSearchesForObjects
index 101ed648d..c6f2a8487 100644
--- a/share/html/Search/Elements/SelectSearchesForObjects
+++ b/share/html/Search/Elements/SelectSearchesForObjects
@@ -50,7 +50,7 @@
 $Name => undef
 $SearchType => 'Ticket',
 </%args>
-<select id="<%$Name%>" name="<%$Name%>">
+<select id="<%$Name%>" name="<%$Name%>" class="form-control selectpicker">
 <option value="">-</option>
 % foreach my $object (@Objects) {
 % my @searches = $object->Attributes->Named('SavedSearch');
diff --git a/share/static/css/base-responsive/forms.css b/share/static/css/base-responsive/forms.css
index dcc693c89..3742f69e7 100644
--- a/share/static/css/base-responsive/forms.css
+++ b/share/static/css/base-responsive/forms.css
@@ -20,7 +20,6 @@ form {
 }
 
 .value {
- font-size: 0.85em;
 
 }
 
@@ -123,14 +122,14 @@ div.results .titlebox-content {
 .fields .value {
     display: table-cell;
     vertical-align: middle;
-    padding-top: 0.25em;
+    padding-top: 0.5em;
 }
 
 .fields > .field:last-child > .label,
 .fields > .field:last-child > .labeltop,
 .fields > .field:last-child > .cflabel,
 .fields > .field:last-child > .value {
-    padding-bottom: 0.25em;
+    padding-bottom: 0.5em;
 }
 
 
@@ -180,16 +179,13 @@ div.results .titlebox-content {
 
 .label, .labeltop {
  text-align: right;
- font-size: 0.8em;
  padding-right: .5em;
  padding-top: .5em;
- margin-top: .5em;
  white-space: nowrap;
 }
 
 .cflabel {
  text-align: right;
- font-size: 0.8em;
  padding-right: .5em;
  width: 12em;
 }
diff --git a/share/static/css/elevator-light/forms.css b/share/static/css/elevator-light/forms.css
index 566b9ab05..1e7a6b7f1 100644
--- a/share/static/css/elevator-light/forms.css
+++ b/share/static/css/elevator-light/forms.css
@@ -63,8 +63,6 @@ input[class=button],
 button {
     color: #fff;
     background: #4868b3;
-    border: 1px solid #fff;
-    padding: 0.5em;
 }
 
 .button:focus,
@@ -101,6 +99,7 @@ button {
     border-radius: 3px;
     padding-left: 0.75em;
     padding-right: 0.75em;
+    width: auto;
 }
 
 .value {
@@ -117,3 +116,7 @@ button {
     -webkit-border-radius: 3px;
     border-radius: 3px;
 }
+
+.form-row {
+    margin-top: 0.5em;
+}
diff --git a/share/static/css/elevator-light/ticket-search.css b/share/static/css/elevator-light/ticket-search.css
index 8f022ae20..ed026e0fd 100644
--- a/share/static/css/elevator-light/ticket-search.css
+++ b/share/static/css/elevator-light/ticket-search.css
@@ -55,15 +55,6 @@
     font: message-box;
 }
 
-#editquery,
-#editsearches {
-    position: absolute;
-    margin-top: 1.5em;
-    right: 1em;
-    left: 60%;
-    top: 1em;
-}
-
 #editquery {
     top: 1.3em
 }
@@ -73,7 +64,6 @@
 }
 
 #pick-criteria {
-    width: 58%;
     padding-top: 0em;
     margin-top: 0em;
 }
@@ -82,12 +72,7 @@
     overflow-x: auto
 }
 
-#BuildQuery .submit {
-    width: 58%
-}
-
 #sorting.titlebox {
-    width: 55%;
     padding-right: 1em;
 }
 
@@ -171,10 +156,6 @@ span#display-options .titlebox#columns table.edit-columns span.value {
     width: 7em;
 }
 
-#BuildQuery #formatbuttons.submit {
-    width: 85%
-}
-
 .refresh {
     float: left
 }
@@ -186,3 +167,23 @@ span#display-options .titlebox#columns table.edit-columns span.value {
 #SavedSearchOwner {
     max-width: 100%
 }
+
+#pick-criteria .form-row .label .bootstrap-select {
+    margin-top: -0.5em;
+}
+
+#pick-criteria .form-row .form-check {
+    margin-top: 0.75em;
+}
+
+#pick-criteria .value .form-row {
+    margin-top: 0;
+}
+
+#pick-criteria .value {
+    max-width: 500px;
+}
+
+.edit-saved-searches .input-group input.btn {
+    margin-left: 0.5em;
+}

commit 319d7a6813d8e70f04e406754be304413db14d02
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue Apr 9 03:38:29 2019 +0800

    Migrate homepage to elevator themes

diff --git a/share/html/Elements/CreateTicket b/share/html/Elements/CreateTicket
index 664e78ad8..ea8ca3c07 100644
--- a/share/html/Elements/CreateTicket
+++ b/share/html/Elements/CreateTicket
@@ -53,8 +53,8 @@
 <p><&|/l&>Select a queue for your new ticket.</&></p>
 % }
 
-% my $button_start = '<input type="submit" class="button" value="';
-% my $button_start_modal = '<input type="submit" class="button ticket-create-modal" value="';
+% my $button_start = '<input type="submit" class="button btn btn-lg btn-primary form-control" value="';
+% my $button_start_modal = '<input type="submit" class="button btn btn-primary form-control ticket-create-modal" value="';
 % my $button_end = '" />';
 % my $queue_selector = $m->scomp('/Elements/SelectNewTicketQueue', AutoSubmit => 1, SendTo => $SendTo, Placeholder => loc('Queue'), Hyperlink => $Hyperlink );
 
diff --git a/share/html/Elements/QueueSummaryByLifecycle b/share/html/Elements/QueueSummaryByLifecycle
index 58a465363..0eb870eb5 100644
--- a/share/html/Elements/QueueSummaryByLifecycle
+++ b/share/html/Elements/QueueSummaryByLifecycle
@@ -51,7 +51,7 @@
     next unless @cur_statuses;
 </%perl>
 
-<table border="0" cellspacing="0" cellpadding="1" width="100%" class="queue-summary">
+<table border="0" cellspacing="0" cellpadding="1" width="100%" class="table queue-summary">
 
 <tr>
     <th class="collection-as-table"><&|/l&>Queue</&></th>
diff --git a/share/html/Elements/QueueSummaryByStatus b/share/html/Elements/QueueSummaryByStatus
index d1bc94273..e0ae8c523 100644
--- a/share/html/Elements/QueueSummaryByStatus
+++ b/share/html/Elements/QueueSummaryByStatus
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<table border="0" cellspacing="0" cellpadding="1" width="100%" class="queue-summary">
+<table border="0" cellspacing="0" cellpadding="1" width="100%" class="table queue-summary">
 
 <tr>
     <th class="collection-as-table"><&|/l&>Queue</&></th>
diff --git a/share/html/Elements/QuickCreate b/share/html/Elements/QuickCreate
index 3a05702b0..a8064026a 100644
--- a/share/html/Elements/QuickCreate
+++ b/share/html/Elements/QuickCreate
@@ -56,7 +56,7 @@
 <div class="wide fields">
   <div class="field input-row">
     <span class="label"><&|/l&>Subject</&>:</span>
-    <span class="value"><input type="text" size="50" name="Subject" value="<% $args->{Subject} || '' %>" /></span>
+    <span class="value"><input type="text" size="50" class="form-control" name="Subject" value="<% $args->{Subject} || '' %>" /></span>
   </div>
   <div class="field input-row">
     <span class="label"><&|/l&>Queue</&>:</span>
@@ -67,7 +67,7 @@
   <div class="field input-row">
       <span class="label"><&|/l&>Owner</&>:</span>
       <span class="value">
-        <select type="select" name="Owner">  
+        <select type="select" name="Owner" class="selectpicker form-control">
 % my $default_owner = $args->{Owner} || $session{'CurrentUser'}->id;
           <option value="<%$session{'CurrentUser'}->id%>" <% $default_owner == $session{'CurrentUser'}->id ? 'selected="selected"' : '' |n %>><&|/l&>Me</&></option>
           <option value="<%RT->Nobody->id%>" <% $default_owner == RT->Nobody->id ? 'selected="selected"' : '' |n %>><%loc('Nobody')%></option>
@@ -80,7 +80,7 @@
   </div>
   <div class="field input-row">
     <span class="labeltop"><&|/l&>Content</&>:</span>
-    <span class="value"><textarea name="Content" cols="50" rows="3"><% $args->{Content} || ''%></textarea></span>
+    <span class="value"><textarea class="form-control" name="Content" cols="50" rows="3"><% $args->{Content} || ''%></textarea></span>
   </div>
 </div>
 <& /Elements/Submit, Label => loc('Create') &>
diff --git a/share/html/Elements/Refresh b/share/html/Elements/Refresh
index 9e6cbc2cb..3ca712261 100644
--- a/share/html/Elements/Refresh
+++ b/share/html/Elements/Refresh
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<%$Name%>">
+<select name="<%$Name%>" class="selectpicker form-control refresh">
 <option value="-1"
 %unless ($Default) {
  selected="selected"
diff --git a/share/html/Elements/RefreshHomepage b/share/html/Elements/RefreshHomepage
index 772d8052f..a2dfa0061 100644
--- a/share/html/Elements/RefreshHomepage
+++ b/share/html/Elements/RefreshHomepage
@@ -47,8 +47,16 @@
 %# END BPS TAGGED BLOCK }}}
 <&|/Widgets/TitleBox, title => loc('Refresh')&>
 <form method="get" action="<% RT->Config->Get('WebPath') . $m->request_path %>">
+<div class="form-row">
+  <div class="col-md-12">
 <& /Elements/Refresh, Name => 'HomeRefreshInterval', 
     Default => $session{'home_refresh_interval'}||RT->Config->Get('HomePageRefreshInterval', $session{'CurrentUser'}) &>
+  </div>
+</div>
+<div class="form-row">
+  <div class="col-md-12">
 <& /Elements/Submit,  Label => loc('Go!') &>
+  </div>
+</div>
 </&>
 </form>
diff --git a/share/html/Elements/SelectNewTicketQueue b/share/html/Elements/SelectNewTicketQueue
index ed30914b8..56a22bf6e 100644
--- a/share/html/Elements/SelectNewTicketQueue
+++ b/share/html/Elements/SelectNewTicketQueue
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<label accesskey="9">
+<label accesskey="9" class="select-queue">
   <& /Elements/SelectQueue, Name => 'Queue', Default => $queue, %ARGS, ShowNullOption => 0, ShowAllQueues => 0 &>
 </label>
 <%INIT>
diff --git a/share/static/css/elevator-light/forms.css b/share/static/css/elevator-light/forms.css
index 1e7a6b7f1..490435e32 100644
--- a/share/static/css/elevator-light/forms.css
+++ b/share/static/css/elevator-light/forms.css
@@ -120,3 +120,19 @@ button {
 .form-row {
     margin-top: 0.5em;
 }
+
+div.field label.select-queue {
+    display: block;
+    margin-bottom: 0;
+}
+
+#topactions .bootstrap-select.form-control {
+    height: auto;
+}
+
+/* Fix Queue name position in Queue select for Firefox */
+ at -moz-document url-prefix() {
+    #topactions .bootstrap-select .dropdown-toggle .filter-option {
+        margin-top: 5px;
+    }
+}
diff --git a/share/static/css/elevator-light/nav.css b/share/static/css/elevator-light/nav.css
index 9ec7fc72d..65f6c2204 100644
--- a/share/static/css/elevator-light/nav.css
+++ b/share/static/css/elevator-light/nav.css
@@ -130,7 +130,6 @@
 }
 
 #topactions input,
-#topactions select,
 #topactions button {
     padding-top: 0;
     padding-bottom: 0;
@@ -190,14 +189,6 @@
     transition: width 0.25s ease-in-out;
 }
 
-#topactions select {
-    -webkit-appearance: menulist-button;
-}
-
-#topactions .select-queue {
-    padding-right: 0
-}
-
 #topactions #simple-search .field {
     margin-left: 1em;
     color: #787;
@@ -267,7 +258,13 @@
     -webkit-border-radius: 3px;
 }
 
-#topactions input.select-queue {
-    border: none;
+#topactions .bootstrap-select.form-control {
+    height: auto;
 }
 
+/* Fix Queue name position in Queue select for Firefox */
+ at -moz-document url-prefix() {
+    #topactions .bootstrap-select .dropdown-toggle .filter-option {
+        margin-top: 5px;
+    }
+}

commit 9c4070fcb18bfd84b50f50a1de1c90e31ff3b1cf
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Wed Apr 10 03:36:27 2019 +0800

    Add bootstrap-combobox 1.2.0 dependency

diff --git a/devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.css b/devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.css
new file mode 100644
index 000000000..18af8d2a8
--- /dev/null
+++ b/devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.css
@@ -0,0 +1,56 @@
+ at media (min-width: 768px) {
+  .form-search .combobox-container,
+  .form-inline .combobox-container {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: top;
+  }
+  .form-search .combobox-container .input-group-addon,
+  .form-inline .combobox-container .input-group-addon {
+    width: auto;
+  }
+}
+.combobox-container .dropdown-toggle {
+  justify-content: center;
+}
+.combobox-container .dropdown-toggle.custom-icon::after {
+  content: none;
+}
+.combobox-container.combobox-selected .dropdown-toggle::after {
+  content: none;
+}
+.combobox-container .utf-remove::after {
+  content: "\00D7";
+}
+.combobox-container.combobox-selected .pulldown {
+  display: none;
+}
+/* :not doesn't work in IE8 */
+.combobox-container:not(.combobox-selected) .remove {
+  display: none;
+}
+.typeahead-long {
+  max-height: 300px;
+  overflow-y: auto;
+}
+.control-group.error .combobox-container .add-on {
+  color: #B94A48;
+  border-color: #B94A48;
+}
+.control-group.error .combobox-container .caret {
+  border-top-color: #B94A48;
+}
+.control-group.warning .combobox-container .add-on {
+  color: #C09853;
+  border-color: #C09853;
+}
+.control-group.warning .combobox-container .caret {
+  border-top-color: #C09853;
+}
+.control-group.success .combobox-container .add-on {
+  color: #468847;
+  border-color: #468847;
+}
+.control-group.success .combobox-container .caret {
+  border-top-color: #468847;
+}
diff --git a/devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.js b/devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.js
new file mode 100644
index 000000000..24f75dfc7
--- /dev/null
+++ b/devel/third-party/bootstrap-combobox-1.2.0/bootstrap-combobox.js
@@ -0,0 +1,480 @@
+/* =============================================================
+ * bootstrap-combobox.js v1.2.0
+ * =============================================================
+ * Copyright 2019 Daniel Farrell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+(function( $ ) {
+
+ "use strict";
+
+ /* COMBOBOX PUBLIC CLASS DEFINITION
+  * ================================ */
+
+  var hasPopper = typeof Popper !== 'undefined';
+
+  var Combobox = function ( element, options ) {
+    this.options = $.extend({}, $.fn.combobox.defaults, options);
+    this.template = this.options.template || this.template
+    this.$source = $(element);
+    this.$container = this.setup();
+    this.$element = this.$container.find('input[type=text]');
+    this.$target = this.$container.find('input[type=hidden]');
+    this.$button = this.$container.find('.dropdown-toggle');
+    this.$menu = $(this.options.menu).appendTo('body');
+    this.matcher = this.options.matcher || this.matcher;
+    this.sorter = this.options.sorter || this.sorter;
+    this.highlighter = this.options.highlighter || this.highlighter;
+    this.shown = false;
+    this.selected = false;
+    this.renderLimit = this.options.renderLimit || -1;
+    this.clearIfNoMatch = this.options.clearIfNoMatch;
+    this.refresh();
+    this.transferAttributes();
+    this.listen();
+  };
+
+  Combobox.prototype = {
+
+    constructor: Combobox
+
+  , setup: function () {
+      var combobox = $(this.template());
+      this.$source.before(combobox);
+      this.$source.hide();
+      return combobox;
+    }
+
+  , disable: function() {
+      this.$element.prop('disabled', true);
+      this.$button.attr('disabled', true);
+      this.disabled = true;
+      this.$container.addClass('combobox-disabled');
+    }
+
+  , enable: function() {
+      this.$element.prop('disabled', false);
+      this.$button.attr('disabled', false);
+      this.disabled = false;
+      this.$container.removeClass('combobox-disabled');
+    }
+  , parse: function () {
+      var that = this
+        , map = {}
+        , source = []
+        , selected = false
+        , selectedValue = '';
+      this.$source.find('option').each(function() {
+        var option = $(this);
+        if (option.val() === '') {
+          that.options.placeholder = option.text();
+          return;
+        }
+        map[option.text()] = option.val();
+        source.push(option.text());
+        if (option.prop('selected')) {
+          selected = option.text();
+          selectedValue = option.val();
+        }
+      })
+      this.map = map;
+      if (selected) {
+        this.$element.val(selected);
+        this.$target.val(selectedValue);
+        this.$container.addClass('combobox-selected');
+        this.selected = true;
+      }
+      return source;
+    }
+
+  , transferAttributes: function() {
+    this.options.placeholder = this.$source.attr('data-placeholder') || this.options.placeholder
+    if(this.options.appendId !== undefined) {
+    	this.$element.attr('id', this.$source.attr('id') + this.options.appendId);
+    }
+    this.$element.attr('placeholder', this.options.placeholder)
+    this.$target.prop('name', this.$source.prop('name'))
+    this.$target.val(this.$source.val())
+    this.$source.removeAttr('name')  // Remove from source otherwise form will pass parameter twice.
+    this.$element.attr('required', this.$source.attr('required'))
+    this.$element.attr('rel', this.$source.attr('rel'))
+    this.$element.attr('title', this.$source.attr('title'))
+    this.$element.attr('class', this.$source.attr('class'))
+    this.$element.attr('tabindex', this.$source.attr('tabindex'))
+    this.$source.removeAttr('tabindex')
+    if (this.$source.attr('disabled')!==undefined)
+      this.disable();
+  }
+
+  , select: function () {
+      var val = this.$menu.find('.active').attr('data-value');
+      this.$element.val(this.updater(val)).trigger('change');
+      this.$target.val(this.map[val]).trigger('change');
+      this.$source.val(this.map[val]).trigger('change');
+      this.$container.addClass('combobox-selected');
+      this.selected = true;
+      return this.hide();
+    }
+
+  , updater: function (item) {
+      return item;
+    }
+
+  , show: function () {
+      var pos = $.extend({}, this.$element.position(), {
+        height: this.$element[0].offsetHeight
+      });
+
+      this.$menu
+        .insertAfter(this.$element)
+        .css({
+          top: pos.top + pos.height
+        , left: pos.left
+        })
+        .show();
+
+      $('.dropdown-menu').on('mousedown', $.proxy(this.scrollSafety, this));
+
+      this.shown = true;
+      return this;
+    }
+
+  , hide: function () {
+      this.$menu.hide();
+      $('.dropdown-menu').off('mousedown', $.proxy(this.scrollSafety, this));
+      this.$element.on('blur', $.proxy(this.blur, this));
+      this.shown = false;
+      return this;
+    }
+
+  , lookup: function (event) {
+      this.query = this.$element.val();
+      return this.process(this.source);
+    }
+
+  , process: function (items) {
+      var that = this;
+
+      items = $.grep(items, function (item) {
+        return that.matcher(item);
+      })
+
+      items = this.sorter(items);
+
+      if (!items.length) {
+        return this.shown ? this.hide() : this;
+      }
+
+      return this.render(items.slice(0, this.options.items)).show();
+    }
+
+  , template: function() {
+      if (this.options.bsVersion == '2') {
+        return '<div class="combobox-container"><input type="hidden" /> <div class="input-append"> <input type="text" autocomplete="off" /> <span class="add-on dropdown-toggle" data-dropdown="dropdown"> <span class="caret pulldown" style="vertical-align: middle"/> <i class="icon-remove remove"/> </span> </div> </div>'
+      } else if (this.options.bsVersion == '3') {
+        return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" /> <span class="input-group-addon dropdown-toggle" data-dropdown="dropdown"> <span class="caret pulldown" /> <span class="glyphicon glyphicon-remove remove" /> </span> </div> </div>'
+      } else {
+        return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" />'
+          + '<span class="input-group-append"' + (hasPopper ? ' data-toggle="dropdown" data-reference="parent"' : '') + '>'
+            + '<span class="input-group-text dropdown-toggle' + (this.options.iconCaret ? ' custom-icon' : '') + '">'
+              + (this.options.iconCaret ? '<span class="' + this.options.iconCaret + ' pulldown" />' : '')
+              + (this.options.iconRemove ? '<span class="' + this.options.iconRemove + ' remove" />' : '<span class="utf-remove remove" />')
+            + '</span>'
+          + '</span> </div> </div>';
+      }
+    }
+
+  , matcher: function (item) {
+      return ~item.toLowerCase().indexOf(this.query.toLowerCase());
+    }
+
+  , sorter: function (items) {
+      var beginswith = []
+        , caseSensitive = []
+        , caseInsensitive = []
+        , item;
+
+      while (item = items.shift()) {
+        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);}
+        else if (~item.indexOf(this.query)) {caseSensitive.push(item);}
+        else {caseInsensitive.push(item);}
+      }
+
+      return beginswith.concat(caseSensitive, caseInsensitive);
+    }
+
+  , highlighter: function (item) {
+      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
+      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
+        return '<strong>' + match + '</strong>';
+      })
+    }
+
+  , render: function (items) {
+      var that = this;
+
+      items = $(items).map(function (i, item) {
+        if(~that.renderLimit && i >= that.renderLimit)
+          return;
+        i = $(that.options.item).attr('data-value', item);
+        i.find('a').html(that.highlighter(item));
+        return i[0];
+      })
+
+      items.first().addClass('active');
+      this.$menu.html(items);
+      return this;
+    }
+
+  , next: function (event) {
+      var active = this.$menu.find('.active').removeClass('active')
+        , next = active.next();
+
+      if (!next.length) {
+        next = $(this.$menu.find('li')[0]);
+      }
+
+      next.addClass('active');
+    }
+
+  , prev: function (event) {
+      var active = this.$menu.find('.active').removeClass('active')
+        , prev = active.prev();
+
+      if (!prev.length) {
+        prev = this.$menu.find('li').last();
+      }
+
+      prev.addClass('active');
+    }
+
+  , toggle: function () {
+    if (!this.disabled) {
+      if (this.$container.hasClass('combobox-selected')) {
+        this.clearTarget();
+        this.triggerChange();
+        this.clearElement();
+      } else {
+        if (this.shown) {
+          this.hide();
+        } else {
+          this.clearElement();
+          this.lookup();
+        }
+      }
+    }
+  }
+
+  , scrollSafety: function(e) {
+      if (e.target.tagName == 'UL') {
+          this.$element.off('blur');
+      }
+  }
+  , clearElement: function () {
+    this.$element.val('').focus();
+  }
+
+  , clearTarget: function () {
+    this.$source.val('');
+    this.$target.val('');
+    this.$container.removeClass('combobox-selected');
+    this.selected = false;
+  }
+
+  , triggerChange: function () {
+    this.$source.trigger('change');
+  }
+
+  , refresh: function () {
+    this.source = this.parse();
+    this.options.items = this.source.length;
+  }
+
+  , listen: function () {
+      this.$element
+        .on('focus',    $.proxy(this.focus, this))
+        .on('blur',     $.proxy(this.blur, this))
+        .on('keypress', $.proxy(this.keypress, this))
+        .on('keyup',    $.proxy(this.keyup, this));
+
+      if (this.eventSupported('keydown')) {
+        this.$element.on('keydown', $.proxy(this.keydown, this));
+      }
+
+      this.$menu
+        .on('click', $.proxy(this.click, this))
+        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+        .on('mouseleave', 'li', $.proxy(this.mouseleave, this));
+
+      this.$button
+        .on('click', $.proxy(this.toggle, this));
+    }
+
+  , eventSupported: function(eventName) {
+      var isSupported = eventName in this.$element;
+      if (!isSupported) {
+        this.$element.setAttribute(eventName, 'return;');
+        isSupported = typeof this.$element[eventName] === 'function';
+      }
+      return isSupported;
+    }
+
+  , move: function (e) {
+      if (!this.shown) {return;}
+
+      switch(e.keyCode) {
+        case 9: // tab
+        case 13: // enter
+        case 27: // escape
+          e.preventDefault();
+          break;
+
+        case 38: // up arrow
+          e.preventDefault();
+          this.prev();
+          this.fixMenuScroll();
+          break;
+
+        case 40: // down arrow
+          e.preventDefault();
+          this.next();
+          this.fixMenuScroll();
+          break;
+      }
+
+      e.stopPropagation();
+    }
+
+  , fixMenuScroll: function(){
+      var active = this.$menu.find('.active');
+      if(active.length){
+          var top = active.position().top;
+          var bottom = top + active.height();
+          var scrollTop = this.$menu.scrollTop();
+          var menuHeight = this.$menu.height();
+          if(bottom > menuHeight){
+              this.$menu.scrollTop(scrollTop + bottom - menuHeight);
+          } else if(top < 0){
+              this.$menu.scrollTop(scrollTop + top);
+          }
+      }
+  }
+
+  , keydown: function (e) {
+      this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
+      this.move(e);
+    }
+
+  , keypress: function (e) {
+      if (this.suppressKeyPressRepeat) {return;}
+      this.move(e);
+    }
+
+  , keyup: function (e) {
+      switch(e.keyCode) {
+        case 40: // down arrow
+         if (!this.shown){
+           this.toggle();
+         }
+         break;
+        case 39: // right arrow
+        case 38: // up arrow
+        case 37: // left arrow
+        case 36: // home
+        case 35: // end
+        case 16: // shift
+        case 17: // ctrl
+        case 18: // alt
+          break;
+
+        case 9: // tab
+        case 13: // enter
+          if (!this.shown) {return;}
+          this.select();
+          break;
+
+        case 27: // escape
+          if (!this.shown) {return;}
+          this.hide();
+          break;
+
+        default:
+          this.clearTarget();
+          this.lookup();
+      }
+
+      e.stopPropagation();
+      e.preventDefault();
+  }
+
+  , focus: function (e) {
+      this.focused = true;
+    }
+
+  , blur: function (e) {
+      var that = this;
+      this.focused = false;
+      var val = this.$element.val();
+      if (!this.selected && val !== '' ) {
+        if(that.clearIfNoMatch)
+          this.$element.val('');
+        this.$source.val('').trigger('change');
+        this.$target.val('').trigger('change');
+      }
+      if (!this.mousedover && this.shown) {setTimeout(function () { that.hide(); }, 200);}
+    }
+
+  , click: function (e) {
+      e.stopPropagation();
+      e.preventDefault();
+      this.select();
+      this.$element.focus();
+    }
+
+  , mouseenter: function (e) {
+      this.mousedover = true;
+      this.$menu.find('.active').removeClass('active');
+      $(e.currentTarget).addClass('active');
+    }
+
+  , mouseleave: function (e) {
+      this.mousedover = false;
+    }
+  };
+
+  /* COMBOBOX PLUGIN DEFINITION
+   * =========================== */
+  $.fn.combobox = function ( option ) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('combobox')
+        , options = typeof option == 'object' && option;
+      if(!data) {$this.data('combobox', (data = new Combobox(this, options)));}
+      if (typeof option == 'string') {data[option]();}
+    });
+  };
+
+  $.fn.combobox.defaults = {
+    bsVersion: '4'
+  , menu: '<ul class="typeahead typeahead-long dropdown-menu"></ul>'
+  , item: '<li><a href="#" class="dropdown-item"></a></li>'
+  , iconCaret: undefined
+  , iconRemove: undefined
+  , clearIfNoMatch: true
+  };
+
+  $.fn.combobox.Constructor = Combobox;
+
+}( window.jQuery ));
diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 8cebfd240..46c00e409 100644
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -1100,8 +1100,8 @@ Set(%ThemeJSFiles,
           dropzone.min.js
           }
     ],
-    'elevator-light' => [qw{popper.min.js bootstrap.min.js bootstrap-select.min.js}],
-    'elevator-dark'  => [qw{popper.min.js bootstrap.min.js bootstrap-select.min.js}],
+    'elevator-light' => [qw{popper.min.js bootstrap.min.js bootstrap-select.min.js bootstrap-combobox.js}],
+    'elevator-dark'  => [qw{popper.min.js bootstrap.min.js bootstrap-select.min.js bootstrap-combobox.js}],
 );
 
 =item C<$UsernameFormat>
diff --git a/share/static/css/elevator-light/bootstrap-combobox.css b/share/static/css/elevator-light/bootstrap-combobox.css
new file mode 100644
index 000000000..18af8d2a8
--- /dev/null
+++ b/share/static/css/elevator-light/bootstrap-combobox.css
@@ -0,0 +1,56 @@
+ at media (min-width: 768px) {
+  .form-search .combobox-container,
+  .form-inline .combobox-container {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: top;
+  }
+  .form-search .combobox-container .input-group-addon,
+  .form-inline .combobox-container .input-group-addon {
+    width: auto;
+  }
+}
+.combobox-container .dropdown-toggle {
+  justify-content: center;
+}
+.combobox-container .dropdown-toggle.custom-icon::after {
+  content: none;
+}
+.combobox-container.combobox-selected .dropdown-toggle::after {
+  content: none;
+}
+.combobox-container .utf-remove::after {
+  content: "\00D7";
+}
+.combobox-container.combobox-selected .pulldown {
+  display: none;
+}
+/* :not doesn't work in IE8 */
+.combobox-container:not(.combobox-selected) .remove {
+  display: none;
+}
+.typeahead-long {
+  max-height: 300px;
+  overflow-y: auto;
+}
+.control-group.error .combobox-container .add-on {
+  color: #B94A48;
+  border-color: #B94A48;
+}
+.control-group.error .combobox-container .caret {
+  border-top-color: #B94A48;
+}
+.control-group.warning .combobox-container .add-on {
+  color: #C09853;
+  border-color: #C09853;
+}
+.control-group.warning .combobox-container .caret {
+  border-top-color: #C09853;
+}
+.control-group.success .combobox-container .add-on {
+  color: #468847;
+  border-color: #468847;
+}
+.control-group.success .combobox-container .caret {
+  border-top-color: #468847;
+}
diff --git a/share/static/css/elevator-light/main.css b/share/static/css/elevator-light/main.css
index ed2ebf65b..9f1f77b45 100644
--- a/share/static/css/elevator-light/main.css
+++ b/share/static/css/elevator-light/main.css
@@ -2,6 +2,7 @@
 
 @import "bootstrap.css";
 @import "bootstrap-select.css";
+ at import "bootstrap-combobox.css";
 @import "base.css";
 @import "layout.css";
 @import "nav.css";
diff --git a/share/static/js/bootstrap-combobox.js b/share/static/js/bootstrap-combobox.js
new file mode 100644
index 000000000..24f75dfc7
--- /dev/null
+++ b/share/static/js/bootstrap-combobox.js
@@ -0,0 +1,480 @@
+/* =============================================================
+ * bootstrap-combobox.js v1.2.0
+ * =============================================================
+ * Copyright 2019 Daniel Farrell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+(function( $ ) {
+
+ "use strict";
+
+ /* COMBOBOX PUBLIC CLASS DEFINITION
+  * ================================ */
+
+  var hasPopper = typeof Popper !== 'undefined';
+
+  var Combobox = function ( element, options ) {
+    this.options = $.extend({}, $.fn.combobox.defaults, options);
+    this.template = this.options.template || this.template
+    this.$source = $(element);
+    this.$container = this.setup();
+    this.$element = this.$container.find('input[type=text]');
+    this.$target = this.$container.find('input[type=hidden]');
+    this.$button = this.$container.find('.dropdown-toggle');
+    this.$menu = $(this.options.menu).appendTo('body');
+    this.matcher = this.options.matcher || this.matcher;
+    this.sorter = this.options.sorter || this.sorter;
+    this.highlighter = this.options.highlighter || this.highlighter;
+    this.shown = false;
+    this.selected = false;
+    this.renderLimit = this.options.renderLimit || -1;
+    this.clearIfNoMatch = this.options.clearIfNoMatch;
+    this.refresh();
+    this.transferAttributes();
+    this.listen();
+  };
+
+  Combobox.prototype = {
+
+    constructor: Combobox
+
+  , setup: function () {
+      var combobox = $(this.template());
+      this.$source.before(combobox);
+      this.$source.hide();
+      return combobox;
+    }
+
+  , disable: function() {
+      this.$element.prop('disabled', true);
+      this.$button.attr('disabled', true);
+      this.disabled = true;
+      this.$container.addClass('combobox-disabled');
+    }
+
+  , enable: function() {
+      this.$element.prop('disabled', false);
+      this.$button.attr('disabled', false);
+      this.disabled = false;
+      this.$container.removeClass('combobox-disabled');
+    }
+  , parse: function () {
+      var that = this
+        , map = {}
+        , source = []
+        , selected = false
+        , selectedValue = '';
+      this.$source.find('option').each(function() {
+        var option = $(this);
+        if (option.val() === '') {
+          that.options.placeholder = option.text();
+          return;
+        }
+        map[option.text()] = option.val();
+        source.push(option.text());
+        if (option.prop('selected')) {
+          selected = option.text();
+          selectedValue = option.val();
+        }
+      })
+      this.map = map;
+      if (selected) {
+        this.$element.val(selected);
+        this.$target.val(selectedValue);
+        this.$container.addClass('combobox-selected');
+        this.selected = true;
+      }
+      return source;
+    }
+
+  , transferAttributes: function() {
+    this.options.placeholder = this.$source.attr('data-placeholder') || this.options.placeholder
+    if(this.options.appendId !== undefined) {
+    	this.$element.attr('id', this.$source.attr('id') + this.options.appendId);
+    }
+    this.$element.attr('placeholder', this.options.placeholder)
+    this.$target.prop('name', this.$source.prop('name'))
+    this.$target.val(this.$source.val())
+    this.$source.removeAttr('name')  // Remove from source otherwise form will pass parameter twice.
+    this.$element.attr('required', this.$source.attr('required'))
+    this.$element.attr('rel', this.$source.attr('rel'))
+    this.$element.attr('title', this.$source.attr('title'))
+    this.$element.attr('class', this.$source.attr('class'))
+    this.$element.attr('tabindex', this.$source.attr('tabindex'))
+    this.$source.removeAttr('tabindex')
+    if (this.$source.attr('disabled')!==undefined)
+      this.disable();
+  }
+
+  , select: function () {
+      var val = this.$menu.find('.active').attr('data-value');
+      this.$element.val(this.updater(val)).trigger('change');
+      this.$target.val(this.map[val]).trigger('change');
+      this.$source.val(this.map[val]).trigger('change');
+      this.$container.addClass('combobox-selected');
+      this.selected = true;
+      return this.hide();
+    }
+
+  , updater: function (item) {
+      return item;
+    }
+
+  , show: function () {
+      var pos = $.extend({}, this.$element.position(), {
+        height: this.$element[0].offsetHeight
+      });
+
+      this.$menu
+        .insertAfter(this.$element)
+        .css({
+          top: pos.top + pos.height
+        , left: pos.left
+        })
+        .show();
+
+      $('.dropdown-menu').on('mousedown', $.proxy(this.scrollSafety, this));
+
+      this.shown = true;
+      return this;
+    }
+
+  , hide: function () {
+      this.$menu.hide();
+      $('.dropdown-menu').off('mousedown', $.proxy(this.scrollSafety, this));
+      this.$element.on('blur', $.proxy(this.blur, this));
+      this.shown = false;
+      return this;
+    }
+
+  , lookup: function (event) {
+      this.query = this.$element.val();
+      return this.process(this.source);
+    }
+
+  , process: function (items) {
+      var that = this;
+
+      items = $.grep(items, function (item) {
+        return that.matcher(item);
+      })
+
+      items = this.sorter(items);
+
+      if (!items.length) {
+        return this.shown ? this.hide() : this;
+      }
+
+      return this.render(items.slice(0, this.options.items)).show();
+    }
+
+  , template: function() {
+      if (this.options.bsVersion == '2') {
+        return '<div class="combobox-container"><input type="hidden" /> <div class="input-append"> <input type="text" autocomplete="off" /> <span class="add-on dropdown-toggle" data-dropdown="dropdown"> <span class="caret pulldown" style="vertical-align: middle"/> <i class="icon-remove remove"/> </span> </div> </div>'
+      } else if (this.options.bsVersion == '3') {
+        return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" /> <span class="input-group-addon dropdown-toggle" data-dropdown="dropdown"> <span class="caret pulldown" /> <span class="glyphicon glyphicon-remove remove" /> </span> </div> </div>'
+      } else {
+        return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" />'
+          + '<span class="input-group-append"' + (hasPopper ? ' data-toggle="dropdown" data-reference="parent"' : '') + '>'
+            + '<span class="input-group-text dropdown-toggle' + (this.options.iconCaret ? ' custom-icon' : '') + '">'
+              + (this.options.iconCaret ? '<span class="' + this.options.iconCaret + ' pulldown" />' : '')
+              + (this.options.iconRemove ? '<span class="' + this.options.iconRemove + ' remove" />' : '<span class="utf-remove remove" />')
+            + '</span>'
+          + '</span> </div> </div>';
+      }
+    }
+
+  , matcher: function (item) {
+      return ~item.toLowerCase().indexOf(this.query.toLowerCase());
+    }
+
+  , sorter: function (items) {
+      var beginswith = []
+        , caseSensitive = []
+        , caseInsensitive = []
+        , item;
+
+      while (item = items.shift()) {
+        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);}
+        else if (~item.indexOf(this.query)) {caseSensitive.push(item);}
+        else {caseInsensitive.push(item);}
+      }
+
+      return beginswith.concat(caseSensitive, caseInsensitive);
+    }
+
+  , highlighter: function (item) {
+      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
+      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
+        return '<strong>' + match + '</strong>';
+      })
+    }
+
+  , render: function (items) {
+      var that = this;
+
+      items = $(items).map(function (i, item) {
+        if(~that.renderLimit && i >= that.renderLimit)
+          return;
+        i = $(that.options.item).attr('data-value', item);
+        i.find('a').html(that.highlighter(item));
+        return i[0];
+      })
+
+      items.first().addClass('active');
+      this.$menu.html(items);
+      return this;
+    }
+
+  , next: function (event) {
+      var active = this.$menu.find('.active').removeClass('active')
+        , next = active.next();
+
+      if (!next.length) {
+        next = $(this.$menu.find('li')[0]);
+      }
+
+      next.addClass('active');
+    }
+
+  , prev: function (event) {
+      var active = this.$menu.find('.active').removeClass('active')
+        , prev = active.prev();
+
+      if (!prev.length) {
+        prev = this.$menu.find('li').last();
+      }
+
+      prev.addClass('active');
+    }
+
+  , toggle: function () {
+    if (!this.disabled) {
+      if (this.$container.hasClass('combobox-selected')) {
+        this.clearTarget();
+        this.triggerChange();
+        this.clearElement();
+      } else {
+        if (this.shown) {
+          this.hide();
+        } else {
+          this.clearElement();
+          this.lookup();
+        }
+      }
+    }
+  }
+
+  , scrollSafety: function(e) {
+      if (e.target.tagName == 'UL') {
+          this.$element.off('blur');
+      }
+  }
+  , clearElement: function () {
+    this.$element.val('').focus();
+  }
+
+  , clearTarget: function () {
+    this.$source.val('');
+    this.$target.val('');
+    this.$container.removeClass('combobox-selected');
+    this.selected = false;
+  }
+
+  , triggerChange: function () {
+    this.$source.trigger('change');
+  }
+
+  , refresh: function () {
+    this.source = this.parse();
+    this.options.items = this.source.length;
+  }
+
+  , listen: function () {
+      this.$element
+        .on('focus',    $.proxy(this.focus, this))
+        .on('blur',     $.proxy(this.blur, this))
+        .on('keypress', $.proxy(this.keypress, this))
+        .on('keyup',    $.proxy(this.keyup, this));
+
+      if (this.eventSupported('keydown')) {
+        this.$element.on('keydown', $.proxy(this.keydown, this));
+      }
+
+      this.$menu
+        .on('click', $.proxy(this.click, this))
+        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+        .on('mouseleave', 'li', $.proxy(this.mouseleave, this));
+
+      this.$button
+        .on('click', $.proxy(this.toggle, this));
+    }
+
+  , eventSupported: function(eventName) {
+      var isSupported = eventName in this.$element;
+      if (!isSupported) {
+        this.$element.setAttribute(eventName, 'return;');
+        isSupported = typeof this.$element[eventName] === 'function';
+      }
+      return isSupported;
+    }
+
+  , move: function (e) {
+      if (!this.shown) {return;}
+
+      switch(e.keyCode) {
+        case 9: // tab
+        case 13: // enter
+        case 27: // escape
+          e.preventDefault();
+          break;
+
+        case 38: // up arrow
+          e.preventDefault();
+          this.prev();
+          this.fixMenuScroll();
+          break;
+
+        case 40: // down arrow
+          e.preventDefault();
+          this.next();
+          this.fixMenuScroll();
+          break;
+      }
+
+      e.stopPropagation();
+    }
+
+  , fixMenuScroll: function(){
+      var active = this.$menu.find('.active');
+      if(active.length){
+          var top = active.position().top;
+          var bottom = top + active.height();
+          var scrollTop = this.$menu.scrollTop();
+          var menuHeight = this.$menu.height();
+          if(bottom > menuHeight){
+              this.$menu.scrollTop(scrollTop + bottom - menuHeight);
+          } else if(top < 0){
+              this.$menu.scrollTop(scrollTop + top);
+          }
+      }
+  }
+
+  , keydown: function (e) {
+      this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
+      this.move(e);
+    }
+
+  , keypress: function (e) {
+      if (this.suppressKeyPressRepeat) {return;}
+      this.move(e);
+    }
+
+  , keyup: function (e) {
+      switch(e.keyCode) {
+        case 40: // down arrow
+         if (!this.shown){
+           this.toggle();
+         }
+         break;
+        case 39: // right arrow
+        case 38: // up arrow
+        case 37: // left arrow
+        case 36: // home
+        case 35: // end
+        case 16: // shift
+        case 17: // ctrl
+        case 18: // alt
+          break;
+
+        case 9: // tab
+        case 13: // enter
+          if (!this.shown) {return;}
+          this.select();
+          break;
+
+        case 27: // escape
+          if (!this.shown) {return;}
+          this.hide();
+          break;
+
+        default:
+          this.clearTarget();
+          this.lookup();
+      }
+
+      e.stopPropagation();
+      e.preventDefault();
+  }
+
+  , focus: function (e) {
+      this.focused = true;
+    }
+
+  , blur: function (e) {
+      var that = this;
+      this.focused = false;
+      var val = this.$element.val();
+      if (!this.selected && val !== '' ) {
+        if(that.clearIfNoMatch)
+          this.$element.val('');
+        this.$source.val('').trigger('change');
+        this.$target.val('').trigger('change');
+      }
+      if (!this.mousedover && this.shown) {setTimeout(function () { that.hide(); }, 200);}
+    }
+
+  , click: function (e) {
+      e.stopPropagation();
+      e.preventDefault();
+      this.select();
+      this.$element.focus();
+    }
+
+  , mouseenter: function (e) {
+      this.mousedover = true;
+      this.$menu.find('.active').removeClass('active');
+      $(e.currentTarget).addClass('active');
+    }
+
+  , mouseleave: function (e) {
+      this.mousedover = false;
+    }
+  };
+
+  /* COMBOBOX PLUGIN DEFINITION
+   * =========================== */
+  $.fn.combobox = function ( option ) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('combobox')
+        , options = typeof option == 'object' && option;
+      if(!data) {$this.data('combobox', (data = new Combobox(this, options)));}
+      if (typeof option == 'string') {data[option]();}
+    });
+  };
+
+  $.fn.combobox.defaults = {
+    bsVersion: '4'
+  , menu: '<ul class="typeahead typeahead-long dropdown-menu"></ul>'
+  , item: '<li><a href="#" class="dropdown-item"></a></li>'
+  , iconCaret: undefined
+  , iconRemove: undefined
+  , clearIfNoMatch: true
+  };
+
+  $.fn.combobox.Constructor = Combobox;
+
+}( window.jQuery ));

commit 87b7ac00251a76c08f3127c75b3f73cb651c2fb2
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Wed Apr 10 05:41:18 2019 +0800

    Migrate cf edit components to elevator themes

diff --git a/share/html/Elements/EditCustomFieldAutocomplete b/share/html/Elements/EditCustomFieldAutocomplete
index 057421982..e48996ea5 100644
--- a/share/html/Elements/EditCustomFieldAutocomplete
+++ b/share/html/Elements/EditCustomFieldAutocomplete
@@ -53,7 +53,7 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
-name="<% $name %>" id="<% $name %>" class="CF-<%$CustomField->id%>-Edit"><% $Default || '' %></textarea>
+name="<% $name %>" id="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control"><% $Default || '' %></textarea>
 
 <script type="text/javascript">
 var id = <% "$name" |n,j%>;
@@ -78,7 +78,7 @@ jQuery('#'+id).autocomplete( {
 }
 );
 % } else {
-<input type="text" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit" value="<% $Default || '' %>"/>
+<input type="text" id="<% $name %>" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control" value="<% $Default || '' %>"/>
 <script type="text/javascript">
 var id = <% $name |n,j%>;
 id = id.replace(/:/g,'\\:');
diff --git a/share/html/Elements/EditCustomFieldBinary b/share/html/Elements/EditCustomFieldBinary
index e5aceee15..27b591a6b 100644
--- a/share/html/Elements/EditCustomFieldBinary
+++ b/share/html/Elements/EditCustomFieldBinary
@@ -47,8 +47,9 @@
 %# END BPS TAGGED BLOCK }}}
 % while ( $Values and my $value = $Values->Next ) {
 %# XXX - let user download the file(s) here?
-<input type="checkbox" name="<%$delete_name%>" class="checkbox CF-<%$CustomField->id%>-Edit" value="<% $value->Id %>" />
-
+<div class="custom-control custom-checkbox">
+  <input type="checkbox" id="<% $delete_name . $value->id %>" name="<%$delete_name%>" class="custom-control-input CF-<%$CustomField->id%>-Edit" value="<% $value->Id %>">
+  <label class="custom-control-label" for="<% $delete_name . $value->id %>">
 % if (my $url = RT->System->ExternalStorageURLFor($value)) {
 <a href="<%$url%>">
 % } else {
@@ -57,14 +58,19 @@
 
 <% $value->Content %>
 </a>
-<br />
+  </label>
+</div>
 % }
 % if ($MaxValues && $Values && $Values->Count >= $MaxValues ) {
 <div class="hints">
 <&|/l&>Reached maximum number, so new values will override old ones.</&>
 </div>
 % }
-<input type="file" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit" />
+
+<div class="custom-file">
+  <input type="file" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit custom-file-input" />
+  <label class="custom-file-label" for="customFile">Choose file</label>
+</div>
 
 <%INIT>
 my $name = $Name || $NamePrefix . $CustomField->Id . '-Upload';
diff --git a/share/html/Elements/EditCustomFieldDate b/share/html/Elements/EditCustomFieldDate
index cdacdaab7..0e1d84373 100644
--- a/share/html/Elements/EditCustomFieldDate
+++ b/share/html/Elements/EditCustomFieldDate
@@ -46,8 +46,14 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 % my $name = $Name || $NamePrefix.$CustomField->Id.'-Values';
-<& /Elements/SelectDate, Name => $name, Default => $Default, current => 0, ShowTime => 0 &> (<%$DateObj->AsString(Time => 0, Timezone => 'utc')%>)
-
+<div class="form-row">
+  <div class="col-auto">
+    <& /Elements/SelectDate, Name => $name, Default => $Default, current => 0, ShowTime => 0 &>
+  </div>
+  <div class="col-auto">
+    <span class="current-value form-control">(<%$DateObj->AsString(Time => 0, Timezone => 'utc')%>)</span>
+  </div>
+</div>
 <%INIT>
 my $DateObj = RT::Date->new ( $session{'CurrentUser'} );
 $DateObj->Set( Format => 'unknown', Value => $Default, Timezone => 'utc' );
diff --git a/share/html/Elements/EditCustomFieldDateTime b/share/html/Elements/EditCustomFieldDateTime
index 1039cb106..f15452d05 100644
--- a/share/html/Elements/EditCustomFieldDateTime
+++ b/share/html/Elements/EditCustomFieldDateTime
@@ -46,7 +46,14 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 % my $name = $Name || $NamePrefix.$CustomField->Id.'-Values';
-<& /Elements/SelectDate, Name => $name, Default => $Default, current => 0 &> (<%$DateObj->AsString%>)
+<div class="form-row">
+    <div class="col-auto">
+        <& /Elements/SelectDate, Name => $name, Default => $Default, current => 0 &>
+    </div>
+    <div class="col-auto">
+        <span class="current-value form-control">(<%$DateObj->AsString%>)</span>
+    </div>
+</div>
 
 <%INIT>
 my $DateObj = RT::Date->new ( $session{'CurrentUser'} );
diff --git a/share/html/Elements/EditCustomFieldFreeform b/share/html/Elements/EditCustomFieldFreeform
index 387b87e78..1fa233469 100644
--- a/share/html/Elements/EditCustomFieldFreeform
+++ b/share/html/Elements/EditCustomFieldFreeform
@@ -54,13 +54,13 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
-name="<%$name%>" id="<%$name%>" wrap="off" class="CF-<%$CustomField->id%>-Edit"><% defined($Default) ? $Default : '' %></textarea>
+name="<%$name%>" id="<%$name%>" wrap="off" class="CF-<%$CustomField->id%>-Edit form-control"><% defined($Default) ? $Default : '' %></textarea>
 % } else {
 <input type="text" name="<%$name%>" id="<%$name%>" \
 % if ( defined $Cols ) {
 size="<% $Cols %>" \
 % }
-class="CF-<%$CustomField->id%>-Edit" value="<% defined($Default) ? $Default : ''%>" />
+class="CF-<%$CustomField->id%>-Edit form-control" value="<% defined($Default) ? $Default : ''%>" />
 % }
 <%INIT>
 if ( $Multiple and $Values ) {
diff --git a/share/html/Elements/EditCustomFieldImage b/share/html/Elements/EditCustomFieldImage
index 374504b1f..07b0cc0bc 100644
--- a/share/html/Elements/EditCustomFieldImage
+++ b/share/html/Elements/EditCustomFieldImage
@@ -46,15 +46,23 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 % while ($Values and my $value = $Values->Next ) {
-<input type="checkbox" class="checkbox" name="<%$delete_name%>" class="CF-<%$CustomField->id%>-Edit" value="<% $value->Id %>" /><& ShowCustomFieldImage, Object => $value &>
-<br />
+<div class="custom-control custom-checkbox">
+  <input type="checkbox" id="<% $delete_name . $value->id %>" name="<%$delete_name%>" class="custom-control-input CF-<%$CustomField->id%>-Edit" value="<% $value->Id %>">
+  <label class="custom-control-label" for="<% $delete_name . $value->id %>">
+    <& ShowCustomFieldImage, Object => $value &>
+  </label>
+</div>
 % }
 % if ($MaxValues && $Values && $Values->Count >= $MaxValues ) {
 <div class="hints">
 <&|/l&>Reached maximum number, so new values will override old ones.</&>
 </div>
 % }
-<input type="file" name="<%$name%>" class="CF-<%$CustomField->id%>-Edit" />
+
+<div class="custom-file">
+  <input type="file" name="<% $name %>" class="CF-<%$CustomField->id%>-Edit custom-file-input" />
+  <label class="custom-file-label" for="customFile">Choose file</label>
+</div>
 
 <%INIT>
 my $name = $Name || $NamePrefix . $CustomField->Id . '-Upload';
diff --git a/share/html/Elements/EditCustomFieldSelect b/share/html/Elements/EditCustomFieldSelect
index 9c91755f1..dd42ab089 100644
--- a/share/html/Elements/EditCustomFieldSelect
+++ b/share/html/Elements/EditCustomFieldSelect
@@ -61,9 +61,9 @@
 >
 %   if ( $checktype eq 'radio' ) {
 % if ( $show_empty_option ) {
-  <div class="none">
-  <input class="none" type="<% $checktype %>" name="<% $name %>" id="<% $name %>-none" value="" <% keys %default ? '' : ' checked="checked"' |n%> />
-  <label for="<% $name %>-none"><&|/l&>(no value)</&></label><br />
+  <div class="none custom-control custom-radio">
+    <input class="none custom-control-input" id="<% $name %>-none" type="<% $checktype %>" name="<% $name %>" id="<% $name %>-none" value="" <% keys %default ? '' : ' checked="checked"' |n%> />
+    <label class="custom-control-label" for="<% $name %>-none"><&|/l&>(no value)</&></label>
   </div>
 % }
 %   }
@@ -71,9 +71,9 @@
 %   while ( my $value = $CFVs->Next ) {
 %     my $content = $value->Name;
 %     my $labelid = "$name-". $value->id;
-<div data-name="<% $value->Category || '' %>">
-  <input type="<% $checktype %>" name="<% $name %>" id="<% $labelid %>" value="<% $content %>" <% $default{ lc $content }? ' checked="checked"' : '' |n%> />
-  <label for="<% $labelid %>"><% $content %></label><br />
+<div data-name="<% $value->Category || '' %>" class="custom-control custom-radio">
+  <input class="custom-control-input"  type="<% $checktype %>" name="<% $name %>" id="<% $labelid %>" value="<% $content %>" <% $default{ lc $content }? ' checked="checked"' : '' |n%> />
+  <label class="custom-control-label" for="<% $labelid %>"><% $content %></label><br />
 </div>
 %   }
 </div>
@@ -92,7 +92,17 @@
 % my $size = ($Rows && ( $Multiple || !@category || $RenderType eq 'Select box')) ? $Rows : 1;
 
 <select
-  name="<%$name%>" id="<%$name%>" class="CF-Edit CF-<%$CustomField->id%>-Edit<% $use_chosen ? ' chosen' : '' %><% $size > 1 ? ' tall' : '' %>"
+  name="<%$name%>" id="<%$name%>"
+
+% if ( grep /\bbootstrap-select\b/, RT::Interface::Web->JSFiles ) {
+    class="CF-Edit CF-<%$CustomField->id%>-Edit <% $RenderType eq 'Dropdown' ? 'selectpicker' : 'form-control' %>"
+%   if ( $use_chosen ) {
+    data-live-search="true"
+%   }
+% } else {
+    class="CF-Edit CF-<%$CustomField->id%>-Edit<% $use_chosen ? ' chosen' : '' %><% $size > 1 ? ' tall' : '' %>"
+% }
+
 % if ($CustomField->BasedOnObj->id) {
   data-cascade-based-on-name="<% $BasedOnName || $NamePrefix . $CustomField->BasedOnObj->id . '-Value' |n %>"
 % }
diff --git a/share/html/Elements/EditCustomFieldText b/share/html/Elements/EditCustomFieldText
index 84d37e3ec..008d9662c 100644
--- a/share/html/Elements/EditCustomFieldText
+++ b/share/html/Elements/EditCustomFieldText
@@ -53,7 +53,7 @@ cols="<% $Cols %>" \
 % if ( defined $Rows ) {
 rows="<% $Rows %>" \
 % }
-name="<%$name%>" class="CF-<%$CustomField->id%>-Edit"><% $value->Content %></textarea><br />
+name="<%$name%>" class="CF-<%$CustomField->id%>-Edit form-control"><% $value->Content %></textarea><br />
 % }
 % if (!$MaxValues or !$Values or $Values->Count < $MaxValues) {
 <textarea \
diff --git a/share/html/Widgets/ComboBox b/share/html/Widgets/ComboBox
index c87934dfc..2453f73b6 100644
--- a/share/html/Widgets/ComboBox
+++ b/share/html/Widgets/ComboBox
@@ -49,6 +49,17 @@
 # the $z_index here is to fix wrong z-index bug in ie7
 my $z_index = 9999;
 </%once>
+
+% if ( grep { /\bbootstrap-combobox\b/ } RT::Interface::Web->JSFiles ) {
+<div class="combobox-wrapper" data-name="<% $Name %>" data-value="<% $Default // '' %>">
+  <select class="combobox" size="<% $Rows %>">
+    <option value=""></option>
+% for my $value (@Values) {
+    <option value="<% $value %>" <% ($Default // '') eq $value ? 'selected="selected"' : '' %>><% $value%></option>
+% }
+  </select>
+</div>
+% } else {
 %# reset $z_index. assuming at most 1000 comboboxx in one page
 % $z_index = 9999 if $z_index < 9000;
 <nobr>
@@ -67,6 +78,8 @@ my $z_index = 9999;
 ComboBox_InitWith(<% $Name |n,j %>);
 //--></script>
 </nobr>
+
+% }
 <%ARGS>
 $Name
 $Size    => undef
diff --git a/share/static/js/util.js b/share/static/js/util.js
index 3f0a99c3a..e9bb4c307 100644
--- a/share/static/js/util.js
+++ b/share/static/js/util.js
@@ -586,6 +586,18 @@ jQuery(function() {
             e.closest('div.titlebox').find('div.card-header span.right').removeClass('invisible');
         });
     });
+
+    if ( jQuery('.combobox').combobox ) {
+        jQuery('.combobox').combobox({ clearIfNoMatch: false });
+        jQuery('.combobox-wrapper').each( function() {
+            jQuery(this).find('input[type=text]').prop('name', jQuery(this).data('name')).prop('value', jQuery(this).data('value'));
+        });
+    }
+
+    /* Show selected file name in UI */
+    jQuery('.custom-file input').change(function (e) {
+        jQuery(this).next('.custom-file-label').html(e.target.files[0].name);
+    });
 });
 
 // focus jquery object in window, only moving the screen when necessary
diff --git a/t/assets/web.t b/t/assets/web.t
index 67a842915..2753128e1 100644
--- a/t/assets/web.t
+++ b/t/assets/web.t
@@ -22,9 +22,9 @@ my $material = create_cf( Name => 'Material' );
 ok $material->id, "Created CF";
 
 my %CF = (
-    Height      => ".CF-" . $height->id    . "-Edit",
-    Material    => ".CF-" . $material->id  . "-Edit",
-    Purchased   => ".CF-" . $purchased->id . "-Edit",
+    Height      => ".CF-" . $height->id    . "-Edit form-control",
+    Material    => ".CF-" . $material->id  . "-Edit form-control",
+    Purchased   => ".CF-" . $purchased->id . "-Edit form-control",
 );
 
 my ($base, $m) = RT::Test::Assets->started_ok;

commit f89f5f7876032a4406b0c5fe3ea4666e8685f979
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Wed Apr 10 07:21:32 2019 +0800

    Migrate ticket modify pages to elevator themes

diff --git a/share/html/Elements/AddLinks b/share/html/Elements/AddLinks
index 47dc14b98..ce5228b86 100644
--- a/share/html/Elements/AddLinks
+++ b/share/html/Elements/AddLinks
@@ -73,27 +73,27 @@ $exclude .= qq| data-autocomplete-exclude="$id"| if $Object->id;
 <div class="fields">
   <div class="field">
     <span class="label"><& ShowRelationLabel, Object => $Object, Label => loc('Depends on').':', Relation => 'DependsOn' &></span>
-    <span class="value entry"><input type="text" name="<%$id%>-DependsOn" value="<% $ARGSRef->{"$id-DependsOn"} || '' %>" <% $exclude |n%>/></span>
+    <span class="value entry"><input type="text" class="form-control" name="<%$id%>-DependsOn" value="<% $ARGSRef->{"$id-DependsOn"} || '' %>" <% $exclude |n%>/></span>
   </div>
   <div class="field">
     <span class="label"><& ShowRelationLabel, Object => $Object, Label => loc('Depended on by').':', Relation => 'DependedOnBy' &></span>
-    <span class="value entry"><input type="text" name="DependsOn-<%$id%>" value="<% $ARGSRef->{"DependsOn-$id"} || '' %>" <% $exclude |n%>/></span>
+    <span class="value entry"><input type="text" class="form-control" name="DependsOn-<%$id%>" value="<% $ARGSRef->{"DependsOn-$id"} || '' %>" <% $exclude |n%>/></span>
   </div>
   <div class="field">
     <span class="label"><& ShowRelationLabel, Object => $Object, Label => loc('Parents').':', Relation => 'Parents' &></span>
-    <span class="value entry"><input type="text" name="<%$id%>-MemberOf" value="<% $ARGSRef->{"$id-MemberOf"} || '' %>" <% $exclude |n%>/></span>
+    <span class="value entry"><input type="text" class="form-control" name="<%$id%>-MemberOf" value="<% $ARGSRef->{"$id-MemberOf"} || '' %>" <% $exclude |n%>/></span>
   </div>
   <div class="field">
     <span class="label"><& ShowRelationLabel, Object => $Object, Label => loc('Children').':', Relation => 'Children' &></span>
-    <span class="value entry"> <input type="text" name="MemberOf-<%$id%>" value="<% $ARGSRef->{"MemberOf-$id"} || '' %>" <% $exclude |n%>/></span>
+    <span class="value entry"> <input type="text" class="form-control" name="MemberOf-<%$id%>" value="<% $ARGSRef->{"MemberOf-$id"} || '' %>" <% $exclude |n%>/></span>
   </div>
   <div class="field">
     <span class="label"><& ShowRelationLabel, Object => $Object, Label => loc('Refers to').':', Relation => 'RefersTo' &></span>
-    <span class="value entry"><input type="text" name="<%$id%>-RefersTo" value="<% $ARGSRef->{"$id-RefersTo"} || '' %>" <% $exclude |n%>/></span>
+    <span class="value entry"><input type="text" class="form-control" name="<%$id%>-RefersTo" value="<% $ARGSRef->{"$id-RefersTo"} || '' %>" <% $exclude |n%>/></span>
   </div>
   <div class="field">
     <span class="label"><& ShowRelationLabel, Object => $Object, Label => loc('Referred to by').':', Relation => 'ReferredToBy' &></span>
-    <span class="value entry"><input type="text" name="RefersTo-<%$id%>" value="<% $ARGSRef->{"RefersTo-$id"} || '' %>" <% $exclude |n%>/></span>
+    <span class="value entry"><input type="text" class="form-control" name="RefersTo-<%$id%>" value="<% $ARGSRef->{"RefersTo-$id"} || '' %>" <% $exclude |n%>/></span>
   </div>
   <& /Elements/EditCustomFields,
         Object          => $Object,
diff --git a/share/html/Elements/EditLink b/share/html/Elements/EditLink
index e6f139708..d6c158288 100644
--- a/share/html/Elements/EditLink
+++ b/share/html/Elements/EditLink
@@ -45,15 +45,15 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
+<div class="custom-control custom-checkbox">
 % if ( $Mode eq 'Target' ) {
-    <input type="checkbox" class="checkbox" id="DeleteLink--<%$Link->Type%>-<%$Link->Target%>" name="DeleteLink--<%$Link->Type%>-<%$Link->Target%>" value="1" />
-    <label for="DeleteLink--<%$Link->Type%>-<%$Link->Target%>"><& ShowLink, URI => $Link->TargetURI &></label>
+  <input type="checkbox" class="checkbox custom-control-input" id="DeleteLink--<%$Link->Type%>-<%$Link->Target%>" name="DeleteLink--<%$Link->Type%>-<%$Link->Target%>" value="1" />
+  <label class="custom-control-label" for="DeleteLink--<%$Link->Type%>-<%$Link->Target%>"><& ShowLink, URI => $Link->TargetURI &></label>
 % } else {
-      <input type="checkbox" class="checkbox" id="DeleteLink-<%$Link->Base%>-<%$Link->Type%>-" name="DeleteLink-<%$Link->Base%>-<%$Link->Type%>-" value="1" />
-      <label for="DeleteLink-<%$Link->Base%>-<%$Link->Type%>-"><& ShowLink, URI => $Link->BaseURI &></label>
+  <input type="checkbox" class="checkbox custom-control-input" id="DeleteLink-<%$Link->Base%>-<%$Link->Type%>-" name="DeleteLink-<%$Link->Base%>-<%$Link->Type%>-" value="1" />
+  <label class="custom-control-label" for="DeleteLink-<%$Link->Base%>-<%$Link->Type%>-"><& ShowLink, URI => $Link->BaseURI &></label>
 % }
-
-<br />
+</div>
 
 <%INIT>
 my $ModeObj = $Mode . 'Obj';
diff --git a/share/html/Elements/EditLinks b/share/html/Elements/EditLinks
index 9a543bbc8..e49c5bba0 100644
--- a/share/html/Elements/EditLinks
+++ b/share/html/Elements/EditLinks
@@ -53,9 +53,11 @@
   <div class="field">
     <span class="labeltop"><& ShowRelationLabel, Object => $Object, Label => loc('Depends on').':', Relation => 'DependsOn' &></span>
     <span class="value">
-      <div class="checkboxes">
+      <div class="checkboxes list-group list-group-compact">
 % while (my $link = $Object->DependsOn->Next) {
-      <& EditLink, Link => $link, Mode => 'Target' &>
+        <div class="list-group-item">
+          <& EditLink, Link => $link, Mode => 'Target' &>
+        </div>
 % }
       </div>
     </span>
@@ -63,9 +65,11 @@
   <div class="field">
     <span class="labeltop"><& ShowRelationLabel, Object => $Object, Label => loc('Depended on by').':', Relation => 'DependedOnBy' &></span>
     <span class="value">
-      <div class="checkboxes">
+      <div class="checkboxes list-group list-group-compact">
 % while (my $link = $Object->DependedOnBy->Next) {
-      <& EditLink, Link => $link, Mode => 'Base' &>
+        <div class="list-group-item">
+          <& EditLink, Link => $link, Mode => 'Base' &>
+        </div>
 % }
       </div>
     </span>
@@ -73,9 +77,11 @@
   <div class="field">
     <span class="labeltop"><& ShowRelationLabel, Object => $Object, Label => loc('Parents').':', Relation => 'Parents' &></span>
     <span class="value">
-      <div class="checkboxes">
+      <div class="checkboxes list-group list-group-compact">
 % while (my $link = $Object->MemberOf->Next) {
-      <& EditLink, Link => $link, Mode => 'Target' &>
+        <div class="list-group-item">
+          <& EditLink, Link => $link, Mode => 'Target' &>
+        </div>
 % }
       </div>
     </span>
@@ -83,9 +89,11 @@
   <div class="field">
     <span class="labeltop"><& ShowRelationLabel, Object => $Object, Label => loc('Children').':', Relation => 'Children' &></span>
     <span class="value">
-      <div class="checkboxes">
+      <div class="checkboxes list-group list-group-compact">
 % while (my $link = $Object->Members->Next) {
-      <& EditLink, Link => $link, Mode => 'Base' &>
+        <div class="list-group-item">
+          <& EditLink, Link => $link, Mode => 'Base' &>
+        </div>
 % }
       </div>
     </span>
@@ -93,9 +101,11 @@
   <div class="field">
     <span class="labeltop"><& ShowRelationLabel, Object => $Object, Label => loc('Refers to').':', Relation => 'RefersTo' &></span>
     <span class="value">
-      <div class="checkboxes">
+      <div class="checkboxes list-group list-group-compact">
 % while (my $link = $Object->RefersTo->Next) {
-      <& EditLink, Link => $link, Mode => 'Target' &>
+        <div class="list-group-item">
+          <& EditLink, Link => $link, Mode => 'Target' &>
+        </div>
 %}
       </div>
     </span>
@@ -103,9 +113,11 @@
   <div class="field">
     <span class="labeltop"><& ShowRelationLabel, Object => $Object, Label => loc('Referred to by').':', Relation => 'ReferredToBy' &></span>
     <span class="value">
-      <div class="checkboxes">
+      <div class="checkboxes list-group list-group-compact">
 % while (my $link = $Object->ReferredToBy->Next) {
-      <& EditLink, Link => $link, Mode => 'Base' &>
+        <div class="list-group-item">
+          <& EditLink, Link => $link, Mode => 'Base' &>
+        </div>
 % }
       </div>
     </span>
diff --git a/share/html/Elements/EmailInput b/share/html/Elements/EmailInput
index 078a2870c..547eb3450 100644
--- a/share/html/Elements/EmailInput
+++ b/share/html/Elements/EmailInput
@@ -49,6 +49,7 @@
     type="text"
     id="<% $Name %>"
     name="<% $Name %>"
+    class="form-control"
     value="<% $Default || '' %>"
 
 % if (defined $Size) {
diff --git a/share/html/Elements/SelectGroups b/share/html/Elements/SelectGroups
index c93815a28..cf1f36b7d 100644
--- a/share/html/Elements/SelectGroups
+++ b/share/html/Elements/SelectGroups
@@ -45,17 +45,23 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<% $SelectFieldName %>">
+<div class="col-md-3">
+  <select name="<% $SelectFieldName %>" class="selectpicker form-control">
 % foreach my $col (RT::Group->BasicColumns) {
-<option <% ($GroupField eq $col->[0]) ? 'selected="selected"' : '' %> value="<% $col->[0] %>"><% loc($col->[1]) %></option>
+    <option <% ($GroupField eq $col->[0]) ? 'selected="selected"' : '' %> value="<% $col->[0] %>"><% loc($col->[1]) %></option>
 % }
 % while (my $CF = $CFs->Next) {
 %   my $val = "CustomField-" . $CF->Id;
-<option <% ($GroupField eq $val) ? 'selected="selected"' : '' %> value="<% $val %>"><&|/l&>CustomField</&>: <% $CF->Name %></option>
+    <option <% ($GroupField eq $val) ? 'selected="selected"' : '' %> value="<% $val %>"><&|/l&>CustomField</&>: <% $CF->Name %></option>
 % }
-</select>
-<& /Elements/SelectMatch, Name => $SelectOpName, Default => $GroupOp &>
-<input type="text" size="8" name="<% $InputStringName %>" value="<% $GroupString %>" />
+  </select>
+</div>
+<div class="col-md-3">
+  <& /Elements/SelectMatch, Name => $SelectOpName, Default => $GroupOp &>
+</div>
+<div class="col-md-3">
+  <input type="text" size="8" name="<% $InputStringName %>" value="<% $GroupString %>" class="form-control"/>
+</div>
 <%INIT>
 my $CFs = RT::CustomFields->new($session{'CurrentUser'});
 $CFs->LimitToChildType('RT::Group');
diff --git a/share/html/Elements/SelectUsers b/share/html/Elements/SelectUsers
index 930815365..aa7fd5afc 100644
--- a/share/html/Elements/SelectUsers
+++ b/share/html/Elements/SelectUsers
@@ -45,17 +45,23 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<select name="<% $SelectFieldName %>">
+<div class="col-md-3">
+  <select name="<% $SelectFieldName %>" class="selectpicker form-control">
 % foreach my $col (@fields) {
-<option <% ($UserField eq $col->[0]) ? 'selected="selected"' : '' |n %> value="<% $col->[0] %>"><% loc($col->[1]) %></option>
+    <option <% ($UserField eq $col->[0]) ? 'selected="selected"' : '' |n %> value="<% $col->[0] %>"><% loc($col->[1]) %></option>
 % }
 % while (my $CF = $CFs->Next) {
 %   my $val = "CustomField-" . $CF->Id;
-<option <% ($UserField eq $val) ? 'selected="selected"' : '' |n %> value="<% $val %>"><&|/l&>CustomField</&>: <% $CF->Name %></option>
+    <option <% ($UserField eq $val) ? 'selected="selected"' : '' |n %> value="<% $val %>"><&|/l&>CustomField</&>: <% $CF->Name %></option>
 % }
-</select>
-<& /Elements/SelectMatch, Name => $SelectOpName, Default => $UserOp &>
-<input type="text" size="8" name="<% $InputStringName %>" value="<% $UserString %>" />
+  </select>
+</div>
+<div class="col-md-3">
+  <& /Elements/SelectMatch, Name => $SelectOpName, Default => $UserOp &>
+</div>
+<div class="col-md-3">
+  <input type="text" size="8" name="<% $InputStringName %>" value="<% $UserString %>" class="form-control" />
+</div>
 <%INIT>
 my $CFs = RT::CustomFields->new($session{'CurrentUser'});
 $CFs->LimitToChildType('RT::User');
diff --git a/share/html/Elements/ShowLinks b/share/html/Elements/ShowLinks
index 68dccca4c..afdc0f135 100644
--- a/share/html/Elements/ShowLinks
+++ b/share/html/Elements/ShowLinks
@@ -69,8 +69,8 @@
 % if ($Object->isa('RT::Ticket')) {
   <form action="<% RT->Config->Get('WebPath') ."/Helpers/SpawnLinkedTicket" %>" name="SpawnLinkedTicket">
     <input type="hidden" name="CloneTicket" value="<% $Object->id %>">
-    <input type="submit" value="<&|/l&>Create</&>" name="SpawnLinkedTicket">
-    <select name="LinkType">
+    <input type="submit" value="<&|/l&>Create</&>" name="SpawnLinkedTicket" class="btn btn-primary">
+    <select name="LinkType" class="selectpicker">
       <option value="DependsOn-new"><% loc('Depends on') %></option>
       <option value="new-DependsOn"><% loc('Depended on by') %></option>
       <option value="MemberOf-new"><% loc('Parents') %></option>
diff --git a/share/html/Ticket/Elements/AddWatchers b/share/html/Ticket/Elements/AddWatchers
index dc1e769a6..c485ae63c 100644
--- a/share/html/Ticket/Elements/AddWatchers
+++ b/share/html/Ticket/Elements/AddWatchers
@@ -50,64 +50,87 @@
 
 <&|/l&>Add new watchers</&>:<br />
 
-<table>
 % if ($Users and $Users->Count) {
-<tr><td>
-<&|/l&>Type</&>
-</td><td>
-<&|/l&>Username</&>
-</td></tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <&|/l&>Type</&>
+    </div>
+    <div class="col-md-3">
+      <&|/l&>Username</&>
+    </div>
+  </div>
 % while (my $u = $Users->Next ) {
-<tr>
-<td><&/Elements/SelectWatcherType,
-    Name  => "Ticket-AddWatcher-Principal-". $u->PrincipalId,
-    Queue => $Ticket->QueueObj,
-&></td>
-<td><& '/Elements/ShowUser', User => $u, style=>'verbose' &></td>
-</tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <&/Elements/SelectWatcherType,
+        Name  => "Ticket-AddWatcher-Principal-". $u->PrincipalId,
+        Queue => $Ticket->QueueObj,
+      &>
+    </div>
+    <div class="col-md-3">
+      <span class="form-control current-value">
+        <& '/Elements/ShowUser', User => $u, style=>'verbose' &>
+      </span>
+    </div>
+  </div>
 % }
 % }
 
 % if ($Groups and $Groups->Count) {
-<tr><td>
-<&|/l&>Type</&>
-</td><td>
-<&|/l&>Group</&>
-</td></tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <&|/l&>Type</&>
+    </div>
+    <div>
+      <&|/l&>Group</&>
+    </div>
+  </div>
 % while (my $g = $Groups->Next ) {
-<tr>
-<td><& /Elements/SelectWatcherType,
-    Name  => "Ticket-AddWatcher-Principal-".$g->PrincipalId,
-    Queue => $Ticket->QueueObj,
-&></td>
-<td><%$g->Name%> (<%$g->Description%>)</td>
-</tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <& /Elements/SelectWatcherType,
+        Name  => "Ticket-AddWatcher-Principal-".$g->PrincipalId,
+        Queue => $Ticket->QueueObj,
+      &>
+    </div>
+    <div class="col-md-3">
+      <%$g->Name%> (<%$g->Description%>)
+    </div>
+  </div>
 % }
 % }
 
-<tr><td>
-<&|/l&>Type</&>
-</td><td>
-<&|/l&>Email</&>
-</td></tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <&|/l&>Type</&>
+    </div>
+    <div class="col-md-3">
+      <&|/l&>Email</&>
+    </div>
+  </div>
 % my $counter = 4;
 % for my $email (@extras) {
 % $counter++;
-<tr><td>
-<&/Elements/SelectWatcherType, Name => "WatcherTypeEmail".$counter, Queue => $Ticket->QueueObj &>
-</td><td>
-<input type="hidden" name="WatcherAddressEmail<%$counter%>" value="<%$email->format%>">
-<%$email->format%>
-</td></tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <&/Elements/SelectWatcherType, Name => "WatcherTypeEmail".$counter, Queue => $Ticket->QueueObj &>
+    </div>
+    <div class="col-md-3">
+      <input type="hidden" name="WatcherAddressEmail<%$counter%>" value="<%$email->format%>">
+      <%$email->format%>
+    </div>
+  </div>
 % }
 % for my $i (1 .. 3) {
-<tr><td>
-<&/Elements/SelectWatcherType, Name => "WatcherTypeEmail" . $i, Queue => $Ticket->QueueObj &>
-</td><td>
-<& /Elements/EmailInput, Name => 'WatcherAddressEmail' . $i, Size => '20' &>
-</td></tr>
+  <div class="form-row">
+    <div class="col-md-3">
+      <&/Elements/SelectWatcherType, Name => "WatcherTypeEmail" . $i, Queue => $Ticket->QueueObj &>
+    </div>
+    <div class="col-md-3">
+      <& /Elements/EmailInput, Name => 'WatcherAddressEmail' . $i, Size => '20' &>
+    </div>
+  </div>
 % }
-</table>
 
 <%INIT>
 my ($Users, $Groups);
diff --git a/share/html/Ticket/Elements/EditBasics b/share/html/Ticket/Elements/EditBasics
index 103c098be..4d7d76db6 100644
--- a/share/html/Ticket/Elements/EditBasics
+++ b/share/html/Ticket/Elements/EditBasics
@@ -62,7 +62,7 @@ unless ( @fields ) {
     my $subject = $defaults{'Subject'} || $TicketObj->Subject;
     @fields = (
         {   name => 'Subject',
-            html => '<input name="Subject" type="text" value="'.(defined($subject) ? $m->interp->apply_escapes( $subject, 'h' ) : '').'" />',
+            html => '<input name="Subject" type="text" value="'.(defined($subject) ? $m->interp->apply_escapes( $subject, 'h' ) : '').'" class="form-control" />',
         },
         {   name => 'Status',
             comp => '/Ticket/Elements/SelectStatus',
diff --git a/share/html/Ticket/Elements/EditDates b/share/html/Ticket/Elements/EditDates
index 656fcb34c..9193be334 100644
--- a/share/html/Ticket/Elements/EditDates
+++ b/share/html/Ticket/Elements/EditDates
@@ -49,6 +49,8 @@
   <div class="field">
     <span class="label"><&|/l&>Starts</&>:</span>
     <span class="value entry">
+        <div class="form-row">
+          <div class="col-auto">
         <& /Elements/SelectDate,
             menu_prefix => 'Starts',
             current     => 0,
@@ -56,12 +58,18 @@
             Object      => $TicketObj,
             ARGSRef     => \%ARGS,
         &>
-        <span class="current-value">(<% $TicketObj->StartsObj->AsString %>)</span>
+          </div>
+          <div class="col-auto">
+            <span class="current-value form-control">(<% $TicketObj->StartsObj->AsString %>)</span>
+          </div>
+        </div>
     </span>
   </div>
   <div class="field">
     <span class="label"><&|/l&>Started</&>:</span>
     <span class="value entry">
+        <div class="form-row">
+          <div class="col-auto">
         <& /Elements/SelectDate,
             menu_prefix => 'Started',
             current     => 0,
@@ -69,7 +77,11 @@
             Object      => $TicketObj,
             ARGSRef     => \%ARGS,
         &>
-        <span class="current-value">(<%$TicketObj->StartedObj->AsString %>)</span>
+          </div>
+          <div class="col-auto">
+            <span class="current-value form-control">(<%$TicketObj->StartedObj->AsString %>)</span>
+          </div>
+        </div>
     </span>
   </div>
 
@@ -78,6 +90,8 @@
       <&|/l&>Last Contact</&>:
     </span>
     <span class="value entry">
+        <div class="form-row">
+          <div class="col-auto">
         <& /Elements/SelectDate,
             menu_prefix => 'Told',
             current     => 0,
@@ -85,12 +99,18 @@
             Object      => $TicketObj,
             ARGSRef     => \%ARGS,
         &>
-        <span class="current-value">(<% $TicketObj->ToldObj->AsString %>)</span>
+          </div>
+          <div class="col-auto">
+        <span class="current-value form-control">(<% $TicketObj->ToldObj->AsString %>)</span>
+          </div>
+        </div>
     </span>
   </div>
   <div class="field">
     <span class="label"><&|/l&>Due</&>:</span>
     <span class="value entry">
+        <div class="form-row">
+          <div class="col-auto">
         <& /Elements/SelectDate,
             menu_prefix => 'Due',
             current     => 0,
@@ -98,7 +118,11 @@
             Object      => $TicketObj,
             ARGSRef     => \%ARGS,
         &>
-        <span class="current-value">(<% $TicketObj->DueObj->AsString %>)</span>
+          </div>
+          <div class="col-auto">
+        <span class="current-value form-control">(<% $TicketObj->DueObj->AsString %>)</span>
+          </div>
+        </div>
     </span>
   </div>
   <& /Elements/EditCustomFields, Object => $TicketObj, Grouping => 'Dates', InTable => 1 &>
diff --git a/share/html/Ticket/Elements/EditMerge b/share/html/Ticket/Elements/EditMerge
index f14b33d1f..0c74f2230 100644
--- a/share/html/Ticket/Elements/EditMerge
+++ b/share/html/Ticket/Elements/EditMerge
@@ -52,7 +52,7 @@
 <div class="fields">
   <div class="field">
     <span class="label"><&|/l&>Merge into</&>:</span>
-    <span class="value entry"><input type="text" name="<% $Name %>" value="<% $Default || '' %>" data-autocomplete="Tickets" data-autocomplete-exclude="<% join( ' ', @excludes) || '' %>" /></span>
+    <span class="value entry"><input type="text" class="form-control" name="<% $Name %>" value="<% $Default || '' %>" data-autocomplete="Tickets" data-autocomplete-exclude="<% join( ' ', @excludes) || '' %>" /></span>
   </div>
 </div>
 
diff --git a/share/html/Ticket/Elements/EditPeople b/share/html/Ticket/Elements/EditPeople
index 25bafe579..ca409ac35 100644
--- a/share/html/Ticket/Elements/EditPeople
+++ b/share/html/Ticket/Elements/EditPeople
@@ -46,29 +46,36 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <div class="row">
-  <div class="boxcontainer col-md-6">
+  <div class="boxcontainer new-watchers col-xl-6">
 
 <h3><&|/l&>New watchers</&></h3>
 <&|/l&>Find people whose</&><br />
+<div class="form-row">
 <& /Elements/SelectUsers &>
-<input type="submit" class="button" name="OnlySearchForPeople" value="<&|/l&>Go!</&>" />
+  <div class="col-auto">
+<input type="submit" class="button btn btn-primary form-control" name="OnlySearchForPeople" value="<&|/l&>Go!</&>" />
+  </div>
+</div>
 <br />
 <&|/l&>Find groups whose</&><br />
+<div class="form-row">
 <& /Elements/SelectGroups &>
-<input type="submit" class="button" name="OnlySearchForGroup" value="<&|/l&>Go!</&>" />
+  <div class="col-auto">
+<input type="submit" class="button btn btn-primary form-control" name="OnlySearchForGroup" value="<&|/l&>Go!</&>" />
+  </div>
+</div>
 
 <& AddWatchers, Ticket => $Ticket, UserString => $UserString,
         UserOp => $UserOp, UserField => $UserField,
         GroupString => $GroupString, GroupOp => $GroupOp,
         GroupField => $GroupField, PrivilegedOnly => $PrivilegedOnly &> 
   </div>
-  <div class="boxcontainer col-md-6">
+  <div class="boxcontainer current-watchers col-xl-6">
 <h3><&|/l&>People</&></h3>
-<div class="fields">
 
-<div class="field">
-  <span class="label"><&|/l&>Owner</&>:</span>
-  <span class="value"><& /Elements/SelectOwner, Name => 'Owner', QueueObj => $Ticket->QueueObj, TicketObj => $Ticket, Default => $Ticket->OwnerObj->Id, DefaultValue => 0&></span>
+<div class="form-row">
+  <span class="col-md-3 label"><&|/l&>Owner</&>:</span>
+  <span class="col-md-6 value"><& /Elements/SelectOwner, Name => 'Owner', QueueObj => $Ticket->QueueObj, TicketObj => $Ticket, Default => $Ticket->OwnerObj->Id, DefaultValue => 0&></span>
 </div>
 
 % my @role_fields;
@@ -76,39 +83,44 @@
 % $single_roles->LimitToSingleValue;
 % $m->callback( CustomRoles => $single_roles, SingleRoles => 1, Ticket => $Ticket, %ARGS, CallbackName => 'ModifyCustomRoles' );
 % while (my $role = $single_roles->Next) {
-<div class="field">
-  <span class="label"><% $role->Name %>:</span>
-  <span class="value"><& /Elements/SingleUserRoleInput, role => $role, Ticket => $Ticket &></span>
+<div class="form-row">
+  <div class="col-md-3 label"><% $role->Name %>:</div>
+  <div class="col-md-6 value"><& /Elements/SingleUserRoleInput, role => $role, Ticket => $Ticket &></div>
 </div>
 
 % }
 
-</div>
-
 <h3><&|/l&>Current watchers</&></h3>
 <i><&|/l&>(Check box to delete)</&></i><br />
 
-<div class="wide fields">
-
-<div class="field">
-  <span class="label">
-    <input type="checkbox" class="checkbox" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-Requestor-/)">
-    <&|/l&>Requestors</&>:</span>
-  <span class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Requestors &></span>
+<div class="form-row">
+  <div class="col-md-3 label">
+    <div class="custom-control custom-checkbox">
+      <input type="checkbox" id="delete-requestors-checkbox" class="checkbox custom-control-input" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-Requestor-/)">
+      <label class="custom-control-label" for="delete-requestors-checkbox"><&|/l&>Requestors</&>:</label>
+    </div>
+  </div>
+  <div class="col-md-6 value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Requestors &></div>
 </div>
 
-<div class="field">
-  <span class="label">
-    <input type="checkbox" class="checkbox" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-Cc-/)">
-    <&|/l&>Cc</&>:</span>
-  <span class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Cc &></span>
+<div class="form-row">
+  <div class="col-md-3 label">
+    <div class="custom-control custom-checkbox">
+      <input type="checkbox" id="delete-cc-checkbox" class="checkbox custom-control-input" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-Cc-/)">
+      <label class="custom-control-label" for="delete-cc-checkbox"><&|/l&>Cc</&>:</label>
+    </div>
+  </div>
+  <div class="col-md-6 value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Cc &></div>
 </div>
 
-<div class="field">
-  <span class="label">
-    <input type="checkbox" class="checkbox" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-AdminCc-/)">
-    <&|/l&>Admin Cc</&>:</span>
-  <span class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->AdminCc &></span>
+<div class="form-row">
+  <div class="col-md-3 label">
+    <div class="custom-control custom-checkbox">
+      <input type="checkbox" id="delete-admincc-checkbox" class="checkbox custom-control-input" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-AdminCc-/)">
+      <label class="custom-control-label" for="delete-admincc-checkbox"><&|/l&>Admin Cc</&>:</label>
+    </div>
+  </div>
+  <div class="col-md-6 value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->AdminCc &></div>
 </div>
 
 % my $multi_roles = $Ticket->QueueObj->CustomRoles;
@@ -116,18 +128,19 @@
 % $m->callback( CustomRoles => $multi_roles, SingleRoles => 0, Ticket => $Ticket, %ARGS, CallbackName => 'ModifyCustomRoles' );
 % while (my $role = $multi_roles->Next) {
 % my $group = $Ticket->RoleGroup($role->GroupType);
-<div class="field">
-  <span class="label">
-    <input type="checkbox" class="checkbox" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-RT::CustomRole-<% $role->Id %>-/)">
-    <% $role->Name %>:</span>
-  <span class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $group &></span>
+<div class="form-row">
+  <div class="col-md-3 label">
+    <div class="custom-control custom-checkbox">
+      <input type="checkbox" id="delete-<% $role->id %>-checkbox" class="checkbox custom-control-input" onclick="setCheckbox(this, /^Ticket-DeleteWatcher-Type-RT::CustomRole-<% $role->Id %>-/)">
+      <label class="custom-control-label" for="delete-<% $role->id %>-checkbox"><% $role->Name %>:</label>
+    </div>
+  </div>
+  <div class="col-md-6 value"><& EditWatchers, TicketObj => $Ticket, Watchers => $group &></div>
 </div>
 % }
 
 <& /Elements/EditCustomFields, Object => $Ticket, Grouping => 'People', InTable => 1 &>
 
-</div>
-
 </div>
 </div>
 
diff --git a/share/html/Ticket/Elements/EditWatchers b/share/html/Ticket/Elements/EditWatchers
index cfc454de7..3c01e9e37 100644
--- a/share/html/Ticket/Elements/EditWatchers
+++ b/share/html/Ticket/Elements/EditWatchers
@@ -45,15 +45,18 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<ul>
+<ul class="list-group list-group-compact">
 %# Print out a placeholder if there are none.
 % if ( !$Watchers->id || $Members->Count == 0 ) {
-<li><i><&|/l&>none</&></i></li>
+<li class="list-group-item"><i><&|/l&>none</&></i></li>
 % } else {
 % while ( my $watcher = $Members->Next ) {
 % my $member = $watcher->MemberObj->Object;
-<li>
-<input type="checkbox" class="checkbox" name="Ticket-DeleteWatcher-Type-<% $Watchers->Name %>-Principal-<% $watcher->MemberId %>" value="1" unchecked />
+<li class="list-group-item">
+  <div class="custom-control custom-checkbox">
+%   my $name = 'Ticket-DeleteWatcher-Type-' . $Watchers->Name . '-Principal-' . $watcher->MemberId;
+    <input type="checkbox" class="checkbox custom-control-input" id="<% $name %>" name="<% $name %>" value="1" unchecked />
+    <label class="custom-control-label" for="<% $name %>">
 % if ( $member->isa( 'RT::User' ) ) { 
 <& /Elements/ShowUser, User => $member &> <& /Elements/ShowUserEmailFrequency, User => $member, Ticket => $TicketObj &>
 % } else {
@@ -65,7 +68,8 @@
 % } else {
 <% $member->Name %>
 % } }
-
+    </label>
+  </div>
 </li>
 % }
 % }
diff --git a/share/html/Ticket/ModifyAll.html b/share/html/Ticket/ModifyAll.html
index 6b439f82f..847ebc0e4 100644
--- a/share/html/Ticket/ModifyAll.html
+++ b/share/html/Ticket/ModifyAll.html
@@ -95,10 +95,10 @@
 
 <&| /Widgets/TitleBox, title => loc('Update ticket'), class => 'messagedetails' &>
 <div class="fields">
-  <div class="field">
+  <div class="field input-row">
     <span class="label"><&|/l&>Update Type</&>:</span>
     <span class="value entry">
-      <select name="UpdateType" id="UpdateType">
+      <select name="UpdateType" id="UpdateType" class="form-control selectpicker">
 % if ($CanComment) {
         <option value="private" ><&|/l&>Comments (Not sent to requestors)</&></option>
 % }
@@ -109,18 +109,18 @@
 % $m->callback( %ARGS, CallbackName => 'AfterUpdateType' );
     </span>
   </div>
-  <div class="field">
+  <div class="field input-row">
     <span class="label"><&|/l&>Subject</&>:</span>
-    <span class="entry"><input type="text" name="UpdateSubject" value="<%$Ticket->Subject%>" />
+    <span class="value entry"><input type="text" name="UpdateSubject" value="<%$Ticket->Subject%>" class="form-control" />
 % $m->callback( %ARGS, CallbackName => 'AfterSubject' );
     </span>
   </div>
 
-  <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $Ticket, InTable => 1 &>
+  <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, TicketObj => $Ticket &>
 
 <& /Ticket/Elements/AddAttachments, %ARGS, TicketObj => $Ticket &>
 
-  <div class="field">
+  <div class="field input-row">
     <span class="labeltop"><&|/l&>Message</&>:</span>
     <span class="value entry messagebox-container action-<% $ARGS{UpdateType} || ($CanComment ? 'private' : 'response') %>">
 % $m->callback( %ARGS, CallbackName => 'BeforeMessageBox' );
diff --git a/share/html/Ticket/ModifyPeople.html b/share/html/Ticket/ModifyPeople.html
index b7208ce1f..77f7226f2 100644
--- a/share/html/Ticket/ModifyPeople.html
+++ b/share/html/Ticket/ModifyPeople.html
@@ -66,15 +66,20 @@
 <%PERL>
 my $all_recipients_checked = (grep { !$_ } values %recips) ? 0 : 1;
 </%PERL>
-<input type="checkbox" class="checkbox" id="TxnSendMailToAll" onclick="setCheckbox(this, 'checked_recipient')" <% $all_recipients_checked ? 'checked' : '' %>>
-<label for="TxnSendMailToAll"><b><% loc('All recipients') %></b></label><br />
 
-<ul>
+<div class="custom-control custom-checkbox">
+  <input type="checkbox" class="checkbox custom-control-input" id="TxnSendMailToAll" onclick="setCheckbox(this, 'checked_recipient')" <% $all_recipients_checked ? 'checked' : '' %>>
+  <label class="custom-control-label" for="TxnSendMailToAll"><b><% loc('All recipients') %></b></label><br />
+</div>
+
+<ul class="list-group list-group-boardless">
 % for my $addr (sort keys %recips) {
-  <li>
-  <input type="hidden" name="autorecipient" value="<% $addr %>">
-  <input type="checkbox" name="checked_recipient" id="checked_recipient_<%$addr%>" value="<%$addr%>" <% $recips{$addr} ? "checked" : "" %>>
-  <label for="checked_recipient_<%$addr%>"><& /Elements/ShowUser, Address => Email::Address->parse($addr) &></label>
+  <li class="list-group-item">
+    <input type="hidden" name="autorecipient" value="<% $addr %>">
+      <div class="custom-control custom-checkbox">
+        <input type="checkbox" class="custom-control-input" name="checked_recipient" id="checked_recipient_<%$addr%>" value="<%$addr%>" <% $recips{$addr} ? "checked" : "" %>>
+        <label class="custom-control-label" for="checked_recipient_<%$addr%>"><& /Elements/ShowUser, Address => Email::Address->parse($addr) &></label>
+      </div>
   </li>
 % }
 </ul>
diff --git a/share/static/css/elevator-light/forms.css b/share/static/css/elevator-light/forms.css
index 490435e32..2e4cfb519 100644
--- a/share/static/css/elevator-light/forms.css
+++ b/share/static/css/elevator-light/forms.css
@@ -126,13 +126,36 @@ div.field label.select-queue {
     margin-bottom: 0;
 }
 
-#topactions .bootstrap-select.form-control {
-    height: auto;
+.col-auto .datepicker {
+    width: 17em;
 }
 
-/* Fix Queue name position in Queue select for Firefox */
- at -moz-document url-prefix() {
-    #topactions .bootstrap-select .dropdown-toggle .filter-option {
-        margin-top: 5px;
-    }
+span.current-value.form-control {
+    border: none;
+    padding-left: 0;
+}
+
+.current-watchers div.label {
+    padding-top: 0.25em;
+}
+
+.list-group-item label {
+    margin-bottom: 0;
+}
+
+.list-group-compact .list-group-item,
+.list-group-boardless .list-group-item {
+    border: none;
+}
+
+.list-group-compact .list-group-item {
+    padding: 0.25em;
+}
+
+.messagedetails .fields {
+    max-width: 1200px;
+}
+
+.bootstrap-select button:focus {
+    background: #f8f9fa;
 }

-----------------------------------------------------------------------


More information about the rt-commit mailing list