datastake-daf 0.6.487 → 0.6.489
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/index.js +119 -38
- package/dist/services/index.js +6338 -0
- package/dist/utils/index.js +297 -0
- package/package.json +1 -1
- package/rollup.config.js +20 -0
- package/src/@daf/core/components/Dashboard/ComponentWithFocus/HoverFocus/index.jsx +114 -0
- package/src/@daf/core/components/Dashboard/ComponentWithFocus/index.jsx +1 -1
- package/src/@daf/services/BaseHTTPService.js +229 -0
- package/src/@daf/services/ErrorHandler.js +43 -0
- package/src/helpers/StringHelper.js +12 -1
- package/src/helpers/errorHandling.js +97 -0
- package/src/helpers/urlHelpers.js +36 -0
- package/src/index.js +1 -0
- package/src/services.js +2 -0
- package/src/utils.js +9 -2
- package/dist/style/datastake/mapbox-gl.css +0 -330
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { cleanJSON } from '../../helpers/StringHelper.js';
|
|
3
|
+
import { assignParamsToUrl } from '../../helpers/urlHelpers.js';
|
|
4
|
+
import { getToken } from '../../helpers/Token.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base HTTP Service Class
|
|
8
|
+
* Provides axios wrapper with token management, cancel tokens, and interceptors
|
|
9
|
+
*/
|
|
10
|
+
export class BaseHTTPService {
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
const {getHeaders, getBaseURL, onError, timeout = 300000, customAxiosConfig = {}} = config;
|
|
13
|
+
|
|
14
|
+
this.getToken = getToken || (() => null);
|
|
15
|
+
this.getHeaders = getHeaders || (() => ({}));
|
|
16
|
+
this.getBaseURL = getBaseURL || (() => null);
|
|
17
|
+
this.onError = onError || (() => null);
|
|
18
|
+
this.cleanJSON = cleanJSON;
|
|
19
|
+
this.timeout = timeout;
|
|
20
|
+
this.customAxiosConfig = customAxiosConfig;
|
|
21
|
+
|
|
22
|
+
// Init
|
|
23
|
+
this.cancelToken = {}
|
|
24
|
+
this.token = this.getToken();
|
|
25
|
+
|
|
26
|
+
this.setupAxios();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setupAxios() {
|
|
30
|
+
const headers = {
|
|
31
|
+
Authorization: `Bearer ${this.token}`,
|
|
32
|
+
...this.getHeaders(),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
this.api = axios.create({
|
|
36
|
+
baseURL: this.getBaseURL(),
|
|
37
|
+
headers,
|
|
38
|
+
timeout: this.timeout,
|
|
39
|
+
...this.customAxiosConfig,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.setupInterceptors();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setupInterceptors() {
|
|
46
|
+
this.api.interceptors.response.use((response) => response,
|
|
47
|
+
(error) => Promise.reject(error)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Request interceptor - clean JSON data
|
|
51
|
+
this.api.interceptors.request.use(
|
|
52
|
+
(config) => {
|
|
53
|
+
if (['post', 'put', 'patch'].includes(config.method)) {
|
|
54
|
+
config.data = this.cleanJSON(config.data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return config;
|
|
58
|
+
},
|
|
59
|
+
(error) => Promise.reject(error)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
reloadAxios() {
|
|
64
|
+
const token = this.getToken();
|
|
65
|
+
this.token = token;
|
|
66
|
+
|
|
67
|
+
const options = {
|
|
68
|
+
baseURL: this.getBaseURL(),
|
|
69
|
+
timeout: this.timeout,
|
|
70
|
+
...this.customAxiosConfig,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (token) {
|
|
74
|
+
options.headers = {
|
|
75
|
+
Authorization: `Bearer ${token}`,
|
|
76
|
+
...this.getHeaders(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.api = axios.create(options);
|
|
81
|
+
this.setupInterceptors();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async formatResponse(call) {
|
|
85
|
+
try {
|
|
86
|
+
const res = await call;
|
|
87
|
+
const { data, status, statusText } = res || {};
|
|
88
|
+
this.cancelToken = {};
|
|
89
|
+
return { data, status, statusText };
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return Promise.reject(error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
apiPost(options) {
|
|
96
|
+
// Check if there are any previous pending requests
|
|
97
|
+
if (typeof this.cancelToken[options.url] != typeof undefined) {
|
|
98
|
+
try {
|
|
99
|
+
this.cancelToken[options.url].cancel("Operation canceled due to new request.");
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.log(e);
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.cancelToken[options.url] = axios.CancelToken.source();
|
|
107
|
+
const token = this.getToken();
|
|
108
|
+
|
|
109
|
+
if (token !== this.token || !token) {
|
|
110
|
+
this.reloadAxios();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return this.formatResponse(
|
|
114
|
+
this.api.post(options.url, options.data, {
|
|
115
|
+
baseURL: options.baseURL || this.getBaseURL(options),
|
|
116
|
+
cancelToken: this.cancelToken[options.url].token,
|
|
117
|
+
headers: {
|
|
118
|
+
Authorization: `Bearer ${this.getToken()}`,
|
|
119
|
+
...this.getHeaders(),
|
|
120
|
+
...(options?.headers || {}),
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
.catch((err) => this.onError(err))
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
apiGet(options) {
|
|
128
|
+
const token = this.getToken();
|
|
129
|
+
|
|
130
|
+
if (token !== this.token || !token) {
|
|
131
|
+
this.reloadAxios();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { url, ...config } = options;
|
|
135
|
+
|
|
136
|
+
return this.formatResponse(
|
|
137
|
+
this.api.get(url, {
|
|
138
|
+
...config,
|
|
139
|
+
baseURL: options.baseURL || this.getBaseURL(options),
|
|
140
|
+
headers: {
|
|
141
|
+
Authorization: `Bearer ${this.getToken()}`,
|
|
142
|
+
...this.getHeaders(),
|
|
143
|
+
...(config?.headers || {}),
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
.catch((err) => this.onError(err))
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
apiDelete(options) {
|
|
151
|
+
const token = this.getToken();
|
|
152
|
+
|
|
153
|
+
if (token !== this.token || !token) {
|
|
154
|
+
this.reloadAxios();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const { url, ...config } = options;
|
|
158
|
+
|
|
159
|
+
return this.formatResponse(
|
|
160
|
+
this.api.delete(url, {
|
|
161
|
+
...config,
|
|
162
|
+
baseURL: options.baseURL || this.getBaseURL(options),
|
|
163
|
+
headers: {
|
|
164
|
+
Authorization: `Bearer ${this.getToken()}`,
|
|
165
|
+
...this.getHeaders(),
|
|
166
|
+
...(config?.headers || {}),
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
.catch((err) => this.onError(err))
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
apiPut(options) {
|
|
174
|
+
if (typeof this.cancelToken[options.url] != typeof undefined) {
|
|
175
|
+
try {
|
|
176
|
+
this.cancelToken[options.url].cancel("Operation canceled due to new request.");
|
|
177
|
+
} catch (e) {
|
|
178
|
+
console.log(e);
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this.cancelToken[options.url] = axios.CancelToken.source();
|
|
184
|
+
const token = this.getToken();
|
|
185
|
+
|
|
186
|
+
if (token !== this.token || !token) {
|
|
187
|
+
this.reloadAxios();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return this.formatResponse(
|
|
191
|
+
this.api.put(options.url, options.data, {
|
|
192
|
+
cancelToken: this.cancelToken[options.url].token,
|
|
193
|
+
baseURL: options.baseURL || this.getBaseURL(options),
|
|
194
|
+
headers: {
|
|
195
|
+
Authorization: `Bearer ${this.getToken()}`,
|
|
196
|
+
...this.getHeaders(),
|
|
197
|
+
...(options?.headers || {}),
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
.catch((err) => this.onError(err, options.onUnauthorized))
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
apiPatch(options) {
|
|
205
|
+
const token = this.getToken();
|
|
206
|
+
|
|
207
|
+
if (token !== this.token || !token) {
|
|
208
|
+
this.reloadAxios();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return this.formatResponse(
|
|
212
|
+
this.api.patch(options.url, options.data, {
|
|
213
|
+
baseURL: options.baseURL || this.getBaseURL(options),
|
|
214
|
+
headers: {
|
|
215
|
+
Authorization: `Bearer ${this.getToken()}`,
|
|
216
|
+
...this.getHeaders(),
|
|
217
|
+
...(options?.headers || {}),
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
.catch((err) => this.onError(err))
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
// Utility method
|
|
226
|
+
assignParamsToUrl(path, params) {
|
|
227
|
+
return assignParamsToUrl(path, params);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export class ErrorHandler {
|
|
2
|
+
constructor(config = {}) {
|
|
3
|
+
this.store = config.store;
|
|
4
|
+
this.addToastAction = config.addToastAction;
|
|
5
|
+
this.formatData = config.formatData || this.defaultFormatData;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
handle({stats, statusText, data}) {
|
|
9
|
+
if(this.store && this.addToastAction) {
|
|
10
|
+
this.store.dispatch(this.addToastAction({
|
|
11
|
+
title: statusText,
|
|
12
|
+
type: 'danger',
|
|
13
|
+
body: this.formatData(data),
|
|
14
|
+
}));
|
|
15
|
+
} else {
|
|
16
|
+
console.error('Error: ', {stats, statusText, data});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
defaultFormatData(errors) {
|
|
21
|
+
if (!Array.isArray(errors)) {
|
|
22
|
+
return String(errors);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const e = [];
|
|
26
|
+
errors.forEach(error => {
|
|
27
|
+
if (error && typeof error === 'object' && error.constraints) {
|
|
28
|
+
Object.keys(error.constraints)
|
|
29
|
+
.forEach(key => e.push(error.constraints[key]));
|
|
30
|
+
} else if (typeof error === 'string') {
|
|
31
|
+
e.push(error);
|
|
32
|
+
} else {
|
|
33
|
+
e.push(JSON.stringify(error));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return e.join('\n');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static createInstance(config) {
|
|
41
|
+
return new ErrorHandler(config);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -202,4 +202,15 @@ export const safeJsonParse = (value, fallback = value) => {
|
|
|
202
202
|
console.warn('Failed to parse JSON:', value);
|
|
203
203
|
return fallback;
|
|
204
204
|
}
|
|
205
|
-
};
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const cleanJSON = (json) => {
|
|
208
|
+
for (let key in json) {
|
|
209
|
+
if (json[key] === undefined) {
|
|
210
|
+
json[key] = null;
|
|
211
|
+
} /*else if (typeof json[key] === 'object')
|
|
212
|
+
json[key] = cleanJSON(json[key]);
|
|
213
|
+
*/
|
|
214
|
+
}
|
|
215
|
+
return json;
|
|
216
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { message } from 'antd';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generic error handler factory for axios requests
|
|
5
|
+
* Highly configurable to adapt to different project needs
|
|
6
|
+
*/
|
|
7
|
+
export const createErrorHandler = (config = {}) => {
|
|
8
|
+
const {
|
|
9
|
+
onUnauthorized,
|
|
10
|
+
handleError,
|
|
11
|
+
getStorageManager,
|
|
12
|
+
checkTokenValidity = true,
|
|
13
|
+
unauthorizedRedirect = '/',
|
|
14
|
+
tokenStorageKey = 'token',
|
|
15
|
+
handleNetworkError = true,
|
|
16
|
+
} = config;
|
|
17
|
+
|
|
18
|
+
return (error, customOnUnauthorized) => {
|
|
19
|
+
// Handle cases where error.response doesn't exist (network errors)
|
|
20
|
+
if (!error.response) {
|
|
21
|
+
if (handleNetworkError && handleError) {
|
|
22
|
+
handleError({
|
|
23
|
+
status: 0,
|
|
24
|
+
statusText: "Network Error",
|
|
25
|
+
data: ["Please check your internet connection."],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return Promise.reject(error);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { status, statusText, data: { errors, message } = {} } = error.response || { data: {} };
|
|
32
|
+
|
|
33
|
+
// Handle 401 Unauthorized
|
|
34
|
+
if (status === 401) {
|
|
35
|
+
if (checkTokenValidity && getStorageManager) {
|
|
36
|
+
const token = getStorageManager().get(tokenStorageKey);
|
|
37
|
+
if (token) {
|
|
38
|
+
if (typeof customOnUnauthorized === 'function') {
|
|
39
|
+
customOnUnauthorized();
|
|
40
|
+
} else if (typeof onUnauthorized === 'function') {
|
|
41
|
+
onUnauthorized();
|
|
42
|
+
} else {
|
|
43
|
+
getStorageManager().clearOne(tokenStorageKey);
|
|
44
|
+
if (typeof window !== 'undefined') {
|
|
45
|
+
window.location.href = unauthorizedRedirect;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Handle 4xx and 5xx errors
|
|
53
|
+
if (status >= 400 && status <= 500) {
|
|
54
|
+
if (handleError) {
|
|
55
|
+
handleError({
|
|
56
|
+
status,
|
|
57
|
+
statusText: message || statusText,
|
|
58
|
+
data: errors || []
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return Promise.reject(error);
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Simple error handler using antd message component
|
|
69
|
+
* Useful for quick error notifications
|
|
70
|
+
*/
|
|
71
|
+
export const handleError = (err) => {
|
|
72
|
+
const errorMessage = err?.response?.data?.message ||
|
|
73
|
+
err?.message ||
|
|
74
|
+
'An error occurred';
|
|
75
|
+
message.error(errorMessage);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Success message handler
|
|
80
|
+
*/
|
|
81
|
+
export const handleSuccess = (msg) => {
|
|
82
|
+
message.success(msg || 'Operation successful');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Warning message handler
|
|
87
|
+
*/
|
|
88
|
+
export const handleWarning = (msg) => {
|
|
89
|
+
message.warning(msg || 'Warning');
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Info message handler
|
|
94
|
+
*/
|
|
95
|
+
export const handleInfo = (msg) => {
|
|
96
|
+
message.info(msg);
|
|
97
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for URL manipulation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Assigns parameters to URL path
|
|
7
|
+
* Example: assignParamsToUrl('/users/{id}/posts/{postId}', { id: 1, postId: 2 })
|
|
8
|
+
* Returns: '/users/1/posts/2'
|
|
9
|
+
*/
|
|
10
|
+
export const assignParamsToUrl = (path, params) => {
|
|
11
|
+
let paramsPath = path;
|
|
12
|
+
const matches = path.match(/\{\w+\}/gm);
|
|
13
|
+
|
|
14
|
+
if (matches) {
|
|
15
|
+
for (let param of matches) {
|
|
16
|
+
const key = param.match(/\w+/)[0];
|
|
17
|
+
paramsPath = paramsPath.replace(/\{\w+\}/, params[key]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return paramsPath;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build query string from object
|
|
26
|
+
* Example: buildQueryString({ page: 1, limit: 10 })
|
|
27
|
+
* Returns: '?page=1&limit=10'
|
|
28
|
+
*/
|
|
29
|
+
export const buildQueryString = (params) => {
|
|
30
|
+
const query = Object.keys(params)
|
|
31
|
+
.filter(key => params[key] !== null && params[key] !== undefined)
|
|
32
|
+
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
|
|
33
|
+
.join('&');
|
|
34
|
+
|
|
35
|
+
return query ? `?${query}` : '';
|
|
36
|
+
};
|
package/src/index.js
CHANGED
|
@@ -71,6 +71,7 @@ export { default as KeyIndicatorsDetails } from "./@daf/core/components/Dashboar
|
|
|
71
71
|
export { default as DetailsSection } from "./@daf/core/components/Dashboard/Widget/DetailsSection/index.jsx";
|
|
72
72
|
export { default as SDGWidget } from "./@daf/core/components/Dashboard/Widget/SDGWidget/index.jsx";
|
|
73
73
|
export { default as ComponentWithFocus } from "./@daf/core/components/Dashboard/ComponentWithFocus/index.jsx";
|
|
74
|
+
export { default as ComponentWithHoverFocus } from "./@daf/core/components/Dashboard/ComponentWithFocus/HoverFocus/index.jsx";
|
|
74
75
|
export { default as ProjectWidget } from "./@daf/core/components/Dashboard/Widget/ProjectWidget/index.jsx";
|
|
75
76
|
export { default as WidgetCard } from "./@daf/core/components/Dashboard/Widget/WidgetCard/index.js";
|
|
76
77
|
export { default as CarouselWidget } from "./@daf/core/components/Dashboard/Widget/CarouselWidget/index.jsx";
|
package/src/services.js
ADDED
package/src/utils.js
CHANGED
|
@@ -9,7 +9,7 @@ export { renderTooltip, renderTooltipJsx } from './@daf/utils/tooltip'
|
|
|
9
9
|
export { getRangeOfTicks } from './helpers/chart'
|
|
10
10
|
|
|
11
11
|
export { propHasValue } from './helpers/deepFind'
|
|
12
|
-
export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse } from './helpers/StringHelper'
|
|
12
|
+
export { isEmptyOrSpaces, capitalizeAll, capitalize, camelCaseToTitle, snakeCaseToTitleCase, titleToCamelCase, findOptions, getOptionAsObject, nowToIso, renderTemplateString, renderTemplateStringInObject, truncateString, splitStringInMultipleLines, safeJsonParse, cleanJSON } from './helpers/StringHelper'
|
|
13
13
|
export { getNkey, groupSubsections, getImageUploadViewValue } from './@daf/core/components/ViewForm/helper'
|
|
14
14
|
export { renderRows } from './@daf/core/components/Table/helper'
|
|
15
15
|
export { filterOptions, filterString, hasNotChanged, filterSelectOptions, mapSubGroupsInSubmit, mapSubGroupsInGet, filterCreateData, changeInputMeta, renderDateFormatted } from './helpers/Forms'
|
|
@@ -39,4 +39,11 @@ export { captureElementsAsImages, captureComponentsAsImages } from './helpers/co
|
|
|
39
39
|
|
|
40
40
|
export { createDocument } from './@daf/core/components/Document/WordDocument/createDocument.js'
|
|
41
41
|
|
|
42
|
-
export { processConfig, fetchImageAsBuffer } from './helpers/docHelper.js'
|
|
42
|
+
export { processConfig, fetchImageAsBuffer } from './helpers/docHelper.js'
|
|
43
|
+
|
|
44
|
+
export { getToken } from './helpers/Token.js';
|
|
45
|
+
export { StorageManager } from './helpers/StorageManager.js';
|
|
46
|
+
|
|
47
|
+
export { assignParamsToUrl, buildQueryString } from './helpers/urlHelpers.js';
|
|
48
|
+
|
|
49
|
+
export { createErrorHandler, handleError, handleSuccess, handleWarning, handleInfo } from './helpers/errorHandling.js';
|