diff --git a/netbox/project-static/dist/config.js b/netbox/project-static/dist/config.js index 385a88ee2..87d23b05d 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 e7e38f3c5..f40c00961 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 90d4375bb..eb8e1cfb0 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 8b7e5480a..0fc0f76e2 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 4a20d8ff7..e6d717b2a 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 5a531da0a..538a584b5 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.js b/netbox/project-static/dist/netbox.js index 38ad9b6e5..2ef85bdd2 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 88ee490af..baad2a597 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 66c05a18b..dbac3942c 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 e65f9c203..15c5ea99a 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 ffb23d10d..ba27dc9a4 100644 --- a/netbox/project-static/src/bs.ts +++ b/netbox/project-static/src/bs.ts @@ -18,7 +18,7 @@ function initMasonry(): void { function initTooltips() { for (const tooltip of getElements('[data-bs-toggle="tooltip"]')) { - new Tooltip(tooltip, { container: 'body', boundary: 'window' }); + new Tooltip(tooltip, { container: 'body' }); } } diff --git a/netbox/project-static/src/select/api.ts b/netbox/project-static/src/select/api.ts index 15e7d210d..f16456f5a 100644 --- a/netbox/project-static/src/select/api.ts +++ b/netbox/project-static/src/select/api.ts @@ -1,8 +1,15 @@ import SlimSelect from 'slim-select'; import queryString from 'query-string'; -import { getApiData, isApiError, getElements, isTruthy, hasError } from '../util'; +import { + getApiData, + isApiError, + getElements, + isTruthy, + hasError, + findFirstAdjacent, +} from '../util'; import { createToast } from '../bs'; -import { setOptionStyles, toggle, getDependencyIds } from './util'; +import { setOptionStyles, toggle, getDependencyIds, initResetButton } from './util'; import type { Option } from 'slim-select/dist/data'; @@ -318,18 +325,45 @@ export function initApiSelect() { select.addEventListener(`netbox.select.onload.${dep}`, handleEvent); } - // Load data. - getOptions(url, select, disabledOptions) - .then(options => instance.setData(options)) - .catch(console.error) - .finally(() => { - // Set option styles, if the field calls for it (color selectors). + /** + * Load this element's options from the NetBox API. + */ + async function loadData(): Promise { + try { + const options = await getOptions(url, select, disabledOptions); + instance.setData(options); + } catch (err) { + console.error(err); + } finally { setOptionStyles(instance); - // Enable the element after data has loaded. toggle('enable', instance); - // Inform any event listeners that data has updated. select.dispatchEvent(event); - }); + } + } + + /** + * Delete this element's options. + */ + function clearData(): void { + return instance.setData([]); + } + + // Determine if this element is part of collapsible element. + const collapse = findFirstAdjacent(select, '.collapse', '.content-container'); + console.log('collapse', collapse); + if (collapse !== null) { + // If this element is part of a collapsible element, only load the data when the + // collapsible element is shown. + // See: https://getbootstrap.com/docs/5.0/components/collapse/#events + collapse.addEventListener('show.bs.collapse', loadData); + collapse.addEventListener('hide.bs.collapse', clearData); + } else { + // Otherwise, load the data on render. + Promise.all([loadData()]); + } + + // Bind event listener to + initResetButton(select, instance); // Set the underlying select element to the same size as the SlimSelect instance. // This is primarily for built-in HTML form validation, which doesn't really work, diff --git a/netbox/project-static/src/select/util.ts b/netbox/project-static/src/select/util.ts index e12d79ef1..b8ee6cd4c 100644 --- a/netbox/project-static/src/select/util.ts +++ b/netbox/project-static/src/select/util.ts @@ -1,4 +1,5 @@ import { readableColor } from 'color2k'; +import { findFirstAdjacent, getElements } from '../util'; import type SlimSelect from 'slim-select'; @@ -184,3 +185,23 @@ export function getDependencyIds(element: Nullable): s const ids = new Set(getAllDependencyIds(element)); return Array.from(ids).map(i => i.replaceAll('_id', '')); } + +/** + * Initialize any adjacent reset buttons so that when clicked, the instance's selected value is cleared. + * + * @param select Select Element + * @param instance SlimSelect Instance + */ +export function initResetButton(select: HTMLSelectElement, instance: SlimSelect) { + const resetButton = findFirstAdjacent(select, 'button[data-reset-select'); + if (resetButton !== null) { + resetButton.addEventListener('click', () => { + select.value = ''; + if (select.multiple) { + instance.setSelected([]); + } else { + instance.setSelected(''); + } + }); + } +} diff --git a/netbox/project-static/src/util.ts b/netbox/project-static/src/util.ts index d43c3af25..f3140e168 100644 --- a/netbox/project-static/src/util.ts +++ b/netbox/project-static/src/util.ts @@ -251,13 +251,23 @@ export function* getRowValues(table: HTMLTableRowElement): Generator { * * @param base Base Element * @param query CSS Query + * @param boundary Optionally specify a CSS Query which, when matched, recursion will cease. */ export function findFirstAdjacent( base: B, query: string, + boundary?: string, ): Nullable { + function atBoundary(element: E): boolean { + if (typeof boundary === 'string' && element !== null) { + if (element.matches(boundary)) { + return true; + } + } + return false; + } function match

(parent: P): Nullable { - if (parent !== null && parent.parentElement !== null) { + if (parent !== null && parent.parentElement !== null && !atBoundary(parent)) { for (const child of parent.parentElement.querySelectorAll(query)) { if (child !== null) { return child; diff --git a/netbox/templates/inc/advanced_search.html b/netbox/templates/inc/advanced_search.html index 4236aec54..43ea21e32 100644 --- a/netbox/templates/inc/advanced_search.html +++ b/netbox/templates/inc/advanced_search.html @@ -50,9 +50,12 @@ {% endif %}