adminforth 1.2.86 → 1.2.88
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,18 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative flex items-center justify-center min-h-screen bg-gray-100 dark:bg-gray-800"
|
|
3
3
|
:style="coreStore.config?.loginBackgroundImage ? {
|
|
4
|
-
'background-image': 'url(' +
|
|
4
|
+
'background-image': 'url(' + coreStore.config?.loginBackgroundImage + ')',
|
|
5
5
|
'background-size': 'cover',
|
|
6
6
|
'background-position': 'center',
|
|
7
7
|
'background-blend-mode': 'darken'
|
|
8
8
|
}: {}"
|
|
9
9
|
>
|
|
10
|
-
|
|
11
|
-
<!-- Main modal -->
|
|
10
|
+
<!-- Main modal -->
|
|
12
11
|
<div id="authentication-modal" tabindex="-1" class=" overflow-y-auto overflow-x-hidden z-50 min-w-[400px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
|
13
12
|
<div class="relative p-4 w-full max-w-md max-h-full">
|
|
14
13
|
<!-- Modal content -->
|
|
15
|
-
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700
|
|
14
|
+
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
|
16
15
|
<!-- Modal header -->
|
|
17
16
|
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
|
|
18
17
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
|
|
@@ -22,23 +21,17 @@
|
|
|
22
21
|
</div>
|
|
23
22
|
<!-- Modal body -->
|
|
24
23
|
<div class="p-4 md:p-5">
|
|
25
|
-
<form class="space-y-4"
|
|
24
|
+
<form class="space-y-4" @submit.prevent>
|
|
26
25
|
<div>
|
|
27
26
|
<label for="username" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your {{ coreStore.config?.usernameFieldName?.toLowerCase() }}</label>
|
|
28
|
-
<input type="username" name="username" id="username"
|
|
29
|
-
ref="usernameInput"
|
|
30
|
-
@keydown.enter="passwordInput.focus()"
|
|
31
|
-
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" required />
|
|
27
|
+
<input type="username" name="username" id="username" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" required />
|
|
32
28
|
</div>
|
|
33
29
|
<div class="relative">
|
|
34
30
|
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your password</label>
|
|
35
|
-
<input
|
|
36
|
-
ref="passwordInput"
|
|
37
|
-
@keydown.enter="login"
|
|
38
|
-
:type="!showPw ? 'password': 'text'" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
|
|
31
|
+
<input :type="!showPw ? 'password': 'text'" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
|
|
39
32
|
<button type="button" @click="showPw = !showPw" class="absolute top-12 right-3 -translate-y-1/2 text-gray-400 dark:text-gray-300">
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
<IconEyeSolid class="w-5 h-5" v-if="!showPw" />
|
|
34
|
+
<IconEyeSlashSolid class="w-5 h-5" v-else />
|
|
42
35
|
</button>
|
|
43
36
|
</div>
|
|
44
37
|
<!-- <div class="flex justify-between">
|
|
@@ -61,17 +54,6 @@
|
|
|
61
54
|
</div>
|
|
62
55
|
</div>
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
<div v-if="coreStore.config?.loginPromptHTML"
|
|
66
|
-
class="flex items-center p-4 mb-4 text-sm text-gray-800 rounded-lg bg-gray-50 dark:bg-gray-800 dark:text-gray-400" role="alert"
|
|
67
|
-
>
|
|
68
|
-
<svg class="flex-shrink-0 inline w-4 h-4 me-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
|
69
|
-
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/>
|
|
70
|
-
</svg>
|
|
71
|
-
<span class="sr-only">Info</span>
|
|
72
|
-
<div v-html="coreStore.config?.loginPromptHTML"></div>
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
57
|
<button
|
|
76
58
|
@click="login"
|
|
77
59
|
type="submit" class="flex items-center justify-center gap-1 w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
|
|
@@ -96,64 +78,44 @@
|
|
|
96
78
|
|
|
97
79
|
<script setup>
|
|
98
80
|
|
|
99
|
-
import { onMounted, ref
|
|
81
|
+
import { onMounted, ref } from 'vue';
|
|
100
82
|
import { useCoreStore } from '@/stores/core';
|
|
101
|
-
import { useUserStore } from '@/stores/user';
|
|
102
83
|
import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbite';
|
|
103
|
-
import { callAdminForthApi
|
|
84
|
+
import { callAdminForthApi } from '@/utils';
|
|
104
85
|
import { useRouter } from 'vue-router';
|
|
105
86
|
|
|
106
|
-
const passwordInput = ref(null);
|
|
107
|
-
const usernameInput = ref(null);
|
|
108
|
-
|
|
109
87
|
const router = useRouter();
|
|
110
88
|
const inProgress = ref(false);
|
|
111
89
|
|
|
112
90
|
const coreStore = useCoreStore();
|
|
113
|
-
const user = useUserStore();
|
|
114
|
-
|
|
115
91
|
|
|
116
92
|
const showPw = ref(false);
|
|
117
93
|
|
|
118
94
|
const error = ref(null);
|
|
119
95
|
|
|
120
|
-
onMounted(
|
|
121
|
-
|
|
122
|
-
if (coreStore.config?.demoCredentials) {
|
|
123
|
-
console.log('Setting demo credentials');
|
|
124
|
-
const [username, password] = coreStore.config.demoCredentials.split(':');
|
|
125
|
-
usernameInput.value.value = username;
|
|
126
|
-
passwordInput.value.value = password;
|
|
127
|
-
}
|
|
128
|
-
usernameInput.value.focus();
|
|
96
|
+
onMounted(() => {
|
|
97
|
+
coreStore.getPublicConfig()
|
|
129
98
|
});
|
|
130
99
|
|
|
131
|
-
|
|
132
100
|
async function login() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
101
|
+
inProgress.value = true;
|
|
102
|
+
const resp = await callAdminForthApi({
|
|
103
|
+
path: '/login',
|
|
104
|
+
method: 'POST',
|
|
105
|
+
body: {
|
|
106
|
+
username: document.getElementById('username').value,
|
|
107
|
+
password: document.getElementById('password').value,
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
inProgress.value = false;
|
|
111
|
+
if (resp.error) {
|
|
112
|
+
error.value = resp.error;
|
|
113
|
+
} else {
|
|
114
|
+
error.value = null;
|
|
115
|
+
router.push('/');
|
|
116
|
+
await coreStore.fetchMenuAndResource();
|
|
146
117
|
}
|
|
147
|
-
|
|
148
|
-
inProgress.value = false;
|
|
149
|
-
if (resp.error) {
|
|
150
|
-
error.value = resp.error;
|
|
151
|
-
} else if (resp.redirectTo) {
|
|
152
|
-
router.push(resp.redirectTo);
|
|
153
|
-
} else {
|
|
154
|
-
error.value = null;
|
|
155
|
-
await user.finishLogin();
|
|
156
|
-
}
|
|
118
|
+
|
|
157
119
|
}
|
|
158
120
|
|
|
159
121
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div>
|
|
3
3
|
<RouterView/>
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
import { useCoreStore } from '@/stores/core';
|
|
14
|
+
import { onMounted } from 'vue';
|
|
14
15
|
|
|
15
16
|
const coreStore = useCoreStore()
|
|
16
17
|
|
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
|
-
<component
|
|
4
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.beforeBreadcrumbs || []"
|
|
5
|
-
:is="getCustomComponent(c)"
|
|
6
|
-
:meta="c.meta"
|
|
7
|
-
:record="coreStore.record"
|
|
8
|
-
:resource="coreStore.resource"
|
|
9
|
-
:adminUser="coreStore.adminUser"
|
|
10
|
-
/>
|
|
11
3
|
<BreadcrumbsWithButtons>
|
|
12
|
-
<RouterLink
|
|
13
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded
|
|
4
|
+
<RouterLink :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
|
|
5
|
+
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"
|
|
14
6
|
>
|
|
15
7
|
<IconPenSolid class="w-4 h-4" />
|
|
16
8
|
Edit
|
|
17
9
|
</RouterLink>
|
|
18
10
|
|
|
19
|
-
<button
|
|
20
|
-
class="flex items-center py-1 px-3 text-sm font-medium
|
|
11
|
+
<button @click="deleteRecord"
|
|
12
|
+
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"
|
|
21
13
|
>
|
|
22
14
|
<IconTrashBinSolid class="w-4 h-4" />
|
|
23
15
|
Delete
|
|
24
16
|
</button>
|
|
25
17
|
</BreadcrumbsWithButtons>
|
|
26
18
|
|
|
27
|
-
<component
|
|
28
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.afterBreadcrumbs || []"
|
|
29
|
-
:is="getCustomComponent(c)"
|
|
30
|
-
:meta="c.meta"
|
|
31
|
-
:record="coreStore.record"
|
|
32
|
-
:resource="coreStore.resource"
|
|
33
|
-
:adminUser="coreStore.adminUser"
|
|
34
|
-
/>
|
|
35
|
-
|
|
36
19
|
<div v-if="loading" role="status" class="max-w-sm animate-pulse">
|
|
37
20
|
<div class="h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4"></div>
|
|
38
21
|
<div class="h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5"></div>
|
|
@@ -43,69 +26,35 @@
|
|
|
43
26
|
<span class="sr-only">Loading...</span>
|
|
44
27
|
</div>
|
|
45
28
|
<div
|
|
46
|
-
v-else
|
|
47
|
-
class="relative overflow-x-auto
|
|
29
|
+
v-else
|
|
30
|
+
class="relative overflow-x-auto shadow-md sm:rounded-lg"
|
|
48
31
|
>
|
|
49
|
-
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400
|
|
50
|
-
<thead class="text-xs text-gray-700 uppercase bg-
|
|
32
|
+
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
|
33
|
+
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
|
51
34
|
<tr>
|
|
52
35
|
<th scope="col" class="px-6 py-3">
|
|
53
36
|
Field
|
|
54
37
|
</th>
|
|
55
|
-
<th scope="col" class="px-6 py-3 w-
|
|
38
|
+
<th scope="col" class="px-6 py-3 w-4/6">
|
|
56
39
|
Value
|
|
57
40
|
</th>
|
|
58
41
|
</tr>
|
|
59
42
|
</thead>
|
|
60
43
|
<tbody>
|
|
61
|
-
<tr v-for="column in coreStore.
|
|
62
|
-
class="bg-
|
|
44
|
+
<tr v-for="column in coreStore.resourceColumns?.filter(c => c.showIn.includes('show'))" :key="column.name"
|
|
45
|
+
class="odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800 border-b dark:border-gray-700"
|
|
63
46
|
>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
:is="getCustomComponent(column.components.showRow)"
|
|
67
|
-
:meta="column.components.showRow.meta"
|
|
68
|
-
:column="column"
|
|
69
|
-
:resource="coreStore.resource"
|
|
70
|
-
:record="coreStore.record"
|
|
71
|
-
/>
|
|
72
|
-
<template v-else>
|
|
73
|
-
<td class="px-6 py-4 whitespace-nowrap "> <!--align-top-->
|
|
74
|
-
{{ column.label }}
|
|
47
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
48
|
+
{{ column.label }}
|
|
75
49
|
</td>
|
|
76
50
|
<td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap">
|
|
77
|
-
|
|
78
|
-
v-if="column?.components?.show"
|
|
79
|
-
:is="getCustomComponent(column?.components?.show)"
|
|
80
|
-
:resource="coreStore.resource"
|
|
81
|
-
:meta="column.components.show.meta"
|
|
82
|
-
:column="column"
|
|
83
|
-
:record="coreStore.record"
|
|
84
|
-
/>
|
|
85
|
-
<ValueRenderer v-else
|
|
86
|
-
:column="column"
|
|
87
|
-
:record="coreStore.record"
|
|
88
|
-
/>
|
|
51
|
+
<ValueRenderer :column="column" :row="coreStore.record" />
|
|
89
52
|
</td>
|
|
90
|
-
</template>
|
|
91
53
|
</tr>
|
|
54
|
+
|
|
92
55
|
</tbody>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<div v-else class="text-center text-gray-500 dark:text-gray-400 mt-10">
|
|
97
|
-
Ooops. Record not found
|
|
98
|
-
</div>
|
|
99
|
-
|
|
100
|
-
<component
|
|
101
|
-
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.bottom || []"
|
|
102
|
-
:is="getCustomComponent(c)"
|
|
103
|
-
:meta="c.meta"
|
|
104
|
-
:column="column"
|
|
105
|
-
:record="coreStore.record"
|
|
106
|
-
:resource="coreStore.resource"
|
|
107
|
-
:adminUser="coreStore.adminUser"
|
|
108
|
-
/>
|
|
56
|
+
</table>
|
|
57
|
+
</div>
|
|
109
58
|
|
|
110
59
|
|
|
111
60
|
</div>
|
|
@@ -114,71 +63,31 @@
|
|
|
114
63
|
|
|
115
64
|
<script setup>
|
|
116
65
|
|
|
66
|
+
import { ref, computed, onMounted } from 'vue';
|
|
67
|
+
import { useRoute } from 'vue-router';
|
|
68
|
+
import { callAdminForthApi } from '@/utils';
|
|
117
69
|
import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
|
|
118
|
-
|
|
119
|
-
import ValueRenderer from '@/components/ValueRenderer.vue';
|
|
120
|
-
import { useCoreStore } from '@/stores/core';
|
|
121
|
-
import { useModalStore } from '@/stores/modal';
|
|
122
|
-
import { getCustomComponent, checkAcessByAllowedActions } from '@/utils';
|
|
123
70
|
import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
|
|
124
|
-
import {
|
|
125
|
-
import
|
|
126
|
-
import {callAdminForthApi} from '@/utils';
|
|
127
|
-
import { showSuccesTost, showErrorTost } from '@/composables/useFrontendApi';
|
|
71
|
+
import { useCoreStore } from '@/stores/core';
|
|
72
|
+
import ValueRenderer from '@/components/ValueRenderer.vue';
|
|
128
73
|
|
|
129
74
|
|
|
130
75
|
const item = ref(null);
|
|
131
76
|
const route = useRoute();
|
|
132
|
-
const
|
|
133
|
-
const loading = ref(true);
|
|
134
|
-
|
|
135
|
-
console.log(route.params,'showWiev');
|
|
136
|
-
|
|
77
|
+
const loading = ref(false);
|
|
137
78
|
|
|
138
79
|
const coreStore = useCoreStore();
|
|
139
|
-
const modalStore = useModalStore();
|
|
140
80
|
|
|
141
81
|
onMounted(async () => {
|
|
142
82
|
loading.value = true;
|
|
143
|
-
await coreStore.
|
|
83
|
+
await coreStore.fetchColumns({
|
|
144
84
|
resourceId: route.params.resourceId
|
|
145
85
|
});
|
|
146
86
|
await coreStore.fetchRecord({
|
|
147
87
|
resourceId: route.params.resourceId,
|
|
148
88
|
primaryKey: route.params.primaryKey,
|
|
149
89
|
});
|
|
150
|
-
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'show');
|
|
151
90
|
loading.value = false;
|
|
152
91
|
});
|
|
153
92
|
|
|
154
|
-
|
|
155
|
-
const data = await window.adminforth.confirm({
|
|
156
|
-
message: 'Are you sure you want to delete this item?',
|
|
157
|
-
yes: 'Delete',
|
|
158
|
-
no: 'Cancel',
|
|
159
|
-
});
|
|
160
|
-
if (data) {
|
|
161
|
-
try {
|
|
162
|
-
const res = await callAdminForthApi({
|
|
163
|
-
path: '/delete_record',
|
|
164
|
-
method: 'POST',
|
|
165
|
-
body: {
|
|
166
|
-
resourceId: route.params.resourceId,
|
|
167
|
-
primaryKey: route.params.primaryKey,
|
|
168
|
-
}});
|
|
169
|
-
if (!res.error){
|
|
170
|
-
router.push({ name: 'resource-list', params: { resourceId: route.params.resourceId } });
|
|
171
|
-
showSuccesTost('Record deleted successfully')
|
|
172
|
-
} else {
|
|
173
|
-
showErrorTost(res.error)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
} catch (e) {
|
|
177
|
-
console.error(e);
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
</script>
|
|
93
|
+
</script>
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
/** @type {import('tailwindcss').Config} */
|
|
2
2
|
export default {
|
|
3
|
-
content: ["./src/**/*.{vue, js
|
|
3
|
+
content: ["./src/**/*.{vue, js}", "./node_modules/flowbite/**/*.js"],
|
|
4
4
|
theme: {
|
|
5
|
-
extend: {
|
|
6
|
-
/* IMPORTANT:ADMINFORTH TAILWIND STYLES */
|
|
7
|
-
}
|
|
5
|
+
extend: {},
|
|
8
6
|
},
|
|
9
|
-
|
|
10
7
|
darkMode: 'class',
|
|
11
8
|
plugins: [
|
|
12
|
-
require('flowbite/plugin')
|
|
13
|
-
charts: true,
|
|
14
|
-
}),
|
|
9
|
+
require('flowbite/plugin'),
|
|
15
10
|
],
|
|
16
11
|
}
|
|
17
12
|
|
package/dist/spa/vite.config.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { fileURLToPath, URL } from 'node:url'
|
|
|
2
2
|
|
|
3
3
|
import { defineConfig } from 'vite'
|
|
4
4
|
import vue from '@vitejs/plugin-vue'
|
|
5
|
-
import { clear, error } from 'node:console';
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
const customLogger = {
|
|
@@ -12,12 +11,6 @@ const customLogger = {
|
|
|
12
11
|
console.log(msg);
|
|
13
12
|
}
|
|
14
13
|
},
|
|
15
|
-
warnOnce(msg: string) {
|
|
16
|
-
console.warn('warn once', msg);
|
|
17
|
-
if (!this.hasWarned) {
|
|
18
|
-
this.hasWarned = true;
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
14
|
warn(msg: string) {
|
|
22
15
|
console.warn(msg);
|
|
23
16
|
},
|
|
@@ -27,13 +20,7 @@ const customLogger = {
|
|
|
27
20
|
clear() {
|
|
28
21
|
console.clear();
|
|
29
22
|
},
|
|
30
|
-
clearScreen() {
|
|
31
|
-
console.clear();
|
|
32
|
-
},
|
|
33
23
|
hasWarned: false,
|
|
34
|
-
hasErrorLogged: (error: any): boolean => {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
24
|
};
|
|
38
25
|
|
|
39
26
|
// https://vitejs.dev/config/
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// typical types which AdminForth supports
|
|
2
|
+
//
|
|
3
|
+
export const AdminForthTypes = {
|
|
4
|
+
STRING: 'string',
|
|
5
|
+
INTEGER: 'integer',
|
|
6
|
+
FLOAT: 'float',
|
|
7
|
+
DECIMAL: 'decimal',
|
|
8
|
+
BOOLEAN: 'boolean',
|
|
9
|
+
DATE: 'date',
|
|
10
|
+
DATETIME: 'datetime',
|
|
11
|
+
TIME: 'time',
|
|
12
|
+
TEXT: 'text',
|
|
13
|
+
JSON: 'json',
|
|
14
|
+
};
|
|
15
|
+
export const AdminForthFilterOperators = {
|
|
16
|
+
EQ: 'eq',
|
|
17
|
+
NE: 'ne',
|
|
18
|
+
GT: 'gt',
|
|
19
|
+
LT: 'lt',
|
|
20
|
+
GTE: 'gte',
|
|
21
|
+
LTE: 'lte',
|
|
22
|
+
LIKE: 'like',
|
|
23
|
+
ILIKE: 'ilike',
|
|
24
|
+
IN: 'in',
|
|
25
|
+
NIN: 'nin',
|
|
26
|
+
};
|
|
27
|
+
export const AdminForthSortDirections = {
|
|
28
|
+
ASC: 'asc',
|
|
29
|
+
DESC: 'desc',
|
|
30
|
+
};
|
package/modules/restApi.ts
CHANGED
|
@@ -182,7 +182,18 @@ export default class AdminForthRestAPI {
|
|
|
182
182
|
throw new Error(`'visible' function of ${menuItem.label || menuItem.type } must return boolean value`);
|
|
183
183
|
}
|
|
184
184
|
return toReturn;
|
|
185
|
-
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function processMenuItem(menuItem) {
|
|
191
|
+
if (menuItem.badge) {
|
|
192
|
+
if (typeof menuItem.badge === 'function') {
|
|
193
|
+
menuItem.badge = menuItem.badge(adminUser);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
186
197
|
let newMenu = []
|
|
187
198
|
for (let menuItem of this.adminforth.config.menu) {
|
|
188
199
|
let newMenuItem = {...menuItem,}
|
|
@@ -200,10 +211,12 @@ export default class AdminForthRestAPI {
|
|
|
200
211
|
continue
|
|
201
212
|
}
|
|
202
213
|
}
|
|
214
|
+
processMenuItem(newChild)
|
|
203
215
|
newChildren.push(newChild)
|
|
204
216
|
}
|
|
205
217
|
newMenuItem = {...newMenuItem, children: newChildren}
|
|
206
218
|
}
|
|
219
|
+
processMenuItem(newMenuItem)
|
|
207
220
|
newMenu.push(newMenuItem)
|
|
208
221
|
}
|
|
209
222
|
|
package/package.json
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
>
|
|
13
13
|
<component v-if="item.icon" :is="getIcon(item.icon)" class="w-5 h-5 text-lightSidebarIcons dark:text-darkSidebarIcons transition duration-75 group-hover:text-lightSidebarIconsHover dark:group-hover:text-darkSidebarIconsHover" ></component>
|
|
14
14
|
<span class="ms-3">{{ item.label }}</span>
|
|
15
|
+
<span v-if="item.badge" class="inline-flex items-center justify-center w-3 h-3 p-3 ms-3 text-sm font-medium rounded-full bg-lightAnnouncementBG dark:bg-darkAnnouncementBG
|
|
16
|
+
fill-lightAnnouncementText dark:fill-darkAccent text-lightAnnouncementText dark:text-darkAccent">{{ item.badge }}</span>
|
|
17
|
+
|
|
15
18
|
</RouterLink>
|
|
16
19
|
</template>
|
|
17
20
|
|
|
@@ -469,6 +469,12 @@ export type AdminForthConfigMenuItem = {
|
|
|
469
469
|
* You can use it to hide menu items depending on some user
|
|
470
470
|
*/
|
|
471
471
|
visible?: (user: AdminUser) => boolean,
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Optional callback which will be called before rendering the menu for each item.
|
|
475
|
+
* Result of callback if not null will be used as a small badge near the menu item.
|
|
476
|
+
*/
|
|
477
|
+
badge?: string | ((user: AdminUser) => string),
|
|
472
478
|
}
|
|
473
479
|
|
|
474
480
|
|