quasar-ui-danx 0.0.28 → 0.0.30

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -1,15 +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
- </div>
2
+ <PopoverMenu
3
+ class="px-4 h-full flex"
4
+ :items="items"
5
+ @action-item="onAction"
6
+ />
9
7
  </template>
10
8
  <script setup>
11
- import { ref, shallowRef } from 'vue';
12
- import { FlashMessages, performAction } from '../../helpers';
9
+ import { performAction } from '../../helpers';
13
10
  import { PopoverMenu } from '../Utility';
14
11
 
15
12
  const emit = defineEmits(['action']);
@@ -25,59 +22,8 @@ const props = defineProps({
25
22
  });
26
23
 
27
24
 
28
- const activeAction = shallowRef(null);
29
- const confirmDialog = shallowRef(null);
30
- const isSaving = ref(false);
31
-
32
25
  function onAction(item) {
33
26
  emit('action', item);
34
-
35
27
  performAction(item, props.rows);
36
28
  }
37
-
38
- function onCancel() {
39
- activeAction.value = null;
40
- confirmDialog.value = null;
41
- }
42
-
43
- async function onConfirmAction(input) {
44
- if (!activeAction.value.onAction) {
45
- throw new Error('No onAction handler found for the selected action:' + activeAction.value.action);
46
- }
47
-
48
- isSaving.value = true;
49
- const result = await activeAction.value.onAction(input, props.rows);
50
- isSaving.value = false;
51
-
52
- if (!result.success) {
53
- const errors = [];
54
- if (result.errors) {
55
- errors.push(...result.errors);
56
- } else if (result.error) {
57
- errors.push(result.error.message);
58
- } else {
59
- errors.push('An unknown error occurred. Please try again later.');
60
- }
61
-
62
- FlashMessages.combine('error', errors);
63
-
64
- if (activeAction.value.onError) {
65
- await activeAction.value.onError(result, input);
66
- }
67
- }
68
-
69
- FlashMessages.success(`The update was successful`);
70
-
71
- if (activeAction.value.onSuccess) {
72
- await activeAction.value.onSuccess(result, input);
73
- }
74
-
75
- if (activeAction.value.onFinish) {
76
- await activeAction.value.onFinish();
77
- }
78
-
79
- confirmDialog.value = null;
80
- activeAction.value = null;
81
- }
82
-
83
29
  </script>
@@ -6,10 +6,15 @@
6
6
  <slot name="filters" />
7
7
  <slot />
8
8
  </div>
9
- <ActionPerformerTool v-if="activeAction" :targets="actionTargets" :action="activeAction" />
9
+ <ActionPerformerTool
10
+ v-if="activeAction"
11
+ :targets="actionTargets"
12
+ :action="activeAction"
13
+ @done="clearAction"
14
+ />
10
15
  </div>
11
16
  </template>
12
17
  <script setup>
13
- import { actionTargets, activeAction } from '../../../helpers';
18
+ import { actionTargets, activeAction, clearAction } from '../../../helpers';
14
19
  import { ActionPerformerTool } from '../../Utility';
15
20
  </script>
@@ -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,
@@ -165,7 +165,7 @@ export function useListActions(name, {
165
165
  * @returns {Promise<Awaited<void>[]>}
166
166
  */
167
167
  async function refreshAll() {
168
- return Promise.all([loadList(), loadSummary(), loadFilterFieldOptions()]);
168
+ return Promise.all([loadList(), loadSummary(), loadFilterFieldOptions(), getActiveItemDetails()]);
169
169
  }
170
170
 
171
171
  /**
@@ -260,19 +260,30 @@ export function useListActions(name, {
260
260
  // Controls the tab on the Ad Form
261
261
  const formTab = ref("general");
262
262
 
263
+ /**
264
+ * Gets the additional details for the currently active item.
265
+ * (ie: data that is not normally loaded in the list because it is not needed for the list view)
266
+ * @returns {Promise<void>}
267
+ */
268
+ async function getActiveItemDetails() {
269
+ if (!activeItem.value) return;
270
+
271
+ const result = await itemDetailsRoute(activeItem.value);
272
+
273
+ // Only set the ad details if we are the response for the currently loaded item
274
+ // NOTE: race conditions might allow the finished loading item to be different to the currently
275
+ // requested item
276
+ if (result?.id === activeItem.value?.id) {
277
+ activeItem.value = result;
278
+ }
279
+ }
280
+
263
281
  // Whenever the active item changes, fill the additional item details
264
282
  // (ie: tasks, verifications, creatives, etc.)
265
283
  if (itemDetailsRoute) {
266
284
  watch(() => activeItem.value, async (newItem, oldItem) => {
267
285
  if (newItem && oldItem?.id !== newItem.id) {
268
- const result = await itemDetailsRoute(newItem);
269
-
270
- // Only set the ad details if we are the response for the currently loaded item
271
- // NOTE: race conditions might allow the finished loading item to be different to the currently
272
- // requested item
273
- if (result?.id === activeItem.value?.id) {
274
- activeItem.value = result;
275
- }
286
+ await getActiveItemDetails();
276
287
  }
277
288
  });
278
289
  }
@@ -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>
@@ -1,11 +1,20 @@
1
1
  <template>
2
2
  <div>
3
- <Component v-if="confirmDialog" :is="confirmDialog" :is-saving="isSaving" @confirm="onConfirmAction" />
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
+ />
4
11
  </div>
5
12
  </template>
6
13
  <script setup>
7
14
  import { onMounted, ref, shallowRef } from 'vue';
15
+ import { FlashMessages } from '../../../helpers';
8
16
 
17
+ const emit = defineEmits(['done']);
9
18
  const props = defineProps({
10
19
  action: {
11
20
  type: Object,
@@ -21,22 +30,48 @@ const confirmDialog = shallowRef(props.action.confirmDialog ? props.action.confi
21
30
  const isSaving = ref(null);
22
31
 
23
32
  onMounted(async () => {
24
- console.log('mounting action', props.action, props.targets);
25
33
  // If there is no dialog, we auto-confirm the action
26
34
  if (!confirmDialog.value) {
27
- onConfirmAction();
35
+ await onConfirmAction();
28
36
  }
29
37
  });
30
38
 
31
- function onConfirmAction(input) {
32
- console.log('action confirmed', input);
39
+ async function onConfirmAction(input) {
33
40
  if (!props.action.onAction) {
34
41
  throw new Error('No onAction handler found for the selected action:' + props.action.name);
35
42
  }
36
43
 
37
44
  isSaving.value = true;
38
- props.action.onAction().then(() => {
39
- isSaving.value = false;
40
- });
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');
41
76
  }
42
77
  </script>
@@ -1,10 +1,59 @@
1
1
  import { ref } from "vue";
2
+ import { waitForRef } from "./index";
2
3
 
3
4
  export const activeAction = ref(null);
4
5
  export const actionTargets = ref([]);
5
6
 
6
- export async function performAction(action, targets) {
7
- console.log("performing action", action, targets);
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
+ * @param options
22
+ * @returns {Promise<void>}
23
+ */
24
+ async performAction(name, targets, options = {}) {
25
+ const action = typeof name === "string" ? actions.find(a => a.name === name) : name;
26
+ if (!action) {
27
+ throw new Error(`Unknown action: ${name}`);
28
+ }
29
+ targets = Array.isArray(targets) ? targets : [targets];
30
+
31
+ await performAction({ ...action, ...options }, targets);
32
+ }
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Perform an action on a set of targets
38
+ *
39
+ * NOTE: This function and variables should be used w/ the ActionPerformerTool - make sure to use a Layout that has
40
+ * rendered this component so the actions will be performed
41
+ *
42
+ * @param action
43
+ * @param targets
44
+ * @returns {Promise<void>}
45
+ */
46
+ export async function performAction(action: any, targets: any[]): Promise<void> {
8
47
  activeAction.value = action;
9
48
  actionTargets.value = targets;
49
+ await waitForRef(activeAction, null);
50
+ }
51
+
52
+ /**
53
+ * Clear the active action and targets - (note: this will tear down any dialogs / rendered components) triggered by the
54
+ * ActionPerformerTool
55
+ */
56
+ export function clearAction() {
57
+ activeAction.value = null;
58
+ actionTargets.value = [];
10
59
  }
@@ -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
  }