mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Fix eslint misconfiguration and corresponding errors
This commit is contained in:
parent
82a209bc5b
commit
a0ba8380c9
@ -6,7 +6,7 @@
|
|||||||
"plugin:@typescript-eslint/eslint-recommended",
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:prettier/recommended",
|
"plugin:prettier/recommended",
|
||||||
"prettier/@typescript-eslint"
|
"prettier"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"env": {
|
"env": {
|
||||||
@ -19,8 +19,7 @@
|
|||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"arrowFunctions": true
|
"arrowFunctions": true
|
||||||
},
|
}
|
||||||
"project": "./tsconfig.json"
|
|
||||||
},
|
},
|
||||||
"plugins": ["@typescript-eslint", "prettier"],
|
"plugins": ["@typescript-eslint", "prettier"],
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -35,7 +34,7 @@
|
|||||||
"@typescript-eslint/no-unused-vars": "off",
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars-experimental": "error",
|
"@typescript-eslint/no-unused-vars-experimental": "error",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
|
"no-inner-declarations": "off",
|
||||||
"comma-dangle": ["error", "always-multiline"],
|
"comma-dangle": ["error", "always-multiline"],
|
||||||
"global-require": "off",
|
"global-require": "off",
|
||||||
"import/no-dynamic-require": "off",
|
"import/no-dynamic-require": "off",
|
||||||
|
BIN
netbox/project-static/dist/config.js
vendored
BIN
netbox/project-static/dist/config.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/config.js.map
vendored
BIN
netbox/project-static/dist/config.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/jobs.js
vendored
BIN
netbox/project-static/dist/jobs.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/jobs.js.map
vendored
BIN
netbox/project-static/dist/jobs.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/lldp.js
vendored
BIN
netbox/project-static/dist/lldp.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/lldp.js.map
vendored
BIN
netbox/project-static/dist/lldp.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/status.js
vendored
BIN
netbox/project-static/dist/status.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/status.js.map
vendored
BIN
netbox/project-static/dist/status.js.map
vendored
Binary file not shown.
@ -45,12 +45,16 @@ export function createToast(
|
|||||||
switch (level) {
|
switch (level) {
|
||||||
case 'warning':
|
case 'warning':
|
||||||
iconName = 'mdi-alert';
|
iconName = 'mdi-alert';
|
||||||
|
break;
|
||||||
case 'success':
|
case 'success':
|
||||||
iconName = 'mdi-check-circle';
|
iconName = 'mdi-check-circle';
|
||||||
|
break;
|
||||||
case 'info':
|
case 'info':
|
||||||
iconName = 'mdi-information';
|
iconName = 'mdi-information';
|
||||||
|
break;
|
||||||
case 'danger':
|
case 'danger':
|
||||||
iconName = 'mdi-alert';
|
iconName = 'mdi-alert';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
@ -109,7 +113,7 @@ export function createToast(
|
|||||||
*/
|
*/
|
||||||
function initTabs() {
|
function initTabs() {
|
||||||
const { hash } = location;
|
const { hash } = location;
|
||||||
if (hash && hash.match(/^\#tab_.+$/)) {
|
if (hash && hash.match(/^#tab_.+$/)) {
|
||||||
// The tab element will have a data-bs-target attribute with a value of the object type for
|
// The tab element will have a data-bs-target attribute with a value of the object type for
|
||||||
// the corresponding tab. Once we drop the `tab_` prefix, the hash will match the target
|
// the corresponding tab. Once we drop the `tab_` prefix, the hash will match the target
|
||||||
// element's data-bs-target value. For example, `#tab_frontports` becomes `#frontports`.
|
// element's data-bs-target value. For example, `#tab_frontports` becomes `#frontports`.
|
||||||
|
@ -21,7 +21,7 @@ type ObjectDepthState = { hidden: boolean };
|
|||||||
*
|
*
|
||||||
* @param element Connection Toggle Button Element
|
* @param element Connection Toggle Button Element
|
||||||
*/
|
*/
|
||||||
function toggleConnection(element: HTMLButtonElement) {
|
function toggleConnection(element: HTMLButtonElement): void {
|
||||||
const id = element.getAttribute('data');
|
const id = element.getAttribute('data');
|
||||||
const connected = element.classList.contains('connected');
|
const connected = element.classList.contains('connected');
|
||||||
const status = connected ? 'planned' : 'connected';
|
const status = connected ? 'planned' : 'connected';
|
||||||
@ -59,7 +59,7 @@ function toggleConnection(element: HTMLButtonElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initConnectionToggle() {
|
function initConnectionToggle(): void {
|
||||||
for (const element of getElements<HTMLButtonElement>('button.cable-toggle')) {
|
for (const element of getElements<HTMLButtonElement>('button.cable-toggle')) {
|
||||||
element.addEventListener('click', () => toggleConnection(element));
|
element.addEventListener('click', () => toggleConnection(element));
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ function handleDepthToggle(state: StateManager<ObjectDepthState>, button: HTMLBu
|
|||||||
/**
|
/**
|
||||||
* Initialize object depth toggle buttons.
|
* Initialize object depth toggle buttons.
|
||||||
*/
|
*/
|
||||||
function initDepthToggle() {
|
function initDepthToggle(): void {
|
||||||
const initiallyHidden = objectDepthState.get('hidden');
|
const initiallyHidden = objectDepthState.get('hidden');
|
||||||
|
|
||||||
for (const button of getElements<HTMLButtonElement>('button.toggle-depth')) {
|
for (const button of getElements<HTMLButtonElement>('button.toggle-depth')) {
|
||||||
@ -190,7 +190,7 @@ function handlePreferenceSave(event: Event): void {
|
|||||||
/**
|
/**
|
||||||
* Initialize handlers for user profile updates.
|
* Initialize handlers for user profile updates.
|
||||||
*/
|
*/
|
||||||
function initPreferenceUpdate() {
|
function initPreferenceUpdate(): void {
|
||||||
const form = getElement<HTMLFormElement>('preferences-update');
|
const form = getElement<HTMLFormElement>('preferences-update');
|
||||||
if (form !== null) {
|
if (form !== null) {
|
||||||
form.addEventListener('submit', handlePreferenceSave);
|
form.addEventListener('submit', handlePreferenceSave);
|
||||||
@ -203,7 +203,7 @@ function initPreferenceUpdate() {
|
|||||||
*
|
*
|
||||||
* @param event Change Event
|
* @param event Change Event
|
||||||
*/
|
*/
|
||||||
function handleSelectAllToggle(event: Event) {
|
function handleSelectAllToggle(event: Event): void {
|
||||||
// Select all checkbox in header row.
|
// Select all checkbox in header row.
|
||||||
const tableSelectAll = event.currentTarget as HTMLInputElement;
|
const tableSelectAll = event.currentTarget as HTMLInputElement;
|
||||||
// Nearest table to the select all checkbox.
|
// Nearest table to the select all checkbox.
|
||||||
@ -248,7 +248,7 @@ function handleSelectAllToggle(event: Event) {
|
|||||||
*
|
*
|
||||||
* @param event Change Event
|
* @param event Change Event
|
||||||
*/
|
*/
|
||||||
function handlePkCheck(event: Event) {
|
function handlePkCheck(event: Event): void {
|
||||||
const target = event.currentTarget as HTMLInputElement;
|
const target = event.currentTarget as HTMLInputElement;
|
||||||
if (!target.checked) {
|
if (!target.checked) {
|
||||||
for (const element of getElements<HTMLInputElement>(
|
for (const element of getElements<HTMLInputElement>(
|
||||||
@ -267,7 +267,7 @@ function handlePkCheck(event: Event) {
|
|||||||
*
|
*
|
||||||
* @param event Change Event
|
* @param event Change Event
|
||||||
*/
|
*/
|
||||||
function handleSelectAll(event: Event) {
|
function handleSelectAll(event: Event): void {
|
||||||
const target = event.currentTarget as HTMLInputElement;
|
const target = event.currentTarget as HTMLInputElement;
|
||||||
const selectAllBox = getElement<HTMLDivElement>('select-all-box');
|
const selectAllBox = getElement<HTMLDivElement>('select-all-box');
|
||||||
if (selectAllBox !== null) {
|
if (selectAllBox !== null) {
|
||||||
@ -286,7 +286,7 @@ function handleSelectAll(event: Event) {
|
|||||||
/**
|
/**
|
||||||
* Initialize table select all elements.
|
* Initialize table select all elements.
|
||||||
*/
|
*/
|
||||||
function initSelectAll() {
|
function initSelectAll(): void {
|
||||||
for (const element of getElements<HTMLInputElement>(
|
for (const element of getElements<HTMLInputElement>(
|
||||||
'table tr th > input[type="checkbox"].toggle',
|
'table tr th > input[type="checkbox"].toggle',
|
||||||
)) {
|
)) {
|
||||||
@ -302,20 +302,20 @@ function initSelectAll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePerPageSelect(event: Event) {
|
function handlePerPageSelect(event: Event): void {
|
||||||
const select = event.currentTarget as HTMLSelectElement;
|
const select = event.currentTarget as HTMLSelectElement;
|
||||||
if (select.form !== null) {
|
if (select.form !== null) {
|
||||||
select.form.submit();
|
select.form.submit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPerPage() {
|
function initPerPage(): void {
|
||||||
for (const element of getElements<HTMLSelectElement>('select.per-page')) {
|
for (const element of getElements<HTMLSelectElement>('select.per-page')) {
|
||||||
element.addEventListener('change', handlePerPageSelect);
|
element.addEventListener('change', handlePerPageSelect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initButtons() {
|
export function initButtons(): void {
|
||||||
for (const func of [
|
for (const func of [
|
||||||
initDepthToggle,
|
initDepthToggle,
|
||||||
initConnectionToggle,
|
initConnectionToggle,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Clipboard from 'clipboard';
|
import Clipboard from 'clipboard';
|
||||||
import { getElements } from './util';
|
import { getElements } from './util';
|
||||||
|
|
||||||
export function initClipboard() {
|
export function initClipboard(): void {
|
||||||
for (const element of getElements('a.copy-token', 'button.copy-secret')) {
|
for (const element of getElements('a.copy-token', 'button.copy-secret')) {
|
||||||
new Clipboard(element);
|
new Clipboard(element);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ const TEXT_WHEN_LIGHT = 'Dark Mode';
|
|||||||
const ICON_WHEN_DARK = 'mdi-lightbulb-on';
|
const ICON_WHEN_DARK = 'mdi-lightbulb-on';
|
||||||
const ICON_WHEN_LIGHT = 'mdi-lightbulb';
|
const ICON_WHEN_LIGHT = 'mdi-lightbulb';
|
||||||
|
|
||||||
function isColorMode(value: string): value is ColorMode {
|
/**
|
||||||
|
* Determine if a value is a supported color mode string value.
|
||||||
|
*/
|
||||||
|
function isColorMode(value: unknown): value is ColorMode {
|
||||||
return value === 'dark' || value === 'light';
|
return value === 'dark' || value === 'light';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { apiGetBase, getNetboxData, hasError, toggleLoader } from '../util';
|
|||||||
/**
|
/**
|
||||||
* Initialize device config elements.
|
* Initialize device config elements.
|
||||||
*/
|
*/
|
||||||
function initConfig() {
|
function initConfig(): void {
|
||||||
toggleLoader('show');
|
toggleLoader('show');
|
||||||
const url = getNetboxData('data-object-url');
|
const url = getNetboxData('data-object-url');
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ function updateRowStyle(data: LLDPNeighborDetail) {
|
|||||||
|
|
||||||
let cInterfaceShort = null;
|
let cInterfaceShort = null;
|
||||||
if (isTruthy(cInterface)) {
|
if (isTruthy(cInterface)) {
|
||||||
cInterfaceShort = cInterface.replace(/^([A-Z][a-z])[^0-9]*([0-9\/]+)$/, '$1$2');
|
cInterfaceShort = cInterface.replace(/^([A-Z][a-z])[^0-9]*([0-9/]+)$/, '$1$2');
|
||||||
}
|
}
|
||||||
|
|
||||||
const nHost = neighbor.remote_system_name ?? '';
|
const nHost = neighbor.remote_system_name ?? '';
|
||||||
|
@ -92,7 +92,7 @@ function getUptime(seconds: number): Uptime {
|
|||||||
*
|
*
|
||||||
* @param facts NAPALM Device Facts
|
* @param facts NAPALM Device Facts
|
||||||
*/
|
*/
|
||||||
function processFacts(facts: DeviceFacts) {
|
function processFacts(facts: DeviceFacts): void {
|
||||||
for (const key of factKeys) {
|
for (const key of factKeys) {
|
||||||
if (key in facts) {
|
if (key in facts) {
|
||||||
// Find the target element which should have its innerHTML/innerText set to a NAPALM value.
|
// Find the target element which should have its innerHTML/innerText set to a NAPALM value.
|
||||||
@ -149,7 +149,7 @@ function insertTitleRow<E extends HTMLElement>(next: E, title1: string, title2:
|
|||||||
* @param next Next adjacent element.For example, if this is the CPU data, `next` would be the
|
* @param next Next adjacent element.For example, if this is the CPU data, `next` would be the
|
||||||
* memory row.
|
* memory row.
|
||||||
*/
|
*/
|
||||||
function insertNoneRow<E extends Nullable<HTMLElement>>(next: E) {
|
function insertNoneRow<E extends Nullable<HTMLElement>>(next: E): void {
|
||||||
const none = createElement('td', { colSpan: '2', innerText: 'No Data' }, [
|
const none = createElement('td', { colSpan: '2', innerText: 'No Data' }, [
|
||||||
'text-muted',
|
'text-muted',
|
||||||
'text-center',
|
'text-center',
|
||||||
@ -173,7 +173,7 @@ function getNext<E extends HTMLElement>(id: string): Nullable<E> {
|
|||||||
*
|
*
|
||||||
* @param cpu NAPALM CPU data.
|
* @param cpu NAPALM CPU data.
|
||||||
*/
|
*/
|
||||||
function processCpu(cpu: DeviceEnvironment['cpu']) {
|
function processCpu(cpu: DeviceEnvironment['cpu']): void {
|
||||||
// Find the next adjacent element, so we can insert elements before it.
|
// Find the next adjacent element, so we can insert elements before it.
|
||||||
const next = getNext<HTMLTableRowElement>('status-cpu');
|
const next = getNext<HTMLTableRowElement>('status-cpu');
|
||||||
if (typeof cpu !== 'undefined') {
|
if (typeof cpu !== 'undefined') {
|
||||||
@ -200,7 +200,7 @@ function processCpu(cpu: DeviceEnvironment['cpu']) {
|
|||||||
*
|
*
|
||||||
* @param mem NAPALM memory data.
|
* @param mem NAPALM memory data.
|
||||||
*/
|
*/
|
||||||
function processMemory(mem: DeviceEnvironment['memory']) {
|
function processMemory(mem: DeviceEnvironment['memory']): void {
|
||||||
// Find the next adjacent element, so we can insert elements before it.
|
// Find the next adjacent element, so we can insert elements before it.
|
||||||
const next = getNext<HTMLTableRowElement>('status-memory');
|
const next = getNext<HTMLTableRowElement>('status-memory');
|
||||||
if (typeof mem !== 'undefined') {
|
if (typeof mem !== 'undefined') {
|
||||||
@ -222,7 +222,7 @@ function processMemory(mem: DeviceEnvironment['memory']) {
|
|||||||
*
|
*
|
||||||
* @param temp NAPALM temperature data.
|
* @param temp NAPALM temperature data.
|
||||||
*/
|
*/
|
||||||
function processTemp(temp: DeviceEnvironment['temperature']) {
|
function processTemp(temp: DeviceEnvironment['temperature']): void {
|
||||||
// Find the next adjacent element, so we can insert elements before it.
|
// Find the next adjacent element, so we can insert elements before it.
|
||||||
const next = getNext<HTMLTableRowElement>('status-temperature');
|
const next = getNext<HTMLTableRowElement>('status-temperature');
|
||||||
if (typeof temp !== 'undefined') {
|
if (typeof temp !== 'undefined') {
|
||||||
@ -249,7 +249,7 @@ function processTemp(temp: DeviceEnvironment['temperature']) {
|
|||||||
*
|
*
|
||||||
* @param fans NAPALM fan data.
|
* @param fans NAPALM fan data.
|
||||||
*/
|
*/
|
||||||
function processFans(fans: DeviceEnvironment['fans']) {
|
function processFans(fans: DeviceEnvironment['fans']): void {
|
||||||
// Find the next adjacent element, so we can insert elements before it.
|
// Find the next adjacent element, so we can insert elements before it.
|
||||||
const next = getNext<HTMLTableRowElement>('status-fans');
|
const next = getNext<HTMLTableRowElement>('status-fans');
|
||||||
if (typeof fans !== 'undefined') {
|
if (typeof fans !== 'undefined') {
|
||||||
@ -285,7 +285,7 @@ function processFans(fans: DeviceEnvironment['fans']) {
|
|||||||
*
|
*
|
||||||
* @param power NAPALM power data.
|
* @param power NAPALM power data.
|
||||||
*/
|
*/
|
||||||
function processPower(power: DeviceEnvironment['power']) {
|
function processPower(power: DeviceEnvironment['power']): void {
|
||||||
// Find the next adjacent element, so we can insert elements before it.
|
// Find the next adjacent element, so we can insert elements before it.
|
||||||
const next = getNext<HTMLTableRowElement>('status-power');
|
const next = getNext<HTMLTableRowElement>('status-power');
|
||||||
if (typeof power !== 'undefined') {
|
if (typeof power !== 'undefined') {
|
||||||
@ -322,7 +322,7 @@ function processPower(power: DeviceEnvironment['power']) {
|
|||||||
*
|
*
|
||||||
* @param env NAPALM Device Environment
|
* @param env NAPALM Device Environment
|
||||||
*/
|
*/
|
||||||
function processEnvironment(env: DeviceEnvironment) {
|
function processEnvironment(env: DeviceEnvironment): void {
|
||||||
const { cpu, memory, temperature, fans, power } = env;
|
const { cpu, memory, temperature, fans, power } = env;
|
||||||
processCpu(cpu);
|
processCpu(cpu);
|
||||||
processMemory(memory);
|
processMemory(memory);
|
||||||
@ -334,7 +334,7 @@ function processEnvironment(env: DeviceEnvironment) {
|
|||||||
/**
|
/**
|
||||||
* Initialize NAPALM device status handlers.
|
* Initialize NAPALM device status handlers.
|
||||||
*/
|
*/
|
||||||
function initStatus() {
|
function initStatus(): void {
|
||||||
// Show loading state for both Facts & Environment cards.
|
// Show loading state for both Facts & Environment cards.
|
||||||
toggleLoader('show');
|
toggleLoader('show');
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ function initFormElements() {
|
|||||||
function moveOptionUp(element: HTMLSelectElement): void {
|
function moveOptionUp(element: HTMLSelectElement): void {
|
||||||
const options = Array.from(element.options);
|
const options = Array.from(element.options);
|
||||||
for (let i = 1; i < options.length; i++) {
|
for (let i = 1; i < options.length; i++) {
|
||||||
let option = options[i];
|
const option = options[i];
|
||||||
if (option.selected) {
|
if (option.selected) {
|
||||||
element.removeChild(option);
|
element.removeChild(option);
|
||||||
element.insertBefore(option, element.options[i - 1]);
|
element.insertBefore(option, element.options[i - 1]);
|
||||||
@ -290,7 +290,7 @@ function initScopeSelector() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initForms() {
|
export function initForms(): void {
|
||||||
for (const func of [
|
for (const func of [
|
||||||
initFormElements,
|
initFormElements,
|
||||||
initFormActions,
|
initFormActions,
|
||||||
|
2
netbox/project-static/src/global.d.ts
vendored
2
netbox/project-static/src/global.d.ts
vendored
@ -33,6 +33,8 @@ interface Window {
|
|||||||
*/
|
*/
|
||||||
type Index<O extends Dict, K extends keyof O> = K extends string ? K : never;
|
type Index<O extends Dict, K extends keyof O> = K extends string ? K : never;
|
||||||
|
|
||||||
|
type APIResponse<T> = T | ErrorBase | APIError;
|
||||||
|
|
||||||
type APIAnswer<T> = {
|
type APIAnswer<T> = {
|
||||||
count: number;
|
count: number;
|
||||||
next: Nullable<string>;
|
next: Nullable<string>;
|
||||||
|
@ -44,10 +44,13 @@ function updateLabel(status: JobStatus) {
|
|||||||
switch (status.value) {
|
switch (status.value) {
|
||||||
case 'failed' || 'errored':
|
case 'failed' || 'errored':
|
||||||
labelClass = 'danger';
|
labelClass = 'danger';
|
||||||
|
break;
|
||||||
case 'running':
|
case 'running':
|
||||||
labelClass = 'warning';
|
labelClass = 'warning';
|
||||||
|
break;
|
||||||
case 'completed':
|
case 'completed':
|
||||||
labelClass = 'success';
|
labelClass = 'success';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
element.setAttribute('class', `badge bg-${labelClass}`);
|
element.setAttribute('class', `badge bg-${labelClass}`);
|
||||||
element.innerText = status.label;
|
element.innerText = status.label;
|
||||||
|
@ -3,7 +3,7 @@ import { isTruthy, getElements } from './util';
|
|||||||
/**
|
/**
|
||||||
* Allow any element to be made "clickable" with the use of the `data-href` attribute.
|
* Allow any element to be made "clickable" with the use of the `data-href` attribute.
|
||||||
*/
|
*/
|
||||||
export function initLinks() {
|
export function initLinks(): void {
|
||||||
for (const link of getElements('*[data-href]')) {
|
for (const link of getElements('*[data-href]')) {
|
||||||
const href = link.getAttribute('data-href');
|
const href = link.getAttribute('data-href');
|
||||||
if (isTruthy(href)) {
|
if (isTruthy(href)) {
|
||||||
|
@ -13,7 +13,7 @@ import { initSideNav } from './sidenav';
|
|||||||
import { initRackElevation } from './racks';
|
import { initRackElevation } from './racks';
|
||||||
import { initLinks } from './links';
|
import { initLinks } from './links';
|
||||||
|
|
||||||
function initDocument() {
|
function initDocument(): void {
|
||||||
for (const init of [
|
for (const init of [
|
||||||
initBootstrap,
|
initBootstrap,
|
||||||
initColorMode,
|
initColorMode,
|
||||||
@ -34,7 +34,7 @@ function initDocument() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initWindow() {
|
function initWindow(): void {
|
||||||
const contentContainer = document.querySelector<HTMLElement>('.content-container');
|
const contentContainer = document.querySelector<HTMLElement>('.content-container');
|
||||||
if (contentContainer !== null) {
|
if (contentContainer !== null) {
|
||||||
// Focus the content container for accessible navigation.
|
// Focus the content container for accessible navigation.
|
||||||
|
@ -67,7 +67,7 @@ function handleRackImageToggle(
|
|||||||
* Add onClick callback for toggling rack elevation images. Synchronize the image toggle button
|
* Add onClick callback for toggling rack elevation images. Synchronize the image toggle button
|
||||||
* text and display state of images with the local state.
|
* text and display state of images with the local state.
|
||||||
*/
|
*/
|
||||||
export function initRackElevation() {
|
export function initRackElevation(): void {
|
||||||
const initiallyHidden = rackImagesState.get('hidden');
|
const initiallyHidden = rackImagesState.get('hidden');
|
||||||
for (const button of getElements<HTMLButtonElement>('button.toggle-images')) {
|
for (const button of getElements<HTMLButtonElement>('button.toggle-images')) {
|
||||||
toggleRackImagesButton(initiallyHidden, button);
|
toggleRackImagesButton(initiallyHidden, button);
|
||||||
|
@ -8,7 +8,7 @@ import { getElements, getRowValues, findFirstAdjacent, isTruthy } from './util';
|
|||||||
* @param event "click" event for each dropdown item.
|
* @param event "click" event for each dropdown item.
|
||||||
* @param button Each dropdown item element.
|
* @param button Each dropdown item element.
|
||||||
*/
|
*/
|
||||||
function handleSearchDropdownClick(event: Event, button: HTMLButtonElement) {
|
function handleSearchDropdownClick(event: Event, button: HTMLButtonElement): void {
|
||||||
const dropdown = event.currentTarget as HTMLButtonElement;
|
const dropdown = event.currentTarget as HTMLButtonElement;
|
||||||
const selectedValue = findFirstAdjacent<HTMLSpanElement>(dropdown, 'span.search-obj-selected');
|
const selectedValue = findFirstAdjacent<HTMLSpanElement>(dropdown, 'span.search-obj-selected');
|
||||||
const selectedType = findFirstAdjacent<HTMLInputElement>(dropdown, 'input.search-obj-type');
|
const selectedType = findFirstAdjacent<HTMLInputElement>(dropdown, 'input.search-obj-type');
|
||||||
@ -31,7 +31,7 @@ function handleSearchDropdownClick(event: Event, button: HTMLButtonElement) {
|
|||||||
/**
|
/**
|
||||||
* Initialize Search Bar Elements.
|
* Initialize Search Bar Elements.
|
||||||
*/
|
*/
|
||||||
function initSearchBar() {
|
function initSearchBar(): void {
|
||||||
for (const dropdown of getElements<HTMLUListElement>('.search-obj-selector')) {
|
for (const dropdown of getElements<HTMLUListElement>('.search-obj-selector')) {
|
||||||
for (const button of dropdown.querySelectorAll<HTMLButtonElement>(
|
for (const button of dropdown.querySelectorAll<HTMLButtonElement>(
|
||||||
'li > button.dropdown-item',
|
'li > button.dropdown-item',
|
||||||
@ -44,7 +44,7 @@ function initSearchBar() {
|
|||||||
/**
|
/**
|
||||||
* Initialize Interface Table Filter Elements.
|
* Initialize Interface Table Filter Elements.
|
||||||
*/
|
*/
|
||||||
function initInterfaceFilter() {
|
function initInterfaceFilter(): void {
|
||||||
for (const input of getElements<HTMLInputElement>('input.interface-filter')) {
|
for (const input of getElements<HTMLInputElement>('input.interface-filter')) {
|
||||||
const table = findFirstAdjacent<HTMLTableElement>(input, 'table');
|
const table = findFirstAdjacent<HTMLTableElement>(input, 'table');
|
||||||
const rows = Array.from(
|
const rows = Array.from(
|
||||||
@ -53,7 +53,7 @@ function initInterfaceFilter() {
|
|||||||
/**
|
/**
|
||||||
* Filter on-page table by input text.
|
* Filter on-page table by input text.
|
||||||
*/
|
*/
|
||||||
function handleInput(event: Event) {
|
function handleInput(event: Event): void {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
// Create a regex pattern from the input search text to match against.
|
// Create a regex pattern from the input search text to match against.
|
||||||
const filter = new RegExp(target.value.toLowerCase().trim());
|
const filter = new RegExp(target.value.toLowerCase().trim());
|
||||||
@ -87,7 +87,7 @@ function initInterfaceFilter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initTableFilter() {
|
function initTableFilter(): void {
|
||||||
for (const input of getElements<HTMLInputElement>('input.object-filter')) {
|
for (const input of getElements<HTMLInputElement>('input.object-filter')) {
|
||||||
// Find the first adjacent table element.
|
// Find the first adjacent table element.
|
||||||
const table = findFirstAdjacent<HTMLTableElement>(input, 'table');
|
const table = findFirstAdjacent<HTMLTableElement>(input, 'table');
|
||||||
@ -101,7 +101,7 @@ function initTableFilter() {
|
|||||||
* Filter table rows by matched input text.
|
* Filter table rows by matched input text.
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
function handleInput(event: Event) {
|
function handleInput(event: Event): void {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
|
|
||||||
// Create a regex pattern from the input search text to match against.
|
// Create a regex pattern from the input search text to match against.
|
||||||
@ -132,7 +132,7 @@ function initTableFilter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initSearch() {
|
export function initSearch(): void {
|
||||||
for (const func of [initSearchBar, initTableFilter, initInterfaceFilter]) {
|
for (const func of [initSearchBar, initTableFilter, initInterfaceFilter]) {
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
@ -711,7 +711,7 @@ class APISelect {
|
|||||||
* @param id DOM ID of the other element.
|
* @param id DOM ID of the other element.
|
||||||
*/
|
*/
|
||||||
private updatePathValues(id: string): void {
|
private updatePathValues(id: string): void {
|
||||||
let key = id.replaceAll(/^id_/gi, '');
|
const key = id.replaceAll(/^id_/gi, '');
|
||||||
const element = getElement<HTMLSelectElement>(`id_${key}`);
|
const element = getElement<HTMLSelectElement>(`id_${key}`);
|
||||||
if (element !== null) {
|
if (element !== null) {
|
||||||
// If this element's URL contains Django template tags ({{), replace the template tag
|
// If this element's URL contains Django template tags ({{), replace the template tag
|
||||||
@ -982,15 +982,16 @@ class APISelect {
|
|||||||
'button',
|
'button',
|
||||||
{ type: 'button' },
|
{ type: 'button' },
|
||||||
['btn', 'btn-sm', 'btn-ghost-dark'],
|
['btn', 'btn-sm', 'btn-ghost-dark'],
|
||||||
[createElement('i', {}, ['mdi', 'mdi-reload'])],
|
[createElement('i', null, ['mdi', 'mdi-reload'])],
|
||||||
);
|
);
|
||||||
refreshButton.addEventListener('click', () => this.loadData());
|
refreshButton.addEventListener('click', () => this.loadData());
|
||||||
|
refreshButton.type = 'button';
|
||||||
this.slim.slim.search.container.appendChild(refreshButton);
|
this.slim.slim.search.container.appendChild(refreshButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initApiSelect() {
|
export function initApiSelect(): void {
|
||||||
for (const select of getElements<HTMLSelectElement>('.netbox-api-select')) {
|
for (const select of getElements<HTMLSelectElement>('.netbox-api-select')) {
|
||||||
new APISelect(select);
|
new APISelect(select);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,30 @@ function canChangeColor(option: Option | HTMLOptionElement): boolean {
|
|||||||
return typeof option.value === 'string' && option.value !== '';
|
return typeof option.value === 'string' && option.value !== '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style the container element based on the selected option value.
|
||||||
|
*/
|
||||||
|
function styleContainer(
|
||||||
|
instance: InstanceType<typeof SlimSelect>,
|
||||||
|
option: Option | HTMLOptionElement,
|
||||||
|
): void {
|
||||||
|
if (instance.slim.singleSelected !== null) {
|
||||||
|
if (canChangeColor(option)) {
|
||||||
|
// Get the background color from the selected option's value.
|
||||||
|
const bg = `#${option.value}`;
|
||||||
|
// Determine an accessible foreground color based on the background color.
|
||||||
|
const fg = readableColor(bg);
|
||||||
|
|
||||||
|
// Set the container's style attributes.
|
||||||
|
instance.slim.singleSelected.container.style.backgroundColor = bg;
|
||||||
|
instance.slim.singleSelected.container.style.color = fg;
|
||||||
|
} else {
|
||||||
|
// If the color cannot be set (i.e., the placeholder), remove any inline styles.
|
||||||
|
instance.slim.singleSelected.container.removeAttribute('style');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize color selection widget. Dynamically change the style of the select container to match
|
* Initialize color selection widget. Dynamically change the style of the select container to match
|
||||||
* the selected option.
|
* the selected option.
|
||||||
@ -40,7 +64,7 @@ export function initColorSelect(): void {
|
|||||||
// Style the select container to match any pre-selectd options.
|
// Style the select container to match any pre-selectd options.
|
||||||
for (const option of instance.data.data) {
|
for (const option of instance.data.data) {
|
||||||
if ('selected' in option && option.selected) {
|
if ('selected' in option && option.selected) {
|
||||||
styleContainer(option);
|
styleContainer(instance, option);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,25 +74,7 @@ export function initColorSelect(): void {
|
|||||||
instance.slim.container.classList.remove(className);
|
instance.slim.container.classList.remove(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
function styleContainer(option: Option | HTMLOptionElement): void {
|
|
||||||
if (instance.slim.singleSelected !== null) {
|
|
||||||
if (canChangeColor(option)) {
|
|
||||||
// Get the background color from the selected option's value.
|
|
||||||
const bg = `#${option.value}`;
|
|
||||||
// Determine an accessible foreground color based on the background color.
|
|
||||||
const fg = readableColor(bg);
|
|
||||||
|
|
||||||
// Set the container's style attributes.
|
|
||||||
instance.slim.singleSelected.container.style.backgroundColor = bg;
|
|
||||||
instance.slim.singleSelected.container.style.color = fg;
|
|
||||||
} else {
|
|
||||||
// If the color cannot be set (i.e., the placeholder), remove any inline styles.
|
|
||||||
instance.slim.singleSelected.container.removeAttribute('style');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the SlimSelect container's style based on the selected option.
|
// Change the SlimSelect container's style based on the selected option.
|
||||||
instance.onChange = styleContainer;
|
instance.onChange = option => styleContainer(instance, option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { initApiSelect } from './api';
|
|||||||
import { initColorSelect } from './color';
|
import { initColorSelect } from './color';
|
||||||
import { initStaticSelect } from './static';
|
import { initStaticSelect } from './static';
|
||||||
|
|
||||||
export function initSelect() {
|
export function initSelect(): void {
|
||||||
for (const func of [initApiSelect, initColorSelect, initStaticSelect]) {
|
for (const func of [initApiSelect, initColorSelect, initStaticSelect]) {
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import SlimSelect from 'slim-select';
|
import SlimSelect from 'slim-select';
|
||||||
import { getElements } from '../util';
|
import { getElements } from '../util';
|
||||||
|
|
||||||
export function initStaticSelect() {
|
export function initStaticSelect(): void {
|
||||||
for (const select of getElements<HTMLSelectElement>('.netbox-static-select')) {
|
for (const select of getElements<HTMLSelectElement>('.netbox-static-select')) {
|
||||||
if (select !== null) {
|
if (select !== null) {
|
||||||
const label = document.querySelector(`label[for=${select.id}]`) as HTMLLabelElement;
|
const label = document.querySelector(`label[for=${select.id}]`) as HTMLLabelElement;
|
||||||
|
@ -237,7 +237,7 @@ class SideNav {
|
|||||||
'.navbar-nav .nav .nav-item a.nav-link',
|
'.navbar-nav .nav .nav-item a.nav-link',
|
||||||
)) {
|
)) {
|
||||||
const href = new RegExp(link.href, 'gi');
|
const href = new RegExp(link.href, 'gi');
|
||||||
if (Boolean(window.location.href.match(href))) {
|
if (window.location.href.match(href)) {
|
||||||
yield link;
|
yield link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ class SideNav {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initSideNav() {
|
export function initSideNav(): void {
|
||||||
for (const sidenav of getElements<HTMLDivElement>('.sidenav')) {
|
for (const sidenav of getElements<HTMLDivElement>('.sidenav')) {
|
||||||
new SideNav(sidenav);
|
new SideNav(sidenav);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import { getElements, apiPatch, hasError, getSelectedOptions } from './util';
|
|||||||
* Mark each option element in the selected columns element as 'selected' so they are submitted to
|
* Mark each option element in the selected columns element as 'selected' so they are submitted to
|
||||||
* the API.
|
* the API.
|
||||||
*/
|
*/
|
||||||
function saveTableConfig() {
|
function saveTableConfig(): void {
|
||||||
for (const element of getElements<HTMLOptionElement>('select[name="columns"] option')) {
|
for (const element of getElements<HTMLOptionElement>('select[name="columns"] option')) {
|
||||||
element.selected = true;
|
element.selected = true;
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ function saveTableConfig() {
|
|||||||
/**
|
/**
|
||||||
* Delete all selected columns, which reverts the user's preferences to the default column set.
|
* Delete all selected columns, which reverts the user's preferences to the default column set.
|
||||||
*/
|
*/
|
||||||
function resetTableConfig() {
|
function resetTableConfig(): void {
|
||||||
for (const element of getElements<HTMLSelectElement>('select[name="columns"]')) {
|
for (const element of getElements<HTMLSelectElement>('select[name="columns"]')) {
|
||||||
element.value = '';
|
element.value = '';
|
||||||
}
|
}
|
||||||
@ -23,7 +23,7 @@ function resetTableConfig() {
|
|||||||
/**
|
/**
|
||||||
* Add columns to the table config select element.
|
* Add columns to the table config select element.
|
||||||
*/
|
*/
|
||||||
function addColumns(event: Event) {
|
function addColumns(event: Event): void {
|
||||||
for (const selectedOption of getElements<HTMLOptionElement>('#id_available_columns > option')) {
|
for (const selectedOption of getElements<HTMLOptionElement>('#id_available_columns > option')) {
|
||||||
if (selectedOption.selected) {
|
if (selectedOption.selected) {
|
||||||
for (const selected of getElements<HTMLSelectElement>('#id_columns')) {
|
for (const selected of getElements<HTMLSelectElement>('#id_columns')) {
|
||||||
@ -38,7 +38,7 @@ function addColumns(event: Event) {
|
|||||||
/**
|
/**
|
||||||
* Remove columns from the table config select element.
|
* Remove columns from the table config select element.
|
||||||
*/
|
*/
|
||||||
function removeColumns(event: Event) {
|
function removeColumns(event: Event): void {
|
||||||
for (const selectedOption of getElements<HTMLOptionElement>('#id_columns > option')) {
|
for (const selectedOption of getElements<HTMLOptionElement>('#id_columns > option')) {
|
||||||
if (selectedOption.selected) {
|
if (selectedOption.selected) {
|
||||||
for (const available of getElements<HTMLSelectElement>('#id_available_columns')) {
|
for (const available of getElements<HTMLSelectElement>('#id_available_columns')) {
|
||||||
@ -53,7 +53,7 @@ function removeColumns(event: Event) {
|
|||||||
/**
|
/**
|
||||||
* Submit form configuration to the NetBox API.
|
* Submit form configuration to the NetBox API.
|
||||||
*/
|
*/
|
||||||
async function submitFormConfig(formConfig: Dict<Dict>) {
|
async function submitFormConfig(formConfig: Dict<Dict>): Promise<APIResponse<APIUserConfig>> {
|
||||||
return await apiPatch<APIUserConfig>('/api/users/config/', formConfig);
|
return await apiPatch<APIUserConfig>('/api/users/config/', formConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ async function submitFormConfig(formConfig: Dict<Dict>) {
|
|||||||
* Handle table config form submission. Sends the selected columns to the NetBox API to update
|
* Handle table config form submission. Sends the selected columns to the NetBox API to update
|
||||||
* the user's table configuration preferences.
|
* the user's table configuration preferences.
|
||||||
*/
|
*/
|
||||||
function handleSubmit(event: Event) {
|
function handleSubmit(event: Event): void {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const element = event.currentTarget as HTMLFormElement;
|
const element = event.currentTarget as HTMLFormElement;
|
||||||
@ -96,7 +96,7 @@ function handleSubmit(event: Event) {
|
|||||||
/**
|
/**
|
||||||
* Initialize table configuration elements.
|
* Initialize table configuration elements.
|
||||||
*/
|
*/
|
||||||
export function initTableConfig() {
|
export function initTableConfig(): void {
|
||||||
for (const element of getElements<HTMLButtonElement>('#save_tableconfig')) {
|
for (const element of getElements<HTMLButtonElement>('#save_tableconfig')) {
|
||||||
element.addEventListener('click', saveTableConfig);
|
element.addEventListener('click', saveTableConfig);
|
||||||
}
|
}
|
||||||
|
@ -164,18 +164,14 @@ class TableState {
|
|||||||
private table: HTMLTableElement;
|
private table: HTMLTableElement;
|
||||||
/**
|
/**
|
||||||
* Instance of ButtonState for the 'show/hide enabled rows' button.
|
* Instance of ButtonState for the 'show/hide enabled rows' button.
|
||||||
*
|
|
||||||
* TS Error is expected because null handling is performed in the constructor.
|
|
||||||
*/
|
*/
|
||||||
// @ts-expect-error
|
// @ts-expect-error null handling is performed in the constructor
|
||||||
private enabledButton: ButtonState;
|
private enabledButton: ButtonState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of ButtonState for the 'show/hide disabled rows' button.
|
* Instance of ButtonState for the 'show/hide disabled rows' button.
|
||||||
*
|
|
||||||
* TS Error is expected because null handling is performed in the constructor.
|
|
||||||
*/
|
*/
|
||||||
// @ts-expect-error
|
// @ts-expect-error null handling is performed in the constructor
|
||||||
private disabledButton: ButtonState;
|
private disabledButton: ButtonState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,7 +284,7 @@ class TableState {
|
|||||||
/**
|
/**
|
||||||
* Initialize table states.
|
* Initialize table states.
|
||||||
*/
|
*/
|
||||||
export function initInterfaceTable() {
|
export function initInterfaceTable(): void {
|
||||||
for (const element of getElements<HTMLTableElement>('table')) {
|
for (const element of getElements<HTMLTableElement>('table')) {
|
||||||
new TableState(element);
|
new TableState(element);
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import Cookie from 'cookie';
|
import Cookie from 'cookie';
|
||||||
|
|
||||||
type APIRes<T> = T | ErrorBase | APIError;
|
|
||||||
type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||||
type ReqData = URLSearchParams | Dict | undefined | unknown;
|
type ReqData = URLSearchParams | Dict | undefined | unknown;
|
||||||
type SelectedOption = { name: string; options: string[] };
|
type SelectedOption = { name: string; options: string[] };
|
||||||
|
|
||||||
type HTMLElementProperties<E extends HTMLElement> =
|
/**
|
||||||
| {
|
* Infer valid HTMLElement props based on element name.
|
||||||
[k in keyof E]: E[k];
|
*/
|
||||||
}
|
type InferredProps<
|
||||||
| {};
|
// Element name.
|
||||||
|
T extends keyof HTMLElementTagNameMap,
|
||||||
type InferredProps<T extends keyof HTMLElementTagNameMap> = HTMLElementProperties<
|
// Element type.
|
||||||
HTMLElementTagNameMap[T]
|
E extends HTMLElementTagNameMap[T] = HTMLElementTagNameMap[T]
|
||||||
>;
|
> = Partial<Record<keyof E, E[keyof E]>>;
|
||||||
|
|
||||||
export function isApiError(data: Record<string, unknown>): data is APIError {
|
export function isApiError(data: Record<string, unknown>): data is APIError {
|
||||||
return 'error' in data && 'exception' in data;
|
return 'error' in data && 'exception' in data;
|
||||||
@ -36,9 +35,9 @@ export function hasMore(data: APIAnswer<APIObjectBase>): data is APIAnswerWithNe
|
|||||||
*/
|
*/
|
||||||
export function slugify(slug: string, chars: number): string {
|
export function slugify(slug: string, chars: number): string {
|
||||||
return slug
|
return slug
|
||||||
.replace(/[^\-\.\w\s]/g, '') // Remove unneeded chars
|
.replace(/[^\-.\w\s]/g, '') // Remove unneeded chars
|
||||||
.replace(/^[\s\.]+|[\s\.]+$/g, '') // Trim leading/trailing spaces
|
.replace(/^[\s.]+|[\s.]+$/g, '') // Trim leading/trailing spaces
|
||||||
.replace(/[\-\.\s]+/g, '-') // Convert spaces and decimals to hyphens
|
.replace(/[-.\s]+/g, '-') // Convert spaces and decimals to hyphens
|
||||||
.toLowerCase() // Convert to lowercase
|
.toLowerCase() // Convert to lowercase
|
||||||
.substring(0, chars); // Trim to first chars chars
|
.substring(0, chars); // Trim to first chars chars
|
||||||
}
|
}
|
||||||
@ -82,7 +81,7 @@ export async function apiRequest<R extends Dict, D extends ReqData = undefined>(
|
|||||||
url: string,
|
url: string,
|
||||||
method: Method,
|
method: Method,
|
||||||
data?: D,
|
data?: D,
|
||||||
): Promise<APIRes<R>> {
|
): Promise<APIResponse<R>> {
|
||||||
const token = getCsrfToken();
|
const token = getCsrfToken();
|
||||||
const headers = new Headers({ 'X-CSRFToken': token });
|
const headers = new Headers({ 'X-CSRFToken': token });
|
||||||
|
|
||||||
@ -111,18 +110,18 @@ export async function apiRequest<R extends Dict, D extends ReqData = undefined>(
|
|||||||
export async function apiPatch<R extends Dict, D extends ReqData = Dict>(
|
export async function apiPatch<R extends Dict, D extends ReqData = Dict>(
|
||||||
url: string,
|
url: string,
|
||||||
data: D,
|
data: D,
|
||||||
): Promise<APIRes<R>> {
|
): Promise<APIResponse<R>> {
|
||||||
return await apiRequest(url, 'PATCH', data);
|
return await apiRequest(url, 'PATCH', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiGetBase<R extends Dict>(url: string): Promise<APIRes<R>> {
|
export async function apiGetBase<R extends Dict>(url: string): Promise<APIResponse<R>> {
|
||||||
return await apiRequest<R>(url, 'GET');
|
return await apiRequest<R>(url, 'GET');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiPostForm<R extends Dict, D extends Dict>(
|
export async function apiPostForm<R extends Dict, D extends Dict>(
|
||||||
url: string,
|
url: string,
|
||||||
data: D,
|
data: D,
|
||||||
): Promise<APIRes<R>> {
|
): Promise<APIResponse<R>> {
|
||||||
const body = new URLSearchParams();
|
const body = new URLSearchParams();
|
||||||
for (const [k, v] of Object.entries(data)) {
|
for (const [k, v] of Object.entries(data)) {
|
||||||
body.append(k, String(v));
|
body.append(k, String(v));
|
||||||
@ -149,7 +148,7 @@ export function getElements<K extends keyof HTMLElementTagNameMap>(
|
|||||||
export function getElements<E extends Element>(...key: string[]): Generator<E>;
|
export function getElements<E extends Element>(...key: string[]): Generator<E>;
|
||||||
export function* getElements(
|
export function* getElements(
|
||||||
...key: (string | keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap)[]
|
...key: (string | keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap)[]
|
||||||
) {
|
): Generator<Element> {
|
||||||
for (const query of key) {
|
for (const query of key) {
|
||||||
for (const element of document.querySelectorAll(query)) {
|
for (const element of document.querySelectorAll(query)) {
|
||||||
if (element !== null) {
|
if (element !== null) {
|
||||||
@ -249,7 +248,7 @@ export function getNetboxData(key: string): string | null {
|
|||||||
/**
|
/**
|
||||||
* Toggle visibility of card loader.
|
* Toggle visibility of card loader.
|
||||||
*/
|
*/
|
||||||
export function toggleLoader(action: 'show' | 'hide') {
|
export function toggleLoader(action: 'show' | 'hide'): void {
|
||||||
for (const element of getElements<HTMLDivElement>('div.card-overlay')) {
|
for (const element of getElements<HTMLDivElement>('div.card-overlay')) {
|
||||||
if (action === 'show') {
|
if (action === 'show') {
|
||||||
element.classList.remove('d-none');
|
element.classList.remove('d-none');
|
||||||
@ -316,25 +315,27 @@ export function findFirstAdjacent<R extends HTMLElement, B extends Element = Ele
|
|||||||
* @param children Child elements.
|
* @param children Child elements.
|
||||||
*/
|
*/
|
||||||
export function createElement<
|
export function createElement<
|
||||||
|
// Element name.
|
||||||
T extends keyof HTMLElementTagNameMap,
|
T extends keyof HTMLElementTagNameMap,
|
||||||
|
// Element props.
|
||||||
|
P extends InferredProps<T>,
|
||||||
|
// Child element type.
|
||||||
C extends HTMLElement = HTMLElement
|
C extends HTMLElement = HTMLElement
|
||||||
>(
|
>(tag: T, properties: P | null, classes: string[], children: C[] = []): HTMLElementTagNameMap[T] {
|
||||||
tag: T,
|
|
||||||
properties: InferredProps<T>,
|
|
||||||
classes: string[],
|
|
||||||
children: C[] = [],
|
|
||||||
): HTMLElementTagNameMap[T] {
|
|
||||||
// Create the base element.
|
// Create the base element.
|
||||||
const element = document.createElement<T>(tag);
|
const element = document.createElement<T>(tag);
|
||||||
|
|
||||||
|
if (properties !== null) {
|
||||||
for (const k of Object.keys(properties)) {
|
for (const k of Object.keys(properties)) {
|
||||||
// Add each property to the element.
|
// Add each property to the element.
|
||||||
const key = k as keyof HTMLElementProperties<HTMLElementTagNameMap[T]>;
|
const key = k as keyof InferredProps<T>;
|
||||||
const value = properties[key];
|
const value = properties[key] as NonNullable<P[keyof P]>;
|
||||||
if (key in element) {
|
if (key in element) {
|
||||||
element[key] = value;
|
element[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add each CSS class to the element's class list.
|
// Add each CSS class to the element's class list.
|
||||||
element.classList.add(...classes);
|
element.classList.add(...classes);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user