adminforth 1.1.62 → 1.1.64
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/index.js +3 -0
- package/dist/plugins/AccessControl/index.js +66 -0
- package/dist/plugins/AccessControl/types.js +1 -0
- package/dist/spa/index.html +2 -2
- package/dist/spa/package-lock.json +4 -17
- package/dist/spa/package.json +1 -2
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/src/App.vue +45 -125
- package/dist/spa/src/assets/logo.svg +1 -19
- package/dist/spa/src/components/AcceptModal.vue +9 -2
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +3 -16
- package/dist/spa/src/components/CustomDateRangePicker.vue +2 -11
- package/dist/spa/src/components/Dropdown.vue +1 -6
- package/dist/spa/src/components/Filters.vue +19 -40
- package/dist/spa/src/components/ResourceForm.vue +24 -26
- package/dist/spa/src/components/ValueRenderer.vue +8 -14
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/router/index.ts +20 -30
- package/dist/spa/src/stores/core.ts +31 -48
- package/dist/spa/src/stores/modal.ts +3 -13
- package/dist/spa/src/utils.ts +7 -62
- package/dist/spa/src/views/CreateView.vue +15 -67
- package/dist/spa/src/views/EditView.vue +11 -45
- package/dist/spa/src/views/ListView.vue +366 -82
- package/dist/spa/src/views/LoginView.vue +4 -16
- package/dist/spa/src/views/ShowView.vue +21 -105
- package/dist/spa/tailwind.config.js +1 -1
- package/dist/spa/vite.config.ts +0 -6
- package/dist/types.js +30 -0
- package/index.ts +3 -0
- package/package.json +1 -1
- package/dist/spa/src/components/ResourceListTable.vue +0 -419
- package/dist/spa/src/components/Toast.vue +0 -66
- package/dist/spa/src/composables/useFrontendApi.ts +0 -26
- package/dist/spa/src/composables/useStores.ts +0 -113
- package/dist/spa/src/spa_types/core.ts +0 -51
- package/dist/spa/src/stores/filters.ts +0 -22
- package/dist/spa/src/stores/toast.ts +0 -15
- package/dist/spa/src/stores/user.ts +0 -54
- /package/dist/spa/{public/assets → spa/public}/favicon.png +0 -0
package/dist/spa/src/utils.ts
CHANGED
|
@@ -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
|
-
|
|
21
|
-
router.push({
|
|
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(
|
|
41
|
-
const name =
|
|
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
|
|
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
|
|
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="
|
|
49
|
-
:
|
|
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
|
|
48
|
+
import { callAdminForthApi, getCustomComponent } from '@/utils';
|
|
77
49
|
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
|
|
78
|
-
import { onMounted, ref
|
|
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
|
-
|
|
115
|
-
await coreStore.fetchResourceFull({
|
|
74
|
+
await coreStore.fetchColumns({
|
|
116
75
|
resourceId: route.params.resourceId
|
|
117
76
|
});
|
|
118
|
-
createComponentsPerColumn = coreStore.
|
|
119
|
-
if (column.
|
|
120
|
-
acc[column.name] = getCustomComponent(column.
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|
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
|
|
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
|
-
:
|
|
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
|
|
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.
|
|
70
|
+
if (!coreStore.resourceColumns) {
|
|
100
71
|
return {};
|
|
101
72
|
}
|
|
102
|
-
coreStore.
|
|
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.
|
|
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.
|
|
124
|
-
if (column.
|
|
125
|
-
acc[column.name] = getCustomComponent(column.
|
|
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
|
-
|
|
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
|
}
|