adminforth 1.4.3-next.8 → 1.5.1
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/basePlugin.d.ts.map +1 -1
- package/dist/basePlugin.js +2 -3
- package/dist/basePlugin.js.map +1 -1
- package/dist/dataConnectors/postgres.d.ts.map +1 -1
- package/dist/dataConnectors/postgres.js +29 -9
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dataConnectors/sqlite.d.ts.map +1 -1
- package/dist/dataConnectors/sqlite.js +12 -5
- package/dist/dataConnectors/sqlite.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts +4 -2
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +98 -79
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +5 -4
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/operationalResource.d.ts.map +1 -1
- package/dist/modules/operationalResource.js.map +1 -1
- package/dist/modules/restApi.d.ts +8 -3
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +112 -39
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/socketBroker.d.ts +16 -0
- package/dist/modules/socketBroker.d.ts.map +1 -0
- package/dist/modules/socketBroker.js +99 -0
- package/dist/modules/socketBroker.js.map +1 -0
- package/dist/modules/utils.d.ts +2 -1
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +5 -2
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/common.d.ts +21 -0
- package/dist/servers/common.d.ts.map +1 -0
- package/dist/servers/common.js +13 -0
- package/dist/servers/common.js.map +1 -0
- package/dist/servers/express.d.ts +5 -0
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +54 -7
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/package-lock.json +59 -0
- package/dist/spa/package.json +1 -0
- package/dist/spa/src/App.vue +58 -36
- package/dist/spa/src/afcl/Button.vue +8 -1
- package/dist/spa/src/afcl/Input.vue +41 -0
- package/dist/spa/src/afcl/LinkButton.vue +23 -0
- package/dist/spa/src/afcl/Select.vue +8 -7
- package/dist/spa/src/afcl/index.ts +3 -0
- package/dist/spa/src/components/Filters.vue +0 -1
- package/dist/spa/src/components/GroupsTable.vue +4 -4
- package/dist/spa/src/components/ResourceListTable.vue +21 -21
- package/dist/spa/src/components/ValueRenderer.vue +3 -1
- package/dist/spa/src/composables/useStores.ts +4 -1
- package/dist/spa/src/renderers/CompactField.vue +4 -4
- package/dist/spa/src/renderers/CompactUUID.vue +4 -4
- package/dist/spa/src/renderers/CountryFlag.vue +3 -3
- package/dist/spa/src/renderers/HumanNumber.vue +5 -4
- package/dist/spa/src/renderers/RelativeTime.vue +5 -4
- package/dist/spa/src/router/index.ts +2 -0
- package/dist/spa/src/stores/core.ts +39 -6
- package/dist/spa/src/types/Back.ts +102 -9
- package/dist/spa/src/types/Common.ts +6 -1
- package/dist/spa/src/types/FrontendAPI.ts +7 -0
- package/dist/spa/src/views/EditView.vue +1 -0
- package/dist/spa/src/views/ListView.vue +2 -2
- package/dist/spa/src/views/LoginView.vue +7 -7
- package/dist/spa/src/views/PageNotFound.vue +20 -0
- package/dist/spa/src/views/ResourceParent.vue +0 -1
- package/dist/spa/src/views/ShowView.vue +1 -0
- package/dist/spa/src/websocket.ts +84 -0
- package/dist/spa/vite.config.ts +16 -34
- package/dist/types/Back.d.ts +70 -4
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +4 -0
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/FrontendAPI.d.ts +6 -0
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/package.json +5 -3
- package/dist/plugins/audit-log/types.d.ts +0 -35
- package/dist/plugins/audit-log/types.d.ts.map +0 -1
- package/dist/plugins/audit-log/types.js +0 -2
- package/dist/plugins/audit-log/types.js.map +0 -1
- package/dist/plugins/chat-gpt/types.d.ts +0 -82
- package/dist/plugins/chat-gpt/types.d.ts.map +0 -1
- package/dist/plugins/chat-gpt/types.js +0 -2
- package/dist/plugins/chat-gpt/types.js.map +0 -1
- package/dist/plugins/email-password-reset/types.d.ts +0 -28
- package/dist/plugins/email-password-reset/types.d.ts.map +0 -1
- package/dist/plugins/email-password-reset/types.js +0 -2
- package/dist/plugins/email-password-reset/types.js.map +0 -1
- package/dist/plugins/foreign-inline-list/types.d.ts +0 -19
- package/dist/plugins/foreign-inline-list/types.d.ts.map +0 -1
- package/dist/plugins/foreign-inline-list/types.js +0 -2
- package/dist/plugins/foreign-inline-list/types.js.map +0 -1
- package/dist/plugins/import-export/types.d.ts +0 -3
- package/dist/plugins/import-export/types.d.ts.map +0 -1
- package/dist/plugins/import-export/types.js +0 -2
- package/dist/plugins/import-export/types.js.map +0 -1
- package/dist/plugins/rich-editor/custom/async-queue.d.ts +0 -8
- package/dist/plugins/rich-editor/custom/async-queue.d.ts.map +0 -1
- package/dist/plugins/rich-editor/custom/async-queue.js +0 -29
- package/dist/plugins/rich-editor/custom/async-queue.js.map +0 -1
- package/dist/plugins/rich-editor/dist/custom/async-queue.d.ts +0 -8
- package/dist/plugins/rich-editor/dist/custom/async-queue.d.ts.map +0 -1
- package/dist/plugins/rich-editor/dist/custom/async-queue.js +0 -29
- package/dist/plugins/rich-editor/dist/custom/async-queue.js.map +0 -1
- package/dist/plugins/rich-editor/types.d.ts +0 -153
- package/dist/plugins/rich-editor/types.d.ts.map +0 -1
- package/dist/plugins/rich-editor/types.js +0 -16
- package/dist/plugins/rich-editor/types.js.map +0 -1
- package/dist/plugins/two-factors-auth/types.d.ts +0 -18
- package/dist/plugins/two-factors-auth/types.d.ts.map +0 -1
- package/dist/plugins/two-factors-auth/types.js +0 -2
- package/dist/plugins/two-factors-auth/types.js.map +0 -1
- package/dist/plugins/upload/types.d.ts +0 -132
- package/dist/plugins/upload/types.d.ts.map +0 -1
- package/dist/plugins/upload/types.js +0 -2
- package/dist/plugins/upload/types.js.map +0 -1
- package/dist/spa/src/acl/Button.vue +0 -21
- package/dist/spa/src/acl/Link.vue +0 -9
- package/dist/spa/src/components/Dropdown.vue +0 -167
- package/dist/spa/src/types/AdminForthConfig.js +0 -150
- package/dist/spa/src/types/AdminForthConfig.ts +0 -1816
- package/dist/spa/src/types/Commons.ts +0 -702
- package/dist/spa/src/types/FrontAndBack.ts +0 -698
- package/dist/types/AdminForthConfig.d.ts +0 -1665
- package/dist/types/AdminForthConfig.d.ts.map +0 -1
- package/dist/types/AdminForthConfig.js +0 -146
- package/dist/types/AdminForthConfig.js.map +0 -1
- package/dist/types/Commons.d.ts +0 -616
- package/dist/types/Commons.d.ts.map +0 -1
- package/dist/types/Commons.js +0 -65
- package/dist/types/Commons.js.map +0 -1
- package/dist/types/FrontAndBack.d.ts +0 -613
- package/dist/types/FrontAndBack.d.ts.map +0 -1
- package/dist/types/FrontAndBack.js +0 -62
- package/dist/types/FrontAndBack.js.map +0 -1
- /package/dist/spa/src/{components/AfTooltip.vue → afcl/Tooltip.vue} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<router-link
|
|
3
|
+
v-bind="$attrs"
|
|
4
|
+
type="submit"
|
|
5
|
+
class="flex items-center justify-center gap-1 text-lightPrimaryContrast bg-lightPrimary dark:bg-darkPrimary hover:brightness-110
|
|
6
|
+
focus:ring-4 focus:outline-none focus:ring-lightPrimary focus:ring-opacity-50 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:focus:ring-darkPrimary dark:focus:ring-opacity-50"
|
|
7
|
+
:class="{
|
|
8
|
+
'cursor-default': props.disabled,
|
|
9
|
+
'opacity-50': props.disabled,
|
|
10
|
+
'pointer-events-none': props.disabled,
|
|
11
|
+
}"
|
|
12
|
+
>
|
|
13
|
+
<slot></slot>
|
|
14
|
+
</router-link>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
|
|
19
|
+
const props = defineProps({
|
|
20
|
+
disabled: Boolean,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
</script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
v-model="search"
|
|
7
7
|
@click="inputClick"
|
|
8
8
|
@input="inputInput"
|
|
9
|
-
class="block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md leading-5 bg-
|
|
9
|
+
class="block w-full pl-3 pr-10 py-2.5 border border-gray-300 rounded-md leading-5 bg-gray-50 placeholder-gray-500 sm:text-sm transition duration-150 ease-in-out dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
|
|
10
10
|
:placeholder="
|
|
11
11
|
selectedItems.length && !multiple ? '' : (showDropdown ? 'Search' : placeholder || 'Select...')
|
|
12
12
|
"
|
|
@@ -24,11 +24,12 @@
|
|
|
24
24
|
|
|
25
25
|
<div class="absolute inset-y-0 right-2 flex items-center pointer-events-none">
|
|
26
26
|
<!-- triangle icon -->
|
|
27
|
-
<IconCaretDownSolid
|
|
28
|
-
|
|
27
|
+
<IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-gray-400 opacity-50 transition duration-150 ease-in"
|
|
28
|
+
:class="{ 'transform rotate-180': showDropdown }"
|
|
29
|
+
/>
|
|
29
30
|
</div>
|
|
30
31
|
</div>
|
|
31
|
-
<div v-if="showDropdown" class="absolute z-10 mt-1 w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700 dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
|
|
32
|
+
<div v-if="showDropdown" class="absolute z-10 mt-1 w-full bg-white shadow-lg dark:shadow-black dark:bg-gray-700 dark:border-gray-600 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm max-h-96">
|
|
32
33
|
<div
|
|
33
34
|
v-for="item in filteredItems"
|
|
34
35
|
:key="item.value"
|
|
@@ -74,8 +75,8 @@
|
|
|
74
75
|
</template>
|
|
75
76
|
|
|
76
77
|
<script setup lang="ts">
|
|
77
|
-
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
|
78
|
-
import { IconCaretDownSolid
|
|
78
|
+
import { ref, computed, onMounted, onUnmounted, watch, type Ref } from 'vue';
|
|
79
|
+
import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
|
|
79
80
|
|
|
80
81
|
|
|
81
82
|
const props = defineProps({
|
|
@@ -98,7 +99,7 @@ const emit = defineEmits(['update:modelValue']);
|
|
|
98
99
|
const search = ref('');
|
|
99
100
|
const showDropdown = ref(false);
|
|
100
101
|
|
|
101
|
-
const selectedItems = ref([]);
|
|
102
|
+
const selectedItems: Ref<any[]> = ref([]);
|
|
102
103
|
|
|
103
104
|
function inputInput() {
|
|
104
105
|
if (!props.multiple && selectedItems.value.length) {
|
|
@@ -3,3 +3,6 @@
|
|
|
3
3
|
export { default as Select } from './Select.vue';
|
|
4
4
|
export { default as Link } from './Link.vue';
|
|
5
5
|
export { default as Button } from './Button.vue';
|
|
6
|
+
export { default as Input } from './Input.vue';
|
|
7
|
+
export { default as Tooltip } from './Tooltip.vue';
|
|
8
|
+
export { default as LinkButton } from './LinkButton.vue';
|
|
@@ -121,7 +121,6 @@
|
|
|
121
121
|
|
|
122
122
|
<script setup>
|
|
123
123
|
import { watch, computed } from 'vue'
|
|
124
|
-
import Dropdown from '@/components/Dropdown.vue';
|
|
125
124
|
import CustomDateRangePicker from '@/components/CustomDateRangePicker.vue';
|
|
126
125
|
import { callAdminForthApi } from '@/utils';
|
|
127
126
|
import { useRouter } from 'vue-router';
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
:key="column.name"
|
|
21
21
|
v-if="currentValues !== null"
|
|
22
22
|
class="bg-ligftForm dark:bg-gray-800 dark:border-gray-700 block md:table-row"
|
|
23
|
-
:class="{ 'border-b': i !== group.columns.length - 1 }"
|
|
23
|
+
:class="{ 'border-b': i !== group.columns.length - 1, 'opacity-50 pointer-events-none': column.editReadonly && source === 'edit'}"
|
|
24
24
|
>
|
|
25
25
|
<td class="px-6 py-4 flex items-center block md:table-cell pb-0 md:pb-4"
|
|
26
26
|
:class="{'rounded-bl-lg border-b-none': i === group.columns.length - 1}"> <!--align-top-->
|
|
27
27
|
<span class="flex items-center gap-1">
|
|
28
28
|
{{ column.label }}
|
|
29
|
-
<
|
|
29
|
+
<Tooltip v-if="column.required[mode]">
|
|
30
30
|
|
|
31
31
|
<IconExclamationCircleSolid v-if="column.required[mode]" class="w-4 h-4"
|
|
32
32
|
:class="(columnError(column) && validating) ? 'text-red-500 dark:text-red-400' : 'text-gray-400 dark:text-gray-500'"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
<template #tooltip>
|
|
36
36
|
Required field
|
|
37
37
|
</template>
|
|
38
|
-
</
|
|
38
|
+
</Tooltip>
|
|
39
39
|
</span>
|
|
40
40
|
|
|
41
41
|
|
|
@@ -154,8 +154,8 @@
|
|
|
154
154
|
import { IconExclamationCircleSolid, IconEyeSlashSolid, IconEyeSolid } from '@iconify-prerendered/vue-flowbite';
|
|
155
155
|
import CustomDatePicker from "@/components/CustomDatePicker.vue";
|
|
156
156
|
import Select from '@/afcl/Select.vue';
|
|
157
|
-
import AfTooltip from "./AfTooltip.vue";
|
|
158
157
|
import { getCustomComponent } from '@/utils';
|
|
158
|
+
import { Tooltip } from '@/afcl';
|
|
159
159
|
|
|
160
160
|
|
|
161
161
|
const props = defineProps({
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
</td>
|
|
110
110
|
<td class=" items-center px-2 md:px-3 lg:px-6 py-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
|
|
111
111
|
<div class="flex text-lightPrimary dark:text-darkPrimary items-center">
|
|
112
|
-
<
|
|
112
|
+
<Tooltip>
|
|
113
113
|
<RouterLink
|
|
114
114
|
v-if="resource.options?.allowedActions.show"
|
|
115
115
|
:to="{
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
<template v-slot:tooltip>
|
|
128
128
|
Show item
|
|
129
129
|
</template>
|
|
130
|
-
</
|
|
130
|
+
</Tooltip>
|
|
131
131
|
|
|
132
|
-
<
|
|
132
|
+
<Tooltip>
|
|
133
133
|
<RouterLink
|
|
134
134
|
v-if="resource.options?.allowedActions.edit"
|
|
135
135
|
:to="{
|
|
@@ -145,9 +145,9 @@
|
|
|
145
145
|
<template v-slot:tooltip>
|
|
146
146
|
Edit item
|
|
147
147
|
</template>
|
|
148
|
-
</
|
|
148
|
+
</Tooltip>
|
|
149
149
|
|
|
150
|
-
<
|
|
150
|
+
<Tooltip>
|
|
151
151
|
<button
|
|
152
152
|
v-if="resource.options?.allowedActions.delete"
|
|
153
153
|
@click="deleteRecord(row)"
|
|
@@ -158,11 +158,11 @@
|
|
|
158
158
|
<template v-slot:tooltip>
|
|
159
159
|
Delete item
|
|
160
160
|
</template>
|
|
161
|
-
</
|
|
161
|
+
</Tooltip>
|
|
162
162
|
|
|
163
|
-
<template v-if="
|
|
163
|
+
<template v-if="customActionsInjection">
|
|
164
164
|
<component
|
|
165
|
-
v-for="c in
|
|
165
|
+
v-for="c in customActionsInjection"
|
|
166
166
|
:is="getCustomComponent(c)"
|
|
167
167
|
:meta="c.meta"
|
|
168
168
|
:resource="coreStore.resource"
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
</div>
|
|
245
245
|
</template>
|
|
246
246
|
|
|
247
|
-
<script setup>
|
|
247
|
+
<script setup lang="ts">
|
|
248
248
|
|
|
249
249
|
|
|
250
250
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
@@ -266,21 +266,21 @@ import {
|
|
|
266
266
|
IconTrashBinSolid
|
|
267
267
|
} from '@iconify-prerendered/vue-flowbite';
|
|
268
268
|
import router from '@/router';
|
|
269
|
-
import
|
|
269
|
+
import { Tooltip } from '@/afcl';
|
|
270
270
|
|
|
271
271
|
const coreStore = useCoreStore();
|
|
272
272
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
273
|
+
const props = defineProps<{
|
|
274
|
+
page: number,
|
|
275
|
+
resource: any,
|
|
276
|
+
rows: any[] | null,
|
|
277
|
+
totalRows: number,
|
|
278
|
+
pageSize: number,
|
|
279
|
+
checkboxes: any[],
|
|
280
|
+
sort: any[],
|
|
281
|
+
noRoundings?: boolean,
|
|
282
|
+
customActionsInjection?: any[],
|
|
283
|
+
}>();
|
|
284
284
|
|
|
285
285
|
// emits, update page
|
|
286
286
|
const emits = defineEmits([
|
|
@@ -29,9 +29,11 @@
|
|
|
29
29
|
<span v-else-if="column.type === 'richtext'">
|
|
30
30
|
<div v-html="protectAgainstXSS(record[column.name])" class="allow-lists"></div>
|
|
31
31
|
</span>
|
|
32
|
+
<span v-else-if="column.type === 'decimal'">
|
|
33
|
+
{{ checkEmptyValues(record[column.name] && parseFloat(record[column.name]), route.meta.type) }}
|
|
34
|
+
</span>
|
|
32
35
|
<span v-else-if="column.type === 'json'">
|
|
33
36
|
<JsonViewer :value="record[column.name]" :expandDepth="column.extra?.jsonCollapsedLevel" copyable sort :theme="coreStore.theme" />
|
|
34
|
-
|
|
35
37
|
</span>
|
|
36
38
|
<span v-else>
|
|
37
39
|
{{ checkEmptyValues(record[column.name],route.meta.type) }}
|
|
@@ -50,7 +50,10 @@ export class FrontendAPI {
|
|
|
50
50
|
setFilter: () => this.setListFilter.bind(this),
|
|
51
51
|
updateFilter: () => this.updateListFilter.bind(this),
|
|
52
52
|
clearFilters: () => this.clearListFilters.bind(this),
|
|
53
|
-
}
|
|
53
|
+
},
|
|
54
|
+
menu: {
|
|
55
|
+
refreshMenuBadges: () => {/* will be redefined */}
|
|
56
|
+
},
|
|
54
57
|
};
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Tooltip>
|
|
3
3
|
<span class="flex items-center">
|
|
4
4
|
{{ visualValue }} <IconFileCopyAltSolid @click.stop="copyToCB" class="w-5 h-5 text-lightPrimary dark:text-darkPrimary" v-if="visualValue"/>
|
|
5
5
|
</span>
|
|
6
6
|
<template #tooltip v-if="visualValue">
|
|
7
7
|
{{ props.record[props.column.name] }}
|
|
8
8
|
</template>
|
|
9
|
-
</
|
|
9
|
+
</Tooltip>
|
|
10
10
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<script setup>
|
|
14
14
|
import { computed, ref, onMounted, nextTick } from 'vue';
|
|
15
15
|
import { IconFileCopyAltSolid } from '@iconify-prerendered/vue-flowbite';
|
|
16
|
-
import
|
|
16
|
+
import Tooltip from '@/afcl/Tooltip.vue';
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
const visualValue = computed(() => {
|
|
@@ -25,7 +25,7 @@ const visualValue = computed(() => {
|
|
|
25
25
|
return val;
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const props = defineProps(['column', 'record', 'meta']);
|
|
28
|
+
const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
|
|
29
29
|
|
|
30
30
|
const id = ref();
|
|
31
31
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Tooltip>
|
|
3
3
|
<span class="flex items-center">
|
|
4
4
|
{{ visualValue }} <IconFileCopyAltSolid @click.stop="copyToCB" class="w-5 h-5 text-lightPrimary dark:text-darkPrimary" v-if="visualValue"/>
|
|
5
5
|
</span>
|
|
6
6
|
<template #tooltip v-if="visualValue">
|
|
7
7
|
{{ props.record[props.column.name] }}
|
|
8
8
|
</template>
|
|
9
|
-
</
|
|
9
|
+
</Tooltip>
|
|
10
10
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<script setup>
|
|
14
14
|
import { computed, ref, onMounted, nextTick } from 'vue';
|
|
15
15
|
import { IconFileCopyAltSolid } from '@iconify-prerendered/vue-flowbite';
|
|
16
|
-
import
|
|
16
|
+
import Tooltip from '@/afcl/Tooltip.vue';
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
const visualValue = computed(() => {
|
|
@@ -25,7 +25,7 @@ const visualValue = computed(() => {
|
|
|
25
25
|
return val;
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const props = defineProps(['column', 'record', 'meta']);
|
|
28
|
+
const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
|
|
29
29
|
|
|
30
30
|
const id = ref();
|
|
31
31
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Tooltip>
|
|
3
3
|
<span class="flex items-center">
|
|
4
4
|
<span
|
|
5
5
|
:class="{[`fi-${countryIsoLow}`]: true, 'flag-icon': countryName}"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<template v-if="shouldShowTooltip" #tooltip>
|
|
11
11
|
{{ countryName }}
|
|
12
12
|
</template>
|
|
13
|
-
</
|
|
13
|
+
</Tooltip>
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script setup>
|
|
@@ -19,7 +19,7 @@ import { computed, ref, onMounted } from 'vue';
|
|
|
19
19
|
import 'flag-icons/css/flag-icons.min.css';
|
|
20
20
|
import isoCountries from 'i18n-iso-countries';
|
|
21
21
|
import enLocal from 'i18n-iso-countries/langs/en.json';
|
|
22
|
-
import
|
|
22
|
+
import Tooltip from '@/afcl/Tooltip.vue';
|
|
23
23
|
|
|
24
24
|
isoCountries.registerLocale(enLocal);
|
|
25
25
|
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Tooltip>
|
|
3
3
|
{{ formattedValue }}
|
|
4
4
|
<template #tooltip v-if="formattedValue">
|
|
5
5
|
{{ formattedTooltipValue }}
|
|
6
6
|
</template>
|
|
7
|
-
</
|
|
7
|
+
</Tooltip>
|
|
8
8
|
</template>
|
|
9
9
|
|
|
10
10
|
<script setup>
|
|
11
11
|
import { computed, ref, onMounted, nextTick } from 'vue';
|
|
12
|
-
import
|
|
12
|
+
import Tooltip from '@/afcl/Tooltip.vue';
|
|
13
13
|
|
|
14
|
-
const props = defineProps(['column', 'record']);
|
|
14
|
+
const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
|
|
15
|
+
|
|
15
16
|
const id = ref();
|
|
16
17
|
const userLocale = ref(navigator.language || 'en-US');
|
|
17
18
|
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Tooltip>
|
|
3
3
|
{{ relativeTime }}
|
|
4
4
|
<template #tooltip v-if="relativeTime">
|
|
5
5
|
{{ fullTime }}
|
|
6
6
|
</template>
|
|
7
|
-
</
|
|
7
|
+
</Tooltip>
|
|
8
8
|
</template>
|
|
9
9
|
|
|
10
10
|
<script setup>
|
|
11
11
|
import { computed, ref, onMounted } from 'vue';
|
|
12
|
-
import
|
|
12
|
+
import Tooltip from '@/afcl/Tooltip.vue';
|
|
13
13
|
import en from 'javascript-time-ago/locale/en';
|
|
14
14
|
import TimeAgo from 'javascript-time-ago';
|
|
15
15
|
import dayjs from 'dayjs';
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
const id = ref();
|
|
18
19
|
|
|
19
20
|
TimeAgo.addLocale(en);
|
|
20
21
|
|
|
21
|
-
const props = defineProps(['column', 'record']);
|
|
22
|
+
const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
|
|
22
23
|
|
|
23
24
|
const userLocale = ref(navigator.language || 'en-US');
|
|
24
25
|
const timeAgoFormatter = new TimeAgo(userLocale.value);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRouter, createWebHistory } from 'vue-router';
|
|
2
2
|
import ResourceParent from '@/views/ResourceParent.vue';
|
|
3
|
+
import PageNotFound from '@/views/PageNotFound.vue';
|
|
3
4
|
|
|
4
5
|
/* IMPORTANT:ADMINFORTH ROUTES IMPORTS */
|
|
5
6
|
|
|
@@ -53,6 +54,7 @@ const router = createRouter({
|
|
|
53
54
|
]
|
|
54
55
|
},
|
|
55
56
|
/* IMPORTANT:ADMINFORTH ROUTES */
|
|
57
|
+
{ path: "/:pathMatch(.*)*", component: PageNotFound },
|
|
56
58
|
]
|
|
57
59
|
})
|
|
58
60
|
|
|
@@ -3,6 +3,7 @@ import { defineStore } from 'pinia'
|
|
|
3
3
|
import { callAdminForthApi } from '@/utils';
|
|
4
4
|
import type { AdminForthResourceCommon, AdminForthResourceColumnCommon } from '@/types/Common';
|
|
5
5
|
import type { Ref } from 'vue'
|
|
6
|
+
import type { AdminForthConfigMenuItem } from '@/types/Back';
|
|
6
7
|
|
|
7
8
|
export const useCoreStore = defineStore('core', () => {
|
|
8
9
|
const resourceById: Ref<Object> = ref({});
|
|
@@ -12,6 +13,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
12
13
|
const config = ref({});
|
|
13
14
|
const record: Ref<any | null> = ref({});
|
|
14
15
|
const resource: Ref<AdminForthResourceCommon | null> = ref(null);
|
|
16
|
+
const userData = ref(null);
|
|
15
17
|
|
|
16
18
|
const resourceColumnsWithFilters = computed(() => {
|
|
17
19
|
if (!resource.value) {
|
|
@@ -52,11 +54,42 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
52
54
|
return acc;
|
|
53
55
|
}, {});
|
|
54
56
|
config.value = resp.config;
|
|
55
|
-
adminUser.value = resp.
|
|
57
|
+
adminUser.value = resp.adminUser;
|
|
58
|
+
userData.value = resp.user;
|
|
56
59
|
console.log('🌍 AdminForth v', resp.version);
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
|
|
62
|
+
function findItemWithId(items: AdminForthConfigMenuItem[], _itemId: string): AdminForthConfigMenuItem | undefined {
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
if (item._itemId === _itemId) {
|
|
65
|
+
return item;
|
|
66
|
+
}
|
|
67
|
+
if (item.children) {
|
|
68
|
+
const found = findItemWithId(item.children, _itemId);
|
|
69
|
+
if (found) {
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function fetchMenuBadges() {
|
|
76
|
+
const resp: Record<string, string> = await callAdminForthApi({
|
|
77
|
+
path: '/get_menu_badges',
|
|
78
|
+
method: 'GET',
|
|
79
|
+
});
|
|
80
|
+
if (!resp) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
Object.entries(resp).forEach(([_itemId, badge]: [string, string]) => {
|
|
84
|
+
const item: AdminForthConfigMenuItem | undefined = findItemWithId(menu.value, _itemId);
|
|
85
|
+
if (item) {
|
|
86
|
+
item.badge = badge;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
async function fetchRecord({ resourceId, primaryKey, source }: { resourceId: string, primaryKey: string, source: string }) {
|
|
60
93
|
record.value = null;
|
|
61
94
|
|
|
62
95
|
if (!resource.value) {
|
|
@@ -71,7 +104,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
71
104
|
path: '/get_resource_data',
|
|
72
105
|
method: 'POST',
|
|
73
106
|
body: {
|
|
74
|
-
source:
|
|
107
|
+
source: source,
|
|
75
108
|
resourceId: resourceId,
|
|
76
109
|
filters: [
|
|
77
110
|
{
|
|
@@ -130,16 +163,15 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
130
163
|
config.value = {...config.value, ...res};
|
|
131
164
|
}
|
|
132
165
|
|
|
133
|
-
|
|
134
166
|
|
|
135
167
|
const username = computed(() => {
|
|
136
168
|
const usernameField = config.value.usernameField;
|
|
137
|
-
return
|
|
169
|
+
return userData.value && userData.value[usernameField];
|
|
138
170
|
});
|
|
139
171
|
|
|
140
172
|
const userFullname = computed(() => {
|
|
141
173
|
const userFullnameField = config.value.userFullnameField;
|
|
142
|
-
return
|
|
174
|
+
return userData.value && userData.value[userFullnameField];
|
|
143
175
|
})
|
|
144
176
|
|
|
145
177
|
|
|
@@ -161,5 +193,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
161
193
|
resourceColumnsWithFilters,
|
|
162
194
|
toggleTheme,
|
|
163
195
|
theme,
|
|
196
|
+
fetchMenuBadges,
|
|
164
197
|
}
|
|
165
198
|
})
|