quasar-ui-danx 0.4.2 → 0.4.4
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 +7127 -6615
- package/dist/danx.es.js.map +1 -1
- package/dist/danx.umd.js +11 -5
- package/dist/danx.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -1
- package/src/components/ActionTable/ActionTable.vue +28 -41
- package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +6 -6
- package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
- package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
- package/src/components/ActionTable/Filters/index.ts +2 -2
- package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
- package/src/components/ActionTable/Form/Fields/SelectField.vue +24 -38
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
- package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
- package/src/components/ActionTable/Form/Fields/index.ts +2 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +50 -9
- package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
- package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
- package/src/components/ActionTable/Form/index.ts +1 -0
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +16 -15
- package/src/components/ActionTable/Toolbars/ActionToolbar.vue +6 -6
- package/src/components/ActionTable/listControls.ts +106 -166
- package/src/components/ActionTable/listHelpers.ts +2 -3
- package/src/components/ActionTable/tableColumns.ts +3 -27
- package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
- package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
- package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
- package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
- package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +10 -24
- package/src/components/Utility/Dialogs/DialogLayout.vue +10 -28
- package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
- package/src/components/Utility/Dialogs/index.ts +1 -0
- package/src/components/Utility/Files/FilePreview.vue +76 -73
- package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
- package/src/components/Utility/Tools/ActionVnode.vue +3 -3
- package/src/components/Utility/Tools/RenderVnode.vue +1 -1
- package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
- package/src/components/Utility/Transitions/index.ts +1 -0
- package/src/config/index.ts +36 -31
- package/src/helpers/FileUpload.ts +295 -297
- package/src/helpers/FlashMessages.ts +80 -71
- package/src/helpers/actions.ts +102 -82
- package/src/helpers/download.ts +189 -189
- package/src/helpers/downloadPdf.ts +55 -52
- package/src/helpers/formats.ts +151 -109
- package/src/helpers/index.ts +2 -0
- package/src/helpers/multiFileUpload.ts +72 -58
- package/src/helpers/objectStore.ts +52 -0
- package/src/helpers/request.ts +70 -51
- package/src/helpers/routes.ts +29 -0
- package/src/helpers/storage.ts +7 -3
- package/src/helpers/utils.ts +47 -29
- package/src/styles/quasar-reset.scss +16 -1
- package/src/styles/themes/danx/dialogs.scss +4 -0
- package/src/types/actions.d.ts +43 -0
- package/src/types/config.d.ts +15 -0
- package/src/types/controls.d.ts +99 -0
- package/src/types/dialogs.d.ts +32 -0
- package/src/types/fields.d.ts +20 -0
- package/src/types/files.d.ts +54 -0
- package/src/types/formats.d.ts +4 -0
- package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
- package/src/types/index.d.ts +12 -0
- package/src/types/requests.d.ts +13 -0
- package/src/types/shared.d.ts +15 -0
- package/src/types/tables.d.ts +27 -0
- package/types/index.d.ts +1 -1
- /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
@@ -1,135 +1,40 @@
|
|
1
|
-
import { computed,
|
2
|
-
import {
|
1
|
+
import { computed, Ref, ref, shallowRef, watch } from "vue";
|
2
|
+
import { RouteLocationNormalizedLoaded, RouteParams, Router, useRoute, useRouter } from "vue-router";
|
3
|
+
import { getItem, setItem, storeObject, waitForRef } from "../../helpers";
|
4
|
+
import {
|
5
|
+
ActionController,
|
6
|
+
ActionTargetItem,
|
7
|
+
AnyObject,
|
8
|
+
FilterGroup,
|
9
|
+
ListControlsFilter,
|
10
|
+
ListControlsOptions,
|
11
|
+
ListControlsPagination,
|
12
|
+
PagedItems
|
13
|
+
} from "../../types";
|
3
14
|
import { getFilterFromUrl } from "./listHelpers";
|
4
15
|
|
5
|
-
export
|
6
|
-
name: string;
|
7
|
-
label: string;
|
8
|
-
pagedItems: Ref<PagedItems | null>;
|
9
|
-
activeFilter: Ref<ListControlsFilter>;
|
10
|
-
globalFilter: Ref<ListControlsFilter>;
|
11
|
-
filterActiveCount: ComputedRef<number>;
|
12
|
-
showFilters: Ref<boolean>;
|
13
|
-
summary: ShallowRef<object | null>;
|
14
|
-
filterFieldOptions: Ref<AnyObject>;
|
15
|
-
selectedRows: ShallowRef<ActionTargetItem[]>;
|
16
|
-
isLoadingList: Ref<boolean>;
|
17
|
-
isLoadingFilters: Ref<boolean>;
|
18
|
-
isLoadingSummary: Ref<boolean>;
|
19
|
-
pager: ComputedRef<{
|
20
|
-
perPage: number;
|
21
|
-
page: number;
|
22
|
-
filter: ListControlsFilter;
|
23
|
-
sort: object[] | undefined;
|
24
|
-
}>;
|
25
|
-
pagination: ShallowRef<ListControlsPagination>;
|
26
|
-
activeItem: ShallowRef<ActionTargetItem | null>;
|
27
|
-
activePanel: ShallowRef<string | null>;
|
28
|
-
|
29
|
-
// Actions
|
30
|
-
initialize: () => void;
|
31
|
-
loadSummary: () => Promise<void>;
|
32
|
-
resetPaging: () => void;
|
33
|
-
setPagination: (updated: ListControlsPagination) => void;
|
34
|
-
setSelectedRows: (selection: ActionTargetItem[]) => void;
|
35
|
-
loadList: () => Promise<void>;
|
36
|
-
loadMore: (index: number, perPage?: number) => Promise<boolean>;
|
37
|
-
refreshAll: () => Promise<void[]>;
|
38
|
-
exportList: () => Promise<void>;
|
39
|
-
setActiveItem: (item: ActionTargetItem | null) => void;
|
40
|
-
getNextItem: (offset: number) => Promise<void>;
|
41
|
-
activatePanel: (item: ActionTargetItem | null, panel: string | null) => void;
|
42
|
-
setActiveFilter: (filter: ListControlsFilter) => void;
|
43
|
-
applyFilterFromUrl: (url: string, filterFields: Ref<FilterGroup[]> | null) => void;
|
44
|
-
setItemInList: (updatedItem: ActionTargetItem) => void;
|
45
|
-
}
|
46
|
-
|
47
|
-
export interface LabelValueItem {
|
48
|
-
label: string;
|
49
|
-
value: string | number | boolean;
|
50
|
-
}
|
51
|
-
|
52
|
-
export interface FilterField {
|
53
|
-
name: string;
|
54
|
-
label: string;
|
55
|
-
type: string;
|
56
|
-
options?: string[] | number[] | LabelValueItem[];
|
57
|
-
inline?: boolean;
|
58
|
-
}
|
59
|
-
|
60
|
-
export interface FilterGroup {
|
61
|
-
name?: string;
|
62
|
-
flat?: boolean;
|
63
|
-
fields: FilterField[];
|
64
|
-
}
|
65
|
-
|
66
|
-
export interface ActionPanel {
|
67
|
-
name: string;
|
68
|
-
label: string;
|
69
|
-
category?: string;
|
70
|
-
enabled: boolean | (() => boolean);
|
71
|
-
tabVnode: () => VNode;
|
72
|
-
vnode: () => VNode;
|
73
|
-
}
|
74
|
-
|
75
|
-
export interface ListControlsFilter {
|
76
|
-
[key: string]: object | object[] | null | undefined | string | number | boolean;
|
77
|
-
}
|
78
|
-
|
79
|
-
export interface ListControlsRoutes {
|
80
|
-
list: (pager: object) => Promise<ActionTargetItem[]>;
|
81
|
-
details?: (item: object) => Promise<ActionTargetItem> | null;
|
82
|
-
summary?: (filter: object | null) => Promise<object> | null;
|
83
|
-
filterFieldOptions?: (filter: object | null) => Promise<object> | null;
|
84
|
-
more?: (pager: object) => Promise<ActionTargetItem[]> | null;
|
85
|
-
export: (filter: object) => Promise<void>;
|
86
|
-
}
|
87
|
-
|
88
|
-
export interface ListControlsOptions {
|
89
|
-
label?: string,
|
90
|
-
routes: ListControlsRoutes;
|
91
|
-
urlPattern?: RegExp | null;
|
92
|
-
filterDefaults?: Record<string, object>;
|
93
|
-
refreshFilters?: boolean;
|
94
|
-
}
|
95
|
-
|
96
|
-
export interface ListControlsPagination {
|
97
|
-
__sort: object[] | null;
|
98
|
-
sortBy: string | null;
|
99
|
-
descending: boolean;
|
100
|
-
page: number;
|
101
|
-
rowsNumber: number;
|
102
|
-
rowsPerPage: number;
|
103
|
-
}
|
104
|
-
|
105
|
-
export interface PagedItems {
|
106
|
-
data: ActionTargetItem[] | undefined;
|
107
|
-
meta: {
|
108
|
-
total: number;
|
109
|
-
last_page?: number;
|
110
|
-
} | undefined;
|
111
|
-
}
|
112
|
-
|
113
|
-
export function useListControls(name: string, options: ListControlsOptions) {
|
16
|
+
export function useListControls(name: string, options: ListControlsOptions): ActionController {
|
114
17
|
let isInitialized = false;
|
18
|
+
let vueRoute: RouteLocationNormalizedLoaded | null = null;
|
19
|
+
let vueRouter: Router | null = null;
|
115
20
|
const PAGE_SETTINGS_KEY = `dx-${name}-pager`;
|
116
|
-
const pagedItems
|
117
|
-
const activeFilter
|
21
|
+
const pagedItems = shallowRef<PagedItems | null>(null);
|
22
|
+
const activeFilter = ref<ListControlsFilter>({});
|
118
23
|
const globalFilter = ref({});
|
119
24
|
const showFilters = ref(false);
|
120
|
-
const selectedRows
|
25
|
+
const selectedRows = shallowRef<ActionTargetItem[]>([]);
|
121
26
|
const isLoadingList = ref(false);
|
122
27
|
const isLoadingSummary = ref(false);
|
123
|
-
const summary
|
28
|
+
const summary = shallowRef<AnyObject | null>(null);
|
124
29
|
|
125
30
|
// The active ad for viewing / editing
|
126
|
-
const activeItem
|
31
|
+
const activeItem = shallowRef<ActionTargetItem | null>(null);
|
127
32
|
// Controls the active panel (ie: tab) if rendering a panels drawer or similar
|
128
|
-
const activePanel
|
33
|
+
const activePanel = shallowRef<string>("");
|
129
34
|
|
130
|
-
//
|
35
|
+
// Field options are the lists of field values available given the applied filter on the list query. These are used for drop-downs / options in forms, filters, etc.
|
131
36
|
// (ie: all states available under the current filter)
|
132
|
-
const
|
37
|
+
const fieldOptions = ref<AnyObject>({});
|
133
38
|
const isLoadingFilters = ref(false);
|
134
39
|
|
135
40
|
const filterActiveCount = computed(() => Object.keys(activeFilter.value).filter(key => activeFilter.value[key] !== undefined).length);
|
@@ -163,7 +68,7 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
163
68
|
watch(selectedRows, loadSummary);
|
164
69
|
|
165
70
|
if (options.refreshFilters) {
|
166
|
-
watch(activeFilter,
|
71
|
+
watch(activeFilter, loadFieldOptions);
|
167
72
|
}
|
168
73
|
|
169
74
|
async function loadList() {
|
@@ -185,11 +90,15 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
185
90
|
isLoadingSummary.value = false;
|
186
91
|
}
|
187
92
|
|
93
|
+
async function loadListAndSummary() {
|
94
|
+
await Promise.all([loadList(), loadSummary()]);
|
95
|
+
}
|
96
|
+
|
188
97
|
/**
|
189
98
|
* Gets the field options for the given field name.
|
190
99
|
*/
|
191
|
-
function getFieldOptions(field: string) {
|
192
|
-
return
|
100
|
+
function getFieldOptions(field: string): any[] {
|
101
|
+
return fieldOptions.value[field] || [];
|
193
102
|
}
|
194
103
|
|
195
104
|
/**
|
@@ -197,20 +106,20 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
197
106
|
*
|
198
107
|
* @returns {Promise<void>}
|
199
108
|
*/
|
200
|
-
async function
|
201
|
-
if (!options.routes.
|
109
|
+
async function loadFieldOptions() {
|
110
|
+
if (!options.routes.fieldOptions || !isInitialized) return;
|
202
111
|
isLoadingFilters.value = true;
|
203
|
-
|
112
|
+
fieldOptions.value = await options.routes.fieldOptions(activeFilter.value) || {};
|
204
113
|
isLoadingFilters.value = false;
|
205
114
|
}
|
206
115
|
|
207
116
|
/**
|
208
117
|
* Watches for a filter URL parameter and applies the filter if it is set.
|
209
118
|
*/
|
210
|
-
function applyFilterFromUrl(url: string,
|
119
|
+
function applyFilterFromUrl(url: string, filterGroups: Ref<FilterGroup[]> | null = null) {
|
211
120
|
if (options.urlPattern && url.match(options.urlPattern)) {
|
212
121
|
// A flat list of valid filterable field names
|
213
|
-
const validFilterKeys =
|
122
|
+
const validFilterKeys = filterGroups?.value?.map(group => group.fields.map(field => field.name)).flat();
|
214
123
|
|
215
124
|
const urlFilter = getFilterFromUrl(url, validFilterKeys);
|
216
125
|
|
@@ -231,7 +140,6 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
231
140
|
if (Array.isArray(items)) {
|
232
141
|
data = items;
|
233
142
|
meta = { total: items.length };
|
234
|
-
|
235
143
|
} else if (items.data) {
|
236
144
|
data = items.data;
|
237
145
|
meta = items.meta;
|
@@ -243,11 +151,11 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
243
151
|
}
|
244
152
|
|
245
153
|
// Add a reactive isSaving property to each item (for performance reasons in checking saving state)
|
246
|
-
data = data.map((item) => {
|
154
|
+
data = data.map((item: ActionTargetItem) => {
|
155
|
+
item.isSaving = item.isSaving === undefined ? false : item.isSaving;
|
247
156
|
// We want to keep the isSaving state if it is already set, as optimizations prevent reloading the
|
248
157
|
// components, and therefore reactivity is not responding to the new isSaving state
|
249
|
-
|
250
|
-
return { ...item, isSaving: oldItem?.isSaving || ref(false) };
|
158
|
+
return storeObject(item);
|
251
159
|
});
|
252
160
|
|
253
161
|
pagedItems.value = { data, meta };
|
@@ -276,30 +184,17 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
276
184
|
}
|
277
185
|
|
278
186
|
/**
|
279
|
-
*
|
280
|
-
*
|
281
|
-
* @param updatedItem
|
187
|
+
* Clears the selected rows in the list.
|
282
188
|
*/
|
283
|
-
function
|
284
|
-
|
285
|
-
const data = pagedItems.value?.data?.map(item => (item.id === updatedItem.id && (item.updated_at === null || item.updated_at <= updatedItem.updated_at)) ? updatedItem : item);
|
286
|
-
setPagedItems({
|
287
|
-
data,
|
288
|
-
meta: { total: pagedItems.value?.meta?.total || 0 }
|
289
|
-
});
|
290
|
-
|
291
|
-
// Update the active item as well if it is set
|
292
|
-
if (activeItem.value?.id === updatedItem.id) {
|
293
|
-
activeItem.value = { ...activeItem.value, ...updatedItem };
|
294
|
-
}
|
295
|
-
}
|
189
|
+
function clearSelectedRows() {
|
190
|
+
selectedRows.value = [];
|
296
191
|
}
|
297
192
|
|
298
193
|
/**
|
299
194
|
* Loads more items into the list.
|
300
195
|
*/
|
301
|
-
async function loadMore(index: number, perPage = undefined) {
|
302
|
-
if (!options.routes.more) return;
|
196
|
+
async function loadMore(index: number, perPage: number | undefined = undefined) {
|
197
|
+
if (!options.routes.more) return false;
|
303
198
|
|
304
199
|
const newItems = await options.routes.more({
|
305
200
|
page: index + 1,
|
@@ -322,7 +217,7 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
322
217
|
* Refreshes the list, summary, and filter field options.
|
323
218
|
*/
|
324
219
|
async function refreshAll() {
|
325
|
-
return Promise.all([loadList(), loadSummary(),
|
220
|
+
return Promise.all([loadList(), loadSummary(), loadFieldOptions(), getActiveItemDetails()]);
|
326
221
|
}
|
327
222
|
|
328
223
|
/**
|
@@ -362,7 +257,7 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
362
257
|
}
|
363
258
|
|
364
259
|
if (!isLoadingFilters.value) {
|
365
|
-
|
260
|
+
loadFieldOptions();
|
366
261
|
}
|
367
262
|
}, 1);
|
368
263
|
}
|
@@ -389,13 +284,12 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
389
284
|
|
390
285
|
const result = await options.routes.details(activeItem.value);
|
391
286
|
|
392
|
-
|
393
|
-
|
394
|
-
// requested item
|
395
|
-
if (result?.id === activeItem.value?.id) {
|
396
|
-
const loadedItem = pagedItems.value?.data?.find((i: ActionTargetItem) => i.id === result.id);
|
397
|
-
activeItem.value = { ...result, isSaving: loadedItem?.isSaving || ref(false) };
|
287
|
+
if (!result || !result.__type || !result.id) {
|
288
|
+
return console.error("Invalid response from details route: All responses must include a __type and id field. result =", result);
|
398
289
|
}
|
290
|
+
|
291
|
+
// Reassign the active item to the store object to ensure reactivity
|
292
|
+
activeItem.value = storeObject(result);
|
399
293
|
}
|
400
294
|
|
401
295
|
// Whenever the active item changes, fill the additional item details
|
@@ -411,16 +305,32 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
411
305
|
/**
|
412
306
|
* Opens the item's form with the given item and tab
|
413
307
|
*/
|
414
|
-
function activatePanel(item: ActionTargetItem | null, panel: string) {
|
415
|
-
|
308
|
+
function activatePanel(item: ActionTargetItem | null, panel: string = "") {
|
309
|
+
// If we're already on the correct item and panel, don't do anything
|
310
|
+
if (item?.id === activeItem.value?.id && panel === activePanel.value) return;
|
311
|
+
|
312
|
+
setActiveItem(item);
|
416
313
|
activePanel.value = panel;
|
314
|
+
|
315
|
+
// Push vue router change /:id/:panel
|
316
|
+
if (vueRoute && vueRouter && item?.id) {
|
317
|
+
vueRouter.push({
|
318
|
+
name: Array.isArray(vueRoute.name) ? vueRoute.name[0] : vueRoute.name,
|
319
|
+
params: { id: item.id, panel },
|
320
|
+
replace: true
|
321
|
+
});
|
322
|
+
}
|
417
323
|
}
|
418
324
|
|
419
325
|
/**
|
420
326
|
* Sets the currently active item in the list.
|
421
327
|
*/
|
422
328
|
function setActiveItem(item: ActionTargetItem | null) {
|
423
|
-
activeItem.value = item;
|
329
|
+
activeItem.value = item ? storeObject(item) : item;
|
330
|
+
|
331
|
+
if (!item?.id) {
|
332
|
+
vueRouter?.push({ name: vueRoute?.name || "home" });
|
333
|
+
}
|
424
334
|
}
|
425
335
|
|
426
336
|
/**
|
@@ -465,11 +375,11 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
465
375
|
/**
|
466
376
|
* Sets the active filter to the given filter.
|
467
377
|
*/
|
468
|
-
function setActiveFilter(filter
|
469
|
-
activeFilter.value = filter;
|
378
|
+
function setActiveFilter(filter?: ListControlsFilter) {
|
379
|
+
activeFilter.value = filter || {};
|
470
380
|
}
|
471
381
|
|
472
|
-
async function exportList(filter
|
382
|
+
async function exportList(filter?: ListControlsFilter) {
|
473
383
|
return options.routes.export(filter);
|
474
384
|
}
|
475
385
|
|
@@ -477,6 +387,35 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
477
387
|
function initialize() {
|
478
388
|
isInitialized = true;
|
479
389
|
loadSettings();
|
390
|
+
|
391
|
+
// Setup Vue Router handling
|
392
|
+
vueRoute = useRoute();
|
393
|
+
vueRouter = useRouter();
|
394
|
+
|
395
|
+
console.log("init listControl", name, options, "vueRoute", vueRoute);
|
396
|
+
/**
|
397
|
+
* Watch the id params in the route and set the active item to the item with the given id.
|
398
|
+
*/
|
399
|
+
if (options.routes.details && vueRoute) {
|
400
|
+
const { params, meta } = vueRoute;
|
401
|
+
|
402
|
+
const controlRouteName = vueRoute.name;
|
403
|
+
vueRouter.afterEach((to) => {
|
404
|
+
if (to.name === controlRouteName) {
|
405
|
+
setPanelFromRoute(to.params, to.meta);
|
406
|
+
}
|
407
|
+
});
|
408
|
+
|
409
|
+
setPanelFromRoute(params, meta);
|
410
|
+
}
|
411
|
+
}
|
412
|
+
|
413
|
+
function setPanelFromRoute(params: RouteParams, meta: AnyObject) {
|
414
|
+
const id = Array.isArray(params?.id) ? params.id[0] : params?.id;
|
415
|
+
if (id && meta.type) {
|
416
|
+
const panel = Array.isArray(params?.panel) ? params.panel[0] : params?.panel;
|
417
|
+
activatePanel({ id, __type: "" + meta.type }, panel || activePanel.value || "");
|
418
|
+
}
|
480
419
|
}
|
481
420
|
|
482
421
|
return {
|
@@ -489,7 +428,6 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
489
428
|
filterActiveCount,
|
490
429
|
showFilters,
|
491
430
|
summary,
|
492
|
-
filterFieldOptions,
|
493
431
|
selectedRows,
|
494
432
|
isLoadingList,
|
495
433
|
isLoadingFilters,
|
@@ -501,12 +439,15 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
501
439
|
|
502
440
|
// Actions
|
503
441
|
initialize,
|
504
|
-
loadSummary,
|
505
442
|
resetPaging,
|
506
443
|
setPagination,
|
507
444
|
setSelectedRows,
|
445
|
+
clearSelectedRows,
|
508
446
|
loadList,
|
447
|
+
loadSummary,
|
448
|
+
loadListAndSummary,
|
509
449
|
loadMore,
|
450
|
+
getActiveItemDetails,
|
510
451
|
refreshAll,
|
511
452
|
exportList,
|
512
453
|
setActiveItem,
|
@@ -514,7 +455,6 @@ export function useListControls(name: string, options: ListControlsOptions) {
|
|
514
455
|
activatePanel,
|
515
456
|
setActiveFilter,
|
516
457
|
applyFilterFromUrl,
|
517
|
-
setItemInList,
|
518
458
|
getFieldOptions
|
519
459
|
};
|
520
460
|
}
|
@@ -1,7 +1,6 @@
|
|
1
|
-
import { ListControlsPagination } from "src/components/ActionTable/listControls";
|
2
|
-
import { TableColumn } from "src/components/ActionTable/tableColumns";
|
3
1
|
import { onMounted, Ref } from "vue";
|
4
|
-
import {
|
2
|
+
import { getUrlParam } from "../../helpers";
|
3
|
+
import { AnyObject, ListControlsPagination, TableColumn } from "../../types";
|
5
4
|
|
6
5
|
export function registerStickyScrolling(tableRef: Ref) {
|
7
6
|
onMounted(() => {
|
@@ -1,30 +1,6 @@
|
|
1
|
-
import { computed, ref,
|
2
|
-
import {
|
3
|
-
|
4
|
-
export interface TableColumn {
|
5
|
-
actionMenu?: ActionOptions[],
|
6
|
-
align?: string,
|
7
|
-
category?: string,
|
8
|
-
class?: string | object,
|
9
|
-
field: string,
|
10
|
-
format?: (value: any, options: any) => any,
|
11
|
-
innerClass?: string | object,
|
12
|
-
style?: string | object,
|
13
|
-
headerStyle?: string | object,
|
14
|
-
isSavingRow?: boolean | (() => boolean),
|
15
|
-
label: string,
|
16
|
-
maxWidth?: number,
|
17
|
-
minWidth?: number,
|
18
|
-
name: string,
|
19
|
-
onClick?: (target: any) => void,
|
20
|
-
required?: boolean,
|
21
|
-
resizeable?: boolean,
|
22
|
-
sortable?: boolean,
|
23
|
-
sortBy?: string,
|
24
|
-
sortByExpression?: string,
|
25
|
-
titleColumns?: () => string[],
|
26
|
-
vnode?: () => VNode,
|
27
|
-
}
|
1
|
+
import { computed, ref, watch } from "vue";
|
2
|
+
import { getItem, setItem } from "../../helpers";
|
3
|
+
import { TableColumn } from "../../types";
|
28
4
|
|
29
5
|
export function useTableColumns(name: string, columns: TableColumn[]) {
|
30
6
|
const COLUMN_ORDER_KEY = `${name}-column-order`;
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<div class="flex space-x-2">
|
3
3
|
<template v-if="type === 'SINGLE_FILE'">
|
4
4
|
<FilePreview
|
5
|
-
:
|
5
|
+
:file="value"
|
6
6
|
class="w-24"
|
7
7
|
/>
|
8
8
|
</template>
|
@@ -10,7 +10,7 @@
|
|
10
10
|
<FilePreview
|
11
11
|
v-for="file in value"
|
12
12
|
:key="'file-' + file.id"
|
13
|
-
:
|
13
|
+
:file="file"
|
14
14
|
class="w-24 mb-2"
|
15
15
|
/>
|
16
16
|
</template>
|
@@ -27,34 +27,34 @@ import { fCurrency, fDate, fLocalizedDateTime, fNumber } from "../../helpers";
|
|
27
27
|
import { FilePreview } from "../Utility";
|
28
28
|
|
29
29
|
const props = defineProps({
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
type: {
|
31
|
+
type: String,
|
32
|
+
required: true
|
33
|
+
},
|
34
|
+
value: {
|
35
|
+
type: [Number, String, Array, Object, Boolean],
|
36
|
+
default: null
|
37
|
+
}
|
38
38
|
});
|
39
39
|
|
40
40
|
function format(value) {
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
if (value === null || value === "" || value === undefined) {
|
42
|
+
return "";
|
43
|
+
}
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
switch (props.type) {
|
46
|
+
case "NUMBER":
|
47
|
+
return fNumber(value);
|
48
|
+
case "CURRENCY":
|
49
|
+
return fCurrency(value);
|
50
|
+
case "DATE":
|
51
|
+
return fDate(value);
|
52
|
+
case "DATETIME":
|
53
|
+
return fLocalizedDateTime(value);
|
54
|
+
case "BOOLEAN":
|
55
|
+
return value ? "Yes" : "No";
|
56
|
+
}
|
57
57
|
|
58
|
-
|
58
|
+
return value;
|
59
59
|
}
|
60
60
|
</script>
|
@@ -6,6 +6,7 @@
|
|
6
6
|
content-class="h-full"
|
7
7
|
class="dx-panels-drawer"
|
8
8
|
title=""
|
9
|
+
no-route-dismiss
|
9
10
|
@update:show="$emit('close')"
|
10
11
|
>
|
11
12
|
<div class="flex flex-col flex-nowrap h-full">
|
@@ -33,15 +34,17 @@
|
|
33
34
|
<div class="dx-panels-drawer-body flex-grow overflow-hidden h-full">
|
34
35
|
<div class="flex items-stretch flex-nowrap h-full">
|
35
36
|
<PanelsDrawerTabs
|
37
|
+
:key="'pd-tabs:' + activeItem.id"
|
36
38
|
v-model="activePanel"
|
37
39
|
:class="tabsClass"
|
38
40
|
:panels="panels"
|
39
41
|
@update:model-value="$emit('update:model-value', $event)"
|
40
42
|
/>
|
41
43
|
<PanelsDrawerPanels
|
44
|
+
:key="'pd-panels:' + activeItem.id"
|
42
45
|
:panels="panels"
|
43
46
|
:active-panel="activePanel"
|
44
|
-
:class="panelsClass"
|
47
|
+
:class="activePanelOptions?.class || panelsClass"
|
45
48
|
/>
|
46
49
|
<div
|
47
50
|
v-if="$slots['right-sidebar']"
|
@@ -55,16 +58,17 @@
|
|
55
58
|
</ContentDrawer>
|
56
59
|
</template>
|
57
60
|
<script setup lang="ts">
|
58
|
-
import { ref, watch } from "vue";
|
61
|
+
import { computed, onMounted, ref, watch } from "vue";
|
59
62
|
import { XIcon as CloseIcon } from "../../svg";
|
60
|
-
import { ActionPanel } from "
|
63
|
+
import { ActionPanel, ActionTargetItem } from "../../types";
|
61
64
|
import { ContentDrawer } from "../Utility";
|
62
65
|
import PanelsDrawerPanels from "./PanelsDrawerPanels";
|
63
66
|
import PanelsDrawerTabs from "./PanelsDrawerTabs";
|
64
67
|
|
65
68
|
export interface Props {
|
66
69
|
title?: string,
|
67
|
-
modelValue?: string,
|
70
|
+
modelValue?: string | number,
|
71
|
+
activeItem?: ActionTargetItem;
|
68
72
|
tabsClass?: string | object,
|
69
73
|
panelsClass?: string | object,
|
70
74
|
panels: ActionPanel[]
|
@@ -74,10 +78,19 @@ defineEmits(["update:model-value", "close"]);
|
|
74
78
|
const props = withDefaults(defineProps<Props>(), {
|
75
79
|
title: "",
|
76
80
|
modelValue: null,
|
81
|
+
activeItem: null,
|
77
82
|
tabsClass: "w-[13.5rem]",
|
78
83
|
panelsClass: "w-[35.5rem]"
|
79
84
|
});
|
80
85
|
|
81
86
|
const activePanel = ref(props.modelValue);
|
87
|
+
const activePanelOptions = computed(() => props.panels.find((panel) => panel.name === activePanel.value));
|
82
88
|
watch(() => props.modelValue, (value) => activePanel.value = value);
|
89
|
+
|
90
|
+
onMounted(() => {
|
91
|
+
// Resolve the default panel if a panel has not been selected
|
92
|
+
if (!activePanel.value && props.panels.length) {
|
93
|
+
activePanel.value = props.panels[0].name;
|
94
|
+
}
|
95
|
+
});
|
83
96
|
</script>
|
@@ -16,17 +16,12 @@
|
|
16
16
|
</QTabPanels>
|
17
17
|
</template>
|
18
18
|
|
19
|
-
<script setup>
|
19
|
+
<script setup lang="ts">
|
20
|
+
import { ActionPanel } from "../../types";
|
20
21
|
import { RenderVnode } from "../Utility";
|
21
22
|
|
22
|
-
defineProps
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
},
|
27
|
-
panels: {
|
28
|
-
type: Array,
|
29
|
-
required: true
|
30
|
-
}
|
31
|
-
});
|
23
|
+
defineProps<{
|
24
|
+
activePanel?: string | number,
|
25
|
+
panels: ActionPanel[]
|
26
|
+
}>();
|
32
27
|
</script>
|