quasar-ui-danx 0.4.69 → 0.4.71

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.4.69",
3
+ "version": "0.4.71",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  import { Ref } from "vue";
2
2
  import { danxOptions } from "../config";
3
- import { HttpResponse, RequestApi } from "../types";
3
+ import { ActiveRequest, HttpResponse, RequestApi } from "../types";
4
4
  import { sleep } from "./utils";
5
5
 
6
6
  /**
@@ -21,16 +21,18 @@ export const request: RequestApi = {
21
21
  options = options || {};
22
22
  const requestKey = options?.requestKey || url + JSON.stringify(options.params || "");
23
23
  const waitOnPrevious = !!options?.waitOnPrevious;
24
- const shouldAbort = !waitOnPrevious;
24
+ const useMostRecentResponse = !!options?.useMostRecentResponse;
25
+ const shouldAbortPrevious = !waitOnPrevious;
25
26
  const timestamp = Date.now();
26
27
 
27
28
  // If there was a request with the same key made that is still active, track that here
28
29
  const previousRequest = request.activeRequests[requestKey];
29
30
 
30
31
  // Set the current active request to this one
31
- request.activeRequests[requestKey] = { timestamp };
32
+ const currentRequest: ActiveRequest = { timestamp };
33
+ request.activeRequests[requestKey] = currentRequest;
32
34
 
33
- if (shouldAbort) {
35
+ if (shouldAbortPrevious) {
34
36
  // If there is already an abort controller set for this key, abort it
35
37
  if (previousRequest) {
36
38
  previousRequest.abortController?.abort("Request was aborted due to a newer request being made");
@@ -38,7 +40,7 @@ export const request: RequestApi = {
38
40
 
39
41
  const abortController = new AbortController();
40
42
  // Set the new abort controller for this key
41
- request.activeRequests[requestKey].abortController = abortController;
43
+ currentRequest.abortController = abortController;
42
44
  options.signal = abortController.signal;
43
45
  }
44
46
 
@@ -54,59 +56,85 @@ export const request: RequestApi = {
54
56
  delete options.params;
55
57
  }
56
58
 
57
- let response = null;
58
- try {
59
- // If there is a previous request still active, wait for it to finish before proceeding (if the waitForPrevious flag is set)
60
- if (waitOnPrevious && previousRequest?.requestPromise) {
59
+ let resolvePromise!: (value: any) => any;
60
+ let rejectPromise!: (reason?: any) => any;
61
+ currentRequest.requestPromise = new Promise((resolve, reject) => {
62
+ resolvePromise = resolve;
63
+ rejectPromise = reject;
64
+ });
65
+
66
+ // If there is a previous request still active, wait for it to finish before proceeding (if the waitForPrevious flag is set)
67
+ if (waitOnPrevious && previousRequest?.requestPromise) {
68
+ try {
61
69
  await previousRequest.requestPromise;
70
+ } catch (e) {
71
+ // We don't care if it fails, we just need to wait for it to complete
62
72
  }
73
+ }
63
74
 
64
- const requestPromise = fetch(request.url(url), options);
65
- request.activeRequests[requestKey].requestPromise = requestPromise;
66
- response = await requestPromise;
75
+ // Wait to finish the request before proceeding
76
+ let response: Response;
77
+ try {
78
+ response = await fetch(request.url(url), options);
67
79
  } catch (e) {
68
80
  if (options.ignoreAbort && (e + "").match(/Request was aborted/)) {
69
- return { abort: true };
81
+ const abortResponse = { abort: true };
82
+ resolvePromise(abortResponse);
83
+ return abortResponse;
70
84
  }
85
+ rejectPromise(e);
71
86
  throw e;
72
87
  }
73
88
 
74
89
  // Verify the app version of the client and server are matching
75
90
  checkAppVersion(response);
76
91
 
77
- // handle the case where the request was aborted too late, and we need to abort the response via timestamp check
78
- if (shouldAbort) {
79
- // If the request was aborted too late, but there was still another request that was made after the current,
80
- // then abort the current request with an abort flag
81
- if (timestamp < request.activeRequests[requestKey].timestamp) {
82
- return { abort: true };
92
+ // Track the most recent request (maybe another request with the same key was made after this request started)
93
+ let mostRecentRequest = request.activeRequests[requestKey];
94
+
95
+ // Always fetch the result
96
+ let responseJson = await response.json();
97
+
98
+ // Send the real JSON response to the promise in case other requests are waiting on this request result
99
+ resolvePromise(responseJson);
100
+
101
+ // If this request is not the most recent request...
102
+ if (mostRecentRequest.timestamp !== timestamp) {
103
+ // and it should be aborted but was aborted too late, return an aborted response
104
+ if (shouldAbortPrevious) {
105
+ responseJson = { abort: true };
106
+ } else if (useMostRecentResponse) {
107
+ // or if there is a more recent request, and the useMoreRecentResponse flag is set, update this response to the more recent one
108
+ do {
109
+ // Always update on each iteration to make sure we're checking the current most recent
110
+ // (maybe additional requests will be made before the current most recent finishes)
111
+ mostRecentRequest = request.activeRequests[requestKey];
112
+ responseJson = await mostRecentRequest.requestPromise;
113
+
114
+ // If the most recent request is the same as this one, break out of the loop
115
+ if (request.activeRequests[requestKey].timestamp === mostRecentRequest.timestamp) {
116
+ break;
117
+ }
118
+ } while (mostRecentRequest.timestamp !== request.activeRequests[requestKey].timestamp);
83
119
  }
84
120
  }
85
121
 
86
- // If this request is the active request for the requestKey, we can clear this key from active requests
87
- if (request.activeRequests[requestKey].timestamp === timestamp) {
88
- // Remove the request from the active requests list
89
- delete request.activeRequests[requestKey];
90
- }
91
-
92
- const result = await response.json();
93
-
94
122
  if (response.status === 401) {
95
123
  const onUnauthorized = danxOptions.value.request?.onUnauthorized;
96
- return onUnauthorized ? onUnauthorized(result, response) : {
124
+ return onUnauthorized ? onUnauthorized(responseJson, response) : {
97
125
  error: true,
98
126
  message: "Unauthorized",
99
- ...result
127
+ ...responseJson
100
128
  };
101
129
  }
102
130
 
103
131
  if (response.status > 400) {
104
- if (result.exception && !result.error) {
105
- result.error = true;
132
+ if (responseJson.exception && !responseJson.error) {
133
+ responseJson.error = true;
106
134
  }
107
135
  }
108
136
 
109
- return result;
137
+ return responseJson;
110
138
  },
111
139
 
112
140
  async poll(url: string, options, interval, fnUntil) {
@@ -57,6 +57,7 @@ export function useActionRoutes(baseUrl: string, extend?: object): ListControlsR
57
57
  options = {
58
58
  ...options,
59
59
  waitOnPrevious: true,
60
+ useMostRecentResponse: true,
60
61
  headers: {
61
62
  ...options?.headers,
62
63
  "X-Timestamp": Date.now().toString()
@@ -1,8 +1,14 @@
1
1
  import { AnyObject } from "./shared";
2
2
 
3
+ export interface ActiveRequest {
4
+ requestPromise?: Promise<any>,
5
+ abortController?: AbortController,
6
+ timestamp: number
7
+ }
8
+
3
9
  export interface RequestApi {
4
10
  activeRequests: {
5
- [key: string]: { requestPromise?: Promise<any>, abortController?: AbortController, timestamp: number }
11
+ [key: string]: ActiveRequest
6
12
  };
7
13
 
8
14
  url(url: string): string;
@@ -34,6 +40,7 @@ export interface RequestOptions {
34
40
  export interface RequestCallOptions extends RequestInit {
35
41
  requestKey?: string;
36
42
  waitOnPrevious?: boolean;
43
+ useMostRecentResponse?: boolean;
37
44
  ignoreAbort?: boolean;
38
45
  params?: AnyObject;
39
46
  }