adminforth 1.2.17 → 1.2.19
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/spa/src/components/ResourceForm.vue +28 -16
- package/dist/spa/spa/src/components/Toast.vue +11 -6
- package/dist/spa/spa/src/composables/useStores.ts +1 -0
- package/package.json +1 -1
- package/spa/src/components/ResourceForm.vue +28 -16
- package/spa/src/components/Toast.vue +11 -6
- package/spa/src/composables/useStores.ts +1 -0
- package/types/AdminForthConfig.ts +95 -92
- package/types/FrontendAPI.ts +5 -0
|
@@ -20,29 +20,31 @@
|
|
|
20
20
|
<tr v-for="column, i in editableColumns" :key="column.name"
|
|
21
21
|
class="bg-ligftForm dark:bg-gray-800 border-b dark:border-gray-700"
|
|
22
22
|
>
|
|
23
|
-
<td class="px-6 py-4 whitespace-nowrap "> <!--align-top-->
|
|
23
|
+
<td class="px-6 py-4 whitespace-nowrap flex items-center"> <!--align-top-->
|
|
24
24
|
{{ column.label }}
|
|
25
|
-
<span :data-tooltip-target="`tooltip-show-${i}`" class="relative inline-block">
|
|
25
|
+
<span :data-tooltip-target="`tooltip-show-${i}`" class="ml-1 relative inline-block">
|
|
26
26
|
<IconExclamationCircleSolid v-if="column.required[mode]" class="w-4 h-4"
|
|
27
27
|
:class="(columnError(column) && validating) ? 'text-red-500 dark:text-red-400' : 'text-gray-400 dark:text-gray-500'"
|
|
28
28
|
/>
|
|
29
29
|
</span>
|
|
30
30
|
<div :id="`tooltip-show-${i}`"
|
|
31
|
-
role="tooltip"
|
|
31
|
+
role="tooltip"
|
|
32
|
+
class="ml-1 absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
|
32
33
|
Required field
|
|
33
34
|
<div class="tooltip-arrow" data-popper-arrow></div>
|
|
34
35
|
</div>
|
|
35
36
|
</td>
|
|
36
37
|
<td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap relative">
|
|
37
|
-
|
|
38
38
|
<template v-if="column?.components?.[props.source]?.file">
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
<component
|
|
40
|
+
:is="getCustomComponent(column.components[props.source])"
|
|
41
|
+
:column="column"
|
|
42
|
+
:value="currentValues[column.name]"
|
|
43
|
+
@update:value="setCurrentValue(column.name, $event)"
|
|
44
|
+
:meta="column.components[props.source].meta"
|
|
45
|
+
:record="props.record"
|
|
46
|
+
@update:inValidity="customComponentsInValidity[column.name] = $event"
|
|
47
|
+
/>
|
|
46
48
|
</template>
|
|
47
49
|
<template v-else>
|
|
48
50
|
<Dropdown
|
|
@@ -122,10 +124,11 @@
|
|
|
122
124
|
<IconEyeSolid class="w-6 h-6 text-gray-400" v-if="!unmasked[column.name]" />
|
|
123
125
|
<IconEyeSlashSolid class="w-6 h-6 text-gray-400" v-else />
|
|
124
126
|
</button>
|
|
125
|
-
<div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
|
|
126
|
-
|
|
127
|
-
<div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
|
|
128
127
|
</template>
|
|
128
|
+
<div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
|
|
129
|
+
|
|
130
|
+
<div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
|
|
131
|
+
|
|
129
132
|
</td>
|
|
130
133
|
</tr>
|
|
131
134
|
|
|
@@ -167,9 +170,15 @@ const emit = defineEmits(['update:record', 'update:isValid']);
|
|
|
167
170
|
|
|
168
171
|
const currentValues = ref({});
|
|
169
172
|
|
|
173
|
+
const customComponentsInValidity = ref({});
|
|
174
|
+
|
|
170
175
|
|
|
171
176
|
const columnError = (column) => {
|
|
172
177
|
const val = computed(() => {
|
|
178
|
+
if (customComponentsInValidity.value[column.name]) {
|
|
179
|
+
return customComponentsInValidity.value[column.name];
|
|
180
|
+
}
|
|
181
|
+
|
|
173
182
|
if ( column.required[mode.value] && (currentValues.value[column.name] === undefined || currentValues.value[column.name] === null || currentValues.value[column.name] === '') ) {
|
|
174
183
|
return 'This field is required';
|
|
175
184
|
}
|
|
@@ -182,14 +191,17 @@ const columnError = (column) => {
|
|
|
182
191
|
}
|
|
183
192
|
}
|
|
184
193
|
if ( ['integer', 'decimal', 'float'].includes(column.type) ) {
|
|
185
|
-
if ( column.minValue !== undefined
|
|
194
|
+
if ( column.minValue !== undefined
|
|
195
|
+
&& currentValues.value[column.name] !== null
|
|
196
|
+
&& currentValues.value[column.name] < column.minValue
|
|
197
|
+
) {
|
|
186
198
|
return `This field must be greater than ${column.minValue}`;
|
|
187
199
|
}
|
|
188
200
|
if ( column.maxValue !== undefined && currentValues.value[column.name] > column.maxValue ) {
|
|
189
201
|
return `This field must be less than ${column.maxValue}`;
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
|
-
if ( column.validation && column.validation.length ){
|
|
204
|
+
if ( column.validation && column.validation.length ) {
|
|
193
205
|
const validationArray = column.validation;
|
|
194
206
|
for (let i = 0; i < validationArray.length; i++) {
|
|
195
207
|
if (validationArray[i].regExp) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
<div id="toast-default" class="flex items-center w-full
|
|
4
|
+
<div id="toast-default" class="flex items-center w-full p-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert">
|
|
5
5
|
<div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200">
|
|
6
6
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
|
7
7
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.147 15.085a7.159 7.159 0 0 1-6.189 3.307A6.713 6.713 0 0 1 3.1 15.444c-2.679-4.513.287-8.737.888-9.548A4.373 4.373 0 0 0 5 1.608c1.287.953 6.445 3.218 5.537 10.5 1.5-1.122 2.706-3.01 2.853-6.14 1.433 1.049 3.993 5.395 1.757 9.117Z"/>
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
</svg>
|
|
27
27
|
<span class="sr-only">Check icon</span>
|
|
28
28
|
</div>
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
<div class="ms-3 text-sm font-normal max-w-xs" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
31
|
+
<div class="ms-3 text-sm font-normal max-w-xs" v-else>{{toast.message}}</div>
|
|
30
32
|
<button @click="closeToast" type="button" class="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700" >
|
|
31
33
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
32
34
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
@@ -43,10 +45,13 @@ import { useToastStore } from '@/stores/toast';
|
|
|
43
45
|
const toastStore = useToastStore();
|
|
44
46
|
const emit = defineEmits(['close']);
|
|
45
47
|
const props = defineProps<{
|
|
46
|
-
toast:{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
toast: {
|
|
49
|
+
message?: string;
|
|
50
|
+
messageHtml?: string;
|
|
51
|
+
variant: string;
|
|
52
|
+
id: string;
|
|
53
|
+
timeout?: number|'unlimited';
|
|
54
|
+
}
|
|
50
55
|
}>();
|
|
51
56
|
function closeToast() {
|
|
52
57
|
emit('close');
|
package/package.json
CHANGED
|
@@ -20,29 +20,31 @@
|
|
|
20
20
|
<tr v-for="column, i in editableColumns" :key="column.name"
|
|
21
21
|
class="bg-ligftForm dark:bg-gray-800 border-b dark:border-gray-700"
|
|
22
22
|
>
|
|
23
|
-
<td class="px-6 py-4 whitespace-nowrap "> <!--align-top-->
|
|
23
|
+
<td class="px-6 py-4 whitespace-nowrap flex items-center"> <!--align-top-->
|
|
24
24
|
{{ column.label }}
|
|
25
|
-
<span :data-tooltip-target="`tooltip-show-${i}`" class="relative inline-block">
|
|
25
|
+
<span :data-tooltip-target="`tooltip-show-${i}`" class="ml-1 relative inline-block">
|
|
26
26
|
<IconExclamationCircleSolid v-if="column.required[mode]" class="w-4 h-4"
|
|
27
27
|
:class="(columnError(column) && validating) ? 'text-red-500 dark:text-red-400' : 'text-gray-400 dark:text-gray-500'"
|
|
28
28
|
/>
|
|
29
29
|
</span>
|
|
30
30
|
<div :id="`tooltip-show-${i}`"
|
|
31
|
-
role="tooltip"
|
|
31
|
+
role="tooltip"
|
|
32
|
+
class="ml-1 absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
|
32
33
|
Required field
|
|
33
34
|
<div class="tooltip-arrow" data-popper-arrow></div>
|
|
34
35
|
</div>
|
|
35
36
|
</td>
|
|
36
37
|
<td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap relative">
|
|
37
|
-
|
|
38
38
|
<template v-if="column?.components?.[props.source]?.file">
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
<component
|
|
40
|
+
:is="getCustomComponent(column.components[props.source])"
|
|
41
|
+
:column="column"
|
|
42
|
+
:value="currentValues[column.name]"
|
|
43
|
+
@update:value="setCurrentValue(column.name, $event)"
|
|
44
|
+
:meta="column.components[props.source].meta"
|
|
45
|
+
:record="props.record"
|
|
46
|
+
@update:inValidity="customComponentsInValidity[column.name] = $event"
|
|
47
|
+
/>
|
|
46
48
|
</template>
|
|
47
49
|
<template v-else>
|
|
48
50
|
<Dropdown
|
|
@@ -122,10 +124,11 @@
|
|
|
122
124
|
<IconEyeSolid class="w-6 h-6 text-gray-400" v-if="!unmasked[column.name]" />
|
|
123
125
|
<IconEyeSlashSolid class="w-6 h-6 text-gray-400" v-else />
|
|
124
126
|
</button>
|
|
125
|
-
<div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
|
|
126
|
-
|
|
127
|
-
<div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
|
|
128
127
|
</template>
|
|
128
|
+
<div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
|
|
129
|
+
|
|
130
|
+
<div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
|
|
131
|
+
|
|
129
132
|
</td>
|
|
130
133
|
</tr>
|
|
131
134
|
|
|
@@ -167,9 +170,15 @@ const emit = defineEmits(['update:record', 'update:isValid']);
|
|
|
167
170
|
|
|
168
171
|
const currentValues = ref({});
|
|
169
172
|
|
|
173
|
+
const customComponentsInValidity = ref({});
|
|
174
|
+
|
|
170
175
|
|
|
171
176
|
const columnError = (column) => {
|
|
172
177
|
const val = computed(() => {
|
|
178
|
+
if (customComponentsInValidity.value[column.name]) {
|
|
179
|
+
return customComponentsInValidity.value[column.name];
|
|
180
|
+
}
|
|
181
|
+
|
|
173
182
|
if ( column.required[mode.value] && (currentValues.value[column.name] === undefined || currentValues.value[column.name] === null || currentValues.value[column.name] === '') ) {
|
|
174
183
|
return 'This field is required';
|
|
175
184
|
}
|
|
@@ -182,14 +191,17 @@ const columnError = (column) => {
|
|
|
182
191
|
}
|
|
183
192
|
}
|
|
184
193
|
if ( ['integer', 'decimal', 'float'].includes(column.type) ) {
|
|
185
|
-
if ( column.minValue !== undefined
|
|
194
|
+
if ( column.minValue !== undefined
|
|
195
|
+
&& currentValues.value[column.name] !== null
|
|
196
|
+
&& currentValues.value[column.name] < column.minValue
|
|
197
|
+
) {
|
|
186
198
|
return `This field must be greater than ${column.minValue}`;
|
|
187
199
|
}
|
|
188
200
|
if ( column.maxValue !== undefined && currentValues.value[column.name] > column.maxValue ) {
|
|
189
201
|
return `This field must be less than ${column.maxValue}`;
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
|
-
if ( column.validation && column.validation.length ){
|
|
204
|
+
if ( column.validation && column.validation.length ) {
|
|
193
205
|
const validationArray = column.validation;
|
|
194
206
|
for (let i = 0; i < validationArray.length; i++) {
|
|
195
207
|
if (validationArray[i].regExp) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
<div id="toast-default" class="flex items-center w-full
|
|
4
|
+
<div id="toast-default" class="flex items-center w-full p-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800" role="alert">
|
|
5
5
|
<div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-blue-500 bg-blue-100 rounded-lg dark:bg-blue-800 dark:text-blue-200">
|
|
6
6
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
|
7
7
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.147 15.085a7.159 7.159 0 0 1-6.189 3.307A6.713 6.713 0 0 1 3.1 15.444c-2.679-4.513.287-8.737.888-9.548A4.373 4.373 0 0 0 5 1.608c1.287.953 6.445 3.218 5.537 10.5 1.5-1.122 2.706-3.01 2.853-6.14 1.433 1.049 3.993 5.395 1.757 9.117Z"/>
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
</svg>
|
|
27
27
|
<span class="sr-only">Check icon</span>
|
|
28
28
|
</div>
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
<div class="ms-3 text-sm font-normal max-w-xs" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
31
|
+
<div class="ms-3 text-sm font-normal max-w-xs" v-else>{{toast.message}}</div>
|
|
30
32
|
<button @click="closeToast" type="button" class="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700" >
|
|
31
33
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
32
34
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
@@ -43,10 +45,13 @@ import { useToastStore } from '@/stores/toast';
|
|
|
43
45
|
const toastStore = useToastStore();
|
|
44
46
|
const emit = defineEmits(['close']);
|
|
45
47
|
const props = defineProps<{
|
|
46
|
-
toast:{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
toast: {
|
|
49
|
+
message?: string;
|
|
50
|
+
messageHtml?: string;
|
|
51
|
+
variant: string;
|
|
52
|
+
id: string;
|
|
53
|
+
timeout?: number|'unlimited';
|
|
54
|
+
}
|
|
50
55
|
}>();
|
|
51
56
|
function closeToast() {
|
|
52
57
|
emit('close');
|
|
@@ -651,12 +651,101 @@ export type BeforeLoginConfirmationFunction = (params?: {
|
|
|
651
651
|
}
|
|
652
652
|
}>;
|
|
653
653
|
|
|
654
|
+
|
|
655
|
+
export type AdminForthBulkAction = {
|
|
656
|
+
id?: string,
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Label for action button which will be displayed in the list view
|
|
660
|
+
*/
|
|
661
|
+
label: string,
|
|
662
|
+
state: string,
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Icon for action button which will be displayed in the list view
|
|
666
|
+
*/
|
|
667
|
+
icon?: string,
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Callback which will be called on backend when user clicks on action button.
|
|
671
|
+
* It should return Promise which will be resolved when action is done.
|
|
672
|
+
*/
|
|
673
|
+
action: ({ resource, selectedIds, adminUser }: { resource: AdminForthResource, selectedIds: Array<any>, adminUser: AdminUser }) => Promise<void>,
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Confirmation message which will be displayed to user before action is executed.
|
|
677
|
+
*/
|
|
678
|
+
confirm?: string,
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Allowed callback called to check whether action is allowed for user.
|
|
682
|
+
* 1. It called first time when user goes to list view. If callback returns false, action button will be hidden on list view.
|
|
683
|
+
* 2. This same callback called second time when user clicks an action button. If callback returns false, action will not be executed.
|
|
684
|
+
* In second time selectedIds will be passed to callback (because checkbox for items are selected), so you can use this to make additional
|
|
685
|
+
* checks ( for example to check if user has permission for certain records ).
|
|
686
|
+
*
|
|
687
|
+
* Example:
|
|
688
|
+
*
|
|
689
|
+
* ```ts
|
|
690
|
+
* allowed: async ({ resource, adminUser, selectedIds }) => {
|
|
691
|
+
* if (adminUser.isRoot || adminUser.dbUser.role !== 'superadmin') {
|
|
692
|
+
* return false;
|
|
693
|
+
* }
|
|
694
|
+
* return true;
|
|
695
|
+
* }
|
|
696
|
+
* ```
|
|
697
|
+
*
|
|
698
|
+
*/
|
|
699
|
+
allowed?: ({ resource, adminUser, selectedIds, allowedActions }: {
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* recordIds will be passed only once user tries to perform bulk action by clicking on button
|
|
703
|
+
*/
|
|
704
|
+
selectedIds?: Array<any>,
|
|
705
|
+
resource: AdminForthResource,
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Admin user object
|
|
709
|
+
*/
|
|
710
|
+
adminUser: AdminUser,
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Allowed standard actions for current user resolved by calling allowedActions callbacks if they are passed.
|
|
714
|
+
* You can use this variable to rely on standard actions permissions. E.g. if you have custom actions "Mark as read", you
|
|
715
|
+
* might want to allow it only for users who have "edit" action allowed:
|
|
716
|
+
*
|
|
717
|
+
* Example:
|
|
718
|
+
*
|
|
719
|
+
* ```ts
|
|
720
|
+
*
|
|
721
|
+
* options: \{
|
|
722
|
+
* bulkActions: [
|
|
723
|
+
* \{
|
|
724
|
+
* label: 'Mark as read',
|
|
725
|
+
* action: async (\{ resource, recordIds \}) => \{
|
|
726
|
+
* await markAsRead(recordIds);
|
|
727
|
+
* \},
|
|
728
|
+
* allowed: (\{ allowedActions \}) => allowedActions.edit,
|
|
729
|
+
* \}
|
|
730
|
+
* ],
|
|
731
|
+
* allowedActions: \{
|
|
732
|
+
* edit: (\{ resource, adminUser, recordIds \}) => \{
|
|
733
|
+
* return adminUser.isRoot || adminUser.dbUser.role === 'superadmin';
|
|
734
|
+
* \}
|
|
735
|
+
* \}
|
|
736
|
+
* \}
|
|
737
|
+
* ```
|
|
738
|
+
*
|
|
739
|
+
*/
|
|
740
|
+
allowedActions: AllowedActionsResolved,
|
|
741
|
+
}) => Promise<boolean>,
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
|
|
654
745
|
/**
|
|
655
746
|
* Resource describes one table or collection in database.
|
|
656
747
|
* AdminForth generates set of pages for 'list', 'show', 'edit', 'create', 'filter' operations for each resource.
|
|
657
748
|
*/
|
|
658
|
-
|
|
659
|
-
|
|
660
749
|
export type AdminForthResource = {
|
|
661
750
|
/**
|
|
662
751
|
* Unique identifier of resource. By default it equals to table name in database.
|
|
@@ -764,97 +853,11 @@ export type AdminForthResource = {
|
|
|
764
853
|
direction: AdminForthSortDirections | string,
|
|
765
854
|
}
|
|
766
855
|
|
|
767
|
-
/**
|
|
768
|
-
* Custom bulk actions list
|
|
856
|
+
/**
|
|
857
|
+
* Custom bulk actions list. Bulk actions available in list view when user selects multiple records by
|
|
858
|
+
* using checkboxes.
|
|
769
859
|
*/
|
|
770
|
-
bulkActions?:
|
|
771
|
-
id?: string,
|
|
772
|
-
|
|
773
|
-
/**
|
|
774
|
-
* Label for action button which will be displayed in the list view
|
|
775
|
-
*/
|
|
776
|
-
label: string,
|
|
777
|
-
state: string,
|
|
778
|
-
|
|
779
|
-
/**
|
|
780
|
-
* Icon for action button which will be displayed in the list view
|
|
781
|
-
*/
|
|
782
|
-
icon?: string,
|
|
783
|
-
|
|
784
|
-
/**
|
|
785
|
-
* Callback which will be called on backend when user clicks on action button.
|
|
786
|
-
* It should return Promise which will be resolved when action is done.
|
|
787
|
-
*/
|
|
788
|
-
action: ({ resource, selectedIds, adminUser }: { resource: AdminForthResource, selectedIds: Array<any>, adminUser: AdminUser }) => Promise<void>,
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Confirmation message which will be displayed to user before action is executed.
|
|
792
|
-
*/
|
|
793
|
-
confirm?: string,
|
|
794
|
-
|
|
795
|
-
/**
|
|
796
|
-
* Allowed callback called to check whether action is allowed for user.
|
|
797
|
-
* 1. It called first time when user goes to list view. If callback returns false, action button will be hidden on list view.
|
|
798
|
-
* 2. This same callback called second time when user clicks an action button. If callback returns false, action will not be executed.
|
|
799
|
-
* In second time selectedIds will be passed to callback (because checkbox for items are selected), so you can use this to make additional
|
|
800
|
-
* checks ( for example to check if user has permission for certain records ).
|
|
801
|
-
*
|
|
802
|
-
* Example:
|
|
803
|
-
*
|
|
804
|
-
* ```ts
|
|
805
|
-
* allowed: async ({ resource, adminUser, selectedIds }) => {
|
|
806
|
-
* if (adminUser.isRoot || adminUser.dbUser.role !== 'superadmin') {
|
|
807
|
-
* return false;
|
|
808
|
-
* }
|
|
809
|
-
* return true;
|
|
810
|
-
* }
|
|
811
|
-
* ```
|
|
812
|
-
*
|
|
813
|
-
*/
|
|
814
|
-
allowed?: ({ resource, adminUser, selectedIds, allowedActions }: {
|
|
815
|
-
|
|
816
|
-
/**
|
|
817
|
-
* recordIds will be passed only once user tries to perform bulk action by clicking on button
|
|
818
|
-
*/
|
|
819
|
-
selectedIds?: Array<any>,
|
|
820
|
-
resource: AdminForthResource,
|
|
821
|
-
|
|
822
|
-
/**
|
|
823
|
-
* Admin user object
|
|
824
|
-
*/
|
|
825
|
-
adminUser: AdminUser,
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* Allowed standard actions for current user resolved by calling allowedActions callbacks if they are passed.
|
|
829
|
-
* You can use this variable to rely on standard actions permissions. E.g. if you have custom actions "Mark as read", you
|
|
830
|
-
* might want to allow it only for users who have "edit" action allowed:
|
|
831
|
-
*
|
|
832
|
-
* Example:
|
|
833
|
-
*
|
|
834
|
-
* ```ts
|
|
835
|
-
*
|
|
836
|
-
* options: {
|
|
837
|
-
* bulkActions: [
|
|
838
|
-
* {
|
|
839
|
-
* label: 'Mark as read',
|
|
840
|
-
* action: async ({ resource, recordIds }) => {
|
|
841
|
-
* await markAsRead(recordIds);
|
|
842
|
-
* },
|
|
843
|
-
* allowed: ({ allowedActions }) => allowedActions.edit,
|
|
844
|
-
* }
|
|
845
|
-
* ],
|
|
846
|
-
* allowedActions: {
|
|
847
|
-
* edit: ({ resource, adminUser, recordIds }) => {
|
|
848
|
-
* return adminUser.isRoot || adminUser.dbUser.role === 'superadmin';
|
|
849
|
-
* }
|
|
850
|
-
* }
|
|
851
|
-
* }
|
|
852
|
-
* ```
|
|
853
|
-
*
|
|
854
|
-
*/
|
|
855
|
-
allowedActions: AllowedActionsResolved,
|
|
856
|
-
}) => Promise<boolean>,
|
|
857
|
-
}[],
|
|
860
|
+
bulkActions?: AdminForthBulkAction[],
|
|
858
861
|
|
|
859
862
|
/**
|
|
860
863
|
* Allowed actions for resource.
|
package/types/FrontendAPI.ts
CHANGED