adminforth 1.0.75 → 1.0.77
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 +4 -4
- package/dist/spa/spa/src/components/ValueRenderer.vue +9 -3
- package/dist/spa/spa/src/router/index.ts +4 -4
- package/dist/spa/spa/src/spa_types/core.ts +51 -0
- package/dist/spa/spa/src/stores/core.ts +1 -2
- package/dist/spa/spa/src/utils.ts +16 -9
- package/index.ts +5 -5
- package/package.json +2 -1
- package/spa/src/components/ValueRenderer.vue +9 -3
- package/spa/src/router/index.ts +4 -4
- package/spa/src/spa_types/core.ts +51 -0
- package/spa/src/stores/core.ts +1 -2
- package/spa/src/utils.ts +16 -9
- package/types/AdminForthConfig.ts +3 -4
package/dist/index.js
CHANGED
|
@@ -73,6 +73,9 @@ class AdminForth {
|
|
|
73
73
|
}
|
|
74
74
|
console.log('\n ⚠️⚠️⚠️ [INSECURE ALERT] config.rootUser is set, please create a new user and remove config.rootUser from config before going to production\n');
|
|
75
75
|
}
|
|
76
|
+
if (!this.config.customization.customComponentsDir) {
|
|
77
|
+
this.config.customization.customComponentsDir = './custom';
|
|
78
|
+
}
|
|
76
79
|
if (this.config.auth) {
|
|
77
80
|
if (!this.config.auth.resourceId) {
|
|
78
81
|
throw new Error('No config.auth.resourceId defined');
|
|
@@ -94,9 +97,6 @@ class AdminForth {
|
|
|
94
97
|
if (!this.config.customization) {
|
|
95
98
|
this.config.customization = {};
|
|
96
99
|
}
|
|
97
|
-
if (!this.config.customization.customComponentsDir) {
|
|
98
|
-
this.config.customization.customComponentsDir = './custom';
|
|
99
|
-
}
|
|
100
100
|
if (!this.config.baseUrl) {
|
|
101
101
|
this.config.baseUrl = '';
|
|
102
102
|
}
|
|
@@ -484,7 +484,7 @@ class AdminForth {
|
|
|
484
484
|
auth: this.config.auth,
|
|
485
485
|
usernameField: this.config.auth.usernameField,
|
|
486
486
|
title: (_h = this.config.customization) === null || _h === void 0 ? void 0 : _h.title,
|
|
487
|
-
|
|
487
|
+
emptyFieldPlaceholder: (_j = this.config.customization) === null || _j === void 0 ? void 0 : _j.emptyFieldPlaceholder,
|
|
488
488
|
},
|
|
489
489
|
adminUser,
|
|
490
490
|
version: ADMINFORTH_VERSION,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
+
|
|
3
4
|
<span v-if="column.foreignResource">
|
|
4
5
|
<RouterLink v-if="row[column.name]" class="font-medium text-blue-600 dark:text-blue-500 hover:brightness-110"
|
|
5
6
|
:to="{ name: 'resource-show', params: { resourceId: column.foreignResource.resourceId, primaryKey: row[column.name].pk } }">
|
|
@@ -15,14 +16,14 @@
|
|
|
15
16
|
<span v-else class="bg-red-100 text-red-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400">No</span>
|
|
16
17
|
</span>
|
|
17
18
|
<span v-else-if="column.enum">
|
|
18
|
-
{{ column.enum.find(e => e.value === row[column.name])?.label }}
|
|
19
|
+
{{ checkEmptyValues(column.enum.find(e => e.value === row[column.name])?.label,route.meta.type) }}
|
|
19
20
|
</span>
|
|
20
21
|
<span v-else-if="column.type === 'datetime'">
|
|
21
|
-
{{ formatDate(row[column.name]) }}
|
|
22
|
+
{{ checkEmptyValues(formatDate(row[column.name]),route.meta.type) }}
|
|
22
23
|
|
|
23
24
|
</span>
|
|
24
25
|
<span v-else>
|
|
25
|
-
{{ row[column.name] }}
|
|
26
|
+
{{ checkEmptyValues(row[column.name],route.meta.type) }}
|
|
26
27
|
</span>
|
|
27
28
|
</div>
|
|
28
29
|
</template>
|
|
@@ -33,10 +34,15 @@
|
|
|
33
34
|
import dayjs from 'dayjs';
|
|
34
35
|
import utc from 'dayjs/plugin/utc';
|
|
35
36
|
import timezone from 'dayjs/plugin/timezone';
|
|
37
|
+
import {checkEmptyValues} from '@/utils';
|
|
38
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
39
|
+
|
|
36
40
|
|
|
37
41
|
import { useCoreStore } from '@/stores/core';
|
|
38
42
|
|
|
39
43
|
const coreStore = useCoreStore();
|
|
44
|
+
const route = useRoute();
|
|
45
|
+
|
|
40
46
|
|
|
41
47
|
dayjs.extend(utc);
|
|
42
48
|
dayjs.extend(timezone);
|
|
@@ -20,26 +20,26 @@ const router = createRouter({
|
|
|
20
20
|
path: '',
|
|
21
21
|
component: () => import('@/views/ListView.vue'),
|
|
22
22
|
name: 'resource-list',
|
|
23
|
-
meta: { title: 'list' }
|
|
23
|
+
meta: { title: 'list',type: 'list' }
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
path: 'show/:primaryKey',
|
|
27
27
|
component: () => import('@/views/ShowView.vue'),
|
|
28
28
|
name: 'resource-show',
|
|
29
|
-
meta: { title: 'show' }
|
|
29
|
+
meta: { title: 'show', type: 'show'}
|
|
30
30
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
path: 'edit/:primaryKey',
|
|
34
34
|
component: () => import('@/views/EditView.vue'),
|
|
35
35
|
name: 'resource-edit',
|
|
36
|
-
meta: { title: 'edit' }
|
|
36
|
+
meta: { title: 'edit', type: 'edit'}
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
path: 'create',
|
|
40
40
|
component: () => import('@/views/CreateView.vue'),
|
|
41
41
|
name: 'resource-create',
|
|
42
|
-
meta: { title: 'create' }
|
|
42
|
+
meta: { title: 'create', type: 'create'}
|
|
43
43
|
|
|
44
44
|
},
|
|
45
45
|
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AdminForthResource, AdminForthResourceColumn } from '../types/AdminForthConfig';
|
|
2
|
+
|
|
3
|
+
export type resourceById = {
|
|
4
|
+
[key: string]: AdminForthResource;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type Menu = {
|
|
8
|
+
label: string,
|
|
9
|
+
icon: string,
|
|
10
|
+
resourceId: string,
|
|
11
|
+
children?: Array<Menu>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Record = {
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type ResourceColumns = {
|
|
19
|
+
[key: string]: Array<AdminForthResourceColumn>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type CoreConfig = {
|
|
23
|
+
brandName: string,
|
|
24
|
+
brandLogo: string,
|
|
25
|
+
title: string,
|
|
26
|
+
datesFormat: string,
|
|
27
|
+
usernameField: string,
|
|
28
|
+
usernameFieldName?: string,
|
|
29
|
+
deleteConfirmation?: boolean,
|
|
30
|
+
auth?: {
|
|
31
|
+
resourceId: string,
|
|
32
|
+
usernameField: string,
|
|
33
|
+
passwordHashField: string,
|
|
34
|
+
loginBackgroundImage: string,
|
|
35
|
+
userFullnameField: string,
|
|
36
|
+
},
|
|
37
|
+
emptyFieldPlaceholder?: {
|
|
38
|
+
show: string,
|
|
39
|
+
list: string,
|
|
40
|
+
|
|
41
|
+
} | string,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export type AllowedActions = {
|
|
46
|
+
show: boolean,
|
|
47
|
+
create: boolean,
|
|
48
|
+
edit: boolean,
|
|
49
|
+
delete: boolean,
|
|
50
|
+
}
|
|
51
|
+
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { onMounted, ref, resolveComponent } from 'vue';
|
|
2
|
+
import type { CoreConfig } from './spa_types/core';
|
|
2
3
|
|
|
3
4
|
import router from "./router";
|
|
4
5
|
import { useCoreStore } from './stores/core';
|
|
@@ -64,12 +65,18 @@ export const loadFile = (file: string) => {
|
|
|
64
65
|
return baseUrl;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
export function checkEmptyValues(value: any, viewType:'show' | 'list' ) {
|
|
69
|
+
const config: CoreConfig | {} = useCoreStore().config;
|
|
70
|
+
let emptyFieldPlaceholder = '';
|
|
71
|
+
if (config.emptyFieldPlaceholder) {
|
|
72
|
+
if(typeof config.emptyFieldPlaceholder === 'string') {
|
|
73
|
+
emptyFieldPlaceholder = config.emptyFieldPlaceholder;
|
|
74
|
+
} else {
|
|
75
|
+
emptyFieldPlaceholder = config.emptyFieldPlaceholder?.[viewType] || '';
|
|
76
|
+
}
|
|
77
|
+
if (value === null || value === undefined || value === '') {
|
|
78
|
+
return emptyFieldPlaceholder;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
package/index.ts
CHANGED
|
@@ -93,6 +93,10 @@ class AdminForth implements AdminForthClass {
|
|
|
93
93
|
|
|
94
94
|
console.log('\n ⚠️⚠️⚠️ [INSECURE ALERT] config.rootUser is set, please create a new user and remove config.rootUser from config before going to production\n');
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
if (!this.config.customization.customComponentsDir) {
|
|
98
|
+
this.config.customization.customComponentsDir = './custom';
|
|
99
|
+
}
|
|
96
100
|
|
|
97
101
|
if (this.config.auth) {
|
|
98
102
|
if (!this.config.auth.resourceId) {
|
|
@@ -117,10 +121,6 @@ class AdminForth implements AdminForthClass {
|
|
|
117
121
|
this.config.customization = {};
|
|
118
122
|
}
|
|
119
123
|
|
|
120
|
-
if (!this.config.customization.customComponentsDir) {
|
|
121
|
-
this.config.customization.customComponentsDir = './custom';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
124
|
|
|
125
125
|
if (!this.config.baseUrl) {
|
|
126
126
|
this.config.baseUrl = '';
|
|
@@ -557,7 +557,7 @@ class AdminForth implements AdminForthClass {
|
|
|
557
557
|
auth: this.config.auth,
|
|
558
558
|
usernameField: this.config.auth.usernameField,
|
|
559
559
|
title: this.config.customization?.title,
|
|
560
|
-
|
|
560
|
+
emptyFieldPlaceholder: this.config.customization?.emptyFieldPlaceholder,
|
|
561
561
|
},
|
|
562
562
|
adminUser,
|
|
563
563
|
version: ADMINFORTH_VERSION,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adminforth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.77",
|
|
4
4
|
"description": "OpenSource Vue3 powered forth-generation admin panel",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"fs-extra": "^11.2.0",
|
|
23
23
|
"jsonwebtoken": "^9.0.2",
|
|
24
24
|
"mongodb": "6.6",
|
|
25
|
+
"node-fetch": "^3.3.2",
|
|
25
26
|
"pg": "^8.11.5",
|
|
26
27
|
"request": "^2.88.2",
|
|
27
28
|
"uuid": "^9.0.1"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
+
|
|
3
4
|
<span v-if="column.foreignResource">
|
|
4
5
|
<RouterLink v-if="row[column.name]" class="font-medium text-blue-600 dark:text-blue-500 hover:brightness-110"
|
|
5
6
|
:to="{ name: 'resource-show', params: { resourceId: column.foreignResource.resourceId, primaryKey: row[column.name].pk } }">
|
|
@@ -15,14 +16,14 @@
|
|
|
15
16
|
<span v-else class="bg-red-100 text-red-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400">No</span>
|
|
16
17
|
</span>
|
|
17
18
|
<span v-else-if="column.enum">
|
|
18
|
-
{{ column.enum.find(e => e.value === row[column.name])?.label }}
|
|
19
|
+
{{ checkEmptyValues(column.enum.find(e => e.value === row[column.name])?.label,route.meta.type) }}
|
|
19
20
|
</span>
|
|
20
21
|
<span v-else-if="column.type === 'datetime'">
|
|
21
|
-
{{ formatDate(row[column.name]) }}
|
|
22
|
+
{{ checkEmptyValues(formatDate(row[column.name]),route.meta.type) }}
|
|
22
23
|
|
|
23
24
|
</span>
|
|
24
25
|
<span v-else>
|
|
25
|
-
{{ row[column.name] }}
|
|
26
|
+
{{ checkEmptyValues(row[column.name],route.meta.type) }}
|
|
26
27
|
</span>
|
|
27
28
|
</div>
|
|
28
29
|
</template>
|
|
@@ -33,10 +34,15 @@
|
|
|
33
34
|
import dayjs from 'dayjs';
|
|
34
35
|
import utc from 'dayjs/plugin/utc';
|
|
35
36
|
import timezone from 'dayjs/plugin/timezone';
|
|
37
|
+
import {checkEmptyValues} from '@/utils';
|
|
38
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
39
|
+
|
|
36
40
|
|
|
37
41
|
import { useCoreStore } from '@/stores/core';
|
|
38
42
|
|
|
39
43
|
const coreStore = useCoreStore();
|
|
44
|
+
const route = useRoute();
|
|
45
|
+
|
|
40
46
|
|
|
41
47
|
dayjs.extend(utc);
|
|
42
48
|
dayjs.extend(timezone);
|
package/spa/src/router/index.ts
CHANGED
|
@@ -20,26 +20,26 @@ const router = createRouter({
|
|
|
20
20
|
path: '',
|
|
21
21
|
component: () => import('@/views/ListView.vue'),
|
|
22
22
|
name: 'resource-list',
|
|
23
|
-
meta: { title: 'list' }
|
|
23
|
+
meta: { title: 'list',type: 'list' }
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
path: 'show/:primaryKey',
|
|
27
27
|
component: () => import('@/views/ShowView.vue'),
|
|
28
28
|
name: 'resource-show',
|
|
29
|
-
meta: { title: 'show' }
|
|
29
|
+
meta: { title: 'show', type: 'show'}
|
|
30
30
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
path: 'edit/:primaryKey',
|
|
34
34
|
component: () => import('@/views/EditView.vue'),
|
|
35
35
|
name: 'resource-edit',
|
|
36
|
-
meta: { title: 'edit' }
|
|
36
|
+
meta: { title: 'edit', type: 'edit'}
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
path: 'create',
|
|
40
40
|
component: () => import('@/views/CreateView.vue'),
|
|
41
41
|
name: 'resource-create',
|
|
42
|
-
meta: { title: 'create' }
|
|
42
|
+
meta: { title: 'create', type: 'create'}
|
|
43
43
|
|
|
44
44
|
},
|
|
45
45
|
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AdminForthResource, AdminForthResourceColumn } from '../types/AdminForthConfig';
|
|
2
|
+
|
|
3
|
+
export type resourceById = {
|
|
4
|
+
[key: string]: AdminForthResource;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type Menu = {
|
|
8
|
+
label: string,
|
|
9
|
+
icon: string,
|
|
10
|
+
resourceId: string,
|
|
11
|
+
children?: Array<Menu>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Record = {
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type ResourceColumns = {
|
|
19
|
+
[key: string]: Array<AdminForthResourceColumn>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type CoreConfig = {
|
|
23
|
+
brandName: string,
|
|
24
|
+
brandLogo: string,
|
|
25
|
+
title: string,
|
|
26
|
+
datesFormat: string,
|
|
27
|
+
usernameField: string,
|
|
28
|
+
usernameFieldName?: string,
|
|
29
|
+
deleteConfirmation?: boolean,
|
|
30
|
+
auth?: {
|
|
31
|
+
resourceId: string,
|
|
32
|
+
usernameField: string,
|
|
33
|
+
passwordHashField: string,
|
|
34
|
+
loginBackgroundImage: string,
|
|
35
|
+
userFullnameField: string,
|
|
36
|
+
},
|
|
37
|
+
emptyFieldPlaceholder?: {
|
|
38
|
+
show: string,
|
|
39
|
+
list: string,
|
|
40
|
+
|
|
41
|
+
} | string,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export type AllowedActions = {
|
|
46
|
+
show: boolean,
|
|
47
|
+
create: boolean,
|
|
48
|
+
edit: boolean,
|
|
49
|
+
delete: boolean,
|
|
50
|
+
}
|
|
51
|
+
|
package/spa/src/stores/core.ts
CHANGED
package/spa/src/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { onMounted, ref, resolveComponent } from 'vue';
|
|
2
|
+
import type { CoreConfig } from './spa_types/core';
|
|
2
3
|
|
|
3
4
|
import router from "./router";
|
|
4
5
|
import { useCoreStore } from './stores/core';
|
|
@@ -64,12 +65,18 @@ export const loadFile = (file: string) => {
|
|
|
64
65
|
return baseUrl;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
export function checkEmptyValues(value: any, viewType:'show' | 'list' ) {
|
|
69
|
+
const config: CoreConfig | {} = useCoreStore().config;
|
|
70
|
+
let emptyFieldPlaceholder = '';
|
|
71
|
+
if (config.emptyFieldPlaceholder) {
|
|
72
|
+
if(typeof config.emptyFieldPlaceholder === 'string') {
|
|
73
|
+
emptyFieldPlaceholder = config.emptyFieldPlaceholder;
|
|
74
|
+
} else {
|
|
75
|
+
emptyFieldPlaceholder = config.emptyFieldPlaceholder?.[viewType] || '';
|
|
76
|
+
}
|
|
77
|
+
if (value === null || value === undefined || value === '') {
|
|
78
|
+
return emptyFieldPlaceholder;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
@@ -134,12 +134,11 @@ export type AdminForthConfig = {
|
|
|
134
134
|
datesFormat?: string,
|
|
135
135
|
title?: string,
|
|
136
136
|
brandLogo?: string,
|
|
137
|
-
|
|
137
|
+
emptyFieldPlaceholder?: {
|
|
138
138
|
show?: string,
|
|
139
139
|
list?: string,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
},
|
|
140
|
+
|
|
141
|
+
} | string,
|
|
143
142
|
},
|
|
144
143
|
baseUrl?: string,
|
|
145
144
|
|