adminforth 1.2.87 → 1.2.89
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/modules/restApi.js +9 -0
- package/dist/spa/.vscode/extensions.json +6 -0
- package/dist/spa/index.html +4 -4
- package/dist/spa/package-lock.json +6 -421
- package/dist/spa/package.json +2 -10
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/.eslintrc.cjs +14 -0
- package/dist/spa/spa/.vscode/extensions.json +6 -0
- package/dist/spa/spa/README.md +39 -0
- package/dist/spa/spa/env.d.ts +1 -0
- package/dist/spa/spa/index.html +23 -0
- package/dist/spa/spa/package-lock.json +4573 -0
- package/dist/spa/spa/package.json +49 -0
- package/dist/spa/spa/postcss.config.js +6 -0
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/src/App.vue +314 -0
- package/dist/spa/spa/src/assets/base.css +0 -0
- package/dist/spa/spa/src/assets/logo.svg +19 -0
- package/dist/spa/spa/src/components/AcceptModal.vue +45 -0
- package/dist/spa/spa/src/components/Breadcrumbs.vue +40 -0
- package/dist/spa/spa/src/components/BreadcrumbsWithButtons.vue +26 -0
- package/dist/spa/spa/src/components/CustomDatePicker.vue +174 -0
- package/dist/spa/spa/src/components/CustomDateRangePicker.vue +218 -0
- package/dist/spa/spa/src/components/Dropdown.vue +168 -0
- package/dist/spa/spa/src/components/Filters.vue +222 -0
- package/dist/spa/spa/src/components/HelloWorld.vue +17 -0
- package/dist/spa/spa/src/components/MenuLink.vue +24 -0
- package/dist/spa/spa/src/components/ResourceForm.vue +289 -0
- package/dist/spa/{src → spa/src}/components/ResourceListTable.vue +3 -6
- package/dist/spa/spa/src/components/SingleSkeletLoader.vue +13 -0
- package/dist/spa/{src → spa/src}/components/Toast.vue +3 -9
- package/dist/spa/spa/src/components/ValueRenderer.vue +66 -0
- package/dist/spa/spa/src/components/icons/IconCalendar.vue +5 -0
- package/dist/spa/spa/src/components/icons/IconCommunity.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconDocumentation.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconEcosystem.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconSupport.vue +7 -0
- package/dist/spa/spa/src/components/icons/IconTime.vue +5 -0
- package/dist/spa/spa/src/components/icons/IconTooling.vue +19 -0
- package/dist/spa/spa/src/index.scss +27 -0
- package/dist/spa/spa/src/main.ts +18 -0
- package/dist/spa/spa/src/router/index.ts +63 -0
- package/dist/spa/spa/src/stores/core.ts +144 -0
- package/dist/spa/spa/src/stores/modal.ts +48 -0
- package/dist/spa/spa/src/utils.ts +103 -0
- package/dist/spa/spa/src/views/CreateView.vue +156 -0
- package/dist/spa/spa/src/views/EditView.vue +157 -0
- package/dist/spa/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/spa/src/views/ListView.vue +258 -0
- package/dist/spa/spa/src/views/LoginView.vue +143 -0
- package/dist/spa/spa/src/views/ResourceParent.vue +17 -0
- package/dist/spa/spa/src/views/ShowView.vue +184 -0
- package/dist/spa/spa/tailwind.config.js +17 -0
- package/dist/spa/spa/tsconfig.app.json +14 -0
- package/dist/spa/spa/tsconfig.json +11 -0
- package/dist/spa/spa/tsconfig.node.json +19 -0
- package/dist/spa/spa/vite.config.ts +56 -0
- package/dist/spa/src/App.vue +94 -236
- package/dist/spa/src/assets/base.css +0 -2
- package/dist/spa/src/assets/logo.svg +1 -19
- package/dist/spa/src/components/AcceptModal.vue +10 -3
- package/dist/spa/src/components/Breadcrumbs.vue +2 -3
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +10 -25
- 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 +38 -103
- package/dist/spa/src/components/MenuLink.vue +3 -3
- package/dist/spa/src/components/ResourceForm.vue +116 -205
- package/dist/spa/src/components/ValueRenderer.vue +8 -30
- package/dist/spa/src/index.scss +1 -2
- package/dist/spa/src/main.ts +2 -2
- package/dist/spa/src/router/index.ts +19 -29
- package/dist/spa/src/stores/core.ts +59 -65
- package/dist/spa/src/stores/modal.ts +3 -13
- package/dist/spa/src/utils.ts +10 -69
- package/dist/spa/src/views/CreateView.vue +16 -69
- package/dist/spa/src/views/EditView.vue +14 -68
- package/dist/spa/src/views/HomeView.vue +8 -0
- package/dist/spa/src/views/ListView.vue +371 -100
- package/dist/spa/src/views/LoginView.vue +29 -67
- package/dist/spa/src/views/ResourceParent.vue +2 -1
- package/dist/spa/src/views/ShowView.vue +25 -116
- package/dist/spa/tailwind.config.js +3 -8
- package/dist/spa/vite.config.ts +0 -13
- package/dist/types.js +30 -0
- package/modules/restApi.ts +14 -1
- package/package.json +1 -1
- package/spa/src/components/MenuLink.vue +3 -0
- package/types/AdminForthConfig.ts +6 -0
- package/dist/spa/src/types/AdminForthConfig.ts +0 -1477
- package/dist/spa/src/types/FrontendAPI.ts +0 -121
- /package/dist/spa/{public → spa/public}/assets/favicon.png +0 -0
- /package/dist/spa/{src → spa/src}/components/CustomRangePicker.vue +0 -0
- /package/dist/spa/{src → spa/src}/components/SkeleteLoader.vue +0 -0
- /package/dist/spa/{src → spa/src}/composables/useFrontendApi.ts +0 -0
- /package/dist/spa/{src → spa/src}/composables/useStores.ts +0 -0
- /package/dist/spa/{src → spa/src}/spa_types/core.ts +0 -0
- /package/dist/spa/{src → spa/src}/stores/filters.ts +0 -0
- /package/dist/spa/{src → spa/src}/stores/toast.ts +0 -0
- /package/dist/spa/{src → spa/src}/stores/user.ts +0 -0
|
@@ -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,15 +1,8 @@
|
|
|
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
|
-
export async function callApi({path, method, body=undefined}
|
|
10
|
-
path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
|
|
11
|
-
body?: any
|
|
12
|
-
}): Promise<any> {
|
|
5
|
+
export async function callApi({path, method, body=undefined} ) {
|
|
13
6
|
const options = {
|
|
14
7
|
method,
|
|
15
8
|
headers: {
|
|
@@ -19,19 +12,15 @@ export async function callApi({path, method, body=undefined}: {
|
|
|
19
12
|
};
|
|
20
13
|
const fullPath = `${import.meta.env.VITE_ADMINFORTH_PUBLIC_PATH || ''}${path}`;
|
|
21
14
|
const r = await fetch(fullPath, options);
|
|
22
|
-
if (r.status == 401
|
|
23
|
-
|
|
24
|
-
router.push({
|
|
15
|
+
if (r.status == 401) {
|
|
16
|
+
console.log('router', router);
|
|
17
|
+
router.push({name: 'login'});
|
|
25
18
|
return null;
|
|
26
|
-
}
|
|
19
|
+
}
|
|
27
20
|
return await r.json();
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
export async function callAdminForthApi({ path, method, body=undefined }
|
|
31
|
-
path: string,
|
|
32
|
-
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
|
33
|
-
body?: any
|
|
34
|
-
}) {
|
|
23
|
+
export async function callAdminForthApi({ path, method, body=undefined }) {
|
|
35
24
|
try {
|
|
36
25
|
return callApi({path: `/adminapi/v1${path}`, method, body} );
|
|
37
26
|
} catch (e) {
|
|
@@ -40,10 +29,9 @@ export async function callAdminForthApi({ path, method, body=undefined }: {
|
|
|
40
29
|
}
|
|
41
30
|
}
|
|
42
31
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
47
35
|
|
|
48
36
|
export function getIcon(icon: string) {
|
|
49
37
|
// icon format is "feather:icon-name". We need to get IconName in pascal case
|
|
@@ -53,51 +41,4 @@ export function getIcon(icon: string) {
|
|
|
53
41
|
const [iconSet, iconName] = icon.split(':');
|
|
54
42
|
const compName = 'Icon' + iconName.split('-').map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join('');
|
|
55
43
|
return resolveComponent(compName);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const loadFile = (file: string) => {
|
|
59
|
-
if (file.startsWith('http')) {
|
|
60
|
-
return file;
|
|
61
|
-
}
|
|
62
|
-
let path;
|
|
63
|
-
let baseUrl = '';
|
|
64
|
-
if (file.startsWith('@/')) {
|
|
65
|
-
path = file.replace('@/', '');
|
|
66
|
-
baseUrl = new URL(`./${path}`, import.meta.url).href;
|
|
67
|
-
} else if (file.startsWith('@@/')) {
|
|
68
|
-
path = file.replace('@@/', '');
|
|
69
|
-
baseUrl = new URL(`./custom/${path}`, import.meta.url).href;
|
|
70
|
-
} else {
|
|
71
|
-
baseUrl = new URL(`./${file}`, import.meta.url).href;
|
|
72
|
-
}
|
|
73
|
-
return baseUrl;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function checkEmptyValues(value: any, viewType: 'show' | 'list' ) {
|
|
77
|
-
const config: CoreConfig | {} = useCoreStore().config;
|
|
78
|
-
let emptyFieldPlaceholder = '';
|
|
79
|
-
if (config.emptyFieldPlaceholder) {
|
|
80
|
-
if(typeof config.emptyFieldPlaceholder === 'string') {
|
|
81
|
-
emptyFieldPlaceholder = config.emptyFieldPlaceholder;
|
|
82
|
-
} else {
|
|
83
|
-
emptyFieldPlaceholder = config.emptyFieldPlaceholder?.[viewType] || '';
|
|
84
|
-
}
|
|
85
|
-
if (value === null || value === undefined || value === '') {
|
|
86
|
-
return emptyFieldPlaceholder;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function checkAcessByAllowedActions(allowedActions:any, action:any ) {
|
|
93
|
-
if (!allowedActions) {
|
|
94
|
-
console.warn('allowedActions not set');
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if(allowedActions[action] === false) {
|
|
98
|
-
console.warn(`Action ${action} is not allowed`);
|
|
99
|
-
router.back();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
:source="'create'"
|
|
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);
|
|
@@ -94,15 +62,6 @@ const record = ref({});
|
|
|
94
62
|
|
|
95
63
|
const coreStore = useCoreStore();
|
|
96
64
|
|
|
97
|
-
const initalValues = computed(() => {
|
|
98
|
-
if (!route.query.values) {
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
101
|
-
return JSON.parse(decodeURIComponent(route.query.values));
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
65
|
async function onUpdateRecord(newRecord) {
|
|
107
66
|
console.log('newRecord', newRecord);
|
|
108
67
|
record.value = newRecord;
|
|
@@ -110,16 +69,13 @@ async function onUpdateRecord(newRecord) {
|
|
|
110
69
|
|
|
111
70
|
onMounted(async () => {
|
|
112
71
|
loading.value = true;
|
|
113
|
-
|
|
114
|
-
await coreStore.fetchResourceFull({
|
|
72
|
+
coreStore.fetchColumns({
|
|
115
73
|
resourceId: route.params.resourceId
|
|
116
74
|
});
|
|
117
75
|
loading.value = false;
|
|
118
|
-
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'create');
|
|
119
76
|
});
|
|
120
77
|
|
|
121
78
|
async function saveRecord() {
|
|
122
|
-
console.log('saveRecord isValid', isValid.value);
|
|
123
79
|
if (!isValid.value) {
|
|
124
80
|
validating.value = true;
|
|
125
81
|
return;
|
|
@@ -135,21 +91,12 @@ async function saveRecord() {
|
|
|
135
91
|
record: record.value,
|
|
136
92
|
},
|
|
137
93
|
});
|
|
138
|
-
if (response.error) {
|
|
139
|
-
showErrorTost(response.error);
|
|
140
|
-
}
|
|
141
94
|
saving.value = false;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
params: {
|
|
148
|
-
resourceId: route.params.resourceId,
|
|
149
|
-
primaryKey: response.newRecordId
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
95
|
+
router.push({ name: 'resource-show', params: {
|
|
96
|
+
resourceId: route.params.resourceId,
|
|
97
|
+
primaryKey: response.newRecordId
|
|
98
|
+
|
|
99
|
+
} });
|
|
153
100
|
}
|
|
154
101
|
|
|
155
102
|
|
|
@@ -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,53 +19,31 @@
|
|
|
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
|
-
:record="
|
|
44
|
-
:
|
|
45
|
-
:adminUser="coreStore.adminUser"
|
|
26
|
+
:record="coreStore.record"
|
|
27
|
+
:resourceColumns="coreStore.resourceColumns"
|
|
46
28
|
@update:record="onUpdateRecord"
|
|
47
29
|
@update:isValid="isValid = $event"
|
|
48
30
|
:validating="validating"
|
|
49
|
-
:source="'edit'"
|
|
50
31
|
>
|
|
51
32
|
</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
33
|
</div>
|
|
63
34
|
</template>
|
|
64
35
|
|
|
65
36
|
|
|
66
37
|
<script setup>
|
|
67
38
|
|
|
68
|
-
import
|
|
69
|
-
import
|
|
70
|
-
import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
|
|
39
|
+
import { ref, computed, onMounted } from 'vue';
|
|
40
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
71
41
|
import { useCoreStore } from '@/stores/core';
|
|
72
|
-
import
|
|
42
|
+
import ResourceForm from '@/components/ResourceForm.vue';
|
|
43
|
+
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
73
44
|
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
|
|
74
|
-
import
|
|
75
|
-
import {
|
|
76
|
-
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
45
|
+
import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
|
|
46
|
+
import { callAdminForthApi } from '@/utils';
|
|
77
47
|
|
|
78
48
|
const coreStore = useCoreStore();
|
|
79
49
|
|
|
@@ -93,31 +63,18 @@ async function onUpdateRecord(newRecord) {
|
|
|
93
63
|
record.value = newRecord;
|
|
94
64
|
}
|
|
95
65
|
|
|
96
|
-
const editableRecord = computed(() => {
|
|
97
|
-
const newRecord = { ...coreStore.record };
|
|
98
|
-
if (!coreStore.resource) {
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
101
|
-
coreStore.resource.columns.forEach(column => {
|
|
102
|
-
if (column.foreignResource) {
|
|
103
|
-
newRecord[column.name] = newRecord[column.name]?.pk
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
return newRecord;
|
|
107
|
-
})
|
|
108
66
|
|
|
109
67
|
onMounted(async () => {
|
|
110
|
-
|
|
111
68
|
loading.value = true;
|
|
112
69
|
|
|
113
|
-
await coreStore.
|
|
70
|
+
await coreStore.fetchColumns({
|
|
114
71
|
resourceId: route.params.resourceId
|
|
115
72
|
});
|
|
116
73
|
await coreStore.fetchRecord({
|
|
117
74
|
resourceId: route.params.resourceId,
|
|
118
75
|
primaryKey: route.params.primaryKey,
|
|
119
76
|
});
|
|
120
|
-
|
|
77
|
+
|
|
121
78
|
loading.value = false;
|
|
122
79
|
});
|
|
123
80
|
|
|
@@ -130,26 +87,15 @@ async function saveRecord() {
|
|
|
130
87
|
}
|
|
131
88
|
|
|
132
89
|
saving.value = true;
|
|
133
|
-
|
|
134
|
-
const updates = {};
|
|
135
|
-
for (const key in record.value) {
|
|
136
|
-
if (record.value[key] !== coreStore.record[key]) {
|
|
137
|
-
updates[key] = record.value[key];
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const resp = await callAdminForthApi({
|
|
90
|
+
await callAdminForthApi({
|
|
142
91
|
method: 'POST',
|
|
143
92
|
path: `/update_record`,
|
|
144
93
|
body: {
|
|
145
94
|
resourceId: route.params.resourceId,
|
|
146
95
|
recordId: route.params.primaryKey,
|
|
147
|
-
record:
|
|
96
|
+
record: record.value,
|
|
148
97
|
},
|
|
149
98
|
});
|
|
150
|
-
if (resp.error) {
|
|
151
|
-
showErrorTost(resp.error);
|
|
152
|
-
}
|
|
153
99
|
saving.value = false;
|
|
154
100
|
router.push({ name: 'resource-show', params: { resourceId: route.params.resourceId, primaryKey: coreStore.record[coreStore.primaryKey] } });
|
|
155
101
|
}
|