Browse Source

implement generic api request function

checktheroads 4 năm trước cách đây
mục cha
commit
82ef6f8ac5
2 tập tin đã thay đổi với 61 bổ sung34 xóa
  1. 7 0
      netbox/project-static/src/global.d.ts
  2. 54 34
      netbox/project-static/src/util.ts

+ 7 - 0
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<T extends unknown = unknown> = Record<string, T>;
+
 type Nullable<T> = T | null;
 
 type APIAnswer<T> = {
@@ -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<APIReference>;
 }

+ 54 - 34
netbox/project-static/src/util.ts

@@ -1,4 +1,10 @@
 import Cookie from 'cookie';
+
+type APIRes<T> = 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<string, unknown>): data is APIError {
   return 'error' in data && 'exception' in data;
 }
@@ -35,58 +41,56 @@ export function getCsrfToken(): string {
   return csrfToken;
 }
 
-export async function apiGetBase<T extends Record<string, unknown>>(
+export async function apiRequest<R extends Dict, D extends ReqData = undefined>(
   url: string,
-): Promise<T | ErrorBase | APIError> {
+  method: Method,
+  data?: D,
+): Promise<APIRes<R>> {
   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<string, unknown>,
-  R extends Record<string, unknown>
->(url: string, data: T): Promise<R | ErrorBase | APIError> {
-  const token = getCsrfToken();
+export async function apiPatch<R extends Dict, D extends ReqData = Dict>(
+  url: string,
+  data: D,
+): Promise<APIRes<R>> {
+  return await apiRequest(url, 'PATCH', data);
+}
+
+export async function apiGetBase<R extends Dict>(url: string): Promise<APIRes<R>> {
+  return await apiRequest<R>(url, 'GET');
+}
+
+export async function apiPostForm<R extends Dict, D extends Dict>(
+  url: string,
+  data: D,
+): Promise<APIRes<R>> {
   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<R, URLSearchParams>(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<E extends HTMLElement>(base: E): SelectedOption[] {
+  let selected = [] as SelectedOption[];
+  for (const element of base.querySelectorAll<HTMLSelectElement>('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;
+}