#6372: Don't autopopulate collapsible API select data, improve advanced search
This commit is contained in:
parent
429d995270
commit
e8c91ea3a1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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' });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<E extends HTMLElement>(element: Nullable<E>): s
|
|||
const ids = new Set<string>(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<HTMLButtonElement>(select, 'button[data-reset-select');
|
||||
if (resetButton !== null) {
|
||||
resetButton.addEventListener('click', () => {
|
||||
select.value = '';
|
||||
if (select.multiple) {
|
||||
instance.setSelected([]);
|
||||
} else {
|
||||
instance.setSelected('');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,13 +251,23 @@ export function* getRowValues(table: HTMLTableRowElement): Generator<string> {
|
|||
*
|
||||
* @param base Base Element
|
||||
* @param query CSS Query
|
||||
* @param boundary Optionally specify a CSS Query which, when matched, recursion will cease.
|
||||
*/
|
||||
export function findFirstAdjacent<R extends HTMLElement, B extends Element = Element>(
|
||||
base: B,
|
||||
query: string,
|
||||
boundary?: string,
|
||||
): Nullable<R> {
|
||||
function atBoundary<E extends Element | null>(element: E): boolean {
|
||||
if (typeof boundary === 'string' && element !== null) {
|
||||
if (element.matches(boundary)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function match<P extends Element | null>(parent: P): Nullable<R> {
|
||||
if (parent !== null && parent.parentElement !== null) {
|
||||
if (parent !== null && parent.parentElement !== null && !atBoundary(parent)) {
|
||||
for (const child of parent.parentElement.querySelectorAll<R>(query)) {
|
||||
if (child !== null) {
|
||||
return child;
|
||||
|
|
|
|||
|
|
@ -50,9 +50,12 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-end noprint border-0">
|
||||
<a href="." class="btn btn-sm btn-outline-dark m-1">
|
||||
<i class="mdi mdi-close"></i> Clear
|
||||
</a>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark m-1" data-bs-toggle="collapse" data-bs-target="#advanced-search-content">
|
||||
<i class="mdi mdi-close"></i> Close
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger m-1" data-reset-select>
|
||||
<i class="mdi mdi-backspace"></i> Reset
|
||||
</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary m-1">
|
||||
<i class="mdi mdi-magnify"></i> Search
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Reference in New Issue