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

Display device names in front of device front/rear images

Fixes #6879
Brian Candler 4 лет назад
Родитель
Сommit
eb9f2b36ab

+ 6 - 0
netbox/dcim/svg.py

@@ -112,6 +112,9 @@ class RackElevationSVG:
             )
             image.fit(scale='slice')
             link.add(image)
+            link.add(drawing.text(str(name), insert=text, stroke='black',
+                     stroke_width='0.2em', stroke_linejoin='round', class_='device-image-label'))
+            link.add(drawing.text(str(name), insert=text, fill='white', class_='device-image-label'))
 
     def _draw_device_rear(self, drawing, device, start, end, text):
         rect = drawing.rect(start, end, class_="slot blocked")
@@ -129,6 +132,9 @@ class RackElevationSVG:
             )
             image.fit(scale='slice')
             drawing.add(image)
+            drawing.add(drawing.text(str(device), insert=text, stroke='black',
+                        stroke_width='0.2em', stroke_linejoin='round', class_='device-image-label'))
+            drawing.add(drawing.text(str(device), insert=text, fill='white', class_='device-image-label'))
 
     @staticmethod
     def _draw_empty(drawing, rack, start, end, text, id_, face_id, class_, reservation):

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


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


+ 55 - 57
netbox/project-static/src/racks.ts

@@ -1,92 +1,90 @@
-import { rackImagesState } from './stores';
+import { rackImagesState, RackViewSelection } from './stores';
 import { getElements } from './util';
 
 import type { StateManager } from './state';
 
-type RackToggleState = { hidden: boolean };
+export type RackViewState = { view: RackViewSelection };
 
 /**
- * Toggle the Rack Image button to reflect the current state. If the current state is hidden and
- * the images are therefore hidden, the button should say "Show Images". Likewise, if the current
- * state is *not* hidden, and therefore the images are shown, the button should say "Hide Images".
- *
- * @param hidden Current State - `true` if images are hidden, `false` otherwise.
- * @param button Button element.
+ * Show or hide images and labels to build the desired rack view.
  */
-function toggleRackImagesButton(hidden: boolean, button: HTMLButtonElement): void {
-  const text = hidden ? 'Show Images' : 'Hide Images';
-  const selected = hidden ? '' : 'selected';
-  button.setAttribute('selected', selected);
-  button.innerHTML = `<i class="mdi mdi-file-image-outline"></i>&nbsp;${text}`;
+function setRackView(
+  view: RackViewSelection,
+  elevation: HTMLObjectElement,
+): void {
+  switch(view) {
+    case 'images-and-labels': {
+      showRackElements('image.device-image', elevation);
+      showRackElements('text.device-image-label', elevation);
+      break;
+    }
+    case 'images-only': {
+      showRackElements('image.device-image', elevation);
+      hideRackElements('text.device-image-label', elevation);
+      break;
+    }
+    case 'labels-only': {
+      hideRackElements('image.device-image', elevation);
+      hideRackElements('text.device-image-label', elevation);
+      break;
+    }
+  }
 }
 
-/**
- * Show all rack images.
- */
-function showRackImages(): void {
-  for (const elevation of getElements<HTMLObjectElement>('.rack_elevation')) {
-    const images = elevation.contentDocument?.querySelectorAll('image.device-image') ?? [];
-    for (const image of images) {
-      image.classList.remove('hidden');
-    }
+function showRackElements(
+  selector: string,
+  elevation: HTMLObjectElement,
+): void {
+  const elements = elevation.contentDocument?.querySelectorAll(selector) ?? [];
+  for (const element of elements) {
+    element.classList.remove('hidden');
   }
 }
 
-/**
- * Hide all rack images.
- */
-function hideRackImages(): void {
-  for (const elevation of getElements<HTMLObjectElement>('.rack_elevation')) {
-    const images = elevation.contentDocument?.querySelectorAll('image.device-image') ?? [];
-    for (const image of images) {
-      image.classList.add('hidden');
-    }
+function hideRackElements(
+  selector: string,
+  elevation: HTMLObjectElement,
+): void {
+  const elements = elevation.contentDocument?.querySelectorAll(selector) ?? [];
+  for (const element of elements) {
+    element.classList.add('hidden');
   }
 }
 
 /**
- * Toggle the visibility of device images and update the toggle button style.
+ * Change the visibility of all racks in response to selection.
  */
-function handleRackImageToggle(
-  target: HTMLButtonElement,
-  state: StateManager<RackToggleState>,
+function handleRackViewSelect(
+  newView: RackViewSelection,
+  state: StateManager<RackViewState>,
 ): void {
-  const initiallyHidden = state.get('hidden');
-  state.set('hidden', !initiallyHidden);
-  const hidden = state.get('hidden');
-
-  if (hidden) {
-    hideRackImages();
-  } else {
-    showRackImages();
+  state.set('view', newView);
+  for (const elevation of getElements<HTMLObjectElement>('.rack_elevation')) {
+    setRackView(newView, elevation);
   }
-  toggleRackImagesButton(hidden, target);
 }
 
 /**
- * Add onClick callback for toggling rack elevation images. Synchronize the image toggle button
- * text and display state of images with the local state.
+ * Add change callback for selecting rack elevation images, and set
+ * initial state of select and the images themselves
  */
 export function initRackElevation(): void {
-  const initiallyHidden = rackImagesState.get('hidden');
-  for (const button of getElements<HTMLButtonElement>('button.toggle-images')) {
-    toggleRackImagesButton(initiallyHidden, button);
+  const initialView = rackImagesState.get('view');
 
-    button.addEventListener(
-      'click',
+  for (const control of getElements<HTMLSelectElement>('select.rack-view')) {
+    control.selectedIndex = [...control.options].findIndex(o => o.value == initialView);
+    control.addEventListener(
+      'change',
       event => {
-        handleRackImageToggle(event.currentTarget as HTMLButtonElement, rackImagesState);
+        handleRackViewSelect((event.currentTarget as any).value as RackViewSelection, rackImagesState);
       },
       false,
     );
   }
+
   for (const element of getElements<HTMLObjectElement>('.rack_elevation')) {
     element.addEventListener('load', () => {
-      if (initiallyHidden) {
-        hideRackImages();
-      } else if (!initiallyHidden) {
-        showRackImages();
-      }
+      setRackView(initialView, element);
     });
   }
 }

+ 4 - 2
netbox/project-static/src/stores/rackImages.ts

@@ -1,6 +1,8 @@
 import { createState } from '../state';
 
-export const rackImagesState = createState<{ hidden: boolean }>(
-  { hidden: false },
+export type RackViewSelection = 'images-and-labels' | 'images-only' | 'labels-only';
+
+export const rackImagesState = createState<{ view: RackViewSelection }>(
+  { view: 'images-and-labels' },
   { persist: true },
 );

+ 5 - 4
netbox/templates/dcim/rack.html

@@ -18,10 +18,11 @@
 {% endblock %}
 
 {% block extra_controls %}
-  <button class="btn btn-sm btn-outline-primary toggle-images" selected="selected">
-    <i class="mdi mdi-file-image-outline"></i> 
-    Hide Images
-  </button>
+  <select class="btn btn-sm btn-outline-dark rack-view">
+    <option value="images-and-labels" selected="selected">Images and Labels</option>
+    <option value="images-only">Images only</option>
+    <option value="labels-only">Labels only</option>
+  </select>
   <a {% if prev_rack %}href="{% url 'dcim:rack' pk=prev_rack.pk %}{% endif %}" class="btn btn-sm btn-primary{% if not prev_rack %} disabled{% endif %}">
     <i class="mdi mdi-chevron-left" aria-hidden="true"></i> Previous
   </a>

+ 7 - 3
netbox/templates/dcim/rack_elevation_list.html

@@ -7,9 +7,13 @@
 {% block controls %}
     <div class="controls">
         <div class="control-group">
-            <button class="btn btn-sm btn-outline-dark toggle-images" selected="selected">
-                <span class="mdi mdi mdi-checkbox-marked-circle-outline" aria-hidden="true"></span> Show Images
-            </button>
+            <div class="btn-group btn-group-sm" role="group">
+                <select class="btn btn-sm btn-outline-secondary active rack-view">
+                  <option value="images-and-labels" selected="selected">Images and Labels</option>
+                  <option value="images-only">Images only</option>
+                  <option value="labels-only">Labels only</option>
+                </select>
+            </div>
             <div class="btn-group btn-group-sm" role="group">
                 <a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face='front' %}" class="btn btn-outline-secondary{% if rack_face == 'front' %} active{% endif %}">Front</a>
                 <a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face='rear' %}" class="btn btn-outline-secondary{% if rack_face == 'rear' %} active{% endif %}">Rear</a>

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