quasar-ui-danx 0.0.24 → 0.0.26

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.24",
3
+ "version": "0.0.26",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -0,0 +1,97 @@
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>
17
+ </template>
18
+ <script setup>
19
+ import { ref, shallowRef } from 'vue';
20
+ import { FlashMessages } from '../../helpers';
21
+ import { PopoverMenu } from '../Utility';
22
+
23
+ const emit = defineEmits(['action']);
24
+ const props = defineProps({
25
+ items: {
26
+ type: Array,
27
+ required: true
28
+ },
29
+ rows: {
30
+ type: Array,
31
+ required: true
32
+ }
33
+ });
34
+
35
+
36
+ const activeAction = shallowRef(null);
37
+ const confirmDialog = shallowRef(null);
38
+ const isSaving = ref(false);
39
+
40
+ function onAction(item) {
41
+ 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;
55
+ }
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
+ </script>
@@ -12,7 +12,7 @@
12
12
  color="blue-base"
13
13
  @update:selected="$emit('update:selected-rows', $event)"
14
14
  @update:pagination="() => {}"
15
- @request="$emit('update:quasar-pagination', $event.pagination)"
15
+ @request="$emit('update:quasar-pagination', {...$event.pagination, __sort: mapSortBy($event.pagination, columns)})"
16
16
  >
17
17
  <template #no-data>
18
18
  <slot name="empty">
@@ -51,24 +51,30 @@
51
51
  <q-td :key="rowProps.key" :props="rowProps">
52
52
  <component
53
53
  :is="rowProps.col.onClick ? 'a' : 'div'"
54
+ class="flex items-center flex-nowrap"
54
55
  @click="() => rowProps.col.onClick && rowProps.col.onClick(rowProps.row)"
55
56
  >
56
- <template v-if="rowProps.col.component">
57
- <RenderComponent
58
- :row-props="rowProps"
59
- @action="$emit('action', $event)"
60
- />
61
- </template>
62
- <template v-else-if="rowProps.col.fieldList">
57
+ <RenderComponent
58
+ v-if="rowProps.col.component"
59
+ :row-props="rowProps"
60
+ @action="$emit('action', $event)"
61
+ />
62
+ <div v-else-if="rowProps.col.fieldList">
63
63
  <div v-for="field in rowProps.col.fieldList" :key="field">
64
64
  {{ rowProps.row[field] }}
65
65
  </div>
66
- </template>
67
- <template v-else>
66
+ </div>
67
+ <div v-else>
68
68
  <slot v-bind="{name: rowProps.col.name, row: rowProps.row, value: rowProps.value}">
69
69
  {{ rowProps.value }}
70
70
  </slot>
71
- </template>
71
+ </div>
72
+ <ActionMenu
73
+ v-if="rowProps.col.actions" class="ml-2"
74
+ :items="rowProps.col.actions"
75
+ :rows="[rowProps.row]"
76
+ @action="(action) => $emit('action', {action: action, row: rowProps.row})"
77
+ />
72
78
  </component>
73
79
  </q-td>
74
80
  </template>
@@ -79,7 +85,14 @@
79
85
  import { ref } from 'vue';
80
86
  import { DragHandleIcon as RowResizeIcon } from '../../svg';
81
87
  import { HandleDraggable } from '../DragAndDrop';
82
- import { EmptyTableState, registerStickyScrolling, RenderComponent, TableSummaryRow } from './index';
88
+ import {
89
+ ActionMenu,
90
+ EmptyTableState,
91
+ mapSortBy,
92
+ registerStickyScrolling,
93
+ RenderComponent,
94
+ TableSummaryRow
95
+ } from './index';
83
96
 
84
97
  defineEmits(['action', 'filter', 'update:quasar-pagination', 'update:selected-rows']);
85
98
  defineProps({
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <FilterGroupList
11
11
  :filter="filter"
12
- :filter-groups="filterGroups"
12
+ :filter-fields="filterFields"
13
13
  @update:filter="$emit('update:filter', $event)"
14
14
  />
15
15
  </CollapsableSidebar>
@@ -29,7 +29,7 @@ defineProps({
29
29
  type: Object,
30
30
  default: null
31
31
  },
32
- filterGroups: {
32
+ filterFields: {
33
33
  type: Array,
34
34
  default: () => []
35
35
  }
@@ -2,7 +2,7 @@
2
2
  <q-list>
3
3
  <div class="px-4 py-2 max-w-full">
4
4
  <template
5
- v-for="(group, index) in filterGroups"
5
+ v-for="(group, index) in filterFields"
6
6
  :key="'group-' + group.name"
7
7
  >
8
8
  <template v-if="group.flat">
@@ -34,12 +34,12 @@
34
34
  </FilterGroupItem>
35
35
 
36
36
  <q-separator
37
- v-if="index < (filterGroups.length - 1)"
37
+ v-if="index < (filterFields.length - 1)"
38
38
  class="my-2"
39
39
  />
40
40
  </template>
41
41
  </div>
42
- </q-list>
42
+ </q-list>
43
43
  </template>
44
44
  <script setup>
45
45
  import { computed } from 'vue';
@@ -48,7 +48,7 @@ import FilterGroupItem from './FilterGroupItem';
48
48
 
49
49
  const emit = defineEmits(['update:filter']);
50
50
  const props = defineProps({
51
- filterGroups: {
51
+ filterFields: {
52
52
  type: Array,
53
53
  required: true
54
54
  },
@@ -61,7 +61,7 @@ const props = defineProps({
61
61
 
62
62
  const activeCountByGroup = computed(() => {
63
63
  const activeCountByGroup = {};
64
- for (const group of props.filterGroups) {
64
+ for (const group of props.filterFields) {
65
65
  activeCountByGroup[group.name] = group.fields.filter(field => props.filter[field.name] !== undefined).length;
66
66
  }
67
67
  return activeCountByGroup;
@@ -3,6 +3,7 @@ export * from "./Form";
3
3
  export * from "./listActions";
4
4
  export * from "./listHelpers";
5
5
  export * from "./tableColumns";
6
+ export { default as ActionMenu } from "./ActionMenu.vue";
6
7
  export { default as ActionTable } from "./ActionTable.vue";
7
8
  export { default as BatchActionMenu } from "./BatchActionMenu.vue";
8
9
  export { default as EmptyTableState } from "./EmptyTableState.vue";
@@ -1,6 +1,6 @@
1
1
  import { computed, ref, watch } from "vue";
2
2
  import { getItem, setItem } from "../../helpers";
3
- import { getFilterFromUrl, mapSortBy, waitForRef } from "./listHelpers";
3
+ import { getFilterFromUrl, waitForRef } from "./listHelpers";
4
4
 
5
5
  export function useListActions(name, {
6
6
  listRoute,
@@ -10,7 +10,6 @@ export function useListActions(name, {
10
10
  applyActionRoute = null,
11
11
  applyBatchActionRoute = null,
12
12
  itemDetailsRoute = null,
13
- columns = null,
14
13
  filterGroups = null,
15
14
  refreshFilters = false,
16
15
  urlPattern = null,
@@ -30,6 +29,7 @@ export function useListActions(name, {
30
29
  const filterActiveCount = computed(() => Object.keys(filter.value).filter(key => filter.value[key] !== undefined).length);
31
30
 
32
31
  const PAGING_DEFAULT = {
32
+ __sort: null,
33
33
  sortBy: null,
34
34
  descending: false,
35
35
  page: 1,
@@ -42,7 +42,7 @@ export function useListActions(name, {
42
42
  perPage: quasarPagination.value.rowsPerPage,
43
43
  page: quasarPagination.value.page,
44
44
  filter: { ...filter.value, ...globalFilter.value },
45
- sort: columns ? mapSortBy(quasarPagination.value, columns) : undefined
45
+ sort: quasarPagination.value.__sort || undefined
46
46
  }));
47
47
 
48
48
  // When any part of the filter changes, get the new list of creatives
@@ -95,15 +95,15 @@ export function useListActions(name, {
95
95
  isLoadingFilters.value = false;
96
96
  }
97
97
 
98
- // A flat list of valid filterable field names
99
- const validFilterKeys = computed(() => filterGroups?.value?.map(group => group.fields.map(field => field.name)).flat());
100
-
101
98
  /**
102
99
  * Watches for a filter URL parameter and applies the filter if it is set.
103
100
  */
104
- function applyFilterFromUrl(url) {
101
+ function applyFilterFromUrl(url, filterGroups = null) {
105
102
  if (url.match(urlPattern)) {
106
- const urlFilter = getFilterFromUrl(url, validFilterKeys.value);
103
+ // A flat list of valid filterable field names
104
+ const validFilterKeys = filterGroups?.value?.map(group => group.fields.map(field => field.name)).flat();
105
+
106
+ const urlFilter = getFilterFromUrl(url, validFilterKeys);
107
107
 
108
108
  if (Object.keys(urlFilter).length > 0) {
109
109
  filter.value = urlFilter;
@@ -187,9 +187,6 @@ export function useListActions(name, {
187
187
  filter.value = { ...filterDefaults, ...filter.value };
188
188
  }
189
189
 
190
- // Load the URL filters if they are set
191
- applyFilterFromUrl(window.location.href);
192
-
193
190
  setTimeout(() => {
194
191
  if (!isLoadingList.value) {
195
192
  loadList();
@@ -355,7 +352,6 @@ export function useListActions(name, {
355
352
  isApplyingBatchAction,
356
353
  activeItem,
357
354
  formTab,
358
- columns,
359
355
  filterGroups,
360
356
 
361
357
  // Actions
@@ -37,19 +37,19 @@
37
37
  :key="item.action"
38
38
  clickable
39
39
  :class="item.class"
40
- @click="$emit('action', item.action)"
40
+ @click="onAction(item)"
41
41
  >
42
42
  {{ item.label }}
43
- </q-item>
43
+ </q-item>
44
44
  </template>
45
- </q-list>
46
- </q-menu>
45
+ </q-list>
46
+ </q-menu>
47
47
  </a>
48
48
  </template>
49
49
  <script setup>
50
50
  import { DotsVerticalIcon as MenuIcon } from '@heroicons/vue/outline';
51
51
 
52
- defineEmits(['action']);
52
+ const emit = defineEmits(['action', 'action-item']);
53
53
  defineProps({
54
54
  items: {
55
55
  type: Array,
@@ -61,4 +61,9 @@ defineProps({
61
61
  disabled: Boolean,
62
62
  loading: Boolean
63
63
  });
64
+
65
+ function onAction(item) {
66
+ emit('action', item.action);
67
+ emit('action-item', item);
68
+ }
64
69
  </script>