diff --git a/netbox/project-static/dist/config.js b/netbox/project-static/dist/config.js index cd92937fb..c88353232 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 5059d5e89..01c611816 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 b033042d1..30794b5f2 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 f924ade99..339676ed1 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 377a53bcf..b194fdc70 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 0c07910c6..cedede19c 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 76e025f4c..744a9562d 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 76e164494..3ac8f3bd7 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 50714ec4e..13e24ffb2 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 b8f51a48c..a29e1878a 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/util.ts b/netbox/project-static/src/util.ts index 7ff6ad869..9ba10da8f 100644 --- a/netbox/project-static/src/util.ts +++ b/netbox/project-static/src/util.ts @@ -11,7 +11,7 @@ type InferredProps< // Element name. T extends keyof HTMLElementTagNameMap, // Element type. - E extends HTMLElementTagNameMap[T] = HTMLElementTagNameMap[T] + E extends HTMLElementTagNameMap[T] = HTMLElementTagNameMap[T], > = Partial>; export function isApiError(data: Record): data is APIError { @@ -94,7 +94,7 @@ export function isElement(obj: Element | null | undefined): obj is Element { /** * Retrieve the CSRF token from cookie storage. */ -export function getCsrfToken(): string { +function getCsrfToken(): string { const { csrftoken: csrfToken } = Cookie.parse(document.cookie); if (typeof csrfToken === 'undefined') { throw new Error('Invalid or missing CSRF token'); @@ -102,8 +102,45 @@ export function getCsrfToken(): string { return csrfToken; } +/** + * Get the NetBox `settings.BASE_PATH` from the `` element's data attributes. + * + * @returns If there is no `BASE_PATH` specified, the return value will be `''`. + */ function getBasePath(): string { + const value = document.documentElement.getAttribute('data-netbox-base-path'); + if (value === null) { + return ''; + } + return value; +} + +/** + * Build a NetBox URL that includes `settings.BASE_PATH` and enforces leading and trailing slashes. + * + * @example + * ```js + * // With a BASE_PATH of 'netbox/' + * const url = buildUrl('/api/dcim/devices'); + * console.log(url); + * // => /netbox/api/dcim/devices/ + * ``` + * + * @param path Relative path _after_ (excluding) the `BASE_PATH`. + */ +function buildUrl(path: string): string { + const basePath = getBasePath(); + let combined = [...basePath.split('/'), ...path.split('/')].filter(p => p); + if (combined[0] !== '/') { + combined = ['', ...combined]; + } + if (combined[combined.length - 1] !== '/') { + combined = [...combined, '']; + } + return combined.join('/'); +} + export async function apiRequest( - url: string, + path: string, method: Method, data?: D, ): Promise> { @@ -115,6 +152,7 @@ export async function apiRequest( body = JSON.stringify(data); headers.set('content-type', 'application/json'); } + const url = buildUrl(path); const res = await fetch(url, { method, body, headers, credentials: 'same-origin' }); const contentType = res.headers.get('Content-Type'); @@ -367,7 +405,7 @@ export function createElement< // Element props. P extends InferredProps, // Child element type. - C extends HTMLElement = HTMLElement + C extends HTMLElement = HTMLElement, >(tag: T, properties: P | null, classes: string[], children: C[] = []): HTMLElementTagNameMap[T] { // Create the base element. const element = document.createElement(tag); diff --git a/netbox/templates/base/base.html b/netbox/templates/base/base.html index 0a1f846fd..13e11ebf2 100644 --- a/netbox/templates/base/base.html +++ b/netbox/templates/base/base.html @@ -5,6 +5,7 @@ Any: return value[attr] -# -# Tags -# - -@register.simple_tag() -def querystring(request, **kwargs): - """ - Append or update the page number in a querystring. - """ - querydict = request.GET.copy() - for k, v in kwargs.items(): - if v is not None: - querydict[k] = str(v) - elif k in querydict: - querydict.pop(k) - querystring = querydict.urlencode(safe='/') - if querystring: - return '?' + querystring - else: - return '' - - @register.filter def status_from_tag(tag: str = "info") -> str: """ @@ -355,6 +333,36 @@ def icon_from_status(status: str = "info") -> str: return icon_map.get(status.lower(), 'information') +# +# Tags +# + +@register.simple_tag() +def querystring(request, **kwargs): + """ + Append or update the page number in a querystring. + """ + querydict = request.GET.copy() + for k, v in kwargs.items(): + if v is not None: + querydict[k] = str(v) + elif k in querydict: + querydict.pop(k) + querystring = querydict.urlencode(safe='/') + if querystring: + return '?' + querystring + else: + return '' + + +@register.simple_tag() +def base_path(): + """ + Access `BASE_PATH` in templates. + """ + return settings.BASE_PATH + + @register.inclusion_tag('utilities/templatetags/utilization_graph.html') def utilization_graph(utilization, warning_threshold=75, danger_threshold=90): """