From 82ef6f8ac5838a58a8db762317caa3895e0300a3 Mon Sep 17 00:00:00 2001 From: checktheroads Date: Mon, 19 Apr 2021 16:59:26 -0700 Subject: [PATCH] implement generic api request function --- netbox/project-static/src/global.d.ts | 7 +++ netbox/project-static/src/util.ts | 88 ++++++++++++++++----------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/netbox/project-static/src/global.d.ts b/netbox/project-static/src/global.d.ts index 0ebd614a2..33afd083b 100644 --- a/netbox/project-static/src/global.d.ts +++ b/netbox/project-static/src/global.d.ts @@ -2,6 +2,8 @@ type Primitives = string | number | boolean | undefined | null; type JSONAble = Primitives | Primitives[] | { [k: string]: JSONAble } | JSONAble[]; +type Dict = Record; + type Nullable = T | null; type APIAnswer = { @@ -91,6 +93,11 @@ type APIJobResult = { }; }; +type APIUserConfig = { + tables: { [k: string]: { columns: string[]; available_columns: string[] } }; + [k: string]: unknown; +}; + interface ObjectWithGroup extends APIObjectBase { group: Nullable; } diff --git a/netbox/project-static/src/util.ts b/netbox/project-static/src/util.ts index 960fd30e2..3580f9c22 100644 --- a/netbox/project-static/src/util.ts +++ b/netbox/project-static/src/util.ts @@ -1,4 +1,10 @@ import Cookie from 'cookie'; + +type APIRes = T | ErrorBase | APIError; +type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; +type ReqData = URLSearchParams | Dict | undefined | unknown; +type SelectedOption = { name: string; options: string[] }; + export function isApiError(data: Record): data is APIError { return 'error' in data && 'exception' in data; } @@ -35,58 +41,56 @@ export function getCsrfToken(): string { return csrfToken; } -export async function apiGetBase>( +export async function apiRequest( url: string, -): Promise { + method: Method, + data?: D, +): Promise> { const token = getCsrfToken(); - const res = await fetch(url, { - method: 'GET', - headers: { 'X-CSRFToken': token }, - credentials: 'same-origin', - }); + const headers = new Headers({ 'X-CSRFToken': token }); + + let body; + if (typeof data !== 'undefined') { + body = JSON.stringify(data); + headers.set('content-type', 'application/json'); + } + + const res = await fetch(url, { method, body, headers, credentials: 'same-origin' }); const contentType = res.headers.get('Content-Type'); if (typeof contentType === 'string' && contentType.includes('text')) { const error = await res.text(); return { error } as ErrorBase; } - - const json = (await res.json()) as T | APIError; + const json = (await res.json()) as R | APIError; if (!res.ok && Array.isArray(json)) { const error = json.join('\n'); return { error } as ErrorBase; + } else if (!res.ok && 'detail' in json) { + return { error: json.detail } as ErrorBase; } return json; } -export async function apiPostForm< - T extends Record, - R extends Record ->(url: string, data: T): Promise { - const token = getCsrfToken(); +export async function apiPatch( + url: string, + data: D, +): Promise> { + return await apiRequest(url, 'PATCH', data); +} + +export async function apiGetBase(url: string): Promise> { + return await apiRequest(url, 'GET'); +} + +export async function apiPostForm( + url: string, + data: D, +): Promise> { const body = new URLSearchParams(); for (const [k, v] of Object.entries(data)) { body.append(k, String(v)); } - const res = await fetch(url, { - method: 'POST', - body, - headers: { 'X-CSRFToken': token }, - }); - - const contentType = res.headers.get('Content-Type'); - if (typeof contentType === 'string' && contentType.includes('text')) { - let error = await res.text(); - if (contentType.includes('text/html')) { - error = res.statusText; - } - return { error } as ErrorBase; - } - - const json = (await res.json()) as R | APIError; - if (!res.ok && 'detail' in json) { - return { error: json.detail as string } as ErrorBase; - } - return json; + return await apiRequest(url, 'POST', body); } /** @@ -139,3 +143,19 @@ export function scrollTo(element: Element, offset: number = 0): void { window.scrollTo({ top, behavior: 'smooth' }); return; } + +export function getSelectedOptions(base: E): SelectedOption[] { + let selected = [] as SelectedOption[]; + for (const element of base.querySelectorAll('select')) { + if (element !== null) { + const select = { name: element.name, options: [] } as SelectedOption; + for (const option of element.options) { + if (option.selected) { + select.options.push(option.value); + } + } + selected = [...selected, select]; + } + } + return selected; +}