adminforth 2.4.0-next.124 → 2.4.0-next.126
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/spa/src/adminforth.ts +5 -6
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Checkbox.vue +1 -1
- package/dist/spa/src/afcl/Dropzone.vue +2 -2
- package/dist/spa/src/afcl/Input.vue +1 -1
- package/dist/spa/src/afcl/LinkButton.vue +1 -1
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/Select.vue +9 -8
- package/dist/spa/src/afcl/Table.vue +18 -9
- package/dist/spa/src/afcl/Toggle.vue +1 -1
- package/dist/spa/src/components/ResourceListTable.vue +42 -42
- package/dist/spa/src/components/ResourceListTableVirtual.vue +41 -41
- package/dist/spa/src/components/SkeleteLoader.vue +2 -2
- package/dist/spa/src/components/ThreeDotsMenu.vue +15 -14
- package/dist/spa/src/components/ValueRenderer.vue +39 -12
- package/dist/spa/src/spa_types/core.ts +1 -1
- package/dist/spa/src/stores/modal.ts +6 -1
- package/dist/spa/src/types/Common.ts +17 -21
- package/dist/spa/src/views/CreateView.vue +1 -5
- package/dist/spa/src/views/EditView.vue +1 -5
- package/dist/spa/src/views/ListView.vue +67 -38
- package/dist/spa/src/views/ShowView.vue +36 -37
- package/dist/spa/vite.config.ts +3 -3
- package/dist/types/Common.d.ts +12 -20
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/package.json +1 -1
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
</div>
|
|
52
52
|
<span
|
|
53
53
|
class="bg-red-100 text-red-800 text-xs font-medium me-1 px-1 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400"
|
|
54
|
-
v-if="sort.findIndex((s) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
55
|
-
{{ sort.findIndex((s) => s.field === c.name) + 1 }}
|
|
54
|
+
v-if="sort.findIndex((s: any) => s.field === c.name) !== -1 && sort?.length > 1">
|
|
55
|
+
{{ sort.findIndex((s: any) => s.field === c.name) + 1 }}
|
|
56
56
|
</span>
|
|
57
57
|
|
|
58
58
|
</div>
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
<!-- table header end -->
|
|
69
69
|
<SkeleteLoader
|
|
70
70
|
v-if="!rows"
|
|
71
|
-
:columns="resource?.columns.filter(c => c.showIn
|
|
71
|
+
:columns="resource?.columns.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list).length + 2"
|
|
72
72
|
:rows="rowHeights.length || 20"
|
|
73
73
|
:row-heights="rowHeights"
|
|
74
74
|
:column-widths="columnWidths"
|
|
@@ -99,13 +99,13 @@
|
|
|
99
99
|
ref="rowRefs"
|
|
100
100
|
class="bg-lightListTable dark:bg-darkListTable border-lightListBorder dark:border-gray-700 hover:bg-lightListTableRowHover dark:hover:bg-darkListTableRowHover"
|
|
101
101
|
:class="{'border-b': rowI !== visibleRows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
|
|
102
|
-
@mounted="(el) => updateRowHeight(`row_${row._primaryKeyValue}`, el.offsetHeight)"
|
|
102
|
+
@mounted="(el: any) => updateRowHeight(`row_${row._primaryKeyValue}`, el.offsetHeight)"
|
|
103
103
|
>
|
|
104
104
|
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
|
|
105
105
|
<Checkbox
|
|
106
106
|
:model-value="checkboxesInternal.includes(row._primaryKeyValue)"
|
|
107
|
-
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
|
|
108
|
-
@click="(e)=>e.stopPropagation()"
|
|
107
|
+
@change="(e: any)=>{addToCheckedValues(row._primaryKeyValue)}"
|
|
108
|
+
@click="(e: any)=>e.stopPropagation()"
|
|
109
109
|
>
|
|
110
110
|
<span class="sr-only">{{ $t('checkbox') }}</span>
|
|
111
111
|
</Checkbox>
|
|
@@ -113,8 +113,8 @@
|
|
|
113
113
|
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
|
|
114
114
|
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
|
|
115
115
|
<component
|
|
116
|
-
:is="c?.components?.list ? getCustomComponent(c.components.list) : ValueRenderer"
|
|
117
|
-
:meta="c?.components?.list
|
|
116
|
+
:is="c?.components?.list ? getCustomComponent(typeof c.components.list === 'string' ? { file: c.components.list } : c.components.list) : ValueRenderer"
|
|
117
|
+
:meta="typeof c?.components?.list === 'object' ? c.components.list.meta : undefined"
|
|
118
118
|
:column="c"
|
|
119
119
|
:record="row"
|
|
120
120
|
:adminUser="coreStore.adminUser"
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
<div class="flex text-lightPrimary dark:text-darkPrimary items-center">
|
|
126
126
|
<Tooltip>
|
|
127
127
|
<RouterLink
|
|
128
|
-
v-if="resource.options?.allowedActions
|
|
128
|
+
v-if="resource.options?.allowedActions?.show"
|
|
129
129
|
:to="{
|
|
130
130
|
name: 'resource-show',
|
|
131
131
|
params: {
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
|
|
146
146
|
<Tooltip>
|
|
147
147
|
<RouterLink
|
|
148
|
-
v-if="resource.options?.allowedActions
|
|
148
|
+
v-if="resource.options?.allowedActions?.edit"
|
|
149
149
|
:to="{
|
|
150
150
|
name: 'resource-edit',
|
|
151
151
|
params: {
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
|
|
164
164
|
<Tooltip>
|
|
165
165
|
<button
|
|
166
|
-
v-if="resource.options?.allowedActions
|
|
166
|
+
v-if="resource.options?.allowedActions?.delete"
|
|
167
167
|
@click="deleteRecord(row)"
|
|
168
168
|
>
|
|
169
169
|
<IconTrashBinSolid class="w-5 h-5 me-2"/>
|
|
@@ -325,7 +325,7 @@ import {
|
|
|
325
325
|
} from '@iconify-prerendered/vue-flowbite';
|
|
326
326
|
import router from '@/router';
|
|
327
327
|
import { Tooltip } from '@/afcl';
|
|
328
|
-
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
328
|
+
import type { AdminForthResourceCommon, AdminForthResourceColumnCommon } from '@/types/Common';
|
|
329
329
|
import adminforth from '@/adminforth';
|
|
330
330
|
import Checkbox from '@/afcl/Checkbox.vue';
|
|
331
331
|
|
|
@@ -359,7 +359,7 @@ const emits = defineEmits([
|
|
|
359
359
|
const checkboxesInternal: Ref<any[]> = ref([]);
|
|
360
360
|
const pageInput = ref('1');
|
|
361
361
|
const page = ref(1);
|
|
362
|
-
const sort = ref([]);
|
|
362
|
+
const sort: Ref<Array<{field: string, direction: string}>> = ref([]);
|
|
363
363
|
|
|
364
364
|
|
|
365
365
|
const from = computed(() => ((page.value || 1) - 1) * props.pageSize + 1);
|
|
@@ -368,11 +368,11 @@ const to = computed(() => Math.min((page.value || 1) * props.pageSize, props.tot
|
|
|
368
368
|
watch(() => page.value, (newPage) => {
|
|
369
369
|
emits('update:page', newPage);
|
|
370
370
|
});
|
|
371
|
-
async function onPageKeydown(event) {
|
|
371
|
+
async function onPageKeydown(event: any) {
|
|
372
372
|
// page input should accept only numbers, arrow keys and backspace
|
|
373
373
|
if (['Enter', 'Space'].includes(event.code) ||
|
|
374
374
|
(!['Backspace', 'ArrowRight', 'ArrowLeft'].includes(event.code)
|
|
375
|
-
&& isNaN(String.fromCharCode(event.keyCode)))) {
|
|
375
|
+
&& isNaN(Number(String.fromCharCode(event.keyCode || 0))))) {
|
|
376
376
|
event.preventDefault();
|
|
377
377
|
if (event.code === 'Enter') {
|
|
378
378
|
validatePageInput();
|
|
@@ -393,7 +393,7 @@ watch(() => props.checkboxes, (newCheckboxes) => {
|
|
|
393
393
|
checkboxesInternal.value = newCheckboxes;
|
|
394
394
|
});
|
|
395
395
|
|
|
396
|
-
watch(() => props.sort, (newSort) => {
|
|
396
|
+
watch(() => props.sort, (newSort: any) => {
|
|
397
397
|
sort.value = newSort;
|
|
398
398
|
});
|
|
399
399
|
|
|
@@ -404,17 +404,17 @@ watch(() => props.page, (newPage) => {
|
|
|
404
404
|
page.value = newPage;
|
|
405
405
|
});
|
|
406
406
|
|
|
407
|
-
const rowRefs = useTemplateRef('rowRefs');
|
|
408
|
-
const headerRefs = useTemplateRef('headerRefs');
|
|
409
|
-
const rowHeights = ref([]);
|
|
410
|
-
const columnWidths = ref([]);
|
|
407
|
+
const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
|
|
408
|
+
const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
|
|
409
|
+
const rowHeights = ref<number[]>([]);
|
|
410
|
+
const columnWidths = ref<number[]>([]);
|
|
411
411
|
watch(() => props.rows, (newRows) => {
|
|
412
412
|
// rows are set to null when new records are loading
|
|
413
|
-
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el) => el.offsetHeight);
|
|
414
|
-
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el) => el.offsetWidth)];
|
|
413
|
+
rowHeights.value = newRows || !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
|
|
414
|
+
columnWidths.value = newRows || !headerRefs.value ? [] : [48, ...headerRefs.value.map((el: HTMLElement) => el.offsetWidth)];
|
|
415
415
|
});
|
|
416
416
|
|
|
417
|
-
function addToCheckedValues(id) {
|
|
417
|
+
function addToCheckedValues(id: any) {
|
|
418
418
|
if (checkboxesInternal.value.includes(id)) {
|
|
419
419
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== id);
|
|
420
420
|
} else {
|
|
@@ -423,17 +423,17 @@ function addToCheckedValues(id) {
|
|
|
423
423
|
checkboxesInternal.value = [ ...checkboxesInternal.value ]
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
const columnsListed = computed(() => props.resource?.columns?.filter(c => c.showIn
|
|
426
|
+
const columnsListed = computed(() => props.resource?.columns?.filter((c: AdminForthResourceColumnCommon) => c.showIn?.list));
|
|
427
427
|
|
|
428
|
-
async function selectAll(
|
|
428
|
+
async function selectAll() {
|
|
429
429
|
if (!allFromThisPageChecked.value) {
|
|
430
|
-
props.rows
|
|
430
|
+
props.rows?.forEach((r) => {
|
|
431
431
|
if (!checkboxesInternal.value.includes(r._primaryKeyValue)) {
|
|
432
432
|
checkboxesInternal.value.push(r._primaryKeyValue)
|
|
433
433
|
}
|
|
434
434
|
});
|
|
435
435
|
} else {
|
|
436
|
-
props.rows
|
|
436
|
+
props.rows?.forEach((r) => {
|
|
437
437
|
checkboxesInternal.value = checkboxesInternal.value.filter((item) => item !== r._primaryKeyValue);
|
|
438
438
|
});
|
|
439
439
|
}
|
|
@@ -446,15 +446,15 @@ const allFromThisPageChecked = computed(() => {
|
|
|
446
446
|
if (!props.rows || !props.rows.length) return false;
|
|
447
447
|
return props.rows.every((r) => checkboxesInternal.value.includes(r._primaryKeyValue));
|
|
448
448
|
});
|
|
449
|
-
const ascArr = computed(() => sort.value.filter((s) => s.direction === 'asc').map((s) => s.field));
|
|
450
|
-
const descArr = computed(() => sort.value.filter((s) => s.direction === 'desc').map((s) => s.field));
|
|
449
|
+
const ascArr = computed(() => sort.value.filter((s: any) => s.direction === 'asc').map((s: any) => s.field));
|
|
450
|
+
const descArr = computed(() => sort.value.filter((s: any) => s.direction === 'desc').map((s: any) => s.field));
|
|
451
451
|
|
|
452
452
|
|
|
453
|
-
function onSortButtonClick(event, field) {
|
|
453
|
+
function onSortButtonClick(event: any, field: any) {
|
|
454
454
|
// if ctrl key is pressed, add to sort otherwise sort by this field
|
|
455
455
|
// in any case if field is already in sort, toggle direction
|
|
456
456
|
|
|
457
|
-
const sortIndex = sort.value.findIndex((s) => s.field === field);
|
|
457
|
+
const sortIndex = sort.value.findIndex((s: any) => s.field === field);
|
|
458
458
|
if (sortIndex === -1) {
|
|
459
459
|
// field is not in sort, add it
|
|
460
460
|
if (event.ctrlKey) {
|
|
@@ -475,11 +475,11 @@ function onSortButtonClick(event, field) {
|
|
|
475
475
|
|
|
476
476
|
const clickTarget = ref(null);
|
|
477
477
|
|
|
478
|
-
async function onClick(e,row) {
|
|
478
|
+
async function onClick(e: any,row: any) {
|
|
479
479
|
if(clickTarget.value === e.target) return;
|
|
480
480
|
clickTarget.value = e.target;
|
|
481
481
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
482
|
-
if (window.getSelection()
|
|
482
|
+
if (window.getSelection()?.toString()) return;
|
|
483
483
|
else {
|
|
484
484
|
if (row._clickUrl === null) {
|
|
485
485
|
// user asked to nothing on click
|
|
@@ -494,7 +494,7 @@ async function onClick(e,row) {
|
|
|
494
494
|
router.resolve({
|
|
495
495
|
name: 'resource-show',
|
|
496
496
|
params: {
|
|
497
|
-
resourceId: props.resource
|
|
497
|
+
resourceId: props.resource?.resourceId,
|
|
498
498
|
primaryKey: row._primaryKeyValue,
|
|
499
499
|
},
|
|
500
500
|
}).href,
|
|
@@ -512,7 +512,7 @@ async function onClick(e,row) {
|
|
|
512
512
|
router.push({
|
|
513
513
|
name: 'resource-show',
|
|
514
514
|
params: {
|
|
515
|
-
resourceId: props.resource
|
|
515
|
+
resourceId: props.resource?.resourceId,
|
|
516
516
|
primaryKey: row._primaryKeyValue,
|
|
517
517
|
},
|
|
518
518
|
});
|
|
@@ -521,7 +521,7 @@ async function onClick(e,row) {
|
|
|
521
521
|
}
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
-
async function deleteRecord(row) {
|
|
524
|
+
async function deleteRecord(row: any) {
|
|
525
525
|
const data = await adminforth.confirm({
|
|
526
526
|
message: t('Are you sure you want to delete this item?'),
|
|
527
527
|
yes: t('Delete'),
|
|
@@ -533,7 +533,7 @@ async function deleteRecord(row) {
|
|
|
533
533
|
path: '/delete_record',
|
|
534
534
|
method: 'POST',
|
|
535
535
|
body: {
|
|
536
|
-
resourceId: props.resource
|
|
536
|
+
resourceId: props.resource?.resourceId,
|
|
537
537
|
primaryKey: row._primaryKeyValue,
|
|
538
538
|
}
|
|
539
539
|
});
|
|
@@ -551,16 +551,16 @@ async function deleteRecord(row) {
|
|
|
551
551
|
}
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
const actionLoadingStates = ref({});
|
|
554
|
+
const actionLoadingStates = ref<Record<string | number, boolean>>({});
|
|
555
555
|
|
|
556
|
-
async function startCustomAction(actionId, row) {
|
|
556
|
+
async function startCustomAction(actionId: string, row: any) {
|
|
557
557
|
actionLoadingStates.value[actionId] = true;
|
|
558
558
|
|
|
559
559
|
const data = await callAdminForthApi({
|
|
560
560
|
path: '/start_custom_action',
|
|
561
561
|
method: 'POST',
|
|
562
562
|
body: {
|
|
563
|
-
resourceId: props.resource
|
|
563
|
+
resourceId: props.resource?.resourceId,
|
|
564
564
|
actionId: actionId,
|
|
565
565
|
recordId: row._primaryKeyValue
|
|
566
566
|
}
|
|
@@ -598,7 +598,7 @@ async function startCustomAction(actionId, row) {
|
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
-
function onPageInput(event) {
|
|
601
|
+
function onPageInput(event: any) {
|
|
602
602
|
pageInput.value = event.target.innerText;
|
|
603
603
|
}
|
|
604
604
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template >
|
|
2
|
-
<template v-if="threeDotsDropdownItems?.length || customActions?.length || (bulkActions?.some(action => action.showInThreeDotsDropdown))">
|
|
2
|
+
<template v-if="threeDotsDropdownItems?.length || customActions?.length || (bulkActions?.some((action: AdminForthBulkActionCommon) => action.showInThreeDotsDropdown))">
|
|
3
3
|
<button
|
|
4
4
|
data-dropdown-toggle="listThreeDotsDropdown"
|
|
5
5
|
class="flex items-center py-2 px-2 text-sm font-medium text-lightThreeDotsMenuIconDots focus:outline-none bg-lightThreeDotsMenuIconBackground rounded border border-lightThreeDotsMenuIconBackgroundBorder hover:bg-lightThreeDotsMenuIconBackgroundHover hover:text-lightThreeDotsMenuIconDotsHover focus:z-10 focus:ring-4 focus:ring-lightThreeDotsMenuIconFocus dark:focus:ring-darkThreeDotsMenuIconFocus dark:bg-darkThreeDotsMenuIconBackground dark:text-darkThreeDotsMenuIconDots dark:border-darkThreeDotsMenuIconBackgroundBorder dark:hover:text-darkThreeDotsMenuIconDotsHover dark:hover:bg-darkThreeDotsMenuIconBackgroundHover rounded-default"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
id="listThreeDotsDropdown"
|
|
15
15
|
class="z-20 hidden bg-lightThreeDotsMenuBodyBackground divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-darkThreeDotsMenuBodyBackground dark:divide-gray-600">
|
|
16
16
|
<ul class="py-2 text-sm text-lightThreeDotsMenuBodyText dark:text-darkThreeDotsMenuBodyText" aria-labelledby="dropdownMenuIconButton">
|
|
17
|
-
<li v-for="item in threeDotsDropdownItems" :key="`dropdown-item-${
|
|
17
|
+
<li v-for="(item, i) in threeDotsDropdownItems" :key="`dropdown-item-${i}`">
|
|
18
18
|
<a href="#"
|
|
19
19
|
class="block px-4 py-2 hover:bg-lightThreeDotsMenuBodyBackgroundHover hover:text-lightThreeDotsMenuBodyTextHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover"
|
|
20
20
|
:class="{
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
/>
|
|
33
33
|
</a>
|
|
34
34
|
</li>
|
|
35
|
-
<li v-for="action in customActions" :key="action.id">
|
|
35
|
+
<li v-if="customActions" v-for="action in customActions" :key="action.id">
|
|
36
36
|
<a href="#" @click.prevent="handleActionClick(action)" class="block px-4 py-2 hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover">
|
|
37
37
|
<div class="flex items-center gap-2">
|
|
38
38
|
<component
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
</div>
|
|
45
45
|
</a>
|
|
46
46
|
</li>
|
|
47
|
-
<li v-for="action in bulkActions
|
|
47
|
+
<li v-for="action in bulkActions?.filter((a:AdminForthBulkActionCommon ) => a.showInThreeDotsDropdown)" :key="action.id">
|
|
48
48
|
<a href="#" @click.prevent="startBulkAction(action.id)"
|
|
49
49
|
class="block px-4 py-2 hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover"
|
|
50
50
|
:class="{
|
|
51
|
-
'pointer-events-none':
|
|
52
|
-
'opacity-50':
|
|
53
|
-
'cursor-not-allowed':
|
|
51
|
+
'pointer-events-none': checkboxes && checkboxes.length === 0,
|
|
52
|
+
'opacity-50': checkboxes && checkboxes.length === 0,
|
|
53
|
+
'cursor-not-allowed': checkboxes && checkboxes.length === 0
|
|
54
54
|
}">
|
|
55
55
|
<div class="flex items-center gap-2">
|
|
56
56
|
<component
|
|
@@ -74,15 +74,16 @@ import { useCoreStore } from '@/stores/core';
|
|
|
74
74
|
import adminforth from '@/adminforth';
|
|
75
75
|
import { callAdminForthApi } from '@/utils';
|
|
76
76
|
import { useRoute, useRouter } from 'vue-router';
|
|
77
|
+
import type { AdminForthComponentDeclarationFull, AdminForthBulkActionCommon, AdminForthActionInput } from '@/types/Common.js';
|
|
77
78
|
|
|
78
79
|
const route = useRoute();
|
|
79
80
|
const coreStore = useCoreStore();
|
|
80
81
|
const router = useRouter();
|
|
81
82
|
|
|
82
83
|
const props = defineProps({
|
|
83
|
-
threeDotsDropdownItems: Array
|
|
84
|
-
customActions: Array
|
|
85
|
-
bulkActions: Array
|
|
84
|
+
threeDotsDropdownItems: Array<AdminForthComponentDeclarationFull>,
|
|
85
|
+
customActions: Array<AdminForthActionInput>,
|
|
86
|
+
bulkActions: Array<AdminForthBulkActionCommon>,
|
|
86
87
|
checkboxes: Array,
|
|
87
88
|
updateList: {
|
|
88
89
|
type: Function,
|
|
@@ -94,7 +95,7 @@ const props = defineProps({
|
|
|
94
95
|
|
|
95
96
|
const emit = defineEmits(['startBulkAction']);
|
|
96
97
|
|
|
97
|
-
async function handleActionClick(action) {
|
|
98
|
+
async function handleActionClick(action: AdminForthActionInput) {
|
|
98
99
|
adminforth.list.closeThreeDotsDropdown();
|
|
99
100
|
|
|
100
101
|
const actionId = action.id;
|
|
@@ -125,8 +126,8 @@ async function handleActionClick(action) {
|
|
|
125
126
|
|
|
126
127
|
if (data?.ok) {
|
|
127
128
|
await coreStore.fetchRecord({
|
|
128
|
-
resourceId: route.params.resourceId,
|
|
129
|
-
primaryKey: route.params.primaryKey,
|
|
129
|
+
resourceId: route.params.resourceId as string,
|
|
130
|
+
primaryKey: route.params.primaryKey as string,
|
|
130
131
|
source: 'show',
|
|
131
132
|
});
|
|
132
133
|
|
|
@@ -146,7 +147,7 @@ async function handleActionClick(action) {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
function startBulkAction(actionId) {
|
|
150
|
+
function startBulkAction(actionId: string) {
|
|
150
151
|
adminforth.list.closeThreeDotsDropdown();
|
|
151
152
|
emit('startBulkAction', actionId);
|
|
152
153
|
}
|
|
@@ -12,13 +12,40 @@
|
|
|
12
12
|
>
|
|
13
13
|
<RouterLink
|
|
14
14
|
class="font-medium text-lightSidebarText dark:text-darkSidebarText hover:brightness-110 whitespace-nowrap"
|
|
15
|
-
:to="{
|
|
15
|
+
:to="{
|
|
16
|
+
name: 'resource-show',
|
|
17
|
+
params: {
|
|
18
|
+
primaryKey: foreignResource.pk,
|
|
19
|
+
resourceId: column.foreignResource
|
|
20
|
+
? (
|
|
21
|
+
column.foreignResource.resourceId
|
|
22
|
+
|| column.foreignResource.polymorphicResources?.find(
|
|
23
|
+
(pr: any) => pr.whenValue === record[column.foreignResource?.polymorphicOn!]
|
|
24
|
+
)?.resourceId
|
|
25
|
+
)
|
|
26
|
+
: undefined
|
|
27
|
+
}
|
|
28
|
+
}"
|
|
16
29
|
>
|
|
17
30
|
{{ foreignResource.label }}
|
|
18
31
|
</RouterLink>
|
|
19
32
|
</span>
|
|
20
33
|
<RouterLink v-else-if="record[column.name]" class="font-medium text-lightPrimary dark:text-darkPrimary hover:brightness-110 whitespace-nowrap"
|
|
21
|
-
|
|
34
|
+
:to="{
|
|
35
|
+
name: 'resource-show',
|
|
36
|
+
params: {
|
|
37
|
+
primaryKey: record[column.name].pk,
|
|
38
|
+
resourceId: column.foreignResource
|
|
39
|
+
? (
|
|
40
|
+
column.foreignResource.resourceId
|
|
41
|
+
|| column.foreignResource.polymorphicResources?.find(
|
|
42
|
+
(pr: any) => pr.whenValue === record[column.foreignResource?.polymorphicOn!]
|
|
43
|
+
)?.resourceId
|
|
44
|
+
)
|
|
45
|
+
: undefined
|
|
46
|
+
}
|
|
47
|
+
}"
|
|
48
|
+
>
|
|
22
49
|
{{ record[column.name].label }}
|
|
23
50
|
</RouterLink>
|
|
24
51
|
<div v-else>
|
|
@@ -38,13 +65,13 @@
|
|
|
38
65
|
<template v-for="(arrayItem, arrayItemIndex) in record[column.name]">
|
|
39
66
|
<span
|
|
40
67
|
v-if="column.isArray.itemType === 'boolean' && arrayItem"
|
|
41
|
-
:key="`${column.name}-${arrayItemIndex}`"
|
|
68
|
+
:key="`${column.name}-${arrayItemIndex}-true`"
|
|
42
69
|
class="af-true-value-icon bg-green-100 whitespace-nowrap text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-green-400 border border-green-400">
|
|
43
70
|
{{ $t('Yes') }}
|
|
44
71
|
</span>
|
|
45
72
|
<span
|
|
46
73
|
v-else-if="column.isArray.itemType === 'boolean'"
|
|
47
|
-
:key="`${column.name}-${arrayItemIndex}`"
|
|
74
|
+
:key="`${column.name}-${arrayItemIndex}-false`"
|
|
48
75
|
class="af-false-value-icon bg-red-100 whitespace-nowrap text-red-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400">
|
|
49
76
|
{{ $t('No') }}
|
|
50
77
|
</span>
|
|
@@ -53,30 +80,30 @@
|
|
|
53
80
|
:key="`${column.name}-${arrayItemIndex}`"
|
|
54
81
|
class="rounded-md m-0.5 bg-lightAnnouncementBG dark:bg-darkAnnouncementBG text-lightAnnouncementText dark:text-darkAnnouncementText py-0.5 px-2.5 text-sm"
|
|
55
82
|
>
|
|
56
|
-
{{ checkEmptyValues(getArrayItemDisplayValue(arrayItem, column), route.meta.type) }}
|
|
83
|
+
{{ checkEmptyValues(getArrayItemDisplayValue(arrayItem, column), route.meta.type as "show" | "list") }}
|
|
57
84
|
</span>
|
|
58
85
|
</template>
|
|
59
86
|
</span>
|
|
60
87
|
<span v-else-if="column.enum">
|
|
61
|
-
{{ checkEmptyValues(column.enum.find(e => e.value === record[column.name])?.label || record[column.name], route.meta.type) }}
|
|
88
|
+
{{ checkEmptyValues(column.enum.find(e => e.value === record[column.name])?.label || record[column.name], route.meta.type as "show" | "list") }}
|
|
62
89
|
</span>
|
|
63
90
|
<span v-else-if="column.type === 'datetime'" class="whitespace-nowrap">
|
|
64
|
-
{{ checkEmptyValues(formatDateTime(record[column.name]), route.meta.type) }}
|
|
91
|
+
{{ checkEmptyValues(formatDateTime(record[column.name]), route.meta.type as "show" | "list") }}
|
|
65
92
|
</span>
|
|
66
93
|
<span v-else-if="column.type === 'date'" class="whitespace-nowrap">
|
|
67
|
-
{{ checkEmptyValues(formatDate(record[column.name]), route.meta.type) }}
|
|
94
|
+
{{ checkEmptyValues(formatDate(record[column.name]), route.meta.type as "show" | "list") }}
|
|
68
95
|
</span>
|
|
69
96
|
<span v-else-if="column.type === 'time'" class="whitespace-nowrap">
|
|
70
|
-
{{ checkEmptyValues(formatTime(record[column.name]), route.meta.type) }}
|
|
97
|
+
{{ checkEmptyValues(formatTime(record[column.name]), route.meta.type as "show" | "list") }}
|
|
71
98
|
</span>
|
|
72
99
|
<span v-else-if="column.type === 'decimal'">
|
|
73
|
-
{{ checkEmptyValues(record[column.name] && parseFloat(record[column.name]), route.meta.type) }}
|
|
100
|
+
{{ checkEmptyValues(record[column.name] && parseFloat(record[column.name]), route.meta.type as "show" | "list") }}
|
|
74
101
|
</span>
|
|
75
102
|
<span v-else-if="column.type === 'json'">
|
|
76
103
|
<JsonViewer class="min-w-[6rem]" :value="record[column.name]" :expandDepth="column.extra?.jsonCollapsedLevel" copyable sort :theme="coreStore.theme"/>
|
|
77
104
|
</span>
|
|
78
105
|
<span v-else>
|
|
79
|
-
{{ checkEmptyValues(record[column.name],route.meta.type) }}
|
|
106
|
+
{{ checkEmptyValues(record[column.name], route.meta.type as "show" | "list") }}
|
|
80
107
|
</span>
|
|
81
108
|
</div>
|
|
82
109
|
</template>
|
|
@@ -122,7 +149,7 @@ function formatTime(time: string) {
|
|
|
122
149
|
return dayjs(`0000-00-00 ${time}`).format(coreStore.config?.timeFormat || 'HH:mm:ss');
|
|
123
150
|
}
|
|
124
151
|
|
|
125
|
-
function getArrayItemDisplayValue(value, column) {
|
|
152
|
+
function getArrayItemDisplayValue(value: any, column: AdminForthResourceColumnCommon) {
|
|
126
153
|
if (column.isArray?.itemType === 'datetime') {
|
|
127
154
|
return formatDateTime(value);
|
|
128
155
|
} else if (column.isArray?.itemType === 'date') {
|
|
@@ -29,7 +29,12 @@ export const useModalStore = defineStore('modal', () => {
|
|
|
29
29
|
onCancelFunction.value = func;
|
|
30
30
|
}
|
|
31
31
|
function setModalContent(content: ModalContentType) {
|
|
32
|
-
modalContent.value =
|
|
32
|
+
modalContent.value = {
|
|
33
|
+
title: content.title || 'title',
|
|
34
|
+
content: content.content || 'content',
|
|
35
|
+
acceptText: content.acceptText || 'acceptText',
|
|
36
|
+
cancelText: content.cancelText || 'cancelText',
|
|
37
|
+
};
|
|
33
38
|
}
|
|
34
39
|
function resetmodalState() {
|
|
35
40
|
isOpened.value = false;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
* Types that are common for both frontend side (SPA) and backend side (server).
|
|
4
3
|
*/
|
|
@@ -264,9 +263,17 @@ export interface AdminForthComponentDeclarationFull {
|
|
|
264
263
|
*/
|
|
265
264
|
meta?: any,
|
|
266
265
|
}
|
|
266
|
+
import { type AdminForthActionInput } from './Back.js'
|
|
267
|
+
export { type AdminForthActionInput } from './Back.js'
|
|
267
268
|
|
|
268
269
|
export type AdminForthComponentDeclaration = AdminForthComponentDeclarationFull | string;
|
|
269
270
|
|
|
271
|
+
export type FieldGroup = {
|
|
272
|
+
groupName: string;
|
|
273
|
+
columns: string[];
|
|
274
|
+
noTitle?: boolean;
|
|
275
|
+
};
|
|
276
|
+
|
|
270
277
|
/**
|
|
271
278
|
* Resource describes one table or collection in database.
|
|
272
279
|
* AdminForth generates set of pages for 'list', 'show', 'edit', 'create', 'filter' operations for each resource.
|
|
@@ -348,6 +355,11 @@ export interface AdminForthResourceInputCommon {
|
|
|
348
355
|
direction: AdminForthSortDirections | string,
|
|
349
356
|
}
|
|
350
357
|
|
|
358
|
+
/*
|
|
359
|
+
* Custom actions list. Actions available in show, edit and create views.
|
|
360
|
+
*/
|
|
361
|
+
actions?: AdminForthActionInput[],
|
|
362
|
+
|
|
351
363
|
/**
|
|
352
364
|
* Custom bulk actions list. Bulk actions available in list view when user selects multiple records by
|
|
353
365
|
* using checkboxes.
|
|
@@ -375,26 +387,10 @@ export interface AdminForthResourceInputCommon {
|
|
|
375
387
|
/**
|
|
376
388
|
* Allows to make groups of columns in show, create and edit resource pages.
|
|
377
389
|
*/
|
|
378
|
-
fieldGroups?:
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}[];
|
|
383
|
-
createFieldGroups?: {
|
|
384
|
-
groupName: string;
|
|
385
|
-
columns: string[];
|
|
386
|
-
noTitle?: boolean;
|
|
387
|
-
}[];
|
|
388
|
-
editFieldGroups?: {
|
|
389
|
-
groupName: string;
|
|
390
|
-
columns: string[];
|
|
391
|
-
noTitle?: boolean;
|
|
392
|
-
}[];
|
|
393
|
-
showFieldGroups?: {
|
|
394
|
-
groupName: string;
|
|
395
|
-
columns: string[];
|
|
396
|
-
noTitle?: boolean;
|
|
397
|
-
}[];
|
|
390
|
+
fieldGroups?: FieldGroup[];
|
|
391
|
+
createFieldGroups?: FieldGroup[];
|
|
392
|
+
editFieldGroups?: FieldGroup[];
|
|
393
|
+
showFieldGroups?: FieldGroup[];
|
|
398
394
|
|
|
399
395
|
/**
|
|
400
396
|
* Page size for list view
|
|
@@ -31,11 +31,7 @@
|
|
|
31
31
|
</button>
|
|
32
32
|
|
|
33
33
|
<ThreeDotsMenu
|
|
34
|
-
:threeDotsDropdownItems="
|
|
35
|
-
? coreStore.resourceOptions?.pageInjections?.create?.threeDotsDropdownItems
|
|
36
|
-
: coreStore.resourceOptions?.pageInjections?.create?.threeDotsDropdownItems
|
|
37
|
-
? [coreStore.resourceOptions?.pageInjections?.create?.threeDotsDropdownItems]
|
|
38
|
-
: []"
|
|
34
|
+
:threeDotsDropdownItems="(coreStore.resourceOptions?.pageInjections?.create?.threeDotsDropdownItems as [])"
|
|
39
35
|
></ThreeDotsMenu>
|
|
40
36
|
|
|
41
37
|
</BreadcrumbsWithButtons>
|
|
@@ -27,11 +27,7 @@
|
|
|
27
27
|
</button>
|
|
28
28
|
|
|
29
29
|
<ThreeDotsMenu
|
|
30
|
-
:threeDotsDropdownItems="
|
|
31
|
-
? coreStore.resourceOptions.pageInjections.edit.threeDotsDropdownItems
|
|
32
|
-
: coreStore.resourceOptions?.pageInjections?.edit?.threeDotsDropdownItems
|
|
33
|
-
? [coreStore.resourceOptions.pageInjections.edit.threeDotsDropdownItems]
|
|
34
|
-
: undefined"
|
|
30
|
+
:threeDotsDropdownItems="(coreStore.resourceOptions?.pageInjections?.edit?.threeDotsDropdownItems as [])"
|
|
35
31
|
></ThreeDotsMenu>
|
|
36
32
|
|
|
37
33
|
</BreadcrumbsWithButtons>
|