Просмотр исходного кода

Merge pull request #9964 from jsenecal/feat9857

Add a "clear" button for quick search
Jeremy Stretch 3 лет назад
Родитель
Сommit
a59169fa96

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-dark.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-light.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-print.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 44 - 0
netbox/project-static/src/search.ts

@@ -27,6 +27,23 @@ function handleSearchDropdownClick(event: Event, button: HTMLButtonElement): voi
   }
   }
 }
 }
 
 
+/**
+ * Show/hide quicksearch clear button.
+ *
+ * @param event "keyup" or "search" event for the quicksearch input
+ */
+function quickSearchEventHandler(event: Event): void {
+  const quicksearch = event.currentTarget as HTMLInputElement;
+  const inputgroup = quicksearch.parentElement as HTMLDivElement;
+  if (isTruthy(inputgroup)) {
+    if (quicksearch.value === "") {
+      inputgroup.classList.add("hide-last-child");
+    } else {
+      inputgroup.classList.remove("hide-last-child");
+    }
+  }
+}
+
 /**
 /**
  * Initialize Search Bar Elements.
  * Initialize Search Bar Elements.
  */
  */
@@ -40,8 +57,35 @@ function initSearchBar(): void {
   }
   }
 }
 }
 
 
+/**
+ * Initialize Quicksearch Event listener/handlers.
+ */
+function initQuickSearch(): void {
+  const quicksearch = document.getElementById("quicksearch") as HTMLInputElement;
+  const clearbtn = document.getElementById("quicksearch_clear") as HTMLButtonElement;
+  if (isTruthy(quicksearch)) {
+    quicksearch.addEventListener("keyup", quickSearchEventHandler, {
+      passive: true
+    })
+    quicksearch.addEventListener("search", quickSearchEventHandler, {
+      passive: true
+    })
+    if (isTruthy(clearbtn)) {
+      clearbtn.addEventListener("click", async () => {
+        const search = new Event('search');
+        quicksearch.value = '';
+        await new Promise(f => setTimeout(f, 100));
+        quicksearch.dispatchEvent(search);
+      }, {
+        passive: true
+      })
+    }
+  }
+}
+
 export function initSearch(): void {
 export function initSearch(): void {
   for (const func of [initSearchBar]) {
   for (const func of [initSearchBar]) {
     func();
     func();
   }
   }
+  initQuickSearch();
 }
 }

+ 21 - 0
netbox/project-static/styles/netbox.scss

@@ -416,6 +416,27 @@ nav.search {
   }
   }
 }
 }
 
 
+// Styles for the quicksearch and its clear button; 
+// Overrides input-group styles and adds transition effects
+.quicksearch {
+  input[type="search"] {
+    border-radius: $border-radius  !important;
+  }
+
+  button {
+    margin-left: -32px !important;
+    z-index: 100 !important;
+    outline: none !important;
+    border-radius: $border-radius  !important;
+    transition: visibility 0s, opacity 0.2s linear;
+  }
+
+  button :hover {
+    opacity: 50%;
+    transition: visibility 0s, opacity 0.1s linear;
+  }
+}
+
 main.layout {
 main.layout {
   display: flex;
   display: flex;
   flex-wrap: nowrap;
   flex-wrap: nowrap;

+ 8 - 0
netbox/project-static/styles/overrides.scss

@@ -34,3 +34,11 @@ a[type='button'] {
 .badge {
 .badge {
   font-size: $font-size-xs;
   font-size: $font-size-xs;
 }
 }
+
+/* clears the 'X' in search inputs from webkit browsers */
+input[type='search']::-webkit-search-decoration,
+input[type='search']::-webkit-search-cancel-button,
+input[type='search']::-webkit-search-results-button,
+input[type='search']::-webkit-search-results-decoration {
+  -webkit-appearance: none !important;
+}

+ 4 - 0
netbox/project-static/styles/theme-dark.scss

@@ -92,6 +92,10 @@ $input-focus-color: $input-color;
 $input-placeholder-color: $gray-700;
 $input-placeholder-color: $gray-700;
 $input-plaintext-color: $body-color;
 $input-plaintext-color: $body-color;
 
 
+input {
+  color-scheme: dark;
+}
+
 $form-check-input-active-filter: brightness(90%);
 $form-check-input-active-filter: brightness(90%);
 $form-check-input-bg: $input-bg;
 $form-check-input-bg: $input-bg;
 $form-check-input-border: 1px solid rgba(255, 255, 255, 0.25);
 $form-check-input-border: 1px solid rgba(255, 255, 255, 0.25);

+ 1 - 2
netbox/project-static/styles/theme-light.scss

@@ -22,7 +22,6 @@ $theme-colors: (
   'danger': $danger,
   'danger': $danger,
   'light': $light,
   'light': $light,
   'dark': $dark,
   'dark': $dark,
-
   // General-purpose palette
   // General-purpose palette
   'blue': $blue-500,
   'blue': $blue-500,
   'indigo': $indigo-500,
   'indigo': $indigo-500,
@@ -36,7 +35,7 @@ $theme-colors: (
   'cyan': $cyan-500,
   'cyan': $cyan-500,
   'gray': $gray-500,
   'gray': $gray-500,
   'black': $black,
   'black': $black,
-  'white': $white,
+  'white': $white
 );
 );
 
 
 $light: $gray-200;
 $light: $gray-200;

+ 6 - 0
netbox/project-static/styles/utilities.scss

@@ -42,3 +42,9 @@ table td {
     visibility: visible !important;
     visibility: visible !important;
   }
   }
 }
 }
+
+// Hides the last child of an element
+.hide-last-child :last-child {
+  visibility: hidden;
+  opacity: 0;
+}

+ 70 - 69
netbox/templates/dcim/device/interfaces.html

@@ -4,84 +4,85 @@
 {% load static %}
 {% load static %}
 
 
 {% block content %}
 {% block content %}
-  <div class="row mb-3 justify-content-between">
-    <div class="col col-12 col-lg-4 my-3 my-lg-0 d-flex noprint table-controls">
-      <div class="input-group input-group-sm">
-        <input
-            type="text"
-            name="q"
-            class="form-control"
-            placeholder="Quick search"
-            hx-get="{{ request.full_path }}"
-            hx-target="#object_list"
-            hx-trigger="keyup changed delay:500ms"
-        />
-      </div>
+<div class="row mb-3 justify-content-between">
+  <div class="col col-12 col-lg-4 my-3 my-lg-0 d-flex noprint table-controls">
+    <div class="input-group input-group-sm quicksearch hide-last-child">
+      <input type="search" results=5 name="q" id="quicksearch" class="form-control" placeholder="Quick search"
+        hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
+      <button class="btn bg-transparent" type="button" id="quicksearch_clear"><i
+          class="mdi mdi-close-circle"></i></button>
     </div>
     </div>
-    <div class="col col-md-3 mb-0 d-flex noprint table-controls">
-      <div class="input-group input-group-sm justify-content-end">
-        {% if request.user.is_authenticated %}
-          <button
-              type="button"
-              class="btn btn-sm btn-outline-dark"
-              data-bs-toggle="modal"
-              data-bs-target="#DeviceInterfaceTable_config"
-              title="Configure Table">
-              <i class="mdi mdi-cog"></i> Configure Table
-          </button>
-        {% endif %}
-        <button class="btn btn-sm btn-outline-dark dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
-          <i class="mdi mdi-eye"></i>
-        </button>
-        <ul class="dropdown-menu">
-          <button type="button" class="dropdown-item toggle-enabled" data-state="show">Hide Enabled</button>
-          <button type="button" class="dropdown-item toggle-disabled" data-state="show">Hide Disabled</button>
-        </ul>
-      </div>
+  </div>
+  <div class="col col-md-3 mb-0 d-flex noprint table-controls">
+    <div class="input-group input-group-sm justify-content-end">
+      {% if request.user.is_authenticated %}
+      <button type="button" class="btn btn-sm btn-outline-dark" data-bs-toggle="modal"
+        data-bs-target="#DeviceInterfaceTable_config" title="Configure Table">
+        <i class="mdi mdi-cog"></i> Configure Table
+      </button>
+      {% endif %}
+      <button class="btn btn-sm btn-outline-dark dropdown-toggle" type="button" data-bs-toggle="dropdown"
+        aria-expanded="false">
+        <i class="mdi mdi-eye"></i>
+      </button>
+      <ul class="dropdown-menu">
+        <button type="button" class="dropdown-item toggle-enabled" data-state="show">Hide Enabled</button>
+        <button type="button" class="dropdown-item toggle-disabled" data-state="show">Hide Disabled</button>
+      </ul>
     </div>
     </div>
   </div>
   </div>
+</div>
 
 
-  <form method="post">
-    {% csrf_token %}
+<form method="post">
+  {% csrf_token %}
 
 
 
 
-    <div class="card">
-      <div class="card-body" id="object_list">
-        {% include 'htmx/table.html' %}
-      </div>
+  <div class="card">
+    <div class="card-body" id="object_list">
+      {% include 'htmx/table.html' %}
     </div>
     </div>
+  </div>
 
 
-    <div class="noprint bulk-buttons">
-        <div class="bulk-button-group">
-        {% if perms.dcim.change_interface %}
-            <button type="submit" name="_rename" formaction="{% url 'dcim:interface_bulk_rename' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
-                <i class="mdi mdi-pencil-outline" aria-hidden="true"></i> Rename
-            </button>
-            <button type="submit" name="_edit" formaction="{% url 'dcim:interface_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}" class="btn btn-warning btn-sm">
-                <i class="mdi mdi-pencil" aria-hidden="true"></i> Edit
-            </button>
-            <button type="submit" name="_disconnect" formaction="{% url 'dcim:interface_bulk_disconnect' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
-                <span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> Disconnect
-            </button>
-        {% endif %}
-        {% if perms.dcim.delete_interface %}
-            <button type="submit" name="_delete" formaction="{% url 'dcim:interface_bulk_delete' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}" class="btn btn-danger btn-sm">
-                <i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete
-            </button>
-        {% endif %}
-        </div>
-        {% if perms.dcim.add_interface %}
-            <div class="bulk-button-group">
-                <a href="{% url 'dcim:interface_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}" class="btn btn-primary btn-sm">
-                    <i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add Interfaces
-                </a>
-            </div>
-        {% endif %}
+  <div class="noprint bulk-buttons">
+    <div class="bulk-button-group">
+      {% if perms.dcim.change_interface %}
+      <button type="submit" name="_rename"
+        formaction="{% url 'dcim:interface_bulk_rename' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
+        class="btn btn-outline-warning btn-sm">
+        <i class="mdi mdi-pencil-outline" aria-hidden="true"></i> Rename
+      </button>
+      <button type="submit" name="_edit"
+        formaction="{% url 'dcim:interface_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
+        class="btn btn-warning btn-sm">
+        <i class="mdi mdi-pencil" aria-hidden="true"></i> Edit
+      </button>
+      <button type="submit" name="_disconnect"
+        formaction="{% url 'dcim:interface_bulk_disconnect' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
+        class="btn btn-outline-danger btn-sm">
+        <span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> Disconnect
+      </button>
+      {% endif %}
+      {% if perms.dcim.delete_interface %}
+      <button type="submit" name="_delete"
+        formaction="{% url 'dcim:interface_bulk_delete' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
+        class="btn btn-danger btn-sm">
+        <i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete
+      </button>
+      {% endif %}
     </div>
     </div>
-  </form>
+    {% if perms.dcim.add_interface %}
+    <div class="bulk-button-group">
+      <a href="{% url 'dcim:interface_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
+        class="btn btn-primary btn-sm">
+        <i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add Interfaces
+      </a>
+    </div>
+    {% endif %}
+  </div>
+</form>
 {% endblock %}
 {% endblock %}
 
 
 {% block modals %}
 {% block modals %}
-  {{ block.super }}
-  {% table_config_form table %}
-{% endblock modals %}
+{{ block.super }}
+{% table_config_form table %}
+{% endblock modals %}

+ 12 - 22
netbox/templates/inc/table_controls_htmx.html

@@ -2,31 +2,21 @@
 
 
 <div class="row mb-3 justify-content-between">
 <div class="row mb-3 justify-content-between">
   <div class="table-controls noprint col col-12 col-md-8 col-lg-4">
   <div class="table-controls noprint col col-12 col-md-8 col-lg-4">
-    <div class="input-group input-group-sm">
-      <input
-        type="text"
-        name="q"
-        class="form-control"
-        placeholder="Quick search"
-        hx-get="{{ request.full_path }}"
-        hx-target="#object_list"
-        hx-trigger="keyup changed delay:500ms"
-      />
+    <div class="input-group input-group-sm quicksearch hide-last-child">
+      <input type="search" results=5 name="q" id="quicksearch" class="form-control" placeholder="Quick search"
+        hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
+      <button class="btn bg-transparent" type="button" id="quicksearch_clear"><i
+          class="mdi mdi-close-circle"></i></button>
     </div>
     </div>
   </div>
   </div>
   <div class="table-controls noprint col col-md-3 mb-0">
   <div class="table-controls noprint col col-md-3 mb-0">
     {% if request.user.is_authenticated and table_modal %}
     {% if request.user.is_authenticated and table_modal %}
-      <div class="table-configure input-group input-group-sm">
-        <button
-          type="button"
-          data-bs-toggle="modal"
-          title="Configure Table"
-          data-bs-target="#{{ table_modal }}"
-          class="btn btn-sm btn-outline-dark"
-        >
-          <i class="mdi mdi-cog"></i> Configure Table
-        </button>
-      </div>
+    <div class="table-configure input-group input-group-sm">
+      <button type="button" data-bs-toggle="modal" title="Configure Table" data-bs-target="#{{ table_modal }}"
+        class="btn btn-sm btn-outline-dark">
+        <i class="mdi mdi-cog"></i> Configure Table
+      </button>
+    </div>
     {% endif %}
     {% endif %}
   </div>
   </div>
-</div>
+</div>

Некоторые файлы не были показаны из-за большого количества измененных файлов