quasar-ui-danx 0.4.27 → 0.4.29
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/README.md +35 -35
- package/dist/danx.es.js +24686 -24119
- package/dist/danx.es.js.map +1 -1
- package/dist/danx.umd.js +109 -109
- package/dist/danx.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/ActionTable/ActionTable.vue +29 -7
- package/src/components/ActionTable/Filters/FilterableField.vue +14 -2
- package/src/components/ActionTable/Form/ActionForm.vue +17 -12
- package/src/components/ActionTable/Form/Fields/DateField.vue +24 -20
- package/src/components/ActionTable/Form/Fields/DateRangeField.vue +57 -53
- package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +9 -2
- package/src/components/ActionTable/Form/Fields/EditableDiv.vue +51 -21
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +1 -1
- package/src/components/ActionTable/Form/Fields/SelectField.vue +27 -6
- package/src/components/ActionTable/Form/Fields/SelectOrCreateField.vue +56 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +2 -0
- package/src/components/ActionTable/Form/Fields/index.ts +1 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +7 -20
- package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +1 -1
- package/src/components/ActionTable/Form/Utilities/SaveStateIndicator.vue +37 -0
- package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +20 -23
- package/src/components/ActionTable/Toolbars/ActionToolbar.vue +44 -36
- package/src/components/ActionTable/{listControls.ts → controls.ts} +13 -9
- package/src/components/ActionTable/index.ts +1 -1
- package/src/components/DragAndDrop/ListItemDraggable.vue +45 -31
- package/src/components/DragAndDrop/dragAndDrop.ts +221 -220
- package/src/components/DragAndDrop/listDragAndDrop.ts +269 -227
- package/src/components/PanelsDrawer/PanelsDrawer.vue +7 -7
- package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +3 -3
- package/src/components/Utility/Buttons/ShowHideButton.vue +86 -0
- package/src/components/Utility/Buttons/index.ts +1 -0
- package/src/components/Utility/Dialogs/ActionFormDialog.vue +30 -0
- package/src/components/Utility/Dialogs/CreateNewWithNameDialog.vue +26 -0
- package/src/components/Utility/Dialogs/RenderedFormDialog.vue +50 -0
- package/src/components/Utility/Dialogs/index.ts +3 -0
- package/src/helpers/FileUpload.ts +4 -4
- package/src/helpers/actions.ts +84 -20
- package/src/helpers/files.ts +56 -43
- package/src/helpers/formats.ts +23 -20
- package/src/helpers/objectStore.ts +24 -12
- package/src/types/actions.d.ts +50 -26
- package/src/types/controls.d.ts +23 -25
- package/src/types/fields.d.ts +1 -0
- package/src/types/files.d.ts +2 -2
- package/src/types/index.d.ts +5 -0
- package/src/types/shared.d.ts +9 -0
- package/src/types/tables.d.ts +3 -3
- package/types/vue-shims.d.ts +3 -2
@@ -23,6 +23,7 @@
|
|
23
23
|
:disable="disabled"
|
24
24
|
:label-slot="!noLabel"
|
25
25
|
:input-class="inputClass"
|
26
|
+
:rows="rows"
|
26
27
|
:class="{'dx-input-prepend-label': prependLabel}"
|
27
28
|
stack-label
|
28
29
|
:type="type"
|
@@ -71,6 +72,7 @@ withDefaults(defineProps<TextFieldProps>(), {
|
|
71
72
|
labelClass: "",
|
72
73
|
inputClass: "",
|
73
74
|
maxLength: null,
|
75
|
+
rows: 3,
|
74
76
|
debounce: 0,
|
75
77
|
placeholder: null
|
76
78
|
});
|
@@ -19,6 +19,7 @@ export { default as NumberField } from "./NumberField.vue";
|
|
19
19
|
export { default as NumberRangeField } from "./NumberRangeField.vue";
|
20
20
|
export { default as SelectDrawer } from "./SelectDrawer.vue";
|
21
21
|
export { default as SelectField } from "./SelectField.vue";
|
22
|
+
export { default as SelectOrCreateField } from "./SelectOrCreateField.vue";
|
22
23
|
export { default as SelectWithChildrenField } from "./SelectWithChildrenField.vue";
|
23
24
|
export { default as SingleFileField } from "./SingleFileField.vue";
|
24
25
|
export { default as SliderNumberField } from "./SliderNumberField.vue";
|
@@ -93,25 +93,11 @@
|
|
93
93
|
</div>
|
94
94
|
</template>
|
95
95
|
<slot />
|
96
|
-
<
|
97
|
-
|
98
|
-
:
|
99
|
-
class="
|
100
|
-
|
101
|
-
<slot
|
102
|
-
v-if="saving"
|
103
|
-
name="saving"
|
104
|
-
>
|
105
|
-
Saving...
|
106
|
-
<QSpinnerPie class="ml-2" />
|
107
|
-
</slot>
|
108
|
-
<slot
|
109
|
-
v-else
|
110
|
-
name="saved"
|
111
|
-
>
|
112
|
-
Saved at {{ fDateTime(savedAt, { format: "M/d/yy h:mm:ssa" }) }}
|
113
|
-
</slot>
|
114
|
-
</div>
|
96
|
+
<SaveStateIndicator
|
97
|
+
:saving="saving"
|
98
|
+
:saved-at="savedAt"
|
99
|
+
:saving-class="savingClass"
|
100
|
+
/>
|
115
101
|
<ConfirmDialog
|
116
102
|
v-if="variationToEdit !== false"
|
117
103
|
title="Change variation name"
|
@@ -139,7 +125,7 @@
|
|
139
125
|
<script setup lang="ts">
|
140
126
|
import { ExclamationCircleIcon as MissingIcon, PencilIcon as EditIcon } from "@heroicons/vue/solid";
|
141
127
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
142
|
-
import {
|
128
|
+
import { FlashMessages, incrementName, replace } from "../../../helpers";
|
143
129
|
import { TrashIcon as RemoveIcon } from "../../../svg";
|
144
130
|
import { AnyObject, FormFieldValue, RenderedFormProps } from "../../../types";
|
145
131
|
import { ConfirmDialog, RenderVnode } from "../../Utility";
|
@@ -154,6 +140,7 @@ import {
|
|
154
140
|
TextField,
|
155
141
|
WysiwygField
|
156
142
|
} from "./Fields";
|
143
|
+
import SaveStateIndicator from "./Utilities/SaveStateIndicator";
|
157
144
|
|
158
145
|
const props = withDefaults(defineProps<RenderedFormProps>(), {
|
159
146
|
values: null,
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
:class="savingClass"
|
4
|
+
class="dx-saving-indicator flex items-center flex-nowrap"
|
5
|
+
>
|
6
|
+
<slot
|
7
|
+
v-if="saving"
|
8
|
+
name="saving"
|
9
|
+
>
|
10
|
+
Saving...
|
11
|
+
<QSpinnerPie class="ml-2" />
|
12
|
+
</slot>
|
13
|
+
<slot
|
14
|
+
v-else
|
15
|
+
name="saved"
|
16
|
+
>
|
17
|
+
<template v-if="savedAt">
|
18
|
+
Saved at {{ fDateTime(savedAt, { format: "M/d/yy h:mm:ssa" }) }}
|
19
|
+
</template>
|
20
|
+
<template v-else>
|
21
|
+
Not saved
|
22
|
+
</template>
|
23
|
+
</slot>
|
24
|
+
</div>
|
25
|
+
</template>
|
26
|
+
<script setup lang="ts">
|
27
|
+
import { fDateTime } from "../../../../helpers";
|
28
|
+
|
29
|
+
withDefaults(defineProps<{
|
30
|
+
saving?: boolean;
|
31
|
+
savedAt?: string;
|
32
|
+
savingClass?: string;
|
33
|
+
}>(), {
|
34
|
+
savingClass: "text-sm text-slate-500",
|
35
|
+
savedAt: ""
|
36
|
+
});
|
37
|
+
</script>
|
@@ -6,11 +6,13 @@
|
|
6
6
|
v-if="!hideToolbar"
|
7
7
|
:title="title"
|
8
8
|
:refresh-button="refreshButton"
|
9
|
-
:
|
9
|
+
:create-button="createButton"
|
10
|
+
:actions="controller.batchActions"
|
10
11
|
:action-target="controller.selectedRows.value"
|
11
12
|
:exporter="controller.exportList"
|
12
13
|
:loading="controller.isLoadingList.value || controller.isLoadingSummary.value"
|
13
14
|
@refresh="controller.refreshAll"
|
15
|
+
@create="controller.action && controller.action('create')"
|
14
16
|
>
|
15
17
|
<template #default>
|
16
18
|
<slot name="action-toolbar" />
|
@@ -23,7 +25,7 @@
|
|
23
25
|
v-if="activeFilter"
|
24
26
|
:name="controller.name"
|
25
27
|
:show-filters="showFilters"
|
26
|
-
:filters="filters"
|
28
|
+
:filters="controller.filters?.value"
|
27
29
|
:active-filter="activeFilter"
|
28
30
|
class="dx-action-table-filters"
|
29
31
|
@update:active-filter="controller.setActiveFilter"
|
@@ -37,11 +39,12 @@
|
|
37
39
|
:label="controller.label"
|
38
40
|
:name="controller.name"
|
39
41
|
:class="tableClass"
|
42
|
+
:menu-actions="controller.menuActions"
|
40
43
|
:summary="controller.summary.value"
|
41
44
|
:loading-list="controller.isLoadingList.value"
|
42
45
|
:loading-summary="controller.isLoadingSummary.value"
|
43
46
|
:paged-items="controller.pagedItems.value"
|
44
|
-
:columns="columns"
|
47
|
+
:columns="controller.columns || []"
|
45
48
|
:selection="selection"
|
46
49
|
@update:selected-rows="controller.setSelectedRows"
|
47
50
|
@update:pagination="controller.setPagination"
|
@@ -49,11 +52,11 @@
|
|
49
52
|
</slot>
|
50
53
|
<slot name="panels">
|
51
54
|
<PanelsDrawer
|
52
|
-
v-if="activeItem && panels"
|
55
|
+
v-if="activeItem && controller.panels"
|
53
56
|
:title="panelTitle"
|
54
57
|
:model-value="activePanel"
|
55
|
-
:
|
56
|
-
:panels="panels"
|
58
|
+
:target="activeItem"
|
59
|
+
:panels="controller.panels"
|
57
60
|
@update:model-value="panel => controller.activatePanel(activeItem, panel)"
|
58
61
|
@close="controller.setActiveItem(null)"
|
59
62
|
>
|
@@ -70,7 +73,7 @@
|
|
70
73
|
</template>
|
71
74
|
<script setup lang="ts">
|
72
75
|
import { computed } from "vue";
|
73
|
-
import {
|
76
|
+
import { DanxController } from "../../../types";
|
74
77
|
import { PanelsDrawer } from "../../PanelsDrawer";
|
75
78
|
import { PreviousNextControls } from "../../Utility";
|
76
79
|
import ActionTable from "../ActionTable.vue";
|
@@ -78,30 +81,24 @@ import { CollapsableFiltersSidebar } from "../Filters";
|
|
78
81
|
import { ActionToolbar } from "../Toolbars";
|
79
82
|
|
80
83
|
export interface ActionTableLayoutProps {
|
81
|
-
|
82
|
-
controller: ActionController;
|
83
|
-
columns: TableColumn[];
|
84
|
-
filters?: FilterGroup[];
|
85
|
-
panels?: ActionPanel[];
|
86
|
-
actions?: ResourceAction[];
|
84
|
+
controller: DanxController;
|
87
85
|
exporter?: () => Promise<void>;
|
86
|
+
hideToolbar?: boolean;
|
88
87
|
panelTitleField?: string;
|
89
|
-
tableClass?: string;
|
90
88
|
refreshButton?: boolean;
|
91
|
-
|
92
|
-
hideToolbar?: boolean;
|
89
|
+
createButton?: boolean;
|
93
90
|
selection?: "multiple" | "single";
|
91
|
+
showFilters?: boolean;
|
92
|
+
tableClass?: string;
|
93
|
+
title?: string;
|
94
94
|
}
|
95
95
|
|
96
96
|
const props = withDefaults(defineProps<ActionTableLayoutProps>(), {
|
97
|
-
title: "",
|
98
|
-
tableClass: "",
|
99
|
-
selection: "multiple",
|
100
|
-
filters: undefined,
|
101
|
-
panels: undefined,
|
102
|
-
actions: undefined,
|
103
97
|
exporter: undefined,
|
104
|
-
panelTitleField: ""
|
98
|
+
panelTitleField: "",
|
99
|
+
selection: "multiple",
|
100
|
+
tableClass: "",
|
101
|
+
title: ""
|
105
102
|
});
|
106
103
|
|
107
104
|
const activeFilter = computed(() => props.controller.activeFilter.value);
|
@@ -1,46 +1,54 @@
|
|
1
1
|
<template>
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
2
|
+
<div class="dx-action-toolbar flex items-center">
|
3
|
+
<div class="flex-grow px-6">
|
4
|
+
<slot name="title">
|
5
|
+
<h4 v-if="title">
|
6
|
+
{{ title }}
|
7
|
+
</h4>
|
8
|
+
</slot>
|
9
|
+
</div>
|
10
|
+
<div class="py-3 flex items-center flex-nowrap">
|
11
|
+
<slot />
|
12
|
+
<QBtn
|
13
|
+
v-if="createButton"
|
14
|
+
class="bg-green-900 mr-4 px-4"
|
15
|
+
@click="$emit('create')"
|
16
|
+
>
|
17
|
+
Create
|
18
|
+
</QBtn>
|
19
|
+
<RefreshButton
|
20
|
+
v-if="refreshButton"
|
21
|
+
:loading="loading"
|
22
|
+
@click="$emit('refresh')"
|
23
|
+
/>
|
24
|
+
<ExportButton
|
25
|
+
v-if="exporter"
|
26
|
+
:exporter="exporter"
|
27
|
+
class="ml-4"
|
28
|
+
/>
|
29
|
+
<ActionMenu
|
30
|
+
v-if="actions && actions.length > 0"
|
31
|
+
class="ml-4 dx-batch-actions"
|
32
|
+
:target="actionTarget"
|
33
|
+
:actions="actions"
|
34
|
+
/>
|
35
|
+
<slot name="after" />
|
36
|
+
</div>
|
37
|
+
</div>
|
31
38
|
</template>
|
32
39
|
<script setup lang="ts">
|
33
40
|
import { ActionTargetItem, AnyObject, ResourceAction } from "../../../types";
|
34
41
|
import { ExportButton, RefreshButton } from "../../Utility";
|
35
42
|
import ActionMenu from "../ActionMenu";
|
36
43
|
|
37
|
-
defineEmits(["refresh"]);
|
44
|
+
defineEmits(["refresh", "create"]);
|
38
45
|
defineProps<{
|
39
|
-
title?: string
|
40
|
-
actions?: ResourceAction[]
|
41
|
-
actionTarget?: ActionTargetItem[]
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
title?: string;
|
47
|
+
actions?: ResourceAction[];
|
48
|
+
actionTarget?: ActionTargetItem[];
|
49
|
+
createButton?: boolean;
|
50
|
+
refreshButton?: boolean;
|
51
|
+
loading?: boolean;
|
52
|
+
exporter?: (filter?: AnyObject) => void | Promise<void>;
|
45
53
|
}>();
|
46
54
|
</script>
|
@@ -1,20 +1,21 @@
|
|
1
|
-
import { computed,
|
1
|
+
import { computed, ref, shallowRef, watch } from "vue";
|
2
2
|
import { RouteParams, Router } from "vue-router";
|
3
3
|
import { danxOptions } from "../../config";
|
4
4
|
import { getItem, latestCallOnly, setItem, storeObject, waitForRef } from "../../helpers";
|
5
5
|
import {
|
6
|
-
ActionController,
|
7
6
|
ActionTargetItem,
|
8
7
|
AnyObject,
|
9
8
|
FilterGroup,
|
9
|
+
ListController,
|
10
10
|
ListControlsFilter,
|
11
11
|
ListControlsOptions,
|
12
12
|
ListControlsPagination,
|
13
|
-
PagedItems
|
13
|
+
PagedItems,
|
14
|
+
Ref
|
14
15
|
} from "../../types";
|
15
16
|
import { getFilterFromUrl } from "./listHelpers";
|
16
17
|
|
17
|
-
export function
|
18
|
+
export function useControls(name: string, options: ListControlsOptions): ListController {
|
18
19
|
let isInitialized = false;
|
19
20
|
const PAGE_SETTINGS_KEY = `dx-${name}-pager`;
|
20
21
|
const pagedItems = shallowRef<PagedItems | null>(null);
|
@@ -72,12 +73,13 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
72
73
|
|
73
74
|
async function loadList() {
|
74
75
|
if (!isInitialized) return;
|
75
|
-
isLoadingList.value = true;
|
76
|
+
// isLoadingList.value = true;
|
76
77
|
try {
|
77
78
|
setPagedItems(await options.routes.list(pager.value));
|
78
|
-
isLoadingList.value = false;
|
79
79
|
} catch (e) {
|
80
80
|
// Fail silently
|
81
|
+
} finally {
|
82
|
+
isLoadingList.value = false;
|
81
83
|
}
|
82
84
|
}
|
83
85
|
|
@@ -91,9 +93,10 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
91
93
|
}
|
92
94
|
try {
|
93
95
|
summary.value = await options.routes.summary(summaryFilter);
|
94
|
-
isLoadingSummary.value = false;
|
95
96
|
} catch (e) {
|
96
97
|
// Fail silently
|
98
|
+
} finally {
|
99
|
+
isLoadingSummary.value = false;
|
97
100
|
}
|
98
101
|
}
|
99
102
|
|
@@ -116,9 +119,10 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
116
119
|
isLoadingFilters.value = true;
|
117
120
|
try {
|
118
121
|
fieldOptions.value = await options.routes.fieldOptions(activeFilter.value) || {};
|
119
|
-
isLoadingFilters.value = false;
|
120
122
|
} catch (e) {
|
121
123
|
// Fail silently
|
124
|
+
} finally {
|
125
|
+
isLoadingFilters.value = false;
|
122
126
|
}
|
123
127
|
}
|
124
128
|
|
@@ -490,7 +494,7 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
490
494
|
activeItem,
|
491
495
|
activePanel,
|
492
496
|
|
493
|
-
//
|
497
|
+
// List controls
|
494
498
|
initialize,
|
495
499
|
resetPaging,
|
496
500
|
setPagination,
|
@@ -1,8 +1,8 @@
|
|
1
1
|
export * from "./Columns";
|
2
|
+
export * from "./controls";
|
2
3
|
export * from "./Filters";
|
3
4
|
export * from "./Form";
|
4
5
|
export * from "./Layouts";
|
5
|
-
export * from "./listControls";
|
6
6
|
export * from "./listHelpers";
|
7
7
|
export * from "./tableColumns";
|
8
8
|
export * from "./Toolbars";
|
@@ -1,12 +1,16 @@
|
|
1
1
|
<template>
|
2
2
|
<div
|
3
|
-
class="cursor-move"
|
3
|
+
:class="{'cursor-move': !showHandle}"
|
4
4
|
draggable="true"
|
5
|
-
@dragstart="dragAndDrop.dragStart"
|
5
|
+
@dragstart.stop="dragAndDrop.dragStart"
|
6
6
|
@dragend="dragAndDrop.dragEnd"
|
7
7
|
>
|
8
|
-
<div class="
|
9
|
-
<div
|
8
|
+
<div :class="contentClass">
|
9
|
+
<div
|
10
|
+
v-if="showHandle"
|
11
|
+
class="cursor-move"
|
12
|
+
:class="handleClass"
|
13
|
+
>
|
10
14
|
<SvgImg
|
11
15
|
:svg="DragHandleIcon"
|
12
16
|
class="w-4 h-4"
|
@@ -19,39 +23,49 @@
|
|
19
23
|
</div>
|
20
24
|
</div>
|
21
25
|
</template>
|
22
|
-
<script setup>
|
26
|
+
<script setup lang="ts">
|
23
27
|
import { DragHandleDotsIcon as DragHandleIcon } from "../../svg";
|
24
28
|
import { SvgImg } from "../Utility";
|
25
29
|
import { ListDragAndDrop } from "./listDragAndDrop";
|
26
30
|
|
27
|
-
const emit = defineEmits(["position", "update:list-items"]);
|
28
|
-
const
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
}
|
31
|
+
const emit = defineEmits(["position", "update:list-items", "drop-zone"]);
|
32
|
+
const dragging = defineModel<boolean>();
|
33
|
+
const props = withDefaults(defineProps<{
|
34
|
+
dropZone: string | (() => string);
|
35
|
+
direction?: "vertical" | "horizontal";
|
36
|
+
showHandle?: boolean;
|
37
|
+
changeDropZone?: boolean;
|
38
|
+
contentClass?: string | object;
|
39
|
+
handleClass?: string | object;
|
40
|
+
listItems?: any[];
|
41
|
+
}>(), {
|
42
|
+
direction: "vertical",
|
43
|
+
handleClass: "",
|
44
|
+
contentClass: "flex flex-nowrap items-center",
|
45
|
+
listItems: () => []
|
43
46
|
});
|
44
47
|
|
45
48
|
const dragAndDrop = new ListDragAndDrop()
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
.setDropZone(props.dropZone)
|
50
|
+
.setOptions({ showPlaceholder: true, allowDropZoneChange: props.changeDropZone, direction: props.direction })
|
51
|
+
.onStart(() => dragging.value = true)
|
52
|
+
.onEnd(() => dragging.value = false)
|
53
|
+
.onDropZoneChange((target, dropZone, newPosition, oldPosition, data) => {
|
54
|
+
let item = null;
|
55
|
+
let items = [];
|
56
|
+
if (props.listItems) {
|
57
|
+
items = [...props.listItems];
|
58
|
+
item = items.splice(oldPosition, 1)[0];
|
59
|
+
}
|
50
60
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
61
|
+
emit("drop-zone", { target, item, items, dropZone, oldPosition, newPosition, data });
|
62
|
+
})
|
63
|
+
.onPositionChange((newPosition, oldPosition) => {
|
64
|
+
emit("position", newPosition);
|
65
|
+
if (props.listItems) {
|
66
|
+
const items = [...props.listItems];
|
67
|
+
items.splice(newPosition, 0, items.splice(oldPosition, 1)[0]);
|
68
|
+
emit("update:list-items", items);
|
69
|
+
}
|
70
|
+
});
|
57
71
|
</script>
|