quasar-ui-danx 0.0.35 → 0.0.37
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 +1 -1
- package/src/components/ActionTable/ActionMenu.vue +14 -6
- package/src/components/ActionTable/ActionTable.vue +27 -10
- package/src/components/ActionTable/index.ts +0 -1
- package/src/components/ActionTable/listActions.ts +5 -5
- package/src/components/ActionTable/tableColumns.ts +2 -17
- package/src/components/Utility/Popovers/PopoverMenu.vue +20 -5
- package/src/components/Utility/Tools/ActionPerformerTool.vue +15 -4
- package/src/components/Utility/Tools/index.ts +1 -0
- package/tsconfig.json +0 -3
- /package/src/components/{ActionTable → Utility/Tools}/RenderComponent.vue +0 -0
package/package.json
CHANGED
@@ -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
|
-
|
42
|
+
const isSaving = ref(false);
|
43
|
+
async function onAction(item) {
|
38
44
|
emit('action', item);
|
39
|
-
|
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
|
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
|
-
|
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";
|
@@ -252,10 +252,10 @@ export function useListActions(name: string, {
|
|
252
252
|
return result;
|
253
253
|
}
|
254
254
|
|
255
|
-
// The active ad for viewing / editing
|
255
|
+
// The active ad for viewing / editing
|
256
256
|
const activeItem = ref(null);
|
257
|
-
// Controls the tab
|
258
|
-
const
|
257
|
+
// Controls the active panel (ie: tab) if rendering a panels drawer or similar
|
258
|
+
const activePanel = ref(null);
|
259
259
|
|
260
260
|
/**
|
261
261
|
* Gets the additional details for the currently active item.
|
@@ -293,7 +293,7 @@ export function useListActions(name: string, {
|
|
293
293
|
*/
|
294
294
|
function openItemForm(item, tab) {
|
295
295
|
activeItem.value = item;
|
296
|
-
|
296
|
+
activePanel.value = tab;
|
297
297
|
}
|
298
298
|
|
299
299
|
/**
|
@@ -357,7 +357,7 @@ export function useListActions(name: string, {
|
|
357
357
|
quasarPagination,
|
358
358
|
isApplyingActionToItem,
|
359
359
|
activeItem,
|
360
|
-
|
360
|
+
activePanel,
|
361
361
|
|
362
362
|
// Actions
|
363
363
|
initialize,
|
@@ -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
|
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
|
-
|
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
|
-
<
|
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
|
-
<
|
13
|
+
<RenderComponent
|
12
14
|
v-if="loading"
|
13
|
-
|
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.
|
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
|
-
|
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
|
-
|
49
|
-
|
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
|
}
|
package/tsconfig.json
CHANGED
File without changes
|