adminforth 1.1.23 → 1.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.js +12 -12
  2. package/dist/plugins/AccessControl/index.js +3 -56
  3. package/dist/plugins/AuditLog/index.js +13 -0
  4. package/dist/plugins/AuditLog/types.js +1 -0
  5. package/dist/plugins/plugins/ForeignInlineListPlugin/custom/InlineList.vue +248 -0
  6. package/dist/spa/index.html +2 -2
  7. package/dist/spa/package-lock.json +1 -189
  8. package/dist/spa/package.json +1 -6
  9. package/dist/spa/spa/src/components/ShowTableItem.vue +14 -0
  10. package/dist/spa/spa/src/views/HomeView.vue +8 -0
  11. package/dist/spa/src/App.vue +57 -76
  12. package/dist/spa/src/components/AcceptModal.vue +1 -1
  13. package/dist/spa/src/components/CustomDatePicker.vue +3 -3
  14. package/dist/spa/src/components/CustomDateRangePicker.vue +3 -3
  15. package/dist/spa/src/components/Dropdown.vue +4 -13
  16. package/dist/spa/src/components/Filters.vue +22 -55
  17. package/dist/spa/src/components/MenuLink.vue +2 -2
  18. package/dist/spa/src/components/ResourceForm.vue +99 -157
  19. package/dist/spa/src/components/ValueRenderer.vue +1 -11
  20. package/dist/spa/src/router/index.ts +2 -3
  21. package/dist/spa/src/stores/core.ts +33 -22
  22. package/dist/spa/src/utils.ts +3 -5
  23. package/dist/spa/src/views/CreateView.vue +7 -15
  24. package/dist/spa/src/views/EditView.vue +8 -36
  25. package/dist/spa/src/views/HomeView.vue +8 -0
  26. package/dist/spa/src/views/ListView.vue +23 -35
  27. package/dist/spa/src/views/LoginView.vue +1 -1
  28. package/dist/spa/src/views/ResourceParent.vue +1 -1
  29. package/dist/spa/src/views/ShowView.vue +9 -20
  30. package/dist/spa/tailwind.config.js +2 -5
  31. package/dist/types/AdminForthConfig.js +9 -0
  32. package/index.ts +16 -18
  33. package/package.json +1 -1
  34. package/plugins/AuditLog/index.ts +29 -0
  35. package/plugins/AuditLog/types.ts +4 -0
  36. package/types/AdminForthConfig.ts +23 -1
  37. package/dist/spa/src/components/CustomRangePicker.vue +0 -148
@@ -23,12 +23,11 @@
23
23
 
24
24
  <ResourceForm
25
25
  v-else
26
- :record="editableRecord"
26
+ :record="coreStore.record"
27
27
  :resourceColumns="coreStore.resourceColumns"
28
28
  @update:record="onUpdateRecord"
29
29
  @update:isValid="isValid = $event"
30
30
  :validating="validating"
31
- :customComponentsPerColumn="editComponentsPerColumn"
32
31
  >
33
32
  </ResourceForm>
34
33
  </div>
@@ -37,14 +36,14 @@
37
36
 
38
37
  <script setup>
39
38
 
40
- import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
41
- import ResourceForm from '@/components/ResourceForm.vue';
42
- import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
39
+ import { ref, computed, onMounted } from 'vue';
40
+ import { useRoute, useRouter } from 'vue-router';
43
41
  import { useCoreStore } from '@/stores/core';
44
- import { callAdminForthApi, getCustomComponent } from '@/utils';
42
+ import ResourceForm from '@/components/ResourceForm.vue';
43
+ import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
45
44
  import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
46
- import { computed, onMounted, ref } from 'vue';
47
- import { useRoute, useRouter } from 'vue-router';
45
+ import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
46
+ import { callAdminForthApi } from '@/utils';
48
47
 
49
48
  const coreStore = useCoreStore();
50
49
 
@@ -59,24 +58,11 @@ const loading = ref(false);
59
58
  const saving = ref(false);
60
59
 
61
60
  const record = ref({});
62
- let editComponentsPerColumn = {};
63
61
 
64
62
  async function onUpdateRecord(newRecord) {
65
63
  record.value = newRecord;
66
64
  }
67
65
 
68
- const editableRecord = computed(() => {
69
- const newRecord = { ...coreStore.record };
70
- if (!coreStore.resourceColumns) {
71
- return {};
72
- }
73
- coreStore.resourceColumns.forEach(column => {
74
- if (column.foreignResource) {
75
- newRecord[column.name] = newRecord[column.name]?.pk
76
- }
77
- });
78
- return newRecord;
79
- })
80
66
 
81
67
  onMounted(async () => {
82
68
  loading.value = true;
@@ -89,12 +75,6 @@ onMounted(async () => {
89
75
  primaryKey: route.params.primaryKey,
90
76
  });
91
77
 
92
- editComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
93
- if (column.component?.edit) {
94
- acc[column.name] = getCustomComponent(column.component.edit);
95
- }
96
- return acc;
97
- }, {});
98
78
  loading.value = false;
99
79
  });
100
80
 
@@ -107,21 +87,13 @@ async function saveRecord() {
107
87
  }
108
88
 
109
89
  saving.value = true;
110
-
111
- const updates = {};
112
- for (const key in record.value) {
113
- if (record.value[key] !== coreStore.record[key]) {
114
- updates[key] = record.value[key];
115
- }
116
- }
117
-
118
90
  await callAdminForthApi({
119
91
  method: 'POST',
120
92
  path: `/update_record`,
121
93
  body: {
122
94
  resourceId: route.params.resourceId,
123
95
  recordId: route.params.primaryKey,
124
- record: updates,
96
+ record: record.value,
125
97
  },
126
98
  });
127
99
  saving.value = false;
@@ -0,0 +1,8 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <main>
6
+ 123
7
+ </main>
8
+ </template>
@@ -65,7 +65,7 @@
65
65
  </BreadcrumbsWithButtons>
66
66
 
67
67
  <!-- table -->
68
- <div class="relative overflow-x-auto shadow-list-table-shadow dark:shadow-black dark:s">
68
+ <div class="relative overflow-x-auto shadow-md sm:rounded-lg dark:shadow-2xl">
69
69
 
70
70
 
71
71
  <!-- skelet loader -->
@@ -90,7 +90,7 @@
90
90
  </div>
91
91
 
92
92
  <table v-else class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
93
- <thead class="text-xs text-view-table-heading-text bg-list-view-table-heading dark:bg-gray-700 dark:text-gray-400">
93
+ <thead class="text-xs text-gray-700 bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
94
94
  <tr>
95
95
  <th scope="col" class="p-4">
96
96
  <div v-if="rows && rows.length" class="flex items-center">
@@ -127,7 +127,7 @@
127
127
  </tr>
128
128
  </thead>
129
129
  <tbody>
130
- <tr v-if="!rows" class="bg-list-view-table-bg border-b dark:bg-gray-800 dark:border-gray-700">
130
+ <tr v-if="!rows" class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
131
131
  <td :colspan="coreStore.resourceColumns.length + 2">
132
132
 
133
133
  <div role="status"
@@ -171,7 +171,7 @@
171
171
  </div>
172
172
  </td>
173
173
  </tr>
174
- <tr v-else-if="rows.length === 0" class="bg-list-view-table-bg border-b dark:bg-gray-800 dark:border-gray-700">
174
+ <tr v-else-if="rows.length === 0" class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
175
175
  <td :colspan="coreStore.resourceColumns.length + 2">
176
176
 
177
177
  <div id="toast-simple"
@@ -185,7 +185,7 @@
185
185
  </tr>
186
186
 
187
187
  <tr v-else v-for="(row, rowI) in rows" :key="row.id"
188
- class="bg-list-view-table-bg border-b dark:bg-gray-800 border-list-view-border-color dark:border-gray-700 hover:bg-list-view-table-row-hover dark:hover:bg-gray-600">
188
+ class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
189
189
  <td class="w-4 p-4">
190
190
  <div class="flex items center">
191
191
  <input
@@ -198,12 +198,7 @@
198
198
  </div>
199
199
  </td>
200
200
  <td v-for="c in columnsListed" class="px-6 py-4">
201
- <!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
202
- <component
203
- :is="listComponentsPerColumn[c.name] || ValueRenderer"
204
- :column="c"
205
- :row="row"
206
- />
201
+ <ValueRenderer :column="c" :row="row"/>
207
202
  </td>
208
203
  <td class="flex items-center px-6 py-4">
209
204
 
@@ -315,28 +310,29 @@
315
310
  </template>
316
311
 
317
312
  <script setup>
313
+ import {ref, onMounted, watch, computed} from 'vue';
314
+ import {callAdminForthApi, getIcon} from '@/utils';
315
+ import {useRoute} from 'vue-router';
316
+ import {useCoreStore} from '@/stores/core';
317
+ import {useModalStore} from '@/stores/modal';
318
318
  import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
319
- import { useCoreStore } from '@/stores/core';
320
- import { useModalStore } from '@/stores/modal';
321
- import { callAdminForthApi, getIcon } from '@/utils';
322
- import { initFlowbite } from 'flowbite';
323
- import { computed, onMounted, ref, watch } from 'vue';
324
- import { useRoute } from 'vue-router';
319
+ import {initFlowbite} from 'flowbite'
325
320
 
326
321
  import ValueRenderer from '@/components/ValueRenderer.vue';
327
- import { getCustomComponent } from '@/utils';
328
322
 
329
323
  import {
330
- IconInboxOutline,
331
- IconPlusOutline
324
+ IconChevronDoubleLeftOutline,
325
+ IconChevronDoubleRightOutline,
326
+ IconInboxFullSolid,
327
+ IconInboxOutline,
328
+ IconPlusOutline
332
329
  } from '@iconify-prerendered/vue-flowbite';
333
330
 
334
331
  import {
335
- IconBanOutline,
336
- IconEyeSolid,
337
- IconFilterOutline,
338
- IconPenSolid,
339
- IconTrashBinSolid
332
+ IconEyeSolid,
333
+ IconTrashBinSolid,
334
+ IconPenSolid,
335
+ IconFilterOutline, IconBanOutline
340
336
  } from '@iconify-prerendered/vue-flowbite';
341
337
 
342
338
  import Filters from '@/components/Filters.vue';
@@ -361,6 +357,7 @@ const totalRows = ref(0);
361
357
  const allCheckedActions = ref([]);
362
358
  const allowedActions = ref({});
363
359
 
360
+
364
361
  const DEFAULT_PAGE_SIZE = 10;
365
362
 
366
363
  const columnsListed = computed(() => coreStore.resourceColumns?.filter(c => c.showIn.includes('list')));
@@ -379,7 +376,6 @@ async function selectAll(value) {
379
376
 
380
377
  const pageSize = computed(() => coreStore.resourceById[route.params.resourceId]?.pageSize || DEFAULT_PAGE_SIZE);
381
378
  const totalPages = computed(() => Math.ceil(totalRows.value / pageSize.value));
382
- let listComponentsPerColumn = {};
383
379
  const allFromThisPageChecked = computed(() => {
384
380
  if (!rows.value) return false;
385
381
  return rows.value.every((r) => checkboxes.value.includes(r.id));
@@ -423,7 +419,6 @@ async function getList() {
423
419
  path: '/get_resource_data',
424
420
  method: 'POST',
425
421
  body: {
426
- source: 'list',
427
422
  resourceId: route.params.resourceId,
428
423
  limit: pageSize.value,
429
424
  offset: (page.value - 1) * pageSize.value,
@@ -431,14 +426,7 @@ async function getList() {
431
426
  sort: sort.value,
432
427
  }
433
428
  });
434
- listComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
435
- if (column.component?.list) {
436
- acc[column.name] = getCustomComponent(column.component.list);
437
- }
438
- return acc;
439
- }, {});
440
-
441
- fetchStatus.value.pending = false;
429
+ fetchStatus.value.pending = false;
442
430
  rows.value = data.data?.map(row => {
443
431
  row._primaryKeyValue = row[coreStore.resourceColumns.find(c => c.primaryKey).name];
444
432
  return row;
@@ -11,7 +11,7 @@
11
11
  <div id="authentication-modal" tabindex="-1" class=" overflow-y-auto overflow-x-hidden z-50 min-w-[400px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
12
12
  <div class="relative p-4 w-full max-w-md max-h-full">
13
13
  <!-- Modal content -->
14
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black" >
14
+ <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
15
15
  <!-- Modal header -->
16
16
  <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
17
17
  <h3 class="text-xl font-semibold text-gray-900 dark:text-white">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :key="`${$route?.params.resourceId}---${$route?.params.primaryKey}`">
2
+ <div>
3
3
  <RouterView/>
4
4
  </div>
5
5
  </template>
@@ -27,10 +27,10 @@
27
27
  </div>
28
28
  <div
29
29
  v-else
30
- class="relative overflow-x-auto shadow-resourse-form-shadow "
30
+ class="relative overflow-x-auto shadow-md sm:rounded-lg"
31
31
  >
32
32
  <table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
33
- <thead class="text-xs text-gray-700 uppercase bg-form-view-heading dark:bg-gray-700 dark:text-gray-400">
33
+ <thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
34
34
  <tr>
35
35
  <th scope="col" class="px-6 py-3">
36
36
  Field
@@ -42,17 +42,13 @@
42
42
  </thead>
43
43
  <tbody>
44
44
  <tr v-for="column in coreStore.resourceColumns?.filter(c => c.showIn.includes('show'))" :key="column.name"
45
- class="bg-form-view-bg odd:dark:bg-gray-900 even:dark:bg-gray-800 border-b dark:border-gray-700"
45
+ class="odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800 border-b dark:border-gray-700"
46
46
  >
47
47
  <td class="px-6 py-4 whitespace-nowrap">
48
48
  {{ column.label }}
49
49
  </td>
50
50
  <td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap">
51
- <component
52
- :is="showComponentsPerColumn[column.name] || ValueRenderer"
53
- :column="column"
54
- :row="coreStore.record"
55
- />
51
+ <ValueRenderer :column="column" :row="coreStore.record" />
56
52
  </td>
57
53
  </tr>
58
54
 
@@ -67,19 +63,18 @@
67
63
 
68
64
  <script setup>
69
65
 
66
+ import { ref, computed, onMounted } from 'vue';
67
+ import { useRoute } from 'vue-router';
68
+ import { callAdminForthApi } from '@/utils';
70
69
  import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
71
- import ValueRenderer from '@/components/ValueRenderer.vue';
72
- import { useCoreStore } from '@/stores/core';
73
- import { getCustomComponent } from '@/utils';
74
70
  import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
75
- import { onMounted, ref } from 'vue';
76
- import { useRoute } from 'vue-router';
71
+ import { useCoreStore } from '@/stores/core';
72
+ import ValueRenderer from '@/components/ValueRenderer.vue';
77
73
 
78
74
 
79
75
  const item = ref(null);
80
76
  const route = useRoute();
81
77
  const loading = ref(false);
82
- let showComponentsPerColumn = {};
83
78
 
84
79
  const coreStore = useCoreStore();
85
80
 
@@ -92,12 +87,6 @@ onMounted(async () => {
92
87
  resourceId: route.params.resourceId,
93
88
  primaryKey: route.params.primaryKey,
94
89
  });
95
- showComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
96
- if (column.component?.show) {
97
- acc[column.name] = getCustomComponent(column.component.show);
98
- }
99
- return acc;
100
- }, {});
101
90
  loading.value = false;
102
91
  });
103
92
 
@@ -1,12 +1,9 @@
1
1
  /** @type {import('tailwindcss').Config} */
2
2
  export default {
3
- content: ["./src/**/*.{vue, js}","./src/*.{vue, js}", "./index.html", "./node_modules/flowbite/**/*.js"],
3
+ content: ["./src/**/*.{vue, js}", "./node_modules/flowbite/**/*.js"],
4
4
  theme: {
5
- extend: {
6
- /* IMPORTANT:ADMINFORTH TAILWIND STYLES */
7
- }
5
+ extend: {},
8
6
  },
9
-
10
7
  darkMode: 'class',
11
8
  plugins: [
12
9
  require('flowbite/plugin'),
@@ -61,6 +61,15 @@ export var AllowedActionsEnum;
61
61
  AllowedActionsEnum["delete"] = "delete";
62
62
  AllowedActionsEnum["filter"] = "filter";
63
63
  })(AllowedActionsEnum || (AllowedActionsEnum = {}));
64
+ export var ActionCheckSource;
65
+ (function (ActionCheckSource) {
66
+ ActionCheckSource["DisplayButtons"] = "displayButtons";
67
+ ActionCheckSource["ListRequest"] = "listRequest";
68
+ ActionCheckSource["ShowRequest"] = "showRequest";
69
+ ActionCheckSource["EditRequest"] = "editRequest";
70
+ ActionCheckSource["CreateRequest"] = "createRequest";
71
+ ActionCheckSource["DeleteRequest"] = "deleteRequest";
72
+ })(ActionCheckSource || (ActionCheckSource = {}));
64
73
  export var AdminForthDataTypes;
65
74
  (function (AdminForthDataTypes) {
66
75
  AdminForthDataTypes["STRING"] = "string";
package/index.ts CHANGED
@@ -16,7 +16,8 @@ import { AdminForthConfig, AdminForthClass, AdminForthComponentDeclaration, Admi
16
16
  BeforeDataSourceRequestFunction,
17
17
  AfterDataSourceResponseFunction, AllowedActionValue, AdminUser,
18
18
  AdminForthResource,
19
- AllowedActionsEnum
19
+ AllowedActionsEnum,
20
+ ActionCheckSource
20
21
  } from './types/AdminForthConfig.js';
21
22
  import path from 'path';
22
23
  import AdminForthPlugin from './plugins/base.js';
@@ -696,10 +697,6 @@ class AdminForth implements AdminForthClass {
696
697
  }
697
698
  newMenu.push(newMenuItem)
698
699
  }
699
-
700
-
701
-
702
-
703
700
 
704
701
  return {
705
702
  user: userData,
@@ -724,13 +721,13 @@ class AdminForth implements AdminForthClass {
724
721
  },
725
722
  });
726
723
 
727
- async function interpretResource(adminUser: AdminUser, resource: AdminForthResource, meta: any) {
724
+ async function interpretResource(adminUser: AdminUser, resource: AdminForthResource, meta: any, source: ActionCheckSource) {
728
725
  await Promise.all(
729
726
  Object.entries(resource.options?.allowedActions || {}).map(
730
727
  async ([key, value]: [string, AllowedActionValue]) => {
731
728
  // if callable then call
732
729
  if (typeof value === 'function') {
733
- resource.options.allowedActions[key] = await value( adminUser, resource, meta );
730
+ resource.options.allowedActions[key] = await value({ adminUser, resource, meta, source });
734
731
  }
735
732
  })
736
733
  );
@@ -761,7 +758,7 @@ class AdminForth implements AdminForthClass {
761
758
  return { error: `Resource ${resourceId} not found` };
762
759
  }
763
760
 
764
- await interpretResource(adminUser, resource, {});
761
+ await interpretResource(adminUser, resource, {}, ActionCheckSource.DisplayButtons);
765
762
 
766
763
  // exclude "plugins" key
767
764
  return { resource: { ...resource, plugins: undefined } };
@@ -786,7 +783,7 @@ class AdminForth implements AdminForthClass {
786
783
  return { error: `Resource ${resourceId} not found` };
787
784
  }
788
785
 
789
- await interpretResource(adminUser, resource, { requestBody: body });
786
+ await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
790
787
 
791
788
  const { allowed, error } = checkAccess(source as AllowedActionsEnum, resource);
792
789
  console.log('allowed', allowed, error);
@@ -1011,7 +1008,7 @@ class AdminForth implements AdminForthClass {
1011
1008
  if (!resource) {
1012
1009
  return { error: `Resource '${body['resourceId']}' not found` };
1013
1010
  }
1014
- await interpretResource(adminUser, resource, { requestBody: body });
1011
+ await interpretResource(adminUser, resource, { requestBody: body}, ActionCheckSource.CreateRequest);
1015
1012
 
1016
1013
  const { allowed, error } = checkAccess(AllowedActionsEnum.create, resource);
1017
1014
  if (!allowed) {
@@ -1092,13 +1089,7 @@ class AdminForth implements AdminForthClass {
1092
1089
  if (!resource) {
1093
1090
  return { error: `Resource '${body['resourceId']}' not found` };
1094
1091
  }
1095
- await interpretResource(adminUser, resource, { requestBody: body });
1096
-
1097
- const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
1098
- if (!allowed) {
1099
- return { error };
1100
- }
1101
-
1092
+
1102
1093
  const recordId = body['recordId'];
1103
1094
  const connector = this.connectors[resource.dataSource];
1104
1095
  const oldRecord = await connector.getRecordByPrimaryKey(resource, recordId)
@@ -1108,6 +1099,13 @@ class AdminForth implements AdminForthClass {
1108
1099
  }
1109
1100
  const record = body['record'];
1110
1101
 
1102
+ await interpretResource(adminUser, resource, { requestBody: body, record, oldRecord}, ActionCheckSource.EditRequest);
1103
+
1104
+ const { allowed, error } = checkAccess(AllowedActionsEnum.edit, resource);
1105
+ if (!allowed) {
1106
+ return { error };
1107
+ }
1108
+
1111
1109
  // execute hook if needed
1112
1110
  for (const hook of listify(resource.hooks?.edit?.beforeSave as BeforeSaveFunction[])) {
1113
1111
  const resp = await hook({ resource, record, adminUser });
@@ -1172,7 +1170,7 @@ class AdminForth implements AdminForthClass {
1172
1170
  return { error: `Resource '${resource.resourceId}' does not allow delete action` };
1173
1171
  }
1174
1172
 
1175
- await interpretResource(adminUser, resource, { requestBody: body });
1173
+ await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DeleteRequest);
1176
1174
 
1177
1175
  const { allowed, error } = checkAccess(AllowedActionsEnum.delete, resource);
1178
1176
  if (!allowed) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.1.23",
3
+ "version": "1.1.25",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,29 @@
1
+ import {
2
+ AdminForthResource, AdminForthClass, BeforeDataSourceRequestFunction,
3
+ AllowedActionsEnum,
4
+ BeforeSaveFunction
5
+ } from "../../types/AdminForthConfig.js";
6
+ import AdminForthPlugin from "../base.js";
7
+ import { PluginOptions } from "./types.js";
8
+
9
+
10
+
11
+ export default class AuditLogPlugin extends AdminForthPlugin {
12
+
13
+ options: PluginOptions;
14
+ adminforth: AdminForthClass;
15
+
16
+ constructor(options: PluginOptions) {
17
+ super(options, import.meta.url);
18
+ this.options = options;
19
+ }
20
+
21
+ static defaultError = 'Sorry, you do not have access to this resource.'
22
+
23
+
24
+ modifyResourceConfig(adminforth: AdminForthClass, resourceConfig: AdminForthResource) {
25
+ super.modifyResourceConfig(adminforth, resourceConfig);
26
+ this.adminforth = adminforth;
27
+
28
+ }
29
+ }
@@ -0,0 +1,4 @@
1
+
2
+
3
+ export type PluginOptions = {
4
+ }
@@ -838,7 +838,29 @@ export enum AllowedActionsEnum {
838
838
  * or function which returns Boolean or string with error message
839
839
  *
840
840
  */
841
- export type AllowedActionValue = boolean | ((adminUser: AdminUser, resource: AdminForthResource, meta: any) => Promise<boolean | string>);
841
+ export type AllowedActionValue = boolean | (({adminUser, resource, meta, source}: {
842
+ adminUser: AdminUser,
843
+ resource: AdminForthResource,
844
+
845
+ /**
846
+ * Meta object which will pass request information just in case
847
+ */
848
+ meta: any,
849
+
850
+ /**
851
+ * Source of the check
852
+ */
853
+ source: ActionCheckSource,
854
+ }) => Promise<boolean | string>);
855
+
856
+ export enum ActionCheckSource {
857
+ DisplayButtons = 'displayButtons',
858
+ ListRequest = 'listRequest',
859
+ ShowRequest = 'showRequest',
860
+ EditRequest = 'editRequest',
861
+ CreateRequest = 'createRequest',
862
+ DeleteRequest = 'deleteRequest',
863
+ }
842
864
 
843
865
  /**
844
866
  * Object which describes allowed actions for user.