diff --git a/docs/release-notes/version-3.0.md b/docs/release-notes/version-3.0.md index 45fc473ba..db3bc822c 100644 --- a/docs/release-notes/version-3.0.md +++ b/docs/release-notes/version-3.0.md @@ -8,6 +8,7 @@ * [#7071](https://github.com/netbox-community/netbox/issues/7071) - Fix exception when removing a primary IP from a device/VM * [#7072](https://github.com/netbox-community/netbox/issues/7072) - Fix table configuration under prefix child object views * [#7075](https://github.com/netbox-community/netbox/issues/7075) - Fix UI bug when a custom field has a space in the name +* [#7080](https://github.com/netbox-community/netbox/issues/7080) - Fix missing image previews * [#7081](https://github.com/netbox-community/netbox/issues/7081) - Fix UI bug that did not properly request and handle paginated data * [#7082](https://github.com/netbox-community/netbox/issues/7082) - Avoid exception when referencing invalid content type in table * [#7083](https://github.com/netbox-community/netbox/issues/7083) - Correct labeling for VM memory attribute diff --git a/netbox/project-static/dist/config.js b/netbox/project-static/dist/config.js index 079d7b90a..18f4811a2 100644 Binary files a/netbox/project-static/dist/config.js and b/netbox/project-static/dist/config.js differ diff --git a/netbox/project-static/dist/config.js.map b/netbox/project-static/dist/config.js.map index 3d034b9df..176f8c85e 100644 Binary files a/netbox/project-static/dist/config.js.map and b/netbox/project-static/dist/config.js.map differ diff --git a/netbox/project-static/dist/jobs.js b/netbox/project-static/dist/jobs.js index 74ae33272..3faf4b7ec 100644 Binary files a/netbox/project-static/dist/jobs.js and b/netbox/project-static/dist/jobs.js differ diff --git a/netbox/project-static/dist/jobs.js.map b/netbox/project-static/dist/jobs.js.map index 89a6b6abe..fbd950267 100644 Binary files a/netbox/project-static/dist/jobs.js.map and b/netbox/project-static/dist/jobs.js.map differ diff --git a/netbox/project-static/dist/lldp.js b/netbox/project-static/dist/lldp.js index 0ddfddd27..86adb3db6 100644 Binary files a/netbox/project-static/dist/lldp.js and b/netbox/project-static/dist/lldp.js differ diff --git a/netbox/project-static/dist/lldp.js.map b/netbox/project-static/dist/lldp.js.map index 179f3b7e9..be357a5bc 100644 Binary files a/netbox/project-static/dist/lldp.js.map and b/netbox/project-static/dist/lldp.js.map differ diff --git a/netbox/project-static/dist/netbox-dark.css b/netbox/project-static/dist/netbox-dark.css index e319596b5..4caf6a4e6 100644 Binary files a/netbox/project-static/dist/netbox-dark.css and b/netbox/project-static/dist/netbox-dark.css differ diff --git a/netbox/project-static/dist/netbox-light.css b/netbox/project-static/dist/netbox-light.css index 06606cf83..f5db11538 100644 Binary files a/netbox/project-static/dist/netbox-light.css and b/netbox/project-static/dist/netbox-light.css differ diff --git a/netbox/project-static/dist/netbox-print.css b/netbox/project-static/dist/netbox-print.css index c13fad0fc..170e92bc4 100644 Binary files a/netbox/project-static/dist/netbox-print.css and b/netbox/project-static/dist/netbox-print.css differ diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index f63f39d86..a5995f96a 100644 Binary files a/netbox/project-static/dist/netbox.js and b/netbox/project-static/dist/netbox.js differ diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 394847d5a..db0366f6b 100644 Binary files a/netbox/project-static/dist/netbox.js.map and b/netbox/project-static/dist/netbox.js.map differ diff --git a/netbox/project-static/dist/status.js b/netbox/project-static/dist/status.js index 13c6a7b42..b60da0a36 100644 Binary files a/netbox/project-static/dist/status.js and b/netbox/project-static/dist/status.js differ diff --git a/netbox/project-static/dist/status.js.map b/netbox/project-static/dist/status.js.map index 75ee69a42..a249f7380 100644 Binary files a/netbox/project-static/dist/status.js.map and b/netbox/project-static/dist/status.js.map differ diff --git a/netbox/project-static/src/bs.ts b/netbox/project-static/src/bs.ts index f31bbb9ef..e819b7cb1 100644 --- a/netbox/project-static/src/bs.ts +++ b/netbox/project-static/src/bs.ts @@ -1,6 +1,6 @@ -import { Collapse, Modal, Tab, Toast, Tooltip } from 'bootstrap'; +import { Collapse, Modal, Popover, Tab, Toast, Tooltip } from 'bootstrap'; import Masonry from 'masonry-layout'; -import { getElements } from './util'; +import { createElement, getElements } from './util'; type ToastLevel = 'danger' | 'warning' | 'success' | 'info'; @@ -8,6 +8,7 @@ type ToastLevel = 'danger' | 'warning' | 'success' | 'info'; // plugins). window.Collapse = Collapse; window.Modal = Modal; +window.Popover = Popover; window.Toast = Toast; window.Tooltip = Tooltip; @@ -156,13 +157,48 @@ function initSidebarAccordions(): void { } } +/** + * Initialize image preview popover, which shows a preview of an image from an image link with the + * `.image-preview` class. + */ +function initImagePreview(): void { + for (const element of getElements('a.image-preview')) { + // Generate a max-width that's a quarter of the screen's width (note - the actual element + // width will be slightly larger due to the popover body's padding). + const maxWidth = `${Math.round(window.innerWidth / 4)}px`; + + // Create an image element that uses the linked image as its `src`. + const image = createElement('img', { src: element.href }); + image.style.maxWidth = maxWidth; + + // Create a container for the image. + const content = createElement('div', null, null, [image]); + + // Initialize the Bootstrap Popper instance. + new Popover(element, { + // Attach this custom class to the popover so that it styling can be controlled via CSS. + customClass: 'image-preview-popover', + trigger: 'hover', + html: true, + content, + }); + } +} + /** * Enable any defined Bootstrap Tooltips. * * @see https://getbootstrap.com/docs/5.0/components/tooltips */ export function initBootstrap(): void { - for (const func of [initTooltips, initModals, initMasonry, initTabs, initSidebarAccordions]) { + for (const func of [ + initTooltips, + initModals, + initMasonry, + initTabs, + initImagePreview, + initSidebarAccordions, + ]) { func(); } } diff --git a/netbox/project-static/src/global.d.ts b/netbox/project-static/src/global.d.ts index f3dd7edd9..af5819c8e 100644 --- a/netbox/project-static/src/global.d.ts +++ b/netbox/project-static/src/global.d.ts @@ -17,6 +17,11 @@ interface Window { */ Modal: typeof import('bootstrap').Modal; + /** + * Bootstrap Popover Instance. + */ + Popover: typeof import('bootstrap').Popover; + /** * Bootstrap Toast Instance. */ diff --git a/netbox/project-static/src/util.ts b/netbox/project-static/src/util.ts index 99c9d039d..c3dd05b0e 100644 --- a/netbox/project-static/src/util.ts +++ b/netbox/project-static/src/util.ts @@ -422,7 +422,12 @@ export function createElement< P extends InferredProps, // Child element type. C extends HTMLElement = HTMLElement, ->(tag: T, properties: P | null, classes: string[], children: C[] = []): HTMLElementTagNameMap[T] { +>( + tag: T, + properties: P | null, + classes: Nullable = null, + children: C[] = [], +): HTMLElementTagNameMap[T] { // Create the base element. const element = document.createElement(tag); @@ -438,7 +443,9 @@ export function createElement< } // Add each CSS class to the element's class list. - element.classList.add(...classes); + if (classes !== null && classes.length > 0) { + element.classList.add(...classes); + } for (const child of children) { // Add each child element to the base element. diff --git a/netbox/project-static/styles/netbox.scss b/netbox/project-static/styles/netbox.scss index cc70dd2a0..b05cc07d4 100644 --- a/netbox/project-static/styles/netbox.scss +++ b/netbox/project-static/styles/netbox.scss @@ -956,6 +956,11 @@ div.card-overlay { } } +// Remove the max-width from image preview popovers as this is controlled on the image element. +.popover.image-preview-popover { + max-width: unset; +} + #django-messages { position: fixed; right: $spacer;