168 lines
4.7 KiB
TypeScript
168 lines
4.7 KiB
TypeScript
import type { DataProvider, DeleteManyParams, RaRecord } from 'react-admin';
|
|
import { env } from './config/env';
|
|
import { ensureFreshToken, getAccessToken } from './auth/keycloak';
|
|
|
|
type HttpResult<T> = {
|
|
data: T;
|
|
headers: Headers;
|
|
};
|
|
|
|
async function withAuthHeaders(headers = new Headers()) {
|
|
await ensureFreshToken();
|
|
const token = getAccessToken();
|
|
|
|
if (token) {
|
|
headers.set('Authorization', `Bearer ${token}`);
|
|
}
|
|
|
|
headers.set('Accept', 'application/json');
|
|
headers.set('Content-Type', 'application/json');
|
|
return headers;
|
|
}
|
|
|
|
function appendFilterParams(searchParams: URLSearchParams, filter?: Record<string, unknown>) {
|
|
if (!filter) {
|
|
return;
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(filter)) {
|
|
if (value === undefined || value === null || value === '') {
|
|
continue;
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
value.forEach((entry) => {
|
|
if (entry !== undefined && entry !== null && entry !== '') {
|
|
searchParams.append(key, String(entry));
|
|
}
|
|
});
|
|
continue;
|
|
}
|
|
|
|
searchParams.append(key, String(value));
|
|
}
|
|
}
|
|
|
|
async function http<T>(url: string, init?: RequestInit): Promise<HttpResult<T>> {
|
|
const headers = await withAuthHeaders(new Headers(init?.headers));
|
|
const response = await fetch(url, {
|
|
...init,
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const error = new Error(`Request failed with status ${response.status}`) as Error & { status: number };
|
|
error.status = response.status;
|
|
throw error;
|
|
}
|
|
|
|
const text = await response.text();
|
|
return {
|
|
data: text ? (JSON.parse(text) as T) : (null as T),
|
|
headers: response.headers,
|
|
};
|
|
}
|
|
|
|
function parseTotal(headers: Headers, fallback: number) {
|
|
const contentRange = headers.get('Content-Range');
|
|
if (!contentRange) {
|
|
return fallback;
|
|
}
|
|
|
|
const match = contentRange.match(/\/(\d+)$/);
|
|
return match ? Number(match[1]) : fallback;
|
|
}
|
|
|
|
export const dataProvider: DataProvider = {
|
|
async getList(resource, params) {
|
|
const searchParams = new URLSearchParams({
|
|
_start: String(params.pagination.page <= 1 ? 0 : (params.pagination.page - 1) * params.pagination.perPage),
|
|
_end: String(params.pagination.page * params.pagination.perPage),
|
|
_sort: params.sort.field,
|
|
_order: params.sort.order,
|
|
});
|
|
|
|
appendFilterParams(searchParams, params.filter);
|
|
|
|
const { data, headers } = await http<RaRecord[]>(`${env.apiUrl}/${resource}?${searchParams.toString()}`);
|
|
return {
|
|
data,
|
|
total: parseTotal(headers, data.length),
|
|
};
|
|
},
|
|
|
|
async getOne(resource, params) {
|
|
const { data } = await http<RaRecord>(`${env.apiUrl}/${resource}/${params.id}`);
|
|
return { data };
|
|
},
|
|
|
|
async getMany(resource, params) {
|
|
const results = await Promise.all(params.ids.map((id) => http<RaRecord>(`${env.apiUrl}/${resource}/${id}`)));
|
|
return { data: results.map((result) => result.data) };
|
|
},
|
|
|
|
async getManyReference(resource, params) {
|
|
const searchParams = new URLSearchParams({
|
|
_start: String(params.pagination.page <= 1 ? 0 : (params.pagination.page - 1) * params.pagination.perPage),
|
|
_end: String(params.pagination.page * params.pagination.perPage),
|
|
_sort: params.sort.field,
|
|
_order: params.sort.order,
|
|
[params.target]: String(params.id),
|
|
});
|
|
|
|
appendFilterParams(searchParams, params.filter);
|
|
|
|
const { data, headers } = await http<RaRecord[]>(`${env.apiUrl}/${resource}?${searchParams.toString()}`);
|
|
return {
|
|
data,
|
|
total: parseTotal(headers, data.length),
|
|
};
|
|
},
|
|
|
|
async create(resource, params) {
|
|
const { data } = await http<RaRecord>(`${env.apiUrl}/${resource}`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(params.data),
|
|
});
|
|
return { data };
|
|
},
|
|
|
|
async update(resource, params) {
|
|
const { data } = await http<RaRecord>(`${env.apiUrl}/${resource}/${params.id}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(params.data),
|
|
});
|
|
return { data };
|
|
},
|
|
|
|
async updateMany(resource, params) {
|
|
const results = await Promise.all(
|
|
params.ids.map((id) =>
|
|
http<RaRecord>(`${env.apiUrl}/${resource}/${id}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(params.data),
|
|
}),
|
|
),
|
|
);
|
|
return { data: results.map((result) => result.data.id) };
|
|
},
|
|
|
|
async delete(resource, params) {
|
|
const { data } = await http<RaRecord>(`${env.apiUrl}/${resource}/${params.id}`, {
|
|
method: 'DELETE',
|
|
});
|
|
return { data };
|
|
},
|
|
|
|
async deleteMany(resource, params: DeleteManyParams<any>) {
|
|
const results = await Promise.all(
|
|
params.ids.map((id) =>
|
|
http<RaRecord>(`${env.apiUrl}/${resource}/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
),
|
|
);
|
|
return { data: results.map((result) => result.data.id) };
|
|
},
|
|
};
|