adminforth 1.2.39 → 1.2.41
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/dataConnectors/mongo.ts +8 -5
- package/dist/dataConnectors/mongo.js +5 -1
- package/dist/spa/index.html +4 -4
- package/dist/spa/package-lock.json +5 -206
- package/dist/spa/package.json +2 -8
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/src/App.vue +72 -171
- package/dist/spa/src/assets/logo.svg +1 -19
- package/dist/spa/src/components/AcceptModal.vue +10 -3
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +6 -19
- package/dist/spa/src/components/CustomDateRangePicker.vue +5 -14
- package/dist/spa/src/components/Dropdown.vue +5 -19
- package/dist/spa/src/components/Filters.vue +37 -91
- package/dist/spa/src/components/MenuLink.vue +2 -2
- package/dist/spa/src/components/ResourceForm.vue +103 -163
- package/dist/spa/src/components/ValueRenderer.vue +6 -22
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/router/index.ts +19 -30
- package/dist/spa/src/stores/core.ts +59 -65
- package/dist/spa/src/stores/modal.ts +3 -13
- package/dist/spa/src/utils.ts +8 -65
- package/dist/spa/src/views/CreateView.vue +16 -76
- package/dist/spa/src/views/EditView.vue +14 -76
- package/dist/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/src/views/ListView.vue +360 -88
- package/dist/spa/src/views/LoginView.vue +5 -17
- package/dist/spa/src/views/ResourceParent.vue +1 -1
- package/dist/spa/src/views/ShowView.vue +19 -114
- package/dist/spa/tailwind.config.js +2 -5
- package/dist/spa/vite.config.ts +0 -6
- package/dist/types.js +30 -0
- package/package.json +1 -1
- package/dist/spa/public/assets/favicon.png +0 -0
- package/dist/spa/src/components/CustomRangePicker.vue +0 -148
- 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
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
|
+
import HomeView from '../views/HomeView.vue'
|
|
2
3
|
import ResourceParent from '@/views/ResourceParent.vue'
|
|
3
|
-
import
|
|
4
|
-
|
|
4
|
+
import ListView from '@/views/ListView.vue'
|
|
5
|
+
import ShowView from '@/views/ShowView.vue'
|
|
6
|
+
import EditView from '@/views/EditView.vue'
|
|
7
|
+
import CreateView from '@/views/CreateView.vue'
|
|
5
8
|
|
|
6
9
|
const router = createRouter({
|
|
7
10
|
history: createWebHistory(import.meta.env.BASE_URL),
|
|
8
11
|
routes: [
|
|
12
|
+
{
|
|
13
|
+
path: '/',
|
|
14
|
+
name: 'home',
|
|
15
|
+
component: HomeView
|
|
16
|
+
},
|
|
9
17
|
{
|
|
10
18
|
path: '/login',
|
|
11
19
|
name: 'login',
|
|
12
|
-
component: () => import('@/views/LoginView.vue')
|
|
13
|
-
meta: { title: 'login' },
|
|
14
|
-
beforeEnter: async (to, from, next) => {
|
|
15
|
-
const userStore = useUserStore()
|
|
16
|
-
if(localStorage.getItem('isAuthorized') === 'true'){
|
|
17
|
-
next({name: 'home'})
|
|
18
|
-
} else {
|
|
19
|
-
next()
|
|
20
|
-
}
|
|
21
|
-
}
|
|
20
|
+
component: () => import('@/views/LoginView.vue')
|
|
22
21
|
},
|
|
23
22
|
{
|
|
24
23
|
path: '/resource/:resourceId',
|
|
@@ -27,29 +26,23 @@ const router = createRouter({
|
|
|
27
26
|
children: [
|
|
28
27
|
{
|
|
29
28
|
path: '',
|
|
30
|
-
component:
|
|
31
|
-
name: 'resource-list'
|
|
32
|
-
meta: { title: 'list',type: 'list' }
|
|
29
|
+
component: ListView,
|
|
30
|
+
name: 'resource-list'
|
|
33
31
|
},
|
|
34
32
|
{
|
|
35
33
|
path: 'show/:primaryKey',
|
|
36
|
-
component:
|
|
37
|
-
name: 'resource-show'
|
|
38
|
-
meta: { title: 'show', type: 'show'}
|
|
39
|
-
|
|
34
|
+
component: ShowView,
|
|
35
|
+
name: 'resource-show'
|
|
40
36
|
},
|
|
41
37
|
{
|
|
42
38
|
path: 'edit/:primaryKey',
|
|
43
|
-
component:
|
|
44
|
-
name: 'resource-edit'
|
|
45
|
-
meta: { title: 'edit', type: 'edit'}
|
|
39
|
+
component: EditView,
|
|
40
|
+
name: 'resource-edit'
|
|
46
41
|
},
|
|
47
42
|
{
|
|
48
43
|
path: 'create',
|
|
49
|
-
component:
|
|
50
|
-
name: 'resource-create'
|
|
51
|
-
meta: { title: 'create', type: 'create'}
|
|
52
|
-
|
|
44
|
+
component: CreateView,
|
|
45
|
+
name: 'resource-create'
|
|
53
46
|
},
|
|
54
47
|
]
|
|
55
48
|
},
|
|
@@ -57,8 +50,4 @@ const router = createRouter({
|
|
|
57
50
|
]
|
|
58
51
|
})
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
53
|
export default router
|
|
@@ -1,105 +1,96 @@
|
|
|
1
1
|
import { ref, computed } from 'vue'
|
|
2
2
|
import { defineStore } from 'pinia'
|
|
3
3
|
import { callAdminForthApi } from '@/utils';
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import router from '@/router';
|
|
5
|
+
|
|
6
|
+
async function findHomepage(menu) {
|
|
7
|
+
for (const item of menu) {
|
|
8
|
+
if (item.homepage) {
|
|
9
|
+
return item;
|
|
10
|
+
}
|
|
11
|
+
if (item.children) {
|
|
12
|
+
const res = findHomepage(item.children);
|
|
13
|
+
if (res) {
|
|
14
|
+
return res;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
6
20
|
|
|
7
21
|
export const useCoreStore = defineStore('core', () => {
|
|
8
|
-
const resourceById
|
|
22
|
+
const resourceById = ref([]);
|
|
9
23
|
const menu = ref([]);
|
|
10
24
|
const config = ref({});
|
|
11
|
-
const record
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const resourceColumnsWithFilters = computed(() => {
|
|
15
|
-
if (!resource.value) {
|
|
16
|
-
return [];
|
|
17
|
-
}
|
|
18
|
-
return resource.value.columns.filter((col: AdminForthResourceColumn) => col.showIn?.includes('filter'));
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
const resourceOptions = ref(null);
|
|
25
|
+
const record = ref({});
|
|
26
|
+
const resourceColumns = ref(null);
|
|
22
27
|
const resourceColumnsError = ref('');
|
|
23
28
|
const resourceColumnsId = ref(null);
|
|
24
|
-
const
|
|
29
|
+
const user = ref(null);
|
|
25
30
|
|
|
26
31
|
async function fetchMenuAndResource() {
|
|
27
32
|
const resp = await callAdminForthApi({
|
|
28
33
|
path: '/get_base_config',
|
|
29
34
|
method: 'GET',
|
|
30
35
|
});
|
|
31
|
-
if(!resp){
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
36
|
menu.value = resp.menu;
|
|
35
|
-
resourceById.value = resp.resources.reduce((acc
|
|
37
|
+
resourceById.value = resp.resources.reduce((acc, resource) => {
|
|
36
38
|
acc[resource.resourceId] = resource;
|
|
37
39
|
return acc;
|
|
38
40
|
}, {});
|
|
39
41
|
config.value = resp.config;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
user.value = resp.user;
|
|
43
|
+
|
|
44
|
+
// find homepage:true in menu recuresively
|
|
45
|
+
if (import.meta.env.DEV){
|
|
46
|
+
return
|
|
47
|
+
} else {
|
|
48
|
+
const homepage = await findHomepage(menu.value);
|
|
49
|
+
if (homepage) {
|
|
50
|
+
if (homepage.resourceId) {
|
|
51
|
+
// redirect to homepage
|
|
52
|
+
router.push({ name: 'resource-list', params: { resourceId: homepage.resourceId } });
|
|
53
|
+
} else {
|
|
54
|
+
// redirect to path
|
|
55
|
+
router.push(homepage.path);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
async function fetchRecord({ resourceId, primaryKey }) {
|
|
45
62
|
record.value = null;
|
|
46
|
-
|
|
47
|
-
if (!resource.value) {
|
|
48
|
-
throw new Error('Columns not fetched yet');
|
|
49
|
-
}
|
|
50
63
|
|
|
51
|
-
|
|
52
|
-
path: '/
|
|
64
|
+
record.value = await callAdminForthApi({
|
|
65
|
+
path: '/get_record',
|
|
53
66
|
method: 'POST',
|
|
54
67
|
body: {
|
|
55
|
-
source: 'show',
|
|
56
68
|
resourceId: resourceId,
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
field: resource.value.columns.find((col: AdminForthResourceColumn) => col.primaryKey).name,
|
|
60
|
-
operator: 'eq',
|
|
61
|
-
value: primaryKey
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
sort: [],
|
|
65
|
-
limit: 1,
|
|
66
|
-
offset: 0
|
|
69
|
+
primaryKey: primaryKey,
|
|
67
70
|
}
|
|
68
71
|
});
|
|
69
|
-
|
|
70
|
-
if (respData.error) {
|
|
71
|
-
window.adminforth.alert({
|
|
72
|
-
message: respData.error,
|
|
73
|
-
variant: 'danger',
|
|
74
|
-
timeout: 'unlimited'
|
|
75
|
-
});
|
|
76
|
-
record.value = {};
|
|
77
|
-
} else {
|
|
78
|
-
record.value = respData.data[0];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
72
|
}
|
|
82
73
|
|
|
83
|
-
async function
|
|
84
|
-
if (resourceColumnsId.value === resourceId &&
|
|
74
|
+
async function fetchColumns({ resourceId }) {
|
|
75
|
+
if (resourceColumnsId.value === resourceId && resourceColumns.value) {
|
|
85
76
|
// already fetched
|
|
86
77
|
return;
|
|
87
78
|
}
|
|
88
79
|
resourceColumnsId.value = resourceId;
|
|
80
|
+
resourceColumns.value = null;
|
|
89
81
|
resourceColumnsError.value = '';
|
|
90
82
|
const res = await callAdminForthApi({
|
|
91
|
-
path: '/
|
|
83
|
+
path: '/get_resource_columns',
|
|
92
84
|
method: 'POST',
|
|
93
85
|
body: {
|
|
94
86
|
resourceId,
|
|
95
87
|
}
|
|
96
|
-
}
|
|
88
|
+
}
|
|
89
|
+
);
|
|
97
90
|
if (res.error) {
|
|
98
91
|
resourceColumnsError.value = res.error;
|
|
99
92
|
} else {
|
|
100
|
-
|
|
101
|
-
resource.value = res.resource;
|
|
102
|
-
resourceOptions.value = res.resource.options;
|
|
93
|
+
resourceColumns.value = res.resource.columns;
|
|
103
94
|
}
|
|
104
95
|
}
|
|
105
96
|
|
|
@@ -111,16 +102,21 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
111
102
|
config.value = {...config.value, ...res};
|
|
112
103
|
}
|
|
113
104
|
|
|
114
|
-
|
|
105
|
+
async function logout() {
|
|
106
|
+
await callAdminForthApi({
|
|
107
|
+
path: '/logout',
|
|
108
|
+
method: 'POST',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
115
111
|
|
|
116
112
|
const username = computed(() => {
|
|
117
113
|
const usernameField = config.value.usernameField;
|
|
118
|
-
return
|
|
114
|
+
return user.value && user.value[usernameField];
|
|
119
115
|
});
|
|
120
116
|
|
|
121
117
|
const userFullname = computed(() => {
|
|
122
118
|
const userFullnameField = config.value.userFullnameField;
|
|
123
|
-
return
|
|
119
|
+
return user.value && user.value[userFullnameField];
|
|
124
120
|
})
|
|
125
121
|
|
|
126
122
|
|
|
@@ -134,11 +130,9 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
134
130
|
fetchMenuAndResource,
|
|
135
131
|
fetchRecord,
|
|
136
132
|
record,
|
|
137
|
-
|
|
133
|
+
resourceColumns,
|
|
134
|
+
fetchColumns,
|
|
138
135
|
resourceColumnsError,
|
|
139
|
-
|
|
140
|
-
resource,
|
|
141
|
-
adminUser,
|
|
142
|
-
resourceColumnsWithFilters
|
|
136
|
+
logout
|
|
143
137
|
}
|
|
144
138
|
})
|
|
@@ -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
|
|
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,
|
|
36
|
+
return {isOpened, setModalContent, togleModal,modalContent, setOnAcceptFunction, onAcceptFunction,resetmodalState}
|
|
47
37
|
|
|
48
38
|
})
|
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,11 +29,9 @@ export async function callAdminForthApi({ path, method, body=undefined }: {
|
|
|
37
29
|
}
|
|
38
30
|
}
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return resolveComponent(name);
|
|
44
|
-
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
45
35
|
|
|
46
36
|
export function getIcon(icon: string) {
|
|
47
37
|
// icon format is "feather:icon-name". We need to get IconName in pascal case
|
|
@@ -51,51 +41,4 @@ export function getIcon(icon: string) {
|
|
|
51
41
|
const [iconSet, iconName] = icon.split(':');
|
|
52
42
|
const compName = 'Icon' + iconName.split('-').map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join('');
|
|
53
43
|
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
|
-
|
|
44
|
+
}
|
|
@@ -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,55 +22,32 @@
|
|
|
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"
|
|
53
|
-
:customComponentsPerColumn="createComponentsPerColumn"
|
|
54
34
|
>
|
|
55
35
|
</ResourceForm>
|
|
56
36
|
|
|
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
37
|
</div>
|
|
67
38
|
</template>
|
|
68
39
|
|
|
69
40
|
|
|
70
41
|
<script setup>
|
|
71
42
|
|
|
72
|
-
import
|
|
73
|
-
import
|
|
74
|
-
import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
|
|
43
|
+
import { ref, computed, onMounted } from 'vue';
|
|
44
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
75
45
|
import { useCoreStore } from '@/stores/core';
|
|
76
|
-
import { callAdminForthApi
|
|
46
|
+
import { callAdminForthApi } from '@/utils';
|
|
47
|
+
import ResourceForm from '@/components/ResourceForm.vue';
|
|
48
|
+
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
77
49
|
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
|
|
78
|
-
import
|
|
79
|
-
import { useRoute, useRouter } from 'vue-router';
|
|
80
|
-
import { computed } from 'vue';
|
|
81
|
-
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
82
|
-
|
|
50
|
+
import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
|
|
83
51
|
|
|
84
52
|
const isValid = ref(false);
|
|
85
53
|
const validating = ref(false);
|
|
@@ -91,19 +59,9 @@ const route = useRoute();
|
|
|
91
59
|
const router = useRouter();
|
|
92
60
|
|
|
93
61
|
const record = ref({});
|
|
94
|
-
let createComponentsPerColumn = {};
|
|
95
62
|
|
|
96
63
|
const coreStore = useCoreStore();
|
|
97
64
|
|
|
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
65
|
async function onUpdateRecord(newRecord) {
|
|
108
66
|
console.log('newRecord', newRecord);
|
|
109
67
|
record.value = newRecord;
|
|
@@ -111,18 +69,10 @@ async function onUpdateRecord(newRecord) {
|
|
|
111
69
|
|
|
112
70
|
onMounted(async () => {
|
|
113
71
|
loading.value = true;
|
|
114
|
-
|
|
115
|
-
await coreStore.fetchResourceFull({
|
|
72
|
+
coreStore.fetchColumns({
|
|
116
73
|
resourceId: route.params.resourceId
|
|
117
74
|
});
|
|
118
|
-
createComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
119
|
-
if (column.components?.create) {
|
|
120
|
-
acc[column.name] = getCustomComponent(column.components.create);
|
|
121
|
-
}
|
|
122
|
-
return acc;
|
|
123
|
-
}, {});
|
|
124
75
|
loading.value = false;
|
|
125
|
-
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'create');
|
|
126
76
|
});
|
|
127
77
|
|
|
128
78
|
async function saveRecord() {
|
|
@@ -141,22 +91,12 @@ async function saveRecord() {
|
|
|
141
91
|
record: record.value,
|
|
142
92
|
},
|
|
143
93
|
});
|
|
144
|
-
if (response.error) {
|
|
145
|
-
showErrorTost(response.error);
|
|
146
|
-
|
|
147
|
-
}
|
|
148
94
|
saving.value = false;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
params: {
|
|
155
|
-
resourceId: route.params.resourceId,
|
|
156
|
-
primaryKey: response.newRecordId
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
95
|
+
router.push({ name: 'resource-show', params: {
|
|
96
|
+
resourceId: route.params.resourceId,
|
|
97
|
+
primaryKey: response.newRecordId
|
|
98
|
+
|
|
99
|
+
} });
|
|
160
100
|
}
|
|
161
101
|
|
|
162
102
|
|