quasar-ui-danx 0.0.36 → 0.0.37

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.36",
3
+ "version": "0.0.37",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -3,13 +3,14 @@
3
3
  class="px-2 flex action-button"
4
4
  :items="activeItems"
5
5
  :disabled="targets.length === 0"
6
+ :tooltip="targets.length === 0 ? tooltip : null"
7
+ :loading="isSaving"
8
+ :loading-component="loadingComponent"
6
9
  @action-item="onAction"
7
- >
8
- <q-tooltip v-if="targets.length === 0">{{ tooltip }}</q-tooltip>
9
- </PopoverMenu>
10
+ />
10
11
  </template>
11
12
  <script setup>
12
- import { computed } from 'vue';
13
+ import { computed, ref } from 'vue';
13
14
  import { performAction } from '../../helpers';
14
15
  import { PopoverMenu } from '../Utility';
15
16
 
@@ -26,6 +27,10 @@ const props = defineProps({
26
27
  tooltip: {
27
28
  type: String,
28
29
  default: 'First select records to perform a batch action'
30
+ },
31
+ loadingComponent: {
32
+ type: [Function, Object],
33
+ default: undefined
29
34
  }
30
35
  });
31
36
 
@@ -34,8 +39,11 @@ const activeItems = computed(() => props.items.filter(item => {
34
39
  return typeof item.enabled === 'function' ? !!item.enabled(props.targets?.[0] ?? null, props.targets) : !!item.enabled;
35
40
  }));
36
41
 
37
- function onAction(item) {
42
+ const isSaving = ref(false);
43
+ async function onAction(item) {
38
44
  emit('action', item);
39
- performAction(item, props.targets);
45
+ isSaving.value = true;
46
+ await performAction(item, props.targets);
47
+ isSaving.value = false;
40
48
  }
41
49
  </script>
@@ -41,7 +41,7 @@
41
41
  v-if="rowProps.col.resizeable"
42
42
  :drop-zone="`resize-column-` + rowProps.col.name"
43
43
  class="resize-handle"
44
- @resize="rowProps.col.onResize"
44
+ @resize="onResizeColumn(rowProps.col, $event)"
45
45
  >
46
46
  <RowResizeIcon class="w-4 text-neutral-base" />
47
47
  </HandleDraggable>
@@ -53,6 +53,7 @@
53
53
  :is="rowProps.col.onClick ? 'a' : 'div'"
54
54
  class="flex items-center flex-nowrap"
55
55
  :class="{'justify-end': rowProps.col.align === 'right', 'justify-center': rowProps.col.align === 'center', 'justify-start': rowProps.col.align === 'left'}"
56
+ :style="getColumnStyle(rowProps.col)"
56
57
  @click="() => rowProps.col.onClick && rowProps.col.onClick(rowProps.row)"
57
58
  >
58
59
  <RenderComponent
@@ -87,19 +88,18 @@
87
88
 
88
89
  <script setup>
89
90
  import { ref } from 'vue';
91
+ import { getItem, setItem } from '../../helpers';
90
92
  import { DragHandleIcon as RowResizeIcon } from '../../svg';
91
93
  import { HandleDraggable } from '../DragAndDrop';
92
- import {
93
- ActionMenu,
94
- EmptyTableState,
95
- mapSortBy,
96
- registerStickyScrolling,
97
- RenderComponent,
98
- TableSummaryRow
99
- } from './index';
94
+ import { mapSortBy, RenderComponent } from '../index';
95
+ import { ActionMenu, EmptyTableState, registerStickyScrolling, TableSummaryRow } from './index';
100
96
 
101
97
  defineEmits(['action', 'filter', 'update:quasar-pagination', 'update:selected-rows']);
102
- defineProps({
98
+ const props = defineProps({
99
+ name: {
100
+ type: String,
101
+ required: true
102
+ },
103
103
  label: {
104
104
  type: String,
105
105
  required: true
@@ -133,6 +133,23 @@ defineProps({
133
133
  });
134
134
  const actionTable = ref(null);
135
135
  registerStickyScrolling(actionTable);
136
+
137
+ const COLUMN_SETTINGS_KEY = `column-settings-${props.name}`;
138
+ const columnSettings = ref(getItem(COLUMN_SETTINGS_KEY) || {});
139
+ function onResizeColumn(column, val) {
140
+ columnSettings.value[column.name] = Math.max(Math.min(val.distance + val.startDropZoneSize, column.maxWidth || 500), column.minWidth || 80);
141
+ setItem(COLUMN_SETTINGS_KEY, columnSettings.value);
142
+ }
143
+ function getColumnStyle(column) {
144
+ const width = columnSettings.value[column.name] || column.width;
145
+
146
+ if (width) {
147
+ return {
148
+ width: `${width}px`
149
+ };
150
+ }
151
+ return null;
152
+ }
136
153
  </script>
137
154
 
138
155
  <style lang="scss" scoped>
@@ -7,5 +7,4 @@ export * from "./tableColumns";
7
7
  export { default as ActionMenu } from "./ActionMenu.vue";
8
8
  export { default as ActionTable } from "./ActionTable.vue";
9
9
  export { default as EmptyTableState } from "./EmptyTableState.vue";
10
- export { default as RenderComponent } from "./RenderComponent.vue";
11
10
  export { default as TableSummaryRow } from "./TableSummaryRow.vue";
@@ -1,11 +1,10 @@
1
1
  import { computed, ref, watch } from "vue";
2
2
  import { getItem, setItem } from "../../helpers";
3
3
 
4
- export function useTableColumns(name, columns, options = { titleMinWidth: 120, titleMaxWidth: 200 }) {
4
+ export function useTableColumns(name, columns) {
5
5
  const COLUMN_ORDER_KEY = `${name}-column-order`;
6
6
  const VISIBLE_COLUMNS_KEY = `${name}-visible-columns`;
7
7
  const TITLE_COLUMNS_KEY = `${name}-title-columns`;
8
- const TITLE_WIDTH_KEY = `${name}-title-width`;
9
8
 
10
9
  // The list that defines the order the columns should appear in
11
10
  const columnOrder = ref(getItem(COLUMN_ORDER_KEY) || []);
@@ -16,17 +15,6 @@ export function useTableColumns(name, columns, options = { titleMinWidth: 120, t
16
15
  // Title columns will have their name appear on the first column of the table as part of the records' title
17
16
  const titleColumnNames = ref(getItem(TITLE_COLUMNS_KEY, []));
18
17
 
19
- // The width of the title column
20
- const titleWidth = ref(getItem(TITLE_WIDTH_KEY, options.titleMinWidth));
21
-
22
- /**
23
- * When the title column is resized, update the titleWidth
24
- * @param val
25
- */
26
- function onResizeTitleColumn(val) {
27
- titleWidth.value = Math.max(Math.min(val.distance + val.startDropZoneSize, options.titleMaxWidth), options.titleMinWidth);
28
- }
29
-
30
18
  // Columns that should be locked to the left side of the table
31
19
  const lockedColumns = computed(() => orderedColumns.value.slice(0, 1));
32
20
 
@@ -57,7 +45,6 @@ export function useTableColumns(name, columns, options = { titleMinWidth: 120, t
57
45
  // Save changes to the list of hidden columns in localStorage
58
46
  watch(() => hiddenColumnNames.value, () => setItem(VISIBLE_COLUMNS_KEY, hiddenColumnNames.value));
59
47
  watch(() => titleColumnNames.value, () => setItem(TITLE_COLUMNS_KEY, titleColumnNames.value));
60
- watch(() => titleWidth.value, () => setItem(TITLE_WIDTH_KEY, titleWidth.value));
61
48
 
62
49
  return {
63
50
  sortableColumns,
@@ -65,8 +52,6 @@ export function useTableColumns(name, columns, options = { titleMinWidth: 120, t
65
52
  visibleColumns,
66
53
  hiddenColumnNames,
67
54
  titleColumnNames,
68
- titleWidth,
69
- orderedTitleColumns,
70
- onResizeTitleColumn
55
+ orderedTitleColumns
71
56
  };
72
57
  }
@@ -3,14 +3,16 @@
3
3
  class="p-3 actionable"
4
4
  :class="{'opacity-50 cursor-not-allowed': disabled}"
5
5
  >
6
- <slot />
6
+ <q-tooltip v-if="$slots.tooltip || tooltip">
7
+ <slot name="tooltip">{{ tooltip }}</slot>
8
+ </q-tooltip>
7
9
  <Transition
8
10
  mode="out-in"
9
11
  :duration="150"
10
12
  >
11
- <q-spinner
13
+ <RenderComponent
12
14
  v-if="loading"
13
- class="w-4 h-4 text-black"
15
+ :component="loadingComponent"
14
16
  />
15
17
  <MenuIcon
16
18
  v-else
@@ -49,6 +51,8 @@
49
51
  </template>
50
52
  <script setup>
51
53
  import { DotsVerticalIcon as MenuIcon } from '@heroicons/vue/outline';
54
+ import { QSpinner } from 'quasar';
55
+ import { RenderComponent } from '../index';
52
56
 
53
57
  const emit = defineEmits(['action', 'action-item']);
54
58
  defineProps({
@@ -56,11 +60,22 @@ defineProps({
56
60
  type: Array,
57
61
  required: true,
58
62
  validator(items) {
59
- return items.every((item) => item.label && (item.url || item.action || item.name));
63
+ return items.every((item) => item.url || item.action || item.name);
60
64
  }
61
65
  },
66
+ tooltip: {
67
+ type: String,
68
+ default: null
69
+ },
62
70
  disabled: Boolean,
63
- loading: Boolean
71
+ loading: Boolean,
72
+ loadingComponent: {
73
+ type: [Function, Object],
74
+ default: () => ({
75
+ is: QSpinner,
76
+ props: { class: 'w-4 h-4 text-black' }
77
+ })
78
+ }
64
79
  });
65
80
 
66
81
  function onAction(item) {
@@ -42,11 +42,22 @@ async function onConfirmAction(input) {
42
42
  }
43
43
 
44
44
  isSaving.value = true;
45
- const result = await props.action.onAction(props.targets, input);
45
+ let result;
46
+ try {
47
+ result = await props.action.onAction(props.targets, input);
48
+ } catch (e) {
49
+ console.error(e);
50
+ result = { error: `An error occurred while performing the action ${props.action.label}. Please try again later.` };
51
+ }
52
+
46
53
  isSaving.value = false;
47
54
 
48
- if (result.success) {
49
- FlashMessages.success(`The update was successful`);
55
+ // If there is no return value or the result marks it as successful, we show a success message
56
+ if (result === undefined || result?.success) {
57
+
58
+ if (result?.success) {
59
+ FlashMessages.success(`The update was successful`);
60
+ }
50
61
 
51
62
  if (props.action.onSuccess) {
52
63
  await props.action.onSuccess(result, props.targets, input);
@@ -58,7 +69,7 @@ async function onConfirmAction(input) {
58
69
  if (result.errors) {
59
70
  errors.push(...result.errors);
60
71
  } else if (result.error) {
61
- errors.push(result.error.message);
72
+ errors.push(typeof result.error === 'string' ? result.error : result.error.message);
62
73
  } else {
63
74
  errors.push('An unknown error occurred. Please try again later.');
64
75
  }
@@ -1 +1,2 @@
1
1
  export { default as ActionPerformerTool } from "./ActionPerformerTool.vue";
2
+ export { default as RenderComponent } from "./RenderComponent.vue";
package/tsconfig.json CHANGED
@@ -25,9 +25,6 @@
25
25
  "paths": {
26
26
  "@/*": [
27
27
  "./dev/src/*"
28
- ],
29
- "ui": [
30
- "./src/index.esm.js"
31
28
  ]
32
29
  }
33
30
  },