(
- 'select.netbox-color-select:not([data-ssid])',
- )) {
- for (const option of select.options) {
- if (canChangeColor(option)) {
- // Get the background color from the option's value.
- const bg = `#${option.value}`;
- // Determine an accessible foreground color based on the background color.
- const fg = readableColor(bg);
-
- // Set the option's style attributes.
- option.style.backgroundColor = bg;
- option.style.color = fg;
- }
- }
-
- const instance = new SlimSelect({
- select,
- allowDeselect: true,
- // Inherit the calculated color on the deselect icon.
- deselectLabel: ``,
- });
-
- // Style the select container to match any pre-selectd options.
- for (const option of instance.data.data) {
- if ('selected' in option && option.selected) {
- styleContainer(instance, option);
- break;
- }
- }
-
- // Don't inherit the select element's classes.
- for (const className of select.classList) {
- instance.slim.container.classList.remove(className);
- }
-
- // Change the SlimSelect container's style based on the selected option.
- instance.onChange = option => styleContainer(instance, option);
- }
-}
diff --git a/netbox/project-static/src/select/config.ts b/netbox/project-static/src/select/config.ts
new file mode 100644
index 000000000..74c2fb63d
--- /dev/null
+++ b/netbox/project-static/src/select/config.ts
@@ -0,0 +1,9 @@
+export const config = {
+ plugins: {
+ // Provides the "clear" button on the widget
+ clear_button: {
+ html: (data: Dict) =>
+ ``,
+ },
+ },
+};
diff --git a/netbox/project-static/src/select/dynamic.ts b/netbox/project-static/src/select/dynamic.ts
new file mode 100644
index 000000000..9f29efe1d
--- /dev/null
+++ b/netbox/project-static/src/select/dynamic.ts
@@ -0,0 +1,51 @@
+import { TomOption } from 'tom-select/src/types';
+import { escape_html } from 'tom-select/src/utils';
+import { DynamicTomSelect } from './classes/dynamicTomSelect';
+import { config } from './config';
+import { getElements } from '../util';
+
+const VALUE_FIELD = 'id';
+const LABEL_FIELD = 'display';
+const MAX_OPTIONS = 100;
+
+// Render the HTML for a dropdown option
+function renderOption(data: TomOption, escape: typeof escape_html) {
+ // If the option has a `_depth` property, indent its label
+ if (typeof data._depth === 'number' && data._depth > 0) {
+ return `${'─'.repeat(data._depth)} ${escape(data[LABEL_FIELD])}
`;
+ }
+
+ return `${escape(data[LABEL_FIELD])}
`;
+}
+
+// Initialize