quasar-ui-danx 0.0.31 → 0.0.33
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 +1 -1
- package/src/components/ActionTable/ActionMenu.vue +10 -3
- package/src/components/ActionTable/ActionTable.vue +7 -6
- package/src/components/ActionTable/index.ts +0 -1
- package/src/components/ActionTable/listActions.ts +34 -38
- package/src/components/Utility/Popovers/PopoverMenu.vue +1 -0
- package/src/components/Utility/Tools/ActionPerformerTool.vue +9 -9
- package/src/helpers/http.ts +34 -34
- package/src/helpers/performAction.ts +13 -1
- package/src/styles/actions.scss +10 -0
- package/src/components/ActionTable/BatchActionMenu.vue +0 -60
package/package.json
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
<template>
|
2
2
|
<PopoverMenu
|
3
|
-
class="px-
|
3
|
+
class="px-2 flex action-button"
|
4
4
|
:items="activeItems"
|
5
|
+
:disabled="targets.length === 0"
|
5
6
|
@action-item="onAction"
|
6
|
-
|
7
|
+
>
|
8
|
+
<q-tooltip v-if="targets.length === 0">{{ tooltip }}</q-tooltip>
|
9
|
+
</PopoverMenu>
|
7
10
|
</template>
|
8
11
|
<script setup>
|
9
12
|
import { computed } from 'vue';
|
@@ -19,12 +22,16 @@ const props = defineProps({
|
|
19
22
|
targets: {
|
20
23
|
type: Array,
|
21
24
|
required: true
|
25
|
+
},
|
26
|
+
tooltip: {
|
27
|
+
type: String,
|
28
|
+
default: 'First select records to perform a batch action'
|
22
29
|
}
|
23
30
|
});
|
24
31
|
|
25
32
|
const activeItems = computed(() => props.items.filter(item => {
|
26
33
|
if (item.enabled === undefined) return true;
|
27
|
-
return typeof item.enabled === 'function' ? !!item.enabled(props.targets) : !!item.enabled;
|
34
|
+
return typeof item.enabled === 'function' ? !!item.enabled(props.targets?.[0] ?? null, props.targets) : !!item.enabled;
|
28
35
|
}));
|
29
36
|
|
30
37
|
function onAction(item) {
|
@@ -70,12 +70,13 @@
|
|
70
70
|
{{ rowProps.value }}
|
71
71
|
</slot>
|
72
72
|
</div>
|
73
|
-
<
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
<div v-if="rowProps.col.actions" class="flex-grow flex justify-end pl-2">
|
74
|
+
<ActionMenu
|
75
|
+
:items="rowProps.col.actions"
|
76
|
+
:targets="[rowProps.row]"
|
77
|
+
@action="(action) => $emit('action', {action: action, row: rowProps.row})"
|
78
|
+
/>
|
79
|
+
</div>
|
79
80
|
</component>
|
80
81
|
</q-td>
|
81
82
|
</template>
|
@@ -6,7 +6,6 @@ export * from "./listHelpers";
|
|
6
6
|
export * from "./tableColumns";
|
7
7
|
export { default as ActionMenu } from "./ActionMenu.vue";
|
8
8
|
export { default as ActionTable } from "./ActionTable.vue";
|
9
|
-
export { default as BatchActionMenu } from "./BatchActionMenu.vue";
|
10
9
|
export { default as EmptyTableState } from "./EmptyTableState.vue";
|
11
10
|
export { default as RenderComponent } from "./RenderComponent.vue";
|
12
11
|
export { default as TableSummaryRow } from "./TableSummaryRow.vue";
|
@@ -2,18 +2,30 @@ import { computed, ref, watch } from "vue";
|
|
2
2
|
import { getItem, setItem, waitForRef } from "../../helpers";
|
3
3
|
import { getFilterFromUrl } from "./listHelpers";
|
4
4
|
|
5
|
-
|
5
|
+
interface ListActionsOptions {
|
6
|
+
listRoute: Function;
|
7
|
+
summaryRoute?: Function;
|
8
|
+
filterFieldOptionsRoute?: Function;
|
9
|
+
moreRoute?: Function;
|
10
|
+
applyActionRoute?: Function;
|
11
|
+
itemDetailsRoute?: Function;
|
12
|
+
urlPattern?: RegExp;
|
13
|
+
filterDefaults?: Record<string, any>;
|
14
|
+
refreshFilters?: boolean;
|
15
|
+
}
|
16
|
+
|
17
|
+
|
18
|
+
export function useListActions(name: string, {
|
6
19
|
listRoute,
|
7
|
-
filterFieldOptionsRoute,
|
8
20
|
summaryRoute = null,
|
21
|
+
filterFieldOptionsRoute = null,
|
9
22
|
moreRoute = null,
|
10
23
|
applyActionRoute = null,
|
11
|
-
applyBatchActionRoute = null,
|
12
24
|
itemDetailsRoute = null,
|
13
25
|
refreshFilters = false,
|
14
26
|
urlPattern = null,
|
15
27
|
filterDefaults = {}
|
16
|
-
}) {
|
28
|
+
}: ListActionsOptions) {
|
17
29
|
let isInitialized = false;
|
18
30
|
const PAGE_SETTINGS_KEY = `${name}-pagination-settings`;
|
19
31
|
const pagedItems = ref(null);
|
@@ -60,23 +72,22 @@ export function useListActions(name, {
|
|
60
72
|
}
|
61
73
|
|
62
74
|
async function loadList() {
|
63
|
-
if (isInitialized)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
}
|
75
|
+
if (!isInitialized) return;
|
76
|
+
isLoadingList.value = true;
|
77
|
+
setPagedItems(await listRoute(pager.value));
|
78
|
+
isLoadingList.value = false;
|
68
79
|
}
|
69
80
|
|
70
81
|
async function loadSummary() {
|
71
|
-
if (summaryRoute
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
summary.value = await summaryRoute(summaryFilter);
|
78
|
-
isLoadingSummary.value = false;
|
82
|
+
if (!summaryRoute || !isInitialized) return;
|
83
|
+
|
84
|
+
isLoadingSummary.value = true;
|
85
|
+
const summaryFilter = { id: null, ...filter.value, ...globalFilter.value };
|
86
|
+
if (selectedRows.value.length) {
|
87
|
+
summaryFilter.id = selectedRows.value.map((row) => row.id);
|
79
88
|
}
|
89
|
+
summary.value = await summaryRoute(summaryFilter);
|
90
|
+
isLoadingSummary.value = false;
|
80
91
|
}
|
81
92
|
|
82
93
|
// Filter fields are the field values available for the currently applied filter on Creative Groups
|
@@ -89,6 +100,7 @@ export function useListActions(name, {
|
|
89
100
|
});
|
90
101
|
|
91
102
|
async function loadFilterFieldOptions() {
|
103
|
+
if (!filterFieldOptionsRoute || !isInitialized) return;
|
92
104
|
isLoadingFilters.value = true;
|
93
105
|
filterFieldOptions.value = await filterFieldOptionsRoute(filter.value);
|
94
106
|
isLoadingFilters.value = false;
|
@@ -240,21 +252,6 @@ export function useListActions(name, {
|
|
240
252
|
return result;
|
241
253
|
}
|
242
254
|
|
243
|
-
/**
|
244
|
-
* Applies an action to all selected items.
|
245
|
-
*/
|
246
|
-
const isApplyingBatchAction = ref(false);
|
247
|
-
|
248
|
-
async function applyBatchAction(input) {
|
249
|
-
isApplyingBatchAction.value = true;
|
250
|
-
const batchFilter = { id: selectedRows.value.map(r => r.id) };
|
251
|
-
const result = await applyBatchActionRoute(batchFilter, input);
|
252
|
-
isApplyingBatchAction.value = false;
|
253
|
-
await refreshAll();
|
254
|
-
|
255
|
-
return result;
|
256
|
-
}
|
257
|
-
|
258
255
|
// The active ad for viewing / editing in the Ad Form
|
259
256
|
const activeItem = ref(null);
|
260
257
|
// Controls the tab on the Ad Form
|
@@ -267,7 +264,7 @@ export function useListActions(name, {
|
|
267
264
|
*/
|
268
265
|
async function getActiveItemDetails() {
|
269
266
|
if (!activeItem.value) return;
|
270
|
-
|
267
|
+
|
271
268
|
const result = await itemDetailsRoute(activeItem.value);
|
272
269
|
|
273
270
|
// Only set the ad details if we are the response for the currently loaded item
|
@@ -337,11 +334,11 @@ export function useListActions(name, {
|
|
337
334
|
activeItem.value = pagedItems.value.data[nextIndex];
|
338
335
|
}
|
339
336
|
|
340
|
-
//
|
341
|
-
|
337
|
+
// Initialize the list actions and load settings, lists, summaries, filter fields, etc.
|
338
|
+
function initialize() {
|
342
339
|
isInitialized = true;
|
343
340
|
loadSettings();
|
344
|
-
}
|
341
|
+
}
|
345
342
|
|
346
343
|
return {
|
347
344
|
// State
|
@@ -359,18 +356,17 @@ export function useListActions(name, {
|
|
359
356
|
pager,
|
360
357
|
quasarPagination,
|
361
358
|
isApplyingActionToItem,
|
362
|
-
isApplyingBatchAction,
|
363
359
|
activeItem,
|
364
360
|
formTab,
|
365
361
|
|
366
362
|
// Actions
|
363
|
+
initialize,
|
367
364
|
loadSummary,
|
368
365
|
resetPaging,
|
369
366
|
loadList,
|
370
367
|
loadMore,
|
371
368
|
refreshAll,
|
372
369
|
applyAction,
|
373
|
-
applyBatchAction,
|
374
370
|
getNextItem,
|
375
371
|
openItemForm,
|
376
372
|
applyFilterFromUrl
|
@@ -45,7 +45,15 @@ async function onConfirmAction(input) {
|
|
45
45
|
const result = await props.action.onAction(props.targets, input);
|
46
46
|
isSaving.value = false;
|
47
47
|
|
48
|
-
if (
|
48
|
+
if (result.success) {
|
49
|
+
FlashMessages.success(`The update was successful`);
|
50
|
+
|
51
|
+
if (props.action.onSuccess) {
|
52
|
+
await props.action.onSuccess(result, props.targets, input);
|
53
|
+
}
|
54
|
+
|
55
|
+
emit('done');
|
56
|
+
} else {
|
49
57
|
const errors = [];
|
50
58
|
if (result.errors) {
|
51
59
|
errors.push(...result.errors);
|
@@ -62,16 +70,8 @@ async function onConfirmAction(input) {
|
|
62
70
|
}
|
63
71
|
}
|
64
72
|
|
65
|
-
FlashMessages.success(`The update was successful`);
|
66
|
-
|
67
|
-
if (props.action.onSuccess) {
|
68
|
-
await props.action.onSuccess(result, props.targets, input);
|
69
|
-
}
|
70
|
-
|
71
73
|
if (props.action.onFinish) {
|
72
74
|
await props.action.onFinish(result, props.targets, input);
|
73
75
|
}
|
74
|
-
|
75
|
-
emit('done');
|
76
76
|
}
|
77
77
|
</script>
|
package/src/helpers/http.ts
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
export const request = {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
2
|
+
async get(url, options = {}) {
|
3
|
+
return fetch(url, {
|
4
|
+
method: "get",
|
5
|
+
headers: {
|
6
|
+
Accept: "application/json",
|
7
|
+
"Content-Type": "application/json"
|
8
|
+
},
|
9
|
+
...options
|
10
|
+
}).then((r) => r.json());
|
11
|
+
},
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
13
|
+
async post(url, data = {}, options = {}) {
|
14
|
+
return fetch(url, {
|
15
|
+
method: "post",
|
16
|
+
body: JSON.stringify(data),
|
17
|
+
headers: {
|
18
|
+
Accept: "application/json",
|
19
|
+
"Content-Type": "application/json"
|
20
|
+
},
|
21
|
+
...options
|
22
|
+
}).then((r) => r.json());
|
23
|
+
}
|
24
24
|
};
|
25
25
|
|
26
26
|
/**
|
@@ -36,19 +36,19 @@ export const request = {
|
|
36
36
|
* @returns {Promise<void>}
|
37
37
|
*/
|
38
38
|
export async function fetchResourceListWithSelected(fetchFn, list, id, filter) {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
// First make sure we have the selected record, so we can always add it to the list
|
40
|
+
let selectedResource;
|
41
|
+
if (id) {
|
42
|
+
selectedResource = list.value.find((c) => c.id === id) || (await fetchFn({ id }))[0];
|
43
|
+
}
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
// Get the filtered campaign list
|
46
|
+
list.value = await fetchFn(filter);
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
// If our selected campaign is not in the filtered list, add it
|
49
|
+
if (selectedResource && !list.value.find((c) => c.id === id)) {
|
50
|
+
list.value.push(selectedResource);
|
51
|
+
}
|
52
52
|
}
|
53
53
|
|
54
54
|
/**
|
@@ -57,6 +57,6 @@ export async function fetchResourceListWithSelected(fetchFn, list, id, filter) {
|
|
57
57
|
* @param url
|
58
58
|
*/
|
59
59
|
export function getUrlParam(key, url = undefined) {
|
60
|
-
|
61
|
-
|
60
|
+
const params = new URLSearchParams(url?.replace(/.*\?/, "") || window.location.search);
|
61
|
+
return params.get(key);
|
62
62
|
}
|
@@ -12,6 +12,17 @@ export const actionTargets = ref([]);
|
|
12
12
|
* @returns {{performAction(name, targets): Promise<void>}}
|
13
13
|
*/
|
14
14
|
export function usePerformAction(actions: any[]) {
|
15
|
+
|
16
|
+
function filterActions(filters) {
|
17
|
+
let filteredActions = [...actions];
|
18
|
+
|
19
|
+
for (const filter of Object.keys(filters)) {
|
20
|
+
const filterValue = filters[filter];
|
21
|
+
filteredActions = filteredActions.filter(a => a[filter] === filterValue || (Array.isArray(filterValue) && filterValue.includes(a[filter])));
|
22
|
+
}
|
23
|
+
return filteredActions;
|
24
|
+
}
|
25
|
+
|
15
26
|
return {
|
16
27
|
/**
|
17
28
|
* Perform an action on a set of targets
|
@@ -31,7 +42,8 @@ export function usePerformAction(actions: any[]) {
|
|
31
42
|
await performAction({ ...action, ...options }, targets);
|
32
43
|
},
|
33
44
|
|
34
|
-
|
45
|
+
actions,
|
46
|
+
filterActions,
|
35
47
|
};
|
36
48
|
}
|
37
49
|
|
@@ -1,60 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<div>
|
3
|
-
<PopoverMenu
|
4
|
-
class="bg-neutral-plus-6 px-4 h-full flex"
|
5
|
-
:items="items"
|
6
|
-
:disabled="selectedRows.length === 0"
|
7
|
-
@action="onAction"
|
8
|
-
/>
|
9
|
-
<q-tooltip v-if="selectedRows.length === 0">
|
10
|
-
Batch actions require a selection
|
11
|
-
</q-tooltip>
|
12
|
-
<slot>
|
13
|
-
<Component
|
14
|
-
:is="activeComponent.is"
|
15
|
-
v-if="activeComponent"
|
16
|
-
v-bind="activeComponent.props"
|
17
|
-
:is-saving="isSaving"
|
18
|
-
@close="activeAction = false"
|
19
|
-
@confirm="onConfirmAction"
|
20
|
-
/>
|
21
|
-
</slot>
|
22
|
-
</div>
|
23
|
-
</template>
|
24
|
-
<script setup>
|
25
|
-
import { computed, ref } from 'vue';
|
26
|
-
import { PopoverMenu } from '../Utility';
|
27
|
-
|
28
|
-
const emit = defineEmits(['action']);
|
29
|
-
const props = defineProps({
|
30
|
-
items: {
|
31
|
-
type: Array,
|
32
|
-
required: true
|
33
|
-
},
|
34
|
-
selectedRows: {
|
35
|
-
type: Array,
|
36
|
-
required: true
|
37
|
-
},
|
38
|
-
applyBatchAction: {
|
39
|
-
type: Function,
|
40
|
-
required: true
|
41
|
-
},
|
42
|
-
isSaving: Boolean
|
43
|
-
});
|
44
|
-
|
45
|
-
|
46
|
-
const activeAction = ref(null);
|
47
|
-
const activeComponent = computed(() => (props.items.find(i => i.action === activeAction.value)?.component || (() => null))(props.selectedRows));
|
48
|
-
|
49
|
-
function onAction(action) {
|
50
|
-
activeAction.value = action;
|
51
|
-
emit('action', action);
|
52
|
-
}
|
53
|
-
async function onConfirmAction(input) {
|
54
|
-
const result = await props.applyBatchAction(input || activeComponent.value.input());
|
55
|
-
|
56
|
-
if (result?.success) {
|
57
|
-
activeAction.value = null;
|
58
|
-
}
|
59
|
-
}
|
60
|
-
</script>
|