diff --git a/netbox/project-static/dist/jobs.js b/netbox/project-static/dist/jobs.js index fb8621ff6..b22aed341 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 668867504..d3fe6c62c 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/netbox.js b/netbox/project-static/dist/netbox.js index f4ec02d6c..7fc5747d6 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 13c4a6bd2..3d34dd847 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/src/netbox.ts b/netbox/project-static/src/netbox.ts index 1ff0c9ecb..94ad562a9 100644 --- a/netbox/project-static/src/netbox.ts +++ b/netbox/project-static/src/netbox.ts @@ -8,6 +8,7 @@ import { initRackElevation } from './buttons'; import { initClipboard } from './clipboard'; import { initSearchBar, initInterfaceFilter } from './search'; import { initGenerateKeyPair, initLockUnlock, initGetSessionKey } from './secrets'; +import { initTableConfig } from './tableConfig'; import { getElements } from './util'; const INITIALIZERS = [ @@ -25,6 +26,7 @@ const INITIALIZERS = [ initLockUnlock, initGetSessionKey, initInterfaceFilter, + initTableConfig, ] as (() => void)[]; /** diff --git a/netbox/project-static/src/tableConfig.ts b/netbox/project-static/src/tableConfig.ts new file mode 100644 index 000000000..f2403b14f --- /dev/null +++ b/netbox/project-static/src/tableConfig.ts @@ -0,0 +1,115 @@ +import { createToast } from './toast'; +import { getElements, apiPatch, hasError, getSelectedOptions } from './util'; + +/** + * Mark each option element in the selected columns element as 'selected' so they are submitted to + * the API. + */ +function saveTableConfig() { + for (const element of getElements('select[name="columns"] option')) { + element.selected = true; + } +} + +/** + * Delete all selected columns, which reverts the user's preferences to the default column set. + */ +function resetTableConfig() { + for (const element of getElements('select[name="columns"]')) { + element.value = ''; + } +} + +/** + * Add columns to the table config select element. + */ +function addColumns(event: Event) { + for (const selectedOption of getElements('#id_available_columns > option')) { + if (selectedOption.selected) { + for (const selected of getElements('#id_columns')) { + selected.appendChild(selectedOption.cloneNode(true)); + } + selectedOption.remove(); + } + } + event.preventDefault(); +} + +/** + * Remove columns from the table config select element. + */ +function removeColumns(event: Event) { + for (const selectedOption of getElements('#id_columns > option')) { + if (selectedOption.selected) { + for (const available of getElements('#id_available_columns')) { + available.appendChild(selectedOption.cloneNode(true)); + } + selectedOption.remove(); + } + } + event.preventDefault(); +} + +/** + * Submit form configuration to the NetBox API. + */ +async function submitFormConfig(formConfig: Dict) { + return await apiPatch('/api/users/config/', formConfig); +} + +/** + * Handle table config form submission. Sends the selected columns to the NetBox API to update + * the user's table configuration preferences. + */ +function handleSubmit(event: Event) { + event.preventDefault(); + + const element = event.currentTarget as HTMLFormElement; + + // Get all the selected options from any select element in the form. + const options = getSelectedOptions(element); + + // Create an object mapping the select element's name to all selected options for that element. + const formData: Dict> = Object.assign( + {}, + ...options.map(opt => ({ [opt.name]: opt.options })), + ); + // Create an array from the dot-separated config path. E.g. tables.DevicePowerOutletTable becomes + // ['tables', 'DevicePowerOutletTable'] + const path = element.getAttribute('data-config-root')?.split('.') ?? []; + + // Create an object mapping the configuration path to the select element names, which contain the + // selection options. E.g. {tables: {DevicePowerOutletTable: {columns: ['label', 'type']}}} + const data = path.reduceRight>((value, key) => ({ [key]: value }), formData); + + // Submit the resulting object to the API to update the user's preferences for this table. + submitFormConfig(data).then(res => { + if (hasError(res)) { + const toast = createToast('danger', 'Error Updating Table Configuration', res.error); + toast.show(); + } else { + location.reload(); + } + }); +} + +/** + * Initialize table configuration elements. + */ +export function initTableConfig() { + for (const element of getElements('#save_tableconfig')) { + element.addEventListener('click', saveTableConfig); + } + for (const element of getElements('#reset_tableconfig')) { + element.addEventListener('click', resetTableConfig); + } + for (const element of getElements('#add_columns')) { + element.addEventListener('click', addColumns); + } + for (const element of getElements('#remove_columns')) { + element.addEventListener('click', removeColumns); + } + for (const element of getElements('form.userconfigform')) { + element.addEventListener('submit', handleSubmit); + } +} diff --git a/netbox/templates/dcim/device/consoleports.html b/netbox/templates/dcim/device/consoleports.html index 5214047e6..b74c6a84a 100644 --- a/netbox/templates/dcim/device/consoleports.html +++ b/netbox/templates/dcim/device/consoleports.html @@ -52,5 +52,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/dcim/device/consoleserverports.html b/netbox/templates/dcim/device/consoleserverports.html index de53184f9..a09b4b1ad 100644 --- a/netbox/templates/dcim/device/consoleserverports.html +++ b/netbox/templates/dcim/device/consoleserverports.html @@ -52,5 +52,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/dcim/device/devicebays.html b/netbox/templates/dcim/device/devicebays.html index 7af01a9c6..b36473f2c 100644 --- a/netbox/templates/dcim/device/devicebays.html +++ b/netbox/templates/dcim/device/devicebays.html @@ -46,7 +46,3 @@ {% include 'inc/paginator.html' with paginator=devicebay_table.paginator page=devicebay_table.page %} {% table_config_form devicebay_table %} {% endblock %} - -{% block javascript %} - -{% endblock %} diff --git a/netbox/templates/dcim/device/frontports.html b/netbox/templates/dcim/device/frontports.html index dd6c54e57..eed0d1f79 100644 --- a/netbox/templates/dcim/device/frontports.html +++ b/netbox/templates/dcim/device/frontports.html @@ -52,5 +52,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/dcim/device/interfaces.html b/netbox/templates/dcim/device/interfaces.html index 7913782e8..dbf26fb85 100644 --- a/netbox/templates/dcim/device/interfaces.html +++ b/netbox/templates/dcim/device/interfaces.html @@ -56,5 +56,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/dcim/device/inventory.html b/netbox/templates/dcim/device/inventory.html index e328aa6d3..992ce93a0 100644 --- a/netbox/templates/dcim/device/inventory.html +++ b/netbox/templates/dcim/device/inventory.html @@ -47,6 +47,3 @@ {% table_config_form inventoryitem_table %} {% endblock %} -{% block javascript %} - -{% endblock %} diff --git a/netbox/templates/dcim/device/poweroutlets.html b/netbox/templates/dcim/device/poweroutlets.html index 5656c4f3a..6a28513bf 100644 --- a/netbox/templates/dcim/device/poweroutlets.html +++ b/netbox/templates/dcim/device/poweroutlets.html @@ -52,5 +52,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/dcim/device/powerports.html b/netbox/templates/dcim/device/powerports.html index bc0bd3350..352691dcf 100644 --- a/netbox/templates/dcim/device/powerports.html +++ b/netbox/templates/dcim/device/powerports.html @@ -52,5 +52,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/dcim/device/rearports.html b/netbox/templates/dcim/device/rearports.html index 25c2415ad..35aec0b14 100644 --- a/netbox/templates/dcim/device/rearports.html +++ b/netbox/templates/dcim/device/rearports.html @@ -52,5 +52,4 @@ {% block javascript %} - {% endblock %} diff --git a/netbox/templates/generic/object_list.html b/netbox/templates/generic/object_list.html index d94de4e04..28d136e63 100644 --- a/netbox/templates/generic/object_list.html +++ b/netbox/templates/generic/object_list.html @@ -99,7 +99,3 @@ {% table_config_form table table_name="ObjectTable" %} {% endblock %} - -{% block javascript %} - -{% endblock %} diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html index 953bd481e..4df6f156f 100644 --- a/netbox/templates/virtualization/virtualmachine.html +++ b/netbox/templates/virtualization/virtualmachine.html @@ -212,7 +212,3 @@ {% include 'secrets/inc/private_key_modal.html' %} {% endblock %} - -{% block javascript %} - -{% endblock %} diff --git a/netbox/templates/virtualization/virtualmachine/interfaces.html b/netbox/templates/virtualization/virtualmachine/interfaces.html index dd85f5541..269fc32bc 100644 --- a/netbox/templates/virtualization/virtualmachine/interfaces.html +++ b/netbox/templates/virtualization/virtualmachine/interfaces.html @@ -51,5 +51,4 @@ {% block javascript %} - {% endblock %}