quasar-ui-danx 0.3.47 → 0.3.49

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.
@@ -3,31 +3,31 @@ import { Ref, shallowRef, VNode } from "vue";
3
3
  import { FlashMessages } from "./FlashMessages";
4
4
 
5
5
  export type ActionTargetItem = {
6
- id: number | string;
7
- isSaving: Ref<boolean>;
8
- [key: string]: any;
6
+ id: number | string;
7
+ isSaving: Ref<boolean>;
8
+ [key: string]: any;
9
9
  };
10
10
  export type ActionTarget = ActionTargetItem[] | ActionTargetItem;
11
11
 
12
12
  export interface ActionOptions {
13
- name?: string;
14
- label?: string;
15
- menu?: boolean;
16
- batch?: boolean;
17
- category?: string;
18
- class?: string;
19
- debounce?: number;
20
- trigger?: (target: ActionTarget, input: any) => Promise<any>;
21
- vnode?: (target: ActionTarget) => VNode;
22
- enabled?: (target: object) => boolean;
23
- batchEnabled?: (targets: object[]) => boolean;
24
- optimistic?: (action: ActionOptions, target: object, input: any) => void;
25
- onAction?: (action: string | null | undefined, target: object, input: any) => Promise<any>;
26
- onBatchAction?: (action: string | null | undefined, targets: object[], input: any) => Promise<any>;
27
- onStart?: (action: ActionOptions | null, targets: ActionTarget, input: any) => boolean;
28
- onSuccess?: (result: any, targets: ActionTarget, input: any) => any;
29
- onError?: (result: any, targets: ActionTarget, input: any) => any;
30
- onFinish?: (result: any, targets: ActionTarget, input: any) => any;
13
+ name?: string;
14
+ label?: string;
15
+ menu?: boolean;
16
+ batch?: boolean;
17
+ category?: string;
18
+ class?: string;
19
+ debounce?: number;
20
+ trigger?: (target: ActionTarget, input: any) => Promise<any>;
21
+ vnode?: (target: ActionTarget) => VNode;
22
+ enabled?: (target: object) => boolean;
23
+ batchEnabled?: (targets: object[]) => boolean;
24
+ optimistic?: (action: ActionOptions, target: object, input: any) => void;
25
+ onAction?: (action: string | null | undefined, target: object, input: any) => Promise<any>;
26
+ onBatchAction?: (action: string | null | undefined, targets: object[], input: any) => Promise<any>;
27
+ onStart?: (action: ActionOptions | null, targets: ActionTarget, input: any) => boolean;
28
+ onSuccess?: (result: any, targets: ActionTarget, input: any) => any;
29
+ onError?: (result: any, targets: ActionTarget, input: any) => any;
30
+ onFinish?: (result: any, targets: ActionTarget, input: any) => any;
31
31
  }
32
32
 
33
33
  export const activeActionVnode: Ref = shallowRef(null);
@@ -40,173 +40,173 @@ export const activeActionVnode: Ref = shallowRef(null);
40
40
  * @param {ActionOptions | null} globalOptions
41
41
  */
42
42
  export function useActions(actions: ActionOptions[], globalOptions: ActionOptions | null = null) {
43
- const mappedActions = actions.map(action => {
44
- const mappedAction: ActionOptions = { ...globalOptions, ...action };
45
- if (mappedAction.debounce) {
46
- mappedAction.trigger = useDebounceFn((target, input) => performAction(mappedAction, target, input, true), mappedAction.debounce);
47
- } else if (!mappedAction.trigger) {
48
- mappedAction.trigger = (target, input) => performAction(mappedAction, target, input, true);
49
- }
50
- return mappedAction;
51
- });
52
-
53
- /**
54
- * Set the reactive saving state of a target
55
- */
56
- function setTargetSavingState(target: ActionTarget, saving: boolean) {
57
- if (Array.isArray(target)) {
58
- for (const t of target) {
59
- t.isSaving.value = saving;
60
- }
61
- } else {
62
- target.isSaving.value = saving;
63
- }
64
- }
65
-
66
- /**
67
- * Perform an action on a set of targets
68
- *
69
- * @param {string} name - can either be a string or an action object
70
- * @param {object[]|object} target - an array of targets or a single target object
71
- * @param {any} input - The input data to pass to the action handler
72
- * @param isTriggered - Whether the action was triggered by a trigger function
73
- */
74
- async function performAction(name: string | object, target: ActionTarget, input: any = null, isTriggered = false) {
75
- const action: ActionOptions | null | undefined = typeof name === "string" ? mappedActions.find(a => a.name === name) : name;
76
- if (!action) {
77
- throw new Error(`Unknown action: ${name}`);
78
- }
79
-
80
- // We always want to call the trigger function if it exists, unless it's already been triggered
81
- // This provides behavior like debounce and custom action resolution
82
- if (action.trigger && !isTriggered) {
83
- return action.trigger(target, input);
84
- }
85
-
86
- const vnode = action.vnode && action.vnode(target);
87
- let result: any;
88
-
89
- // Run the onStart handler if it exists and quit the operation if it returns false
90
- if (action.onStart) {
91
- if (!action.onStart(action, target, input)) {
92
- return;
93
- }
94
- }
95
-
96
- setTargetSavingState(target, true);
97
-
98
- // If additional input is required, first render the vnode and wait for the confirm or cancel action
99
- if (vnode) {
100
- // If the action requires an input, we set the activeActionVnode to the input component.
101
- // This will tell the ActionVnode to render the input component, and confirm or cancel the
102
- // action The confirm function has the input from the component passed and will resolve the promise
103
- // with the result of the action
104
- result = await new Promise((resolve, reject) => {
105
- activeActionVnode.value = {
106
- vnode,
107
- confirm: async (confirmInput: any) => {
108
- const result = await onConfirmAction(action, target, { ...input, ...confirmInput });
109
-
110
- // Only resolve when we have a non-error response, so we can show the error message w/o
111
- // hiding the dialog / vnode
112
- if (result === undefined || result === true || result?.success) {
113
- resolve(result);
114
- }
115
- },
116
- cancel: resolve
117
- };
118
- });
119
-
120
- activeActionVnode.value = null;
121
- } else {
122
- result = await onConfirmAction(action, target, input);
123
- }
124
-
125
- setTargetSavingState(target, false);
126
-
127
- return result;
128
- }
129
-
130
- /**
131
- * Filter the list of actions based on the provided filters in key-value pairs
132
- * You can filter on any ActionOptions property by matching the value exactly or by providing an array of values
133
- *
134
- * @param filters
135
- * @returns {ActionOptions[]}
136
- */
137
- function filterActions(filters: object): ActionOptions[] {
138
- let filteredActions = [...mappedActions];
139
-
140
- for (const filter of Object.keys(filters)) {
141
- const filterValue = filters[filter];
142
- filteredActions = filteredActions.filter((a: object) => a[filter] === filterValue || (Array.isArray(filterValue) && filterValue.includes(a[filter])));
143
- }
144
- return filteredActions;
145
- }
146
-
147
- return {
148
- actions: mappedActions,
149
- filterActions,
150
- performAction
151
- };
43
+ const mappedActions = actions.map(action => {
44
+ const mappedAction: ActionOptions = { ...globalOptions, ...action };
45
+ if (mappedAction.debounce) {
46
+ mappedAction.trigger = useDebounceFn((target, input) => performAction(mappedAction, target, input, true), mappedAction.debounce);
47
+ } else if (!mappedAction.trigger) {
48
+ mappedAction.trigger = (target, input) => performAction(mappedAction, target, input, true);
49
+ }
50
+ return mappedAction;
51
+ });
52
+
53
+ /**
54
+ * Set the reactive saving state of a target
55
+ */
56
+ function setTargetSavingState(target: ActionTarget, saving: boolean) {
57
+ if (Array.isArray(target)) {
58
+ for (const t of target) {
59
+ t.isSaving.value = saving;
60
+ }
61
+ } else if (target.isSaving) {
62
+ target.isSaving.value = saving;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Perform an action on a set of targets
68
+ *
69
+ * @param {string} name - can either be a string or an action object
70
+ * @param {object[]|object} target - an array of targets or a single target object
71
+ * @param {any} input - The input data to pass to the action handler
72
+ * @param isTriggered - Whether the action was triggered by a trigger function
73
+ */
74
+ async function performAction(name: string | object, target: ActionTarget, input: any = null, isTriggered = false) {
75
+ const action: ActionOptions | null | undefined = typeof name === "string" ? mappedActions.find(a => a.name === name) : name;
76
+ if (!action) {
77
+ throw new Error(`Unknown action: ${name}`);
78
+ }
79
+
80
+ // We always want to call the trigger function if it exists, unless it's already been triggered
81
+ // This provides behavior like debounce and custom action resolution
82
+ if (action.trigger && !isTriggered) {
83
+ return action.trigger(target, input);
84
+ }
85
+
86
+ const vnode = action.vnode && action.vnode(target);
87
+ let result: any;
88
+
89
+ // Run the onStart handler if it exists and quit the operation if it returns false
90
+ if (action.onStart) {
91
+ if (!action.onStart(action, target, input)) {
92
+ return;
93
+ }
94
+ }
95
+
96
+ setTargetSavingState(target, true);
97
+
98
+ // If additional input is required, first render the vnode and wait for the confirm or cancel action
99
+ if (vnode) {
100
+ // If the action requires an input, we set the activeActionVnode to the input component.
101
+ // This will tell the ActionVnode to render the input component, and confirm or cancel the
102
+ // action The confirm function has the input from the component passed and will resolve the promise
103
+ // with the result of the action
104
+ result = await new Promise((resolve, reject) => {
105
+ activeActionVnode.value = {
106
+ vnode,
107
+ confirm: async (confirmInput: any) => {
108
+ const result = await onConfirmAction(action, target, { ...input, ...confirmInput });
109
+
110
+ // Only resolve when we have a non-error response, so we can show the error message w/o
111
+ // hiding the dialog / vnode
112
+ if (result === undefined || result === true || result?.success) {
113
+ resolve(result);
114
+ }
115
+ },
116
+ cancel: resolve
117
+ };
118
+ });
119
+
120
+ activeActionVnode.value = null;
121
+ } else {
122
+ result = await onConfirmAction(action, target, input);
123
+ }
124
+
125
+ setTargetSavingState(target, false);
126
+
127
+ return result;
128
+ }
129
+
130
+ /**
131
+ * Filter the list of actions based on the provided filters in key-value pairs
132
+ * You can filter on any ActionOptions property by matching the value exactly or by providing an array of values
133
+ *
134
+ * @param filters
135
+ * @returns {ActionOptions[]}
136
+ */
137
+ function filterActions(filters: object): ActionOptions[] {
138
+ let filteredActions = [...mappedActions];
139
+
140
+ for (const filter of Object.keys(filters)) {
141
+ const filterValue = filters[filter];
142
+ filteredActions = filteredActions.filter((a: object) => a[filter] === filterValue || (Array.isArray(filterValue) && filterValue.includes(a[filter])));
143
+ }
144
+ return filteredActions;
145
+ }
146
+
147
+ return {
148
+ actions: mappedActions,
149
+ filterActions,
150
+ performAction
151
+ };
152
152
  }
153
153
 
154
154
  async function onConfirmAction(action: ActionOptions, target: ActionTarget, input: any = null) {
155
- if (!action.onAction) {
156
- throw new Error("No onAction handler found for the selected action:" + action.name);
157
- }
158
-
159
- let result: any;
160
- try {
161
- if (Array.isArray(target)) {
162
- if (action.onBatchAction) {
163
- result = await action.onBatchAction(action.name, target, input);
164
- } else {
165
- result = { error: `Action ${action.name} does not support batch actions` };
166
- }
167
- } else {
168
- // If the action has an optimistic callback, we call it before the actual action to immediately
169
- // update the UI
170
- if (action.optimistic) {
171
- action.optimistic(action, target, input);
172
- }
173
-
174
- result = await action.onAction(action.name, target, input);
175
- }
176
- } catch (e) {
177
- console.error(e);
178
- result = { error: `An error occurred while performing the action ${action.label}. Please try again later.` };
179
- }
180
-
181
- // If there is no return value or the result marks it as successful, we show a success message
182
- if (result === undefined || result === true || result?.success) {
183
- if (result?.success && Array.isArray(target)) {
184
- FlashMessages.success(`Successfully performed action ${action.label} on ${target.length} items`);
185
- }
186
-
187
- if (action.onSuccess) {
188
- action.onSuccess(result, target, input);
189
- }
190
- } else {
191
- const errors = [];
192
- if (result.errors) {
193
- errors.push(...result.errors);
194
- } else if (result.error) {
195
- errors.push(typeof result.error === "string" ? result.error : result.error.message);
196
- } else {
197
- errors.push("An unknown error occurred. Please try again later.");
198
- }
199
-
200
- FlashMessages.combine("error", errors);
201
-
202
- if (action.onError) {
203
- action.onError(result, target, input);
204
- }
205
- }
206
-
207
- if (action.onFinish) {
208
- action.onFinish(result, target, input);
209
- }
210
-
211
- return result;
155
+ if (!action.onAction) {
156
+ throw new Error("No onAction handler found for the selected action:" + action.name);
157
+ }
158
+
159
+ let result: any;
160
+ try {
161
+ if (Array.isArray(target)) {
162
+ if (action.onBatchAction) {
163
+ result = await action.onBatchAction(action.name, target, input);
164
+ } else {
165
+ result = { error: `Action ${action.name} does not support batch actions` };
166
+ }
167
+ } else {
168
+ // If the action has an optimistic callback, we call it before the actual action to immediately
169
+ // update the UI
170
+ if (action.optimistic) {
171
+ action.optimistic(action, target, input);
172
+ }
173
+
174
+ result = await action.onAction(action.name, target, input);
175
+ }
176
+ } catch (e) {
177
+ console.error(e);
178
+ result = { error: `An error occurred while performing the action ${action.label}. Please try again later.` };
179
+ }
180
+
181
+ // If there is no return value or the result marks it as successful, we show a success message
182
+ if (result === undefined || result === true || result?.success) {
183
+ if (result?.success && Array.isArray(target)) {
184
+ FlashMessages.success(`Successfully performed action ${action.label} on ${target.length} items`);
185
+ }
186
+
187
+ if (action.onSuccess) {
188
+ action.onSuccess(result, target, input);
189
+ }
190
+ } else {
191
+ const errors = [];
192
+ if (result.errors) {
193
+ errors.push(...result.errors);
194
+ } else if (result.error) {
195
+ errors.push(typeof result.error === "string" ? result.error : result.error.message);
196
+ } else {
197
+ errors.push("An unknown error occurred. Please try again later.");
198
+ }
199
+
200
+ FlashMessages.combine("error", errors);
201
+
202
+ if (action.onError) {
203
+ action.onError(result, target, input);
204
+ }
205
+ }
206
+
207
+ if (action.onFinish) {
208
+ action.onFinish(result, target, input);
209
+ }
210
+
211
+ return result;
212
212
  }
@@ -1,50 +1,56 @@
1
1
  import { ref, Ref } from "vue";
2
2
 
3
3
  interface RequestOptions {
4
- baseUrl: string;
4
+ baseUrl: string;
5
5
  }
6
6
 
7
7
  const requestOptions: Ref<RequestOptions> = ref({
8
- baseUrl: ""
8
+ baseUrl: ""
9
9
  });
10
10
  /**
11
11
  * A simple request helper that wraps the fetch API
12
12
  * to make GET and POST requests easier w/ JSON payloads
13
13
  */
14
14
  export const request = {
15
- configure(options: RequestOptions) {
16
- requestOptions.value = options;
17
- },
15
+ configure(options: RequestOptions) {
16
+ requestOptions.value = options;
17
+ },
18
18
 
19
- url(url: string) {
20
- if (url.startsWith("http")) {
21
- return url;
22
- }
23
- return requestOptions.value.baseUrl + url;
24
- },
19
+ url(url: string) {
20
+ if (url.startsWith("http")) {
21
+ return url;
22
+ }
23
+ return requestOptions.value.baseUrl + url;
24
+ },
25
25
 
26
- async get(url: string, options = {}): Promise<object> {
27
- return fetch(request.url(url), {
28
- method: "get",
29
- headers: {
30
- Accept: "application/json",
31
- "Content-Type": "application/json"
32
- },
33
- ...options
34
- }).then((r) => r.json());
35
- },
26
+ async get(url: string, options = {}): Promise<object> {
27
+ return fetch(request.url(url), {
28
+ method: "get",
29
+ headers: {
30
+ Accept: "application/json",
31
+ "Content-Type": "application/json"
32
+ },
33
+ ...options
34
+ }).then((r) => r.json());
35
+ },
36
36
 
37
- async post(url: string, data = {}, options = {}) {
38
- return fetch(request.url(url), {
39
- method: "post",
40
- body: JSON.stringify(data),
41
- headers: {
42
- Accept: "application/json",
43
- "Content-Type": "application/json"
44
- },
45
- ...options
46
- }).then((r) => r.json());
47
- }
37
+ async post(url: string, data = {}, options = {}) {
38
+ let body = "";
39
+ try {
40
+ body = JSON.stringify(data);
41
+ } catch (e) {
42
+ // fail silently
43
+ }
44
+ return fetch(request.url(url), {
45
+ method: "post",
46
+ body,
47
+ headers: {
48
+ Accept: "application/json",
49
+ "Content-Type": "application/json"
50
+ },
51
+ ...options
52
+ }).then((r) => r.json());
53
+ }
48
54
  };
49
55
 
50
56
  /**
@@ -55,25 +61,25 @@ export const request = {
55
61
  *
56
62
  */
57
63
  export async function fetchResourceListWithSelected(fetchFn: (filter: object) => Promise<any[]>, list: Ref, id: string, filter: object): Promise<void> {
58
- // First make sure we have the selected record, so we can always add it to the list
59
- let selectedResource;
60
- if (id) {
61
- selectedResource = list.value.find((c: { id: string }) => c.id === id) || (await fetchFn({ id }))[0];
62
- }
64
+ // First make sure we have the selected record, so we can always add it to the list
65
+ let selectedResource;
66
+ if (id) {
67
+ selectedResource = list.value.find((c: { id: string }) => c.id === id) || (await fetchFn({ id }))[0];
68
+ }
63
69
 
64
- // Get the filtered campaign list
65
- list.value = await fetchFn(filter);
70
+ // Get the filtered campaign list
71
+ list.value = await fetchFn(filter);
66
72
 
67
- // If our selected campaign is not in the filtered list, add it
68
- if (selectedResource && !list.value.find((c: { id: string }) => c.id === id)) {
69
- list.value.push(selectedResource);
70
- }
73
+ // If our selected campaign is not in the filtered list, add it
74
+ if (selectedResource && !list.value.find((c: { id: string }) => c.id === id)) {
75
+ list.value.push(selectedResource);
76
+ }
71
77
  }
72
78
 
73
79
  /**
74
80
  * Returns the value of the URL parameter (if it is set)
75
81
  */
76
82
  export function getUrlParam(key: string, url?: string) {
77
- const params = new URLSearchParams(url?.replace(/.*\?/, "") || window.location.search);
78
- return params.get(key);
83
+ const params = new URLSearchParams(url?.replace(/.*\?/, "") || window.location.search);
84
+ return params.get(key);
79
85
  }