quasar-ui-danx 0.0.41 → 0.0.43

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.41",
3
+ "version": "0.0.43",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -21,7 +21,7 @@ const props = defineProps({
21
21
  },
22
22
  target: {
23
23
  type: [Array, Object],
24
- required: true
24
+ default: () => []
25
25
  },
26
26
  tooltip: {
27
27
  type: String,
@@ -34,10 +34,13 @@ const props = defineProps({
34
34
  }
35
35
  });
36
36
 
37
- const hasTarget = computed(() => !!props.target?.length);
37
+ const hasTarget = computed(() => Array.isArray(props.target) ? props.target.length > 0 : !!props.target);
38
38
 
39
39
  const activeActions = computed(() => props.actions.filter(action => {
40
- if (action.enabled === undefined) return true;
41
- return typeof action.enabled === 'function' ? !!action.enabled(props.target) : !!action.enabled;
40
+ if (Array.isArray(props.target)) {
41
+ return action.batchEnabled ? action.batchEnabled(props.target) : true;
42
+ }
43
+
44
+ return action.enabled ? action.enabled(props.target) : true;
42
45
  }));
43
46
  </script>
@@ -56,12 +56,14 @@
56
56
  :style="getColumnStyle(rowProps.col)"
57
57
  @click="() => rowProps.col.onClick && rowProps.col.onClick(rowProps.row)"
58
58
  >
59
+ <RenderVNode
60
+ v-if="rowProps.col.vnode"
61
+ :vnode="rowProps.col.vnode(rowProps.row)"
62
+ />
59
63
  <RenderComponent
60
- v-if="rowProps.col.component"
64
+ v-else-if="rowProps.col.component"
61
65
  :params="[rowProps.row]"
62
66
  :component="rowProps.col.component"
63
- :text="rowProps.value"
64
- @action="$emit('action', $event)"
65
67
  />
66
68
  <div v-else-if="rowProps.col.fieldList">
67
69
  <div v-for="field in rowProps.col.fieldList" :key="field">
@@ -77,8 +79,8 @@
77
79
  <ActionMenu
78
80
  :actions="rowProps.col.actions"
79
81
  :target="rowProps.row"
80
- :loading="isSavingItem?.id === rowProps.row.id"
81
- @action="(action) => $emit('action', {action, target: rowProps.row})"
82
+ :loading="isSavingRow(rowProps.row)"
83
+ @action="(action) => $emit('action', action, rowProps.row)"
82
84
  />
83
85
  </div>
84
86
  </component>
@@ -95,10 +97,10 @@ import { ref } from 'vue';
95
97
  import { getItem, setItem } from '../../helpers';
96
98
  import { DragHandleIcon as RowResizeIcon } from '../../svg';
97
99
  import { HandleDraggable } from '../DragAndDrop';
98
- import { ActionInputComponent, mapSortBy, RenderComponent } from '../index';
100
+ import { ActionInputComponent, mapSortBy, RenderComponent, RenderVNode } from '../index';
99
101
  import { ActionMenu, EmptyTableState, registerStickyScrolling, TableSummaryRow } from './index';
100
102
 
101
- defineEmits(['action', 'filter', 'update:quasar-pagination', 'update:selected-rows']);
103
+ defineEmits(['action', 'update:quasar-pagination', 'update:selected-rows']);
102
104
  const props = defineProps({
103
105
  name: {
104
106
  type: String,
@@ -116,7 +118,7 @@ const props = defineProps({
116
118
  type: Object,
117
119
  required: true
118
120
  },
119
- isSavingItem: {
121
+ isSavingTarget: {
120
122
  type: Object,
121
123
  default: null
122
124
  },
@@ -158,6 +160,15 @@ function getColumnStyle(column) {
158
160
  }
159
161
  return null;
160
162
  }
163
+
164
+ function isSavingRow(row) {
165
+ if (!props.isSavingTarget) return false;
166
+
167
+ if (Array.isArray(props.isSavingTarget)) {
168
+ return !!props.isSavingTarget.find(t => t.id === row.id);
169
+ }
170
+ return props.isSavingTarget.id === row.id;
171
+ }
161
172
  </script>
162
173
 
163
174
  <style lang="scss" scoped>
@@ -259,11 +259,11 @@ export function useListControls(name: string, {
259
259
  * Opens the item's form with the given item and tab
260
260
  *
261
261
  * @param item
262
- * @param tab
262
+ * @param panel
263
263
  */
264
- function openItemForm(item, tab) {
264
+ function activatePanel(item, panel) {
265
265
  activeItem.value = item;
266
- activePanel.value = tab;
266
+ activePanel.value = panel;
267
267
  }
268
268
 
269
269
  /**
@@ -336,7 +336,7 @@ export function useListControls(name: string, {
336
336
  loadMore,
337
337
  refreshAll,
338
338
  getNextItem,
339
- openItemForm,
339
+ activatePanel,
340
340
  applyFilterFromUrl,
341
341
  setItemInPagedList
342
342
  };
@@ -1,9 +1,16 @@
1
1
  <template>
2
2
  <Component
3
+ v-if="content"
3
4
  :is="resolvedComponent.is"
4
5
  v-bind="{...resolvedComponent.props, ...overrideProps}"
5
6
  @action="$emit('action', $event)"
6
- >{{ resolvedComponent.value || resolvedComponent.props?.text || text }}</Component>
7
+ >{{ content }}</Component>
8
+ <Component
9
+ v-else
10
+ :is="resolvedComponent.is"
11
+ v-bind="{...resolvedComponent.props, ...overrideProps}"
12
+ @action="$emit('action', $event)"
13
+ />
7
14
  </template>
8
15
  <script setup>
9
16
  import { computed } from 'vue';
@@ -18,16 +25,13 @@ const props = defineProps({
18
25
  type: Array,
19
26
  default: () => []
20
27
  },
21
- text: {
22
- type: String,
23
- default: ''
24
- },
25
28
  overrideProps: {
26
29
  type: Object,
27
30
  default: () => ({})
28
31
  }
29
32
  });
30
33
 
34
+ const content = computed(() => resolvedComponent.value?.value || resolvedComponent.value?.props?.text);
31
35
  const resolvedComponent = computed(() => {
32
36
  if (typeof props.component === 'function') {
33
37
  return props.component(...props.params);
@@ -0,0 +1,6 @@
1
+ <script>
2
+ const RenderVNode = (props) => props.vnode;
3
+ RenderVNode.props = { vnode: { type: Object, required: true } };
4
+ RenderVNode.emits = ['action'];
5
+ export default RenderVNode;
6
+ </script>
@@ -1,2 +1,3 @@
1
1
  export { default as ActionInputComponent } from "./ActionInputComponent.vue";
2
2
  export { default as RenderComponent } from "./RenderComponent.vue";
3
+ export { default as RenderVNode } from "./RenderVNode.vue";
@@ -7,8 +7,10 @@ interface ActionOptions {
7
7
  menu?: boolean;
8
8
  batch?: boolean;
9
9
  category?: string;
10
+ class?: string;
10
11
  inputComponent?: (target: object[] | object) => any;
11
- enabled?: (target: object[] | object) => boolean;
12
+ enabled?: (target: object) => boolean;
13
+ batchEnabled?: (targets: object[]) => boolean;
12
14
  onAction?: (action: string | null, target: object, input: any) => Promise<any>;
13
15
  onBatchAction?: (action: string | null, targets: object[], input: any) => Promise<any>;
14
16
  onSuccess?: (action: string | null, targets: object, input: any) => any;
@@ -20,7 +22,7 @@ export const activeActionInput = shallowRef(null);
20
22
 
21
23
  /**
22
24
  * Hook to perform an action on a set of targets
23
- * This helper allows you applyActionto perform actions by name on a set of targets using a provided list of actions
25
+ * This helper allows you to perform actions by name on a set of targets using a provided list of actions
24
26
  *
25
27
  * @param actions
26
28
  * @param {ActionOptions} globalOptions
@@ -70,8 +72,6 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
70
72
  * TODO: HOW TO INTEGRATE optimistic updates and single item updates?
71
73
  */
72
74
  async applyAction(item, input, itemData = {}) {
73
- isSavingItem.value = item;
74
-
75
75
  setItemInPagedList({ ...item, ...input, ...itemData });
76
76
  const result = await applyActionRoute(item, input);
77
77
  if (result.success) {
@@ -86,7 +86,6 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
86
86
  activeItem.value = { ...activeItem.value, ...result.item };
87
87
  }
88
88
  }
89
- isSavingItem.value = null;
90
89
  return result;
91
90
  },
92
91
 
@@ -113,10 +112,19 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
113
112
  result = await new Promise((resolve, reject) => {
114
113
  activeActionInput.value = {
115
114
  component,
116
- confirm: async () => resolve(await onConfirmAction(action, target, input)),
117
- cancel: reject
115
+ confirm: async input => {
116
+ const result = await onConfirmAction(action, target, input);
117
+
118
+ // Only resolve when we have a non-error response, so we can show the error message w/o
119
+ // hiding the dialog / inputComponent
120
+ if (result === undefined || result === true || result?.success) {
121
+ resolve(result);
122
+ }
123
+ },
124
+ cancel: resolve
118
125
  };
119
126
  });
127
+
120
128
  activeActionInput.value = null;
121
129
  } else {
122
130
  result = await onConfirmAction(action, target, input);
@@ -146,16 +154,14 @@ async function onConfirmAction(action: ActionOptions, target: object[] | object,
146
154
  }
147
155
 
148
156
  // If there is no return value or the result marks it as successful, we show a success message
149
- if (result === undefined || result?.success) {
150
-
151
- if (result?.success) {
152
- FlashMessages.success(`The update was successful`);
157
+ if (result === undefined || result === true || result?.success) {
158
+ if (result?.success && Array.isArray(target)) {
159
+ FlashMessages.success(`Successfully performed action ${action.label} on ${target.length} items`);
153
160
  }
154
161
 
155
162
  if (action.onSuccess) {
156
163
  action.onSuccess(result, target, input);
157
164
  }
158
-
159
165
  } else {
160
166
  const errors = [];
161
167
  if (result.errors) {