quasar-ui-danx 0.0.27 → 0.0.29
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 +7 -75
- package/src/components/ActionTable/Filters/index.ts +1 -1
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +20 -0
- package/src/components/ActionTable/Layouts/index.ts +1 -0
- package/src/components/ActionTable/index.ts +1 -0
- package/src/components/ActionTable/listActions.ts +2 -2
- package/src/components/ActionTable/listHelpers.ts +2 -19
- package/src/components/Utility/Popovers/PopoverMenu.vue +3 -3
- package/src/components/Utility/Tools/ActionPerformerTool.vue +77 -0
- package/src/components/Utility/Tools/index.ts +1 -0
- package/src/components/Utility/index.ts +1 -0
- package/src/helpers/index.ts +1 -0
- package/src/helpers/performAction.ts +58 -0
- package/src/helpers/utils.ts +34 -15
package/package.json
CHANGED
@@ -1,23 +1,12 @@
|
|
1
1
|
<template>
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
/>
|
8
|
-
<Component
|
9
|
-
v-if="confirmDialog"
|
10
|
-
:is="confirmDialog.is"
|
11
|
-
v-bind="confirmDialog.props"
|
12
|
-
:is-saving="isSaving"
|
13
|
-
@close="onCancel"
|
14
|
-
@confirm="onConfirmAction"
|
15
|
-
/>
|
16
|
-
</div>
|
2
|
+
<PopoverMenu
|
3
|
+
class="px-4 h-full flex"
|
4
|
+
:items="items"
|
5
|
+
@action-item="onAction"
|
6
|
+
/>
|
17
7
|
</template>
|
18
8
|
<script setup>
|
19
|
-
import {
|
20
|
-
import { FlashMessages } from '../../helpers';
|
9
|
+
import { performAction } from '../../helpers';
|
21
10
|
import { PopoverMenu } from '../Utility';
|
22
11
|
|
23
12
|
const emit = defineEmits(['action']);
|
@@ -33,65 +22,8 @@ const props = defineProps({
|
|
33
22
|
});
|
34
23
|
|
35
24
|
|
36
|
-
const activeAction = shallowRef(null);
|
37
|
-
const confirmDialog = shallowRef(null);
|
38
|
-
const isSaving = ref(false);
|
39
|
-
|
40
25
|
function onAction(item) {
|
41
26
|
emit('action', item);
|
42
|
-
|
43
|
-
activeAction.value = item;
|
44
|
-
|
45
|
-
if (item.confirmDialog) {
|
46
|
-
confirmDialog.value = typeof item.confirmDialog === 'function' ? item.confirmDialog(props.rows) : item.confirmDialog;
|
47
|
-
} else {
|
48
|
-
console.log('handle default action');
|
49
|
-
}
|
50
|
-
}
|
51
|
-
|
52
|
-
function onCancel() {
|
53
|
-
activeAction.value = null;
|
54
|
-
confirmDialog.value = null;
|
27
|
+
performAction(item, props.rows);
|
55
28
|
}
|
56
|
-
|
57
|
-
async function onConfirmAction(input) {
|
58
|
-
if (!activeAction.value.onAction) {
|
59
|
-
throw new Error('No onAction handler found for the selected action:' + activeAction.value.action);
|
60
|
-
}
|
61
|
-
|
62
|
-
isSaving.value = true;
|
63
|
-
const result = await activeAction.value.onAction(input, props.rows);
|
64
|
-
isSaving.value = false;
|
65
|
-
|
66
|
-
if (!result.success) {
|
67
|
-
const errors = [];
|
68
|
-
if (result.errors) {
|
69
|
-
errors.push(...result.errors);
|
70
|
-
} else if (result.error) {
|
71
|
-
errors.push(result.error.message);
|
72
|
-
} else {
|
73
|
-
errors.push('An unknown error occurred. Please try again later.');
|
74
|
-
}
|
75
|
-
|
76
|
-
FlashMessages.combine('error', errors);
|
77
|
-
|
78
|
-
if (activeAction.value.onError) {
|
79
|
-
await activeAction.value.onError(result, input);
|
80
|
-
}
|
81
|
-
}
|
82
|
-
|
83
|
-
FlashMessages.success(`The update was successful`);
|
84
|
-
|
85
|
-
if (activeAction.value.onSuccess) {
|
86
|
-
await activeAction.value.onSuccess(result, input);
|
87
|
-
}
|
88
|
-
|
89
|
-
if (activeAction.value.onFinish) {
|
90
|
-
await activeAction.value.onFinish();
|
91
|
-
}
|
92
|
-
|
93
|
-
confirmDialog.value = null;
|
94
|
-
activeAction.value = null;
|
95
|
-
}
|
96
|
-
|
97
29
|
</script>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
export {
|
2
2
|
default as CollapsableFiltersSidebar
|
3
3
|
} from "./CollapsableFiltersSidebar.vue";
|
4
|
-
export { default as FilterFieldList } from "
|
4
|
+
export { default as FilterFieldList } from "./FilterFieldList.vue";
|
5
5
|
export { default as FilterListToggle } from "./FilterListToggle.vue";
|
6
6
|
export { default as FilterToolbarLayout } from "./FilterToolbarLayout.vue";
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="flex flex-grow flex-col flex-nowrap overflow-hidden h-full bg-white">
|
3
|
+
<slot name="top" />
|
4
|
+
<slot name="toolbar" />
|
5
|
+
<div class="flex flex-nowrap flex-grow overflow-hidden w-full">
|
6
|
+
<slot name="filters" />
|
7
|
+
<slot />
|
8
|
+
</div>
|
9
|
+
<ActionPerformerTool
|
10
|
+
v-if="activeAction"
|
11
|
+
:targets="actionTargets"
|
12
|
+
:action="activeAction"
|
13
|
+
@done="clearAction"
|
14
|
+
/>
|
15
|
+
</div>
|
16
|
+
</template>
|
17
|
+
<script setup>
|
18
|
+
import { actionTargets, activeAction, clearAction } from '../../../helpers';
|
19
|
+
import { ActionPerformerTool } from '../../Utility';
|
20
|
+
</script>
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default as ActionTableLayout } from "./ActionTableLayout.vue";
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { computed, ref, watch } from "vue";
|
2
|
-
import { getItem, setItem } from "../../helpers";
|
3
|
-
import { getFilterFromUrl
|
2
|
+
import { getItem, setItem, waitForRef } from "../../helpers";
|
3
|
+
import { getFilterFromUrl } from "./listHelpers";
|
4
4
|
|
5
5
|
export function useListActions(name, {
|
6
6
|
listRoute,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { onMounted
|
1
|
+
import { onMounted } from "vue";
|
2
2
|
import { getUrlParam } from "../../helpers";
|
3
3
|
|
4
4
|
export function registerStickyScrolling(tableRef) {
|
@@ -37,29 +37,12 @@ export function mapSortBy(pagination, columns) {
|
|
37
37
|
];
|
38
38
|
}
|
39
39
|
|
40
|
-
/**
|
41
|
-
* Wait for a ref to have a value and then resolve the promise
|
42
|
-
*
|
43
|
-
* @param ref
|
44
|
-
* @param value
|
45
|
-
* @returns {Promise<void>}
|
46
|
-
*/
|
47
|
-
export function waitForRef(ref, value) {
|
48
|
-
return new Promise<void>((resolve) => {
|
49
|
-
watch(ref, (newValue) => {
|
50
|
-
if (newValue === value) {
|
51
|
-
resolve();
|
52
|
-
}
|
53
|
-
});
|
54
|
-
});
|
55
|
-
}
|
56
|
-
|
57
40
|
/**
|
58
41
|
* Returns the filter from the URL if it is set
|
59
42
|
* @param url
|
60
43
|
* @param allowedKeys
|
61
44
|
*/
|
62
|
-
export function getFilterFromUrl(url, allowedKeys = null) {
|
45
|
+
export function getFilterFromUrl(url: string, allowedKeys = null) {
|
63
46
|
const filter = {};
|
64
47
|
const urlFilter = getUrlParam("filter", url);
|
65
48
|
if (urlFilter) {
|
@@ -34,7 +34,7 @@
|
|
34
34
|
</a>
|
35
35
|
<q-item
|
36
36
|
v-else
|
37
|
-
:key="item.action"
|
37
|
+
:key="item.name || item.action"
|
38
38
|
clickable
|
39
39
|
:class="item.class"
|
40
40
|
@click="onAction(item)"
|
@@ -55,7 +55,7 @@ defineProps({
|
|
55
55
|
type: Array,
|
56
56
|
required: true,
|
57
57
|
validator(items) {
|
58
|
-
return items.every((item) => item.label && (item.url || item.action));
|
58
|
+
return items.every((item) => item.label && (item.url || item.action || item.name));
|
59
59
|
}
|
60
60
|
},
|
61
61
|
disabled: Boolean,
|
@@ -63,7 +63,7 @@ defineProps({
|
|
63
63
|
});
|
64
64
|
|
65
65
|
function onAction(item) {
|
66
|
-
emit('action', item.action);
|
66
|
+
emit('action', item.name || item.action);
|
67
67
|
emit('action-item', item);
|
68
68
|
}
|
69
69
|
</script>
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<Component
|
4
|
+
v-if="confirmDialog"
|
5
|
+
:is="confirmDialog.is"
|
6
|
+
v-bind="confirmDialog.props"
|
7
|
+
:is-saving="isSaving"
|
8
|
+
@confirm="onConfirmAction"
|
9
|
+
@close="$emit('done')"
|
10
|
+
/>
|
11
|
+
</div>
|
12
|
+
</template>
|
13
|
+
<script setup>
|
14
|
+
import { onMounted, ref, shallowRef } from 'vue';
|
15
|
+
import { FlashMessages } from '../../../helpers';
|
16
|
+
|
17
|
+
const emit = defineEmits(['done']);
|
18
|
+
const props = defineProps({
|
19
|
+
action: {
|
20
|
+
type: Object,
|
21
|
+
required: true
|
22
|
+
},
|
23
|
+
targets: {
|
24
|
+
type: Array,
|
25
|
+
required: true
|
26
|
+
}
|
27
|
+
});
|
28
|
+
|
29
|
+
const confirmDialog = shallowRef(props.action.confirmDialog ? props.action.confirmDialog(props.targets) : null);
|
30
|
+
const isSaving = ref(null);
|
31
|
+
|
32
|
+
onMounted(async () => {
|
33
|
+
// If there is no dialog, we auto-confirm the action
|
34
|
+
if (!confirmDialog.value) {
|
35
|
+
await onConfirmAction();
|
36
|
+
}
|
37
|
+
});
|
38
|
+
|
39
|
+
async function onConfirmAction(input) {
|
40
|
+
if (!props.action.onAction) {
|
41
|
+
throw new Error('No onAction handler found for the selected action:' + props.action.name);
|
42
|
+
}
|
43
|
+
|
44
|
+
isSaving.value = true;
|
45
|
+
const result = await props.action.onAction(props.targets, input);
|
46
|
+
isSaving.value = false;
|
47
|
+
|
48
|
+
if (!result.success) {
|
49
|
+
const errors = [];
|
50
|
+
if (result.errors) {
|
51
|
+
errors.push(...result.errors);
|
52
|
+
} else if (result.error) {
|
53
|
+
errors.push(result.error.message);
|
54
|
+
} else {
|
55
|
+
errors.push('An unknown error occurred. Please try again later.');
|
56
|
+
}
|
57
|
+
|
58
|
+
FlashMessages.combine('error', errors);
|
59
|
+
|
60
|
+
if (props.action.onError) {
|
61
|
+
await props.action.onError(result, props.targets, input);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
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
|
+
if (props.action.onFinish) {
|
72
|
+
await props.action.onFinish(result, props.targets, input);
|
73
|
+
}
|
74
|
+
|
75
|
+
emit('done');
|
76
|
+
}
|
77
|
+
</script>
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default as ActionPerformerTool } from "./ActionPerformerTool.vue";
|
package/src/helpers/index.ts
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
import { ref } from "vue";
|
2
|
+
import { waitForRef } from "./index";
|
3
|
+
|
4
|
+
export const activeAction = ref(null);
|
5
|
+
export const actionTargets = ref([]);
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Hook to perform an action on a set of targets
|
9
|
+
* This helper allows you to perform actions by name on a set of targets using a provided list of actions
|
10
|
+
*
|
11
|
+
* @param actions
|
12
|
+
* @returns {{performAction(name, targets): Promise<void>}}
|
13
|
+
*/
|
14
|
+
export function usePerformAction(actions: any[]) {
|
15
|
+
return {
|
16
|
+
/**
|
17
|
+
* Perform an action on a set of targets
|
18
|
+
*
|
19
|
+
* @param name - can either be a string or an action object
|
20
|
+
* @param targets - an array of targets (or a single target object)
|
21
|
+
* @returns {Promise<void>}
|
22
|
+
*/
|
23
|
+
async performAction(name, targets) {
|
24
|
+
const action = typeof name === "string" ? actions.find(a => a.name === name) : name;
|
25
|
+
if (!action) {
|
26
|
+
throw new Error(`Unknown action: ${name}`);
|
27
|
+
}
|
28
|
+
targets = Array.isArray(targets) ? targets : [targets];
|
29
|
+
|
30
|
+
await performAction(action, targets);
|
31
|
+
}
|
32
|
+
};
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Perform an action on a set of targets
|
37
|
+
*
|
38
|
+
* NOTE: This function and variables should be used w/ the ActionPerformerTool - make sure to use a Layout that has
|
39
|
+
* rendered this component so the actions will be performed
|
40
|
+
*
|
41
|
+
* @param action
|
42
|
+
* @param targets
|
43
|
+
* @returns {Promise<void>}
|
44
|
+
*/
|
45
|
+
export async function performAction(action: any, targets: any[]): Promise<void> {
|
46
|
+
activeAction.value = action;
|
47
|
+
actionTargets.value = targets;
|
48
|
+
await waitForRef(activeAction, null);
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Clear the active action and targets - (note: this will tear down any dialogs / rendered components) triggered by the
|
53
|
+
* ActionPerformerTool
|
54
|
+
*/
|
55
|
+
export function clearAction() {
|
56
|
+
activeAction.value = null;
|
57
|
+
actionTargets.value = [];
|
58
|
+
}
|
package/src/helpers/utils.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { watch } from "vue";
|
2
|
+
|
1
3
|
/**
|
2
4
|
* Sleep function to be used in conjuction with async await:
|
3
5
|
*
|
@@ -7,7 +9,24 @@
|
|
7
9
|
* @returns {Promise<any>}
|
8
10
|
*/
|
9
11
|
export function sleep(delay) {
|
10
|
-
|
12
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Wait for a ref to have a value and then resolve the promise
|
17
|
+
*
|
18
|
+
* @param ref
|
19
|
+
* @param value
|
20
|
+
* @returns {Promise<void>}
|
21
|
+
*/
|
22
|
+
export function waitForRef(ref, value) {
|
23
|
+
return new Promise<void>((resolve) => {
|
24
|
+
watch(ref, (newValue) => {
|
25
|
+
if (newValue === value) {
|
26
|
+
resolve();
|
27
|
+
}
|
28
|
+
});
|
29
|
+
});
|
11
30
|
}
|
12
31
|
|
13
32
|
/**
|
@@ -18,7 +37,7 @@ export function sleep(delay) {
|
|
18
37
|
* @returns {number}
|
19
38
|
*/
|
20
39
|
export function minmax(min, max, value) {
|
21
|
-
|
40
|
+
return Math.max(min, Math.min(max, value));
|
22
41
|
}
|
23
42
|
|
24
43
|
/**
|
@@ -27,7 +46,7 @@ export function minmax(min, max, value) {
|
|
27
46
|
* @returns {number}
|
28
47
|
*/
|
29
48
|
export function metersToMiles(meters) {
|
30
|
-
|
49
|
+
return meters * 0.000621371;
|
31
50
|
}
|
32
51
|
|
33
52
|
/**
|
@@ -36,7 +55,7 @@ export function metersToMiles(meters) {
|
|
36
55
|
* @returns {number}
|
37
56
|
*/
|
38
57
|
export function milesToMeters(miles) {
|
39
|
-
|
58
|
+
return miles / 0.000621371;
|
40
59
|
}
|
41
60
|
|
42
61
|
/**
|
@@ -45,19 +64,19 @@ export function milesToMeters(miles) {
|
|
45
64
|
* @returns {null|{lng: number, lat: number}}
|
46
65
|
*/
|
47
66
|
export function parseCoords(location) {
|
48
|
-
|
67
|
+
const latLong = location.split(",");
|
49
68
|
|
50
|
-
|
51
|
-
|
52
|
-
|
69
|
+
if (latLong.length === 2) {
|
70
|
+
const lat = parseFloat(latLong[0].trim());
|
71
|
+
const lng = parseFloat(latLong[1].trim());
|
53
72
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
73
|
+
if (!isNaN(lat) && !isNaN(lng)) {
|
74
|
+
return {
|
75
|
+
lat,
|
76
|
+
lng,
|
77
|
+
};
|
78
|
+
}
|
59
79
|
}
|
60
|
-
}
|
61
80
|
|
62
|
-
|
81
|
+
return null;
|
63
82
|
}
|