quasar-ui-danx 0.0.27 → 0.0.29

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.0.27",
3
+ "version": "0.0.29",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -1,23 +1,12 @@
1
1
  <template>
2
- <div>
3
- <PopoverMenu
4
- class="px-4 h-full flex"
5
- :items="items"
6
- @action-item="onAction"
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 { ref, shallowRef } from 'vue';
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 "src/components/ActionTable/Filters/FilterFieldList.vue";
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,5 +1,6 @@
1
1
  export * from "./Filters";
2
2
  export * from "./Form";
3
+ export * from "./Layouts";
3
4
  export * from "./listActions";
4
5
  export * from "./listHelpers";
5
6
  export * from "./tableColumns";
@@ -1,6 +1,6 @@
1
1
  import { computed, ref, watch } from "vue";
2
- import { getItem, setItem } from "../../helpers";
3
- import { getFilterFromUrl, waitForRef } from "./listHelpers";
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, watch } from "vue";
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";
@@ -4,4 +4,5 @@ export * from "./Files";
4
4
  export * from "./Formats";
5
5
  export * from "./Layouts";
6
6
  export * from "./Popovers";
7
+ export * from "./Tools";
7
8
  export * from "./Transitions";
@@ -9,6 +9,7 @@ export * from "./FlashMessages";
9
9
  export * from "./formats";
10
10
  export * from "./http";
11
11
  export * from "./multiFileUpload";
12
+ export * from "./performAction";
12
13
  export * from "./singleFileUpload";
13
14
  export * from "./storage";
14
15
  export * from "./utils";
@@ -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
+ }
@@ -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
- return new Promise((resolve) => setTimeout(resolve, delay));
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
- return Math.max(min, Math.min(max, value));
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
- return meters * 0.000621371;
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
- return miles / 0.000621371;
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
- const latLong = location.split(",");
67
+ const latLong = location.split(",");
49
68
 
50
- if (latLong.length === 2) {
51
- const lat = parseFloat(latLong[0].trim());
52
- const lng = parseFloat(latLong[1].trim());
69
+ if (latLong.length === 2) {
70
+ const lat = parseFloat(latLong[0].trim());
71
+ const lng = parseFloat(latLong[1].trim());
53
72
 
54
- if (!isNaN(lat) && !isNaN(lng)) {
55
- return {
56
- lat,
57
- lng,
58
- };
73
+ if (!isNaN(lat) && !isNaN(lng)) {
74
+ return {
75
+ lat,
76
+ lng,
77
+ };
78
+ }
59
79
  }
60
- }
61
80
 
62
- return null;
81
+ return null;
63
82
  }