quasar-ui-danx 0.4.26 → 0.4.28

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.
Files changed (37) hide show
  1. package/dist/danx.es.js +24536 -24082
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +109 -109
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +1 -1
  7. package/src/components/ActionTable/ActionTable.vue +29 -7
  8. package/src/components/ActionTable/Filters/FilterableField.vue +14 -2
  9. package/src/components/ActionTable/Form/ActionForm.vue +17 -12
  10. package/src/components/ActionTable/Form/Fields/DateField.vue +24 -20
  11. package/src/components/ActionTable/Form/Fields/DateRangeField.vue +57 -53
  12. package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +9 -2
  13. package/src/components/ActionTable/Form/Fields/EditableDiv.vue +12 -12
  14. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +1 -1
  15. package/src/components/ActionTable/Form/Fields/SelectField.vue +27 -6
  16. package/src/components/ActionTable/Form/Fields/SelectOrCreateField.vue +56 -0
  17. package/src/components/ActionTable/Form/Fields/index.ts +1 -0
  18. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +20 -23
  19. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +44 -36
  20. package/src/components/ActionTable/listControls.ts +3 -3
  21. package/src/components/DragAndDrop/ListItemDraggable.vue +38 -28
  22. package/src/components/DragAndDrop/dragAndDrop.ts +220 -220
  23. package/src/components/DragAndDrop/listDragAndDrop.ts +256 -227
  24. package/src/components/PanelsDrawer/PanelsDrawer.vue +7 -7
  25. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +3 -3
  26. package/src/components/Utility/Buttons/ShowHideButton.vue +86 -0
  27. package/src/components/Utility/Buttons/index.ts +1 -0
  28. package/src/components/Utility/Dialogs/ActionFormDialog.vue +30 -0
  29. package/src/components/Utility/Dialogs/CreateNewWithNameDialog.vue +26 -0
  30. package/src/components/Utility/Dialogs/RenderedFormDialog.vue +50 -0
  31. package/src/components/Utility/Dialogs/index.ts +3 -0
  32. package/src/helpers/actions.ts +84 -20
  33. package/src/helpers/formats.ts +23 -21
  34. package/src/helpers/objectStore.ts +24 -12
  35. package/src/types/actions.d.ts +12 -6
  36. package/src/types/controls.d.ts +23 -6
  37. package/types/vue-shims.d.ts +3 -2
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <ConfirmDialog
3
+ :title="title"
4
+ :confirm-text="confirmText || title"
5
+ @confirm="$emit('confirm', {name})"
6
+ @close="$emit('close')"
7
+ >
8
+ <ActionForm
9
+ :form="form"
10
+ :action="action"
11
+ :target="target"
12
+ />
13
+ </ConfirmDialog>
14
+ </template>
15
+ <script setup lang="ts">
16
+ import { ref } from "vue";
17
+ import { ActionTargetItem, Form, ResourceAction } from "../../../types";
18
+ import { ActionForm } from "../../ActionTable";
19
+ import ConfirmDialog from "./ConfirmDialog";
20
+
21
+ defineEmits(["confirm", "close"]);
22
+ defineProps<{
23
+ title: string;
24
+ confirmText?: string;
25
+ form: Form;
26
+ action: ResourceAction;
27
+ target: ActionTargetItem;
28
+ }>();
29
+ const name = ref("");
30
+ </script>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <ConfirmDialog
3
+ :title="title"
4
+ :confirm-text="confirmText || title"
5
+ @confirm="$emit('confirm', {name})"
6
+ @close="$emit('close')"
7
+ >
8
+ <TextField
9
+ v-model="name"
10
+ label="Name"
11
+ />
12
+ <slot />
13
+ </ConfirmDialog>
14
+ </template>
15
+ <script setup lang="ts">
16
+ import { ref } from "vue";
17
+ import { TextField } from "../../ActionTable";
18
+ import ConfirmDialog from "./ConfirmDialog";
19
+
20
+ defineEmits(["confirm", "close"]);
21
+ defineProps<{
22
+ title: string;
23
+ confirmText?: string;
24
+ }>();
25
+ const name = ref("");
26
+ </script>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <ConfirmDialog
3
+ :title="title"
4
+ :confirm-text="confirmText || title"
5
+ :content-class="contentClass"
6
+ @confirm="$emit('confirm', input)"
7
+ @close="$emit('close')"
8
+ >
9
+ <RenderedForm
10
+ v-bind="renderedFormProps"
11
+ v-model:values="input"
12
+ empty-value=""
13
+ >
14
+ <slot />
15
+ </RenderedForm>
16
+ </ConfirmDialog>
17
+ </template>
18
+ <script setup lang="ts">
19
+ import { AnyObject, Form } from "../../../types";
20
+ import { RenderedForm } from "../../ActionTable/Form";
21
+ import ConfirmDialog from "./ConfirmDialog";
22
+
23
+ defineEmits(["confirm", "close"]);
24
+ const props = defineProps<{
25
+ title: string;
26
+ confirmText?: string;
27
+ form: Form;
28
+ noLabel?: boolean;
29
+ showName?: boolean;
30
+ disable?: boolean;
31
+ readonly?: boolean;
32
+ clearable?: boolean;
33
+ fieldClass?: string;
34
+ savingClass?: string;
35
+ hideSavedAt?: boolean;
36
+ contentClass?: string;
37
+ }>();
38
+ const input = defineModel<AnyObject>();
39
+
40
+ const renderedFormProps = {
41
+ form: props.form,
42
+ noLabel: props.noLabel,
43
+ showName: props.showName,
44
+ disable: props.disable,
45
+ readonly: props.readonly,
46
+ clearable: props.clearable,
47
+ fieldClass: props.fieldClass,
48
+ savingClass: props.savingClass
49
+ };
50
+ </script>
@@ -1,6 +1,9 @@
1
+ export { default as ActionFormDialog } from "./ActionFormDialog.vue";
1
2
  export { default as ConfirmActionDialog } from "./ConfirmActionDialog.vue";
2
3
  export { default as ConfirmDialog } from "./ConfirmDialog.vue";
4
+ export { default as CreateNewWithNameDialog } from "./CreateNewWithNameDialog.vue";
3
5
  export { default as FullScreenCarouselDialog } from "./FullscreenCarouselDialog.vue";
4
6
  export { default as FullScreenDialog } from "./FullScreenDialog.vue";
5
7
  export { default as InfoDialog } from "./InfoDialog.vue";
6
8
  export { default as InputDialog } from "./InputDialog.vue";
9
+ export { default as RenderedFormDialog } from "./RenderedFormDialog.vue";
@@ -1,7 +1,9 @@
1
1
  import { useDebounceFn } from "@vueuse/core";
2
+ import { FaSolidCopy as CopyIcon, FaSolidPencil as EditIcon, FaSolidTrash as DeleteIcon } from "danx-icon";
2
3
  import { uid } from "quasar";
3
- import { isReactive, Ref, shallowRef } from "vue";
4
- import type { ActionOptions, ActionTarget, AnyObject, ResourceAction } from "../types";
4
+ import { h, isReactive, Ref, shallowRef } from "vue";
5
+ import { ConfirmActionDialog, CreateNewWithNameDialog } from "../components";
6
+ import type { ActionGlobalOptions, ActionOptions, ActionTarget, ListController, ResourceAction } from "../types";
5
7
  import { FlashMessages } from "./FlashMessages";
6
8
  import { storeObject } from "./objectStore";
7
9
 
@@ -11,7 +13,7 @@ export const activeActionVnode: Ref = shallowRef(null);
11
13
  * Hook to perform an action on a set of targets
12
14
  * This helper allows you to perform actions by name on a set of targets using a provided list of actions
13
15
  */
14
- export function useActions(actions: ActionOptions[], globalOptions: Partial<ActionOptions> | null = null) {
16
+ export function useActions(actions: ActionOptions[], globalOptions: ActionGlobalOptions | null = null) {
15
17
  const namespace = uid();
16
18
 
17
19
  /**
@@ -33,6 +35,14 @@ export function useActions(actions: ActionOptions[], globalOptions: Partial<Acti
33
35
  return storeObject(extendedAction);
34
36
  }
35
37
 
38
+ /**
39
+ * Updates an action replacing the old options with the new options
40
+ */
41
+ function modifyAction(actionName: string, actionOptions: Partial<ActionOptions>): ResourceAction {
42
+ const action = getAction(actionName);
43
+ return storeObject({ ...action, ...actionOptions });
44
+ }
45
+
36
46
  /**
37
47
  * Resolve the action object based on the provided name (or return the object if the name is already an object)
38
48
  */
@@ -48,6 +58,9 @@ export function useActions(actions: ActionOptions[], globalOptions: Partial<Acti
48
58
  if (isReactive(baseOptions) && "__type" in baseOptions) return baseOptions as ResourceAction;
49
59
 
50
60
  const resourceAction: ResourceAction = storeObject({
61
+ onAction: globalOptions?.routes?.applyAction,
62
+ onBatchAction: globalOptions?.routes?.batchAction,
63
+ onBatchSuccess: globalOptions?.controls?.clearSelectedRows,
51
64
  ...globalOptions,
52
65
  ...baseOptions,
53
66
  trigger: (target, input) => performAction(resourceAction, target, input),
@@ -60,27 +73,22 @@ export function useActions(actions: ActionOptions[], globalOptions: Partial<Acti
60
73
  resourceAction.trigger = useDebounceFn((target, input) => performAction(resourceAction, target, input), baseOptions.debounce);
61
74
  }
62
75
 
76
+ // Splice the resourceAction in place of the action in the actions list
77
+ actions.splice(actions.findIndex(a => a.name === actionName), 1, resourceAction);
78
+
63
79
  return resourceAction;
64
80
  }
65
81
 
66
82
  /**
67
- * Filter the list of actions based on the provided filters in key-value pairs
68
- * You can filter on any ActionOptions property by matching the value exactly or by providing an array of values
69
- *
70
- * @param filters
71
- * @returns {ActionOptions[]}
83
+ * Returns a filtered list of actions. Useful for building ordered menus.
84
+ * NOTE: If an action doesn't already exist, it will be created.
72
85
  */
73
- function getActions(filters?: AnyObject): ResourceAction[] {
74
- let filteredActions = [...actions];
75
-
76
- if (filters) {
77
- for (const filterKey of Object.keys(filters)) {
78
- const filterValue = filters[filterKey];
79
- filteredActions = filteredActions.filter((a: AnyObject) => a[filterKey] === filterValue || (Array.isArray(filterValue) && filterValue.includes(a[filterKey])));
80
- }
86
+ function getActions(names: string[]): ResourceAction[] {
87
+ const filteredActions = [];
88
+ for (const name of names) {
89
+ filteredActions.push(getAction(name));
81
90
  }
82
-
83
- return filteredActions.map((a: ActionOptions) => getAction(a.name));
91
+ return filteredActions;
84
92
  }
85
93
 
86
94
  /**
@@ -90,11 +98,15 @@ export function useActions(actions: ActionOptions[], globalOptions: Partial<Acti
90
98
  * @param {object[]|object} target - an array of targets or a single target object
91
99
  * @param {any} input - The input data to pass to the action handler
92
100
  */
93
- async function performAction(action: ResourceAction, target: ActionTarget = null, input: any = null) {
101
+ async function performAction(action: ResourceAction | string, target: ActionTarget = null, input: any = null): Promise<any | void> {
102
+ if (typeof action === "string") {
103
+ action = getAction(action);
104
+ }
105
+
94
106
  // Resolve the original action, if the current action is an alias
95
107
  const aliasedAction = action.alias ? getAction(action.alias) : null;
96
108
 
97
- const vnode = action.vnode && action.vnode(target);
109
+ const vnode = action.vnode && action.vnode(target, input);
98
110
  let result: any;
99
111
 
100
112
  // Run the onStart handler if it exists and quit the operation if it returns false
@@ -160,6 +172,8 @@ export function useActions(actions: ActionOptions[], globalOptions: Partial<Acti
160
172
  return {
161
173
  getAction,
162
174
  getActions,
175
+ action: performAction,
176
+ modifyAction,
163
177
  extendAction
164
178
  };
165
179
  }
@@ -271,3 +285,53 @@ async function onConfirmAction(action: ActionOptions, target: ActionTarget, inpu
271
285
 
272
286
  return result;
273
287
  }
288
+
289
+ export function withDefaultActions(label: string, listController?: ListController): ActionOptions[] {
290
+ return [
291
+ {
292
+ name: "create",
293
+ label: "Create " + label,
294
+ vnode: () => h(CreateNewWithNameDialog, { title: "Create " + label }),
295
+ onFinish: listController && ((result) => {
296
+ listController.activatePanel(result.item, "edit");
297
+ listController.loadListAndSummary();
298
+ })
299
+ },
300
+ {
301
+ name: "update",
302
+ optimistic: true
303
+ },
304
+ {
305
+ name: "update-debounced",
306
+ alias: "update",
307
+ debounce: 1000,
308
+ optimistic: true
309
+ },
310
+ {
311
+ name: "copy",
312
+ label: "Copy",
313
+ icon: CopyIcon,
314
+ onSuccess: listController?.loadListAndSummary
315
+ },
316
+ {
317
+ name: "edit",
318
+ label: "Edit",
319
+ icon: EditIcon,
320
+ onAction: (action, target) => listController?.activatePanel(target, "edit")
321
+ },
322
+ {
323
+ name: "delete",
324
+ label: "Delete",
325
+ class: "text-red-500",
326
+ iconClass: "text-red-500",
327
+ icon: DeleteIcon,
328
+ onFinish: listController?.loadListAndSummary,
329
+ vnode: (target: ActionTarget) => h(ConfirmActionDialog, {
330
+ action: "Delete",
331
+ label,
332
+ target,
333
+ confirmClass: "bg-red-900"
334
+ })
335
+ }
336
+ ];
337
+ }
@@ -32,32 +32,35 @@ export function remoteDateTime(dateTimeString: string) {
32
32
  /**
33
33
  * Parses a date string into a Luxon DateTime object
34
34
  */
35
- export function parseDateTime(dateTime: string | DateTime | null): DateTime {
35
+ export function parseDateTime(dateTime: string | DateTime | null): DateTime<boolean> | null {
36
36
  if (typeof dateTime === "string") {
37
- dateTime = dateTime.replace("T", " ").replace(/\//g, "-");
38
- return DateTime.fromSQL(dateTime);
37
+ return parseSqlDateTime(dateTime) || parseQDate(dateTime) || parseQDateTime(dateTime);
39
38
  }
40
39
  return dateTime || DateTime.fromSQL("0000-00-00 00:00:00");
41
40
  }
42
41
 
42
+ /**
43
+ * Parses a SQL formatted date string into a Luxon DateTime object
44
+ */
45
+ export function parseSqlDateTime(dateTime: string) {
46
+ const parsed = DateTime.fromSQL(dateTime.replace("T", " ").replace(/\//g, "-"));
47
+ return parsed.isValid ? parsed : null;
48
+ }
49
+
43
50
  /**
44
51
  * Parses a Quasar formatted date string into a Luxon DateTime object
45
- * @param date
46
- * @param format
47
- * @returns {DateTime}
48
52
  */
49
- export function parseQDate(date: string, format = "yyyy/MM/dd") {
50
- return DateTime.fromFormat(date, format);
53
+ export function parseQDate(date: string, format = "yyyy/MM/dd"): DateTime<boolean> | null {
54
+ const parsed = DateTime.fromFormat(date, format);
55
+ return parsed.isValid ? parsed : null;
51
56
  }
52
57
 
53
58
  /**
54
59
  * Parses a Quasar formatted date/time string into a Luxon DateTime object
55
- * @param date
56
- * @param format
57
- * @returns {DateTime}
58
60
  */
59
- export function parseQDateTime(date: string, format = "yyyy/MM/dd HH:mm:ss") {
60
- return DateTime.fromFormat(date, format);
61
+ export function parseQDateTime(date: string, format = "yyyy/MM/dd HH:mm:ss"): DateTime<boolean> | null {
62
+ const parsed = DateTime.fromFormat(date, format);
63
+ return parsed.isValid ? parsed : null;
61
64
  }
62
65
 
63
66
  /**
@@ -91,8 +94,8 @@ export function fDateTime(
91
94
  dateTime: string | DateTime | null = null,
92
95
  { format = "M/d/yy h:mma", empty = "- -" }: fDateOptions = {}
93
96
  ) {
94
- const formatted = parseDateTime(dateTime).toFormat(format).toLowerCase();
95
- return ["Invalid DateTime", "invalid datetime"].includes(formatted) ? empty : formatted;
97
+ const formatted = parseDateTime(dateTime)?.toFormat(format).toLowerCase();
98
+ return formatted || empty;
96
99
  }
97
100
 
98
101
  /**
@@ -111,9 +114,9 @@ export function dbDateTime(dateTime: string | DateTime | null = null) {
111
114
  * @param format
112
115
  * @returns {string}
113
116
  */
114
- export function fDate(dateTime: string, { empty = "--", format = "M/d/yy" }: fDateOptions = {}) {
115
- const formatted = parseDateTime(dateTime).toFormat(format || "M/d/yy");
116
- return ["Invalid DateTime", "invalid datetime"].includes(formatted) ? empty : formatted;
117
+ export function fDate(dateTime: string | DateTime | null, { empty = "--", format = "M/d/yy" }: fDateOptions = {}) {
118
+ const formatted = parseDateTime(dateTime)?.toFormat(format || "M/d/yy");
119
+ return formatted || empty;
117
120
  }
118
121
 
119
122
  /**
@@ -130,8 +133,8 @@ export function fSecondsToTime(second: number) {
130
133
 
131
134
  export function fElapsedTime(start: string, end?: string) {
132
135
  const endDateTime = end ? parseDateTime(end) : DateTime.now();
133
- const diff = endDateTime.diff(parseDateTime(start), ["hours", "minutes", "seconds"]);
134
- if (!diff.isValid) {
136
+ const diff = endDateTime?.diff(parseDateTime(start) || DateTime.now(), ["hours", "minutes", "seconds"]);
137
+ if (!diff?.isValid) {
135
138
  return "-";
136
139
  }
137
140
  const hours = Math.floor(diff.hours);
@@ -384,7 +387,6 @@ export function parseMarkdownCode(string: string): string {
384
387
  * ie: a valid JSON string with a ```json prefix and ``` postfix
385
388
  */
386
389
  export function fMarkdownCode(type: string, string: string | object): string {
387
- console.log("formatting", type, string);
388
390
  if (typeof string === "object" || isJSON(string)) {
389
391
  switch (type) {
390
392
  case "yaml":
@@ -1,6 +1,6 @@
1
1
  import { uid } from "quasar";
2
2
  import { ShallowReactive, shallowReactive } from "vue";
3
- import { TypedObject } from "../types";
3
+ import { AnyObject, TypedObject } from "../types";
4
4
  import { FlashMessages } from "./FlashMessages";
5
5
 
6
6
  const store = new Map<string, any>();
@@ -18,7 +18,7 @@ export function storeObjects<T extends TypedObject>(newObjects: T[]) {
18
18
  * Store an object in the object store via type + id
19
19
  * Returns the stored object that should be used instead of the passed object as the returned object is shared across the system
20
20
  */
21
- export function storeObject<T extends TypedObject>(newObject: T): ShallowReactive<T> {
21
+ export function storeObject<T extends TypedObject>(newObject: T, recentlyStoredObjects: AnyObject = {}): ShallowReactive<T> {
22
22
  const id = newObject?.id || newObject?.name;
23
23
  const type = newObject?.__type;
24
24
  if (!id || !type) return shallowReactive(newObject);
@@ -32,38 +32,50 @@ export function storeObject<T extends TypedObject>(newObject: T): ShallowReactiv
32
32
 
33
33
  const objectKey = `${type}:${id}`;
34
34
 
35
+ // If the object was recently stored, return the recently stored object to avoid infinite recursion
36
+ if (recentlyStoredObjects[objectKey]) {
37
+ return recentlyStoredObjects[objectKey];
38
+ }
39
+
35
40
  // Retrieve the existing object if it already exists in the store
36
41
  const oldObject = store.get(objectKey);
37
42
 
38
43
  // If an old object exists, and it is newer than the new object, do not store the new object, just return the old
44
+ // NOTE: If the timestamp is the same, its possible the intention is to update the existing object, so DO NOT return old object in this case
39
45
  // @ts-expect-error __timestamp is guaranteed to be set in this case on both old and new
40
- if (oldObject && newObject.__timestamp <= oldObject.__timestamp) {
46
+ if (oldObject && newObject.__timestamp < oldObject.__timestamp) {
47
+ recentlyStoredObjects[objectKey] = oldObject;
41
48
  return oldObject;
42
49
  }
43
50
 
51
+ // Reference to the reactive version of the object so we can update all the child relationships and return the reactive object
52
+ const reactiveObject = oldObject || shallowReactive(newObject);
53
+
54
+ // Make sure to store the object in the recently stored objects to avoid infinite recursion
55
+ recentlyStoredObjects[objectKey] = reactiveObject;
56
+
44
57
  // Recursively store all the children of the object as well
45
58
  for (const key of Object.keys(newObject)) {
46
59
  const value = newObject[key];
47
60
  if (Array.isArray(value) && value.length > 0) {
48
61
  for (const index in value) {
49
62
  if (value[index] && typeof value[index] === "object") {
50
- newObject[key][index] = storeObject(value[index]);
63
+ newObject[key][index] = storeObject(value[index], recentlyStoredObjects);
51
64
  }
52
65
  }
53
66
  } else if (value?.__type) {
54
- // @ts-expect-error newObject[key] is guaranteed to be a TypedObject
55
- newObject[key] = storeObject(value);
67
+ // @ts-expect-error __type is guaranteed to be set in this case
68
+ newObject[key] = storeObject(value as TypedObject, recentlyStoredObjects);
56
69
  }
57
70
  }
58
71
 
59
- // Update the old object with the new object properties
60
- if (oldObject) {
61
- Object.assign(oldObject, newObject);
62
- return oldObject;
72
+ Object.assign(reactiveObject, newObject);
73
+
74
+ if (!oldObject) {
75
+ // Store the reactive object in the store if there was not already one existing
76
+ store.set(objectKey, reactiveObject);
63
77
  }
64
78
 
65
- const reactiveObject = shallowReactive(newObject);
66
- store.set(objectKey, reactiveObject);
67
79
  return reactiveObject;
68
80
  }
69
81
 
@@ -1,14 +1,15 @@
1
+ import { ListController, ListControlsRoutes } from "src/types/controls";
1
2
  import { VNode } from "vue";
2
- import { TypedObject } from "./shared";
3
+ import { AnyObject, TypedObject } from "./shared";
3
4
 
4
5
  export interface ActionPanel {
5
6
  name: string | number;
6
7
  label: string;
7
8
  category?: string;
8
9
  class?: string | object;
9
- enabled?: boolean | ((activeItem: ActionTargetItem) => boolean);
10
- tabVnode?: (activeItem: ActionTargetItem | null | undefined, activePanel: string | number) => VNode | any;
11
- vnode: (activeItem: ActionTargetItem | null | undefined) => VNode | any;
10
+ enabled?: boolean | ((target: ActionTargetItem) => boolean);
11
+ tabVnode?: (target: ActionTargetItem | null | undefined, activePanel: string | number) => VNode | any;
12
+ vnode: (target: ActionTargetItem | null | undefined) => VNode | any;
12
13
  }
13
14
 
14
15
  export interface ActionTargetItem extends TypedObject {
@@ -33,8 +34,8 @@ export interface ActionOptions {
33
34
  vnode?: ((target: ActionTarget) => VNode) | any;
34
35
  enabled?: (target: object) => boolean;
35
36
  batchEnabled?: (targets: object[]) => boolean;
36
- onAction?: (action: string | null | undefined, target: ActionTargetItem | null, input: any) => Promise<any> | void;
37
- onBatchAction?: (action: string | null | undefined, targets: ActionTargetItem[], input: any) => Promise<any>;
37
+ onAction?: (action: string | ResourceAction | ActionOptions, target: ActionTargetItem | null, input?: AnyObject | any) => Promise<AnyObject | any> | void;
38
+ onBatchAction?: (action: string | ResourceAction | ActionOptions, targets: ActionTargetItem[], input: any) => Promise<AnyObject | any> | void;
38
39
  onStart?: (action: ActionOptions | null, targets: ActionTarget, input: any) => boolean;
39
40
  onSuccess?: (result: any, targets: ActionTarget, input: any) => any;
40
41
  onBatchSuccess?: (result: any, targets: ActionTargetItem[], input: any) => any;
@@ -42,6 +43,11 @@ export interface ActionOptions {
42
43
  onFinish?: (result: any, targets: ActionTarget, input: any) => any;
43
44
  }
44
45
 
46
+ export interface ActionGlobalOptions extends Partial<ActionOptions> {
47
+ routes?: ListControlsRoutes;
48
+ controls?: ListController;
49
+ }
50
+
45
51
  export interface ResourceAction extends ActionOptions {
46
52
  isApplying: boolean;
47
53
  trigger: (target?: ActionTarget, input?: any) => Promise<any>;
@@ -1,5 +1,7 @@
1
+ import { FormField } from "src/types/forms";
2
+ import { TableColumn } from "src/types/tables";
1
3
  import { ComputedRef, Ref, ShallowRef } from "vue";
2
- import { ActionTargetItem } from "./actions";
4
+ import { ActionOptions, ActionPanel, ActionTargetItem, ResourceAction } from "./actions";
3
5
  import { AnyObject, LabelValueItem } from "./shared";
4
6
 
5
7
  export interface ListControlsFilter {
@@ -20,7 +22,6 @@ export interface FilterGroup {
20
22
  fields: FilterableField[];
21
23
  }
22
24
 
23
-
24
25
  export interface ListControlsRoutes {
25
26
  list(pager?: ListControlsPagination): Promise<ActionTargetItem[]>;
26
27
 
@@ -36,9 +37,9 @@ export interface ListControlsRoutes {
36
37
 
37
38
  fieldOptions?(filter?: AnyObject): Promise<AnyObject>;
38
39
 
39
- applyAction?(action: string, target: ActionTargetItem | null, data?: object): Promise<AnyObject>;
40
+ applyAction?(action: string | ResourceAction | ActionOptions, target: ActionTargetItem | null, data?: object): Promise<AnyObject>;
40
41
 
41
- batchAction?(action: string, targets: ActionTargetItem[], data: object): Promise<AnyObject>;
42
+ batchAction?(action: string | ResourceAction | ActionOptions, targets: ActionTargetItem[], data: object): Promise<AnyObject>;
42
43
 
43
44
  export?(filter?: ListControlsFilter, name?: string): Promise<void>;
44
45
  }
@@ -70,7 +71,7 @@ export interface PagedItems {
70
71
  } | undefined;
71
72
  }
72
73
 
73
- export interface ActionController {
74
+ export interface ListController {
74
75
  name: string;
75
76
  label: string;
76
77
  pagedItems: Ref<PagedItems | null>;
@@ -93,7 +94,7 @@ export interface ActionController {
93
94
  activeItem: ShallowRef<ActionTargetItem | null>;
94
95
  activePanel: ShallowRef<string | null>;
95
96
 
96
- // Actions
97
+ // List Controls
97
98
  initialize: () => void;
98
99
  resetPaging: () => void;
99
100
  setPagination: (updated: Partial<ListControlsPagination>) => void;
@@ -114,3 +115,19 @@ export interface ActionController {
114
115
  applyFilterFromUrl: (url: string, filters?: Ref<FilterGroup[]> | null) => void;
115
116
  getFieldOptions: (field: string) => any[];
116
117
  }
118
+
119
+ export interface ActionController {
120
+ // Actions
121
+ action?: (actionName: string, target?: ActionTargetItem | null, input?: any) => Promise<any | void>;
122
+ getAction?: (actionName: string, actionOptions?: Partial<ActionOptions>) => ResourceAction;
123
+ getActions?: (names?: string[]) => ResourceAction[];
124
+ extendAction?: (actionName: string, extendedId: string | number, actionOptions: Partial<ActionOptions>) => ResourceAction;
125
+ modifyAction?: (actionName: string, actionOptions: Partial<ActionOptions>) => ResourceAction;
126
+ batchActions?: ResourceAction[];
127
+ menuActions?: ResourceAction[];
128
+ columns?: TableColumn[];
129
+ filters?: ComputedRef<FilterGroup[]>;
130
+ fields?: FormField[];
131
+ panels?: ActionPanel[];
132
+ routes?: ListControlsRoutes;
133
+ }
@@ -1,4 +1,5 @@
1
1
  declare module "*.vue" {
2
- import Vue from 'vue';
3
- export default Vue;
2
+ import type { DefineComponent } from "vue";
3
+ const component: DefineComponent<object, object, any>;
4
+ export default component;
4
5
  }