quasar-ui-danx 0.3.29 → 0.3.31

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,391 +3,395 @@ import { ActionTargetItem, getItem, setItem, waitForRef } from "../../helpers";
3
3
  import { getFilterFromUrl } from "./listHelpers";
4
4
 
5
5
  export interface ListActionsOptions {
6
- listRoute: Function;
7
- summaryRoute?: Function | null;
8
- filterFieldOptionsRoute?: Function | null;
9
- moreRoute?: Function | null;
10
- itemDetailsRoute?: Function | null;
11
- urlPattern?: RegExp | null;
12
- filterDefaults?: Record<string, any>;
13
- refreshFilters?: boolean;
6
+ listRoute: Function;
7
+ summaryRoute?: Function | null;
8
+ filterFieldOptionsRoute?: Function | null;
9
+ moreRoute?: Function | null;
10
+ itemDetailsRoute?: Function | null;
11
+ urlPattern?: RegExp | null;
12
+ filterDefaults?: Record<string, any>;
13
+ refreshFilters?: boolean;
14
14
  }
15
15
 
16
16
  export interface PagedItems {
17
- data: any[] | undefined;
18
- meta: {
19
- total: number;
20
- last_page?: number;
21
- } | undefined;
17
+ data: any[] | undefined;
18
+ meta: {
19
+ total: number;
20
+ last_page?: number;
21
+ } | undefined;
22
22
  }
23
23
 
24
- export function useListControls(name: string, {
25
- listRoute,
26
- summaryRoute = null,
27
- filterFieldOptionsRoute = null,
28
- moreRoute = null,
29
- itemDetailsRoute = null,
30
- refreshFilters = false,
31
- urlPattern = null,
32
- filterDefaults = {}
33
- }: ListActionsOptions) {
34
- let isInitialized = false;
35
- const PAGE_SETTINGS_KEY = `${name}-pagination-settings`;
36
- const pagedItems: Ref<PagedItems | null> = shallowRef(null);
37
- const filter: Ref<object | any> = ref({});
38
- const globalFilter = ref({});
39
- const showFilters = ref(false);
40
- const selectedRows = shallowRef([]);
41
- const isLoadingList = ref(false);
42
- const isLoadingSummary = ref(false);
43
- const summary = shallowRef(null);
44
-
45
- // The active ad for viewing / editing
46
- const activeItem: ShallowRef<ActionTargetItem | null> = shallowRef(null);
47
- // Controls the active panel (ie: tab) if rendering a panels drawer or similar
48
- const activePanel = shallowRef(null);
49
-
50
- // Filter fields are the field values available for the currently applied filter on Creative Groups
51
- // (ie: all states available under the current filter)
52
- const filterFieldOptions = ref({});
53
- const isLoadingFilters = ref(false);
54
-
55
- const filterActiveCount = computed(() => Object.keys(filter.value).filter(key => filter.value[key] !== undefined).length);
56
-
57
- const PAGING_DEFAULT = {
58
- __sort: null,
59
- sortBy: null,
60
- descending: false,
61
- page: 1,
62
- rowsNumber: 0,
63
- rowsPerPage: 50
64
- };
65
- const quasarPagination = ref(PAGING_DEFAULT);
66
-
67
- const pager = computed(() => ({
68
- perPage: quasarPagination.value.rowsPerPage,
69
- page: quasarPagination.value.page,
70
- filter: { ...filter.value, ...globalFilter.value },
71
- sort: quasarPagination.value.__sort || undefined
72
- }));
73
-
74
- // When any part of the filter changes, get the new list of creatives
75
- watch(pager, () => {
76
- saveSettings();
77
- loadList();
78
- });
79
- watch(filter, () => {
80
- saveSettings();
81
- loadSummary();
82
- });
83
- watch(selectedRows, loadSummary);
84
-
85
- if (refreshFilters) {
86
- watch(filter, loadFilterFieldOptions);
87
- }
88
-
89
- async function loadList() {
90
- if (!isInitialized) return;
91
- isLoadingList.value = true;
92
- setPagedItems(await listRoute(pager.value));
93
- isLoadingList.value = false;
94
- }
95
-
96
- async function loadSummary() {
97
- if (!summaryRoute || !isInitialized) return;
98
-
99
- isLoadingSummary.value = true;
100
- const summaryFilter = { id: null, ...filter.value, ...globalFilter.value };
101
- if (selectedRows.value.length) {
102
- summaryFilter.id = selectedRows.value.map((row: { id: string }) => row.id);
103
- }
104
- summary.value = await summaryRoute(summaryFilter);
105
- isLoadingSummary.value = false;
106
- }
107
-
108
- /**
109
- * Loads the filter field options for the current filter.
110
- *
111
- * @returns {Promise<void>}
112
- */
113
- async function loadFilterFieldOptions() {
114
- if (!filterFieldOptionsRoute || !isInitialized) return;
115
- isLoadingFilters.value = true;
116
- filterFieldOptions.value = await filterFieldOptionsRoute(filter.value);
117
- isLoadingFilters.value = false;
118
- }
119
-
120
- /**
121
- * Watches for a filter URL parameter and applies the filter if it is set.
122
- */
123
- function applyFilterFromUrl(url: string, filterFields = null) {
124
- if (urlPattern && url.match(urlPattern)) {
125
- // A flat list of valid filterable field names
126
- const validFilterKeys = filterFields?.value?.map(group => group.fields.map(field => field.name)).flat();
127
-
128
- const urlFilter = getFilterFromUrl(url, validFilterKeys);
129
-
130
- if (Object.keys(urlFilter).length > 0) {
131
- filter.value = urlFilter;
132
-
133
- // Override whatever is in local storage with this new filter
134
- updateSettings("filter", filter.value);
135
- }
136
- }
137
- }
138
-
139
- // Set the reactive pager to map from the Laravel pagination to Quasar pagination
140
- // and automatically update the list of ads
141
- function setPagedItems(items: any[] | PagedItems) {
142
- let data, meta;
143
-
144
- if (Array.isArray(items)) {
145
- data = items;
146
- meta = { total: items.length };
147
-
148
- } else {
149
- data = items.data;
150
- meta = items.meta;
151
- }
152
-
153
- // Update the Quasar pagination rows number if it is different from the total
154
- if (meta && meta.total !== quasarPagination.value.rowsNumber) {
155
- quasarPagination.value.rowsNumber = meta.total;
156
- }
157
-
158
- // Add a reactive isSaving property to each item (for performance reasons in checking saving state)
159
- data = data.map((item: any) => {
160
- // We want to keep the isSaving state if it is already set, as optimizations prevent reloading the
161
- // components, and therefore reactivity is not responding to the new isSaving state
162
- const oldItem = pagedItems.value?.data?.find(i => i.id === item.id);
163
- return { ...item, isSaving: oldItem?.isSaving || ref(false) };
164
- });
165
-
166
- pagedItems.value = { data, meta };
167
- }
168
-
169
- /**
170
- * Resets the filter and pagination settings to their defaults.
171
- */
172
- function resetPaging() {
173
- quasarPagination.value = PAGING_DEFAULT;
174
- }
175
-
176
- /**
177
- * Updates a row in the paged items list with the new item data. Uses the item's id to find the row.
178
- *
179
- * @param updatedItem
180
- */
181
- function setItemInList(updatedItem: any) {
182
- const data = pagedItems.value?.data?.map(item => (item.id === updatedItem.id && (item.updated_at === null || item.updated_at <= updatedItem.updated_at)) ? updatedItem : item);
183
- setPagedItems({
184
- data,
185
- meta: { total: pagedItems.value.meta.total }
186
- });
187
-
188
- // Update the active item as well if it is set
189
- if (activeItem.value?.id === updatedItem.id) {
190
- activeItem.value = { ...activeItem.value, ...updatedItem };
191
- }
192
- }
193
-
194
- /**
195
- * Loads more items into the list.
196
- */
197
- async function loadMore(index: number, perPage = undefined) {
198
- if (!moreRoute) return;
199
-
200
- const newItems = await moreRoute({
201
- page: index + 1,
202
- perPage,
203
- filter: { ...filter.value, ...globalFilter.value }
204
- });
205
-
206
- if (newItems && newItems.length > 0) {
207
- setPagedItems({
208
- data: [...pagedItems.value.data, ...newItems],
209
- meta: { total: pagedItems.value.meta.total }
210
- });
211
- return true;
212
- }
213
-
214
- return false;
215
- }
216
-
217
- /**
218
- * Refreshes the list, summary, and filter field options.
219
- */
220
- async function refreshAll() {
221
- return Promise.all([loadList(), loadSummary(), loadFilterFieldOptions(), getActiveItemDetails()]);
222
- }
223
-
224
- /**
225
- * Updates the settings in local storage
226
- */
227
- function updateSettings(key: string, value: any) {
228
- const settings = getItem(PAGE_SETTINGS_KEY) || {};
229
- settings[key] = value;
230
- setItem(PAGE_SETTINGS_KEY, settings);
231
- }
232
-
233
- /**
234
- * Loads the filter and pagination settings from local storage.
235
- */
236
- function loadSettings() {
237
- // Only load settings when the class is fully initialized
238
- if (!isInitialized) return;
239
-
240
- const settings = getItem(PAGE_SETTINGS_KEY);
241
-
242
- // Load the filter settings from local storage
243
- if (settings) {
244
- filter.value = { ...settings.filter, ...filter.value };
245
- quasarPagination.value = settings.quasarPagination;
246
- } else {
247
- // If no local storage settings, apply the default filters
248
- filter.value = { ...filterDefaults, ...filter.value };
249
- }
250
-
251
- setTimeout(() => {
252
- if (!isLoadingList.value) {
253
- loadList();
254
- }
255
-
256
- if (!isLoadingSummary.value) {
257
- loadSummary();
258
- }
259
-
260
- if (!isLoadingFilters.value) {
261
- loadFilterFieldOptions();
262
- }
263
- }, 1);
264
- }
265
-
266
- /**
267
- * Saves the current filter and pagination settings to local storage.
268
- */
269
- async function saveSettings() {
270
- const settings = {
271
- filter: filter.value,
272
- quasarPagination: { ...quasarPagination.value, page: 1 }
273
- };
274
- // save in local storage
275
- setItem(PAGE_SETTINGS_KEY, settings);
276
- }
277
-
278
- /**
279
- * Gets the additional details for the currently active item.
280
- * (ie: data that is not normally loaded in the list because it is not needed for the list view)
281
- * @returns {Promise<void>}
282
- */
283
- async function getActiveItemDetails() {
284
- if (!activeItem.value || !itemDetailsRoute) return;
285
-
286
- const result = await itemDetailsRoute(activeItem.value);
287
-
288
- // Only set the ad details if we are the response for the currently loaded item
289
- // NOTE: race conditions might allow the finished loading item to be different to the currently
290
- // requested item
291
- if (result?.id === activeItem.value?.id) {
292
- const loadedItem = pagedItems.value?.data.find((i: { id: string }) => i.id === result.id);
293
- activeItem.value = { ...result, isSaving: loadedItem.isSaving || ref(false) };
294
- }
295
- }
296
-
297
- // Whenever the active item changes, fill the additional item details
298
- // (ie: tasks, verifications, creatives, etc.)
299
- if (itemDetailsRoute) {
300
- watch(() => activeItem.value, async (newItem, oldItem) => {
301
- if (newItem && oldItem?.id !== newItem.id) {
302
- await getActiveItemDetails();
303
- }
304
- });
305
- }
306
-
307
- /**
308
- * Opens the item's form with the given item and tab
309
- *
310
- * @param item
311
- * @param panel
312
- */
313
- function activatePanel(item, panel) {
314
- activeItem.value = item;
315
- activePanel.value = panel;
316
- }
317
-
318
- /**
319
- * Gets the next item in the list at the given offset (ie: 1 or -1) from the current position in the list of the
320
- * selected item. If the next item is on a previous or next page, it will load the page first then select the item
321
- */
322
- async function getNextItem(offset: number) {
323
- if (!pagedItems.value) return;
324
-
325
- const index = pagedItems.value.data.findIndex((i: { id: string }) => i.id === activeItem.value?.id);
326
- if (index === undefined || index === null) return;
327
-
328
- let nextIndex = index + offset;
329
-
330
- // Load the previous page if the offset is before index 0
331
- if (nextIndex < 0) {
332
- if (quasarPagination.value.page > 1) {
333
- quasarPagination.value = { ...quasarPagination.value, page: quasarPagination.value.page - 1 };
334
- await waitForRef(isLoadingList, false);
335
- nextIndex = pagedItems.value.data.length - 1;
336
- } else {
337
- // There are no more previous pages
338
- return;
339
- }
340
- }
341
-
342
- // Load the next page if the offset is past the last index
343
- if (nextIndex >= pagedItems.value.data.length) {
344
- if (quasarPagination.value.page < pagedItems.value.meta.last_page) {
345
- quasarPagination.value = { ...quasarPagination.value, page: quasarPagination.value.page + 1 };
346
- await waitForRef(isLoadingList, false);
347
- nextIndex = 0;
348
- } else {
349
- // There are no more next pages
350
- return;
351
- }
352
- }
353
-
354
- activeItem.value = pagedItems.value?.data[nextIndex];
355
- }
356
-
357
- // Initialize the list actions and load settings, lists, summaries, filter fields, etc.
358
- function initialize() {
359
- isInitialized = true;
360
- loadSettings();
361
- }
362
-
363
- return {
364
- // State
365
- pagedItems,
366
- filter,
367
- globalFilter,
368
- filterActiveCount,
369
- showFilters,
370
- summary,
371
- filterFieldOptions,
372
- selectedRows,
373
- isLoadingList,
374
- isLoadingFilters,
375
- isLoadingSummary,
376
- pager,
377
- quasarPagination,
378
- activeItem,
379
- activePanel,
380
-
381
- // Actions
382
- initialize,
383
- loadSummary,
384
- resetPaging,
385
- loadList,
386
- loadMore,
387
- refreshAll,
388
- getNextItem,
389
- activatePanel,
390
- applyFilterFromUrl,
391
- setItemInList
392
- };
24
+ export function useListControls({
25
+ listRoute,
26
+ summaryRoute = null,
27
+ filterFieldOptionsRoute = null,
28
+ moreRoute = null,
29
+ itemDetailsRoute = null,
30
+ refreshFilters = false,
31
+ urlPattern = null,
32
+ filterDefaults = {}
33
+ }: ListActionsOptions) {
34
+ let isInitialized = false;
35
+ let PAGE_SETTINGS_KEY: string | null = null;
36
+ const pagedItems: Ref<PagedItems | null> = shallowRef(null);
37
+ const filter: Ref<object | any> = ref({});
38
+ const globalFilter = ref({});
39
+ const showFilters = ref(false);
40
+ const selectedRows = shallowRef([]);
41
+ const isLoadingList = ref(false);
42
+ const isLoadingSummary = ref(false);
43
+ const summary = shallowRef(null);
44
+
45
+ // The active ad for viewing / editing
46
+ const activeItem: ShallowRef<ActionTargetItem | null> = shallowRef(null);
47
+ // Controls the active panel (ie: tab) if rendering a panels drawer or similar
48
+ const activePanel = shallowRef(null);
49
+
50
+ // Filter fields are the field values available for the currently applied filter on Creative Groups
51
+ // (ie: all states available under the current filter)
52
+ const filterFieldOptions = ref({});
53
+ const isLoadingFilters = ref(false);
54
+
55
+ const filterActiveCount = computed(() => Object.keys(filter.value).filter(key => filter.value[key] !== undefined).length);
56
+
57
+ const PAGING_DEFAULT = {
58
+ __sort: null,
59
+ sortBy: null,
60
+ descending: false,
61
+ page: 1,
62
+ rowsNumber: 0,
63
+ rowsPerPage: 50
64
+ };
65
+ const quasarPagination = ref(PAGING_DEFAULT);
66
+
67
+ const pager = computed(() => ({
68
+ perPage: quasarPagination.value.rowsPerPage,
69
+ page: quasarPagination.value.page,
70
+ filter: { ...filter.value, ...globalFilter.value },
71
+ sort: quasarPagination.value.__sort || undefined
72
+ }));
73
+
74
+ // When any part of the filter changes, get the new list of creatives
75
+ watch(pager, () => {
76
+ saveSettings();
77
+ loadList();
78
+ });
79
+ watch(filter, () => {
80
+ saveSettings();
81
+ loadSummary();
82
+ });
83
+ watch(selectedRows, loadSummary);
84
+
85
+ if (refreshFilters) {
86
+ watch(filter, loadFilterFieldOptions);
87
+ }
88
+
89
+ async function loadList() {
90
+ if (!isInitialized) return;
91
+ isLoadingList.value = true;
92
+ setPagedItems(await listRoute(pager.value));
93
+ isLoadingList.value = false;
94
+ }
95
+
96
+ async function loadSummary() {
97
+ if (!summaryRoute || !isInitialized) return;
98
+
99
+ isLoadingSummary.value = true;
100
+ const summaryFilter = { id: null, ...filter.value, ...globalFilter.value };
101
+ if (selectedRows.value.length) {
102
+ summaryFilter.id = selectedRows.value.map((row: { id: string }) => row.id);
103
+ }
104
+ summary.value = await summaryRoute(summaryFilter);
105
+ isLoadingSummary.value = false;
106
+ }
107
+
108
+ /**
109
+ * Loads the filter field options for the current filter.
110
+ *
111
+ * @returns {Promise<void>}
112
+ */
113
+ async function loadFilterFieldOptions() {
114
+ if (!filterFieldOptionsRoute || !isInitialized) return;
115
+ isLoadingFilters.value = true;
116
+ filterFieldOptions.value = await filterFieldOptionsRoute(filter.value);
117
+ isLoadingFilters.value = false;
118
+ }
119
+
120
+ /**
121
+ * Watches for a filter URL parameter and applies the filter if it is set.
122
+ */
123
+ function applyFilterFromUrl(url: string, filterFields = null) {
124
+ if (urlPattern && url.match(urlPattern)) {
125
+ // A flat list of valid filterable field names
126
+ const validFilterKeys = filterFields?.value?.map(group => group.fields.map(field => field.name)).flat();
127
+
128
+ const urlFilter = getFilterFromUrl(url, validFilterKeys);
129
+
130
+ if (Object.keys(urlFilter).length > 0) {
131
+ filter.value = urlFilter;
132
+
133
+ // Override whatever is in local storage with this new filter
134
+ updateSettings("filter", filter.value);
135
+ }
136
+ }
137
+ }
138
+
139
+ // Set the reactive pager to map from the Laravel pagination to Quasar pagination
140
+ // and automatically update the list of ads
141
+ function setPagedItems(items: any[] | PagedItems) {
142
+ let data, meta;
143
+
144
+ if (Array.isArray(items)) {
145
+ data = items;
146
+ meta = { total: items.length };
147
+
148
+ } else {
149
+ data = items.data;
150
+ meta = items.meta;
151
+ }
152
+
153
+ // Update the Quasar pagination rows number if it is different from the total
154
+ if (meta && meta.total !== quasarPagination.value.rowsNumber) {
155
+ quasarPagination.value.rowsNumber = meta.total;
156
+ }
157
+
158
+ // Add a reactive isSaving property to each item (for performance reasons in checking saving state)
159
+ data = data.map((item: any) => {
160
+ // We want to keep the isSaving state if it is already set, as optimizations prevent reloading the
161
+ // components, and therefore reactivity is not responding to the new isSaving state
162
+ const oldItem = pagedItems.value?.data?.find(i => i.id === item.id);
163
+ return { ...item, isSaving: oldItem?.isSaving || ref(false) };
164
+ });
165
+
166
+ pagedItems.value = { data, meta };
167
+ }
168
+
169
+ /**
170
+ * Resets the filter and pagination settings to their defaults.
171
+ */
172
+ function resetPaging() {
173
+ quasarPagination.value = PAGING_DEFAULT;
174
+ }
175
+
176
+ /**
177
+ * Updates a row in the paged items list with the new item data. Uses the item's id to find the row.
178
+ *
179
+ * @param updatedItem
180
+ */
181
+ function setItemInList(updatedItem: any) {
182
+ const data = pagedItems.value?.data?.map(item => (item.id === updatedItem.id && (item.updated_at === null || item.updated_at <= updatedItem.updated_at)) ? updatedItem : item);
183
+ setPagedItems({
184
+ data,
185
+ meta: { total: pagedItems.value.meta.total }
186
+ });
187
+
188
+ // Update the active item as well if it is set
189
+ if (activeItem.value?.id === updatedItem.id) {
190
+ activeItem.value = { ...activeItem.value, ...updatedItem };
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Loads more items into the list.
196
+ */
197
+ async function loadMore(index: number, perPage = undefined) {
198
+ if (!moreRoute) return;
199
+
200
+ const newItems = await moreRoute({
201
+ page: index + 1,
202
+ perPage,
203
+ filter: { ...filter.value, ...globalFilter.value }
204
+ });
205
+
206
+ if (newItems && newItems.length > 0) {
207
+ setPagedItems({
208
+ data: [...pagedItems.value.data, ...newItems],
209
+ meta: { total: pagedItems.value.meta.total }
210
+ });
211
+ return true;
212
+ }
213
+
214
+ return false;
215
+ }
216
+
217
+ /**
218
+ * Refreshes the list, summary, and filter field options.
219
+ */
220
+ async function refreshAll() {
221
+ return Promise.all([loadList(), loadSummary(), loadFilterFieldOptions(), getActiveItemDetails()]);
222
+ }
223
+
224
+ /**
225
+ * Updates the settings in local storage
226
+ */
227
+ function updateSettings(key: string, value: any) {
228
+ if (!PAGE_SETTINGS_KEY) throw new Error("updateSettings failed: PAGE_SETTINGS_KEY is not set");
229
+
230
+ const settings = getItem(PAGE_SETTINGS_KEY) || {};
231
+ settings[key] = value;
232
+ setItem(PAGE_SETTINGS_KEY, settings);
233
+ }
234
+
235
+ /**
236
+ * Loads the filter and pagination settings from local storage.
237
+ */
238
+ function loadSettings() {
239
+ if (!PAGE_SETTINGS_KEY) throw new Error("loadSettings failed: PAGE_SETTINGS_KEY is not set");
240
+
241
+ const settings = getItem(PAGE_SETTINGS_KEY);
242
+
243
+ // Load the filter settings from local storage
244
+ if (settings) {
245
+ filter.value = { ...settings.filter, ...filter.value };
246
+ quasarPagination.value = settings.quasarPagination;
247
+ } else {
248
+ // If no local storage settings, apply the default filters
249
+ filter.value = { ...filterDefaults, ...filter.value };
250
+ }
251
+
252
+ setTimeout(() => {
253
+ if (!isLoadingList.value) {
254
+ loadList();
255
+ }
256
+
257
+ if (!isLoadingSummary.value) {
258
+ loadSummary();
259
+ }
260
+
261
+ if (!isLoadingFilters.value) {
262
+ loadFilterFieldOptions();
263
+ }
264
+ }, 1);
265
+ }
266
+
267
+ /**
268
+ * Saves the current filter and pagination settings to local storage.
269
+ */
270
+ async function saveSettings() {
271
+ if (!PAGE_SETTINGS_KEY) throw new Error("saveSettings failed: PAGE_SETTINGS_KEY is not set");
272
+
273
+ const settings = {
274
+ filter: filter.value,
275
+ quasarPagination: { ...quasarPagination.value, page: 1 }
276
+ };
277
+ // save in local storage
278
+ setItem(PAGE_SETTINGS_KEY, settings);
279
+ }
280
+
281
+ /**
282
+ * Gets the additional details for the currently active item.
283
+ * (ie: data that is not normally loaded in the list because it is not needed for the list view)
284
+ * @returns {Promise<void>}
285
+ */
286
+ async function getActiveItemDetails() {
287
+ if (!activeItem.value || !itemDetailsRoute) return;
288
+
289
+ const result = await itemDetailsRoute(activeItem.value);
290
+
291
+ // Only set the ad details if we are the response for the currently loaded item
292
+ // NOTE: race conditions might allow the finished loading item to be different to the currently
293
+ // requested item
294
+ if (result?.id === activeItem.value?.id) {
295
+ const loadedItem = pagedItems.value?.data.find((i: { id: string }) => i.id === result.id);
296
+ activeItem.value = { ...result, isSaving: loadedItem.isSaving || ref(false) };
297
+ }
298
+ }
299
+
300
+ // Whenever the active item changes, fill the additional item details
301
+ // (ie: tasks, verifications, creatives, etc.)
302
+ if (itemDetailsRoute) {
303
+ watch(() => activeItem.value, async (newItem, oldItem) => {
304
+ if (newItem && oldItem?.id !== newItem.id) {
305
+ await getActiveItemDetails();
306
+ }
307
+ });
308
+ }
309
+
310
+ /**
311
+ * Opens the item's form with the given item and tab
312
+ *
313
+ * @param item
314
+ * @param panel
315
+ */
316
+ function activatePanel(item, panel) {
317
+ activeItem.value = item;
318
+ activePanel.value = panel;
319
+ }
320
+
321
+ /**
322
+ * Gets the next item in the list at the given offset (ie: 1 or -1) from the current position in the list of the
323
+ * selected item. If the next item is on a previous or next page, it will load the page first then select the item
324
+ */
325
+ async function getNextItem(offset: number) {
326
+ if (!pagedItems.value) return;
327
+
328
+ const index = pagedItems.value.data.findIndex((i: { id: string }) => i.id === activeItem.value?.id);
329
+ if (index === undefined || index === null) return;
330
+
331
+ let nextIndex = index + offset;
332
+
333
+ // Load the previous page if the offset is before index 0
334
+ if (nextIndex < 0) {
335
+ if (quasarPagination.value.page > 1) {
336
+ quasarPagination.value = { ...quasarPagination.value, page: quasarPagination.value.page - 1 };
337
+ await waitForRef(isLoadingList, false);
338
+ nextIndex = pagedItems.value.data.length - 1;
339
+ } else {
340
+ // There are no more previous pages
341
+ return;
342
+ }
343
+ }
344
+
345
+ // Load the next page if the offset is past the last index
346
+ if (nextIndex >= pagedItems.value.data.length) {
347
+ if (quasarPagination.value.page < pagedItems.value.meta.last_page) {
348
+ quasarPagination.value = { ...quasarPagination.value, page: quasarPagination.value.page + 1 };
349
+ await waitForRef(isLoadingList, false);
350
+ nextIndex = 0;
351
+ } else {
352
+ // There are no more next pages
353
+ return;
354
+ }
355
+ }
356
+
357
+ activeItem.value = pagedItems.value?.data[nextIndex];
358
+ }
359
+
360
+ // Initialize the list actions and load settings, lists, summaries, filter fields, etc.
361
+ function initialize(name: string) {
362
+ PAGE_SETTINGS_KEY = `${name}-pagination-settings`;
363
+ isInitialized = true;
364
+ loadSettings();
365
+ }
366
+
367
+ return {
368
+ // State
369
+ pagedItems,
370
+ filter,
371
+ globalFilter,
372
+ filterActiveCount,
373
+ showFilters,
374
+ summary,
375
+ filterFieldOptions,
376
+ selectedRows,
377
+ isLoadingList,
378
+ isLoadingFilters,
379
+ isLoadingSummary,
380
+ pager,
381
+ quasarPagination,
382
+ activeItem,
383
+ activePanel,
384
+
385
+ // Actions
386
+ initialize,
387
+ loadSummary,
388
+ resetPaging,
389
+ loadList,
390
+ loadMore,
391
+ refreshAll,
392
+ getNextItem,
393
+ activatePanel,
394
+ applyFilterFromUrl,
395
+ setItemInList
396
+ };
393
397
  }