quasar-ui-danx 0.4.13 → 0.4.15
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/dist/danx.es.js +5394 -5322
- package/dist/danx.es.js.map +1 -1
- package/dist/danx.umd.js +80 -80
- 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 +65 -63
- package/src/components/ActionTable/Form/ActionForm.vue +18 -12
- package/src/components/ActionTable/Form/RenderedForm.vue +39 -19
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +80 -70
- package/src/components/ActionTable/Toolbars/ActionToolbar.vue +29 -29
- package/src/components/ActionTable/listControls.ts +32 -31
- package/src/components/Navigation/NavigationMenu.vue +83 -40
- package/src/components/PanelsDrawer/PanelsDrawer.vue +5 -3
- package/src/components/Utility/Transitions/AutoHeightTransition.vue +21 -0
- package/src/components/Utility/Transitions/index.ts +1 -0
- package/src/config/index.ts +1 -0
- package/src/helpers/actions.ts +31 -20
- package/src/helpers/formats.ts +8 -5
- package/src/helpers/objectStore.ts +9 -2
- package/src/helpers/request.ts +1 -1
- package/src/helpers/routes.ts +5 -0
- package/src/types/actions.d.ts +1 -4
- package/src/types/config.d.ts +3 -1
- package/src/types/controls.d.ts +5 -7
- package/src/types/forms.d.ts +1 -0
- package/src/types/shared.d.ts +1 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
import { computed, Ref, ref, shallowRef, watch } from "vue";
|
2
|
-
import {
|
2
|
+
import { RouteParams, Router } from "vue-router";
|
3
|
+
import { danxOptions } from "../../config";
|
3
4
|
import { getItem, setItem, storeObject, waitForRef } from "../../helpers";
|
4
5
|
import {
|
5
6
|
ActionController,
|
@@ -7,7 +8,6 @@ import {
|
|
7
8
|
AnyObject,
|
8
9
|
FilterGroup,
|
9
10
|
ListControlsFilter,
|
10
|
-
ListControlsInitializeOptions,
|
11
11
|
ListControlsOptions,
|
12
12
|
ListControlsPagination,
|
13
13
|
PagedItems
|
@@ -16,8 +16,6 @@ import { getFilterFromUrl } from "./listHelpers";
|
|
16
16
|
|
17
17
|
export function useListControls(name: string, options: ListControlsOptions): ActionController {
|
18
18
|
let isInitialized = false;
|
19
|
-
let vueRoute: RouteLocationNormalizedLoaded | null | undefined;
|
20
|
-
let vueRouter: Router | null | undefined;
|
21
19
|
const PAGE_SETTINGS_KEY = `dx-${name}-pager`;
|
22
20
|
const pagedItems = shallowRef<PagedItems | null>(null);
|
23
21
|
const activeFilter = ref<ListControlsFilter>({});
|
@@ -112,11 +110,9 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
112
110
|
|
113
111
|
/**
|
114
112
|
* Loads the filter field options for the current filter.
|
115
|
-
*
|
116
|
-
* @returns {Promise<void>}
|
117
113
|
*/
|
118
114
|
async function loadFieldOptions() {
|
119
|
-
if (!options.routes.fieldOptions
|
115
|
+
if (!options.routes.fieldOptions) return;
|
120
116
|
isLoadingFilters.value = true;
|
121
117
|
try {
|
122
118
|
fieldOptions.value = await options.routes.fieldOptions(activeFilter.value) || {};
|
@@ -184,9 +180,9 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
184
180
|
/**
|
185
181
|
* Sets the pagination settings to the given values.
|
186
182
|
*/
|
187
|
-
function setPagination(updated: ListControlsPagination) {
|
183
|
+
function setPagination(updated: Partial<ListControlsPagination>) {
|
188
184
|
// @ts-expect-error Seems like a bug in the typescript linting?
|
189
|
-
pagination.value = updated;
|
185
|
+
pagination.value = { ...pagination.value, ...updated };
|
190
186
|
}
|
191
187
|
|
192
188
|
/**
|
@@ -250,9 +246,6 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
250
246
|
* Loads the filter and pagination settings from local storage.
|
251
247
|
*/
|
252
248
|
function loadSettings() {
|
253
|
-
// Only load settings when the class is fully initialized
|
254
|
-
if (!isInitialized) return;
|
255
|
-
|
256
249
|
const settings = getItem(PAGE_SETTINGS_KEY);
|
257
250
|
|
258
251
|
// Load the filter settings from local storage
|
@@ -402,26 +395,26 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
402
395
|
}
|
403
396
|
|
404
397
|
// Initialize the list actions and load settings, lists, summaries, filter fields, etc.
|
405
|
-
function initialize(
|
406
|
-
vueRouter =
|
407
|
-
vueRoute = initOptions?.vueRouter?.currentRoute.value;
|
398
|
+
function initialize() {
|
399
|
+
const vueRouter = getVueRouter();
|
408
400
|
isInitialized = true;
|
409
401
|
loadSettings();
|
410
402
|
|
411
403
|
/**
|
412
404
|
* Watch the id params in the route and set the active item to the item with the given id.
|
413
405
|
*/
|
414
|
-
if (options.routes.details
|
415
|
-
const { params, meta } =
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
406
|
+
if (options.routes.details) {
|
407
|
+
const { params, meta, name: controlRouteName } = vueRouter.currentRoute.value;
|
408
|
+
|
409
|
+
if (controlRouteName === name) {
|
410
|
+
vueRouter.afterEach((to) => {
|
411
|
+
if (to.name === controlRouteName) {
|
412
|
+
setPanelFromRoute(to.params, to.meta);
|
413
|
+
}
|
414
|
+
});
|
423
415
|
|
424
|
-
|
416
|
+
setPanelFromRoute(params, meta);
|
417
|
+
}
|
425
418
|
}
|
426
419
|
}
|
427
420
|
|
@@ -429,12 +422,12 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
429
422
|
* Updates the URL bar and route to the given params.
|
430
423
|
*/
|
431
424
|
function updateRouteParams(params: AnyObject) {
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
}
|
425
|
+
const vueRouter = getVueRouter();
|
426
|
+
const { name: routeName } = vueRouter.currentRoute.value;
|
427
|
+
vueRouter.push({
|
428
|
+
name: (Array.isArray(routeName) ? routeName[0] : routeName) || "home",
|
429
|
+
params
|
430
|
+
});
|
438
431
|
}
|
439
432
|
|
440
433
|
function setPanelFromRoute(params: RouteParams, meta: AnyObject) {
|
@@ -445,6 +438,13 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
445
438
|
}
|
446
439
|
}
|
447
440
|
|
441
|
+
function getVueRouter(): Router {
|
442
|
+
if (!danxOptions.value.router) {
|
443
|
+
throw new Error("Vue Router must be configured in danxOptions");
|
444
|
+
}
|
445
|
+
return danxOptions.value.router;
|
446
|
+
}
|
447
|
+
|
448
448
|
return {
|
449
449
|
// State
|
450
450
|
name,
|
@@ -474,6 +474,7 @@ export function useListControls(name: string, options: ListControlsOptions): Act
|
|
474
474
|
loadSummary,
|
475
475
|
loadListAndSummary,
|
476
476
|
loadMore,
|
477
|
+
loadFieldOptions,
|
477
478
|
getActiveItemDetails,
|
478
479
|
refreshAll,
|
479
480
|
exportList,
|
@@ -8,10 +8,12 @@
|
|
8
8
|
:key="'nav-item-' + item.label"
|
9
9
|
class="nav-menu-item-box"
|
10
10
|
>
|
11
|
-
<
|
11
|
+
<a
|
12
12
|
class="nav-menu-item flex flex-nowrap"
|
13
|
+
:href="resolveUrl(item)"
|
13
14
|
:class="item.class || itemClass"
|
14
|
-
|
15
|
+
:target="item.target || '_self'"
|
16
|
+
@click="onClick($event, item)"
|
15
17
|
>
|
16
18
|
<div
|
17
19
|
v-if="item.icon"
|
@@ -36,7 +38,7 @@
|
|
36
38
|
>
|
37
39
|
{{ item.tooltip?.text || item.label }}
|
38
40
|
</QTooltip>
|
39
|
-
</
|
41
|
+
</a>
|
40
42
|
<QSeparator
|
41
43
|
v-if="item.separator"
|
42
44
|
:key="'separator-' + item.label"
|
@@ -47,55 +49,96 @@
|
|
47
49
|
</template>
|
48
50
|
<script setup>
|
49
51
|
import { computed } from "vue";
|
52
|
+
import { danxOptions } from "../../config";
|
50
53
|
|
51
54
|
const props = defineProps({
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
55
|
+
collapsed: Boolean,
|
56
|
+
itemClass: {
|
57
|
+
type: String,
|
58
|
+
default: "hover:bg-gray-200"
|
59
|
+
},
|
60
|
+
activeClass: {
|
61
|
+
type: String,
|
62
|
+
default: "bg-blue-200"
|
63
|
+
},
|
64
|
+
items: {
|
65
|
+
type: Array,
|
66
|
+
required: true
|
67
|
+
}
|
65
68
|
});
|
66
69
|
|
70
|
+
const router = danxOptions.value.router;
|
67
71
|
const allowedItems = computed(() => props.items.filter((item) => !item.hidden));
|
72
|
+
|
73
|
+
function getItemRoute(item) {
|
74
|
+
if (!router) {
|
75
|
+
console.error("Router is not available. Configure in danx options.");
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
|
79
|
+
return typeof item.route === "function" ? item.route() : item.route;
|
80
|
+
}
|
81
|
+
|
82
|
+
function onClick(e, item) {
|
83
|
+
if (!item.url && !e.ctrlKey) {
|
84
|
+
e.preventDefault();
|
85
|
+
}
|
86
|
+
|
87
|
+
if (item.disabled || e.ctrlKey) {
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (item.onClick) {
|
92
|
+
item.onClick();
|
93
|
+
}
|
94
|
+
|
95
|
+
if (item.route) {
|
96
|
+
router.push(getItemRoute(item));
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
function resolveUrl(item) {
|
101
|
+
if (item.url) {
|
102
|
+
return item.url;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (item.route) {
|
106
|
+
return router.resolve(getItemRoute(item))?.href || "#";
|
107
|
+
}
|
108
|
+
|
109
|
+
return "#";
|
110
|
+
}
|
68
111
|
</script>
|
69
112
|
|
70
113
|
<style lang="scss">
|
71
114
|
.nav-menu-item {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
115
|
+
padding: 1em;
|
116
|
+
border-radius: 0.5em;
|
117
|
+
font-weight: bold;
|
118
|
+
font-size: 14px;
|
119
|
+
transition: all 150ms, color 0ms;
|
120
|
+
cursor: pointer;
|
121
|
+
|
122
|
+
&.is-disabled {
|
123
|
+
@apply bg-inherit;
|
124
|
+
}
|
125
|
+
|
126
|
+
.label {
|
127
|
+
@apply transition-all;
|
128
|
+
}
|
129
|
+
|
130
|
+
.nav-icon {
|
131
|
+
@apply w-5 h-5 flex-shrink-0;
|
132
|
+
}
|
90
133
|
}
|
91
134
|
|
92
135
|
.is-collapsed {
|
93
|
-
|
94
|
-
|
95
|
-
|
136
|
+
.nav-link {
|
137
|
+
width: 3.8em;
|
138
|
+
}
|
96
139
|
|
97
|
-
|
98
|
-
|
99
|
-
|
140
|
+
.label {
|
141
|
+
@apply opacity-0;
|
142
|
+
}
|
100
143
|
}
|
101
144
|
</style>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<template>
|
2
2
|
<ContentDrawer
|
3
|
-
position="
|
3
|
+
:position="position"
|
4
4
|
show
|
5
5
|
overlay
|
6
6
|
content-class="h-full"
|
@@ -82,6 +82,7 @@ export interface Props {
|
|
82
82
|
activeItem: ActionTargetItem;
|
83
83
|
tabsClass?: string | object,
|
84
84
|
panelsClass?: string | object,
|
85
|
+
position?: "standard" | "right" | "left";
|
85
86
|
panels: ActionPanel[]
|
86
87
|
}
|
87
88
|
|
@@ -89,8 +90,9 @@ defineEmits(["update:model-value", "close"]);
|
|
89
90
|
const props = withDefaults(defineProps<Props>(), {
|
90
91
|
title: "",
|
91
92
|
modelValue: null,
|
92
|
-
tabsClass: "w-[13.5rem]",
|
93
|
-
panelsClass: "w-[
|
93
|
+
tabsClass: "w-[13.5rem] flex-shrink-0",
|
94
|
+
panelsClass: "w-[80rem]",
|
95
|
+
position: "right"
|
94
96
|
});
|
95
97
|
|
96
98
|
const activePanel = ref(props.modelValue);
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<template>
|
2
|
+
<Transition name="autoHeight">
|
3
|
+
<slot />
|
4
|
+
</Transition>
|
5
|
+
</template>
|
6
|
+
|
7
|
+
<style lang="scss">
|
8
|
+
.autoHeight-enter-active,
|
9
|
+
.autoHeight-leave-active {
|
10
|
+
transition: height .3s linear;
|
11
|
+
height: calc-size(auto);
|
12
|
+
}
|
13
|
+
|
14
|
+
.autoHeight-enter-to, .autoHeight-leave-from {
|
15
|
+
height: calc-size(auto);
|
16
|
+
}
|
17
|
+
|
18
|
+
.autoHeight-enter-from, .autoHeight-leave-to {
|
19
|
+
height: 0;
|
20
|
+
}
|
21
|
+
</style>
|
@@ -1,3 +1,4 @@
|
|
1
|
+
export { default as AutoHeightTransition } from "./AutoHeightTransition.vue";
|
1
2
|
export { default as ListTransition } from "./ListTransition.vue";
|
2
3
|
export { default as MaxHeightTransition } from "./MaxHeightTransition.vue";
|
3
4
|
export { default as SlideTransition } from "./SlideTransition.vue";
|
package/src/config/index.ts
CHANGED
package/src/helpers/actions.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { useDebounceFn } from "@vueuse/core";
|
2
2
|
import { uid } from "quasar";
|
3
3
|
import { isReactive, Ref, shallowRef } from "vue";
|
4
|
-
import type { ActionOptions,
|
4
|
+
import type { ActionOptions, ActionTarget, AnyObject, ResourceAction } from "../types";
|
5
5
|
import { FlashMessages } from "./FlashMessages";
|
6
6
|
import { storeObject } from "./objectStore";
|
7
7
|
|
@@ -11,36 +11,34 @@ export const activeActionVnode: Ref = shallowRef(null);
|
|
11
11
|
* Hook to perform an action on a set of targets
|
12
12
|
* This helper allows you to perform actions by name on a set of targets using a provided list of actions
|
13
13
|
*/
|
14
|
-
export function useActions(actions: ActionOptions[], globalOptions:
|
14
|
+
export function useActions(actions: ActionOptions[], globalOptions: Partial<ActionOptions> | null = null) {
|
15
15
|
const namespace = uid();
|
16
16
|
|
17
17
|
/**
|
18
18
|
* Resolve the action object based on the provided name (or return the object if the name is already an object)
|
19
19
|
*/
|
20
|
-
function getAction(actionName: string
|
21
|
-
let actionOptions: ActionOptions | ResourceAction;
|
22
|
-
|
20
|
+
function getAction(actionName: string, actionOptions?: Partial<ActionOptions>): ResourceAction {
|
23
21
|
/// Resolve the action options or resource action based on the provided input
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
actionOptions
|
22
|
+
const baseOptions = actions.find(a => a.name === actionName) || { name: actionName };
|
23
|
+
|
24
|
+
if (actionOptions) {
|
25
|
+
Object.assign(baseOptions, actionOptions);
|
28
26
|
}
|
29
27
|
|
30
28
|
// If the action is already reactive, return it
|
31
|
-
if (isReactive(
|
29
|
+
if (isReactive(baseOptions) && "__type" in baseOptions) return baseOptions as ResourceAction;
|
32
30
|
|
33
31
|
const resourceAction: ResourceAction = storeObject({
|
34
32
|
...globalOptions,
|
35
|
-
...
|
33
|
+
...baseOptions,
|
36
34
|
trigger: (target, input) => performAction(resourceAction, target, input),
|
37
35
|
isApplying: false,
|
38
36
|
__type: "__Action:" + namespace
|
39
37
|
});
|
40
38
|
|
41
39
|
// Assign Trigger function if it doesn't exist
|
42
|
-
if (
|
43
|
-
resourceAction.trigger = useDebounceFn((target, input) => performAction(resourceAction, target, input),
|
40
|
+
if (baseOptions.debounce) {
|
41
|
+
resourceAction.trigger = useDebounceFn((target, input) => performAction(resourceAction, target, input), baseOptions.debounce);
|
44
42
|
}
|
45
43
|
|
46
44
|
return resourceAction;
|
@@ -63,7 +61,7 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
|
|
63
61
|
}
|
64
62
|
}
|
65
63
|
|
66
|
-
return filteredActions.map((a: ActionOptions) => getAction(a));
|
64
|
+
return filteredActions.map((a: ActionOptions) => getAction(a.name));
|
67
65
|
}
|
68
66
|
|
69
67
|
/**
|
@@ -121,6 +119,11 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
|
|
121
119
|
result = await onConfirmAction(action, target, input);
|
122
120
|
}
|
123
121
|
|
122
|
+
// If the request was aborted (likely due to a newer request), just return immediately without changing state
|
123
|
+
if (result?.abort) {
|
124
|
+
return result;
|
125
|
+
}
|
126
|
+
|
124
127
|
action.isApplying = false;
|
125
128
|
setTargetSavingState(target, false);
|
126
129
|
|
@@ -187,8 +190,16 @@ async function onConfirmAction(action: ActionOptions, target: ActionTarget, inpu
|
|
187
190
|
result = await action.onAction(action.alias || action.name, target, input);
|
188
191
|
}
|
189
192
|
} catch (e) {
|
190
|
-
|
191
|
-
|
193
|
+
if (("" + e).match(/Request was aborted/)) {
|
194
|
+
result = { abort: true };
|
195
|
+
} else {
|
196
|
+
console.error(e);
|
197
|
+
result = { error: `An error occurred while performing the action ${action.label}. Please try again later.` };
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
if (result?.abort) {
|
202
|
+
return result;
|
192
203
|
}
|
193
204
|
|
194
205
|
// If there is no return value or the result marks it as successful, we show a success message
|
@@ -203,11 +214,11 @@ async function onConfirmAction(action: ActionOptions, target: ActionTarget, inpu
|
|
203
214
|
}
|
204
215
|
|
205
216
|
if (action.onSuccess) {
|
206
|
-
action.onSuccess(result, target, input);
|
217
|
+
await action.onSuccess(result, target, input);
|
207
218
|
}
|
208
219
|
|
209
220
|
if (isBatch && action.onBatchSuccess) {
|
210
|
-
action.onBatchSuccess(result, target, input);
|
221
|
+
await action.onBatchSuccess(result, target, input);
|
211
222
|
}
|
212
223
|
} else {
|
213
224
|
const errors = [];
|
@@ -230,12 +241,12 @@ async function onConfirmAction(action: ActionOptions, target: ActionTarget, inpu
|
|
230
241
|
FlashMessages.combine("error", errors);
|
231
242
|
|
232
243
|
if (action.onError) {
|
233
|
-
action.onError(result, target, input);
|
244
|
+
await action.onError(result, target, input);
|
234
245
|
}
|
235
246
|
}
|
236
247
|
|
237
248
|
if (action.onFinish) {
|
238
|
-
action.onFinish(result, target, input);
|
249
|
+
await action.onFinish(result, target, input);
|
239
250
|
}
|
240
251
|
|
241
252
|
return result;
|
package/src/helpers/formats.ts
CHANGED
@@ -339,21 +339,24 @@ export function fJSON(string: string | object) {
|
|
339
339
|
/**
|
340
340
|
* Convert markdown formatted string into a valid JSON object
|
341
341
|
*/
|
342
|
-
export function parseMarkdownJSON(string: string | object): object | null |
|
342
|
+
export function parseMarkdownJSON(string: string | object): object | null | false {
|
343
|
+
if (!string) return null;
|
343
344
|
if (typeof string === "object") return string as object;
|
344
345
|
|
345
346
|
try {
|
346
347
|
return JSON.parse(parseMarkdownCode(string));
|
347
348
|
} catch (e) {
|
348
|
-
return
|
349
|
+
return false;
|
349
350
|
}
|
350
351
|
}
|
351
352
|
|
352
|
-
export function parseMarkdownYAML(string: string): object | null |
|
353
|
+
export function parseMarkdownYAML(string: string): object | null | false {
|
354
|
+
if (!string) return null;
|
355
|
+
|
353
356
|
try {
|
354
357
|
return parseYAML(parseMarkdownCode(string)) || (string ? undefined : null);
|
355
358
|
} catch (e) {
|
356
|
-
return
|
359
|
+
return false;
|
357
360
|
}
|
358
361
|
}
|
359
362
|
|
@@ -372,7 +375,7 @@ export function fMarkdownCode(type: string, string: string | object): string {
|
|
372
375
|
if (typeof string === "object" || isJSON(string)) {
|
373
376
|
switch (type) {
|
374
377
|
case "yaml":
|
375
|
-
string = stringifyYAML(string);
|
378
|
+
string = stringifyYAML(typeof string === "string" ? JSON.parse(string) : string);
|
376
379
|
break;
|
377
380
|
case "ts":
|
378
381
|
string = "";
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { uid } from "quasar";
|
1
2
|
import { ShallowReactive, shallowReactive } from "vue";
|
2
3
|
import { TypedObject } from "../types";
|
3
4
|
|
@@ -8,10 +9,13 @@ const store = new Map<string, any>();
|
|
8
9
|
* Returns the stored object that should be used instead of the passed object as the returned object is shared across the system
|
9
10
|
*/
|
10
11
|
export function storeObject<T extends TypedObject>(newObject: T): ShallowReactive<T> {
|
11
|
-
const id = newObject
|
12
|
-
const type = newObject
|
12
|
+
const id = newObject?.id || newObject?.name;
|
13
|
+
const type = newObject?.__type;
|
13
14
|
if (!id || !type) return shallowReactive(newObject);
|
14
15
|
|
16
|
+
if (!newObject.__id) {
|
17
|
+
newObject.__id = uid();
|
18
|
+
}
|
15
19
|
if (!newObject.__timestamp) {
|
16
20
|
newObject.__timestamp = newObject.updated_at || 0;
|
17
21
|
}
|
@@ -34,6 +38,9 @@ export function storeObject<T extends TypedObject>(newObject: T): ShallowReactiv
|
|
34
38
|
for (const index in value) {
|
35
39
|
newObject[key][index] = storeObject(value[index]);
|
36
40
|
}
|
41
|
+
} else if (value?.__type) {
|
42
|
+
// @ts-expect-error newObject[key] is guaranteed to be a TypedObject
|
43
|
+
newObject[key] = storeObject(value);
|
37
44
|
}
|
38
45
|
}
|
39
46
|
|
package/src/helpers/request.ts
CHANGED
@@ -45,7 +45,7 @@ export const request: RequestApi = {
|
|
45
45
|
// If the request was aborted too late, but there was still another request that was made after the current,
|
46
46
|
// then abort the current request with an abort flag
|
47
47
|
if (timestamp < request.abortControllers[abortKey].timestamp) {
|
48
|
-
|
48
|
+
return { abort: true };
|
49
49
|
}
|
50
50
|
|
51
51
|
// Otherwise, the current is the most recent request, so we can delete the abort controller
|
package/src/helpers/routes.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { storeObject } from "../helpers";
|
1
2
|
import { ListControlsRoutes } from "../types";
|
2
3
|
import { downloadFile } from "./downloadPdf";
|
3
4
|
import { request } from "./request";
|
@@ -13,6 +14,10 @@ export function useActionRoutes(baseUrl: string): ListControlsRoutes {
|
|
13
14
|
details(target) {
|
14
15
|
return request.get(`${baseUrl}/${target.id}/details`);
|
15
16
|
},
|
17
|
+
async detailsAndStore(target) {
|
18
|
+
const item = await request.get(`${baseUrl}/${target.id}/details`);
|
19
|
+
return storeObject(item);
|
20
|
+
},
|
16
21
|
fieldOptions() {
|
17
22
|
return request.get(`${baseUrl}/field-options`);
|
18
23
|
},
|
package/src/types/actions.d.ts
CHANGED
@@ -13,6 +13,7 @@ export interface ActionPanel {
|
|
13
13
|
|
14
14
|
export interface ActionTargetItem extends TypedObject {
|
15
15
|
isSaving?: boolean;
|
16
|
+
updated_at?: string;
|
16
17
|
}
|
17
18
|
|
18
19
|
export type ActionTarget = ActionTargetItem[] | ActionTargetItem | null;
|
@@ -41,10 +42,6 @@ export interface ActionOptions {
|
|
41
42
|
onFinish?: (result: any, targets: ActionTarget, input: any) => any;
|
42
43
|
}
|
43
44
|
|
44
|
-
export interface ActionOptionsPartial extends ActionOptions {
|
45
|
-
name?: string;
|
46
|
-
}
|
47
|
-
|
48
45
|
export interface ResourceAction extends ActionOptions {
|
49
46
|
isApplying: boolean;
|
50
47
|
trigger: (target?: ActionTarget, input?: any) => Promise<any>;
|
package/src/types/config.d.ts
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import { QNotifyCreateOptions } from "quasar";
|
2
|
+
import { Router } from "vue-router";
|
2
3
|
import { FileUploadOptions } from "./files";
|
3
4
|
import { RequestOptions } from "./requests";
|
4
5
|
|
5
6
|
export interface DanxOptions {
|
6
7
|
tinyMceApiKey?: string;
|
7
8
|
fileUpload?: FileUploadOptions;
|
8
|
-
request?: RequestOptions
|
9
|
+
request?: RequestOptions;
|
10
|
+
router?: Router;
|
9
11
|
flashMessages?: {
|
10
12
|
default?: QNotifyCreateOptions;
|
11
13
|
success?: QNotifyCreateOptions;
|
package/src/types/controls.d.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import { ComputedRef, Ref, ShallowRef } from "vue";
|
2
|
-
import { Router } from "vue-router";
|
3
2
|
import { ActionTargetItem } from "./actions";
|
4
3
|
import { AnyObject, LabelValueItem } from "./shared";
|
5
4
|
|
@@ -29,6 +28,8 @@ export interface ListControlsRoutes {
|
|
29
28
|
|
30
29
|
details?(target: ActionTargetItem): Promise<ActionTargetItem>;
|
31
30
|
|
31
|
+
detailsAndStore?(target: ActionTargetItem): Promise<ActionTargetItem>;
|
32
|
+
|
32
33
|
more?(pager: ListControlsPagination): Promise<ActionTargetItem[]>;
|
33
34
|
|
34
35
|
fieldOptions?(filter?: AnyObject): Promise<AnyObject>;
|
@@ -67,10 +68,6 @@ export interface PagedItems {
|
|
67
68
|
} | undefined;
|
68
69
|
}
|
69
70
|
|
70
|
-
export interface ListControlsInitializeOptions {
|
71
|
-
vueRouter?: Router;
|
72
|
-
}
|
73
|
-
|
74
71
|
export interface ActionController {
|
75
72
|
name: string;
|
76
73
|
label: string;
|
@@ -95,15 +92,16 @@ export interface ActionController {
|
|
95
92
|
activePanel: ShallowRef<string | null>;
|
96
93
|
|
97
94
|
// Actions
|
98
|
-
initialize: (
|
95
|
+
initialize: () => void;
|
99
96
|
resetPaging: () => void;
|
100
|
-
setPagination: (updated: ListControlsPagination) => void;
|
97
|
+
setPagination: (updated: Partial<ListControlsPagination>) => void;
|
101
98
|
setSelectedRows: (selection: ActionTargetItem[]) => void;
|
102
99
|
clearSelectedRows: () => void;
|
103
100
|
loadList: (filter?: ListControlsFilter) => Promise<void>;
|
104
101
|
loadSummary: (filter?: ListControlsFilter) => Promise<void>;
|
105
102
|
loadListAndSummary: (filter?: ListControlsFilter) => Promise<void>;
|
106
103
|
loadMore: (index: number, perPage?: number) => Promise<boolean>;
|
104
|
+
loadFieldOptions: () => Promise<void>;
|
107
105
|
getActiveItemDetails: () => Promise<void>;
|
108
106
|
refreshAll: () => Promise<void[]>;
|
109
107
|
exportList: (filter?: ListControlsFilter) => Promise<void>;
|
package/src/types/forms.d.ts
CHANGED