Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/resources/scripts/api/http.ts
7460 views
1
import axios, { AxiosInstance } from 'axios';
2
import { store } from '@/state';
3
4
const http: AxiosInstance = axios.create({
5
withCredentials: true,
6
timeout: 20000,
7
headers: {
8
'X-Requested-With': 'XMLHttpRequest',
9
Accept: 'application/json',
10
'Content-Type': 'application/json',
11
},
12
});
13
14
http.interceptors.request.use((req) => {
15
if (!req.url?.endsWith('/resources')) {
16
store.getActions().progress.startContinuous();
17
}
18
19
return req;
20
});
21
22
http.interceptors.response.use(
23
(resp) => {
24
if (!resp.request?.url?.endsWith('/resources')) {
25
store.getActions().progress.setComplete();
26
}
27
28
return resp;
29
},
30
(error) => {
31
store.getActions().progress.setComplete();
32
33
throw error;
34
}
35
);
36
37
export default http;
38
39
/**
40
* Converts an error into a human readable response. Mostly just a generic helper to
41
* make sure we display the message from the server back to the user if we can.
42
*/
43
export function httpErrorToHuman(error: any): string {
44
if (error.response && error.response.data) {
45
let { data } = error.response;
46
47
// Some non-JSON requests can still return the error as a JSON block. In those cases, attempt
48
// to parse it into JSON so we can display an actual error.
49
if (typeof data === 'string') {
50
try {
51
data = JSON.parse(data);
52
} catch (e) {
53
// do nothing, bad json
54
}
55
}
56
57
if (data.errors && data.errors[0] && data.errors[0].detail) {
58
return data.errors[0].detail;
59
}
60
61
// Errors from wings directory, mostly just for file uploads.
62
if (data.error && typeof data.error === 'string') {
63
return data.error;
64
}
65
}
66
67
return error.message;
68
}
69
70
export interface FractalResponseData {
71
object: string;
72
attributes: {
73
[k: string]: any;
74
relationships?: Record<string, FractalResponseData | FractalResponseList | null | undefined>;
75
};
76
}
77
78
export interface FractalResponseList {
79
object: 'list';
80
data: FractalResponseData[];
81
}
82
83
export interface FractalPaginatedResponse extends FractalResponseList {
84
meta: {
85
pagination: {
86
total: number;
87
count: number;
88
/* eslint-disable camelcase */
89
per_page: number;
90
current_page: number;
91
total_pages: number;
92
/* eslint-enable camelcase */
93
};
94
};
95
}
96
97
export interface PaginatedResult<T> {
98
items: T[];
99
pagination: PaginationDataSet;
100
}
101
102
export interface PaginationDataSet {
103
total: number;
104
count: number;
105
perPage: number;
106
currentPage: number;
107
totalPages: number;
108
}
109
110
export function getPaginationSet(data: any): PaginationDataSet {
111
return {
112
total: data.total,
113
count: data.count,
114
perPage: data.per_page,
115
currentPage: data.current_page,
116
totalPages: data.total_pages,
117
};
118
}
119
120
type QueryBuilderFilterValue = string | number | boolean | null;
121
122
export interface QueryBuilderParams<FilterKeys extends string = string, SortKeys extends string = string> {
123
page?: number;
124
filters?: {
125
[K in FilterKeys]?: QueryBuilderFilterValue | Readonly<QueryBuilderFilterValue[]>;
126
};
127
sorts?: {
128
[K in SortKeys]?: -1 | 0 | 1 | 'asc' | 'desc' | null;
129
};
130
}
131
132
/**
133
* Helper function that parses a data object provided and builds query parameters
134
* for the Laravel Query Builder package automatically. This will apply sorts and
135
* filters deterministically based on the provided values.
136
*/
137
export const withQueryBuilderParams = (data?: QueryBuilderParams): Record<string, unknown> => {
138
if (!data) return {};
139
140
const filters = Object.keys(data.filters || {}).reduce((obj, key) => {
141
const value = data.filters?.[key];
142
143
return !value || value === '' ? obj : { ...obj, [`filter[${key}]`]: value };
144
}, {} as NonNullable<QueryBuilderParams['filters']>);
145
146
const sorts = Object.keys(data.sorts || {}).reduce((arr, key) => {
147
const value = data.sorts?.[key];
148
if (!value || !['asc', 'desc', 1, -1].includes(value)) {
149
return arr;
150
}
151
152
return [...arr, (value === -1 || value === 'desc' ? '-' : '') + key];
153
}, [] as string[]);
154
155
return {
156
...filters,
157
sort: !sorts.length ? undefined : sorts.join(','),
158
page: data.page,
159
};
160
};
161
162