quasar-ui-danx 0.4.68 → 0.4.69

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.68",
3
+ "version": "0.4.69",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -1,7 +1,7 @@
1
1
  import { useDebounceFn } from "@vueuse/core";
2
2
  import { FaSolidCopy as CopyIcon, FaSolidPencil as EditIcon, FaSolidTrash as DeleteIcon } from "danx-icon";
3
3
  import { uid } from "quasar";
4
- import { h, isReactive, Ref, shallowReactive, shallowRef } from "vue";
4
+ import { h, Ref, shallowRef } from "vue";
5
5
  import { ConfirmActionDialog, CreateNewWithNameDialog } from "../components";
6
6
  import type {
7
7
  ActionGlobalOptions,
@@ -55,39 +55,27 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionGlobal
55
55
  */
56
56
  function getAction(actionName: string, actionOptions?: Partial<ActionOptions>): ResourceAction {
57
57
  /// Resolve the action options or resource action based on the provided input
58
- let resourceAction: Partial<ResourceAction> = actions.find(a => a.name === actionName) || { name: actionName };
59
-
60
- if (actionOptions) {
61
- Object.assign(resourceAction, actionOptions);
62
- }
58
+ const baseOptions: Partial<ResourceAction> = actions.find(a => a.name === actionName) || { name: actionName };
63
59
 
64
60
  // If the action is already reactive, return it
65
- if (!isReactive(resourceAction) || !("__type" in resourceAction)) {
66
- resourceAction = storeObject({
67
- onAction: globalOptions?.routes?.applyAction,
68
- onBatchAction: globalOptions?.routes?.batchAction,
69
- onBatchSuccess: globalOptions?.controls?.clearSelectedRows,
70
- ...globalOptions,
71
- ...resourceAction,
72
- isApplying: false,
73
- __type: "__Action:" + namespace
74
- });
75
-
76
- // Splice the resourceAction in place of the action in the actions list
77
- actions.splice(actions.findIndex(a => a.name === actionName), 1, resourceAction as ResourceAction);
78
- }
79
-
80
- // Return a clone of the action so it can be modified without affecting the original
81
- const clonedAction = shallowReactive({ ...resourceAction }) as ResourceAction;
61
+ const resourceAction = storeObject({
62
+ onAction: globalOptions?.routes?.applyAction,
63
+ onBatchAction: globalOptions?.routes?.batchAction,
64
+ onBatchSuccess: globalOptions?.controls?.clearSelectedRows,
65
+ ...baseOptions,
66
+ ...actionOptions,
67
+ isApplying: false,
68
+ __type: "__Action:" + namespace
69
+ }) as ResourceAction;
82
70
 
83
71
  // Assign Trigger function if it doesn't exist
84
- if (clonedAction.debounce) {
85
- clonedAction.trigger = useDebounceFn((target, input) => performAction(clonedAction, target, input), clonedAction.debounce);
72
+ if (resourceAction.debounce) {
73
+ resourceAction.trigger = useDebounceFn((target, input) => performAction(resourceAction, target, input), resourceAction.debounce);
86
74
  } else {
87
- clonedAction.trigger = (target, input) => performAction(clonedAction, target, input);
75
+ resourceAction.trigger = (target, input) => performAction(resourceAction, target, input);
88
76
  }
89
77
 
90
- return clonedAction;
78
+ return resourceAction;
91
79
  }
92
80
 
93
81
  /**
@@ -8,7 +8,7 @@ import { sleep } from "./utils";
8
8
  * to make GET and POST requests easier w/ JSON payloads
9
9
  */
10
10
  export const request: RequestApi = {
11
- abortControllers: {},
11
+ activeRequests: {},
12
12
 
13
13
  url(url) {
14
14
  if (url.startsWith("http")) {
@@ -19,20 +19,27 @@ export const request: RequestApi = {
19
19
 
20
20
  async call(url, options) {
21
21
  options = options || {};
22
- const abortKey = options?.abortOn !== undefined ? options.abortOn : url + JSON.stringify(options.params || "");
22
+ const requestKey = options?.requestKey || url + JSON.stringify(options.params || "");
23
+ const waitOnPrevious = !!options?.waitOnPrevious;
24
+ const shouldAbort = !waitOnPrevious;
23
25
  const timestamp = Date.now();
24
26
 
25
- if (abortKey) {
26
- const abort = new AbortController();
27
- const previousAbort = request.abortControllers[abortKey];
27
+ // If there was a request with the same key made that is still active, track that here
28
+ const previousRequest = request.activeRequests[requestKey];
29
+
30
+ // Set the current active request to this one
31
+ request.activeRequests[requestKey] = { timestamp };
32
+
33
+ if (shouldAbort) {
28
34
  // If there is already an abort controller set for this key, abort it
29
- if (previousAbort) {
30
- previousAbort.abort.abort("Request was aborted due to a newer request being made");
35
+ if (previousRequest) {
36
+ previousRequest.abortController?.abort("Request was aborted due to a newer request being made");
31
37
  }
32
38
 
39
+ const abortController = new AbortController();
33
40
  // Set the new abort controller for this key
34
- request.abortControllers[abortKey] = { abort, timestamp };
35
- options.signal = abort.signal;
41
+ request.activeRequests[requestKey].abortController = abortController;
42
+ options.signal = abortController.signal;
36
43
  }
37
44
 
38
45
  if (options.params) {
@@ -49,7 +56,14 @@ export const request: RequestApi = {
49
56
 
50
57
  let response = null;
51
58
  try {
52
- response = await fetch(request.url(url), options);
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) {
61
+ await previousRequest.requestPromise;
62
+ }
63
+
64
+ const requestPromise = fetch(request.url(url), options);
65
+ request.activeRequests[requestKey].requestPromise = requestPromise;
66
+ response = await requestPromise;
53
67
  } catch (e) {
54
68
  if (options.ignoreAbort && (e + "").match(/Request was aborted/)) {
55
69
  return { abort: true };
@@ -61,15 +75,18 @@ export const request: RequestApi = {
61
75
  checkAppVersion(response);
62
76
 
63
77
  // handle the case where the request was aborted too late, and we need to abort the response via timestamp check
64
- if (abortKey) {
78
+ if (shouldAbort) {
65
79
  // If the request was aborted too late, but there was still another request that was made after the current,
66
80
  // then abort the current request with an abort flag
67
- if (timestamp < request.abortControllers[abortKey].timestamp) {
81
+ if (timestamp < request.activeRequests[requestKey].timestamp) {
68
82
  return { abort: true };
69
83
  }
84
+ }
70
85
 
71
- // Otherwise, the current is the most recent request, so we can delete the abort controller
72
- delete request.abortControllers[abortKey];
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];
73
90
  }
74
91
 
75
92
  const result = await response.json();
@@ -56,7 +56,7 @@ export function useActionRoutes(baseUrl: string, extend?: object): ListControlsR
56
56
  async applyAction(action, target, data, options?) {
57
57
  options = {
58
58
  ...options,
59
- ignoreAbort: true,
59
+ waitOnPrevious: true,
60
60
  headers: {
61
61
  ...options?.headers,
62
62
  "X-Timestamp": Date.now().toString()
@@ -86,7 +86,7 @@ export function useActionRoutes(baseUrl: string, extend?: object): ListControlsR
86
86
  batchAction(action, targets, data, options?) {
87
87
  options = {
88
88
  ...options,
89
- ignoreAbort: true
89
+ waitOnPrevious: true
90
90
  };
91
91
  return request.post(`${baseUrl}/batch-action`, { action, filter: { id: targets.map(r => r.id) }, data }, options);
92
92
  },
@@ -1,7 +1,9 @@
1
1
  import { AnyObject } from "./shared";
2
2
 
3
3
  export interface RequestApi {
4
- abortControllers: { [key: string]: { abort: AbortController, timestamp: number } };
4
+ activeRequests: {
5
+ [key: string]: { requestPromise?: Promise<any>, abortController?: AbortController, timestamp: number }
6
+ };
5
7
 
6
8
  url(url: string): string;
7
9
 
@@ -30,7 +32,8 @@ export interface RequestOptions {
30
32
  }
31
33
 
32
34
  export interface RequestCallOptions extends RequestInit {
33
- abortOn?: string;
35
+ requestKey?: string;
36
+ waitOnPrevious?: boolean;
34
37
  ignoreAbort?: boolean;
35
38
  params?: AnyObject;
36
39
  }