quasar-ui-danx 0.4.12 → 0.4.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. package/dist/danx.es.js +10975 -6424
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +137 -7
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +3 -2
  7. package/src/components/ActionTable/ActionTable.vue +65 -63
  8. package/src/components/ActionTable/Form/ActionForm.vue +18 -12
  9. package/src/components/ActionTable/Form/RenderedForm.vue +86 -60
  10. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +80 -70
  11. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +29 -29
  12. package/src/components/ActionTable/listControls.ts +32 -31
  13. package/src/components/Navigation/NavigationMenu.vue +83 -40
  14. package/src/components/PanelsDrawer/PanelsDrawer.vue +20 -8
  15. package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +3 -1
  16. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +17 -4
  17. package/src/components/Utility/Tools/RenderVnode.vue +5 -1
  18. package/src/components/Utility/Transitions/AutoHeightTransition.vue +21 -0
  19. package/src/components/Utility/Transitions/index.ts +1 -0
  20. package/src/config/index.ts +1 -0
  21. package/src/helpers/actions.ts +31 -20
  22. package/src/helpers/date.ts +2 -2
  23. package/src/helpers/formats.ts +55 -5
  24. package/src/helpers/objectStore.ts +7 -0
  25. package/src/helpers/request.ts +1 -1
  26. package/src/helpers/routes.ts +5 -0
  27. package/src/helpers/utils.ts +3 -3
  28. package/src/types/actions.d.ts +4 -7
  29. package/src/types/config.d.ts +3 -1
  30. package/src/types/controls.d.ts +5 -7
  31. package/src/types/forms.d.ts +20 -1
  32. package/src/types/shared.d.ts +1 -0
@@ -1,5 +1,6 @@
1
1
  import { computed, Ref, ref, shallowRef, watch } from "vue";
2
- import { RouteLocationNormalizedLoaded, RouteParams, Router } from "vue-router";
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 || !isInitialized) return;
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(initOptions?: ListControlsInitializeOptions) {
406
- vueRouter = initOptions?.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 && vueRoute && vueRouter) {
415
- const { params, meta } = vueRoute;
416
-
417
- const controlRouteName = vueRoute.name;
418
- vueRouter.afterEach((to) => {
419
- if (to.name === controlRouteName) {
420
- setPanelFromRoute(to.params, to.meta);
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
- setPanelFromRoute(params, meta);
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
- if (vueRouter && vueRoute) {
433
- vueRouter.push({
434
- name: (Array.isArray(vueRoute.name) ? vueRoute.name[0] : vueRoute.name) || "home",
435
- params
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
- <div
11
+ <a
12
12
  class="nav-menu-item flex flex-nowrap"
13
+ :href="resolveUrl(item)"
13
14
  :class="item.class || itemClass"
14
- @click="item.onClick"
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
- </div>
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
- collapsed: Boolean,
53
- itemClass: {
54
- type: String,
55
- default: "hover:bg-gray-200"
56
- },
57
- activeClass: {
58
- type: String,
59
- default: "bg-blue-200"
60
- },
61
- items: {
62
- type: Array,
63
- required: true
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
- padding: 1em;
73
- border-radius: 0.5em;
74
- font-weight: bold;
75
- font-size: 14px;
76
- transition: all 150ms, color 0ms;
77
- cursor: pointer;
78
-
79
- &.is-disabled {
80
- @apply bg-inherit;
81
- }
82
-
83
- .label {
84
- @apply transition-all;
85
- }
86
-
87
- .nav-icon {
88
- @apply w-5 h-5 flex-shrink-0;
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
- .nav-link {
94
- width: 3.8em;
95
- }
136
+ .nav-link {
137
+ width: 3.8em;
138
+ }
96
139
 
97
- .label {
98
- @apply opacity-0;
99
- }
140
+ .label {
141
+ @apply opacity-0;
142
+ }
100
143
  }
101
144
  </style>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <ContentDrawer
3
- position="right"
4
- :show="true"
3
+ :position="position"
4
+ show
5
5
  overlay
6
6
  content-class="h-full"
7
7
  class="dx-panels-drawer"
@@ -13,7 +13,13 @@
13
13
  <div class="dx-panels-drawer-header flex items-center px-6 py-4">
14
14
  <div class="flex-grow">
15
15
  <slot name="header">
16
- <h2>{{ title }}</h2>
16
+ <h2 v-if="title">
17
+ {{ title }}
18
+ </h2>
19
+ <div v-if="!activeItem">
20
+ Loading
21
+ <QSpinnerHourglass />
22
+ </div>
17
23
  </slot>
18
24
  </div>
19
25
  <div
@@ -32,10 +38,14 @@
32
38
  </div>
33
39
  </div>
34
40
  <div class="dx-panels-drawer-body flex-grow overflow-hidden h-full">
35
- <div class="flex items-stretch flex-nowrap h-full">
41
+ <div
42
+ v-if="activeItem.__timestamp > 0"
43
+ class="flex items-stretch flex-nowrap h-full"
44
+ >
36
45
  <PanelsDrawerTabs
37
46
  :key="'pd-tabs:' + activeItem.id"
38
47
  v-model="activePanel"
48
+ :active-item="activeItem"
39
49
  :class="tabsClass"
40
50
  :panels="panels"
41
51
  @update:model-value="$emit('update:model-value', $event)"
@@ -44,6 +54,7 @@
44
54
  :key="'pd-panels:' + activeItem.id"
45
55
  :panels="panels"
46
56
  :active-panel="activePanel"
57
+ :active-item="activeItem"
47
58
  :class="activePanelOptions?.class || panelsClass"
48
59
  />
49
60
  <div
@@ -68,9 +79,10 @@ import PanelsDrawerTabs from "./PanelsDrawerTabs";
68
79
  export interface Props {
69
80
  title?: string,
70
81
  modelValue?: string | number,
71
- activeItem?: ActionTargetItem;
82
+ activeItem: ActionTargetItem;
72
83
  tabsClass?: string | object,
73
84
  panelsClass?: string | object,
85
+ position?: "standard" | "right" | "left";
74
86
  panels: ActionPanel[]
75
87
  }
76
88
 
@@ -78,9 +90,9 @@ defineEmits(["update:model-value", "close"]);
78
90
  const props = withDefaults(defineProps<Props>(), {
79
91
  title: "",
80
92
  modelValue: null,
81
- activeItem: null,
82
- tabsClass: "w-[13.5rem]",
83
- panelsClass: "w-[35.5rem]"
93
+ tabsClass: "w-[13.5rem] flex-shrink-0",
94
+ panelsClass: "w-[80rem]",
95
+ position: "right"
84
96
  });
85
97
 
86
98
  const activePanel = ref(props.modelValue);
@@ -11,17 +11,19 @@
11
11
  <RenderVnode
12
12
  v-if="panel.vnode"
13
13
  :vnode="panel.vnode"
14
+ :props="activeItem"
14
15
  />
15
16
  </QTabPanel>
16
17
  </QTabPanels>
17
18
  </template>
18
19
 
19
20
  <script setup lang="ts">
20
- import { ActionPanel } from "../../types";
21
+ import { ActionPanel, ActionTargetItem } from "../../types";
21
22
  import { RenderVnode } from "../Utility";
22
23
 
23
24
  defineProps<{
24
25
  activePanel?: string | number,
26
+ activeItem: ActionTargetItem,
25
27
  panels: ActionPanel[]
26
28
  }>();
27
29
  </script>
@@ -9,11 +9,11 @@
9
9
  @update:model-value="$emit('update:model-value', $event)"
10
10
  >
11
11
  <template v-for="panel in panels">
12
- <template v-if="panel.enabled === undefined || !!panel.enabled">
12
+ <template v-if="isEnabled(panel)">
13
13
  <RenderVnode
14
14
  v-if="panel.tabVnode"
15
15
  :key="panel.name"
16
- :vnode="panel.tabVnode(modelValue)"
16
+ :vnode="panel.tabVnode(activeItem, modelValue)"
17
17
  :is-active="modelValue === panel.name"
18
18
  :name="panel.name"
19
19
  :label="panel.label"
@@ -30,19 +30,32 @@
30
30
  </template>
31
31
  <script setup lang="ts">
32
32
  import { QTab } from "quasar";
33
- import { ActionPanel } from "../../types";
33
+ import { ActionPanel, ActionTargetItem } from "../../types";
34
34
  import { RenderVnode } from "../Utility";
35
35
 
36
36
  defineEmits(["update:model-value"]);
37
37
 
38
38
  interface Props {
39
39
  modelValue?: string | number;
40
+ activeItem: ActionTargetItem;
40
41
  panels: ActionPanel[];
41
42
  }
42
43
 
43
- withDefaults(defineProps<Props>(), {
44
+ const props = withDefaults(defineProps<Props>(), {
44
45
  modelValue: "general"
45
46
  });
47
+
48
+ function isEnabled(panel) {
49
+ if (panel.enabled === undefined) return true;
50
+
51
+ if (!panel.enabled) return false;
52
+
53
+ if (typeof panel.enabled === "function") {
54
+ return panel.enabled(props.activeItem);
55
+ }
56
+
57
+ return true;
58
+ }
46
59
  </script>
47
60
 
48
61
  <style lang="scss" module="cls">
@@ -11,7 +11,7 @@ const RenderVnode = (props) => {
11
11
  }
12
12
 
13
13
  if (typeof props.vnode === "function") {
14
- return props.vnode(props.props);
14
+ return props.vnode(props.props, props.params);
15
15
  }
16
16
 
17
17
  return null;
@@ -24,6 +24,10 @@ RenderVnode.props = {
24
24
  props: {
25
25
  type: Object,
26
26
  default: () => ({})
27
+ },
28
+ params: {
29
+ type: Object,
30
+ default: null
27
31
  }
28
32
  };
29
33
  export default RenderVnode;
@@ -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";
@@ -3,6 +3,7 @@ import { DanxOptions } from "../types";
3
3
 
4
4
  export const danxOptions = shallowRef<DanxOptions>({
5
5
  tinyMceApiKey: "set-api-key-in-danx-options",
6
+ router: undefined,
6
7
  request: {
7
8
  baseUrl: "",
8
9
  headers: {},
@@ -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, ActionOptionsPartial, ActionTarget, AnyObject, ResourceAction } from "../types";
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: ActionOptionsPartial | null = null) {
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 | ActionOptions | ResourceAction): ResourceAction {
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
- if (typeof actionName === "string") {
25
- actionOptions = actions.find(a => a.name === actionName) || { name: actionName };
26
- } else {
27
- actionOptions = actionName;
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(actionOptions) && "__type" in actionOptions) return actionOptions as ResourceAction;
29
+ if (isReactive(baseOptions) && "__type" in baseOptions) return baseOptions as ResourceAction;
32
30
 
33
31
  const resourceAction: ResourceAction = storeObject({
34
32
  ...globalOptions,
35
- ...actionOptions,
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 (actionOptions.debounce) {
43
- resourceAction.trigger = useDebounceFn((target, input) => performAction(resourceAction, target, input), actionOptions.debounce);
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
- console.error(e);
191
- result = { error: `An error occurred while performing the action ${action.label}. Please try again later.` };
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;
@@ -1,5 +1,5 @@
1
1
  import { parseDateTime } from "./formats";
2
2
 
3
- export function diffInDays(date1, date2) {
4
- return parseDateTime(date2).diff(parseDateTime(date1), ["days"]).days;
3
+ export function diffInDays(date1: string, date2: string) {
4
+ return parseDateTime(date2).diff(parseDateTime(date1), ["days"]).days;
5
5
  }