quasar-ui-danx 0.4.31 → 0.4.32

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.4.31",
3
+ "version": "0.4.32",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -72,7 +72,7 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
72
72
  }
73
73
 
74
74
  async function loadList() {
75
- if (!isInitialized) return;
75
+ if (!isInitialized || options.isListEnabled === false) return;
76
76
  // isLoadingList.value = true;
77
77
  try {
78
78
  setPagedItems(await options.routes.list(pager.value));
@@ -84,7 +84,7 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
84
84
  }
85
85
 
86
86
  async function loadSummary() {
87
- if (!options.routes.summary || !isInitialized) return;
87
+ if (!options.routes.summary || !isInitialized || options.isSummaryEnabled === false) return;
88
88
 
89
89
  isLoadingSummary.value = true;
90
90
  const summaryFilter: ListControlsFilter = { id: null, ...activeFilter.value, ...globalFilter.value };
@@ -115,7 +115,8 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
115
115
  * Loads the filter field options for the current filter.
116
116
  */
117
117
  async function loadFieldOptions() {
118
- if (!options.routes.fieldOptions) return;
118
+ if (!options.routes.fieldOptions || options.isFieldOptionsEnabled === false) return;
119
+
119
120
  isLoadingFilters.value = true;
120
121
  try {
121
122
  fieldOptions.value = await options.routes.fieldOptions(activeFilter.value) || {};
@@ -207,7 +208,7 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
207
208
  * Loads more items into the list.
208
209
  */
209
210
  async function loadMore(index: number, perPage: number | undefined = undefined) {
210
- if (!options.routes.more) return false;
211
+ if (!options.routes.more || options.isListEnabled === false) return false;
211
212
 
212
213
  try {
213
214
  const newItems = await options.routes.more({
@@ -296,7 +297,7 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
296
297
  async function getActiveItemDetails() {
297
298
  try {
298
299
  const latestResult = latestCallOnly("active-item", async () => {
299
- if (!activeItem.value || !options.routes.details) return undefined;
300
+ if (!activeItem.value || !options.routes.details || options.isDetailsEnabled === false) return undefined;
300
301
  return await options.routes.details(activeItem.value);
301
302
  });
302
303
 
@@ -414,12 +415,22 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
414
415
  options.routes.export && await options.routes.export(filter);
415
416
  }
416
417
 
418
+ function setOptions(newOptions: Partial<ListControlsOptions>) {
419
+ options = { ...options, ...newOptions };
420
+ }
421
+
417
422
  // Initialize the list actions and load settings, lists, summaries, filter fields, etc.
418
- function initialize() {
423
+ function initialize(updateOptions?: Partial<ListControlsOptions>) {
419
424
  const vueRouter = getVueRouter();
420
425
  isInitialized = true;
426
+
427
+ if (updateOptions) {
428
+ options = { ...options, ...updateOptions };
429
+ }
430
+
421
431
  loadSettings();
422
432
 
433
+
423
434
  /**
424
435
  * Watch the id params in the route and set the active item to the item with the given id.
425
436
  */
@@ -496,6 +507,7 @@ export function useControls(name: string, options: ListControlsOptions): ListCon
496
507
 
497
508
  // List controls
498
509
  initialize,
510
+ setOptions,
499
511
  resetPaging,
500
512
  setPagination,
501
513
  setSelectedRows,
@@ -133,7 +133,19 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionGlobal
133
133
  activeActionVnode.value = {
134
134
  vnode,
135
135
  confirm: async (confirmInput: any) => {
136
- const result = await onConfirmAction(action, target, { ...input, ...confirmInput });
136
+
137
+ // Resolve the input based on the useInputFromConfirm option
138
+ // Not setting useInputFromConfirm will merge the input from the confirm dialog with the input from the action
139
+ let resolvedInput;
140
+ if (action.useInputFromConfirm === false) {
141
+ resolvedInput = input;
142
+ } else if (action.useInputFromConfirm === true) {
143
+ resolvedInput = confirmInput;
144
+ } else {
145
+ resolvedInput = { ...input, ...confirmInput };
146
+ }
147
+
148
+ const result = await onConfirmAction(action, target, resolvedInput);
137
149
 
138
150
  // Only resolve when we have a non-error response, so we can show the error message w/o
139
151
  // hiding the dialog / vnode
@@ -19,6 +19,10 @@ export function storeObjects<T extends TypedObject>(newObjects: T[]) {
19
19
  * Returns the stored object that should be used instead of the passed object as the returned object is shared across the system
20
20
  */
21
21
  export function storeObject<T extends TypedObject>(newObject: T, recentlyStoredObjects: AnyObject = {}): ShallowReactive<T> {
22
+ if (typeof newObject !== "object") {
23
+ return newObject;
24
+ }
25
+
22
26
  const id = newObject?.id || newObject?.name;
23
27
  const type = newObject?.__type;
24
28
  if (!id || !type) return shallowReactive(newObject);
@@ -76,9 +80,31 @@ export function storeObject<T extends TypedObject>(newObject: T, recentlyStoredO
76
80
  store.set(objectKey, reactiveObject);
77
81
  }
78
82
 
83
+ if (reactiveObject.__deleted_at) {
84
+ removeObjectFromLists(reactiveObject);
85
+ }
86
+
79
87
  return reactiveObject;
80
88
  }
81
89
 
90
+ /**
91
+ * Remove an object from all lists in the store
92
+ */
93
+ function removeObjectFromLists<T extends TypedObject>(object: T) {
94
+ for (const storedObject of store.values()) {
95
+ for (const key of Object.keys(storedObject)) {
96
+ const value = storedObject[key];
97
+ if (Array.isArray(value) && value.length > 0) {
98
+ const index = value.findIndex(v => v.__id === object.__id && v.__type === object.__type);
99
+ if (index !== -1) {
100
+ value.splice(index, 1);
101
+ storedObject[key] = [...value];
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+
82
108
  /**
83
109
  * Auto refresh an object based on a condition and a callback. Returns the timeout ID for the auto-refresh.
84
110
  * NOTE: Use the timeout ID to clear the auto-refresh when the object is no longer needed (eg: when the component is unmounted)
@@ -101,9 +127,8 @@ export async function autoRefreshObject<T extends TypedObject>(object: T, condit
101
127
  storeObject(refreshedObject);
102
128
  }
103
129
 
104
-
130
+ // Save the timeoutId to the object so it can be cleared when the object refresh is no longer needed
105
131
  const timeoutId = setTimeout(() => autoRefreshObject(object, condition, callback, interval), interval);
106
-
107
132
  registeredAutoRefreshes[object.__type + ":" + object.id] = timeoutId;
108
133
  }
109
134
 
@@ -35,6 +35,18 @@ export const request: RequestApi = {
35
35
  options.signal = abort.signal;
36
36
  }
37
37
 
38
+ if (options.params) {
39
+ // Transform object values in params to JSON strings
40
+ for (const [key, value] of Object.entries(options.params)) {
41
+ if (typeof value === "object" && value !== null) {
42
+ options.params[key] = JSON.stringify(value);
43
+ }
44
+ }
45
+
46
+ url += (url.match(/\?/) ? "&" : "?") + new URLSearchParams(options.params).toString();
47
+ delete options.params;
48
+ }
49
+
38
50
  const response = await fetch(request.url(url), options);
39
51
 
40
52
  // Verify the app version of the client and server are matching
@@ -32,6 +32,7 @@ export interface ActionOptions<T = ActionTargetItem> {
32
32
  category?: string;
33
33
  class?: string;
34
34
  debounce?: number;
35
+ useInputFromConfirm?: boolean;
35
36
  optimistic?: boolean | ((action: ActionOptions<T>, target: T | null, input: any) => void);
36
37
  vnode?: (target: ActionTarget<T>, data: any) => VNode | any;
37
38
  enabled?: (target: ActionTarget<T>) => boolean;
@@ -47,6 +47,10 @@ export interface ListControlsOptions {
47
47
  urlPattern?: RegExp | null;
48
48
  filterDefaults?: Record<string, object>;
49
49
  refreshFilters?: boolean;
50
+ isListEnabled?: boolean;
51
+ isSummaryEnabled?: boolean;
52
+ isDetailsEnabled?: boolean;
53
+ isFieldOptionsEnabled?: boolean;
50
54
  }
51
55
 
52
56
  export interface ListControlsPagination {
@@ -92,7 +96,8 @@ export interface ListController<T = ActionTargetItem> {
92
96
  activePanel: Ref<string | null>;
93
97
 
94
98
  // List Controls
95
- initialize: () => void;
99
+ initialize: (updateOptions?: Partial<ListControlsOptions>) => void;
100
+ setOptions: (updateOptions: Partial<ListControlsOptions>) => void;
96
101
  resetPaging: () => void;
97
102
  setPagination: (updated: Partial<ListControlsPagination>) => void;
98
103
  setSelectedRows: (selection: T[]) => void;
@@ -31,5 +31,6 @@ export interface RequestOptions {
31
31
 
32
32
  export interface RequestCallOptions extends RequestInit {
33
33
  abortOn?: string;
34
+ params?: AnyObject;
34
35
  }
35
36