quasar-ui-danx 0.4.26 → 0.4.28

Sign up to get free protection for your applications and to get access to all the features.
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
  }