adminforth 2.4.0-next.1 → 2.4.0-next.100
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/commands/callTsProxy.js +14 -4
- package/commands/cli.js +12 -4
- package/commands/createApp/templates/.env.local.hbs +2 -2
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +9 -5
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/utils.js +40 -7
- package/commands/createCustomComponent/configLoader.js +3 -0
- package/commands/createCustomComponent/configUpdater.js +25 -21
- package/commands/createCustomComponent/fileGenerator.js +1 -1
- package/commands/createCustomComponent/main.js +2 -1
- package/commands/createCustomComponent/templates/login/beforeLogin.vue.hbs +18 -0
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +16 -3
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +14 -14
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -9
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +25 -9
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +50 -2
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +145 -25
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +451 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +507 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +1 -0
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +9 -0
- package/dist/modules/utils.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/src/App.vue +24 -14
- package/dist/spa/src/afcl/Button.vue +6 -6
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +6 -6
- package/dist/spa/src/afcl/Dropzone.vue +13 -11
- package/dist/spa/src/afcl/Input.vue +9 -7
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/Link.vue +1 -1
- package/dist/spa/src/afcl/LinkButton.vue +1 -1
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +52 -23
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +13 -13
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +2 -2
- package/dist/spa/src/afcl/VerticalTabs.vue +3 -3
- package/dist/spa/src/afcl/index.ts +4 -3
- package/dist/spa/src/components/AcceptModal.vue +6 -6
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/ColumnValueInput.vue +37 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -8
- package/dist/spa/src/components/Filters.vue +76 -31
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +38 -40
- package/dist/spa/src/components/ResourceListTableVirtual.vue +31 -33
- package/dist/spa/src/components/ShowTable.vue +17 -12
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +1 -1
- package/dist/spa/src/components/ThreeDotsMenu.vue +34 -7
- package/dist/spa/src/components/Toast.vue +2 -7
- package/dist/spa/src/components/ValueRenderer.vue +4 -4
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +1 -1
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +7 -0
- package/dist/spa/src/stores/core.ts +1 -1
- package/dist/spa/src/types/Back.ts +84 -21
- package/dist/spa/src/types/Common.ts +26 -10
- package/dist/spa/src/types/adapters/CompletionAdapter.ts +25 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +27 -0
- package/dist/spa/src/types/adapters/ImageGenerationAdapter.ts +50 -0
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/OAuth2Adapter.ts +34 -0
- package/dist/spa/src/types/adapters/StorageAdapter.ts +73 -0
- package/dist/spa/src/types/adapters/index.ts +6 -0
- package/dist/spa/src/utils.ts +217 -7
- package/dist/spa/src/views/CreateView.vue +21 -16
- package/dist/spa/src/views/EditView.vue +29 -19
- package/dist/spa/src/views/ListView.vue +51 -49
- package/dist/spa/src/views/LoginView.vue +57 -45
- package/dist/spa/src/views/ResourceParent.vue +1 -1
- package/dist/spa/src/views/ShowView.vue +17 -13
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +44 -1
- package/dist/types/Back.d.ts +63 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +24 -8
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/adapters/CompletionAdapter.d.ts +20 -0
- package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CompletionAdapter.js +2 -0
- package/dist/types/adapters/CompletionAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +20 -0
- package/dist/types/adapters/EmailAdapter.d.ts.map +1 -0
- package/dist/types/adapters/EmailAdapter.js +2 -0
- package/dist/types/adapters/EmailAdapter.js.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts +37 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.js +2 -0
- package/dist/types/adapters/ImageGenerationAdapter.js.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/OAuth2Adapter.d.ts +32 -0
- package/dist/types/adapters/OAuth2Adapter.d.ts.map +1 -0
- package/dist/types/adapters/OAuth2Adapter.js +2 -0
- package/dist/types/adapters/OAuth2Adapter.js.map +1 -0
- package/dist/types/adapters/StorageAdapter.d.ts +63 -0
- package/dist/types/adapters/StorageAdapter.d.ts.map +1 -0
- package/dist/types/adapters/StorageAdapter.js +2 -0
- package/dist/types/adapters/StorageAdapter.js.map +1 -0
- package/dist/types/adapters/index.d.ts +7 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/index.js +2 -0
- package/dist/types/adapters/index.js.map +1 -0
- package/package.json +2 -2
- package/dist/spa/src/types/Adapters.ts +0 -213
- package/dist/types/Adapters.d.ts +0 -168
- package/dist/types/Adapters.d.ts.map +0 -1
- package/dist/types/Adapters.js +0 -2
- package/dist/types/Adapters.js.map +0 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
<div class="overflow-x-auto shadow-resourseFormShadow dark:shadow-darkResourseFormShadow"
|
|
3
|
+
:class="{'rounded-default' : isRounded}"
|
|
4
|
+
>
|
|
5
|
+
<div v-if="groupName && !noTitle" class="text-md font-semibold px-6 py-3 flex flex-1 items-center text-lightShowTableHeadingText bg-lightShowTableHeadingBackground dark:bg-darkShowTableHeadingBackground dark:text-darkShowTableHeadingText rounded-t-lg">
|
|
4
6
|
{{ groupName }}
|
|
5
7
|
</div>
|
|
6
|
-
<table class="w-full text-sm text-left rtl:text-right text-
|
|
7
|
-
<thead v-if="!allColumnsHaveCustomComponent" class="text-
|
|
8
|
+
<table class="w-full text-sm text-left rtl:text-right text-lightShowTableBodyText dark:text-darkShowTableBodyText table-fixed">
|
|
9
|
+
<thead v-if="!allColumnsHaveCustomComponent" class="text-lightShowTableUnderHeadingText dark:text-darkShowTableUnderHeadingText bg-lightShowTableUnderHeadingBackground dark:bg-darkShowTableUnderHeadingBackground dark:border-darkFormBorder block md:table-row-group">
|
|
8
10
|
<tr>
|
|
9
11
|
<th scope="col" class="px-6 py-3 text-xs uppercase hidden md:w-52 md:table-cell">
|
|
10
12
|
{{ $t('Field') }}
|
|
@@ -18,8 +20,8 @@
|
|
|
18
20
|
<tr
|
|
19
21
|
v-for="column in columns"
|
|
20
22
|
:key="column.name"
|
|
21
|
-
class="bg-
|
|
22
|
-
dark:bg-
|
|
23
|
+
class="bg-lightShowTablesBodyBackground border-t border-lightShowTableBodyBorder
|
|
24
|
+
dark:bg-darkShowTablesBodyBackground dark:border-darkShowTableBodyBorder block md:table-row"
|
|
23
25
|
>
|
|
24
26
|
<component
|
|
25
27
|
v-if="column.components?.showRow"
|
|
@@ -60,10 +62,11 @@
|
|
|
60
62
|
import { getCustomComponent } from '@/utils';
|
|
61
63
|
import { useCoreStore } from '@/stores/core';
|
|
62
64
|
import { computed } from 'vue';
|
|
63
|
-
|
|
65
|
+
import type { AdminForthResourceCommon } from '@/types/Common';
|
|
66
|
+
const props = withDefaults(defineProps<{
|
|
64
67
|
columns: Array<{
|
|
65
68
|
name: string;
|
|
66
|
-
label
|
|
69
|
+
label?: string;
|
|
67
70
|
components?: {
|
|
68
71
|
show?: {
|
|
69
72
|
file: string;
|
|
@@ -75,13 +78,15 @@
|
|
|
75
78
|
};
|
|
76
79
|
};
|
|
77
80
|
}>;
|
|
78
|
-
source: string;
|
|
79
81
|
groupName?: string | null;
|
|
80
82
|
noTitle?: boolean;
|
|
81
|
-
resource:
|
|
83
|
+
resource: AdminForthResourceCommon | null;
|
|
82
84
|
record: Record<string, any>;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
isRounded?: boolean;
|
|
86
|
+
}>(), {
|
|
87
|
+
isRounded: true
|
|
88
|
+
});
|
|
89
|
+
|
|
85
90
|
const coreStore = useCoreStore();
|
|
86
91
|
const allColumnsHaveCustomComponent = computed(() => {
|
|
87
92
|
return props.columns.every(column => {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
<div
|
|
3
3
|
role="status" class="max-w-sm animate-pulse"
|
|
4
4
|
>
|
|
5
|
-
<div class="h-2.5 bg-
|
|
6
|
-
<div class="h-2 bg-
|
|
7
|
-
<div class="h-2 bg-
|
|
8
|
-
<div class="h-2 bg-
|
|
9
|
-
<div class="h-2 bg-
|
|
10
|
-
<div class="h-2 bg-
|
|
5
|
+
<div class="h-2.5 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor w-48 mb-4"></div>
|
|
6
|
+
<div class="h-2 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor max-w-[360px] mb-2.5"></div>
|
|
7
|
+
<div class="h-2 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor mb-2.5"></div>
|
|
8
|
+
<div class="h-2 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor max-w-[330px] mb-2.5"></div>
|
|
9
|
+
<div class="h-2 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor max-w-[300px] mb-2.5"></div>
|
|
10
|
+
<div class="h-2 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor max-w-[360px]"></div>
|
|
11
11
|
<span class="sr-only">{{ $t('Loading...') }}</span>
|
|
12
12
|
</div>
|
|
13
13
|
</template>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
: '']"
|
|
13
13
|
>
|
|
14
14
|
<div role="status" class="max-w-sm animate-pulse">
|
|
15
|
-
<div class="h-2 bg-
|
|
15
|
+
<div class="h-2 bg-lightSkeletonBackgroundColor rounded-full dark:bg-darkSkeletonBackgroundColor max-w-[360px]"></div>
|
|
16
16
|
</div>
|
|
17
17
|
</td>
|
|
18
18
|
</tr>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template >
|
|
2
|
-
<template v-if="threeDotsDropdownItems?.length || customActions?.length">
|
|
2
|
+
<template v-if="threeDotsDropdownItems?.length || customActions?.length || (bulkActions?.some(action => action.showInThreeDotsDropdown))">
|
|
3
3
|
<button
|
|
4
4
|
data-dropdown-toggle="listThreeDotsDropdown"
|
|
5
|
-
class="flex items-center py-2 px-2 text-sm font-medium text-
|
|
5
|
+
class="flex items-center py-2 px-2 text-sm font-medium text-lightThreeDotsMenuIconDots focus:outline-none bg-lightThreeDotsMenuIconBackground rounded border border-lightThreeDotsMenuIconBackgroundBorder hover:bg-lightThreeDotsMenuIconBackgroundHover hover:text-lightThreeDotsMenuIconDotsHover focus:z-10 focus:ring-4 focus:ring-lightThreeDotsMenuIconFocus dark:focus:ring-darkThreeDotsMenuIconFocus dark:bg-darkThreeDotsMenuIconBackground dark:text-darkThreeDotsMenuIconDots dark:border-darkThreeDotsMenuIconBackgroundBorder dark:hover:text-darkThreeDotsMenuIconDotsHover dark:hover:bg-darkThreeDotsMenuIconBackgroundHover rounded-default"
|
|
6
6
|
>
|
|
7
7
|
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 4 15">
|
|
8
8
|
<path d="M3.5 1.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Zm0 6.041a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Zm0 5.959a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z"/>
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
<!-- Dropdown menu -->
|
|
13
13
|
<div
|
|
14
14
|
id="listThreeDotsDropdown"
|
|
15
|
-
class="z-20 hidden bg-
|
|
16
|
-
<ul class="py-2 text-sm text-
|
|
15
|
+
class="z-20 hidden bg-lightThreeDotsMenuBodyBackground divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-darkThreeDotsMenuBodyBackground dark:divide-gray-600">
|
|
16
|
+
<ul class="py-2 text-sm text-lightThreeDotsMenuBodyText dark:text-darkThreeDotsMenuBodyText" aria-labelledby="dropdownMenuIconButton">
|
|
17
17
|
<li v-for="item in threeDotsDropdownItems" :key="`dropdown-item-${item.label}`">
|
|
18
|
-
<a href="#" class="block px-4 py-2 hover:bg-
|
|
18
|
+
<a href="#" class="block px-4 py-2 hover:bg-lightThreeDotsMenuBodyBackgroundHover hover:text-lightThreeDotsMenuBodyTextHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover">
|
|
19
19
|
<component :is="getCustomComponent(item)"
|
|
20
20
|
:meta="item.meta"
|
|
21
21
|
:resource="coreStore.resource"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</a>
|
|
25
25
|
</li>
|
|
26
26
|
<li v-for="action in customActions" :key="action.id">
|
|
27
|
-
<a href="#" @click.prevent="handleActionClick(action)" class="block px-4 py-2 hover:bg-
|
|
27
|
+
<a href="#" @click.prevent="handleActionClick(action)" class="block px-4 py-2 hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover">
|
|
28
28
|
<div class="flex items-center gap-2">
|
|
29
29
|
<component
|
|
30
30
|
v-if="action.icon"
|
|
@@ -35,6 +35,24 @@
|
|
|
35
35
|
</div>
|
|
36
36
|
</a>
|
|
37
37
|
</li>
|
|
38
|
+
<li v-for="action in bulkActions.filter(a => a.showInThreeDotsDropdown)" :key="action.id">
|
|
39
|
+
<a href="#" @click.prevent="startBulkAction(action.id)"
|
|
40
|
+
class="block px-4 py-2 hover:text-lightThreeDotsMenuBodyTextHover hover:bg-lightThreeDotsMenuBodyBackgroundHover dark:hover:bg-darkThreeDotsMenuBodyBackgroundHover dark:hover:text-darkThreeDotsMenuBodyTextHover"
|
|
41
|
+
:class="{
|
|
42
|
+
'pointer-events-none': !checkboxes.length,
|
|
43
|
+
'opacity-50': !checkboxes.length,
|
|
44
|
+
'cursor-not-allowed': !checkboxes.length
|
|
45
|
+
}">
|
|
46
|
+
<div class="flex items-center gap-2">
|
|
47
|
+
<component
|
|
48
|
+
v-if="action.icon"
|
|
49
|
+
:is="getIcon(action.icon)"
|
|
50
|
+
class="w-4 h-4 text-lightPrimary dark:text-darkPrimary"
|
|
51
|
+
/>
|
|
52
|
+
{{ action.label }}
|
|
53
|
+
</div>
|
|
54
|
+
</a>
|
|
55
|
+
</li>
|
|
38
56
|
</ul>
|
|
39
57
|
</div>
|
|
40
58
|
</template>
|
|
@@ -54,9 +72,13 @@ const router = useRouter();
|
|
|
54
72
|
|
|
55
73
|
const props = defineProps({
|
|
56
74
|
threeDotsDropdownItems: Array,
|
|
57
|
-
customActions: Array
|
|
75
|
+
customActions: Array,
|
|
76
|
+
bulkActions: Array,
|
|
77
|
+
checkboxes: Array
|
|
58
78
|
});
|
|
59
79
|
|
|
80
|
+
const emit = defineEmits(['startBulkAction']);
|
|
81
|
+
|
|
60
82
|
async function handleActionClick(action) {
|
|
61
83
|
adminforth.list.closeThreeDotsDropdown();
|
|
62
84
|
|
|
@@ -108,4 +130,9 @@ async function handleActionClick(action) {
|
|
|
108
130
|
});
|
|
109
131
|
}
|
|
110
132
|
}
|
|
133
|
+
|
|
134
|
+
function startBulkAction(actionId) {
|
|
135
|
+
adminforth.list.closeThreeDotsDropdown();
|
|
136
|
+
emit('startBulkAction', actionId);
|
|
137
|
+
}
|
|
111
138
|
</script>
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
<div class="flex items-center w-full p-4
|
|
4
|
+
<div class="flex items-center w-full p-4 rounded-lg shadow-lg dark:text-darkToastText dark:bg-darkToastBackground bg-lightToastBackground text-lightToastText"
|
|
5
5
|
role="alert"
|
|
6
|
-
:class="
|
|
7
|
-
{
|
|
8
|
-
'danger': 'bg-red-100',
|
|
9
|
-
}[toast.variant]
|
|
10
|
-
"
|
|
11
6
|
>
|
|
12
7
|
<div v-if="toast.variant == 'info'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-lightPrimary dark:text-darkPrimary bg-lightPrimaryOpacity rounded-lg dark:bg-blue-800 dark:text-blue-200">
|
|
13
8
|
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
|
|
@@ -36,7 +31,7 @@
|
|
|
36
31
|
|
|
37
32
|
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
|
|
38
33
|
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-else>{{toast.message}}</div>
|
|
39
|
-
<button @click="closeToast" type="button" class="ms-auto -mx-1.5 -my-1.5 bg-
|
|
34
|
+
<button @click="closeToast" type="button" class="ms-auto -mx-1.5 -my-1.5 bg-lightToastCloseIconBackground text-lightToastCloseIcon hover:text-lightToastCloseIconHover rounded-lg focus:ring-2 focus:ring-lightToastCloseIconFocusRing p-1.5 hover:bg-lightToastCloseIconBackgroundHover inline-flex items-center justify-center h-8 w-8 dark:text-darkToastCloseIcon dark:hover:text-darkToastCloseIconHover dark:bg-darkToastCloseIconBackground dark:hover:bg-darkToastCloseIconBackgroundHover dark:focus:ring-darkToastCloseIconFocusRing" >
|
|
40
35
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
|
41
36
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
|
42
37
|
</svg>
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
</span>
|
|
28
28
|
|
|
29
29
|
<span v-else-if="column.type === 'boolean'">
|
|
30
|
-
<span v-if="record[column.name] === true" class="bg-green-100 whitespace-nowrap text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-green-400 border border-green-400">{{ $t('Yes') }}</span>
|
|
31
|
-
<span v-else-if="record[column.name] === false" class="bg-red-100 whitespace-nowrap text-red-
|
|
30
|
+
<span v-if="record[column.name] === true" class="af-true-value-icon bg-green-100 whitespace-nowrap text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-green-400 border border-green-400">{{ $t('Yes') }}</span>
|
|
31
|
+
<span v-else-if="record[column.name] === false" class="af-false-value-icon bg-red-100 whitespace-nowrap 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">{{ $t('No') }}</span>
|
|
32
32
|
<span v-else class="bg-gray-100 whitespace-nowrap text-gray-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-gray-400 border border-gray-400">{{ $t('Unset') }}</span>
|
|
33
33
|
</span>
|
|
34
34
|
<span
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
<span
|
|
40
40
|
v-if="column.isArray.itemType === 'boolean' && arrayItem"
|
|
41
41
|
:key="`${column.name}-${arrayItemIndex}`"
|
|
42
|
-
class="bg-green-100 whitespace-nowrap text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-green-400 border border-green-400">
|
|
42
|
+
class="af-true-value-icon bg-green-100 whitespace-nowrap text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-green-400 border border-green-400">
|
|
43
43
|
{{ $t('Yes') }}
|
|
44
44
|
</span>
|
|
45
45
|
<span
|
|
46
46
|
v-else-if="column.isArray.itemType === 'boolean'"
|
|
47
47
|
:key="`${column.name}-${arrayItemIndex}`"
|
|
48
|
-
class="bg-red-100 whitespace-nowrap 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">
|
|
48
|
+
class="af-false-value-icon bg-red-100 whitespace-nowrap 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">
|
|
49
49
|
{{ $t('No') }}
|
|
50
50
|
</span>
|
|
51
51
|
<span
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Toggle
|
|
3
|
+
:disabled="readonly"
|
|
4
|
+
@update:modelValue="$emit('update:value', $event)"
|
|
5
|
+
:modelValue="valueFromRecord"
|
|
6
|
+
>
|
|
7
|
+
<p>{{text}}</p>
|
|
8
|
+
</Toggle>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import Toggle from '@/afcl/Toggle.vue';
|
|
13
|
+
import type {
|
|
14
|
+
AdminForthResourceColumnCommon,
|
|
15
|
+
AdminForthResourceCommon,
|
|
16
|
+
AdminUser,
|
|
17
|
+
} from "@/types/Common";
|
|
18
|
+
|
|
19
|
+
const props = defineProps<{
|
|
20
|
+
value: boolean,
|
|
21
|
+
text: string,
|
|
22
|
+
column: AdminForthResourceColumnCommon,
|
|
23
|
+
record: any,
|
|
24
|
+
meta: any,
|
|
25
|
+
resource: AdminForthResourceCommon,
|
|
26
|
+
adminUser: AdminUser,
|
|
27
|
+
readonly: boolean
|
|
28
|
+
}>();
|
|
29
|
+
console.log(JSON.stringify(props));
|
|
30
|
+
console.log("Current mode:", props.meta?.mode)
|
|
31
|
+
defineEmits(['update:value']);
|
|
32
|
+
const valueFromRecord = props.record[props.column.name]
|
|
33
|
+
const editReadOnly = props.column.editReadonly;
|
|
34
|
+
</script>
|
package/dist/spa/src/i18n.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { createApp } from 'vue';
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
// taken from here https://vue-i18n.intlify.dev/guide/essentials/pluralization.html#custom-pluralization
|
|
6
|
-
function slavicPluralRule(choice, choicesLength, orgRule) {
|
|
6
|
+
function slavicPluralRule(choice: number, choicesLength: number, orgRule: any) {
|
|
7
7
|
if (choice === 0) {
|
|
8
8
|
return 0
|
|
9
9
|
}
|
|
@@ -21,6 +21,7 @@ export type ResourceColumns = {
|
|
|
21
21
|
|
|
22
22
|
export type CoreConfig = {
|
|
23
23
|
brandName: string,
|
|
24
|
+
singleTheme?: 'light' | 'dark',
|
|
24
25
|
brandLogo: string,
|
|
25
26
|
title: string,
|
|
26
27
|
datesFormat: string,
|
|
@@ -33,12 +34,18 @@ export type CoreConfig = {
|
|
|
33
34
|
passwordHashField: string,
|
|
34
35
|
loginBackgroundImage: string,
|
|
35
36
|
loginBackgroundPosition: string,
|
|
37
|
+
removeBackgroundBlendMode: boolean,
|
|
36
38
|
userFullnameField: string,
|
|
37
39
|
},
|
|
38
40
|
emptyFieldPlaceholder?: {
|
|
39
41
|
show?: string,
|
|
40
42
|
list?: string,
|
|
41
43
|
} | string,
|
|
44
|
+
|
|
45
|
+
customHeadItems?: {
|
|
46
|
+
tagName: string;
|
|
47
|
+
attributes: { [key: string]: string | boolean };
|
|
48
|
+
}[],
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Express } from 'express';
|
|
1
|
+
import type { Express, Request } from 'express';
|
|
2
2
|
import type { Writable } from 'stream';
|
|
3
3
|
|
|
4
4
|
import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections, AllowedActionsEnum,
|
|
@@ -8,12 +8,12 @@ import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections,
|
|
|
8
8
|
type AdminForthBulkActionCommon,
|
|
9
9
|
type AdminForthForeignResourceCommon,
|
|
10
10
|
type AdminForthResourceColumnCommon,
|
|
11
|
-
AdminForthResourceInputCommon,
|
|
12
|
-
AdminForthComponentDeclarationFull,
|
|
13
|
-
AdminForthConfigMenuItem,
|
|
14
|
-
AnnouncementBadgeResponse,
|
|
11
|
+
type AdminForthResourceInputCommon,
|
|
12
|
+
type AdminForthComponentDeclarationFull,
|
|
13
|
+
type AdminForthConfigMenuItem,
|
|
14
|
+
type AnnouncementBadgeResponse,
|
|
15
15
|
AdminForthResourcePages,
|
|
16
|
-
AdminForthResourceColumnInputCommon,
|
|
16
|
+
type AdminForthResourceColumnInputCommon,
|
|
17
17
|
} from './Common.js';
|
|
18
18
|
|
|
19
19
|
export interface ICodeInjector {
|
|
@@ -92,19 +92,36 @@ export interface IExpressHttpServer extends IHttpServer {
|
|
|
92
92
|
* Adds adminUser to request object if user is authorized. Drops request with 401 status if user is not authorized.
|
|
93
93
|
* @param callable : Function which will be called if user is authorized.
|
|
94
94
|
*
|
|
95
|
-
* Example:
|
|
96
95
|
*
|
|
96
|
+
* @example
|
|
97
97
|
* ```ts
|
|
98
|
-
* expressApp.get('/myApi', authorize((req, res) =>
|
|
98
|
+
* expressApp.get('/myApi', authorize((req, res) => {
|
|
99
99
|
* console.log('User is authorized', req.adminUser);
|
|
100
|
-
* res.json(
|
|
101
|
-
*
|
|
102
|
-
*
|
|
100
|
+
* res.json({ message: 'Hello World' });
|
|
101
|
+
* }));
|
|
102
|
+
* ```
|
|
103
103
|
*
|
|
104
|
-
*/
|
|
104
|
+
*/
|
|
105
105
|
authorize(callable: Function): void;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
export interface ITranslateFunction {
|
|
109
|
+
(
|
|
110
|
+
msg: string,
|
|
111
|
+
category: string,
|
|
112
|
+
params: any,
|
|
113
|
+
pluralizationNumber?: number
|
|
114
|
+
): Promise<string>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Omit <Request, 'param'> is used to remove 'param' method from Request type for correct docs generation
|
|
118
|
+
export interface IAdminUserExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
|
|
119
|
+
adminUser: AdminUser;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface ITranslateExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
|
|
123
|
+
tr: ITranslateFunction;
|
|
124
|
+
}
|
|
108
125
|
|
|
109
126
|
export interface IAdminForthSingleFilter {
|
|
110
127
|
field?: string;
|
|
@@ -336,7 +353,7 @@ export interface IAdminForth {
|
|
|
336
353
|
|
|
337
354
|
createResourceRecord(
|
|
338
355
|
params: { resource: AdminForthResource, record: any, adminUser: AdminUser, extra?: HttpExtra }
|
|
339
|
-
): Promise<{ error?: string, createdRecord?: any }>;
|
|
356
|
+
): Promise<{ error?: string, createdRecord?: any, newRecordId?: any }>;
|
|
340
357
|
|
|
341
358
|
updateResourceRecord(
|
|
342
359
|
params: { resource: AdminForthResource, recordId: any, record: any, oldRecord: any, adminUser: AdminUser, extra?: HttpExtra }
|
|
@@ -474,7 +491,7 @@ export type BeforeDataSourceRequestFunction = (params: {
|
|
|
474
491
|
requestUrl: string,
|
|
475
492
|
},
|
|
476
493
|
adminforth: IAdminForth,
|
|
477
|
-
}) => Promise<{ok: boolean, error?: string}>;
|
|
494
|
+
}) => Promise<{ok: boolean, error?: string, newRecordId?: string}>;
|
|
478
495
|
|
|
479
496
|
/**
|
|
480
497
|
* Modify response to change how data is returned after fetching from database.
|
|
@@ -525,7 +542,7 @@ export type BeforeEditSaveFunction = (params: {
|
|
|
525
542
|
oldRecord: any,
|
|
526
543
|
adminforth: IAdminForth,
|
|
527
544
|
extra?: HttpExtra,
|
|
528
|
-
}) => Promise<{ok: boolean, error?: string}>;
|
|
545
|
+
}) => Promise<{ok: boolean, error?: string | null}>;
|
|
529
546
|
|
|
530
547
|
|
|
531
548
|
|
|
@@ -535,7 +552,7 @@ export type BeforeCreateSaveFunction = (params: {
|
|
|
535
552
|
record: any,
|
|
536
553
|
adminforth: IAdminForth,
|
|
537
554
|
extra?: HttpExtra,
|
|
538
|
-
}) => Promise<{ok: boolean, error?: string}>;
|
|
555
|
+
}) => Promise<{ok: boolean, error?: string | null, newRecordId?: string}>;
|
|
539
556
|
|
|
540
557
|
export type AfterCreateSaveFunction = (params: {
|
|
541
558
|
resource: AdminForthResource,
|
|
@@ -619,6 +636,11 @@ interface AdminForthInputConfigCustomization {
|
|
|
619
636
|
*/
|
|
620
637
|
brandName?: string,
|
|
621
638
|
|
|
639
|
+
/**
|
|
640
|
+
* Whether to use single theme for the app
|
|
641
|
+
*/
|
|
642
|
+
singleTheme?: 'light' | 'dark',
|
|
643
|
+
|
|
622
644
|
/**
|
|
623
645
|
* Whether to show brand name in sidebar
|
|
624
646
|
* default is true
|
|
@@ -747,6 +769,7 @@ interface AdminForthInputConfigCustomization {
|
|
|
747
769
|
*/
|
|
748
770
|
loginPageInjections?: {
|
|
749
771
|
underInputs?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
772
|
+
panelHeader?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
750
773
|
}
|
|
751
774
|
|
|
752
775
|
/**
|
|
@@ -758,6 +781,16 @@ interface AdminForthInputConfigCustomization {
|
|
|
758
781
|
sidebar?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
759
782
|
everyPageBottom?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
|
|
760
783
|
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Allows adding custom elements (e.g., <link>, <script>, <meta>) to the <head> of the HTML document.
|
|
787
|
+
* Each item must include a tag name and a set of attributes.
|
|
788
|
+
*/
|
|
789
|
+
customHeadItems?: {
|
|
790
|
+
tagName: string;
|
|
791
|
+
attributes: Record<string, string | boolean>;
|
|
792
|
+
}[];
|
|
793
|
+
|
|
761
794
|
}
|
|
762
795
|
|
|
763
796
|
export interface AdminForthActionInput {
|
|
@@ -934,6 +967,13 @@ export interface AdminForthInputConfig {
|
|
|
934
967
|
*/
|
|
935
968
|
loginBackgroundPosition?: 'over' | '1/2' | '1/3' | '2/3' | '3/4' | '2/5' | '3/5',
|
|
936
969
|
|
|
970
|
+
/**
|
|
971
|
+
* If true, background blend mode will be removed from login background image when position is 'over'
|
|
972
|
+
*
|
|
973
|
+
* Default: false
|
|
974
|
+
*/
|
|
975
|
+
removeBackgroundBlendMode?: boolean,
|
|
976
|
+
|
|
937
977
|
/**
|
|
938
978
|
* Function or functions which will be called before user try to login.
|
|
939
979
|
* Each function will resive User object as an argument
|
|
@@ -955,7 +995,7 @@ export interface AdminForthInputConfig {
|
|
|
955
995
|
/**
|
|
956
996
|
* Any prompt to show users on login. Supports HTML.
|
|
957
997
|
*/
|
|
958
|
-
loginPromptHTML?: string
|
|
998
|
+
loginPromptHTML?: string | (() => string | void | undefined | Promise<string | void | undefined>) | undefined
|
|
959
999
|
|
|
960
1000
|
/**
|
|
961
1001
|
* Remember me days for "Remember Me" checkbox on login page.
|
|
@@ -1054,6 +1094,7 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
|
|
|
1054
1094
|
|
|
1055
1095
|
loginPageInjections: {
|
|
1056
1096
|
underInputs: Array<AdminForthComponentDeclarationFull>,
|
|
1097
|
+
panelHeader: Array<AdminForthComponentDeclarationFull>,
|
|
1057
1098
|
},
|
|
1058
1099
|
|
|
1059
1100
|
globalInjections: {
|
|
@@ -1062,6 +1103,12 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
|
|
|
1062
1103
|
sidebar: Array<AdminForthComponentDeclarationFull>,
|
|
1063
1104
|
everyPageBottom: Array<AdminForthComponentDeclarationFull>,
|
|
1064
1105
|
},
|
|
1106
|
+
|
|
1107
|
+
customHeadItems?: {
|
|
1108
|
+
tagName: string;
|
|
1109
|
+
attributes: Record<string, string | boolean>;
|
|
1110
|
+
}[];
|
|
1111
|
+
|
|
1065
1112
|
}
|
|
1066
1113
|
|
|
1067
1114
|
export interface AdminForthConfig extends Omit<AdminForthInputConfig, 'customization' | 'resources'> {
|
|
@@ -1316,9 +1363,13 @@ export interface AdminForthResource extends Omit<AdminForthResourceInput, 'optio
|
|
|
1316
1363
|
},
|
|
1317
1364
|
create?: {
|
|
1318
1365
|
/**
|
|
1366
|
+
* Should return `ok: true` to continue saving pipeline and allow creating record in database, and `ok: false` to interrupt pipeline and prevent record creation.
|
|
1367
|
+
* If you need to show error on UI, set `error: \<error message\>` in response.
|
|
1368
|
+
*
|
|
1319
1369
|
* Typical use-cases:
|
|
1320
|
-
* -
|
|
1321
|
-
* -
|
|
1370
|
+
* - Create record by custom code (return `{ ok: false, newRecordId: <id of created record from custom code> }`)
|
|
1371
|
+
* - Validate record before saving to database and interrupt execution if validation failed (return `{ ok: false, error: <validation error> }`), though `allowedActions.create` should be preferred in most cases
|
|
1372
|
+
* - fill-in adminUser as creator of record (set `record.<some field> = x; return \{ ok: true \}`)
|
|
1322
1373
|
* - Attach additional data to record before saving to database (mostly fillOnCreate should be used instead)
|
|
1323
1374
|
*/
|
|
1324
1375
|
beforeSave?: Array<BeforeCreateSaveFunction>,
|
|
@@ -1469,15 +1520,27 @@ export type ShowInInput = ShowInModernInput | ShowInLegacyInput;
|
|
|
1469
1520
|
export type ShowIn = {
|
|
1470
1521
|
[key in AdminForthResourcePages]: AllowedActionValue
|
|
1471
1522
|
}
|
|
1523
|
+
export type BackendOnlyInput =
|
|
1524
|
+
| boolean
|
|
1525
|
+
| ((p: {
|
|
1526
|
+
adminUser: AdminUser;
|
|
1527
|
+
resource: AdminForthResource;
|
|
1528
|
+
meta: any;
|
|
1529
|
+
source: ActionCheckSource;
|
|
1530
|
+
adminforth: IAdminForth;
|
|
1531
|
+
}) => boolean | Promise<boolean>);
|
|
1532
|
+
|
|
1472
1533
|
|
|
1473
|
-
export interface AdminForthResourceColumnInput extends Omit<AdminForthResourceColumnInputCommon, 'showIn'> {
|
|
1534
|
+
export interface AdminForthResourceColumnInput extends Omit<AdminForthResourceColumnInputCommon, 'showIn' | 'backendOnly'> {
|
|
1474
1535
|
showIn?: ShowInInput,
|
|
1475
1536
|
foreignResource?: AdminForthForeignResource,
|
|
1537
|
+
backendOnly?: BackendOnlyInput;
|
|
1476
1538
|
}
|
|
1477
1539
|
|
|
1478
|
-
export interface AdminForthResourceColumn extends Omit<AdminForthResourceColumnCommon, 'showIn'> {
|
|
1540
|
+
export interface AdminForthResourceColumn extends Omit<AdminForthResourceColumnCommon, 'showIn' | 'backendOnly'> {
|
|
1479
1541
|
showIn?: ShowIn,
|
|
1480
1542
|
foreignResource?: AdminForthForeignResource,
|
|
1543
|
+
backendOnly?: BackendOnlyInput;
|
|
1481
1544
|
}
|
|
1482
1545
|
|
|
1483
1546
|
export interface IWebSocketClient {
|
|
@@ -95,12 +95,9 @@ export interface AdminForthBulkActionCommon {
|
|
|
95
95
|
label: string,
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
*
|
|
99
|
-
* * 'danger' - red button
|
|
100
|
-
* * 'success' - green button
|
|
101
|
-
* * 'active' - blue button
|
|
98
|
+
* Add custom class
|
|
102
99
|
**/
|
|
103
|
-
|
|
100
|
+
buttonCustomCssClass?: string;
|
|
104
101
|
|
|
105
102
|
/**
|
|
106
103
|
* Optional small badge for button which will be displayed in the list view
|
|
@@ -122,6 +119,10 @@ export interface AdminForthBulkActionCommon {
|
|
|
122
119
|
*/
|
|
123
120
|
successMessage?: string,
|
|
124
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Show in three dots dropdown menu in list view.
|
|
124
|
+
*/
|
|
125
|
+
showInThreeDotsDropdown?: boolean,
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
export interface AdminForthFieldComponents {
|
|
@@ -584,6 +585,8 @@ export interface AdminForthForeignResourceCommon {
|
|
|
584
585
|
polymorphicResources?: Array<AdminForthPolymorphicForeignResource>,
|
|
585
586
|
polymorphicOn?: string,
|
|
586
587
|
unsetLabel?: string,
|
|
588
|
+
searchableFields?: string | string[],
|
|
589
|
+
searchIsCaseSensitive?: boolean,
|
|
587
590
|
}
|
|
588
591
|
|
|
589
592
|
export type FillOnCreateFunction = (params: {
|
|
@@ -810,9 +813,6 @@ export interface AdminForthResourceColumnInputCommon {
|
|
|
810
813
|
*/
|
|
811
814
|
minLength?: number,
|
|
812
815
|
|
|
813
|
-
min?: number,
|
|
814
|
-
max?: number,
|
|
815
|
-
|
|
816
816
|
/**
|
|
817
817
|
* Minimum value that can be entered in this field.
|
|
818
818
|
*/
|
|
@@ -878,6 +878,15 @@ export interface AdminForthResourceColumnCommon extends AdminForthResourceColumn
|
|
|
878
878
|
|
|
879
879
|
editingNote?: { create?: string, edit?: string },
|
|
880
880
|
|
|
881
|
+
/**
|
|
882
|
+
* Minimal value stored in this field.
|
|
883
|
+
*/
|
|
884
|
+
min?: number,
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Maximum value stored in this field.
|
|
888
|
+
*/
|
|
889
|
+
max?: number,
|
|
881
890
|
}
|
|
882
891
|
|
|
883
892
|
export enum AdminForthMenuTypes {
|
|
@@ -1055,15 +1064,18 @@ export interface AdminForthConfigForFrontend {
|
|
|
1055
1064
|
usernameFieldName: string,
|
|
1056
1065
|
loginBackgroundImage: string,
|
|
1057
1066
|
loginBackgroundPosition: string,
|
|
1067
|
+
removeBackgroundBlendMode: boolean,
|
|
1058
1068
|
title?: string,
|
|
1059
1069
|
demoCredentials?: string,
|
|
1060
|
-
loginPromptHTML?: string
|
|
1070
|
+
loginPromptHTML?: string | (() => string | Promise<string> | void | Promise<void> | Promise<undefined>) | undefined
|
|
1061
1071
|
loginPageInjections: {
|
|
1062
1072
|
underInputs: Array<AdminForthComponentDeclaration>,
|
|
1073
|
+
panelHeader: Array<AdminForthComponentDeclaration>,
|
|
1063
1074
|
},
|
|
1064
1075
|
rememberMeDays: number,
|
|
1065
1076
|
showBrandNameInSidebar: boolean,
|
|
1066
1077
|
brandLogo?: string,
|
|
1078
|
+
singleTheme?: 'light' | 'dark',
|
|
1067
1079
|
datesFormat: string,
|
|
1068
1080
|
timeFormat: string,
|
|
1069
1081
|
auth: any,
|
|
@@ -1079,7 +1091,11 @@ export interface AdminForthConfigForFrontend {
|
|
|
1079
1091
|
header: Array<AdminForthComponentDeclarationFull>,
|
|
1080
1092
|
sidebar: Array<AdminForthComponentDeclarationFull>,
|
|
1081
1093
|
everyPageBottom: Array<AdminForthComponentDeclarationFull>,
|
|
1082
|
-
}
|
|
1094
|
+
},
|
|
1095
|
+
customHeadItems?: {
|
|
1096
|
+
tagName: string;
|
|
1097
|
+
attributes: Record<string, string | boolean>;
|
|
1098
|
+
}[],
|
|
1083
1099
|
}
|
|
1084
1100
|
|
|
1085
1101
|
export interface GetBaseConfigResponse {
|