quasar-ui-danx 0.3.29 → 0.3.31

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }