adminforth 1.1.59 → 1.1.60

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 (67) hide show
  1. package/dist/index.js +68 -63
  2. package/dist/modules/styleGenerator.js +22 -18
  3. package/dist/modules/styles.js +44 -36
  4. package/dist/modules/utils.js +74 -0
  5. package/dist/plugins/AccessControl/index.js +66 -0
  6. package/dist/plugins/AccessControl/types.js +1 -0
  7. package/dist/plugins/AuditLogPlugin/custom/AuditLogView.vue +20 -0
  8. package/dist/plugins/AuditLogPlugin/index.js +83 -0
  9. package/dist/plugins/AuditLogPlugin/types.js +1 -0
  10. package/dist/spa/index.html +2 -2
  11. package/dist/spa/package-lock.json +4 -17
  12. package/dist/spa/package.json +1 -2
  13. package/dist/spa/public/favicon.ico +0 -0
  14. package/dist/spa/spa/package-lock.json +111 -0
  15. package/dist/spa/spa/package.json +1 -0
  16. package/dist/spa/spa/public/favicon.ico +0 -0
  17. package/dist/spa/spa/src/App.vue +4 -4
  18. package/dist/spa/spa/src/components/MenuLink.vue +1 -1
  19. package/dist/spa/spa/src/components/ResourceForm.vue +1 -1
  20. package/dist/spa/src/App.vue +45 -125
  21. package/dist/spa/src/assets/logo.svg +1 -19
  22. package/dist/spa/src/components/AcceptModal.vue +9 -2
  23. package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
  24. package/dist/spa/src/components/CustomDatePicker.vue +3 -16
  25. package/dist/spa/src/components/CustomDateRangePicker.vue +2 -11
  26. package/dist/spa/src/components/Dropdown.vue +1 -6
  27. package/dist/spa/src/components/Filters.vue +19 -40
  28. package/dist/spa/src/components/ResourceForm.vue +24 -26
  29. package/dist/spa/src/components/ValueRenderer.vue +8 -14
  30. package/dist/spa/src/main.ts +1 -1
  31. package/dist/spa/src/router/index.ts +20 -30
  32. package/dist/spa/src/stores/core.ts +31 -48
  33. package/dist/spa/src/stores/modal.ts +3 -13
  34. package/dist/spa/src/utils.ts +7 -62
  35. package/dist/spa/src/views/CreateView.vue +15 -67
  36. package/dist/spa/src/views/EditView.vue +11 -45
  37. package/dist/spa/src/views/ListView.vue +366 -82
  38. package/dist/spa/src/views/LoginView.vue +4 -16
  39. package/dist/spa/src/views/ShowView.vue +21 -105
  40. package/dist/spa/tailwind.config.js +1 -1
  41. package/dist/spa/vite.config.ts +0 -6
  42. package/dist/types.js +30 -0
  43. package/index.ts +62 -61
  44. package/modules/styleGenerator.ts +25 -18
  45. package/modules/styles.ts +46 -36
  46. package/modules/utils.ts +94 -1
  47. package/package.json +2 -1
  48. package/plugins/AuditLogPlugin/custom/AuditLogView.vue +20 -0
  49. package/plugins/AuditLogPlugin/index.ts +99 -0
  50. package/plugins/AuditLogPlugin/types.ts +40 -0
  51. package/spa/package-lock.json +111 -0
  52. package/spa/package.json +1 -0
  53. package/spa/src/App.vue +4 -4
  54. package/spa/src/components/MenuLink.vue +1 -1
  55. package/spa/src/components/ResourceForm.vue +1 -1
  56. package/types/AdminForthConfig.ts +6 -1
  57. package/dist/spa/src/components/ResourceListTable.vue +0 -419
  58. package/dist/spa/src/components/Toast.vue +0 -66
  59. package/dist/spa/src/composables/useFrontendApi.ts +0 -26
  60. package/dist/spa/src/composables/useStores.ts +0 -113
  61. package/dist/spa/src/spa_types/core.ts +0 -51
  62. package/dist/spa/src/stores/filters.ts +0 -22
  63. package/dist/spa/src/stores/toast.ts +0 -15
  64. package/dist/spa/src/stores/user.ts +0 -54
  65. package/plugins/AuditLog/index.ts +0 -29
  66. package/plugins/AuditLog/types.ts +0 -4
  67. /package/dist/spa/{public/assets → spa/public}/favicon.png +0 -0
@@ -1,12 +1,6 @@
1
1
  import { ref } from 'vue'
2
2
  import { defineStore } from 'pinia'
3
-
4
- type ModalContentType = {
5
- title?: string;
6
- content?: string;
7
- acceptText?: string;
8
- cancelText?: string;
9
- }
3
+ import { callAdminForthApi } from '@/utils';
10
4
 
11
5
 
12
6
  export const useModalStore = defineStore('modal', () => {
@@ -18,17 +12,13 @@ export const useModalStore = defineStore('modal', () => {
18
12
  });
19
13
  const isOpened = ref(false);
20
14
  const onAcceptFunction: any = ref(()=>{});
21
- const onCancelFunction: any = ref(()=>{});
22
15
  function togleModal() {
23
16
  isOpened.value = !isOpened.value;
24
17
  }
25
18
  function setOnAcceptFunction(func: Function) {
26
19
  onAcceptFunction.value = func;
27
20
  }
28
- function setOnCancelFunction(func: Function) {
29
- onCancelFunction.value = func;
30
- }
31
- function setModalContent(content: ModalContentType) {
21
+ function setModalContent(content: string) {
32
22
  modalContent.value = content;
33
23
  }
34
24
  function resetmodalState() {
@@ -43,6 +33,6 @@ export const useModalStore = defineStore('modal', () => {
43
33
 
44
34
  }
45
35
 
46
- return {isOpened, setModalContent,onCancelFunction, togleModal,modalContent, setOnAcceptFunction, onAcceptFunction,resetmodalState,setOnCancelFunction}
36
+ return {isOpened, setModalContent, togleModal,modalContent, setOnAcceptFunction, onAcceptFunction,resetmodalState}
47
37
 
48
38
  })
@@ -1,10 +1,6 @@
1
1
  import { onMounted, ref, resolveComponent } from 'vue';
2
- import type { CoreConfig } from './spa_types/core';
3
2
 
4
3
  import router from "./router";
5
- import { useRouter } from 'vue-router';
6
- import { useCoreStore } from './stores/core';
7
- import { useUserStore } from './stores/user';
8
4
 
9
5
  export async function callApi({path, method, body=undefined} ) {
10
6
  const options = {
@@ -17,18 +13,14 @@ export async function callApi({path, method, body=undefined} ) {
17
13
  const fullPath = `${import.meta.env.VITE_ADMINFORTH_PUBLIC_PATH || ''}${path}`;
18
14
  const r = await fetch(fullPath, options);
19
15
  if (r.status == 401) {
20
- useUserStore().unauthorize();
21
- router.push({ name: 'login' });
16
+ console.log('router', router);
17
+ router.push({name: 'login'});
22
18
  return null;
23
- }
19
+ }
24
20
  return await r.json();
25
21
  }
26
22
 
27
- export async function callAdminForthApi({ path, method, body=undefined }: {
28
- path: string,
29
- method: 'GET' | 'POST' | 'PUT' | 'DELETE',
30
- body?: any
31
- }) {
23
+ export async function callAdminForthApi({ path, method, body=undefined }) {
32
24
  try {
33
25
  return callApi({path: `/adminapi/v1${path}`, method, body} );
34
26
  } catch (e) {
@@ -37,8 +29,8 @@ export async function callAdminForthApi({ path, method, body=undefined }: {
37
29
  }
38
30
  }
39
31
 
40
- export function getCustomComponent({ file, meta }: { file: string, meta: any }) {
41
- const name = file.replace(/@/g, '').replace(/\./g, '').replace(/\//g, '');
32
+ export function getCustomComponent(filePath: string) {
33
+ const name = filePath.replace(/@/g, '').replace(/\./g, '').replace(/\//g, '');
42
34
  console.log('resolving name', name);
43
35
  return resolveComponent(name);
44
36
  }
@@ -51,51 +43,4 @@ export function getIcon(icon: string) {
51
43
  const [iconSet, iconName] = icon.split(':');
52
44
  const compName = 'Icon' + iconName.split('-').map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join('');
53
45
  return resolveComponent(compName);
54
- }
55
-
56
- export const loadFile = (file: string) => {
57
- if (file.startsWith('http')) {
58
- return file;
59
- }
60
- let path;
61
- let baseUrl = '';
62
- if (file.startsWith('@/')) {
63
- path = file.replace('@/', '');
64
- baseUrl = new URL(`./${path}`, import.meta.url).href;
65
- } else if (file.startsWith('@@/')) {
66
- path = file.replace('@@/', '');
67
- baseUrl = new URL(`./custom/${path}`, import.meta.url).href;
68
- } else {
69
- baseUrl = new URL(`./${file}`, import.meta.url).href;
70
- }
71
- return baseUrl;
72
- }
73
-
74
- export function checkEmptyValues(value: any, viewType:'show' | 'list' ) {
75
- const config: CoreConfig | {} = useCoreStore().config;
76
- let emptyFieldPlaceholder = '';
77
- if (config.emptyFieldPlaceholder) {
78
- if(typeof config.emptyFieldPlaceholder === 'string') {
79
- emptyFieldPlaceholder = config.emptyFieldPlaceholder;
80
- } else {
81
- emptyFieldPlaceholder = config.emptyFieldPlaceholder?.[viewType] || '';
82
- }
83
- if (value === null || value === undefined || value === '') {
84
- return emptyFieldPlaceholder;
85
- }
86
- }
87
- return value;
88
- }
89
-
90
- export function checkAcessByAllowedActions(allowedActions:any, action:any ) {
91
- if (!allowedActions) {
92
- console.warn('allowedActions not set');
93
- return;
94
- }
95
- if(allowedActions[action] === false) {
96
- console.warn(`Action ${action} is not allowed`);
97
- router.back();
98
- }
99
- }
100
-
101
-
46
+ }
@@ -1,25 +1,16 @@
1
1
  <template>
2
2
  <div class="relative">
3
3
 
4
- <component
5
- v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.beforeBreadcrumbs || []"
6
- :is="getCustomComponent(c)"
7
- :meta="c.meta"
8
- :record="coreStore.record"
9
- :resource="coreStore.resource"
10
- :adminUser="coreStore.adminUser"
11
- />
12
-
13
4
  <BreadcrumbsWithButtons>
14
5
  <!-- save and cancle -->
15
6
  <button @click="$router.back()"
16
- class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
7
+ class="flex items-center py-1 px-3 me-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
17
8
  >
18
9
  Cancel
19
10
  </button>
20
11
 
21
12
  <button @click="saveRecord"
22
- class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
13
+ class="flex items-center py-1 px-3 mb-2 text-sm font-medium text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
23
14
  :disabled="saving || (validating && !isValid)"
24
15
  >
25
16
  <svg v-if="saving" x
@@ -31,22 +22,12 @@
31
22
 
32
23
  </BreadcrumbsWithButtons>
33
24
 
34
- <component
35
- v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.afterBreadcrumbs || []"
36
- :is="getCustomComponent(c)"
37
- :meta="c.meta"
38
- :record="coreStore.record"
39
- :resource="coreStore.resource"
40
- :adminUser="coreStore.adminUser"
41
- />
42
-
43
25
  <SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
44
-
45
26
 
46
27
  <ResourceForm
47
28
  v-else
48
- :record="record"
49
- :resource="coreStore.resource"
29
+ :record="{}"
30
+ :resourceColumns="coreStore.resourceColumns"
50
31
  @update:record="onUpdateRecord"
51
32
  @update:isValid="isValid = $event"
52
33
  :validating="validating"
@@ -54,15 +35,6 @@
54
35
  >
55
36
  </ResourceForm>
56
37
 
57
- <component
58
- v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.bottom || []"
59
- :is="getCustomComponent(c)"
60
- :meta="c.meta"
61
- :record="coreStore.record"
62
- :resource="coreStore.resource"
63
- :adminUser="coreStore.adminUser"
64
- />
65
-
66
38
  </div>
67
39
  </template>
68
40
 
@@ -73,13 +45,10 @@ import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
73
45
  import ResourceForm from '@/components/ResourceForm.vue';
74
46
  import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
75
47
  import { useCoreStore } from '@/stores/core';
76
- import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions } from '@/utils';
48
+ import { callAdminForthApi, getCustomComponent } from '@/utils';
77
49
  import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
78
- import { onMounted, ref, watch } from 'vue';
50
+ import { onMounted, ref } from 'vue';
79
51
  import { useRoute, useRouter } from 'vue-router';
80
- import { computed } from 'vue';
81
- import { showErrorTost } from '@/composables/useFrontendApi';
82
-
83
52
 
84
53
  const isValid = ref(false);
85
54
  const validating = ref(false);
@@ -95,15 +64,6 @@ let createComponentsPerColumn = {};
95
64
 
96
65
  const coreStore = useCoreStore();
97
66
 
98
- const initalValues = computed(() => {
99
- if (!route.query.values) {
100
- return {};
101
- }
102
- return JSON.parse(decodeURIComponent(route.query.values));
103
- });
104
-
105
-
106
-
107
67
  async function onUpdateRecord(newRecord) {
108
68
  console.log('newRecord', newRecord);
109
69
  record.value = newRecord;
@@ -111,18 +71,16 @@ async function onUpdateRecord(newRecord) {
111
71
 
112
72
  onMounted(async () => {
113
73
  loading.value = true;
114
- record.value = initalValues.value;
115
- await coreStore.fetchResourceFull({
74
+ await coreStore.fetchColumns({
116
75
  resourceId: route.params.resourceId
117
76
  });
118
- createComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
119
- if (column.components?.create) {
120
- acc[column.name] = getCustomComponent(column.components.create);
77
+ createComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
78
+ if (column.component?.create) {
79
+ acc[column.name] = getCustomComponent(column.component.create);
121
80
  }
122
81
  return acc;
123
82
  }, {});
124
83
  loading.value = false;
125
- checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'create');
126
84
  });
127
85
 
128
86
  async function saveRecord() {
@@ -141,22 +99,12 @@ async function saveRecord() {
141
99
  record: record.value,
142
100
  },
143
101
  });
144
- if (response.error) {
145
- showErrorTost(response.error);
146
-
147
- }
148
102
  saving.value = false;
149
- if (route.query.returnTo) {
150
- router.push(route.query.returnTo);
151
- } else {
152
- router.push({
153
- name: 'resource-show',
154
- params: {
155
- resourceId: route.params.resourceId,
156
- primaryKey: response.newRecordId
157
- }
158
- });
159
- }
103
+ router.push({ name: 'resource-show', params: {
104
+ resourceId: route.params.resourceId,
105
+ primaryKey: response.newRecordId
106
+
107
+ } });
160
108
  }
161
109
 
162
110
 
@@ -1,24 +1,16 @@
1
1
  <template>
2
2
  <div class="relative">
3
- <component
4
- v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.beforeBreadcrumbs || []"
5
- :is="getCustomComponent(c)"
6
- :meta="c.meta"
7
- :record="editableRecord"
8
- :resource="coreStore.resource"
9
- :adminUser="coreStore.adminUser"
10
- />
11
3
 
12
4
  <BreadcrumbsWithButtons>
13
5
  <!-- save and cancle -->
14
6
  <button @click="$router.back()"
15
- class="flex items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 rounded-default focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
7
+ class="flex items-center py-1 px-3 me-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
16
8
  >
17
9
  Cancel
18
10
  </button>
19
11
 
20
12
  <button @click="saveRecord"
21
- class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
13
+ class="flex items-center py-1 px-3 mb-2 text-sm font-medium text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
22
14
  :disabled="saving || (validating && !isValid)"
23
15
  >
24
16
  <IconFloppyDiskSolid class="w-4 h-4" />
@@ -27,38 +19,18 @@
27
19
 
28
20
  </BreadcrumbsWithButtons>
29
21
 
30
- <component
31
- v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.afterBreadcrumbs || []"
32
- :is="getCustomComponent(c)"
33
- :meta="c.meta"
34
- :record="coreStore.record"
35
- :resource="coreStore.resource"
36
- :adminUser="coreStore.adminUser"
37
- />
38
-
39
22
  <SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
40
23
 
41
24
  <ResourceForm
42
25
  v-else
43
26
  :record="editableRecord"
44
- :resource="coreStore.resource"
45
- :adminUser="coreStore.adminUser"
27
+ :resourceColumns="coreStore.resourceColumns"
46
28
  @update:record="onUpdateRecord"
47
29
  @update:isValid="isValid = $event"
48
30
  :validating="validating"
49
31
  :customComponentsPerColumn="editComponentsPerColumn"
50
32
  >
51
33
  </ResourceForm>
52
-
53
- <component
54
- v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.bottom || []"
55
- :is="getCustomComponent(c)"
56
- :meta="c.meta"
57
- :record="coreStore.record"
58
- :resource="coreStore.resource"
59
- :adminUser="coreStore.adminUser"
60
- />
61
-
62
34
  </div>
63
35
  </template>
64
36
 
@@ -69,11 +41,10 @@ import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
69
41
  import ResourceForm from '@/components/ResourceForm.vue';
70
42
  import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
71
43
  import { useCoreStore } from '@/stores/core';
72
- import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions } from '@/utils';
44
+ import { callAdminForthApi, getCustomComponent } from '@/utils';
73
45
  import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
74
46
  import { computed, onMounted, ref } from 'vue';
75
47
  import { useRoute, useRouter } from 'vue-router';
76
- import { showErrorTost } from '@/composables/useFrontendApi';
77
48
 
78
49
  const coreStore = useCoreStore();
79
50
 
@@ -96,10 +67,10 @@ async function onUpdateRecord(newRecord) {
96
67
 
97
68
  const editableRecord = computed(() => {
98
69
  const newRecord = { ...coreStore.record };
99
- if (!coreStore.resource) {
70
+ if (!coreStore.resourceColumns) {
100
71
  return {};
101
72
  }
102
- coreStore.resource.columns.forEach(column => {
73
+ coreStore.resourceColumns.forEach(column => {
103
74
  if (column.foreignResource) {
104
75
  newRecord[column.name] = newRecord[column.name]?.pk
105
76
  }
@@ -108,21 +79,19 @@ const editableRecord = computed(() => {
108
79
  })
109
80
 
110
81
  onMounted(async () => {
111
-
112
82
  loading.value = true;
113
83
 
114
- await coreStore.fetchResourceFull({
84
+ await coreStore.fetchColumns({
115
85
  resourceId: route.params.resourceId
116
86
  });
117
87
  await coreStore.fetchRecord({
118
88
  resourceId: route.params.resourceId,
119
89
  primaryKey: route.params.primaryKey,
120
90
  });
121
- checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'edit');
122
91
 
123
- editComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
124
- if (column.components?.edit) {
125
- acc[column.name] = getCustomComponent(column.components.edit);
92
+ editComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
93
+ if (column.component?.edit) {
94
+ acc[column.name] = getCustomComponent(column.component.edit);
126
95
  }
127
96
  return acc;
128
97
  }, {});
@@ -146,7 +115,7 @@ async function saveRecord() {
146
115
  }
147
116
  }
148
117
 
149
- const resp = await callAdminForthApi({
118
+ await callAdminForthApi({
150
119
  method: 'POST',
151
120
  path: `/update_record`,
152
121
  body: {
@@ -155,9 +124,6 @@ async function saveRecord() {
155
124
  record: updates,
156
125
  },
157
126
  });
158
- if (resp.error) {
159
- showErrorTost(resp.error);
160
- }
161
127
  saving.value = false;
162
128
  router.push({ name: 'resource-show', params: { resourceId: route.params.resourceId, primaryKey: coreStore.record[coreStore.primaryKey] } });
163
129
  }